From 2d2b1a72b38452b45a137f62ba90053370011691 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Fri, 17 May 2024 14:06:59 +0200 Subject: [PATCH] added about dialog --- app/lib/core/routing/dialog_page.dart | 40 +++++++++++++++++++ app/lib/core/routing/routes.dart | 14 +++++++ app/lib/core/routing/routes.g.dart | 23 +++++++++++ .../repositories/package_info_repository.dart | 9 +++++ .../package_info_repository.g.dart | 24 +++++++++++ .../about/presentation/screens/about.dart | 27 +++++++++++++ .../presentation/screens/browser.dart | 8 ++++ .../domain/services/sharing_intent.g.dart | 2 +- app/lib/main.dart | 3 ++ .../Flutter/GeneratedPluginRegistrant.swift | 2 + app/pubspec.lock | 24 +++++++++++ app/pubspec.yaml | 3 ++ 12 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 app/lib/core/routing/dialog_page.dart create mode 100644 app/lib/features/about/data/repositories/package_info_repository.dart create mode 100644 app/lib/features/about/data/repositories/package_info_repository.g.dart create mode 100644 app/lib/features/about/presentation/screens/about.dart diff --git a/app/lib/core/routing/dialog_page.dart b/app/lib/core/routing/dialog_page.dart new file mode 100644 index 00000000..4a598c87 --- /dev/null +++ b/app/lib/core/routing/dialog_page.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; + +/// A dialog page with Material entrance and exit animations, modal barrier color, +/// and modal barrier behavior (dialog is dismissible with a tap on the barrier). +class DialogPage extends Page { + final Offset? anchorPoint; + final Color? barrierColor; + final bool barrierDismissible; + final String? barrierLabel; + final bool useSafeArea; + final CapturedThemes? themes; + final WidgetBuilder builder; + + const DialogPage({ + required this.builder, + this.anchorPoint, + this.barrierColor = Colors.black54, + this.barrierDismissible = true, + this.barrierLabel, + this.useSafeArea = true, + this.themes, + super.key, + super.name, + super.arguments, + super.restorationId, + }); + + @override + Route createRoute(BuildContext context) => DialogRoute( + context: context, + settings: this, + builder: builder, + anchorPoint: anchorPoint, + barrierColor: barrierColor, + barrierDismissible: barrierDismissible, + barrierLabel: barrierLabel, + useSafeArea: useSafeArea, + themes: themes, + ); +} diff --git a/app/lib/core/routing/routes.dart b/app/lib/core/routing/routes.dart index 319b9103..e030367e 100644 --- a/app/lib/core/routing/routes.dart +++ b/app/lib/core/routing/routes.dart @@ -1,3 +1,5 @@ +import 'package:bang_navigator/core/routing/dialog_page.dart'; +import 'package:bang_navigator/features/about/presentation/screens/about.dart'; import 'package:bang_navigator/features/search_browser/presentation/screens/browser.dart'; import 'package:bang_navigator/features/settings/data/repositories/settings_repository.dart'; import 'package:bang_navigator/features/settings/presentation/screens/settings.dart'; @@ -9,6 +11,11 @@ part 'routes.g.dart'; @TypedGoRoute( path: '/', + routes: [ + TypedGoRoute( + path: 'about', + ), + ], ) class KagiRoute extends GoRouteData { KagiRoute(); @@ -41,3 +48,10 @@ class SettingsRoute extends GoRouteData { return const SettingsScreen(); } } + +class AboutRoute extends GoRouteData { + @override + Page buildPage(BuildContext context, GoRouterState state) { + return DialogPage(builder: (_) => const AboutDialogScreen()); + } +} diff --git a/app/lib/core/routing/routes.g.dart b/app/lib/core/routing/routes.g.dart index 09ddbed3..1c776632 100644 --- a/app/lib/core/routing/routes.g.dart +++ b/app/lib/core/routing/routes.g.dart @@ -14,6 +14,12 @@ List get $appRoutes => [ RouteBase get $kagiRoute => GoRouteData.$route( path: '/', factory: $KagiRouteExtension._fromState, + routes: [ + GoRouteData.$route( + path: 'about', + factory: $AboutRouteExtension._fromState, + ), + ], ); extension $KagiRouteExtension on KagiRoute { @@ -33,6 +39,23 @@ extension $KagiRouteExtension on KagiRoute { void replace(BuildContext context) => context.replace(location); } +extension $AboutRouteExtension on AboutRoute { + static AboutRoute _fromState(GoRouterState state) => AboutRoute(); + + String get location => GoRouteData.$location( + '/about', + ); + + void go(BuildContext context) => context.go(location); + + Future push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + void replace(BuildContext context) => context.replace(location); +} + RouteBase get $settingsRoute => GoRouteData.$route( path: '/settings', factory: $SettingsRouteExtension._fromState, diff --git a/app/lib/features/about/data/repositories/package_info_repository.dart b/app/lib/features/about/data/repositories/package_info_repository.dart new file mode 100644 index 00000000..25341f62 --- /dev/null +++ b/app/lib/features/about/data/repositories/package_info_repository.dart @@ -0,0 +1,9 @@ +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'package_info_repository.g.dart'; + +@Riverpod(keepAlive: true) +Future packageInfo(PackageInfoRef ref) { + return PackageInfo.fromPlatform(); +} diff --git a/app/lib/features/about/data/repositories/package_info_repository.g.dart b/app/lib/features/about/data/repositories/package_info_repository.g.dart new file mode 100644 index 00000000..d0b6c152 --- /dev/null +++ b/app/lib/features/about/data/repositories/package_info_repository.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'package_info_repository.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$packageInfoHash() => r'f7bd90882137aac7a9f28e9d10eae6efeee8c9d0'; + +/// See also [packageInfo]. +@ProviderFor(packageInfo) +final packageInfoProvider = FutureProvider.internal( + packageInfo, + name: r'packageInfoProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$packageInfoHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef PackageInfoRef = FutureProviderRef; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/app/lib/features/about/presentation/screens/about.dart b/app/lib/features/about/presentation/screens/about.dart new file mode 100644 index 00000000..206e3811 --- /dev/null +++ b/app/lib/features/about/presentation/screens/about.dart @@ -0,0 +1,27 @@ +import 'package:bang_navigator/features/about/data/repositories/package_info_repository.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class AboutDialogScreen extends HookConsumerWidget { + const AboutDialogScreen(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final packageInfo = ref.watch( + packageInfoProvider.select( + //During startup we make sure + (value) => value.value!, + ), + ); + + return AboutDialog( + applicationIcon: SizedBox.square( + dimension: IconTheme.of(context).size, + child: Image.asset('assets/icon/icon.png'), + ), + applicationName: packageInfo.appName, + applicationVersion: packageInfo.version, + applicationLegalese: 'Copyright © Fabian Freund, 2024', + ); + } +} diff --git a/app/lib/features/search_browser/presentation/screens/browser.dart b/app/lib/features/search_browser/presentation/screens/browser.dart index bebf8ece..f4b303a9 100644 --- a/app/lib/features/search_browser/presentation/screens/browser.dart +++ b/app/lib/features/search_browser/presentation/screens/browser.dart @@ -215,6 +215,14 @@ class KagiScreen extends HookConsumerWidget { leadingIcon: const Icon(MdiIcons.text), child: const Text('Summarizer'), ), + const Divider(), + MenuItemButton( + onPressed: () async { + await context.push(AboutRoute().location); + }, + leadingIcon: const Icon(Icons.info), + child: const Text('About'), + ), ], ), ], diff --git a/app/lib/features/share_intent/domain/services/sharing_intent.g.dart b/app/lib/features/share_intent/domain/services/sharing_intent.g.dart index d27f7d28..df14bb9e 100644 --- a/app/lib/features/share_intent/domain/services/sharing_intent.g.dart +++ b/app/lib/features/share_intent/domain/services/sharing_intent.g.dart @@ -7,7 +7,7 @@ part of 'sharing_intent.dart'; // ************************************************************************** String _$sharingIntentStreamHash() => - r'6fca6ca6b4ac983397245a09cb61144cd5a4715d'; + r'4b285bac1537aa03007a6e932ddb50f24b2db873'; /// See also [sharingIntentStream]. @ProviderFor(sharingIntentStream) diff --git a/app/lib/main.dart b/app/lib/main.dart index e252ac89..092a3280 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -1,5 +1,6 @@ import 'package:bang_navigator/core/logger.dart'; import 'package:bang_navigator/core/providers.dart'; +import 'package:bang_navigator/features/about/data/repositories/package_info_repository.dart'; import 'package:bang_navigator/features/search_browser/domain/services/session.dart'; import 'package:bang_navigator/features/settings/data/repositories/settings_repository.dart'; import 'package:bang_navigator/presentation/hooks/on_initialization.dart'; @@ -37,6 +38,8 @@ void main() async { builder: (context, ref, child) { useOnInitialization( () async { + await ref.read(packageInfoProvider.future); + final settings = await ref.read(settingsRepositoryProvider.future); diff --git a/app/macos/Flutter/GeneratedPluginRegistrant.swift b/app/macos/Flutter/GeneratedPluginRegistrant.swift index b4e3483b..f7113f8c 100644 --- a/app/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,6 +7,7 @@ import Foundation import flutter_inappwebview_macos import flutter_secure_storage_macos +import package_info_plus import path_provider_foundation import share_plus import shared_preferences_foundation @@ -15,6 +16,7 @@ import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/app/pubspec.lock b/app/pubspec.lock index 381e45f2..68501dd2 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -161,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" code_builder: dependency: transitive description: @@ -683,6 +691,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0 + url: "https://pub.dev" + source: hosted + version: "8.0.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e + url: "https://pub.dev" + source: hosted + version: "3.0.0" path: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 64de0133..c56d728f 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: http: ^1.2.1 logger: ^2.2.0 mime: ^1.0.5 + package_info_plus: ^8.0.0 riverpod: ^2.5.1 riverpod_annotation: ^2.3.5 rxdart: ^0.27.7 @@ -54,6 +55,8 @@ dev_dependencies: flutter: uses-material-design: true + assets: + - assets/icon/icon.png flutter_launcher_icons: android: "launcher_icon"