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 000000000..515a345df Binary files /dev/null and b/app/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png differ diff --git a/app/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png b/app/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png new file mode 100644 index 000000000..7d545361c Binary files /dev/null and b/app/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png differ diff --git a/app/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png b/app/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png new file mode 100644 index 000000000..52adbb769 Binary files /dev/null and b/app/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png differ diff --git a/app/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png b/app/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png new file mode 100644 index 000000000..06cc348bd Binary files /dev/null and b/app/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png differ diff --git a/app/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png b/app/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png new file mode 100644 index 000000000..822c57ee1 Binary files /dev/null and b/app/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png differ diff --git a/app/assets/docs/about_this_app.md b/app/assets/docs/about_this_app.md new file mode 100644 index 000000000..7cd10c474 --- /dev/null +++ b/app/assets/docs/about_this_app.md @@ -0,0 +1,57 @@ +#### **緊急地震速報のP, S波到達予想円について** + +[JMA2001走時表]に対し、線形補間を行い、揺れの到達予想円を算出しています。 +走時表の仕様により、以下の場合到達予想円が表示されない場合があります。 + +- P, S波の到達範囲が半径2,001km以上 +- 震源の深さが701km以上 + +強震モニタで表示される揺れ・実際の揺れ・到達予想円はそれぞれ差異が生じる場合があります。 + +#### **地震情報(緊急地震速報を含む)について** + +[Project DM(Disaster Mitigation)-Data Send Service] (以降 Project DM-D.S.S)を利用し、各種地震情報の取得を行っています。 +Project DM-D.S.Sから受信したデータを、EQMonitor用に開発者が用意したプライベートAPI(HTTP, WebSocket)で再配信しています。 + +- 緊急地震速報の再配信については、Project DM-D.S.Sの[再配信ポリシー](https://dmdata.jp/docs/eew#%E5%86%8D%E9%85%8D%E4%BF%A1%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC)に基づき、事前の許可を得ています。(2022年12月3日承認済み) + - ※本アプリケーションの開発に、Project DM-D.S.Sの運営者は一切関係がありません。したがって、本アプリケーションに関するお問い合わせをProject DM-D.S.Sの運営者にすることはお控えください。 + +[JMA2001走時表]: https://www.data.jma.go.jp/eqev/data/bulletin/catalog/appendix/trtime/trt_j.html +[Project DM(Disaster Mitigation)-Data Send Service]: https://dmdata.jp/ + +#### **著作権関連** + +- 地図データ + - 日本: 国土数値情報 行政区域 + - 日本以外: Natural Earth +- 強震モニタの観測点データ + - 防災科学技術研究所(NIED) +- 各種地震情報 + - 気象庁 + +#### **Special Thanks** + +- [JQuake(フランソワ) 様] + - 強震モニタ画像解析手法 [多項式補間を使用して強震モニタ画像から数値データを決定する](https://qiita.com/NoneType1/items/a4d2cf932e20b56ca444) +- [ingen084 様] + - 各種処理の参考 [KyoshinEewViewerIngen] + - 強震モニタの観測点データ [KyoshinMonitorLib] + - 強震モニタ画像解析手法 [強震モニタの画像から震度と地点を特定するまで](https://qiita.com/ingen084/items/7e91f8da2996972ac586) +- [Laddge 様] ウェブサイトの制作 +- [ともりん 様] 通知音・効果音の制作 + +[JQuake(フランソワ) 様]: https://twitter.com/NoneType1 +[KyoshinEewViewerIngen]: https://github.com/ingen084/KyoshinEewViewerIngen +[ingen084 様]: https://twitter.com/ingen084 +[KyoshinMonitorLib]: https://github.com/ingen084/KyoshinMonitorLib +[Laddge 様]: https://twitter.com/laddge_ +[ともりん 様]: https://twitter.com/tomorin1223 + +#### **本アプリの開発者** + +EQMonitorは、もぐもぐ (Ryotaro Onoue)によって開発されました。 +MIT License に基づき、ソースコードを公開しています。(GitHub: [YumNumm/EQMonitor](https://github.com/YumNumm/EQMonitor)) + +- Twitter: [@YumNumm](https://twitter.com/YumNumm), [@EQMonitorApp](https://twitter.com/EQMonitorApp) +- GitHub: [@YumNumm](https://github.com/YumNumm) +- Mail: [admin@yumnumm.dev](admin@yumnumm.dev) もしくは [contacts@eqmonitor.app](contacts@eqmonitor.app) diff --git a/app/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj index 48365a863..9be93a1a9 100644 --- a/app/ios/Runner.xcodeproj/project.pbxproj +++ b/app/ios/Runner.xcodeproj/project.pbxproj @@ -525,7 +525,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1152; + CURRENT_PROJECT_VERSION = 1157; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = CPL7H8SHVM; ENABLE_BITCODE = NO; @@ -560,7 +560,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1152; + CURRENT_PROJECT_VERSION = 1157; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = CPL7H8SHVM; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -602,7 +602,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1152; + CURRENT_PROJECT_VERSION = 1157; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = CPL7H8SHVM; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -643,7 +643,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1152; + CURRENT_PROJECT_VERSION = 1157; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = CPL7H8SHVM; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -787,7 +787,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1152; + CURRENT_PROJECT_VERSION = 1157; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = CPL7H8SHVM; ENABLE_BITCODE = NO; @@ -819,7 +819,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1152; + CURRENT_PROJECT_VERSION = 1157; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = CPL7H8SHVM; ENABLE_BITCODE = NO; diff --git a/app/ios/Runner/Info.plist b/app/ios/Runner/Info.plist index 2f41daa55..49f47eb81 100644 --- a/app/ios/Runner/Info.plist +++ b/app/ios/Runner/Info.plist @@ -1,43 +1,6 @@ - - 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) {