Sfoglia il codice sorgente

Enable auto update checks

Vishnu Mohandas 4 anni fa
parent
commit
31de45bf1c
5 ha cambiato i file con 231 aggiunte e 0 eliminazioni
  1. 61 0
      lib/services/update_service.dart
  2. 148 0
      lib/ui/app_update_dialog.dart
  3. 14 0
      lib/ui/home_widget.dart
  4. 7 0
      pubspec.lock
  5. 1 0
      pubspec.yaml

+ 61 - 0
lib/services/update_service.dart

@@ -0,0 +1,61 @@
+import 'dart:io';
+
+import 'package:package_info_plus/package_info_plus.dart';
+import 'package:photos/core/network.dart';
+
+class UpdateService {
+  UpdateService._privateConstructor();
+  static final UpdateService instance = UpdateService._privateConstructor();
+
+  LatestVersionInfo _latestVersion;
+
+  Future<bool> shouldUpdate() async {
+    if (Platform.isIOS) {
+      return false;
+    }
+    _latestVersion = await _getLatestVersionInfo();
+    final currentVersionCode =
+        int.parse((await PackageInfo.fromPlatform()).buildNumber);
+    return currentVersionCode < _latestVersion.code;
+  }
+
+  LatestVersionInfo getLatestVersionInfo() {
+    return _latestVersion;
+  }
+
+  Future<LatestVersionInfo> _getLatestVersionInfo() async {
+    final response = await Network.instance
+        .getDio()
+        .get("https://android.ente.io/release-info.json");
+    return LatestVersionInfo.fromMap(response.data["latestVersion"]);
+  }
+}
+
+class LatestVersionInfo {
+  final String name;
+  final int code;
+  final List<String> changelog;
+  final bool shouldForceUpdate;
+  final String url;
+  final int size;
+
+  LatestVersionInfo(
+    this.name,
+    this.code,
+    this.changelog,
+    this.shouldForceUpdate,
+    this.url,
+    this.size,
+  );
+
+  factory LatestVersionInfo.fromMap(Map<String, dynamic> map) {
+    return LatestVersionInfo(
+      map['name'],
+      map['code'],
+      List<String>.from(map['changelog']),
+      map['shouldForceUpdate'],
+      map['url'],
+      map['size'],
+    );
+  }
+}

+ 148 - 0
lib/ui/app_update_dialog.dart

@@ -0,0 +1,148 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:logging/logging.dart';
+import 'package:open_file/open_file.dart';
+import 'package:photos/core/configuration.dart';
+import 'package:photos/core/network.dart';
+import 'package:photos/services/update_service.dart';
+import 'package:photos/ui/common_elements.dart';
+import 'package:photos/utils/dialog_util.dart';
+
+class AppUpdateDialog extends StatefulWidget {
+  final LatestVersionInfo latestVersionInfo;
+
+  AppUpdateDialog(this.latestVersionInfo, {Key key}) : super(key: key);
+
+  @override
+  _AppUpdateDialogState createState() => _AppUpdateDialogState();
+}
+
+class _AppUpdateDialogState extends State<AppUpdateDialog> {
+  @override
+  Widget build(BuildContext context) {
+    final List<Widget> changelog = [];
+    for (final log in widget.latestVersionInfo.changelog) {
+      changelog.add(Padding(
+        padding: const EdgeInsets.fromLTRB(8, 4, 0, 4),
+        child: Text("- " + log,
+            style: TextStyle(
+              fontSize: 14,
+              color: Colors.white.withOpacity(0.7),
+            )),
+      ));
+    }
+    final content = Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      mainAxisSize: MainAxisSize.min,
+      children: [
+        Text(
+          widget.latestVersionInfo.name,
+          style: TextStyle(
+            fontSize: 20,
+            fontWeight: FontWeight.bold,
+          ),
+        ),
+        Padding(padding: EdgeInsets.all(8)),
+        Text("changelog",
+            style: TextStyle(
+              fontSize: 18,
+            )),
+        Padding(padding: EdgeInsets.all(4)),
+        Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: changelog,
+        ),
+        Padding(padding: EdgeInsets.all(8)),
+        Container(
+          width: double.infinity,
+          height: 64,
+          padding: const EdgeInsets.fromLTRB(64, 0, 64, 0),
+          child: button(
+            "update",
+            fontSize: 16,
+            onPressed: () async {
+              Navigator.pop(context);
+              showDialog(
+                context: context,
+                builder: (BuildContext context) {
+                  return ApkDownloaderDialog(widget.latestVersionInfo);
+                },
+                barrierDismissible: false,
+              );
+            },
+          ),
+        ),
+      ],
+    );
+    return WillPopScope(
+      onWillPop: () async => !widget.latestVersionInfo.shouldForceUpdate,
+      child: AlertDialog(
+        title: Text("update available"),
+        content: content,
+      ),
+    );
+  }
+}
+
+class ApkDownloaderDialog extends StatefulWidget {
+  final LatestVersionInfo versionInfo;
+
+  ApkDownloaderDialog(this.versionInfo, {Key key}) : super(key: key);
+
+  @override
+  _ApkDownloaderDialogState createState() => _ApkDownloaderDialogState();
+}
+
+class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
+  String _saveUrl;
+  double _downloadProgress;
+
+  @override
+  void initState() {
+    super.initState();
+    _saveUrl = Configuration.instance.getTempDirectory() +
+        "ente-" +
+        widget.versionInfo.name +
+        ".apk";
+    _downloadApk();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return WillPopScope(
+      onWillPop: () async => false,
+      child: AlertDialog(
+        title: Text(
+          "downloading...",
+          style: TextStyle(
+            fontSize: 16,
+          ),
+          textAlign: TextAlign.center,
+        ),
+        content: LinearProgressIndicator(
+          value: _downloadProgress,
+          valueColor:
+              AlwaysStoppedAnimation<Color>(Theme.of(context).buttonColor),
+        ),
+      ),
+    );
+  }
+
+  Future<void> _downloadApk() async {
+    try {
+      await Network.instance.getDio().download(widget.versionInfo.url, _saveUrl,
+          onReceiveProgress: (count, _) {
+        setState(() {
+          _downloadProgress = count / widget.versionInfo.size;
+        });
+      });
+    } catch (e) {
+      Logger("ApkDownloader").severe(e);
+      Navigator.pop(context);
+      showGenericErrorDialog(context);
+      return;
+    }
+    Navigator.pop(context);
+    OpenFile.open(_saveUrl);
+  }
+}

