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