From f1d5ac661f6a00a64a915263c8dbdf7806cf807b Mon Sep 17 00:00:00 2001 From: Ryotaro Onoue <73390859+YumNumm@users.noreply.github.com> Date: Mon, 8 Apr 2024 00:42:20 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=A9=E3=82=A4=E3=82=BB=E3=83=B3=E3=82=B9?= =?UTF-8?q?=E5=91=A8=E3=82=8A=E3=81=AE=E8=AA=BF=E6=95=B4=20(#626)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add: android notification icon `ic_notification_icon` * fix: Info.plist conflict miss * remove: unused useAnimation * fix: Tipのありがとう文字列 * fix: license * fix: docs * fix: buildnum * fix: bunner color * fix: remove unused repaintboundary * add: about_app * remove: debug * fix: 予想震度の凡例を調整 --- .../drawable-hdpi/ic_notification_icon.png | Bin 0 -> 753 bytes .../drawable-mdpi/ic_notification_icon.png | Bin 0 -> 465 bytes .../drawable-xhdpi/ic_notification_icon.png | Bin 0 -> 1023 bytes .../drawable-xxhdpi/ic_notification_icon.png | Bin 0 -> 1662 bytes .../drawable-xxxhdpi/ic_notification_icon.png | Bin 0 -> 2369 bytes app/assets/docs/about_this_app.md | 57 ++++++++++ app/ios/Runner.xcodeproj/project.pbxproj | 12 +- app/ios/Runner/Info.plist | 43 +------ app/lib/app.dart | 1 - .../component/sheet/basic_modal_sheet.dart | 34 +++--- .../app_information_model.freezed.dart | 2 +- .../model/intensity_color_model.freezed.dart | 2 +- app/lib/core/router/router.dart | 12 ++ app/lib/core/router/router.g.dart | 22 ++++ app/lib/core/theme/build_theme.dart | 10 +- app/lib/core/util/license/init_licenses.dart | 68 +++++++++++ .../donation/ui/donation_choice_modal.dart | 9 +- .../donation/ui/donation_executed_screen.dart | 22 +++- .../feature/donation/ui/donation_screen.dart | 5 +- .../earthquake_history_parameter.freezed.dart | 2 +- .../home/features/map/view/main_map_view.dart | 3 +- .../viewmodel/main_map_viewmodel.freezed.dart | 2 +- app/lib/feature/home/view/home_view.dart | 30 +++-- .../application_info/about_this_app.dart | 65 +++++++++++ .../notification_setting_page.dart | 106 +++++++++--------- ...fiication_settings_view_model.freezed.dart | 2 +- app/lib/feature/settings/settings_screen.dart | 31 +---- app/lib/main.dart | 6 +- 28 files changed, 370 insertions(+), 176 deletions(-) create mode 100644 app/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png create mode 100644 app/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png create mode 100644 app/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png create mode 100644 app/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png create mode 100644 app/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png create mode 100644 app/assets/docs/about_this_app.md create mode 100644 app/lib/core/util/license/init_licenses.dart create mode 100644 app/lib/feature/settings/children/application_info/about_this_app.dart diff --git a/app/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png b/app/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..515a345df0bede1aab61bb937d9b09c62dfcd0bf GIT binary patch literal 753 zcmVfBNz~3Cl)DU6s)Y2M2(HurH+4qqzOo( zRs3qSiXVtx&v9ng*|RgV^WICNS& zY-1liqZ+?$Ao&fEJ-yFJ7~)i+LR{3j$7ShJattQ|O4sRiN*v_t2Z7Y)-+r-_k4T z6LeBzQowu4$Hd@7?_Pc8mT3$o9#?-CjPbECX4K!n+@=?MI(+oSPew8Kq++j+W2HAw zbWUo7XGy)iVs1{wm{4zxxh+3NasroPZlcGSQ*VvAI;3omeKqVL-C$jPA?SZ8{+rMfYwlG)fhT#5C0{4lp44F|td zuZVnw&REIugIMv%<&TYcOTV*6Bz)~7VCmxKPbaE!h%w|R0$XPIH`V?nO|Y~XeEX9GR0O%H7c jpu5n0=%DuR@XzrZ8xp-M4$rM?pyqElTW!sk6R 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 - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - EQMonitor - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - eqmonitor - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - 1152 - LSRequiresIPhoneOS - - UIApplicationSupportsIndirectInputEvents - - UIBackgroundModes - - fetch - remote-notification - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - NSAppTransportSecurity CADisableMinimumFrameDurationOnPhone @@ -60,9 +23,7 @@ CFBundleSignature ???? CFBundleVersion - 1154 - UIViewControllerBasedStatusBarAppearance - + 1157 LSRequiresIPhoneOS UIApplicationSupportsIndirectInputEvents @@ -95,4 +56,4 @@ UIInterfaceOrientationPortraitUpsideDown - + \ No newline at end of file diff --git a/app/lib/app.dart b/app/lib/app.dart index 3a836cff3..02ad925dd 100644 --- a/app/lib/app.dart +++ b/app/lib/app.dart @@ -72,7 +72,6 @@ class App extends HookConsumerWidget { child: Banner( message: 'v${packageInfo.version}-${packageInfo.buildNumber}', location: BannerLocation.bottomStart, - color: Colors.red.shade900, child: app, ), ); diff --git a/app/lib/core/component/sheet/basic_modal_sheet.dart b/app/lib/core/component/sheet/basic_modal_sheet.dart index 27ce30ae4..91eb0f2d1 100644 --- a/app/lib/core/component/sheet/basic_modal_sheet.dart +++ b/app/lib/core/component/sheet/basic_modal_sheet.dart @@ -63,27 +63,25 @@ class BasicModalSheet extends HookWidget { child: SafeArea( top: hasAppBar, bottom: false, - child: RepaintBoundary( - child: Column( - children: [ - barWidget, - if (useColumn) - Expanded( - child: SingleChildScrollView( - child: Column( - children: children, - ), - ), - ) - else - Expanded( - child: ListView( - padding: const EdgeInsets.all(2), + child: Column( + children: [ + barWidget, + if (useColumn) + Expanded( + child: SingleChildScrollView( + child: Column( children: children, ), ), - ], - ), + ) + else + Expanded( + child: ListView( + padding: const EdgeInsets.all(2), + children: children, + ), + ), + ], ), ), ), diff --git a/app/lib/core/provider/app_information/app_information_model.freezed.dart b/app/lib/core/provider/app_information/app_information_model.freezed.dart index 681738baf..94bf867f4 100644 --- a/app/lib/core/provider/app_information/app_information_model.freezed.dart +++ b/app/lib/core/provider/app_information/app_information_model.freezed.dart @@ -12,7 +12,7 @@ part of 'app_information_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); AppInformationModel _$AppInformationModelFromJson(Map json) { return _AppInformationModel.fromJson(json); diff --git a/app/lib/core/provider/config/theme/intensity_color/model/intensity_color_model.freezed.dart b/app/lib/core/provider/config/theme/intensity_color/model/intensity_color_model.freezed.dart index f23e629b1..3f5431be5 100644 --- a/app/lib/core/provider/config/theme/intensity_color/model/intensity_color_model.freezed.dart +++ b/app/lib/core/provider/config/theme/intensity_color/model/intensity_color_model.freezed.dart @@ -12,7 +12,7 @@ part of 'intensity_color_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); IntensityColorModel _$IntensityColorModelFromJson(Map json) { return _IntensityColorModel.fromJson(json); diff --git a/app/lib/core/router/router.dart b/app/lib/core/router/router.dart index 9b394b5e8..df60151f6 100644 --- a/app/lib/core/router/router.dart +++ b/app/lib/core/router/router.dart @@ -11,6 +11,7 @@ import 'package:eqmonitor/feature/earthquake_history_details/screen/earthquake_h import 'package:eqmonitor/feature/home/view/home_view.dart'; import 'package:eqmonitor/feature/information_history/page/information_history_page.dart'; import 'package:eqmonitor/feature/information_history_details/information_history_details_page.dart'; +import 'package:eqmonitor/feature/settings/children/application_info/about_this_app.dart'; import 'package:eqmonitor/feature/settings/children/application_info/license_page.dart'; import 'package:eqmonitor/feature/settings/children/application_info/privacy_policy_screen.dart'; import 'package:eqmonitor/feature/settings/children/application_info/term_of_service_screen.dart'; @@ -152,6 +153,9 @@ class KmoniRoute extends GoRouteData { TypedGoRoute( path: 'earthquake-history', ), + TypedGoRoute( + path: 'about-this-app', + ), TypedGoRoute( path: 'donation', routes: [ @@ -263,6 +267,14 @@ class LicenseRoute extends GoRouteData { const LicensePage(); } +class AboutThisAppRoute extends GoRouteData { + const AboutThisAppRoute(); + + @override + Widget build(BuildContext context, GoRouterState state) => + const AboutThisAppScreen(); +} + class NotificationSettingsRoute extends GoRouteData { const NotificationSettingsRoute(); diff --git a/app/lib/core/router/router.g.dart b/app/lib/core/router/router.g.dart index 10c5d21d0..4a93420ee 100644 --- a/app/lib/core/router/router.g.dart +++ b/app/lib/core/router/router.g.dart @@ -232,6 +232,10 @@ RouteBase get $settingsRoute => GoRouteData.$route( path: 'earthquake-history', factory: $EarthquakeHistoryConfigRouteExtension._fromState, ), + GoRouteData.$route( + path: 'about-this-app', + factory: $AboutThisAppRouteExtension._fromState, + ), GoRouteData.$route( path: 'donation', factory: $DonationRouteExtension._fromState, @@ -402,6 +406,24 @@ extension $EarthquakeHistoryConfigRouteExtension void replace(BuildContext context) => context.replace(location); } +extension $AboutThisAppRouteExtension on AboutThisAppRoute { + static AboutThisAppRoute _fromState(GoRouterState state) => + const AboutThisAppRoute(); + + String get location => GoRouteData.$location( + '/settings/about-this-app', + ); + + 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); +} + extension $DonationRouteExtension on DonationRoute { static DonationRoute _fromState(GoRouterState state) => const DonationRoute(); diff --git a/app/lib/core/theme/build_theme.dart b/app/lib/core/theme/build_theme.dart index aaedfa470..63745e106 100644 --- a/app/lib/core/theme/build_theme.dart +++ b/app/lib/core/theme/build_theme.dart @@ -1,4 +1,5 @@ import 'package:eqmonitor/core/theme/custom_colors.dart'; +import 'package:eqmonitor/gen/fonts.gen.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -6,15 +7,12 @@ ThemeData buildTheme({ ColorScheme? colorScheme, CustomColors? customColors, }) { - final notoSansJp = GoogleFonts.notoSansJp().fontFamily; - final robotoMono = GoogleFonts.robotoMono().fontFamily; return ThemeData( colorScheme: colorScheme, extensions: [if (customColors != null) customColors], useMaterial3: true, - fontFamily: robotoMono, - fontFamilyFallback: [ - if (notoSansJp != null) notoSansJp, - ], + fontFamily: FontFamily.notoSansJP, ); } + +final monoFont = GoogleFonts.fragmentMono().fontFamily; diff --git a/app/lib/core/util/license/init_licenses.dart b/app/lib/core/util/license/init_licenses.dart new file mode 100644 index 000000000..e06707944 --- /dev/null +++ b/app/lib/core/util/license/init_licenses.dart @@ -0,0 +1,68 @@ +import 'package:flutter/foundation.dart'; + +Future initLicenses() async { + LicenseRegistry.addLicense( + () async* { + yield const LicenseEntryWithLineBreaks( + ['KyoshinEewViewerIngen'], + ''' +MIT License + +Copyright (c) 2019 ingen084 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +''', + ); + yield const LicenseEntryWithLineBreaks( + ['KyoshinMonitorLib'], + ''' +MIT License + +Copyright (c) 2020 ingen084 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.''', + ); + yield const LicenseEntryWithLineBreaks( + ['「国土数値情報(行政区域データ)」(国土交通省)(当該ページのURL)を加工して作成'], + ''' +https://nlftp.mlit.go.jp/ksj/other/agreement.html に従います''', + ); + yield const LicenseEntryWithLineBreaks( + ['Natural Earth(世界地図)'], + '© 2009 - 2024. Natural Earth. All rights reserved.\nhttps://www.naturalearthdata.com/', + ); + }, + ); +} diff --git a/app/lib/feature/donation/ui/donation_choice_modal.dart b/app/lib/feature/donation/ui/donation_choice_modal.dart index cbd8cd529..942a8f110 100644 --- a/app/lib/feature/donation/ui/donation_choice_modal.dart +++ b/app/lib/feature/donation/ui/donation_choice_modal.dart @@ -62,7 +62,7 @@ class DonationChoiceModal extends HookConsumerWidget { final product = e.$2; final emoji = product.emoji; return ListTile( - title: Text(choice.title), + title: Text(product.productName), subtitle: Text(choice.description), trailing: Text( choice.priceString, @@ -106,4 +106,11 @@ extension ProductEx on Products { return '🍱'; } } + + String get productName => switch (this) { + Products.coffee => 'コーヒー', + Products.enegyDrink => 'エナジードリンクセット', + Products.meat => '美味しい牛肉', + Products.eel => 'うな重' + }; } diff --git a/app/lib/feature/donation/ui/donation_executed_screen.dart b/app/lib/feature/donation/ui/donation_executed_screen.dart index 94dfff308..8e1a60dec 100644 --- a/app/lib/feature/donation/ui/donation_executed_screen.dart +++ b/app/lib/feature/donation/ui/donation_executed_screen.dart @@ -163,8 +163,16 @@ class _ScrollView extends StatelessWidget { ), ), TextSpan( - text: 'あなたの支援のお陰で、より良いアプリを作ることができます。\n\n' - 'Twitter(X)やメールで私へ連絡いただけると嬉しいです!' + text: 'あなたの支援のお陰で、より良いアプリを作ることができます。\n\n', + ), + TextSpan( + text: '皆様の声が励みになります!\n', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + TextSpan( + text: 'Twitter(X)やメールで私へ連絡いただけると嬉しいです!' 'もしくは、アプリストアへのレビューもお待ちしております\n\n' 'ご意見やご要望があれば、お気軽にお知らせください!\n\n' '- Ryotaro Onoue', @@ -190,23 +198,25 @@ class _Detail extends StatelessWidget { required this.product, required this.textTheme, required this.customer, + this.isScreenshot = false, }); final Products productEnum; final StoreProduct product; final TextTheme textTheme; final CustomerInfo customer; + final bool isScreenshot; @override Widget build(BuildContext context) { return Column( children: [ - const Padding( - padding: EdgeInsets.all(8), + Padding( + padding: const EdgeInsets.all(8), child: Center( child: Text( - 'ありがとうございます! 💖', - style: TextStyle( + isScreenshot ? 'EQMontorを支援しました✌' : 'ありがとうございます! 💖', + style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.w900, diff --git a/app/lib/feature/donation/ui/donation_screen.dart b/app/lib/feature/donation/ui/donation_screen.dart index be921fa62..6896d50ae 100644 --- a/app/lib/feature/donation/ui/donation_screen.dart +++ b/app/lib/feature/donation/ui/donation_screen.dart @@ -182,8 +182,9 @@ class _ShowDonationButton extends HookConsumerWidget { showDialog( context: context, barrierDismissible: false, - builder: (context) => - const CircularProgressIndicator.adaptive(), + builder: (context) => const Center( + child: CircularProgressIndicator.adaptive(), + ), ), ); try { diff --git a/app/lib/feature/earthquake_history/data/model/earthquake_history_parameter.freezed.dart b/app/lib/feature/earthquake_history/data/model/earthquake_history_parameter.freezed.dart index bf68a6050..443808ac5 100644 --- a/app/lib/feature/earthquake_history/data/model/earthquake_history_parameter.freezed.dart +++ b/app/lib/feature/earthquake_history/data/model/earthquake_history_parameter.freezed.dart @@ -12,7 +12,7 @@ part of 'earthquake_history_parameter.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); /// @nodoc mixin _$EarthquakeHistoryParameter { diff --git a/app/lib/feature/home/features/map/view/main_map_view.dart b/app/lib/feature/home/features/map/view/main_map_view.dart index e1c9d19ef..9407419a7 100644 --- a/app/lib/feature/home/features/map/view/main_map_view.dart +++ b/app/lib/feature/home/features/map/view/main_map_view.dart @@ -46,7 +46,6 @@ class MainMapView extends HookConsumerWidget { final controller = useAnimationController( duration: const Duration(microseconds: 1000), ); - useAnimation(controller); useEffect( () { controller @@ -95,7 +94,7 @@ class MainMapView extends HookConsumerWidget { child: MaplibreMap( initialCameraPosition: const CameraPosition( target: LatLng(35.681236, 139.767125), - zoom: 3, + zoom: 5, ), styleString: stylePath.value ?? '', onMapCreated: (controller) { diff --git a/app/lib/feature/home/features/map/viewmodel/main_map_viewmodel.freezed.dart b/app/lib/feature/home/features/map/viewmodel/main_map_viewmodel.freezed.dart index ee0dd7fe3..4070d9f61 100644 --- a/app/lib/feature/home/features/map/viewmodel/main_map_viewmodel.freezed.dart +++ b/app/lib/feature/home/features/map/viewmodel/main_map_viewmodel.freezed.dart @@ -12,7 +12,7 @@ part of 'main_map_viewmodel.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); _EewHypocenterProperties _$EewHypocenterPropertiesFromJson( Map json) { diff --git a/app/lib/feature/home/view/home_view.dart b/app/lib/feature/home/view/home_view.dart index 5228686e9..16c3df347 100644 --- a/app/lib/feature/home/view/home_view.dart +++ b/app/lib/feature/home/view/home_view.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:collection/collection.dart'; import 'package:eqapi_types/eqapi_types.dart'; +import 'package:eqapi_types/model/components/eew_intensity.dart'; import 'package:eqmonitor/core/component/container/bordered_container.dart'; import 'package:eqmonitor/core/component/intenisty/intensity_icon_type.dart'; import 'package:eqmonitor/core/component/intenisty/jma_forecast_intensity_icon.dart'; @@ -217,16 +218,29 @@ class _IntensityIcons extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final aliveEews = ref.watch(eewAliveNormalTelegramProvider); - final maxEstimatedIntensities = - aliveEews.map((e) => e.forecastMaxIntensity).whereNotNull().toList(); + final maxEstimatedIntensities = aliveEews + .map( + (e) => e.regions + ?.map( + (region) => region.forecastMaxInt.toDisplayMaxInt().maxInt, + ) + .toList(), + ) + .whereNotNull() + .flattened + .whereNotNull() + .toList(); final maxIntensity = maxEstimatedIntensities.isNotEmpty ? maxEstimatedIntensities.reduce((a, b) => a > b ? a : b) : null; - final intensities = maxIntensity != null + final minIntensity = maxEstimatedIntensities.isNotEmpty + ? maxEstimatedIntensities.reduce((a, b) => a < b ? a : b) + : null; + final intensities = maxIntensity != null && minIntensity != null ? [ ...JmaForecastIntensity.values, ].where( - (e) => e <= maxIntensity && e >= JmaForecastIntensity.four, + (e) => e <= maxIntensity && e >= minIntensity, ) : null; if (intensities == null || intensities.isEmpty) { @@ -246,12 +260,8 @@ class _IntensityIcons extends ConsumerWidget { spacing: 8, runSpacing: 8, children: [ - if (maxIntensity != null) - for (final intensity in [ - ...JmaForecastIntensity.values, - ].where( - (e) => e <= maxIntensity && e >= JmaForecastIntensity.four, - )) + if (maxIntensity != null && minIntensity != null) + for (final intensity in intensities) JmaForecastIntensityWidget( intensity: intensity, size: 25, diff --git a/app/lib/feature/settings/children/application_info/about_this_app.dart b/app/lib/feature/settings/children/application_info/about_this_app.dart new file mode 100644 index 000000000..82280e2bf --- /dev/null +++ b/app/lib/feature/settings/children/application_info/about_this_app.dart @@ -0,0 +1,65 @@ +import 'package:eqmonitor/core/component/container/bordered_container.dart'; +import 'package:eqmonitor/core/router/router.dart'; +import 'package:eqmonitor/gen/assets.gen.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AboutThisAppScreen extends HookWidget { + const AboutThisAppScreen({super.key}); + + @override + Widget build(BuildContext context) { + final markdownFuture = + useMemoized(() => rootBundle.loadString(Assets.docs.aboutThisApp)); + final markdown = useFuture(markdownFuture); + return Scaffold( + appBar: AppBar( + title: const Text('このアプリについて'), + ), + body: SingleChildScrollView( + child: SafeArea( + child: Column( + children: [ + ListTile( + title: const Text('利用規約'), + leading: const Icon(Icons.description), + onTap: () => + const TermOfServiceRoute($extra: null).push(context), + ), + ListTile( + title: const Text('プライバシーポリシー'), + leading: const Icon(Icons.info), + onTap: () => + const PrivacyPolicyRoute($extra: null).push(context), + ), + ListTile( + title: const Text('ライセンス情報'), + subtitle: + Text('MIT License ${DateTime.now().year} Ryotaro Onoue'), + leading: const Icon(Icons.settings), + onTap: () => const LicenseRoute().push(context), + ), + const Divider(), + BorderedContainer( + elevation: 1, + child: MarkdownBody( + softLineBreak: true, + data: markdown.data ?? '', + onTapLink: (text, href, title) async { + final uri = Uri.tryParse(href ?? ''); + if (uri != null && await canLaunchUrl(uri)) { + await launchUrl(uri); + } + }, + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/app/lib/feature/settings/children/config/notification/notification_setting_page.dart b/app/lib/feature/settings/children/config/notification/notification_setting_page.dart index 031ec2a9a..a3db62316 100644 --- a/app/lib/feature/settings/children/config/notification/notification_setting_page.dart +++ b/app/lib/feature/settings/children/config/notification/notification_setting_page.dart @@ -3,6 +3,7 @@ import 'package:eqmonitor/core/component/container/bordered_container.dart'; import 'package:eqmonitor/core/foundation/result.dart'; import 'package:eqmonitor/core/provider/config/notification/fcm_topic_manager.dart'; import 'package:eqmonitor/core/provider/config/permission/permission_status_provider.dart'; +import 'package:eqmonitor/core/provider/debugger/debugger_provider.dart'; import 'package:eqmonitor/core/provider/notification_token.dart'; import 'package:eqmonitor/core/router/router.dart'; import 'package:eqmonitor/core/util/fullscreen_loading_overlay.dart'; @@ -189,58 +190,63 @@ class _OnNotificationPermissionAllowed extends ConsumerWidget { title: const Text('お知らせ'), subtitle: const Text('アップデート情報や開発者からのお知らせをお伝えします'), ), - const SettingsSectionHeader(text: 'FCM DEBUG'), - Consumer( - builder: (context, ref, _) { - final notificationTokenState = ref.watch(notificationTokenProvider); - return notificationTokenState.when( - data: (value) => Column( - children: [ - ListTile( - title: const Text('FCM デバイストークン'), - trailing: Text( - value.fcmToken?.obfuscate ?? '不明', - ), - onTap: () => Clipboard.setData( - ClipboardData(text: value.fcmToken ?? ''), - ).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('コピーしました'), - ), - ); - }), - visualDensity: VisualDensity.compact, - ), - ListTile( - title: const Text( - 'APNS デバイストークン', + if (ref.watch(debuggerProvider.select( + (value) => value.isDebugger, + ))) ...[ + const SettingsSectionHeader(text: 'FCM DEBUG'), + Consumer( + builder: (context, ref, _) { + final notificationTokenState = + ref.watch(notificationTokenProvider); + return notificationTokenState.when( + data: (value) => Column( + children: [ + ListTile( + title: const Text('FCM デバイストークン'), + trailing: Text( + value.fcmToken?.obfuscate ?? '不明', + ), + onTap: () => Clipboard.setData( + ClipboardData(text: value.fcmToken ?? ''), + ).then((_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('コピーしました'), + ), + ); + }), + visualDensity: VisualDensity.compact, ), - trailing: Text( - value.apnsToken?.obfuscate ?? '不明', + ListTile( + title: const Text( + 'APNS デバイストークン', + ), + trailing: Text( + value.apnsToken?.obfuscate ?? '不明', + ), + onTap: () => Clipboard.setData( + ClipboardData(text: value.apnsToken ?? ''), + ).then((_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('コピーしました'), + ), + ); + }), + visualDensity: VisualDensity.compact, ), - onTap: () => Clipboard.setData( - ClipboardData(text: value.apnsToken ?? ''), - ).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('コピーしました'), - ), - ); - }), - visualDensity: VisualDensity.compact, - ), - ], - ), - error: (error, stackTrace) => Text( - 'エラーが発生しました: $error', - ), - loading: () => const Center( - child: CircularProgressIndicator.adaptive(), - ), - ); - }, - ), + ], + ), + error: (error, stackTrace) => Text( + 'エラーが発生しました: $error', + ), + loading: () => const Center( + child: CircularProgressIndicator.adaptive(), + ), + ); + }, + ), + ], ], ); } diff --git a/app/lib/feature/settings/children/config/notification/notifiication_settings_view_model.freezed.dart b/app/lib/feature/settings/children/config/notification/notifiication_settings_view_model.freezed.dart index 9d53a838e..5a8aa17ad 100644 --- a/app/lib/feature/settings/children/config/notification/notifiication_settings_view_model.freezed.dart +++ b/app/lib/feature/settings/children/config/notification/notifiication_settings_view_model.freezed.dart @@ -12,7 +12,7 @@ part of 'notifiication_settings_view_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); NotificationSettingsState _$NotificationSettingsStateFromJson( Map json) { diff --git a/app/lib/feature/settings/settings_screen.dart b/app/lib/feature/settings/settings_screen.dart index dc724f7b7..b8f826c46 100644 --- a/app/lib/feature/settings/settings_screen.dart +++ b/app/lib/feature/settings/settings_screen.dart @@ -111,26 +111,11 @@ class SettingsScreen extends HookConsumerWidget { onTap: () => _onInquiryTap(context, ref), ), ListTile( - title: const Text('利用規約'), + title: const Text('このアプリケーションについて'), + subtitle: const Text('利用規約やプライバシーポリシーを確認できます'), leading: const Icon(Icons.description), - onTap: () => context.push( - const TermOfServiceRoute($extra: null).location, - ), - ), - ListTile( - title: const Text('プライバシーポリシー'), - leading: const Icon(Icons.info), - onTap: () => context.push( - const PrivacyPolicyRoute($extra: null).location, - ), - ), - ListTile( - title: const Text('ライセンス情報'), - subtitle: Text('MIT License ${DateTime.now().year} Ryotaro Onoue'), - leading: const Icon(Icons.settings), - onTap: () => context.push( - const LicenseRoute().location, - ), + + onTap: () => const AboutThisAppRoute().push(context), ), ListTile( title: const Text('サーバの稼働状況'), @@ -141,14 +126,6 @@ class SettingsScreen extends HookConsumerWidget { mode: LaunchMode.externalApplication, ), ), - ListTile( - title: const Text('ロードマップ'), - subtitle: const Text('アプリの開発ロードマップを確認できます'), - leading: const Icon(Icons.view_timeline), - onTap: () => launchUrlString( - 'https://github.com/YumNumm/EQMonitor/issues/412', - ), - ), Center( child: Padding( padding: const EdgeInsets.only(bottom: 16), diff --git a/app/lib/main.dart b/app/lib/main.dart index 616d0d4a8..7b2379710 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -13,6 +13,7 @@ import 'package:eqmonitor/core/provider/kmoni_observation_points/provider/kyoshi import 'package:eqmonitor/core/provider/log/talker.dart'; import 'package:eqmonitor/core/provider/package_info.dart'; import 'package:eqmonitor/core/provider/shared_preferences.dart'; +import 'package:eqmonitor/core/util/license/init_licenses.dart'; import 'package:eqmonitor/feature/donation/data/donation_notifier.dart'; import 'package:eqmonitor/firebase_options.dart'; import 'package:firebase_core/firebase_core.dart'; @@ -107,7 +108,10 @@ Future main() async { ), ).wait; - await initInAppPurchase(); + await ( + initInAppPurchase(), + initLicenses(), + ).wait; FirebaseMessaging.onBackgroundMessage(onBackgroundMessage); if (!kIsWeb) {