1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import display from '@ohos.display'; 17import { Action } from '@ohos/common/src/main/ets/default/redux/actions/Action'; 18import { EventBus } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBus'; 19import { EventBusManager } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBusManager'; 20import { Dispatch, OhCombinedState } from '@ohos/common/src/main/ets/default/redux/store'; 21import { getStore } from '@ohos/common/src/main/ets/default/redux/store'; 22import { Log } from '@ohos/common/src/main/ets/default/utils/Log'; 23import { 24 PersistType, 25 PreferencesService 26} from '@ohos/common/src/main/ets/default/featurecommon/preferences/PreferencesService'; 27 28class StateStruct { 29 isThirdPartyCall: boolean = false; 30 isFaCall: boolean = false; 31 action: string = ''; 32 uiEnable: boolean = true; 33 modeIndex: number = 1; 34 mode: string = 'PHOTO'; 35 isShowMoreList: boolean = false; 36} 37 38class ControlDispatcher { 39 private mDispatch: Dispatch = (data) => data; 40 41 public setDispatch(dispatch: Dispatch) { 42 this.mDispatch = dispatch; 43 } 44 45 public changeToMode(mode: string): void { 46 this.mDispatch(Action.uiState(false)); 47 this.mDispatch(Action.changeMode(mode)); 48 this.mDispatch(Action.updateShowBigTextFlag(true)); 49 } 50 51 public updateModeIndex(index: number): void { 52 this.mDispatch(Action.updateModeIndex(index)); 53 } 54 55 public updateShowMoreList(isShowMoreList: boolean): void { 56 this.mDispatch(Action.updateShowMoreList(isShowMoreList)); 57 } 58 59 public thirdPartyCall(isThirdPartyCall: boolean, action: string): void { 60 this.mDispatch(Action.thirdPartyCall(isThirdPartyCall, action)); 61 } 62 63 public initAction(action: string): void { 64 this.mDispatch(Action.initAction(action)); 65 } 66 67 public initMode(mode: string): void { 68 this.mDispatch(Action.initMode(mode)); 69 } 70 71 public updateListStatus(enable: boolean): void { 72 this.mDispatch(Action.uiState(enable)); 73 } 74} 75 76class SwipeModeIndexStruct { 77 swipeModeIndex: number = 0; 78} 79 80 81@Component 82export struct Control { 83 private TAG: string = '[Control]' 84 appEventBus: EventBus = EventBusManager.getInstance().getEventBus() 85 private scroller: Scroller = new Scroller() 86 private modeArray: Array<string> = ['MULTI', 'PHOTO', 'VIDEO'] 87 private isScroll: boolean = false 88 private scrollDistance: number = 0 89 protected mPreferencesService: PreferencesService = PreferencesService.getInstance() 90 @State state: StateStruct = new StateStruct() 91 private mAction: ControlDispatcher = new ControlDispatcher(); 92 @State modeBarItemLeftWidth: number = 225 93 @State modeBarItemRightWidth: number = 225 94 @State startScroll: number = 0 95 @State endScroll: number = 0 96 @State index: number = 0 97 98 aboutToAppear(): void { 99 Log.info(`${this.TAG} aboutToAppear E`) 100 getStore().subscribe((state: OhCombinedState) => { 101 this.state = { 102 isThirdPartyCall: state.contextReducer.isThirdPartyCall, 103 isFaCall: state.contextReducer.isFaCall, 104 action: state.contextReducer.action, 105 uiEnable: state.contextReducer.uiEnable, 106 modeIndex: state.modeReducer.modeIndex, 107 mode: state.modeReducer.mode, 108 isShowMoreList: state.modeReducer.isShowMoreList 109 }; 110 }, (dispatch: Dispatch) => { 111 this.mAction.setDispatch(dispatch); 112 }); 113 114 display.getDefaultDisplay().then((dis) => { 115 this.modeBarItemLeftWidth = px2vp(dis.width) / 2 - 156 116 this.modeBarItemRightWidth = px2vp(dis.width) / 2 - 148 117 }) 118 this.appEventBus.on(Action.ACTION_SWIPE_MODE, (data: SwipeModeIndexStruct) => this.swipeChangeMode(data)); 119 Log.info(`${this.TAG} aboutToAppear X`) 120 } 121 122 aboutToDisappear(): void { 123 Log.info(`${this.TAG} aboutToDisappear E`) 124 this.appEventBus.off(Action.ACTION_SWIPE_MODE, (data: SwipeModeIndexStruct) => this.swipeChangeMode(data)) 125 Log.info(`${this.TAG} aboutToDisappear X`) 126 } 127 128 private changeToMode(modeIndex: number): void { 129 Log.debug(`${this.TAG} changeToMode modeIndex: ${modeIndex} E`) 130 this.scroller.scrollToIndex(modeIndex) 131 if (this.modeArray[modeIndex] !== this.state.mode) { 132 Log.debug(`${this.TAG} this.state.changeToMode(${this.modeArray[modeIndex]})`) 133 this.mAction.changeToMode(this.modeArray[modeIndex]) 134 this.mPreferencesService.putModeValue(PersistType.FOR_AWHILE, modeIndex) 135 this.mPreferencesService.flushMode() 136 } else { 137 this.mAction.updateListStatus(true) 138 } 139 Log.debug(`${this.TAG} changeToMode X`) 140 } 141 142 private getModeFontWeight(modeIndex: number): FontWeight { 143 if (this.state.mode === this.modeArray[modeIndex]) { 144 return FontWeight.Bold 145 } else { 146 return FontWeight.Regular 147 } 148 } 149 150 private swipeChangeMode(data: SwipeModeIndexStruct): void { 151 this.changeToMode(data.swipeModeIndex) 152 } 153 154 private scrollSwitchMode(): void { 155 if (this.index == 1 && Math.abs(this.scrollDistance) <= px2vp(28)) { 156 this.changeToMode(1) 157 } 158 if (this.index == 1 && (this.scrollDistance) > px2vp(28)) { 159 this.changeToMode(2) 160 } 161 if (this.index == 1 && (this.scrollDistance) < px2vp(-28)) { 162 this.changeToMode(0) 163 } 164 if (this.index == 0 && (this.scrollDistance < px2vp(36))) { 165 this.changeToMode(0) 166 } 167 if (this.index == 0 && this.scrollDistance <= px2vp(92) && this.scrollDistance >= px2vp(36)) { 168 this.changeToMode(1) 169 } 170 if (this.index == 0 && this.scrollDistance > px2vp(92)) { 171 this.changeToMode(2) 172 } 173 if (this.index == 2 && (this.scrollDistance > px2vp(-28))) { 174 this.changeToMode(2) 175 } 176 if (this.index == 2 && this.scrollDistance <= px2vp(-28) && this.scrollDistance >= px2vp(-92)) { 177 this.changeToMode(1) 178 } 179 if (this.index == 2 && this.scrollDistance < px2vp(-92)) { 180 this.changeToMode(0) 181 } 182 } 183 184 build() { 185 Column() { 186 Stack({ alignContent: Alignment.BottomStart }) { 187 if ((this.state.isThirdPartyCall || this.state.isFaCall) && this.state.mode === 'PHOTO') { 188 Row() { 189 Text($r('app.string.photo_mode')) 190 .width('100%') 191 .height('100%') 192 .fontSize(14) 193 .fontColor(Color.White) 194 .fontWeight(FontWeight.Bold) 195 .textAlign(TextAlign.Center) 196 }.width('100%').height('100%') 197 } else if ((this.state.isThirdPartyCall || this.state.isFaCall) && this.state.mode === 'VIDEO') { 198 Row() { 199 Text($r('app.string.video_mode')) 200 .width('100%') 201 .height('100%') 202 .fontSize(14) 203 .fontColor(Color.White) 204 .fontWeight(FontWeight.Bold) 205 .textAlign(TextAlign.Center) 206 }.width('100%').height('100%') 207 } else { 208 List({ initialIndex: this.state.modeIndex, scroller: this.scroller }) { 209 ListItem() { 210 }.width(64).height('100%') 211 212 ListItem() { 213 }.width(56).height('100%') 214 215 ListItem() { 216 }.width(this.modeBarItemLeftWidth).height('100%') 217 218 ListItem() { 219 Text($r('app.string.multi_mode')) 220 .width('100%') 221 .height('100%') 222 .fontColor('#fff') 223 .fontSize($r("sys.float.ohos_id_text_size_sub_title3")) 224 .fontWeight(this.getModeFontWeight(0)) 225 .textAlign(TextAlign.Center) 226 .enabled(this.state.uiEnable) 227 .onClick(() => { 228 this.changeToMode(0) 229 }) 230 }.width(72).height('100%') 231 232 ListItem() { 233 Text($r('app.string.photo_mode')) 234 .width('100%') 235 .height('100%') 236 .fontColor('#fff') 237 .fontSize($r("sys.float.ohos_id_text_size_sub_title3")) 238 .fontWeight(this.getModeFontWeight(1)) 239 .textAlign(TextAlign.Center) 240 .enabled(this.state.uiEnable) 241 .onClick(() => { 242 this.changeToMode(1) 243 }) 244 }.width(56).height('100%') 245 246 ListItem() { 247 Text($r('app.string.video_mode')) 248 .width('100%') 249 .height('100%') 250 .fontColor('#fff') 251 .fontSize($r("sys.float.ohos_id_text_size_sub_title3")) 252 .fontWeight(this.getModeFontWeight(2)) 253 .textAlign(TextAlign.Center) 254 .enabled(this.state.uiEnable) 255 .onClick(() => { 256 this.changeToMode(2) 257 }) 258 }.width(56).height('100%') 259 260 ListItem() { 261 }.width(this.modeBarItemRightWidth).height('100%') 262 263 ListItem() { 264 }.width(64).height('100%') 265 266 ListItem() { 267 }.width(56).height('100%') 268 } 269 .width('100%') 270 .height('100%') 271 .listDirection(Axis.Horizontal) 272 .edgeEffect(EdgeEffect.None) 273 .chainAnimation(false) 274 .enabled(this.state.uiEnable) 275 .onScrollIndex((firstIndex: number, lastIndex: number) => { 276 Log.debug(`${this.TAG} Control scroll index first: ${firstIndex}, last: ${lastIndex}`) 277 this.mAction.updateModeIndex(firstIndex) 278 Log.debug(`${this.TAG} onScrollIndex this.state.modeIndex: ${this.state.modeIndex}`) 279 }) 280 .onScrollStop(() => { 281 Log.info(`${this.TAG} onScrollStop`) 282 this.scrollSwitchMode() 283 }) 284 .onScroll((scrollOffset: number, scrollState: ScrollState) => { 285 if (scrollState === ScrollState.Fling) { 286 this.scrollDistance += px2vp(scrollOffset) 287 if (!this.isScroll) { 288 this.isScroll = true 289 this.mAction.updateListStatus(false) 290 } 291 } 292 }) 293 .onTouch((event?: TouchEvent) => { 294 if (!event) { 295 return; 296 } 297 if (event.type === TouchType.Down) { 298 this.scrollDistance = 0 299 this.index = this.modeArray.indexOf(this.state.mode) 300 this.startScroll = event.touches[0].screenX 301 } 302 if (event.type === TouchType.Up) { 303 this.endScroll = event.touches[0].screenX 304 this.scrollDistance = px2vp(this.startScroll - this.endScroll) 305 this.isScroll = false 306 } 307 }) 308 } 309 Column() { 310 Column() { 311 }.width(6).height(6).borderRadius(3).backgroundColor('#007DFF') 312 }.width('100%').height(18) 313 }.width('100%').height(58) 314 } 315 } 316}