update_dialog.dart 6.8 KB
import 'dart:io';

import 'package:apk_update/utils/image_utils.dart';
import 'package:dio/dio.dart';
import 'package:flustars_flutter3/flustars_flutter3.dart';
import 'package:flutter/material.dart';

class UpdateDialog extends StatefulWidget {
  final String? title; // 升级版本
  final String? content; // 升级内容
  final bool isUpdateMore; // 是否强升
  final String? versionPath; // apk 路径
  final Function()? jumpAppStore; // 跳转AppStore
  final Function(String? path)? installApk; // 安装Apk
  final Function()? downloadApkError; // 下载Apk错误

  const UpdateDialog({
    Key? key,
    this.title,
    this.content,
    this.isUpdateMore = false,
    this.versionPath,
    this.jumpAppStore,
    this.installApk,
    this.downloadApkError,
  }) : super(key: key);

  @override
  State<UpdateDialog> createState() => _UpdateDialogState();
}

class _UpdateDialogState extends State<UpdateDialog> {
  final CancelToken _cancelToken = CancelToken();
  bool _isDownload = false;
  double _value = 0;

  @override
  void dispose() {
    if (!_cancelToken.isCancelled && _value != 1) {
      _cancelToken.cancel();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () => Future.value(false), //使用false禁止返回键返回,达到强制升级目的
      child: Scaffold(
        resizeToAvoidBottomInset: false,
        backgroundColor: Colors.transparent,
        body: Center(
          child: Container(
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(8.0),
            ),
            width: 280.0,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                // 顶部图片
                _topImage(),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 15.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      // 标题
                      _content(title: widget.title, content: widget.content),
                      _isDownload
                          // 下载进度
                          ? LinearProgressIndicator(
                              backgroundColor: const Color(0xFFF2F3F3),
                              value: _value,
                            )
                          // 按钮
                          : Row(
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
                              children: <Widget>[
                                Offstage(
                                  offstage: widget.isUpdateMore,
                                  child: _btn(
                                    title: '残忍拒绝',
                                    textColor: Theme.of(context).primaryColor,
                                    bgColor: Colors.transparent,
                                    onTap: () => Navigator.pop(context),
                                  ),
                                ),
                                _btn(
                                  title: '立即更新',
                                  onTap: () {
                                    if (Platform.isIOS) {
                                      Navigator.pop(context);
                                      widget.jumpAppStore?.call();
                                    } else {
                                      setState(() {
                                        _isDownload = true;
                                      });
                                      _download();
                                    }
                                  },
                                )
                              ],
                            ),
                      const SizedBox(height: 15.0),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  /// 顶部图片
  Widget _topImage() => Container(
        height: 140.0,
        width: 280.0,
        decoration: BoxDecoration(
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(8.0),
            topRight: Radius.circular(8.0),
          ),
          image: DecorationImage(
            image: ImageUtils.getAssetImage('update_head'),
            fit: BoxFit.cover,
          ),
        ),
      );

  /// 标题、内容
  Widget _content({String? title, String? content}) => Column(
        children: [
          const SizedBox(height: 15.0),
          // 标题
          Text(
            title ?? "",
            style: const TextStyle(
              fontSize: 15.0,
              color: Color(0xFF333C4C),
            ),
          ),
          const SizedBox(height: 5.0),
          // 内容
          Text(
            content ?? "",
            style: const TextStyle(fontSize: 15.0, color: Color(0xFF4E5969)),
          ),
          const SizedBox(height: 15.0),
        ],
      );

  /// 按钮
  Widget _btn({
    String? title,
    GestureTapCallback? onTap,
    Color? textColor,
    Color? bgColor,
  }) =>
      InkWell(
        onTap: onTap,
        child: Container(
          width: 110.0,
          constraints: const BoxConstraints(minHeight: 36.0),
          alignment: Alignment.center,
          decoration: BoxDecoration(
            color: bgColor ?? Theme.of(context).primaryColor,
            borderRadius: BorderRadius.circular(20.0),
            border: Border.all(color: Theme.of(context).primaryColor),
          ),
          child: Text(
            title ?? "",
            style: TextStyle(fontSize: 15.0, color: textColor ?? Colors.white),
          ),
        ),
      );

  ///下载apk
  Future<void> _download() async {
    try {
      setInitDir(initStorageDir: true);
      await DirectoryUtil.getInstance();
      DirectoryUtil.createStorageDirSync(category: 'Download');
      String path = DirectoryUtil.getStoragePath(
          fileName: 'clx_update', category: 'Download', format: 'apk')!;
      File file = File(path);
      debugPrint("===== Apk下载路径:$path");
      /// 链接可能会失效
      await Dio().download(
        widget.versionPath!,
        file.path,
        cancelToken: _cancelToken,
        onReceiveProgress: (int count, int total) {
          if (total != -1) {
            _value = count / total;
            setState(() {});
            if (count == total) {
              debugPrint("===== Apk下载完成");
              Navigator.pop(context);
              widget.installApk?.call(path);
            }
          }
        },
      );
    } catch (e) {
      widget.downloadApkError?.call();
      debugPrint("===== Apk下载错误: $e");
      setState(() {
        _isDownload = false;
      });
    }
  }
}