+ 14 - 0
lib/ui/home_widget.dart

@@ -17,6 +17,8 @@ import 'package:photos/events/trigger_logout_event.dart';
 import 'package:photos/events/user_logged_out_event.dart';
 import 'package:photos/events/user_logged_out_event.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/services/sync_service.dart';
 import 'package:photos/services/sync_service.dart';
+import 'package:photos/services/update_service.dart';
+import 'package:photos/ui/app_update_dialog.dart';
 import 'package:photos/ui/backup_folder_selection_page.dart';
 import 'package:photos/ui/backup_folder_selection_page.dart';
 import 'package:photos/ui/collections_gallery_widget.dart';
 import 'package:photos/ui/collections_gallery_widget.dart';
 import 'package:photos/ui/extents_page_view.dart';
 import 'package:photos/ui/extents_page_view.dart';
@@ -126,6 +128,18 @@ class _HomeWidgetState extends State<HomeWidget> {
       setState(() {});
       setState(() {});
     });
     });
     _initDeepLinks();
     _initDeepLinks();
+    UpdateService.instance.shouldUpdate().then((shouldUpdate) {
+      if (shouldUpdate) {
+        Future.delayed(Duration.zero, () {
+          showDialog(
+              context: context,
+              builder: (BuildContext context) {
+                return AppUpdateDialog(
+                    UpdateService.instance.getLatestVersionInfo());
+              });
+        });
+      }
+    });
     super.initState();
     super.initState();
   }
   }
 
 

+ 7 - 0
pubspec.lock

@@ -478,6 +478,13 @@ packages:
       url: "https://pub.dartlang.org"
       url: "https://pub.dartlang.org"
     source: hosted
     source: hosted
     version: "1.0.0+1"
     version: "1.0.0+1"
+  open_file:
+    dependency: "direct main"
+    description:
+      name: open_file
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.2.1"
   package_info_plus:
   package_info_plus:
     dependency: "direct main"
     dependency: "direct main"
     description:
     description:

+ 1 - 0
pubspec.yaml

@@ -79,6 +79,7 @@ dependencies:
   loading_animations: ^2.1.0
   loading_animations: ^2.1.0
   dots_indicator: ^2.0.0
   dots_indicator: ^2.0.0
   flutter_local_notifications: ^5.0.0+4
   flutter_local_notifications: ^5.0.0+4
+  open_file: ^3.2.1
 
 
 dev_dependencies:
 dev_dependencies:
   flutter_test:
   flutter_test: