diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 8d4492f..9625e10 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/ios/Podfile b/ios/Podfile index 1e8c3c9..88359b2 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4880c33..a154239 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,4 +1,6 @@ PODS: + - device_info_plus (0.0.1): + - Flutter - Flutter (1.0.0) - flutter_native_splash (0.0.1): - Flutter @@ -25,6 +27,7 @@ PODS: - Flutter DEPENDENCIES: + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) @@ -40,6 +43,8 @@ SPEC REPOS: - Sentry EXTERNAL SOURCES: + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" Flutter: :path: Flutter flutter_native_splash: @@ -58,7 +63,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" SPEC CHECKSUMS: - Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e @@ -69,6 +75,6 @@ SPEC CHECKSUMS: sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de -PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c +PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 COCOAPODS: 1.11.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1ccfe8e..6f9779f 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -350,7 +350,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -429,7 +429,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -479,7 +479,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/lib/core/widgets/dwi_appbar.dart b/lib/core/widgets/dwi_appbar.dart index 20c9780..1bd5075 100644 --- a/lib/core/widgets/dwi_appbar.dart +++ b/lib/core/widgets/dwi_appbar.dart @@ -1,7 +1,9 @@ +import 'package:dwi/core/widgets/widgets.dart'; import 'package:dwi/features/features.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:upgrader/upgrader.dart'; /// DWIAppBar class DWIAppBar extends StatelessWidget implements PreferredSizeWidget { @@ -17,6 +19,7 @@ class DWIAppBar extends StatelessWidget implements PreferredSizeWidget { preferredSize: preferredSize, child: AppBar( actions: const [ + _UpdateButton(), _AddCounterButton(), _DeleteCounterButton(), _AboutButton(), @@ -85,3 +88,30 @@ class _DeleteCounterButton extends StatelessWidget { ); } } + +class _UpdateButton extends StatelessWidget { + const _UpdateButton({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return UpgradeWidget( + upgrader: Upgrader( + //! This is a bit of a hack to allow the alert dialog to be shown + //! repeatedly. + durationUntilAlertAgain: const Duration(milliseconds: 500), + showReleaseNotes: false, + showIgnore: false, + ), + builder: (context, upgrader) => CircleAvatar( + child: IconButton( + onPressed: () { + upgrader.checkVersion(context: context); + }, + icon: const Icon(Icons.upload), + ), + ), + ); + } +} diff --git a/lib/core/widgets/upgrade_widget.dart b/lib/core/widgets/upgrade_widget.dart new file mode 100644 index 0000000..fe5d29c --- /dev/null +++ b/lib/core/widgets/upgrade_widget.dart @@ -0,0 +1,51 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:upgrader/upgrader.dart'; + +/// Defines a builder function that allows you to create a custom widget +/// that is displayed in a similar fashion as [UpgradeCard] +typedef UpgradeWidgetBuilder = Widget Function( + BuildContext context, + Upgrader upgrader, +); + +/// A widget to display by checking upgrader info available. +class UpgradeWidget extends UpgradeBase { + /// Creates a new [UpgradeWidget]. + UpgradeWidget({ + Key? key, + Upgrader? upgrader, + required this.builder, + }) : super(upgrader ?? Upgrader.sharedInstance as Upgrader, key: key); + + /// Defines how the widget will be built. Allows the implementation of custom + /// widgets. + final UpgradeWidgetBuilder builder; + + /// Describes the part of the user interface represented by this widget. + @override + Widget build(BuildContext context, UpgradeBaseState state) { + if (upgrader.debugLogging) { + log('UpgradeWidget: build UpgradeWidget'); + } + + return FutureBuilder( + future: state.initialized, + builder: (BuildContext context, AsyncSnapshot processed) { + if (processed.connectionState == ConnectionState.done && + processed.data != null && + processed.data!) { + if (upgrader.shouldDisplayUpgrade()) { + if (upgrader.debugLogging) { + log('UpgradeWidget: will call builder'); + } + return builder.call(context, upgrader); + } + } + + return const SizedBox.shrink(); + }, + ); + } +} diff --git a/lib/core/widgets/widgets.dart b/lib/core/widgets/widgets.dart index d2750e3..7b3e9c6 100644 --- a/lib/core/widgets/widgets.dart +++ b/lib/core/widgets/widgets.dart @@ -1,2 +1,3 @@ export 'dwi_appbar.dart'; export 'empty_state.dart'; +export 'upgrade_widget.dart'; diff --git a/lib/main.dart b/lib/main.dart index 4b09847..ba93c39 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,20 @@ import 'package:data/data.dart'; import 'package:domain/domain.dart'; import 'package:dwi/core/application/application.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:upgrader/upgrader.dart'; Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + + // Only call clearSavedSettings() during testing to reset internal values. + if (kDebugMode) { + await Upgrader.clearSavedSettings(); + } + await SentryFlutter.init( (options) {}, appRunner: () => runApp( diff --git a/pubspec.lock b/pubspec.lock index cbb740d..5f76c8c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "31.0.0" + version: "38.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "2.8.0" + version: "3.4.1" archive: dependency: transitive description: @@ -35,7 +35,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" bloc: dependency: transitive description: @@ -84,7 +84,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: @@ -112,7 +112,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" code_builder: dependency: transitive description: @@ -169,6 +169,48 @@ packages: relative: true source: path version: "1.0.0" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.3" + device_info_plus_linux: + dependency: transitive + description: + name: device_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + device_info_plus_macos: + dependency: transitive + description: + name: device_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + device_info_plus_web: + dependency: transitive + description: + name: device_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + device_info_plus_windows: + dependency: transitive + description: + name: device_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" diff_match_patch: dependency: transitive description: @@ -196,7 +238,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" ffi: dependency: transitive description: @@ -370,21 +412,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" mime: dependency: transitive description: @@ -420,6 +462,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + os_detect: + dependency: transitive + description: + name: os_detect + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" package_config: dependency: transitive description: @@ -475,7 +524,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" path_provider: dependency: transitive description: @@ -711,7 +760,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" sqflite: dependency: transitive description: @@ -746,7 +795,7 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" synchronized: dependency: transitive description: @@ -760,28 +809,28 @@ packages: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test: dependency: transitive description: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.20.2" + version: "1.21.4" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.11" + version: "0.4.16" typed_data: dependency: transitive description: @@ -796,6 +845,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.4" + upgrader: + dependency: "direct main" + description: + name: upgrader + url: "https://pub.dartlang.org" + source: hosted + version: "4.8.0" url_launcher: dependency: "direct main" description: @@ -866,6 +922,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + version: + dependency: transitive + description: + name: version + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" very_good_analysis: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 697db31..772a402 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,33 +7,24 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: - # Data layer data: path: packages/data - # Domain layer domain: path: packages/domain - # Value equality equatable: ^2.0.5 fl_chart: ^0.55.1 flutter: sdk: flutter - # Bloc for state management flutter_bloc: ^8.1.1 - # Feather Icons package flutter_feather_icons: ^2.0.0 flutter_localizations: sdk: flutter - # Build Information intl: ^0.17.0 package_info_plus: ^1.4.3+1 - # Monitoring sentry_flutter: ^6.9.1 - # Launcher for URLs + upgrader: ^4.8.0 url_launcher: ^6.1.5 - # UUID uuid: ^3.0.6 - # Bug Reporting wiredash: ^1.5.0 dev_dependencies: @@ -47,7 +38,7 @@ dev_dependencies: flutter_icons: image_path: 'assets/launcher/dwi-512x512-android.png' - android: true # can specify file name here e.g. "ic_launcher" + android: true ios: true adaptive_icon_background: '#56F0D4' adaptive_icon_foreground: 'assets/launcher/dwi-foreground.png'