• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (c) 2023 Hunan OpenValley Digital Industry Development 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 common from '@ohos.app.ability.common'
16import request from '@ohos.request';
17import fs from '@ohos.file.fs';
18import emitter from '@ohos.events.emitter'
19import CostTimeCompute from '../feature/CostTimeCompute'
20import Logger from '../util/Logger'
21
22@Preview
23@Component
24export default struct DownloadController {
25  @StorageProp('currentBreakpoint') curBp: string = 'sm'
26  fileName: string = ""
27  downloadUrl: string = "";
28  downloadTask: request.DownloadTask = null;
29  downloadPath: string = null;
30  @State isDownloading: boolean = false;
31  @State isCompleted: boolean = false;
32  @State isPausing: boolean = false;
33  @State progress: number = 0;
34  @State total: number = 1;
35  @State speed: string = "0B/s";
36  //  剩余时间计算
37  @State lastTimeStr: string = "";
38  @State isError: boolean = false;
39  costTimeCompute: CostTimeCompute = null;
40
41  aboutToAppear() {
42    Logger.debug("register fileName = " + this.fileName);
43    //定义计算器
44    this.costTimeCompute = new CostTimeCompute(
45      (str) => {
46        this.lastTimeStr = str;
47      },
48      () => {
49        return this.progress;
50      },
51      () => {
52        return this.total;
53      },
54      null,
55      false,
56      (str) => {
57        this.speed = str;
58      }
59    );
60    this.getDownloadPath();
61    fs.access(this.downloadPath)
62      .then(isExist => {
63        if (isExist) {
64          this.isCompleted = true;
65        }
66        //下载监听,在文件检测之后,再注册
67        this.addEventListener();
68      }).catch(err => {
69      Logger.error(err)
70    })
71  }
72
73  addEventListener() {
74    emitter.on({ eventId: 2 }, () => {
75      this.startDownload();
76    })
77  }
78
79  aboutToDisappear() {
80    this.costTimeCompute.cancelCostTime();
81    this.cancel();
82  }
83
84  getDownloadPath() {
85    if (this.downloadPath == null) {
86      let context: common.Context = getContext(this) as common.Context;
87      this.downloadPath = context.cacheDir + "/" + this.fileName;
88      Logger.debug("download file path =" + this.downloadPath)
89    }
90  }
91
92  restart() {
93    this.cancel(true);
94  }
95
96  async startDownload() {
97    if (this.isDownloading || this.isCompleted) {
98      return;
99    }
100    this.isError = false;
101    let context: common.Context = getContext(this) as common.Context;
102    this.getDownloadPath();
103    try {
104      this.downloadTask = await request.downloadFile(context, { url: this.downloadUrl, filePath: this.downloadPath })
105      this.isDownloading = true;
106      this.addListener();
107
108      this.costTimeCompute.startCostTime();
109    } catch (err) {
110      Logger.debug("start download failed,err = " + err)
111      this.onFail();
112    }
113  }
114
115  pauseOrPlay() {
116    if (this.downloadTask == null || !this.isDownloading) {
117      return;
118    }
119    if (this.isPausing) {
120      this.downloadTask.restore(() => {
121        this.isPausing = false;
122      });
123      this.costTimeCompute.startCostTime();
124    } else {
125      this.downloadTask.suspend(() => {
126        this.isPausing = true;
127      })
128      this.costTimeCompute.pauseCostTime();
129    }
130  }
131
132  cancel(restart: boolean = false) {
133    if (this.downloadTask == null || this.isCompleted) {
134      return;
135    }
136    this.isPausing = false;
137    this.isError = false;
138    this.downloadTask.delete(() => {
139      this.costTimeCompute.cancelCostTime();
140      let isExist = fs.accessSync(this.downloadPath);
141      if (isExist) {
142        fs.unlink(this.downloadPath).then(() => {
143          this.reset(restart);
144        })
145      } else {
146        this.reset(restart);
147      }
148    })
149  }
150
151  reset(restart: boolean) {
152    this.isDownloading = false;
153    this.progress = 0;
154    this.total = 1;
155    if (restart) {
156      setTimeout(() => this.startDownload(), 600);
157    }
158  }
159
160  addListener() {
161    if (this.downloadTask == null) {
162      return;
163    }
164    this.downloadTask.on("progress", (receivedSize, totalSize) => {
165      this.progress = receivedSize;
166      this.total = totalSize;
167    })
168    this.downloadTask.on('complete', () => {
169      this.isDownloading = false;
170      this.isCompleted = true;
171      this.costTimeCompute.cancelCostTime();
172    })
173    this.downloadTask.on('fail', err => {
174      Logger.error("下载失败:" + err)
175      this.onFail();
176    })
177  }
178
179  private onFail() {
180    this.cancel();
181    this.isError = true;
182  }
183
184  getTimeLastTip() {
185    let context: common.Context = getContext(this) as common.Context;
186    let lastTime = context.resourceManager.getStringSync($r('app.string.tip_last_time'));
187    let computingStr = context.resourceManager.getStringSync($r('app.string.tip_computing'));
188    return lastTime + ((this.lastTimeStr != null && this.lastTimeStr.length > 0) ? this.lastTimeStr : computingStr);
189  }
190
191  getProgressPercent(): string {
192    switch (this.curBp) {
193      case 'lg':
194        return "80%";
195      case 'md':
196      case 'xs':
197      case 'sm':
198      default:
199        return "65%"
200    }
201  }
202
203  build() {
204    if (this.isDownloading || this.isError || this.isCompleted) {
205      Row() {
206        Column({ space: 10 }) {
207          Text(this.fileName)
208            .fontSize($r('app.float.download_file_name_font_size'))
209          if (!this.isCompleted) {
210            Progress({ value: this.progress, total: this.total, type: ProgressType.Capsule })
211              .height($r('app.float.download_progress_height'))
212              .width('100%')
213              .align(Alignment.Center)
214          }
215          if (this.isPausing) {
216            Text($r("app.string.tip_paused"))
217              .fontSize($r('app.float.download_tip_font_size'))
218              .fontColor($r('app.color.download_font_color'))
219          } else {
220            if (this.isError || this.isCompleted) {
221              Text(this.isCompleted ? $r('app.string.download_success') : $r('app.string.download_fail'))
222                .fontColor(this.isCompleted ? $r('app.color.download_font_color') : $r('app.color.upload_error_color'))
223                .fontSize($r('app.float.download_tip_font_size'))
224            } else {
225              Row() {
226                Text(this.speed)
227                  .fontColor($r('app.color.download_font_color'))
228                  .fontSize($r('app.float.download_tip_font_size'))
229                Blank()
230                Text(this.getTimeLastTip())
231                  .fontColor($r('app.color.download_font_color'))
232                  .fontSize($r('app.float.download_tip_font_size'))
233              }.width('100%')
234            }
235          }
236        }
237        .width(this.getProgressPercent())
238        .alignItems(HorizontalAlign.Start)
239
240        Blank()
241        if (!this.isCompleted) {
242          Row({ space: 15 }) {
243            if (this.isError) {
244              Image($r("app.media.ic_public_reset"))
245                .width($r('app.float.download_icon_size'))
246                .aspectRatio(1)
247                .onClick(() => {
248                  this.restart();
249                })
250            } else {
251              Image(this.isPausing ? $r("app.media.ic_public_play_norm") : $r("app.media.ic_public_pause_norm"))
252                .width($r('app.float.download_icon_size'))
253                .aspectRatio(1)
254                .onClick(() => {
255                  this.pauseOrPlay();
256                })
257            }
258            Image($r("app.media.ic_public_close"))
259              .width($r('app.float.download_icon_size'))
260              .aspectRatio(1)
261              .onClick(() => {
262                this.cancel();
263              })
264          }
265        }
266      }.width("100%")
267      .height('100%')
268      .alignItems(VerticalAlign.Center)
269    } else {
270      Row() {
271        Text(this.fileName)
272          .fontSize($r('app.float.download_file_name_font_size'))
273        Blank()
274        Image($r("app.media.ic_public_download"))
275          .onClick(() => {
276            this.startDownload()
277          })
278          .width($r('app.float.download_icon_size'))
279          .aspectRatio(1)
280      }
281      .width('100%')
282      .height('100%')
283      .alignItems(VerticalAlign.Center)
284    }
285  }
286}