• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 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 */
15import MediaLib from '@ohos.multimedia.mediaLibrary';
16import { Log } from '../utils/Log';
17import { AnimationConstants } from '../constants/AnimationConstants';
18import { MediaDataItem } from '../data/MediaDataItem';
19import { DateUtil } from '../utils/DateUtil';
20import { Broadcast } from '../utils/Broadcast';
21import { BroadcastConstants } from '../constants/BroadcastConstants';
22import { startTrace } from '../utils/TraceControllerUtils';
23import { MediaConstants } from '../constants/MediaConstants';
24import { startTraceWithTaskId, finishTraceWithTaskId } from '../utils/TraceControllerUtils';
25import { LazyItem} from '../vm/ItemDataSource';
26
27const TAG = "ImageGridItemComponent"
28// General grid picture control
29@Component
30export struct ImageGridItemComponent {
31    @Consume broadCast: Broadcast;
32    @Consume  @Watch('restPress') isSelectedMode: boolean;
33    @Consume @Watch('onShow') isShow: boolean;
34    @State thumbnail: string = "";
35    @State isFavourite: boolean = false;
36    @State pressAnimScale: number = 1.0;
37    @State isError: boolean = false;
38    pageName = '';
39    lazyItem: LazyItem<MediaDataItem>
40    mediaItem: MediaDataItem;
41    isThird = false;
42    private isEnteringPhoto = false;
43    private isPush = false;
44    private isPreview = false;
45    @Link isSelectUpperLimited : boolean;
46
47    private resetPressAnim(): void {
48        this.pressAnimScale = 1;
49        this.isEnteringPhoto = false;
50    }
51
52    private restPress(): void {
53        this.pressAnimScale = 1;
54    }
55
56    aboutToAppear(): void {
57        Log.debug(TAG, 'aboutToAppear');
58        this.resetShow();
59    }
60
61    private resetShow() {
62        Log.info(TAG, `getThumbnail1 ${this.thumbnail}`);
63        if (this.mediaItem.isLoad()) {
64            this.thumbnail = this.mediaItem.getThumbnail(MediaConstants.DEFAULT_SIZE, MediaConstants.DEFAULT_SIZE);
65            this.mediaItem.isFavor().then((status: boolean) => {
66                this.isFavourite = status;
67            })
68        } else {
69	    startTraceWithTaskId("load MediaItem", this.mediaItem.index);
70            this.mediaItem.load(false).then(() => {
71                finishTraceWithTaskId("load MediaItem", this.mediaItem.index);
72                this.thumbnail = this.mediaItem.getThumbnail(MediaConstants.DEFAULT_SIZE, MediaConstants.DEFAULT_SIZE);
73                this.isError = false;
74                Log.info(TAG, `getThumbnail2 ${this.thumbnail}`);
75                this.mediaItem.isFavor().then((status: boolean) => {
76                    this.isFavourite = status;
77                })
78            })
79        }
80        this.resetPressAnim();
81        this.isPush = false;
82    }
83
84    aboutToDisappear(): void {
85        Log.debug(TAG, `aboutToDisappear`);
86        this.resetPressAnim();
87    }
88
89    private onShow(): void {
90        if(!this.isShow){
91            return;
92        }
93        if (this.isEnteringPhoto) {
94            this.resetShow();
95        } else {
96            this.resetPressAnim();
97        }
98    }
99
100    async routePage(isError: boolean) {
101        Log.info(TAG, `routePage ${isError}`);
102        try {
103            startTrace('enterPhotoBrowser');
104            if (this.isThird || this.isPreview) {
105                this.broadCast.emit(BroadcastConstants.JUMP_THIRD_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
106            } else {
107                this.broadCast.emit(BroadcastConstants.JUMP_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
108            }
109        } catch (err) {
110            Log.error(TAG, `fail callback, code: ${err.code}, msg: ${err.msg}`);
111        }
112    }
113
114    async routeToPreviewPage() {
115        try {
116            Log.info(TAG, 'routeToPreviewPage');
117            this.broadCast.emit(BroadcastConstants.JUMP_THIRD_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
118        } catch (err) {
119            Log.error(TAG, `fail callback, code: ${err.code}, msg: ${err.msg}`);
120        }
121    }
122
123    private onSelected() {
124        Log.info(TAG, 'onSelected');
125        if ((this.isSelectUpperLimited != undefined && !this.isSelectUpperLimited) || this.mediaItem.isSelect) {
126            this.mediaItem.setSelect(!this.mediaItem.isSelect);
127            if (this.lazyItem) {
128                this.lazyItem.update(this.mediaItem)
129            }
130        }
131        this.broadCast.emit(BroadcastConstants.SELECT, [this.mediaItem.index]);
132    }
133
134    private selectStateChange() {
135        Log.info(TAG, `change selected ${this.isSelectedMode}`);
136        if (!this.isSelectedMode) {
137            this.isSelectedMode = true;
138            this.pressAnimScale = 1;
139        }
140        this.onSelected();
141    }
142
143    jumpToPhotoBrowser() {
144        if(this.isEnteringPhoto){
145            return;
146        }
147        this.isEnteringPhoto = true;
148        this.thumbnail = this.mediaItem.getThumbnail(this.mediaItem.imgWidth, this.mediaItem.imgHeight);
149        console.info("column click, first change source:"+this.thumbnail)
150        this.isPush = true;
151    }
152
153    build() {
154        Stack({ alignContent: Alignment.Start }) {
155            Image(this.isError ? this.mediaItem.getAlt() : this.thumbnail)
156                .aspectRatio(1)
157                .rotate({ x: 0, y: 0, z: 1, angle: 0 })
158                .objectFit(ImageFit.Cover)
159                .autoResize(false)
160                .onComplete(() => {
161                    Log.debug(TAG, `Draw the image! ${this.thumbnail}`);
162                    if (this.isEnteringPhoto && this.isPush) {
163                        Log.info(TAG, "image onComplete, broadCast, thumbnail:"+this.thumbnail);
164                        this.isPush = false;
165                        if (this.isThird || this.isPreview) {
166                            this.broadCast.emit(BroadcastConstants.JUMP_THIRD_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
167                        } else {
168                            this.broadCast.emit(BroadcastConstants.JUMP_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
169                        }
170                    }
171
172                })
173                .onError(() => {
174                    Log.error(TAG, `alt Image ${this.mediaItem.index} error :${this.thumbnail}`);
175                    if (this.thumbnail.length == 0 || this.mediaItem.width == 0 || this.mediaItem.height == 0) {
176                        this.resetShow()
177                    } else {
178                        this.isError = true
179                    }
180                })
181                .sharedTransition(this.pageName + this.mediaItem.getHashCode(), {
182                    duration: AnimationConstants.SHARE_TRANSITION_DURATION,
183                    zIndex: 0,
184                })
185
186            if (this.mediaItem.mediaType == MediaLib.MediaType.VIDEO) {
187                Column()
188                    .position({ x: '0%', y: '50%' })
189                    .height('50%')
190                    .width('100%')
191                    .linearGradient({
192                        angle: 0,
193                        colors: [[$r('app.color.album_cover_gradient_start_color'), 0], [$r('app.color.transparent'), 1.0]]
194                    })
195                Text(DateUtil.getFormattedDuration(this.mediaItem.duration))
196                    .fontSize($r('sys.float.ohos_id_text_size_caption'))
197                    .fontFamily($r('app.string.id_text_font_family_regular'))
198                    .fontColor($r('app.color.text_color_above_picture'))
199                    .lineHeight($r('app.float.grid_item_text_line_height'))
200                    .position({ x: '0%', y: '100%' })
201                    .markAnchor({
202                        x: $r('app.float.grid_item_duration_markAnchor_x'),
203                        y: $r('app.float.grid_item_duration_markAnchor_y')
204                    })
205                    .margin({ right: $r('app.float.grid_item_duration_margin_right') })
206            }
207            if (this.isFavourite) {
208                Image($r('app.media.ic_favorite_overlay'))
209                    .height($r('app.float.icon_size'))
210                    .width($r('app.float.icon_size'))
211                    .objectFit(ImageFit.Contain)
212                    .position({ x: '100%', y: '0%' })
213                    .markAnchor({
214                        x: $r('app.float.grid_item_favor_markAnchor_x'),
215                        y: $r('app.float.grid_item_favor_markAnchor_y')
216                    })
217            }
218
219            Column()
220                .height('100%')
221                .width('100%')
222                .backgroundColor(this.isSelectedMode && this.mediaItem.isSelect ?
223                $r('app.color.item_selection_bg_color') : $r('app.color.transparent'))
224                .onClick(() => {
225                    if (this.isSelectedMode) {
226                        this.onSelected();
227                     } else {
228                        this.isPreview = false;
229                        this.jumpToPhotoBrowser();
230                     }
231                })
232            if (this.isSelectedMode) {
233                Image($r('app.media.ic_photo_preview'))
234                    .onClick(() => {
235                        this.isPreview = true;
236                        this.jumpToPhotoBrowser();
237                        Log.info(TAG, 'expand.');
238                    })
239                    .height($r('app.float.icon_size_hot'))
240                    .width($r('app.float.icon_size_hot'))
241                    .position({ x: '0%', y: '0%' })
242                    .markAnchor({ x: 0, y: 0 })
243                    .padding($r('app.float.grid_item_preview_padding'))
244                Image(this.mediaItem.isSelect
245                    ? $r('app.media.ic_gallery_public_checkbox_filled') : $r('app.media.ic_checkbox_off_overlay'))
246                    .height($r('app.float.icon_size'))
247                    .width($r('app.float.icon_size'))
248                    .position({ x: '100%', y: '100%' })
249                    .markAnchor({
250                        x: $r('app.float.grid_item_checkbox_markAnchor'),
251                        y: $r('app.float.grid_item_checkbox_markAnchor')
252                    })
253                    .onClick(() => {
254                        this.onSelected();
255                    })
256            }
257        }
258        .aspectRatio(1)
259        .scale({
260            x: this.pressAnimScale,
261            y: this.pressAnimScale
262        })
263        .animation({
264            duration: AnimationConstants.PRESS_ANIM_DURATION,
265            curve: Curve.Ease
266        })
267        .onTouch(event => {
268            Log.info(TAG, `onTouch trigger: isSelectedMode: ${this.isSelectedMode},
269                    isEnteringPhoto: ${this.isEnteringPhoto}, ${JSON.stringify(event)}`);
270            if (this.isSelectedMode) {
271                return;
272            }
273
274            // Press animation
275            if (event.type == TouchType.Down) {
276                this.pressAnimScale = AnimationConstants.PRESS_ANIM_SCALE;
277            }
278
279            if (event.type == TouchType.Up && !this.isEnteringPhoto && this.pressAnimScale != 1) {
280                this.pressAnimScale = 1;
281            }
282        })
283        .gesture(LongPressGesture().onAction((event: GestureEvent) => {
284            if (!this.isThird) {
285                Log.info(TAG, `LongPressGesture ${this.isSelectedMode}`);
286                this.selectStateChange();
287            }
288        }))
289    }
290}