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 { Action } from '@ohos/common/src/main/ets/default/redux/actions/Action';
17import { ComponentPosition } from '@ohos/common/src/main/ets/default/utils/ComponentPosition';
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';
27import { SettingManager } from '@ohos/common/src/main/ets/default/setting/SettingManager';
28
29class StateStruct {
30  isThirdPartyCall: boolean = false;
31  isFaCall: boolean = false;
32  action: string = '';
33  uiEnable: boolean = true;
34  modeIndex: number = 0;
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  public changeXComponentSize(xComponentWidth: number, xComponentHeight: number): void {
77    this.mDispatch(Action.changeXComponentSize(xComponentWidth, xComponentHeight));
78  }
79}
80
81class ScreenSizeType {
82  width: number = 0;
83  height: number = 0;
84}
85
86class SwipeModeIndexStruct {
87  swipeModeIndex: number = 0;
88}
89
90@Component
91export struct ControlLand {
92  private TAG: string = '[ControlLand]:';
93  appEventBus: EventBus = EventBusManager.getInstance().getEventBus();
94  private scroller: Scroller = new Scroller();
95  private settingManager = SettingManager.getInstance();
96  private modeArray: Array<string> = ['PHOTO', 'VIDEO']; //, 'MORE'
97  private touchOff: boolean = true;
98  private scrollDistance: number = 0;
99  protected mPreferencesService: PreferencesService = PreferencesService.getInstance();
100  @State state: StateStruct = new StateStruct();
101  private mAction: ControlDispatcher = new ControlDispatcher();
102  @State startScroll: number = 0;
103  @State endScroll: number = 0;
104  @State index: number = 0;
105  @Link screenSize: ScreenSizeType;
106
107  aboutToAppear(): void {
108    Log.info(`${this.TAG} aboutToAppear E`)
109    getStore().subscribe((state: OhCombinedState) => {
110      this.state = {
111        isThirdPartyCall: state.contextReducer.isThirdPartyCall,
112        isFaCall: state.contextReducer.isFaCall,
113        action: state.contextReducer.action,
114        uiEnable: state.contextReducer.uiEnable,
115        modeIndex: state.modeReducer.modeIndex,
116        mode: state.modeReducer.mode,
117        isShowMoreList: state.modeReducer.isShowMoreList
118      };
119    }, (dispatch: Dispatch) => {
120      this.mAction.setDispatch(dispatch);
121    });
122    this.appEventBus.on(Action.ACTION_SWIPE_MODE, (data: SwipeModeIndexStruct) => this.swipeChangeMode(data));
123    Log.info(`${this.TAG} aboutToAppear X`)
124  }
125
126  aboutToDisappear(): void {
127    Log.info(`${this.TAG} aboutToDisappear E`)
128    this.appEventBus.off(Action.ACTION_SWIPE_MODE, (data: SwipeModeIndexStruct) => this.swipeChangeMode(data))
129    Log.info(`${this.TAG} aboutToDisappear X`)
130  }
131
132  private changeToMode(modeIndex: number, callType?: string): void {
133    Log.info(`${this.TAG} changeToMode modeIndex: ${modeIndex} E`);
134    this.scroller.scrollToIndex(modeIndex)
135    if (callType === 'begin') return;
136    if (this.modeArray[modeIndex] !== this.state.mode) {
137      Log.info(`${this.TAG} this.state.changeToMode(${this.modeArray[modeIndex]})`);
138      this.mAction.changeToMode(this.modeArray[modeIndex])
139      let xComponentSize = this.settingManager.getPreviewDisplaySize(this.state.mode)
140      this.mAction.changeXComponentSize(xComponentSize.width, xComponentSize.height)
141      this.mPreferencesService.putModeValue(PersistType.FOR_AWHILE, modeIndex)
142      this.mPreferencesService.flushMode()
143    }
144    Log.info(`${this.TAG} changeToMode X`);
145  }
146
147  private getModeFontWeight(modeIndex: number): FontWeight {
148    if (this.state.mode === this.modeArray[modeIndex]) {
149      return FontWeight.Bold
150    } else {
151      return FontWeight.Regular
152    }
153  }
154
155  private swipeChangeMode(data: SwipeModeIndexStruct): void {
156    this.changeToMode(data.swipeModeIndex)
157  }
158
159  private scrollSwitchMode(callType: string): void {
160    if (this.index == 1 && Math.abs(this.scrollDistance) <= px2vp(20)) {
161      this.changeToMode(1, callType)
162    }
163    if (this.index == 1 && (this.scrollDistance) > px2vp(20)) {
164      this.changeToMode(0, callType)
165    }
166    if (this.index == 1 && (this.scrollDistance) < px2vp(-20)) {
167      this.changeToMode(2, callType)
168    }
169    if (this.index == 0 && (this.scrollDistance > px2vp(-25))) {
170      this.changeToMode(0, callType)
171    }
172    if (this.index == 0 && this.scrollDistance >= px2vp(-50) && this.scrollDistance <= px2vp(-25)) {
173      this.changeToMode(1, callType)
174    }
175    if (this.index == 0 && this.scrollDistance < px2vp(-50)) {
176      this.changeToMode(2, callType)
177    }
178    if (this.index == 2 && (this.scrollDistance < px2vp(25))) {
179      this.changeToMode(2, callType)
180    }
181    if (this.index == 2 && this.scrollDistance >= px2vp(25) && this.scrollDistance <= px2vp(50)) {
182      this.changeToMode(1, callType)
183    }
184    if (this.index == 2 && this.scrollDistance > px2vp(50)) {
185      this.changeToMode(0, callType)
186    }
187  }
188
189  build() {
190    Stack({ alignContent: Alignment.TopStart }) {
191      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
192        if ((this.state.isThirdPartyCall || this.state.isFaCall) && this.state.mode === 'PHOTO') {
193          Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
194            Text($r('app.string.photo_mode'))
195              .fontSize($r('sys.float.ohos_id_text_size_body1'))
196              .fontColor(Color.White)
197              .fontWeight(FontWeight.Bold)
198          }.layoutWeight(1).height('100%')
199        } else if ((this.state.isThirdPartyCall || this.state.isFaCall) && this.state.mode === 'VIDEO') {
200          Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
201            Text($r('app.string.video_mode'))
202              .fontSize($r('sys.float.ohos_id_text_size_body1'))
203              .fontColor(Color.White)
204              .fontWeight(FontWeight.Bold)
205          }.layoutWeight(1).height('100%')
206        } else {
207          List({ initialIndex: this.state.modeIndex, scroller: this.scroller }) {
208            if (ComponentPosition.isUnfoldControl(this.screenSize.width, this.screenSize.height)) {
209              ListItem() {
210              }.width('100%').height(32)
211            }
212            ListItem() {
213            }.width('100%').height(32)
214
215            ListItem() {
216              Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
217                Text($r('app.string.multi_mode'))
218                  .fontSize($r('sys.float.ohos_id_text_size_body1'))
219                  .fontColor(Color.White)
220                  .enabled(this.state.uiEnable)
221                  .onClick(async () => {
222                    this.changeToMode(0)
223                  })
224                  .fontWeight(this.getModeFontWeight(0))
225              }.width('100%').height('100%')
226            }.width('100%').height(32)
227
228            ListItem() {
229              Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
230                Text($r('app.string.photo_mode'))
231                  .fontSize($r('sys.float.ohos_id_text_size_body1'))
232                  .fontColor(Color.White)
233                  .enabled(this.state.uiEnable)
234                  .onClick(async () => {
235                    this.changeToMode(1)
236                  })
237                  .fontWeight(this.getModeFontWeight(1))
238              }.width('100%').height('100%')
239            }.width('100%').height(32)
240
241            ListItem() {
242              Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
243                Text($r('app.string.video_mode'))
244                  .fontSize($r('sys.float.ohos_id_text_size_body1'))
245                  .fontColor(Color.White)
246                  .enabled(this.state.uiEnable)
247                  .onClick(async () => {
248                    this.changeToMode(2)
249                  })
250                  .fontWeight(this.getModeFontWeight(2))
251              }.width('100%').height('100%')
252            }.width('100%').height(32)
253
254            ListItem() {
255            }.width('100%').height(32)
256
257            ListItem() {
258            }.width('100%').height(32)
259          }
260          .layoutWeight(1)
261          .height('100%')
262          .edgeEffect(EdgeEffect.None)
263          .chainAnimation(false)
264          .onScrollIndex((firstIndex: number, lastIndex: number) => {
265            Log.info(`${this.TAG} Control scroll index first: ${firstIndex}, last: ${lastIndex}`);
266            this.mAction.updateModeIndex(firstIndex)
267            Log.info(`${this.TAG} onScrollIndex this.state.modeIndex: ${this.state.modeIndex}`);
268          })
269          // .onScrollBegin(() => {
270          //   if (!this.touchOff) this.scrollSwitchMode('begin')
271          // })
272          .enabled(this.state.uiEnable)
273          .onTouch((event: TouchEvent) => {
274            if (event.type === TouchType.Down) {
275              this.touchOff = true
276              this.index = this.modeArray.indexOf(this.state.mode)
277              this.startScroll = event.touches[0].screenY
278            }
279            if (event.type === TouchType.Up) {
280              this.endScroll = event.touches[0].screenY
281              this.scrollDistance = px2vp(this.endScroll - this.startScroll)
282              this.touchOff = false
283              this.scrollSwitchMode('touch')
284            }
285          })
286        }
287        Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {
288          Column() {
289          }.borderRadius(3).width(6).height(6).backgroundColor('#007DFF')
290
291          //            .shadow({radius: 5, color: 'argb(#7F000000)', offsetX: 0, offsetY: 0})
292        }.width(18).height('100%').margin({ left: 8 })
293      }.width('100%').height('100%')
294    }.width(98).height(ComponentPosition.getControlHeight(this.screenSize.width, this.screenSize.height)).zIndex(2)
295  }
296}