diff --git a/android/.gitignore b/android/.gitignore index 4c8e80d3..ab53372a 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -16,6 +16,5 @@ key.properties # copied files app/google-services.json app/src/main/res/drawable-* -app/src/main/res/mipmap-* app/src/pro/google-services.json diff --git a/android/app/src/dev/res/mipmap-hdpi/ic_launcher.png b/android/app/src/dev/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 1c0f4e58..00000000 Binary files a/android/app/src/dev/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/dev/res/mipmap-mdpi/ic_launcher.png b/android/app/src/dev/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 5f3b40df..00000000 Binary files a/android/app/src/dev/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 4e5837e8..00000000 Binary files a/android/app/src/dev/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index e7cb22ec..00000000 Binary files a/android/app/src/dev/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 5860e8ba..00000000 Binary files a/android/app/src/dev/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/dev/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/dev/res/mipmap/ic_launcher.xml similarity index 100% rename from android/app/src/dev/res/mipmap-anydpi-v26/ic_launcher.xml rename to android/app/src/dev/res/mipmap/ic_launcher.xml diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml index 304732f8..f74085f3 100644 --- a/android/app/src/main/res/drawable/launch_background.xml +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -1,7 +1,7 @@ - + @@ -14,12 +17,14 @@ + + - + @@ -28,10 +33,13 @@ - + - + + + + diff --git a/lib/app.dart b/lib/app.dart index 9072fa3b..19cd0d33 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -3,16 +3,32 @@ import 'package:conference_2023/model/app_locale.dart'; import 'package:conference_2023/model/settings/theme_mode.dart'; import 'package:conference_2023/ui/router/router_provider.dart'; import 'package:conference_2023/ui/theme.dart'; +import 'package:conference_2023/util/firebase.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -class App extends ConsumerWidget { +class App extends ConsumerStatefulWidget { const App({super.key}); @override - Widget build(BuildContext context, WidgetRef ref) { + ConsumerState createState() => _AppState(); +} + +class _AppState extends ConsumerState { + @override + void initState() { + Future(() async { + await initFirebaseRemoteConfig(ref); + await initFirebaseMessaging(ref); + }); + + super.initState(); + } + + @override + Widget build(BuildContext context) { final router = ref.watch(routerProvider); final themeMode = ref.watch(themeModeNotifierProvider); final appLocale = ref.watch(appLocaleProvider); diff --git a/lib/l10n/localization.dart b/lib/l10n/localization.dart index 47ab6d79..f03c0835 100644 --- a/lib/l10n/localization.dart +++ b/lib/l10n/localization.dart @@ -3,7 +3,9 @@ import 'package:intl/intl.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'localization.g.dart'; + part 'localization_en.dart'; + part 'localization_ja.dart'; /// A provider that returns the current [Localization]. @@ -116,6 +118,8 @@ abstract base class Localization { String get settingsPushNotificationMessageAuthorized; + String get settingsPushNotificationMessageAlreadyAuthorized; + String get settingsPushNotificationMessageDenied; String get settingsPushNotificationMessageNotDetermined; diff --git a/lib/l10n/localization_en.dart b/lib/l10n/localization_en.dart index c959d681..70b82cb6 100644 --- a/lib/l10n/localization_en.dart +++ b/lib/l10n/localization_en.dart @@ -139,6 +139,10 @@ final class LocalizationEn extends Localization { String get settingsPushNotificationMessageAuthorized => 'OK! Push notification is enabled.'; + @override + String get settingsPushNotificationMessageAlreadyAuthorized => + 'Push notification is already enabled.'; + @override String get settingsPushNotificationMessageDenied => 'Sorry, do not send push notifications'; diff --git a/lib/l10n/localization_ja.dart b/lib/l10n/localization_ja.dart index b9ec89e4..ebb4bbfa 100644 --- a/lib/l10n/localization_ja.dart +++ b/lib/l10n/localization_ja.dart @@ -138,6 +138,10 @@ final class LocalizationJa extends Localization { @override String get settingsPushNotificationMessageAuthorized => 'プッシュ通知がの受信が許可されました!'; + @override + String get settingsPushNotificationMessageAlreadyAuthorized => + 'プッシュ通知は既に許可されています。'; + @override String get settingsPushNotificationMessageDenied => 'プッシュ通知が拒否されました。'; diff --git a/lib/main.dart b/lib/main.dart index 378bf555..b2099163 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,4 @@ import 'package:conference_2023/app.dart'; -import 'package:conference_2023/model/messaging.dart'; -import 'package:conference_2023/model/remote_config.dart'; import 'package:conference_2023/model/shared_preferences.dart'; import 'package:conference_2023/util/font_license.dart'; import 'package:conference_2023/util/provider_state_logger.dart'; @@ -11,12 +9,15 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); updatePathStrategy(); + GoRouter.optionURLReflectsImperativeAPIs = true; + await Firebase.initializeApp( options: firebaseOptionsWeb, ); @@ -31,10 +32,6 @@ void main() async { return true; }; - /// initialize firebase apps - await initFirebaseRemoteConfig(); - await initFirebaseMessaging(); - fontLicenses(); final pref = await SharedPreferences.getInstance(); diff --git a/lib/model/favorites/favorite_session_ids.g.dart b/lib/model/favorites/favorite_session_ids.g.dart index a54ffddb..07e326bd 100644 --- a/lib/model/favorites/favorite_session_ids.g.dart +++ b/lib/model/favorites/favorite_session_ids.g.dart @@ -7,7 +7,7 @@ part of 'favorite_session_ids.dart'; // ************************************************************************** String _$favoriteSessionIdsNotifierHash() => - r'81eece064524ce2aba87219be6c5f3f10e2d880e'; + r'06dfdc6f3cb304b497401d31cef98b65895a43dc'; /// See also [FavoriteSessionIdsNotifier]. @ProviderFor(FavoriteSessionIdsNotifier) diff --git a/lib/model/messaging.dart b/lib/model/messaging.dart index e6a3a8c8..31d7e076 100644 --- a/lib/model/messaging.dart +++ b/lib/model/messaging.dart @@ -1,9 +1,4 @@ -import 'dart:developer'; -import 'dart:io'; - import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'messaging.g.dart'; @@ -13,67 +8,3 @@ FirebaseMessaging firebaseMessaging( FirebaseMessagingRef ref, ) => FirebaseMessaging.instance; - -Future initFirebaseMessaging() async { - final instance = FlutterLocalNotificationsPlugin(); - await instance.initialize( - const InitializationSettings( - android: AndroidInitializationSettings('@drawable/ic_notification'), - iOS: DarwinInitializationSettings( - requestAlertPermission: false, - requestSoundPermission: false, - requestBadgePermission: false, - ), - ), - ); - - const androidDefaultChannel = AndroidNotificationChannel( - 'default_channel', - 'Default (Importance High)', - importance: Importance.high, - ); - - await instance - .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() - ?.createNotificationChannel(androidDefaultChannel); - - FirebaseMessaging.onMessage.listen( - (event) async { - log('FirebaseMessaging.onMessage: ${event.toMap()}'); - - await instance.show( - event.messageId.hashCode, - event.notification?.title, - event.notification?.body, - NotificationDetails( - android: AndroidNotificationDetails( - androidDefaultChannel.id, - androidDefaultChannel.name, - ), - ), - ); - }, - ); - - if (kIsWeb) { - return; - } - - if (Platform.isIOS) { - final token = await FirebaseMessaging.instance.getAPNSToken(); - if (token == null) { - /// if apns token is null, cannot subscribe to topics. - log('FirebaseMessaging.getAPNSToken: null'); - return; - } - } - - /// read topics - const topics = [ - 'general', - ]; - for (final topic in topics) { - await FirebaseMessaging.instance.subscribeToTopic(topic); - } -} diff --git a/lib/model/remote_config.dart b/lib/model/remote_config.dart index 6d1d3db4..503c28c9 100644 --- a/lib/model/remote_config.dart +++ b/lib/model/remote_config.dart @@ -1,5 +1,4 @@ import 'package:firebase_remote_config/firebase_remote_config.dart'; -import 'package:flutter/foundation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'remote_config.g.dart'; @@ -22,24 +21,3 @@ enum RemoteConfigKey { final String key; } - -Future initFirebaseRemoteConfig() async { - final remoteConfig = FirebaseRemoteConfig.instance; - await remoteConfig.setDefaults( - const { - 'staff': '{"items": []}', - 'developer': '{"items": []}', - 'sponsor': '{"platinum": [], "gold": [], "silver": []}', - 'session': '{"items": {"room1": [],"room2": []}}', - 'lunch': '{"items": []}', - }, - ); - - if (kIsWeb) { - await remoteConfig.fetchAndActivate(); - } else { - remoteConfig.onConfigUpdated.listen((event) async { - await remoteConfig.activate(); - }); - } -} diff --git a/lib/model/venue/lunch_provider.g.dart b/lib/model/venue/lunch_provider.g.dart index 0e2b5099..f8facf53 100644 --- a/lib/model/venue/lunch_provider.g.dart +++ b/lib/model/venue/lunch_provider.g.dart @@ -36,7 +36,7 @@ final sortedStoreListProvider = AutoDisposeProvider.internal( typedef SortedStoreListRef = AutoDisposeProviderRef; String _$storeSortOptionNotifierHash() => - r'22a8268e4926f3866843fc00c7504ea20d59340c'; + r'a6b3ad8a382b9938256fc86ca7691a61d4263b93'; /// See also [StoreSortOptionNotifier]. @ProviderFor(StoreSortOptionNotifier) diff --git a/lib/ui/router/branch/router_app_sessions.dart b/lib/ui/router/branch/router_app_sessions.dart index 26ab8bbc..5660ce11 100644 --- a/lib/ui/router/branch/router_app_sessions.dart +++ b/lib/ui/router/branch/router_app_sessions.dart @@ -28,14 +28,14 @@ class SessionDetailRoute extends GoRouteData { static const path = ':sessionId'; + static final $parentNavigatorKey = rootNavigatorKey; + final String sessionId; @override Widget build(BuildContext context, GoRouterState state) { - return Material( - child: SessionDetailPage( - sessionId: sessionId, - ), + return SessionDetailPage( + sessionId: sessionId, ); } } diff --git a/lib/ui/router/router_app.g.dart b/lib/ui/router/router_app.g.dart index 499dab93..57159e67 100644 --- a/lib/ui/router/router_app.g.dart +++ b/lib/ui/router/router_app.g.dart @@ -32,6 +32,7 @@ RouteBase get $rootRoute => StatefulShellRouteData.$route( routes: [ GoRouteData.$route( path: ':sessionId', + parentNavigatorKey: SessionDetailRoute.$parentNavigatorKey, factory: $SessionDetailRouteExtension._fromState, ), ], diff --git a/lib/ui/screen/root.dart b/lib/ui/screen/root.dart index 6c28fb70..938dc95a 100644 --- a/lib/ui/screen/root.dart +++ b/lib/ui/screen/root.dart @@ -36,18 +36,10 @@ class RootScreen extends ConsumerWidget { final screenSize = context.screenSize; final currentTab = _getCurrentTab(context); - final isShellRouteChildPath = - GoRouterState.of(context).uri.pathSegments.length >= 2; - return SelectionAreaScaffold( appBar: AppBar( title: Text(currentTab.title(localization)), centerTitle: true, - leading: isShellRouteChildPath - ? BackButton( - onPressed: context.pop, - ) - : null, ), drawer: switch (screenSize) { ScreenSize.compact => RootDrawer( diff --git a/lib/ui/screen/sessions/session_detail.dart b/lib/ui/screen/sessions/session_detail.dart index 121ba906..d6e9f9b3 100644 --- a/lib/ui/screen/sessions/session_detail.dart +++ b/lib/ui/screen/sessions/session_detail.dart @@ -42,100 +42,107 @@ class SessionDetailPage extends ConsumerWidget { ), ); - return SingleChildScrollView( - padding: EdgeInsets.symmetric( - horizontal: context.spacing, - vertical: 16, + return Scaffold( + appBar: AppBar( + title: Text(localization.pageTitleSessions), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: Text( - session.title.get(locale), - style: Theme.of(context).textTheme.headlineMedium, - ), - ), - IconButton( - icon: Icon( - isFavorite ? Icons.favorite : Icons.favorite_border, - ), - onPressed: () async { - isFavorite - ? await ref - .read(favoriteSessionIdsNotifierProvider.notifier) - .remove(sessionId) - : await ref - .read(favoriteSessionIdsNotifierProvider.notifier) - .add(sessionId); - }, - ), - ], - ), - const Gap(8), - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondary, - borderRadius: BorderRadius.circular(8), - ), - padding: const EdgeInsets.symmetric( - vertical: 4, - horizontal: 8, - ), - child: Text( - room.alias, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).colorScheme.onSecondary, - ), - ), - ), - const Gap(16), - if (speaker != null) ...[ - Wrap( - spacing: 16, - runSpacing: 8, - crossAxisAlignment: WrapCrossAlignment.center, + body: SingleChildScrollView( + padding: EdgeInsets.symmetric( + horizontal: context.spacing, + vertical: 16, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( children: [ - CircleAvatar( - backgroundImage: NetworkImage(speaker.avatarUrl), + Expanded( + child: Text( + session.title.get(locale), + style: Theme.of(context).textTheme.headlineMedium, + ), ), - Text( - speaker.name, - style: Theme.of(context).textTheme.bodyLarge, + IconButton( + icon: Icon( + isFavorite ? Icons.favorite : Icons.favorite_border, + ), + onPressed: () async { + isFavorite + ? await ref + .read(favoriteSessionIdsNotifierProvider.notifier) + .remove(sessionId) + : await ref + .read(favoriteSessionIdsNotifierProvider.notifier) + .add(sessionId); + }, ), ], ), const Gap(8), - Tooltip( - message: localization.twitterTooltip, - child: ElevatedButton.icon( - icon: Assets.svg.xLogo.svg( - width: 18, - colorFilter: ColorFilter.mode( - Theme.of(context).colorScheme.primary, - BlendMode.srcIn, + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.secondary, + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.symmetric( + vertical: 4, + horizontal: 8, + ), + child: Text( + room.alias, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSecondary, + ), + ), + ), + const Gap(16), + if (speaker != null) ...[ + Wrap( + spacing: 16, + runSpacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + CircleAvatar( + backgroundImage: NetworkImage(speaker.avatarUrl), + ), + Text( + speaker.name, + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + if (speaker.twitter.isNotEmpty) ...[ + const Gap(8), + Tooltip( + message: localization.twitterTooltip, + child: ElevatedButton.icon( + icon: Assets.svg.xLogo.svg( + width: 18, + colorFilter: ColorFilter.mode( + Theme.of(context).colorScheme.primary, + BlendMode.srcIn, + ), + ), + label: Text('@${speaker.twitter}'), + onPressed: () async { + final uri = Uri.parse( + 'https://x.com/${speaker.twitter}', + ); + await launchInExternalApp(uri); + }, ), ), - label: Text('@${speaker.twitter}'), - onPressed: () async { - final uri = Uri.parse( - 'https://x.com/${speaker.twitter}', - ); - await launchInExternalApp(uri); - }, + ], + const Gap(24), + ], + if (description != null) + MarkdownBody( + shrinkWrap: true, + selectable: true, + data: description.get(locale), ), - ), - const Gap(24), ], - if (description != null) - MarkdownBody( - shrinkWrap: true, - selectable: true, - data: description.get(locale), - ), - ], + ), ), ); } diff --git a/lib/ui/screen/sessions/sessions.dart b/lib/ui/screen/sessions/sessions.dart index 40528d96..019db626 100644 --- a/lib/ui/screen/sessions/sessions.dart +++ b/lib/ui/screen/sessions/sessions.dart @@ -197,7 +197,7 @@ class _SessionCard extends ConsumerWidget { SessionTalk() || SessionSponsor() => () { SessionDetailRoute( sessionId: session.id, - ).go(context); + ).push(context); }, _ => null, }, diff --git a/lib/ui/screen/settings/list_tile_push_notification.dart b/lib/ui/screen/settings/list_tile_push_notification.dart index 325ebbec..9cf51cbd 100644 --- a/lib/ui/screen/settings/list_tile_push_notification.dart +++ b/lib/ui/screen/settings/list_tile_push_notification.dart @@ -1,6 +1,7 @@ import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:conference_2023/l10n/localization.dart'; import 'package:conference_2023/model/permission.dart'; +import 'package:conference_2023/util/firebase.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -33,11 +34,11 @@ class ListTilePushNotification extends ConsumerWidget { }, ), onTap: () async { - String message; + final String message; switch (type) { case NotificationPermission.granted: - message = - localization.settingsPushNotificationMessageAuthorized; + message = localization + .settingsPushNotificationMessageAlreadyAuthorized; case NotificationPermission.denied: final shouldShowRequestRationale = await Permission.notification.shouldShowRequestRationale; @@ -60,6 +61,8 @@ class ListTilePushNotification extends ConsumerWidget { case NotificationPermission.provisional: message = localization.settingsPushNotificationMessageAuthorized; + + await subscribeTopics(ref); case NotificationPermission.denied: case NotificationPermission.permanentlyDenied: message = diff --git a/lib/util/firebase.dart b/lib/util/firebase.dart new file mode 100644 index 00000000..2756b831 --- /dev/null +++ b/lib/util/firebase.dart @@ -0,0 +1,114 @@ +import 'dart:developer'; +import 'dart:io'; + +import 'package:conference_2023/model/messaging.dart'; +import 'package:conference_2023/model/permission.dart'; +import 'package:conference_2023/model/remote_config.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +Future initFirebaseRemoteConfig(WidgetRef ref) async { + final remoteConfig = ref.read(remoteConfigProvider); + await remoteConfig.setDefaults( + const { + 'staff': '{"items": []}', + 'developer': '{"items": []}', + 'sponsor': '{"platinum": [], "gold": [], "silver": []}', + 'session': '{"items": {"room1": [],"room2": []}}', + 'lunch': '{"items": []}', + }, + ); + + if (kIsWeb) { + /// [onConfigUpdated] is not supported on web. + /// see [https://github.com/firebase/flutterfire/pull/10647] + await remoteConfig.fetchAndActivate(); + } else { + /// Support realtime update on mobile. + remoteConfig.onConfigUpdated.listen((event) async { + await remoteConfig.activate(); + ref.invalidate(remoteConfigProvider); + }); + } +} + +Future initFirebaseMessaging(WidgetRef ref) async { + final instance = FlutterLocalNotificationsPlugin(); + await instance.initialize( + const InitializationSettings( + android: AndroidInitializationSettings('@drawable/ic_notification'), + iOS: DarwinInitializationSettings( + requestAlertPermission: false, + requestSoundPermission: false, + requestBadgePermission: false, + ), + ), + ); + + const androidDefaultChannel = AndroidNotificationChannel( + 'default_channel', + 'Default (Importance High)', + importance: Importance.high, + ); + + await instance + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(androidDefaultChannel); + + FirebaseMessaging.onMessage.listen( + (event) async { + log('FirebaseMessaging.onMessage: ${event.toMap()}'); + + await instance.show( + event.messageId.hashCode, + event.notification?.title, + event.notification?.body, + NotificationDetails( + android: AndroidNotificationDetails( + androidDefaultChannel.id, + androidDefaultChannel.name, + ), + ), + ); + }, + ); + + if (kIsWeb) { + return; + } + + final currentStatus = await ref.read(notificationPermissionProvider.future); + if (currentStatus == NotificationPermission.granted) { + await subscribeTopics(ref); + } +} + +Future subscribeTopics(WidgetRef ref) async { + if (kIsWeb) { + /// subscribeToTopic is not supported on web. + return; + } + + final instance = ref.read(firebaseMessagingProvider); + + /// Since subscribeToTopic is only supported on mobile devices, + /// we need to check "whether the platform is iOS or macOS". + if (Platform.isIOS || Platform.isMacOS) { + final token = await instance.getAPNSToken(); + if (token == null) { + /// if apns token is null, cannot subscribe to topics. + log('FirebaseMessaging.getAPNSToken: null'); + return; + } + } + + const topics = [ + 'general', + ]; + for (final topic in topics) { + await instance.subscribeToTopic(topic); + } +} diff --git a/pubspec.lock b/pubspec.lock index e3ee377e..b7403404 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "76c15c4167f820b74abcd8c6fc5e393e1ed5e1207a34e9b22953603e03b3ba6a" + sha256: "7bcb5c5d62b3907fb4a269c0f0843df46760d38e12829a715f2ff1fb492f19ef" url: "https://pub.dev" source: hosted - version: "1.3.9" + version: "1.3.10" accessibility_tools: dependency: "direct main" description: @@ -349,10 +349,10 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "57bba167105d2315d243a4524939406df688f38a5b6d7a4159382bbbe43cdd00" + sha256: "37299e4907391d7fac8c7ea059bb3292768cc07b72b6c6c777675cc58da2ef4d" url: "https://pub.dev" source: hosted - version: "2.19.0" + version: "2.20.0" firebase_core_platform_interface: dependency: transitive description: @@ -373,66 +373,66 @@ packages: dependency: "direct main" description: name: firebase_crashlytics - sha256: c58902959e7a73aadcf82c87e8d64f6eb10b5287fd7aaadfab5c2ef34ec11ff5 + sha256: d279ec1a3377df3762778e55ded07fe6d169d216713a44bbc624ae6218e35c3c url: "https://pub.dev" source: hosted - version: "3.4.1" + version: "3.4.2" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - sha256: "9d2f76bda1542615f75fb501a8c7afc6288d69c3728fdc762bf3d51f0ee0f4cb" + sha256: "8a82ce2879e359134f5ce786048737b6385a65ec696d68cf0c27134a1c933676" url: "https://pub.dev" source: hosted - version: "3.6.9" + version: "3.6.10" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: "01320eab9b3f91a6351d873923190a965e5155db942187aa600f85f78b9de501" + sha256: d7b6f9c394f8575598fa94e67220cdd2097a0bc28ce20a3ef2db2da94ede5b47 url: "https://pub.dev" source: hosted - version: "14.7.1" + version: "14.7.2" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: "952df577e7fb3a4550483f86bb568f19ce5da2a91f1597eeefdca0607de82562" + sha256: "825356880eb94bf16ea7ef6a71384d2c32cc88143b54ecffed8b3987f7178854" url: "https://pub.dev" source: hosted - version: "4.5.10" + version: "4.5.11" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: dcc901226c33b4819992c4add900ed5dae79b0db70097a795d7932c85b18cda1 + sha256: "9c82e55c4b470970c77a99c90733adff6be7d5a67251007727b2a98d4f04e0cd" url: "https://pub.dev" source: hosted - version: "3.5.10" + version: "3.5.11" firebase_remote_config: dependency: "direct main" description: name: firebase_remote_config - sha256: "088af33c7d54755a55e2734c59aa838189afb8fe3406ea0d2f18e6706342e993" + sha256: d701609add3ff2a79bbf36610563cd599f23e49f729933d944210a9aaf6d454a url: "https://pub.dev" source: hosted - version: "4.3.1" + version: "4.3.2" firebase_remote_config_platform_interface: dependency: transitive description: name: firebase_remote_config_platform_interface - sha256: "5b6d0dd9174470a6a681e199291a651ff11f3cf2ffe141e4f12ae831f42afe20" + sha256: "262bf51f73ef18e5e46ab626c2e5c8d47dc41c96419b74e70b6359a001f3b657" url: "https://pub.dev" source: hosted - version: "1.4.9" + version: "1.4.10" firebase_remote_config_web: dependency: transitive description: name: firebase_remote_config_web - sha256: facf4c155318225b459b48891e443055fabe0cdb1654a7a3c36e52d5719bdaf8 + sha256: d752bf5ea858d7e77e3906e23af59be083201b370a1ec849b295edb1d07000b1 url: "https://pub.dev" source: hosted - version: "1.4.9" + version: "1.4.10" fixnum: dependency: transitive description: @@ -482,10 +482,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + sha256: ad76540d21c066228ee3f9d1dad64a9f7e46530e8bb7c85011a88bc1fd874bc5 url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "3.0.0" flutter_local_notifications: dependency: "direct main" description: @@ -527,18 +527,18 @@ packages: dependency: "direct main" description: name: flutter_riverpod - sha256: e667e406a74d67715f1fa0bd941d9ded49aff72f3a9f4440a36aece4e8d457a7 + sha256: bdba94be666ecb1beeb0f5a748d96cdd6a37215f27e6b48c7673b95cecb800c8 url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.4" flutter_svg: dependency: "direct main" description: name: flutter_svg - sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338" + sha256: bfc7cc3c75fe1282e8ce2e056d8fd1533f1a6848b65c379b4a5e7a9b623d3371 url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.8" flutter_test: dependency: "direct dev" description: flutter @@ -737,10 +737,10 @@ packages: dependency: transitive description: name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "3.0.0" logging: dependency: transitive description: @@ -841,10 +841,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" + sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" path_provider_foundation: dependency: transitive description: @@ -977,42 +977,42 @@ packages: dependency: transitive description: name: riverpod - sha256: "494bf2cfb4df30000273d3052bdb1cc1de738574c6b678f0beb146ea56f5e208" + sha256: "2af3d127a6e4e34b89b8f1f018086f5ded04b8e538174f0510bba3e4c0d878b1" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.4" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: d72d7096964baf288b55619fe48100001fc4564ab7923ed0a7f5c7650e03c0d6 + sha256: "70e556220b6563a8cd4e392f73c543d9f6999dadea2428f31bda2bbc3a2675bd" url: "https://pub.dev" source: hosted - version: "0.3.4" + version: "0.4.2" riverpod_annotation: dependency: "direct main" description: name: riverpod_annotation - sha256: b724b2085405c4f62a1824a3fa3fb1e4858e09a4e2e8db92b7547c08d07a1377 + sha256: "388b03ed91b8f5126318fa43221fe078ebc20c81523dec9fcb5237cb5431d4dd" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" riverpod_generator: dependency: "direct dev" description: name: riverpod_generator - sha256: "5b36ad2f2b562cffb37212e8d59390b25499bf045b732276e30a207b16a25f61" + sha256: "0a1c8eeb3dba2ce704eb1a4c3b8043716d52bedaaaa5b2725e0bde67ca38a46e" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.5" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: "70198738c3047ae4f6517ef1a2011a8514a980a52576c7f629a3a08810319a02" + sha256: fa33206008e042669537bfdc2edba75672c19cead9f4871b9218e1f3813393e0 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.3.2" rxdart: dependency: transitive description: @@ -1230,66 +1230,66 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27" + sha256: fa6675dc49dea33b0f228bca6f9ad5445c25b51284ca5f88c0d49ab770a0450a url: "https://pub.dev" source: hosted - version: "6.1.14" + version: "6.2.0" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330 + sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f" + sha256: "4ac97281cf60e2e8c5cc703b2b28528f9b50c8f7cebc71df6bdf0845f647268a" url: "https://pub.dev" source: hosted - version: "6.1.5" + version: "6.2.0" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e + sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88 + sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "3.1.0" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618" + sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.0" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5" + sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" url: "https://pub.dev" source: hosted - version: "2.0.20" + version: "2.2.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069" + sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc" url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.1.0" uuid: dependency: transitive description: @@ -1302,26 +1302,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: b16dadf7eb610e20da044c141b4a0199a5e8082ca21daba68322756f953ce714 + sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43" url: "https://pub.dev" source: hosted - version: "1.1.9" + version: "1.1.9+1" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: a4b01403d5c613db115e30e71eca33f7e9e09f2d3c52c3fb84e16333ecddc539 + sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7" url: "https://pub.dev" source: hosted - version: "1.1.9" + version: "1.1.9+1" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: d26c0e2f237476426523eb25512e4c09fa27c6d33ed659a0e69d79e20b5dc47f + sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26 url: "https://pub.dev" source: hosted - version: "1.1.9" + version: "1.1.9+1" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c9ee3b00..436ab89f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: conference_2023 description: FlutterKaigi 2023 official application. publish_to: 'none' -version: 1.0.0+13 +version: 1.1.0+14 environment: sdk: '>=3.2.0-210.1.beta <4.0.0' @@ -54,7 +54,7 @@ dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^3.0.0 custom_lint: ^0.5.0 riverpod_lint: ^2.0.0 diff --git a/web/images/52b19707-6447-42ac-9f7d-77375845d576.jpg b/web/images/52b19707-6447-42ac-9f7d-77375845d576.jpg new file mode 100644 index 00000000..46460957 Binary files /dev/null and b/web/images/52b19707-6447-42ac-9f7d-77375845d576.jpg differ diff --git a/web/manifest.json b/web/manifest.json index 796d195c..e3c84e16 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -13,6 +13,11 @@ "platform": "play", "url": "https://play.google.com/store/apps/details?id=jp.flutterkaigi.conf2023", "id": "jp.flutterkaigi.conf2023" + }, + { + "platform": "itunes", + "url": "https://apps.apple.com/us/app/flutterkaigi-2023/id6469518498", + "id": "jp.flutterkaigi.conf2023" } ], "icons": [