app_update_dialog.dart 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/widgets.dart';
  3. import 'package:logging/logging.dart';
  4. import 'package:open_file/open_file.dart';
  5. import 'package:photos/core/configuration.dart';
  6. import 'package:photos/core/network.dart';
  7. import 'package:photos/services/update_service.dart';
  8. import 'package:photos/ui/common_elements.dart';
  9. class AppUpdateDialog extends StatefulWidget {
  10. final LatestVersionInfo latestVersionInfo;
  11. AppUpdateDialog(this.latestVersionInfo, {Key key}) : super(key: key);
  12. @override
  13. _AppUpdateDialogState createState() => _AppUpdateDialogState();
  14. }
  15. class _AppUpdateDialogState extends State<AppUpdateDialog> {
  16. @override
  17. Widget build(BuildContext context) {
  18. final List<Widget> changelog = [];
  19. for (final log in widget.latestVersionInfo.changelog) {
  20. changelog.add(Padding(
  21. padding: const EdgeInsets.fromLTRB(8, 4, 0, 4),
  22. child: Text("- " + log,
  23. style: TextStyle(
  24. fontSize: 14,
  25. color: Colors.white.withOpacity(0.7),
  26. )),
  27. ));
  28. }
  29. final content = Column(
  30. crossAxisAlignment: CrossAxisAlignment.start,
  31. mainAxisSize: MainAxisSize.min,
  32. children: [
  33. Text(
  34. widget.latestVersionInfo.name,
  35. style: TextStyle(
  36. fontSize: 20,
  37. fontWeight: FontWeight.bold,
  38. ),
  39. ),
  40. Padding(padding: EdgeInsets.all(8)),
  41. Text("changelog",
  42. style: TextStyle(
  43. fontSize: 18,
  44. )),
  45. Padding(padding: EdgeInsets.all(4)),
  46. Column(
  47. crossAxisAlignment: CrossAxisAlignment.start,
  48. children: changelog,
  49. ),
  50. Padding(padding: EdgeInsets.all(8)),
  51. Container(
  52. width: double.infinity,
  53. height: 64,
  54. padding: const EdgeInsets.fromLTRB(50, 0, 50, 0),
  55. child: button(
  56. "update",
  57. fontSize: 16,
  58. onPressed: () async {
  59. Navigator.pop(context);
  60. showDialog(
  61. context: context,
  62. builder: (BuildContext context) {
  63. return ApkDownloaderDialog(widget.latestVersionInfo);
  64. },
  65. barrierDismissible: false,
  66. );
  67. },
  68. ),
  69. ),
  70. ],
  71. );
  72. final shouldForceUpdate =
  73. UpdateService.instance.shouldForceUpdate(widget.latestVersionInfo);
  74. return WillPopScope(
  75. onWillPop: () async => !shouldForceUpdate,
  76. child: AlertDialog(
  77. title: Text(shouldForceUpdate? "critical update available" : "update available"),
  78. content: content,
  79. ),
  80. );
  81. }
  82. }
  83. class ApkDownloaderDialog extends StatefulWidget {
  84. final LatestVersionInfo versionInfo;
  85. ApkDownloaderDialog(this.versionInfo, {Key key}) : super(key: key);
  86. @override
  87. _ApkDownloaderDialogState createState() => _ApkDownloaderDialogState();
  88. }
  89. class _ApkDownloaderDialogState extends State<ApkDownloaderDialog> {
  90. String _saveUrl;
  91. double _downloadProgress;
  92. @override
  93. void initState() {
  94. super.initState();
  95. _saveUrl = Configuration.instance.getTempDirectory() +
  96. "ente-" +
  97. widget.versionInfo.name +
  98. ".apk";
  99. _downloadApk();
  100. }
  101. @override
  102. Widget build(BuildContext context) {
  103. return WillPopScope(
  104. onWillPop: () async => false,
  105. child: AlertDialog(
  106. title: Text(
  107. "downloading...",
  108. style: TextStyle(
  109. fontSize: 16,
  110. ),
  111. textAlign: TextAlign.center,
  112. ),
  113. content: LinearProgressIndicator(
  114. value: _downloadProgress,
  115. valueColor:
  116. AlwaysStoppedAnimation<Color>(Theme.of(context).buttonColor),
  117. ),
  118. ),
  119. );
  120. }
  121. Future<void> _downloadApk() async {
  122. try {
  123. await Network.instance.getDio().download(widget.versionInfo.url, _saveUrl,
  124. onReceiveProgress: (count, _) {
  125. setState(() {
  126. _downloadProgress = count / widget.versionInfo.size;
  127. });
  128. });
  129. Navigator.of(context, rootNavigator: true).pop('dialog');
  130. OpenFile.open(_saveUrl);
  131. } catch (e) {
  132. Logger("ApkDownloader").severe(e);
  133. AlertDialog alert = AlertDialog(
  134. title: Text("sorry"),
  135. content: Text("the download could not be completed"),
  136. actions: [
  137. TextButton(
  138. child: Text(
  139. "ignore",
  140. style: TextStyle(
  141. color: Colors.white,
  142. ),
  143. ),
  144. onPressed: () {
  145. Navigator.of(context, rootNavigator: true).pop('dialog');
  146. Navigator.of(context, rootNavigator: true).pop('dialog');
  147. },
  148. ),
  149. TextButton(
  150. child: Text(
  151. "retry",
  152. style: TextStyle(
  153. color: Theme.of(context).buttonColor,
  154. ),
  155. ),
  156. onPressed: () {
  157. Navigator.of(context, rootNavigator: true).pop('dialog');
  158. Navigator.of(context, rootNavigator: true).pop('dialog');
  159. showDialog(
  160. context: context,
  161. builder: (BuildContext context) {
  162. return ApkDownloaderDialog(widget.versionInfo);
  163. },
  164. barrierDismissible: false,
  165. );
  166. },
  167. ),
  168. ],
  169. );
  170. showDialog(
  171. context: context,
  172. builder: (BuildContext context) {
  173. return alert;
  174. },
  175. barrierColor: Colors.black87,
  176. );
  177. return;
  178. }
  179. }
  180. }