100aff185Sopenharmony_ci/* 200aff185Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd. 300aff185Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 400aff185Sopenharmony_ci * you may not use this file except in compliance with the License. 500aff185Sopenharmony_ci * You may obtain a copy of the License at 600aff185Sopenharmony_ci * 700aff185Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 800aff185Sopenharmony_ci * 900aff185Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1000aff185Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1100aff185Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1200aff185Sopenharmony_ci * See the License for the specific language governing permissions and 1300aff185Sopenharmony_ci * limitations under the License. 1400aff185Sopenharmony_ci */ 1500aff185Sopenharmony_ci 1600aff185Sopenharmony_ciimport type { BrowserDataInterface, PendingCondition } from '@ohos/common'; 1700aff185Sopenharmony_ciimport { 1800aff185Sopenharmony_ci BroadCast, 1900aff185Sopenharmony_ci BrowserDataFactory, 2000aff185Sopenharmony_ci CommonObserverCallback, 2100aff185Sopenharmony_ci Constants, 2200aff185Sopenharmony_ci DateUtil, 2300aff185Sopenharmony_ci Log, 2400aff185Sopenharmony_ci MediaDataSource, 2500aff185Sopenharmony_ci MediaItem, 2600aff185Sopenharmony_ci MediaObserver, 2700aff185Sopenharmony_ci PendingTask, 2800aff185Sopenharmony_ci TimelineData, 2900aff185Sopenharmony_ci TraceControllerUtils, 3000aff185Sopenharmony_ci ViewData, 3100aff185Sopenharmony_ci ViewType 3200aff185Sopenharmony_ci} from '@ohos/common'; 3300aff185Sopenharmony_ciimport { GetTimelineDataCallback } from './GetTimelineDataCallback'; 3400aff185Sopenharmony_ci 3500aff185Sopenharmony_ciconst TITLE_DATA_INDEX = -1; 3600aff185Sopenharmony_ciconst TAG: string = 'timeline_TimelineDataSource'; 3700aff185Sopenharmony_ci 3800aff185Sopenharmony_ci// TimelineDataSource 3900aff185Sopenharmony_ciexport class TimelineDataSource extends MediaDataSource { 4000aff185Sopenharmony_ci initDataTraceName = 'TimeLinePageInitData'; 4100aff185Sopenharmony_ci dataObserver: CommonObserverCallback = new CommonObserverCallback(this); 4200aff185Sopenharmony_ci groups: TimelineData[] = []; 4300aff185Sopenharmony_ci 4400aff185Sopenharmony_ci // layoutIndex to groupIndex 4500aff185Sopenharmony_ci groupIndexes: number[] = []; 4600aff185Sopenharmony_ci groupViewIndexes: number[] = []; 4700aff185Sopenharmony_ci isActive = false; 4800aff185Sopenharmony_ci pendingEmitCallbacks: PendingTask; 4900aff185Sopenharmony_ci groupBrowserDataImpl: BrowserDataInterface; 5000aff185Sopenharmony_ci 5100aff185Sopenharmony_ci constructor(windowSize: number, broadCast: BroadCast) { 5200aff185Sopenharmony_ci super(windowSize); 5300aff185Sopenharmony_ci this.groupBrowserDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_GROUP); 5400aff185Sopenharmony_ci this.broadCast = broadCast; 5500aff185Sopenharmony_ci this.pendingEmitCallbacks = new PendingTask(<PendingCondition> { 5600aff185Sopenharmony_ci shouldPending: () => { 5700aff185Sopenharmony_ci return !this.isActive; 5800aff185Sopenharmony_ci } 5900aff185Sopenharmony_ci }); 6000aff185Sopenharmony_ci this.initData(); 6100aff185Sopenharmony_ci } 6200aff185Sopenharmony_ci 6300aff185Sopenharmony_ci initialize(): void { 6400aff185Sopenharmony_ci } 6500aff185Sopenharmony_ci 6600aff185Sopenharmony_ci getGroupData(): TimelineData[] { 6700aff185Sopenharmony_ci return this.groups; 6800aff185Sopenharmony_ci } 6900aff185Sopenharmony_ci 7000aff185Sopenharmony_ci loadData() { 7100aff185Sopenharmony_ci let callback: GetTimelineDataCallback = new GetTimelineDataCallback(this); 7200aff185Sopenharmony_ci this.groupBrowserDataImpl.getData(callback, null); 7300aff185Sopenharmony_ci } 7400aff185Sopenharmony_ci 7500aff185Sopenharmony_ci public registerTimelineObserver(): void { 7600aff185Sopenharmony_ci MediaObserver.getInstance().registerObserver(this.dataObserver); 7700aff185Sopenharmony_ci } 7800aff185Sopenharmony_ci 7900aff185Sopenharmony_ci public unregisterTimelineObserver(): void { 8000aff185Sopenharmony_ci MediaObserver.getInstance().unregisterObserver(this.dataObserver); 8100aff185Sopenharmony_ci } 8200aff185Sopenharmony_ci 8300aff185Sopenharmony_ci onMediaLibDataChange(changeType: string): void { 8400aff185Sopenharmony_ci Log.info(TAG, `onMediaLibDataChange type: ${changeType}`); 8500aff185Sopenharmony_ci if (!this.isActive) { 8600aff185Sopenharmony_ci this.pendingEmitCallbacks.clear(); 8700aff185Sopenharmony_ci } 8800aff185Sopenharmony_ci this.switchRefreshOn(); 8900aff185Sopenharmony_ci this.onChange(changeType); 9000aff185Sopenharmony_ci } 9100aff185Sopenharmony_ci 9200aff185Sopenharmony_ci updateGroupData(requestTime: number, groups: TimelineData[]): void { 9300aff185Sopenharmony_ci TraceControllerUtils.startTraceWithTaskId('updateGroupData', requestTime); 9400aff185Sopenharmony_ci Log.info(TAG, 'updateGroupData begin'); 9500aff185Sopenharmony_ci this.lastUpdateTime = requestTime; 9600aff185Sopenharmony_ci 9700aff185Sopenharmony_ci this.isPendingUpdateData = true; 9800aff185Sopenharmony_ci this.pendingEmitCallbacks.execute(() => { 9900aff185Sopenharmony_ci this.updateGroupSize(requestTime, groups); 10000aff185Sopenharmony_ci }) 10100aff185Sopenharmony_ci 10200aff185Sopenharmony_ci TraceControllerUtils.finishTraceWithTaskId('updateGroupData', requestTime); 10300aff185Sopenharmony_ci this.isPendingUpdateData = false; 10400aff185Sopenharmony_ci this.pendingUpdateData.flush(); 10500aff185Sopenharmony_ci 10600aff185Sopenharmony_ci } 10700aff185Sopenharmony_ci 10800aff185Sopenharmony_ci /** 10900aff185Sopenharmony_ci * Update related variables of group count 11000aff185Sopenharmony_ci * 11100aff185Sopenharmony_ci * @param requestTime 11200aff185Sopenharmony_ci * @param groups 11300aff185Sopenharmony_ci */ 11400aff185Sopenharmony_ci updateGroupSize(requestTime: number, groups: TimelineData[]): void { 11500aff185Sopenharmony_ci Log.info(TAG, 'updateGroupSize'); 11600aff185Sopenharmony_ci let previousSize: number = this.size; 11700aff185Sopenharmony_ci let previousMediaCount = this.mediaCount; 11800aff185Sopenharmony_ci this.groups = groups; 11900aff185Sopenharmony_ci this.mCallbacks['updateGroupData'] && this.mCallbacks['updateGroupData'](this.groups) 12000aff185Sopenharmony_ci this.size = 0; 12100aff185Sopenharmony_ci this.mediaCount = 0; 12200aff185Sopenharmony_ci this.dataIndexes = []; 12300aff185Sopenharmony_ci this.layoutIndexes = []; 12400aff185Sopenharmony_ci this.groupIndexes = []; 12500aff185Sopenharmony_ci this.groupViewIndexes = []; 12600aff185Sopenharmony_ci let dataIndex = 0; 12700aff185Sopenharmony_ci for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) { 12800aff185Sopenharmony_ci let group = groups[groupIndex]; 12900aff185Sopenharmony_ci this.mediaCount += group.count; 13000aff185Sopenharmony_ci 13100aff185Sopenharmony_ci // title 13200aff185Sopenharmony_ci this.size++; 13300aff185Sopenharmony_ci this.dataIndexes.push(TITLE_DATA_INDEX); 13400aff185Sopenharmony_ci this.groupIndexes.push(groupIndex); 13500aff185Sopenharmony_ci this.groupViewIndexes.push(TITLE_DATA_INDEX); 13600aff185Sopenharmony_ci 13700aff185Sopenharmony_ci // items 13800aff185Sopenharmony_ci for (let i = 0; i < group.count; i++) { 13900aff185Sopenharmony_ci this.dataIndexes.push(dataIndex); 14000aff185Sopenharmony_ci this.groupIndexes.push(groupIndex); 14100aff185Sopenharmony_ci this.layoutIndexes.push(this.size); 14200aff185Sopenharmony_ci this.groupViewIndexes.push(i); 14300aff185Sopenharmony_ci this.size++; 14400aff185Sopenharmony_ci dataIndex++; 14500aff185Sopenharmony_ci } 14600aff185Sopenharmony_ci } 14700aff185Sopenharmony_ci 14800aff185Sopenharmony_ci Log.info(TAG, `updateGroupSize, old size: ${previousSize} , old mediaCount: ${previousMediaCount},\ 14900aff185Sopenharmony_ci new size: ${this.size}, new mediaCount: ${this.mediaCount}, real size: ${this.realSize}`); 15000aff185Sopenharmony_ci 15100aff185Sopenharmony_ci this.isCountChanged = previousSize != this.size; 15200aff185Sopenharmony_ci this.isCountReduced = previousSize > this.size; 15300aff185Sopenharmony_ci if (requestTime !== Constants.NUMBER_0) { 15400aff185Sopenharmony_ci this.addedCount = (this.realSize > Constants.NUMBER_0) ? (this.size - this.realSize) : Constants.NUMBER_0; 15500aff185Sopenharmony_ci this.realSize = this.size; 15600aff185Sopenharmony_ci } 15700aff185Sopenharmony_ci this.updateCountPostProcess(); 15800aff185Sopenharmony_ci } 15900aff185Sopenharmony_ci 16000aff185Sopenharmony_ci emitCountUpdateCallbacks(): void { 16100aff185Sopenharmony_ci this.pendingEmitCallbacks.execute(() => { 16200aff185Sopenharmony_ci super.emitCountUpdateCallbacks(); 16300aff185Sopenharmony_ci }) 16400aff185Sopenharmony_ci } 16500aff185Sopenharmony_ci 16600aff185Sopenharmony_ci updateCountThroughMediaItems(requestTime: number, mediaItems: MediaItem[]): void { 16700aff185Sopenharmony_ci Log.info(TAG, 'updateCountThroughMediaItems'); 16800aff185Sopenharmony_ci this.updateGroupSize(0, this.getGroupDataThroughMediaItems(mediaItems)); 16900aff185Sopenharmony_ci } 17000aff185Sopenharmony_ci 17100aff185Sopenharmony_ci // Get grouping information through media item 17200aff185Sopenharmony_ci getGroupDataThroughMediaItems(mediaItems: MediaItem[]): TimelineData[] { 17300aff185Sopenharmony_ci Log.info(TAG, 'getGroupDataThroughMediaItems'); 17400aff185Sopenharmony_ci let groupDataList: TimelineData[] = []; 17500aff185Sopenharmony_ci if (mediaItems == null || mediaItems.length == 0) { 17600aff185Sopenharmony_ci Log.error(TAG, 'getGroupDataThroughMediaItems, mediaItems are empty!'); 17700aff185Sopenharmony_ci return groupDataList; 17800aff185Sopenharmony_ci } 17900aff185Sopenharmony_ci let groupCount = 1; 18000aff185Sopenharmony_ci let startTime = mediaItems[0].getDataTaken(); 18100aff185Sopenharmony_ci let endTime = mediaItems[0].getDataTaken(); 18200aff185Sopenharmony_ci for (let i = 1; i < mediaItems.length; i++) { 18300aff185Sopenharmony_ci let dateTaken = mediaItems[i].getDataTaken(); 18400aff185Sopenharmony_ci if (DateUtil.isTheSameDay(startTime, dateTaken)) { 18500aff185Sopenharmony_ci groupCount++; 18600aff185Sopenharmony_ci endTime = dateTaken; 18700aff185Sopenharmony_ci } else { 18800aff185Sopenharmony_ci let groupData = new TimelineData(startTime, endTime, groupCount); 18900aff185Sopenharmony_ci groupDataList.push(groupData); 19000aff185Sopenharmony_ci groupCount = 1; 19100aff185Sopenharmony_ci startTime = dateTaken; 19200aff185Sopenharmony_ci endTime = dateTaken; 19300aff185Sopenharmony_ci } 19400aff185Sopenharmony_ci } 19500aff185Sopenharmony_ci let groupData = new TimelineData(startTime, endTime, groupCount); 19600aff185Sopenharmony_ci groupDataList.push(groupData); 19700aff185Sopenharmony_ci return groupDataList; 19800aff185Sopenharmony_ci } 19900aff185Sopenharmony_ci 20000aff185Sopenharmony_ci // Packaging data for the view layer 20100aff185Sopenharmony_ci getWrappedData(index: number): ViewData { 20200aff185Sopenharmony_ci if (index < 0 || index >= this.dataIndexes.length) { 20300aff185Sopenharmony_ci Log.error(TAG, `getWrappedData, index out of the total size, index: ${index}, 20400aff185Sopenharmony_ci total size: ${this.dataIndexes.length}`); 20500aff185Sopenharmony_ci return undefined; 20600aff185Sopenharmony_ci } 20700aff185Sopenharmony_ci // title 20800aff185Sopenharmony_ci if (this.dataIndexes[index] == TITLE_DATA_INDEX) { 20900aff185Sopenharmony_ci let result: ViewData = { 21000aff185Sopenharmony_ci viewType: ViewType.GROUP_TITLE, 21100aff185Sopenharmony_ci viewData: this.groups[this.groupIndexes[index]], 21200aff185Sopenharmony_ci viewIndex: this.groupIndexes[index], 21300aff185Sopenharmony_ci }; 21400aff185Sopenharmony_ci Log.debug(TAG, `index: ${index}, type: ${result.viewType},\ 21500aff185Sopenharmony_ci data: ${result.viewData.startDate}, viewIndex: ${result.viewIndex}`); 21600aff185Sopenharmony_ci return result; 21700aff185Sopenharmony_ci } else { 21800aff185Sopenharmony_ci let dataIndexInWindow = this.dataIndexes[index] - this.activeStart; 21900aff185Sopenharmony_ci let result: ViewData; 22000aff185Sopenharmony_ci if (dataIndexInWindow > this.items.length || dataIndexInWindow < 0) { 22100aff185Sopenharmony_ci Log.error(TAG, 'index out of active window'); 22200aff185Sopenharmony_ci return undefined; 22300aff185Sopenharmony_ci } else { 22400aff185Sopenharmony_ci result = { 22500aff185Sopenharmony_ci viewType: ViewType.ITEM, 22600aff185Sopenharmony_ci mediaItem: this.getMediaItemSafely(dataIndexInWindow), 22700aff185Sopenharmony_ci viewIndex: index, 22800aff185Sopenharmony_ci indexInGroup: this.groupViewIndexes[index] 22900aff185Sopenharmony_ci }; 23000aff185Sopenharmony_ci } 23100aff185Sopenharmony_ci Log.debug(TAG, `index: ${index}, type: ${result.viewType},\ 23200aff185Sopenharmony_ci data: ${result.mediaItem.uri} indexInGroup: ${result.indexInGroup}`); 23300aff185Sopenharmony_ci return result; 23400aff185Sopenharmony_ci } 23500aff185Sopenharmony_ci } 23600aff185Sopenharmony_ci 23700aff185Sopenharmony_ci getPositionByIndex(index: number): number { 23800aff185Sopenharmony_ci let pos = (this.dataIndexes || []).findIndex((item) => item === index); 23900aff185Sopenharmony_ci Log.info(TAG, `pos ${index}, ${this.dataIndexes[pos]} , ${this.groupIndexes[pos]}`); 24000aff185Sopenharmony_ci return this.dataIndexes[pos] + this.groupIndexes[pos] + 1; 24100aff185Sopenharmony_ci } 24200aff185Sopenharmony_ci 24300aff185Sopenharmony_ci getMediaItemByPosition(position: number): MediaItem { 24400aff185Sopenharmony_ci // title 24500aff185Sopenharmony_ci let index = position 24600aff185Sopenharmony_ci if (this.dataIndexes[position] == TITLE_DATA_INDEX) { 24700aff185Sopenharmony_ci index = index + 1 24800aff185Sopenharmony_ci } 24900aff185Sopenharmony_ci let dataIndexInWindow = this.dataIndexes[index] - this.activeStart; 25000aff185Sopenharmony_ci if (dataIndexInWindow > this.items.length || dataIndexInWindow < 0) { 25100aff185Sopenharmony_ci Log.error(TAG, 'index out of active window'); 25200aff185Sopenharmony_ci return undefined; 25300aff185Sopenharmony_ci } else { 25400aff185Sopenharmony_ci return this.getMediaItemSafely(dataIndexInWindow) 25500aff185Sopenharmony_ci } 25600aff185Sopenharmony_ci } 25700aff185Sopenharmony_ci 25800aff185Sopenharmony_ci onPhotoBrowserActive(isActive: boolean, transition: string): void { 25900aff185Sopenharmony_ci Log.debug(TAG, `onPhotoBrowserActive ${isActive}, ${transition}`); 26000aff185Sopenharmony_ci if (transition == Constants.PHOTO_TRANSITION_TIMELINE) { 26100aff185Sopenharmony_ci if (isActive) { 26200aff185Sopenharmony_ci this.onActive(); 26300aff185Sopenharmony_ci } else { 26400aff185Sopenharmony_ci this.onInActive(); 26500aff185Sopenharmony_ci } 26600aff185Sopenharmony_ci } else if (transition == Constants.PHOTO_TRANSITION_EDIT) { 26700aff185Sopenharmony_ci if (isActive) { 26800aff185Sopenharmony_ci this.isEditSaveReload = true; 26900aff185Sopenharmony_ci this.onActive(); 27000aff185Sopenharmony_ci } else { 27100aff185Sopenharmony_ci this.isEditSaveReload = false; 27200aff185Sopenharmony_ci } 27300aff185Sopenharmony_ci } 27400aff185Sopenharmony_ci } 27500aff185Sopenharmony_ci 27600aff185Sopenharmony_ci onActive(): void { 27700aff185Sopenharmony_ci super.onActive(); 27800aff185Sopenharmony_ci this.pendingEmitCallbacks.flush(); 27900aff185Sopenharmony_ci } 28000aff185Sopenharmony_ci 28100aff185Sopenharmony_ci getGroupCountBeforeItem(item: MediaItem): number { 28200aff185Sopenharmony_ci let groupCount = 0; 28300aff185Sopenharmony_ci if (!item) { 28400aff185Sopenharmony_ci return groupCount; 28500aff185Sopenharmony_ci } 28600aff185Sopenharmony_ci let itemTime: number = item.getDataTaken(); 28700aff185Sopenharmony_ci for (let index = 0; index < this.groups.length; index++) { 28800aff185Sopenharmony_ci const group: TimelineData = this.groups[index]; 28900aff185Sopenharmony_ci if (DateUtil.isTheSameDay(itemTime, group.startDate)) { 29000aff185Sopenharmony_ci groupCount = index + 1; 29100aff185Sopenharmony_ci break; 29200aff185Sopenharmony_ci } 29300aff185Sopenharmony_ci } 29400aff185Sopenharmony_ci return groupCount; 29500aff185Sopenharmony_ci } 29600aff185Sopenharmony_ci} 297