From 70920c66a9093d050af92ca56d694a28fdb6cd6a Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 13:07:26 +0200 Subject: [PATCH 01/31] Init repo sync --- .github/sync.yml | 17 +++++++++++ .github/workflows/sync-to-flavored-repos.yml | 32 ++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 .github/sync.yml create mode 100644 .github/workflows/sync-to-flavored-repos.yml diff --git a/.github/sync.yml b/.github/sync.yml new file mode 100644 index 0000000..b746b84 --- /dev/null +++ b/.github/sync.yml @@ -0,0 +1,17 @@ +name: Sync HumHub app with app-flavored + +on: + push: + branches: + - '*' +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@master + - name: Run GitHub File Sync + uses: BetaHuhn/repo-file-sync-action@v1 + with: + GH_PAT: ${{ secrets.REPO2_TOKEN }} + diff --git a/.github/workflows/sync-to-flavored-repos.yml b/.github/workflows/sync-to-flavored-repos.yml new file mode 100644 index 0000000..4fcfea2 --- /dev/null +++ b/.github/workflows/sync-to-flavored-repos.yml @@ -0,0 +1,32 @@ +humhub/app@f-flavored: + - android/ + - ios/ + - assets/ + - lib/ + - linux + - macos/ + - test/ + - web/ + - windows + - .gitignore + - .metadata + - analysis_options.yaml + - l10n.yaml + - pubspec.lock + - pubspec.yaml +humhub/app-flavored@main: + - android/ + - ios/ + - assets/ + - lib/ + - linux + - macos/ + - test/ + - web/ + - windows + - .gitignore + - .metadata + - analysis_options.yaml + - l10n.yaml + - pubspec.lock + - pubspec.yaml \ No newline at end of file From 64e3012fe09b78813c8b165f6924279cd4e54129 Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 13:08:44 +0200 Subject: [PATCH 02/31] For now just trigger on feature branch --- .github/sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/sync.yml b/.github/sync.yml index b746b84..6b85c5e 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -3,7 +3,7 @@ name: Sync HumHub app with app-flavored on: push: branches: - - '*' + - 'f-flavored' jobs: sync: runs-on: ubuntu-latest From f3bc592711e78f8bb72f196c060fd7282659181f Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 13:10:36 +0200 Subject: [PATCH 03/31] rename GH_PAT --- .github/sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/sync.yml b/.github/sync.yml index 6b85c5e..01b4f2d 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -13,5 +13,5 @@ jobs: - name: Run GitHub File Sync uses: BetaHuhn/repo-file-sync-action@v1 with: - GH_PAT: ${{ secrets.REPO2_TOKEN }} + GH_PAT: ${{ secrets.GH_PAT }} From f942902c2d3e970a46f25dd773e34ee23031472f Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 13:12:05 +0200 Subject: [PATCH 04/31] Update sync.yml --- .github/sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/sync.yml b/.github/sync.yml index 01b4f2d..759073f 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -3,7 +3,7 @@ name: Sync HumHub app with app-flavored on: push: branches: - - 'f-flavored' + - f-flavored jobs: sync: runs-on: ubuntu-latest From 84ad485c75ce743a62aef6fd6782f8774ac07598 Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 13:15:23 +0200 Subject: [PATCH 05/31] Fix #2 --- .github/sync.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index 759073f..e07285d 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -3,15 +3,15 @@ name: Sync HumHub app with app-flavored on: push: branches: - - f-flavored + - "f-flavored" + jobs: sync: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@master + uses: actions/checkout@v2 - name: Run GitHub File Sync uses: BetaHuhn/repo-file-sync-action@v1 with: - GH_PAT: ${{ secrets.GH_PAT }} - + GH_PAT: ${{ secrets.GH_PAT }} \ No newline at end of file From b432c8d5fa479582485207d16dbec42f32b4fa1a Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 13:18:18 +0200 Subject: [PATCH 06/31] Fix #3 --- .github/sync.yml | 49 +++++++++++++------- .github/workflows/sync-to-flavored-repos.yml | 49 +++++++------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index e07285d..4fcfea2 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,17 +1,32 @@ -name: Sync HumHub app with app-flavored - -on: - push: - branches: - - "f-flavored" - -jobs: - sync: - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - - name: Run GitHub File Sync - uses: BetaHuhn/repo-file-sync-action@v1 - with: - GH_PAT: ${{ secrets.GH_PAT }} \ No newline at end of file +humhub/app@f-flavored: + - android/ + - ios/ + - assets/ + - lib/ + - linux + - macos/ + - test/ + - web/ + - windows + - .gitignore + - .metadata + - analysis_options.yaml + - l10n.yaml + - pubspec.lock + - pubspec.yaml +humhub/app-flavored@main: + - android/ + - ios/ + - assets/ + - lib/ + - linux + - macos/ + - test/ + - web/ + - windows + - .gitignore + - .metadata + - analysis_options.yaml + - l10n.yaml + - pubspec.lock + - pubspec.yaml \ No newline at end of file diff --git a/.github/workflows/sync-to-flavored-repos.yml b/.github/workflows/sync-to-flavored-repos.yml index 4fcfea2..cb103c4 100644 --- a/.github/workflows/sync-to-flavored-repos.yml +++ b/.github/workflows/sync-to-flavored-repos.yml @@ -1,32 +1,17 @@ -humhub/app@f-flavored: - - android/ - - ios/ - - assets/ - - lib/ - - linux - - macos/ - - test/ - - web/ - - windows - - .gitignore - - .metadata - - analysis_options.yaml - - l10n.yaml - - pubspec.lock - - pubspec.yaml -humhub/app-flavored@main: - - android/ - - ios/ - - assets/ - - lib/ - - linux - - macos/ - - test/ - - web/ - - windows - - .gitignore - - .metadata - - analysis_options.yaml - - l10n.yaml - - pubspec.lock - - pubspec.yaml \ No newline at end of file +name: Sync HumHub app with app-flavored + +on: + push: + branches: + - 'f-flavored' + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: Run GitHub File Sync + uses: BetaHuhn/repo-file-sync-action@v1 + with: + GH_PAT: ${{ secrets.GH_PAT }} \ No newline at end of file From d1e35c87bc990f35372dd878a23774731c98af46 Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 13:44:45 +0200 Subject: [PATCH 07/31] Refactor, prepare for flavored overrides --- .../animated_padding_component.dart | 7 +-- lib/components/bottom_navigation_bar.dart | 4 +- lib/components/language_switcher.dart | 6 +-- lib/components/rotating_globe.dart | 2 +- lib/models/channel_message.g.dart | 54 +++++++++---------- lib/models/event.dart | 42 +++++++-------- lib/models/event.g.dart | 15 +++--- lib/models/hum_hub.dart | 2 +- lib/pages/help/components/first_page.dart | 12 +++-- lib/pages/help/components/second_page.dart | 10 ++-- lib/pages/help/components/third_page.dart | 13 ++--- lib/pages/opener.dart | 4 +- lib/pages/web_view.dart | 3 +- lib/util/connectivity_plugin.dart | 10 ++-- lib/util/const.dart | 15 +++--- lib/util/extensions.dart | 5 +- lib/util/form_helper.dart | 2 +- lib/util/intent/intent_plugin.dart | 2 +- lib/util/log.dart | 20 +++---- lib/util/notifications/channel.dart | 2 +- lib/util/{ => openers}/opener_controller.dart | 10 ++-- .../universal_opener_controller.dart | 4 +- lib/util/override_locale.dart | 6 +-- lib/util/providers.dart | 34 +----------- lib/util/push/provider.dart | 33 ++++++++++++ lib/util/push/push_plugin.dart | 2 +- lib/util/push/register_token_plugin.dart | 17 +++--- test/opener_test.dart | 2 +- 28 files changed, 165 insertions(+), 173 deletions(-) rename lib/util/{ => openers}/opener_controller.dart (95%) rename lib/util/{ => openers}/universal_opener_controller.dart (97%) create mode 100644 lib/util/push/provider.dart diff --git a/lib/components/animated_padding_component.dart b/lib/components/animated_padding_component.dart index e055ee9..44d4e6d 100644 --- a/lib/components/animated_padding_component.dart +++ b/lib/components/animated_padding_component.dart @@ -11,13 +11,8 @@ class AnimatedPaddingComponent extends StatefulWidget { } class AnimatedPaddingComponentState extends State { - @override Widget build(BuildContext context) { - return AnimatedPadding( - duration: const Duration(milliseconds: 500), - padding: widget.padding, - child: widget.child - ); + return AnimatedPadding(duration: const Duration(milliseconds: 500), padding: widget.padding, child: widget.child); } } diff --git a/lib/components/bottom_navigation_bar.dart b/lib/components/bottom_navigation_bar.dart index f489a3d..925dea2 100644 --- a/lib/components/bottom_navigation_bar.dart +++ b/lib/components/bottom_navigation_bar.dart @@ -84,7 +84,9 @@ class BottomNavigationState extends State with TickerProviderS child: TextButton( onPressed: () => navigateForth(), child: Text( - selectedIndex != widget.pageCount - 1 ? AppLocalizations.of(context)!.next : AppLocalizations.of(context)!.connect_now, + selectedIndex != widget.pageCount - 1 + ? AppLocalizations.of(context)!.next + : AppLocalizations.of(context)!.connect_now, style: const TextStyle(color: Colors.grey), ), ), diff --git a/lib/components/language_switcher.dart b/lib/components/language_switcher.dart index c07ffe2..8eaf647 100644 --- a/lib/components/language_switcher.dart +++ b/lib/components/language_switcher.dart @@ -35,7 +35,7 @@ class _LanguageSwitcherState extends State { const SizedBox(width: 20), Text( locale.toUpperCase(), - style: TextStyle(color: primaryColor, fontSize: 16), + style: TextStyle(color: HumhubTheme.primaryColor, fontSize: 16), ), ], ), @@ -56,7 +56,7 @@ class _LanguageSwitcherState extends State { focusedBorder: InputBorder.none, ), value: _value(context), - icon: Icon(Icons.arrow_drop_down, color: primaryColor), + icon: Icon(Icons.arrow_drop_down, color: HumhubTheme.primaryColor), items: _items .mapIndexed( (localeString, index) => DropdownMenuItem( @@ -67,7 +67,7 @@ class _LanguageSwitcherState extends State { const SizedBox(width: 20), Text( localeString.toUpperCase(), - style: TextStyle(color: primaryColor, fontSize: 16), + style: TextStyle(color: HumhubTheme.primaryColor, fontSize: 16), ), ], ), diff --git a/lib/components/rotating_globe.dart b/lib/components/rotating_globe.dart index bdc5eed..da77b25 100644 --- a/lib/components/rotating_globe.dart +++ b/lib/components/rotating_globe.dart @@ -29,7 +29,7 @@ class _RotatingGlobeState extends State with TickerProviderStateM @override Widget build(BuildContext context) { - if(_controller.isCompleted){ + if (_controller.isCompleted) { _animation = widget.rotationDirection == Direction.left ? _animationSec : _animationFir; _controller.reset(); } diff --git a/lib/models/channel_message.g.dart b/lib/models/channel_message.g.dart index 9c5290d..dff8270 100644 --- a/lib/models/channel_message.g.dart +++ b/lib/models/channel_message.g.dart @@ -1,30 +1,24 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'channel_message.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -ChannelMessage _$ChannelMessageFromJson(String json) { - if (json == "humhub.mobile.hideOpener") { - return ChannelMessage( - "hideOpener", - null, - null, - ); - } else if (json == "humhub.mobile.showOpener") { - return ChannelMessage( - "showOpener", - null, - null, - ); - } else { - var jsonMap = jsonDecode(json) as Map; - return ChannelMessage( - jsonMap['type'] as String, - jsonMap['url'] as String?, - jsonMap['count'] as int?, - ); - } -} +part of 'channel_message.dart'; + +ChannelMessage _$ChannelMessageFromJson(String json) { + if (json == "humhub.mobile.hideOpener") { + return ChannelMessage( + "hideOpener", + null, + null, + ); + } else if (json == "humhub.mobile.showOpener") { + return ChannelMessage( + "showOpener", + null, + null, + ); + } else { + var jsonMap = jsonDecode(json) as Map; + return ChannelMessage( + jsonMap['type'] as String, + jsonMap['url'] as String?, + jsonMap['count'] as int?, + ); + } +} diff --git a/lib/models/event.dart b/lib/models/event.dart index 2f1935d..1b425f0 100644 --- a/lib/models/event.dart +++ b/lib/models/event.dart @@ -7,20 +7,20 @@ class PushEvent extends RemoteMessage { PushEvent(RemoteMessage message) : parsedData = PushEventData.fromJson(message.data), super( - senderId: message.senderId, - category: message.category, - collapseKey: message.collapseKey, - contentAvailable: message.contentAvailable, - data: message.data, - from: message.from, - messageId: message.messageId, - messageType: message.messageType, - mutableContent: message.mutableContent, - notification: message.notification, - sentTime: message.sentTime, - threadId: message.threadId, - ttl: message.ttl, - ); + senderId: message.senderId, + category: message.category, + collapseKey: message.collapseKey, + contentAvailable: message.contentAvailable, + data: message.data, + from: message.from, + messageId: message.messageId, + messageType: message.messageType, + mutableContent: message.mutableContent, + notification: message.notification, + sentTime: message.sentTime, + threadId: message.threadId, + ttl: message.ttl, + ); } class PushEventData { @@ -32,13 +32,13 @@ class PushEventData { final String? notificationCount; PushEventData( - this.notificationTitle, - this.notificationBody, - this.channel, - this.channelPayload, - this.redirectUrl, - this.notificationCount, - ); + this.notificationTitle, + this.notificationBody, + this.channel, + this.channelPayload, + this.redirectUrl, + this.notificationCount, + ); factory PushEventData.fromJson(Map json) => _$PushEventDataFromJson(json); } diff --git a/lib/models/event.g.dart b/lib/models/event.g.dart index 374d64b..becfc11 100644 --- a/lib/models/event.g.dart +++ b/lib/models/event.g.dart @@ -1,14 +1,13 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - part of 'event.dart'; -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - PushEventData _$PushEventDataFromJson(Map json) { - return PushEventData(json['notification_title'] as String?, json['notification_body'] as String?, json['channel'] as String?, - json['channel_payload'] as String?, json['url'] as String?, json['notification_count'] as String?); + return PushEventData( + json['notification_title'] as String?, + json['notification_body'] as String?, + json['channel'] as String?, + json['channel_payload'] as String?, + json['url'] as String?, + json['notification_count'] as String?); } SimpleNotification _$SimpleNotificationFromJson(Map json) { diff --git a/lib/models/hum_hub.dart b/lib/models/hum_hub.dart index 19873a0..8203dc9 100644 --- a/lib/models/hum_hub.dart +++ b/lib/models/hum_hub.dart @@ -1,6 +1,6 @@ import 'dart:math'; import 'package:humhub/models/manifest.dart'; -import 'package:humhub/util/universal_opener_controller.dart'; +import 'package:humhub/util/openers/universal_opener_controller.dart'; enum RedirectAction { opener, webView } diff --git a/lib/pages/help/components/first_page.dart b/lib/pages/help/components/first_page.dart index cb3177a..13eb670 100644 --- a/lib/pages/help/components/first_page.dart +++ b/lib/pages/help/components/first_page.dart @@ -3,10 +3,12 @@ import 'package:humhub/components/rotating_globe.dart'; import 'package:humhub/util/const.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - class FirstPage extends StatelessWidget { final bool fadeIn; - const FirstPage({Key? key, required this.fadeIn,}) : super(key: key); + const FirstPage({ + Key? key, + required this.fadeIn, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -22,7 +24,7 @@ class FirstPage extends StatelessWidget { alignment: Alignment.centerLeft, child: Text( AppLocalizations.of(context)!.help_title, - style: getHeaderStyle(context), + style: HumhubTheme.getHeaderStyle(context), ), ), ), @@ -30,12 +32,12 @@ class FirstPage extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: 10), child: Text( AppLocalizations.of(context)!.help_first_par, - style: paragraphStyle, + style: HumhubTheme.paragraphStyle, ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 10), - child: Text(AppLocalizations.of(context)!.help_second_par, style: paragraphStyle), + child: Text(AppLocalizations.of(context)!.help_second_par, style: HumhubTheme.paragraphStyle), ), Center( child: RotatingGlobe( diff --git a/lib/pages/help/components/second_page.dart b/lib/pages/help/components/second_page.dart index 94b5a9e..2d9deb4 100644 --- a/lib/pages/help/components/second_page.dart +++ b/lib/pages/help/components/second_page.dart @@ -21,13 +21,13 @@ class SecondPage extends StatelessWidget { alignment: Alignment.centerLeft, child: Text( AppLocalizations.of(context)!.how_to_connect_title, - style: getHeaderStyle(context), + style: HumhubTheme.getHeaderStyle(context), ), ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 10), - child: Text(AppLocalizations.of(context)!.how_to_connect_first_par, style: paragraphStyle), + child: Text(AppLocalizations.of(context)!.how_to_connect_first_par, style: HumhubTheme.paragraphStyle), ), EaseOutContainer( fadeIn: fadeIn, @@ -79,7 +79,7 @@ class SecondPage extends StatelessWidget { ), Padding( padding: const EdgeInsets.symmetric(vertical: 10), - child: Text(AppLocalizations.of(context)!.how_to_connect_sec_par, style: paragraphStyle), + child: Text(AppLocalizations.of(context)!.how_to_connect_sec_par, style: HumhubTheme.paragraphStyle), ), EaseOutContainer( fadeIn: fadeIn, @@ -94,7 +94,7 @@ class SecondPage extends StatelessWidget { style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (Set states) { - return primaryColor; + return HumhubTheme.primaryColor; }, ), ), @@ -114,7 +114,7 @@ class SecondPage extends StatelessWidget { ), Padding( padding: const EdgeInsets.symmetric(vertical: 20), - child: Text(AppLocalizations.of(context)!.how_to_connect_third_par, style: paragraphStyle), + child: Text(AppLocalizations.of(context)!.how_to_connect_third_par, style: HumhubTheme.paragraphStyle), ) ], ), diff --git a/lib/pages/help/components/third_page.dart b/lib/pages/help/components/third_page.dart index 6781c1f..465d551 100644 --- a/lib/pages/help/components/third_page.dart +++ b/lib/pages/help/components/third_page.dart @@ -22,21 +22,21 @@ class ThirdPage extends StatelessWidget { alignment: Alignment.centerLeft, child: Text( AppLocalizations.of(context)!.more_info_title, - style: getHeaderStyle(context), + style: HumhubTheme.getHeaderStyle(context), ), ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 10), - child: Text(AppLocalizations.of(context)!.more_info_first_par, style: paragraphStyle), + child: Text(AppLocalizations.of(context)!.more_info_first_par, style: HumhubTheme.paragraphStyle), ), Padding( padding: const EdgeInsets.symmetric(vertical: 10), - child: Text(AppLocalizations.of(context)!.more_info_second_par, style: paragraphStyle), + child: Text(AppLocalizations.of(context)!.more_info_second_par, style: HumhubTheme.paragraphStyle), ), Padding( padding: const EdgeInsets.symmetric(vertical: 10), - child: Text(AppLocalizations.of(context)!.more_info_third_par, style: paragraphStyle), + child: Text(AppLocalizations.of(context)!.more_info_third_par, style: HumhubTheme.paragraphStyle), ), const SizedBox( height: 40, @@ -54,12 +54,13 @@ class ThirdPage extends StatelessWidget { style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (Set states) { - return primaryColor; + return HumhubTheme.primaryColor; }, ), ), onPressed: () { - launchUrl(Uri.parse(AppLocalizations.of(context)!.more_info_pro_edition_url), mode: LaunchMode.platformDefault); + launchUrl(Uri.parse(AppLocalizations.of(context)!.more_info_pro_edition_url), + mode: LaunchMode.platformDefault); }, child: Center( child: Text( diff --git a/lib/pages/opener.dart b/lib/pages/opener.dart index ddbcf7c..2f0b7ad 100644 --- a/lib/pages/opener.dart +++ b/lib/pages/opener.dart @@ -8,7 +8,7 @@ import 'package:humhub/util/const.dart'; import 'package:humhub/util/form_helper.dart'; import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/notifications/channel.dart'; -import 'package:humhub/util/opener_controller.dart'; +import 'package:humhub/util/openers/opener_controller.dart'; import 'package:humhub/util/providers.dart'; import 'package:rive/rive.dart'; import 'help/help_android.dart'; @@ -171,7 +171,7 @@ class OpenerState extends ConsumerState with SingleTickerProviderStateMi onPressed: _connectInstance, child: Text( AppLocalizations.of(context)!.connect, - style: TextStyle(color: primaryColor, fontSize: 20), + style: TextStyle(color: HumhubTheme.primaryColor, fontSize: 20), ), ), ), diff --git a/lib/pages/web_view.dart b/lib/pages/web_view.dart index bba9395..d0f73a8 100644 --- a/lib/pages/web_view.dart +++ b/lib/pages/web_view.dart @@ -16,7 +16,8 @@ import 'package:humhub/util/connectivity_plugin.dart'; import 'package:humhub/util/extensions.dart'; import 'package:humhub/util/notifications/channel.dart'; import 'package:humhub/util/providers.dart'; -import 'package:humhub/util/universal_opener_controller.dart'; +import 'package:humhub/util/openers/universal_opener_controller.dart'; +import 'package:humhub/util/push/provider.dart'; import 'package:humhub/util/router.dart'; import 'package:loggy/loggy.dart'; import 'package:permission_handler/permission_handler.dart'; diff --git a/lib/util/connectivity_plugin.dart b/lib/util/connectivity_plugin.dart index 6052083..1059957 100644 --- a/lib/util/connectivity_plugin.dart +++ b/lib/util/connectivity_plugin.dart @@ -15,11 +15,11 @@ class NoConnectionDialog extends StatelessWidget { @override Widget build(BuildContext context) { return AlertDialog( - title: Text(AppLocalizations.of(context)!.connectivity_popup_title), - content: Text(AppLocalizations.of(context)!.connectivity_popup_content), + title: Text(AppLocalizations.of(context)!.connectivity_popup_title), + content: Text(AppLocalizations.of(context)!.connectivity_popup_content), actions: [ TextButton( - child: Text(AppLocalizations.of(context)!.ok.toUpperCase()), + child: Text(AppLocalizations.of(context)!.ok.toUpperCase()), onPressed: () { Navigator.of(context).pop(); // Close the dialog }, @@ -32,7 +32,9 @@ class NoConnectionDialog extends StatelessWidget { showDialog( context: context, builder: (BuildContext context) { - return const NoConnectionDialog(); + return NoConnectionDialog( + key: context.widget.key, + ); }, ); } diff --git a/lib/util/const.dart b/lib/util/const.dart index dfb7957..71137f3 100644 --- a/lib/util/const.dart +++ b/lib/util/const.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; class StorageKeys { static String humhubInstance = "humHubInstance"; static String lastInstanceUrl = "humHubLastUrl"; - } class Assets { @@ -13,11 +12,13 @@ class Assets { static String openerAnimationReverse = "assets/opener_animation_reverse.riv"; } -Color primaryColor = const Color(0xFF21a1b3); +class HumhubTheme { + static Color primaryColor = const Color(0xFF21a1b3); -TextStyle? getHeaderStyle(context) { - return Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w600); -} + static TextStyle? getHeaderStyle(context) { + return Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w600); + } -TextStyle paragraphStyle = - const TextStyle(letterSpacing: 0.5, fontWeight: FontWeight.normal, color: Colors.black, fontSize: 15); + static TextStyle paragraphStyle = + const TextStyle(letterSpacing: 0.5, fontWeight: FontWeight.normal, color: Colors.black, fontSize: 15); +} diff --git a/lib/util/extensions.dart b/lib/util/extensions.dart index f752787..17d23a5 100644 --- a/lib/util/extensions.dart +++ b/lib/util/extensions.dart @@ -18,8 +18,7 @@ extension MyWebViewController on InAppWebViewController { final exitConfirmed = await showDialog( context: context, builder: (context) => AlertDialog( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(10.0))), + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0))), title: Text(AppLocalizations.of(context)!.web_view_exit_popup_title), content: Text(AppLocalizations.of(context)!.web_view_exit_popup_content), actions: [ @@ -58,7 +57,7 @@ class HexColor extends Color { return int.parse(hexColor, radix: 16); } catch (e) { logError("Color from manifest is not valid use primary color"); - return primaryColor.value; + return HumhubTheme.primaryColor.value; } } diff --git a/lib/util/form_helper.dart b/lib/util/form_helper.dart index bfd0b2b..fd93f41 100644 --- a/lib/util/form_helper.dart +++ b/lib/util/form_helper.dart @@ -11,4 +11,4 @@ class FormHelper { bool validate() => key.currentState?.validate() ?? false; void save() => key.currentState?.save(); -} \ No newline at end of file +} diff --git a/lib/util/intent/intent_plugin.dart b/lib/util/intent/intent_plugin.dart index 245a852..7b98b92 100644 --- a/lib/util/intent/intent_plugin.dart +++ b/lib/util/intent/intent_plugin.dart @@ -7,7 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/pages/web_view.dart'; import 'package:humhub/util/loading_provider.dart'; import 'package:humhub/util/router.dart'; -import 'package:humhub/util/universal_opener_controller.dart'; +import 'package:humhub/util/openers/universal_opener_controller.dart'; import 'package:loggy/loggy.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:uni_links/uni_links.dart'; diff --git a/lib/util/log.dart b/lib/util/log.dart index 0bd8661..b8d6956 100644 --- a/lib/util/log.dart +++ b/lib/util/log.dart @@ -11,8 +11,7 @@ class GlobalLog extends LoggyPrinter { bool get _colorize => showColors ?? false; static final _levelColors = { - LogLevel.debug: - AnsiColor(foregroundColor: AnsiColor.grey(0.5), italic: true), + LogLevel.debug: AnsiColor(foregroundColor: AnsiColor.grey(0.5), italic: true), LogLevel.info: AnsiColor(foregroundColor: 35), LogLevel.warning: AnsiColor(foregroundColor: 214), LogLevel.error: AnsiColor(foregroundColor: 196), @@ -30,21 +29,14 @@ class GlobalLog extends LoggyPrinter { @override void onLog(LogRecord record) { final time = record.time.toIso8601String().split('T')[1]; - final callerFrame = - record.callerFrame == null ? '-' : '(${record.callerFrame?.location})'; - final logLevel = record.level - .toString() - .replaceAll('Level.', '') - .toUpperCase() - .padRight(8); + final callerFrame = record.callerFrame == null ? '-' : '(${record.callerFrame?.location})'; + final logLevel = record.level.toString().replaceAll('Level.', '').toUpperCase().padRight(8); - final color = - _colorize ? levelColor(record.level) ?? AnsiColor() : AnsiColor(); + final color = _colorize ? levelColor(record.level) ?? AnsiColor() : AnsiColor(); final prefix = levelPrefix(record.level) ?? _defaultPrefix; if (kDebugMode) { - print(color( - '$prefix$time $logLevel GLOBAL $callerFrame ${record.message}')); + print(color('$prefix$time $logLevel GLOBAL $callerFrame ${record.message}')); } if (record.stackTrace != null) { @@ -61,4 +53,4 @@ class GlobalLog extends LoggyPrinter { AnsiColor? levelColor(LogLevel level) { return _levelColors[level]; } -} \ No newline at end of file +} diff --git a/lib/util/notifications/channel.dart b/lib/util/notifications/channel.dart index b38843f..0e23786 100644 --- a/lib/util/notifications/channel.dart +++ b/lib/util/notifications/channel.dart @@ -1,6 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:humhub/pages/web_view.dart'; -import 'package:humhub/util/universal_opener_controller.dart'; +import 'package:humhub/util/openers/universal_opener_controller.dart'; import 'package:humhub/util/router.dart'; import 'package:loggy/loggy.dart'; diff --git a/lib/util/opener_controller.dart b/lib/util/openers/opener_controller.dart similarity index 95% rename from lib/util/opener_controller.dart rename to lib/util/openers/opener_controller.dart index a5f9647..0ac8eca 100644 --- a/lib/util/opener_controller.dart +++ b/lib/util/openers/opener_controller.dart @@ -6,9 +6,9 @@ import 'package:humhub/models/manifest.dart'; import 'package:humhub/util/providers.dart'; import 'package:http/http.dart' as http; import 'package:loggy/loggy.dart'; -import 'api_provider.dart'; -import 'connectivity_plugin.dart'; -import 'form_helper.dart'; +import '../api_provider.dart'; +import '../connectivity_plugin.dart'; +import '../form_helper.dart'; class OpenerController { late AsyncValue? asyncData; @@ -93,7 +93,9 @@ class OpenerController { String currentUrl = urlTextController.text; String hash = HumHub.generateHash(32); if (lastUrl == currentUrl) hash = ref.read(humHubProvider).randomHash ?? hash; - await ref.read(humHubProvider).setInstance(HumHub(manifest: manifest, randomHash: hash, manifestUrl: manifestUrl)); + await ref + .read(humHubProvider) + .setInstance(HumHub(manifest: manifest, randomHash: hash, manifestUrl: manifestUrl)); } } diff --git a/lib/util/universal_opener_controller.dart b/lib/util/openers/universal_opener_controller.dart similarity index 97% rename from lib/util/universal_opener_controller.dart rename to lib/util/openers/universal_opener_controller.dart index 8a9f96d..1177193 100644 --- a/lib/util/universal_opener_controller.dart +++ b/lib/util/openers/universal_opener_controller.dart @@ -3,8 +3,8 @@ import 'package:http/http.dart'; import 'package:humhub/models/hum_hub.dart'; import 'package:humhub/models/manifest.dart'; import 'package:http/http.dart' as http; -import 'api_provider.dart'; -import 'connectivity_plugin.dart'; +import '../api_provider.dart'; +import '../connectivity_plugin.dart'; class UniversalOpenerController { late AsyncValue? asyncData; diff --git a/lib/util/override_locale.dart b/lib/util/override_locale.dart index 075035b..b73b0d0 100644 --- a/lib/util/override_locale.dart +++ b/lib/util/override_locale.dart @@ -15,9 +15,9 @@ class OverrideLocale extends StatefulWidget { static OverrideLocaleModel of(BuildContext context) { final result = context.dependOnInheritedWidgetOfExactType(); assert( - result != null, - 'No OverrideLocale found in context' - 'Place OverrideLocale widget as high in widget tree as possible.', + result != null, + 'No OverrideLocale found in context' + 'Place OverrideLocale widget as high in widget tree as possible.', ); return result!; } diff --git a/lib/util/providers.dart b/lib/util/providers.dart index 8704437..3bffdea 100644 --- a/lib/util/providers.dart +++ b/lib/util/providers.dart @@ -1,11 +1,9 @@ import 'dart:convert'; -import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:humhub/models/hum_hub.dart'; import 'package:humhub/models/manifest.dart'; -import 'package:humhub/util/extensions.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'const.dart'; @@ -42,7 +40,7 @@ class HumHubNotifier extends ChangeNotifier { _humHubInstance.isHideOpener = instance.isHideOpener; _humHubInstance.randomHash = instance.randomHash; _humHubInstance.appVersion = packageInfo.version; - _humHubInstance.manifestUrl = instance.manifestUrl; + _humHubInstance.manifestUrl = instance.manifestUrl; _updateSafeStorage(); notifyListeners(); } @@ -86,33 +84,3 @@ class HumHubNotifier extends ChangeNotifier { final humHubProvider = ChangeNotifierProvider((ref) { return HumHubNotifier(HumHub()); }); - -/// Remembers whether current FirebaseApp is initialized. -final firebaseInitialized = StateProvider>( - (ref) => const AsyncValue.loading(), -); - -final _pushTokenProvider = FutureProvider>( - (ref) async { - var initialized = ref.watch(firebaseInitialized.notifier).state; - if (initialized.isLoaded) { - return AsyncValue.guard(FirebaseMessaging.instance.getToken); - } - return const AsyncValue.loading(); - }, -); - -/// Provides current push token. Will wait until Firebase is initialized. -/// -/// See also: -/// * [_PushPluginState._init] -final pushTokenProvider = Provider>( - (ref) { - var provider = ref.watch(_pushTokenProvider); - return provider.when( - data: (value) => value, - error: (e, s) => AsyncValue.error(e, s), - loading: () => const AsyncValue.loading(), - ); - }, -); diff --git a/lib/util/push/provider.dart b/lib/util/push/provider.dart new file mode 100644 index 0000000..76ce8b4 --- /dev/null +++ b/lib/util/push/provider.dart @@ -0,0 +1,33 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/util/extensions.dart'; + +/// Remembers whether current FirebaseApp is initialized. +final firebaseInitialized = StateProvider>( + (ref) => const AsyncValue.loading(), +); + +final _pushTokenProvider = FutureProvider>( + (ref) async { + var initialized = ref.watch(firebaseInitialized.notifier).state; + if (initialized.isLoaded) { + return AsyncValue.guard(FirebaseMessaging.instance.getToken); + } + return const AsyncValue.loading(); + }, +); + +/// Provides current push token. Will wait until Firebase is initialized. +/// +/// See also: +/// * [_PushPluginState._init] +final pushTokenProvider = Provider>( + (ref) { + var provider = ref.watch(_pushTokenProvider); + return provider.when( + data: (value) => value, + error: (e, s) => AsyncValue.error(e, s), + loading: () => const AsyncValue.loading(), + ); + }, +); diff --git a/lib/util/push/push_plugin.dart b/lib/util/push/push_plugin.dart index a01195a..43448db 100644 --- a/lib/util/push/push_plugin.dart +++ b/lib/util/push/push_plugin.dart @@ -7,8 +7,8 @@ import 'package:humhub/models/event.dart'; import 'package:humhub/util/notifications/channel.dart'; import 'package:humhub/util/notifications/plugin.dart'; import 'package:humhub/util/notifications/service.dart'; +import 'package:humhub/util/push/provider.dart'; import 'package:humhub/util/push/register_token_plugin.dart'; -import 'package:humhub/util/providers.dart'; import 'package:loggy/loggy.dart'; class PushPlugin extends ConsumerStatefulWidget { diff --git a/lib/util/push/register_token_plugin.dart b/lib/util/push/register_token_plugin.dart index 329c27f..f01d169 100644 --- a/lib/util/push/register_token_plugin.dart +++ b/lib/util/push/register_token_plugin.dart @@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/util/api_provider.dart'; import 'package:humhub/util/extensions.dart'; import 'package:humhub/util/providers.dart'; +import 'package:humhub/util/push/provider.dart'; import 'package:loggy/loggy.dart'; class RegisterToken extends ConsumerWidget { @@ -42,7 +43,7 @@ class _RegisterToken extends ConsumerStatefulWidget { _RegisterTokenState createState() => _RegisterTokenState(); } -class _RegisterTokenState extends ConsumerState<_RegisterToken>{ +class _RegisterTokenState extends ConsumerState<_RegisterToken> { Future _maybeRegisterToken() async { final token = await FirebaseMessaging.instance.getToken(); if (token == null) { @@ -66,13 +67,13 @@ class _RegisterTokenState extends ConsumerState<_RegisterToken>{ } Future Function(Dio dio) _registerToken(String? token) => (dio) async { - await dio.post( - '/fcm-push/token/update', - data: { - 'token': token, - }, - ); - }; + await dio.post( + '/fcm-push/token/update', + data: { + 'token': token, + }, + ); + }; @override void didUpdateWidget(oldWidget) { diff --git a/test/opener_test.dart b/test/opener_test.dart index 6acfdf1..a8a7758 100644 --- a/test/opener_test.dart +++ b/test/opener_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:humhub/util/opener_controller.dart'; +import 'package:humhub/util/openers/opener_controller.dart'; void main() { void testGroupOfURIs(Map uriMap) { From b2e990b89d71602cce62542f4e64a437106c4cd7 Mon Sep 17 00:00:00 2001 From: primozratej Date: Fri, 17 May 2024 14:04:21 +0200 Subject: [PATCH 08/31] SecureStorageService and split app logic --- lib/apps/opener_app.dart | 57 +++++++++++++++++++++++++++ lib/main.dart | 73 ++--------------------------------- lib/util/storage_service.dart | 29 ++++++++++++++ 3 files changed, 90 insertions(+), 69 deletions(-) create mode 100644 lib/apps/opener_app.dart create mode 100644 lib/util/storage_service.dart diff --git a/lib/apps/opener_app.dart b/lib/apps/opener_app.dart new file mode 100644 index 0000000..d4d3e50 --- /dev/null +++ b/lib/apps/opener_app.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/util/intent/intent_plugin.dart'; +import 'package:humhub/util/loading_provider.dart'; +import 'package:humhub/util/notifications/plugin.dart'; +import 'package:humhub/util/override_locale.dart'; +import 'package:humhub/util/push/push_plugin.dart'; +import 'package:humhub/util/router.dart'; +import 'package:humhub/util/storage_service.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class OpenerApp extends ConsumerStatefulWidget { + const OpenerApp({super.key}); + + @override + MyAppState createState() => MyAppState(); +} + +class MyAppState extends ConsumerState { + @override + Widget build(BuildContext context) { + SecureStorageService.clearSecureStorageOnReinstall(); + return IntentPlugin( + child: NotificationPlugin( + child: PushPlugin( + child: OverrideLocale( + builder: (overrideLocale) => Builder( + builder: (context) => FutureBuilder( + future: MyRouter.getInitialRoute(ref), + builder: (context, snap) { + if (snap.hasData) { + return MaterialApp( + debugShowCheckedModeBanner: false, + initialRoute: snap.data, + routes: MyRouter.routes, + navigatorKey: navigatorKey, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + locale: overrideLocale, + builder: (context, child) => LoadingProvider( + child: child!, + ), + theme: ThemeData( + fontFamily: 'OpenSans', + ), + ); + } + return const SizedBox.shrink(); + }, + ), + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index b6557da..784de05 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,83 +1,18 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:humhub/util/intent/intent_plugin.dart'; -import 'package:humhub/util/loading_provider.dart'; import 'package:humhub/util/log.dart'; -import 'package:humhub/util/notifications/plugin.dart'; -import 'package:humhub/util/override_locale.dart'; -import 'package:humhub/util/push/push_plugin.dart'; -import 'package:humhub/util/router.dart'; +import 'package:humhub/util/storage_service.dart'; import 'package:loggy/loggy.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'apps/opener_app.dart'; main() async { Loggy.initLoggy( logPrinter: const GlobalLog(), ); WidgetsFlutterBinding.ensureInitialized(); - await clearSecureStorageOnReinstall(); + await SecureStorageService.clearSecureStorageOnReinstall(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) { - runApp(const ProviderScope(child: MyApp())); + runApp(const ProviderScope(child: OpenerApp())); }); } - -class MyApp extends ConsumerStatefulWidget { - const MyApp({super.key}); - - @override - MyAppState createState() => MyAppState(); -} - -class MyAppState extends ConsumerState { - @override - Widget build(BuildContext context) { - clearSecureStorageOnReinstall(); - return IntentPlugin( - child: NotificationPlugin( - child: PushPlugin( - child: OverrideLocale( - builder: (overrideLocale) => Builder( - builder: (context) => FutureBuilder( - future: MyRouter.getInitialRoute(ref), - builder: (context, snap) { - if (snap.hasData) { - return MaterialApp( - debugShowCheckedModeBanner: false, - initialRoute: snap.data, - routes: MyRouter.routes, - navigatorKey: navigatorKey, - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - locale: overrideLocale, - builder: (context, child) => LoadingProvider( - child: child!, - ), - theme: ThemeData( - fontFamily: 'OpenSans', - ), - ); - } - return const SizedBox.shrink(); - }, - ), - ), - ), - ), - ), - ); - } -} - -clearSecureStorageOnReinstall() async { - String key = 'hasRunBefore'; - SharedPreferences prefs = await SharedPreferences.getInstance(); - bool hasRunBefore = prefs.getBool(key) ?? false; - if (!hasRunBefore) { - FlutterSecureStorage storage = const FlutterSecureStorage(); - await storage.deleteAll(); - prefs.setBool(key, true); - } -} diff --git a/lib/util/storage_service.dart b/lib/util/storage_service.dart new file mode 100644 index 0000000..3963f2b --- /dev/null +++ b/lib/util/storage_service.dart @@ -0,0 +1,29 @@ +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class SecureStorageService { + // Private constructor + static const FlutterSecureStorage _instance = FlutterSecureStorage(); + + // Factory constructor that returns the single instance + factory SecureStorageService() { + return SecureStorageService._internal(); + } + + // Private named constructor + SecureStorageService._internal(); + + // Method to access the single instance of FlutterSecureStorage + static FlutterSecureStorage get instance => _instance; + + static clearSecureStorageOnReinstall() async { + String key = 'hasRunBefore'; + SharedPreferences prefs = await SharedPreferences.getInstance(); + bool hasRunBefore = prefs.getBool(key) ?? false; + if (!hasRunBefore) { + FlutterSecureStorage storage = const FlutterSecureStorage(); + await storage.deleteAll(); + prefs.setBool(key, true); + } + } +} From 707419e46afb1caa34bd743dd8b7cc5c9b4d886f Mon Sep 17 00:00:00 2001 From: primozratej Date: Sun, 19 May 2024 21:06:01 +0200 Subject: [PATCH 09/31] Add logic for white labeled app --- lib/apps/flavored/models/humhub.f.dart | 21 ++ lib/apps/flavored/models/manifest.f.dart | 25 ++ lib/apps/flavored/web_view.f.dart | 245 ++++++++++++++++++ lib/apps/flavored_app.dart | 42 +++ lib/apps/opener_app.dart | 4 +- lib/main.dart | 16 +- lib/models/manifest.dart | 14 +- lib/pages/web_view.dart | 12 +- .../auth_in_app_browser.dart | 0 lib/util/notifications/plugin.dart | 9 + lib/util/show_dialog.dart | 58 +++++ lib/util/web_view_global_controller.dart | 11 + pubspec.lock | 8 + pubspec.yaml | 2 + 14 files changed, 445 insertions(+), 22 deletions(-) create mode 100644 lib/apps/flavored/models/humhub.f.dart create mode 100644 lib/apps/flavored/models/manifest.f.dart create mode 100644 lib/apps/flavored/web_view.f.dart create mode 100644 lib/apps/flavored_app.dart rename lib/{components => util}/auth_in_app_browser.dart (100%) create mode 100644 lib/util/show_dialog.dart create mode 100644 lib/util/web_view_global_controller.dart diff --git a/lib/apps/flavored/models/humhub.f.dart b/lib/apps/flavored/models/humhub.f.dart new file mode 100644 index 0000000..37e10e6 --- /dev/null +++ b/lib/apps/flavored/models/humhub.f.dart @@ -0,0 +1,21 @@ +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:humhub/apps/flavored/models/manifest.f.dart'; +import 'package:humhub/models/hum_hub.dart'; + +class HumHubF extends HumHub{ + @override + ManifestF get manifest => ManifestF.fromEnv(); + @override + String get manifestUrl => dotenv.env['MANIFEST_URL']!; + + HumHubF({ + bool isHideOpener = false, + String? randomHash, + String? appVersion, + String? pushToken, + }) : super( + isHideOpener: isHideOpener, + randomHash: HumHub.generateHash(32), + appVersion: appVersion, + pushToken: pushToken); +} \ No newline at end of file diff --git a/lib/apps/flavored/models/manifest.f.dart b/lib/apps/flavored/models/manifest.f.dart new file mode 100644 index 0000000..6f6cbbc --- /dev/null +++ b/lib/apps/flavored/models/manifest.f.dart @@ -0,0 +1,25 @@ +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:humhub/models/manifest.dart'; + +class ManifestF extends Manifest{ + ManifestF({ + required String display, required String startUrl, required String shortName, required String name, required String backgroundColor, required String themeColor + }) : super( + display: display, + startUrl: startUrl, + shortName: shortName, + name: name, + backgroundColor: backgroundColor, + themeColor: themeColor); + + factory ManifestF.fromEnv() { + return ManifestF( + display: dotenv.env['DISPLAY']!, + startUrl: dotenv.env['START_URL']!, + shortName: dotenv.env['SHORT_NAME']!, + name: dotenv.env['NAME']!, + backgroundColor: dotenv.env['BACKGROUND_COLOR']!, + themeColor: dotenv.env['THEME_COLOR']!, + ); + } +} \ No newline at end of file diff --git a/lib/apps/flavored/web_view.f.dart b/lib/apps/flavored/web_view.f.dart new file mode 100644 index 0000000..6f0af5b --- /dev/null +++ b/lib/apps/flavored/web_view.f.dart @@ -0,0 +1,245 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_app_badger/flutter_app_badger.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/apps/flavored/models/humhub.f.dart'; +import 'package:humhub/util/auth_in_app_browser.dart'; +import 'package:humhub/models/channel_message.dart'; +import 'package:humhub/util/extensions.dart'; +import 'package:humhub/util/loading_provider.dart'; +import 'package:humhub/util/notifications/channel.dart'; +import 'package:humhub/util/notifications/plugin.dart'; +import 'package:humhub/util/providers.dart'; +import 'package:humhub/util/push/provider.dart'; +import 'package:humhub/util/show_dialog.dart'; +import 'package:humhub/util/web_view_global_controller.dart'; +import 'package:loggy/loggy.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class WebViewF extends ConsumerStatefulWidget { + const WebViewF({super.key}); + + @override + FlavoredWebViewState createState() => FlavoredWebViewState(); +} + +class FlavoredWebViewState extends ConsumerState { + HumHubF instance = HumHubF(); + late AuthInAppBrowser _authBrowser; + HeadlessInAppWebView? headlessWebView; + + @override + void initState() { + _authBrowser = AuthInAppBrowser( + manifest: instance.manifest, + concludeAuth: (URLRequest request) { + _concludeAuth(request); + }, + ); + super.initState(); + } + + @override + Widget build(BuildContext context) { + // ignore: deprecated_member_use + return WillPopScope( + onWillPop: () => WebViewGlobalController.value!.exitApp(context, ref), + child: Scaffold( + backgroundColor: HexColor(instance.manifest.themeColor), + body: SafeArea( + bottom: false, + child: InAppWebView( + initialUrlRequest: _initialRequest, + initialOptions: _options, + pullToRefreshController: _pullToRefreshController, + shouldOverrideUrlLoading: _shouldOverrideUrlLoading, + onWebViewCreated: _onWebViewCreated, + shouldInterceptFetchRequest: _shouldInterceptFetchRequest, + onCreateWindow: _onCreateWindow, + onLoadStop: _onLoadStop, + onLoadStart: _onLoadStart, + onLoadError: _onLoadError, + onProgressChanged: _onProgressChanged, + ), + ), + ), + ); + } + + URLRequest get _initialRequest { + String? url = instance.manifest.startUrl; + String? payloadFromPush = InitFromPush.usePayload(); + if (payloadFromPush != null) url = payloadFromPush; + return URLRequest(url: Uri.parse(url), headers: instance.customHeaders); + } + + InAppWebViewGroupOptions get _options => InAppWebViewGroupOptions( + crossPlatform: InAppWebViewOptions( + useShouldOverrideUrlLoading: true, + useShouldInterceptFetchRequest: true, + javaScriptEnabled: true, + supportZoom: false, + javaScriptCanOpenWindowsAutomatically: true, + ), + android: AndroidInAppWebViewOptions( + supportMultipleWindows: true, + ), + ); + + PullToRefreshController get _pullToRefreshController => PullToRefreshController( + options: PullToRefreshOptions( + color: HexColor(instance.manifest.themeColor), + ), + onRefresh: () async { + Uri? url = await WebViewGlobalController.value!.getUrl(); + if (url != null) { + WebViewGlobalController.value!.loadUrl( + urlRequest: URLRequest( + url: await WebViewGlobalController.value!.getUrl(), headers: ref.read(humHubProvider).customHeaders), + ); + } else { + WebViewGlobalController.value!.reload(); + } + }, + ); + + Future _shouldOverrideUrlLoading( + InAppWebViewController controller, NavigationAction action) async { + // 1st check if url is not def. app url and open it in a browser or inApp. + _setAjaxHeadersJQuery(controller); + final url = action.request.url!.origin; + if (!url.startsWith(instance.manifest.baseUrl) && action.isForMainFrame) { + _authBrowser.launchUrl(action.request); + return NavigationActionPolicy.CANCEL; + } + // 2nd Append customHeader if url is in app redirect and CANCEL the requests without custom headers + if (Platform.isAndroid || + action.iosWKNavigationType == IOSWKNavigationType.LINK_ACTIVATED || + action.iosWKNavigationType == IOSWKNavigationType.FORM_SUBMITTED) { + Map mergedMap = {...instance.customHeaders, ...?action.request.headers}; + URLRequest newRequest = action.request.copyWith(headers: mergedMap); + controller.loadUrl(urlRequest: newRequest); + return NavigationActionPolicy.CANCEL; + } + return NavigationActionPolicy.ALLOW; + } + + Future _onWebViewCreated(InAppWebViewController controller) async { + LoadingProvider.of(ref).showLoading(); + headlessWebView = HeadlessInAppWebView(); + headlessWebView!.run(); + await controller.addWebMessageListener( + WebMessageListener( + jsObjectName: "flutterChannel", + onPostMessage: (inMessage, sourceOrigin, isMainFrame, replyProxy) async { + ChannelMessage message = ChannelMessage.fromJson(inMessage!); + await _handleJSMessage(message, headlessWebView!); + }, + ), + ); + WebViewGlobalController.setValue(controller); + } + + Future _shouldInterceptFetchRequest(InAppWebViewController controller, FetchRequest request) async { + request.headers!.addAll(_initialRequest.headers!); + return request; + } + + Future _onCreateWindow(inAppWebViewController, createWindowAction) async { + logDebug("onCreateWindow"); + final urlToOpen = createWindowAction.request.url; + if (urlToOpen == null) return Future.value(false); + if (await canLaunchUrl(urlToOpen)) { + await launchUrl(urlToOpen, mode: LaunchMode.externalApplication); + } else { + logError('Could not launch $urlToOpen'); + } + LoadingProvider.of(ref).dismissAll(); + return Future.value(true); // Allow creating a new window. + } + + Future _onLoadStop(InAppWebViewController controller, Uri? url) async { + // Disable remember me checkbox on login and set def. value to true: check if the page is actually login page, if it is inject JS that hides element + if (url!.path.contains('/user/auth/login')) { + WebViewGlobalController.value! + .evaluateJavascript(source: "document.querySelector('#login-rememberme').checked=true"); + WebViewGlobalController.value!.evaluateJavascript( + source: + "document.querySelector('#account-login-form > div.form-group.field-login-rememberme').style.display='none';"); + } + _setAjaxHeadersJQuery(controller); + await _pullToRefreshController.endRefreshing(); + LoadingProvider.of(ref).dismissAll(); + } + + Future _onLoadStart(InAppWebViewController controller, Uri? url) async { + await _setAjaxHeadersJQuery(controller); + LoadingProvider.of(ref).dismissAll(); + } + + void _onLoadError(InAppWebViewController controller, Uri? url, int code, String message) async { + if (code == -1009) ShowDialog.of(context).noInternetPopup(); + await _pullToRefreshController.endRefreshing(); + } + + void _onProgressChanged(controller, progress) async { + if (progress == 100) { + await _pullToRefreshController.endRefreshing(); + } + } + + void _concludeAuth(URLRequest request) { + _authBrowser.close(); + WebViewGlobalController.value!.loadUrl(urlRequest: request); + } + + Future _setAjaxHeadersJQuery(InAppWebViewController controller) async { + String jsCode = "\$.ajaxSetup({headers: ${jsonEncode(instance.customHeaders).toString()}});"; + await controller.evaluateJavascript(source: jsCode); + } + + Future _handleJSMessage(ChannelMessage message, HeadlessInAppWebView headlessWebView) async { + switch (message.action) { + case ChannelAction.registerFcmDevice: + String? token = ref.read(pushTokenProvider).value; + if (token != null) { + var postData = Uint8List.fromList(utf8.encode("token=$token")); + await headlessWebView.webViewController.postUrl(url: Uri.parse(message.url!), postData: postData); + } + var status = await Permission.notification.status; + // status.isDenied: The user has previously denied the notification permission + // !status.isGranted: The user has never been asked for the notification permission + bool wasAskedBefore = await NotificationPlugin.hasAskedPermissionBefore(); + // ignore: use_build_context_synchronously + if (status != PermissionStatus.granted && !wasAskedBefore) ShowDialog.of(context).notificationPermission(); + break; + case ChannelAction.updateNotificationCount: + if (message.count != null) FlutterAppBadger.updateBadgeCount(message.count!); + break; + case ChannelAction.unregisterFcmDevice: + String? token = ref.read(pushTokenProvider).value; + if (token != null) { + var postData = Uint8List.fromList(utf8.encode("token=$token")); + URLRequest request = URLRequest(url: Uri.parse(message.url!), method: "POST", body: postData); + // Works but for admin to see the changes it need to reload a page because a request is called on separate instance. + await headlessWebView.webViewController.loadUrl(urlRequest: request); + } + break; + default: + break; + } + } + + @override + void dispose() { + super.dispose(); + if (headlessWebView != null) { + headlessWebView!.dispose(); + } + } +} diff --git a/lib/apps/flavored_app.dart b/lib/apps/flavored_app.dart new file mode 100644 index 0000000..1c67a7e --- /dev/null +++ b/lib/apps/flavored_app.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/apps/flavored/web_view.f.dart'; +import 'package:humhub/util/intent/intent_plugin.dart'; +import 'package:humhub/util/loading_provider.dart'; +import 'package:humhub/util/notifications/plugin.dart'; +import 'package:humhub/util/override_locale.dart'; +import 'package:humhub/util/push/push_plugin.dart'; +import 'package:humhub/util/storage_service.dart'; + +class FlavoredApp extends ConsumerStatefulWidget { + const FlavoredApp({super.key}); + + @override + FlavoredAppState createState() => FlavoredAppState(); +} + +class FlavoredAppState extends ConsumerState { + @override + Widget build(BuildContext context) { + SecureStorageService.clearSecureStorageOnReinstall(); + return IntentPlugin( + child: NotificationPlugin( + child: PushPlugin( + child: OverrideLocale( + builder: (overrideLocale) => Builder( + builder: (context) => MaterialApp( + debugShowCheckedModeBanner: false, + builder: (context, child) => const LoadingProvider( + child: WebViewF(), + ), + theme: ThemeData( + fontFamily: 'OpenSans', + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/apps/opener_app.dart b/lib/apps/opener_app.dart index d4d3e50..71e7462 100644 --- a/lib/apps/opener_app.dart +++ b/lib/apps/opener_app.dart @@ -13,10 +13,10 @@ class OpenerApp extends ConsumerStatefulWidget { const OpenerApp({super.key}); @override - MyAppState createState() => MyAppState(); + OpenerAppState createState() => OpenerAppState(); } -class MyAppState extends ConsumerState { +class OpenerAppState extends ConsumerState { @override Widget build(BuildContext context) { SecureStorageService.clearSecureStorageOnReinstall(); diff --git a/lib/main.dart b/lib/main.dart index 784de05..78c1d16 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/apps/flavored_app.dart'; import 'package:humhub/util/log.dart'; import 'package:humhub/util/storage_service.dart'; import 'package:loggy/loggy.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'apps/opener_app.dart'; main() async { @@ -12,7 +15,14 @@ main() async { ); WidgetsFlutterBinding.ensureInitialized(); await SecureStorageService.clearSecureStorageOnReinstall(); - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) { - runApp(const ProviderScope(child: OpenerApp())); - }); + + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + if (packageInfo.packageName == 'com.humhub.app') { + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) { + runApp(const ProviderScope(child: OpenerApp())); + }); + } else { + await dotenv.load(fileName: ".env"); + runApp(const ProviderScope(child: FlavoredApp())); + } } diff --git a/lib/models/manifest.dart b/lib/models/manifest.dart index f71c3d0..2ce792f 100644 --- a/lib/models/manifest.dart +++ b/lib/models/manifest.dart @@ -8,7 +8,7 @@ class Manifest { final String backgroundColor; final String themeColor; - Manifest(this.display, this.startUrl, this.shortName, this.name, this.backgroundColor, this.themeColor); + Manifest({required this.display, required this.startUrl, required this.shortName, required this.name, required this.backgroundColor, required this.themeColor}); String get baseUrl { Uri url = Uri.parse(startUrl); @@ -17,12 +17,12 @@ class Manifest { factory Manifest.fromJson(Map json) { return Manifest( - json['display'] as String, - json['start_url'] as String, - json['short_name'] as String, - json['name'] as String, - json['background_color'] as String, - json['theme_color'] as String, + display: json['display'] as String, + startUrl: json['start_url'] as String, + shortName: json['short_name'] as String, + name: json['name'] as String, + backgroundColor: json['background_color'] as String, + themeColor: json['theme_color'] as String, ); } diff --git a/lib/pages/web_view.dart b/lib/pages/web_view.dart index d0f73a8..12e904d 100644 --- a/lib/pages/web_view.dart +++ b/lib/pages/web_view.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:humhub/components/auth_in_app_browser.dart'; +import 'package:humhub/util/auth_in_app_browser.dart'; import 'package:humhub/models/channel_message.dart'; import 'package:humhub/models/hum_hub.dart'; import 'package:humhub/models/manifest.dart'; @@ -25,15 +25,7 @@ import 'package:humhub/util/router.dart' as m; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -class WebViewGlobalController { - static InAppWebViewController? _value; - - static InAppWebViewController? get value => _value; - - static void setValue(InAppWebViewController newValue) { - _value = newValue; - } -} +import '../util/web_view_global_controller.dart'; class WebViewApp extends ConsumerStatefulWidget { const WebViewApp({super.key}); diff --git a/lib/components/auth_in_app_browser.dart b/lib/util/auth_in_app_browser.dart similarity index 100% rename from lib/components/auth_in_app_browser.dart rename to lib/util/auth_in_app_browser.dart diff --git a/lib/util/notifications/plugin.dart b/lib/util/notifications/plugin.dart index f79ed02..257a1f9 100644 --- a/lib/util/notifications/plugin.dart +++ b/lib/util/notifications/plugin.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/util/notifications/service.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class NotificationPlugin extends StatefulWidget { final Widget child; @@ -17,6 +18,14 @@ class NotificationPlugin extends StatefulWidget { return plugin!; } + static Future hasAskedPermissionBefore() async { + String key = 'was_asked_before'; + SharedPreferences prefs = await SharedPreferences.getInstance(); + var data = prefs.getBool(key) ?? false; + prefs.setBool(key, true); + return data; + } + @override NotificationPluginState createState() => NotificationPluginState(); } diff --git a/lib/util/show_dialog.dart b/lib/util/show_dialog.dart new file mode 100644 index 0000000..780f758 --- /dev/null +++ b/lib/util/show_dialog.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:app_settings/app_settings.dart'; + +class ShowDialog { + final BuildContext context; + + ShowDialog(this.context); + + static ShowDialog of(BuildContext context) { + return ShowDialog(context); + } + + void notificationPermission() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(AppLocalizations.of(context)!.notification_permission_popup_title), + content: Text(AppLocalizations.of(context)!.notification_permission_popup_content), + actions: [ + TextButton( + child: Text(AppLocalizations.of(context)!.enable), + onPressed: () { + AppSettings.openAppSettings(); + Navigator.pop(context); + }, + ), + TextButton( + child: Text(AppLocalizations.of(context)!.skip), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + ); + } + + noInternetPopup(){ + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(AppLocalizations.of(context)!.connectivity_popup_title), + content: Text(AppLocalizations.of(context)!.connectivity_popup_content), + actions: [ + TextButton( + child: Text(AppLocalizations.of(context)!.ok.toUpperCase()), + onPressed: () { + Navigator.of(context).pop(); // Close the dialog + }, + ), + ], + ); + }, + ); + } +} diff --git a/lib/util/web_view_global_controller.dart b/lib/util/web_view_global_controller.dart new file mode 100644 index 0000000..cab3d6e --- /dev/null +++ b/lib/util/web_view_global_controller.dart @@ -0,0 +1,11 @@ +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; + +class WebViewGlobalController { + static InAppWebViewController? _value; + + static InAppWebViewController? get value => _value; + + static void setValue(InAppWebViewController newValue) { + _value = newValue; + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 2242002..5c38660 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -278,6 +278,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77" + url: "https://pub.dev" + source: hosted + version: "5.1.0" flutter_inappwebview: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index cff522b..68b43ab 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,7 @@ dependencies: swipe_to: ^1.0.2 shared_preferences: ^2.2.2 intl: any + flutter_dotenv: ^5.1.0 dev_dependencies: flutter_test: @@ -90,6 +91,7 @@ flutter: - asset: assets/fonts/OpenSans-SemiBold.ttf assets: + - .env - assets/images/ - assets/images/locale/ - assets/opener_animation.riv From 5d658916c23027357b18260083aa066b9d06c1c8 Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 21 May 2024 17:34:58 +0200 Subject: [PATCH 10/31] Add exit app logic to specific web_views --- lib/apps/flavored/util/router.f.dart | 15 ++++++ lib/apps/flavored/web_view.f.dart | 71 ++++++++++++++++++++-------- lib/apps/flavored_app.dart | 12 +++-- lib/pages/web_view.dart | 39 ++++++++++++++- lib/util/extensions.dart | 43 ----------------- 5 files changed, 114 insertions(+), 66 deletions(-) create mode 100644 lib/apps/flavored/util/router.f.dart diff --git a/lib/apps/flavored/util/router.f.dart b/lib/apps/flavored/util/router.f.dart new file mode 100644 index 0000000..1419fe7 --- /dev/null +++ b/lib/apps/flavored/util/router.f.dart @@ -0,0 +1,15 @@ +import 'package:flutter/cupertino.dart'; +import 'package:humhub/apps/flavored/web_view.f.dart'; + +final GlobalKey navigatorKeyF = GlobalKey(); + +NavigatorState? get navigator => navigatorKeyF.currentState; + +class RouterF { + static String? initRoute = WebViewF.path; + static dynamic initParams; + + static var routes = { + WebViewF.path: (context) => const WebViewF(), + }; +} diff --git a/lib/apps/flavored/web_view.f.dart b/lib/apps/flavored/web_view.f.dart index 6f0af5b..7e2c1d9 100644 --- a/lib/apps/flavored/web_view.f.dart +++ b/lib/apps/flavored/web_view.f.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -13,15 +14,16 @@ import 'package:humhub/util/extensions.dart'; import 'package:humhub/util/loading_provider.dart'; import 'package:humhub/util/notifications/channel.dart'; import 'package:humhub/util/notifications/plugin.dart'; -import 'package:humhub/util/providers.dart'; import 'package:humhub/util/push/provider.dart'; import 'package:humhub/util/show_dialog.dart'; import 'package:humhub/util/web_view_global_controller.dart'; import 'package:loggy/loggy.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class WebViewF extends ConsumerStatefulWidget { + static const String path = '/web_view_f'; const WebViewF({super.key}); @override @@ -48,7 +50,7 @@ class FlavoredWebViewState extends ConsumerState { Widget build(BuildContext context) { // ignore: deprecated_member_use return WillPopScope( - onWillPop: () => WebViewGlobalController.value!.exitApp(context, ref), + onWillPop: () => exitApp(context, ref), child: Scaffold( backgroundColor: HexColor(instance.manifest.themeColor), body: SafeArea( @@ -58,8 +60,8 @@ class FlavoredWebViewState extends ConsumerState { initialOptions: _options, pullToRefreshController: _pullToRefreshController, shouldOverrideUrlLoading: _shouldOverrideUrlLoading, - onWebViewCreated: _onWebViewCreated, shouldInterceptFetchRequest: _shouldInterceptFetchRequest, + onWebViewCreated: _onWebViewCreated, onCreateWindow: _onCreateWindow, onLoadStop: _onLoadStop, onLoadStart: _onLoadStart, @@ -79,17 +81,17 @@ class FlavoredWebViewState extends ConsumerState { } InAppWebViewGroupOptions get _options => InAppWebViewGroupOptions( - crossPlatform: InAppWebViewOptions( - useShouldOverrideUrlLoading: true, - useShouldInterceptFetchRequest: true, - javaScriptEnabled: true, - supportZoom: false, - javaScriptCanOpenWindowsAutomatically: true, - ), - android: AndroidInAppWebViewOptions( - supportMultipleWindows: true, - ), - ); + crossPlatform: InAppWebViewOptions( + useShouldOverrideUrlLoading: true, + useShouldInterceptFetchRequest: true, + javaScriptEnabled: true, + supportZoom: false, + javaScriptCanOpenWindowsAutomatically: true, + ), + android: AndroidInAppWebViewOptions( + supportMultipleWindows: true, + ), + ); PullToRefreshController get _pullToRefreshController => PullToRefreshController( options: PullToRefreshOptions( @@ -99,8 +101,8 @@ class FlavoredWebViewState extends ConsumerState { Uri? url = await WebViewGlobalController.value!.getUrl(); if (url != null) { WebViewGlobalController.value!.loadUrl( - urlRequest: URLRequest( - url: await WebViewGlobalController.value!.getUrl(), headers: ref.read(humHubProvider).customHeaders), + urlRequest: + URLRequest(url: await WebViewGlobalController.value!.getUrl(), headers: instance.customHeaders), ); } else { WebViewGlobalController.value!.reload(); @@ -170,7 +172,7 @@ class FlavoredWebViewState extends ConsumerState { .evaluateJavascript(source: "document.querySelector('#login-rememberme').checked=true"); WebViewGlobalController.value!.evaluateJavascript( source: - "document.querySelector('#account-login-form > div.form-group.field-login-rememberme').style.display='none';"); + "document.querySelector('#account-login-form > div.form-group.field-login-rememberme').style.display='none';"); } _setAjaxHeadersJQuery(controller); await _pullToRefreshController.endRefreshing(); @@ -178,7 +180,7 @@ class FlavoredWebViewState extends ConsumerState { } Future _onLoadStart(InAppWebViewController controller, Uri? url) async { - await _setAjaxHeadersJQuery(controller); + _setAjaxHeadersJQuery(controller); LoadingProvider.of(ref).dismissAll(); } @@ -200,7 +202,8 @@ class FlavoredWebViewState extends ConsumerState { Future _setAjaxHeadersJQuery(InAppWebViewController controller) async { String jsCode = "\$.ajaxSetup({headers: ${jsonEncode(instance.customHeaders).toString()}});"; - await controller.evaluateJavascript(source: jsCode); + dynamic jsResponse = await controller.evaluateJavascript(source: jsCode); + logInfo(jsResponse != null ? jsResponse.toString() : "Script returned null value"); } Future _handleJSMessage(ChannelMessage message, HeadlessInAppWebView headlessWebView) async { @@ -235,6 +238,36 @@ class FlavoredWebViewState extends ConsumerState { } } + Future exitApp(context, ref) async { + bool canGoBack = await WebViewGlobalController.value!.canGoBack(); + if (canGoBack) { + WebViewGlobalController.value!.goBack(); + return Future.value(false); + } else { + final exitConfirmed = await showDialog( + context: context, + builder: (context) => AlertDialog( + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0))), + title: Text(AppLocalizations.of(context)!.web_view_exit_popup_title), + content: Text(AppLocalizations.of(context)!.web_view_exit_popup_content), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(AppLocalizations.of(context)!.no), + ), + TextButton( + onPressed: () { + SystemNavigator.pop(); + }, + child: Text(AppLocalizations.of(context)!.yes), + ), + ], + ), + ); + return exitConfirmed ?? false; + } + } + @override void dispose() { super.dispose(); diff --git a/lib/apps/flavored_app.dart b/lib/apps/flavored_app.dart index 1c67a7e..3b4ebd7 100644 --- a/lib/apps/flavored_app.dart +++ b/lib/apps/flavored_app.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:humhub/apps/flavored/web_view.f.dart'; +import 'package:humhub/apps/flavored/util/router.f.dart'; import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/loading_provider.dart'; import 'package:humhub/util/notifications/plugin.dart'; import 'package:humhub/util/override_locale.dart'; import 'package:humhub/util/push/push_plugin.dart'; import 'package:humhub/util/storage_service.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class FlavoredApp extends ConsumerStatefulWidget { const FlavoredApp({super.key}); @@ -26,8 +27,13 @@ class FlavoredAppState extends ConsumerState { builder: (overrideLocale) => Builder( builder: (context) => MaterialApp( debugShowCheckedModeBanner: false, - builder: (context, child) => const LoadingProvider( - child: WebViewF(), + initialRoute: RouterF.initRoute, + routes: RouterF.routes, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + navigatorKey: navigatorKeyF, + builder: (context, child) => LoadingProvider( + child: child!, ), theme: ThemeData( fontFamily: 'OpenSans', diff --git a/lib/pages/web_view.dart b/lib/pages/web_view.dart index 12e904d..fd13666 100644 --- a/lib/pages/web_view.dart +++ b/lib/pages/web_view.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:app_settings/app_settings.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -73,7 +74,7 @@ class WebViewAppState extends ConsumerState { ); // ignore: deprecated_member_use return WillPopScope( - onWillPop: () => WebViewGlobalController.value!.exitApp(context, ref), + onWillPop: () => exitApp(context, ref), child: Scaffold( backgroundColor: HexColor(manifest.themeColor), body: SafeArea( @@ -101,6 +102,7 @@ class WebViewAppState extends ConsumerState { }, onLoadStop: _onLoadStop, onLoadStart: (controller, uri) async { + logDebug("onLoadStart"); _setAjaxHeadersJQuery(controller); }, onProgressChanged: _onProgressChanged, @@ -149,6 +151,7 @@ class WebViewAppState extends ConsumerState { logInfo(inMessage); ChannelMessage message = ChannelMessage.fromJson(inMessage!); await _handleJSMessage(message, headlessWebView!); + logDebug('flutterChannel triggered: ${message.type}'); }, ), ); @@ -156,6 +159,7 @@ class WebViewAppState extends ConsumerState { } Future _shouldInterceptFetchRequest(InAppWebViewController controller, FetchRequest request) async { + logDebug("_shouldInterceptFetchRequest"); request.headers!.addAll(_initialRequest.headers!); return request; } @@ -299,6 +303,39 @@ class WebViewAppState extends ConsumerState { } } + Future exitApp(context, ref) async { + bool canGoBack = await WebViewGlobalController.value!.canGoBack(); + if (canGoBack) { + WebViewGlobalController.value!.goBack(); + return Future.value(false); + } else { + final exitConfirmed = await showDialog( + context: context, + builder: (context) => AlertDialog( + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0))), + title: Text(AppLocalizations.of(context)!.web_view_exit_popup_title), + content: Text(AppLocalizations.of(context)!.web_view_exit_popup_content), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(AppLocalizations.of(context)!.no), + ), + TextButton( + onPressed: () { + var isHide = ref.read(humHubProvider).isHideDialog; + isHide + ? SystemNavigator.pop() + : Navigator.of(context).pushNamedAndRemoveUntil(Opener.path, (Route route) => false); + }, + child: Text(AppLocalizations.of(context)!.yes), + ), + ], + ), + ); + return exitConfirmed ?? false; + } + } + @override void dispose() { super.dispose(); diff --git a/lib/util/extensions.dart b/lib/util/extensions.dart index 17d23a5..524afc8 100644 --- a/lib/util/extensions.dart +++ b/lib/util/extensions.dart @@ -1,51 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:humhub/pages/opener.dart'; import 'package:humhub/util/const.dart'; -import 'package:humhub/util/providers.dart'; import 'package:loggy/loggy.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - -extension MyWebViewController on InAppWebViewController { - Future exitApp(context, ref) async { - bool canGoBack = await this.canGoBack(); - if (canGoBack) { - goBack(); - return Future.value(false); - } else { - final exitConfirmed = await showDialog( - context: context, - builder: (context) => AlertDialog( - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0))), - title: Text(AppLocalizations.of(context)!.web_view_exit_popup_title), - content: Text(AppLocalizations.of(context)!.web_view_exit_popup_content), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text(AppLocalizations.of(context)!.no), - ), - TextButton( - onPressed: () { - closeOrOpenDialog(context, ref); - }, - child: Text(AppLocalizations.of(context)!.yes), - ), - ], - ), - ); - return exitConfirmed ?? false; - } - } - - closeOrOpenDialog(BuildContext context, WidgetRef ref) { - var isHide = ref.read(humHubProvider).isHideDialog; - isHide - ? SystemNavigator.pop() - : Navigator.of(context).pushNamedAndRemoveUntil(Opener.path, (Route route) => false); - } -} class HexColor extends Color { static int _getColorFromHex(String hexColor) { From 89d897ffc70b0f360bb7d9dadeddc34893b6d122 Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 21 May 2024 18:22:18 +0200 Subject: [PATCH 11/31] _onLoadStart fix headers on POST --- lib/{apps/flavored_app.dart => app_flavored.dart} | 2 +- lib/{apps/opener_app.dart => app_opener.dart} | 0 lib/{apps => }/flavored/models/humhub.f.dart | 2 +- lib/{apps => }/flavored/models/manifest.f.dart | 0 lib/{apps => }/flavored/util/router.f.dart | 2 +- lib/{apps => }/flavored/web_view.f.dart | 4 ++-- lib/main.dart | 4 ++-- 7 files changed, 7 insertions(+), 7 deletions(-) rename lib/{apps/flavored_app.dart => app_flavored.dart} (96%) rename lib/{apps/opener_app.dart => app_opener.dart} (100%) rename lib/{apps => }/flavored/models/humhub.f.dart (89%) rename lib/{apps => }/flavored/models/manifest.f.dart (100%) rename lib/{apps => }/flavored/util/router.f.dart (83%) rename lib/{apps => }/flavored/web_view.f.dart (96%) diff --git a/lib/apps/flavored_app.dart b/lib/app_flavored.dart similarity index 96% rename from lib/apps/flavored_app.dart rename to lib/app_flavored.dart index 3b4ebd7..e318c43 100644 --- a/lib/apps/flavored_app.dart +++ b/lib/app_flavored.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:humhub/apps/flavored/util/router.f.dart'; +import 'package:humhub/flavored/util/router.f.dart'; import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/loading_provider.dart'; import 'package:humhub/util/notifications/plugin.dart'; diff --git a/lib/apps/opener_app.dart b/lib/app_opener.dart similarity index 100% rename from lib/apps/opener_app.dart rename to lib/app_opener.dart diff --git a/lib/apps/flavored/models/humhub.f.dart b/lib/flavored/models/humhub.f.dart similarity index 89% rename from lib/apps/flavored/models/humhub.f.dart rename to lib/flavored/models/humhub.f.dart index 37e10e6..ecc0d55 100644 --- a/lib/apps/flavored/models/humhub.f.dart +++ b/lib/flavored/models/humhub.f.dart @@ -1,5 +1,5 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:humhub/apps/flavored/models/manifest.f.dart'; +import 'package:humhub/flavored/models/manifest.f.dart'; import 'package:humhub/models/hum_hub.dart'; class HumHubF extends HumHub{ diff --git a/lib/apps/flavored/models/manifest.f.dart b/lib/flavored/models/manifest.f.dart similarity index 100% rename from lib/apps/flavored/models/manifest.f.dart rename to lib/flavored/models/manifest.f.dart diff --git a/lib/apps/flavored/util/router.f.dart b/lib/flavored/util/router.f.dart similarity index 83% rename from lib/apps/flavored/util/router.f.dart rename to lib/flavored/util/router.f.dart index 1419fe7..ca1eeb1 100644 --- a/lib/apps/flavored/util/router.f.dart +++ b/lib/flavored/util/router.f.dart @@ -1,5 +1,5 @@ import 'package:flutter/cupertino.dart'; -import 'package:humhub/apps/flavored/web_view.f.dart'; +import 'package:humhub/flavored/web_view.f.dart'; final GlobalKey navigatorKeyF = GlobalKey(); diff --git a/lib/apps/flavored/web_view.f.dart b/lib/flavored/web_view.f.dart similarity index 96% rename from lib/apps/flavored/web_view.f.dart rename to lib/flavored/web_view.f.dart index 7e2c1d9..ed70ea6 100644 --- a/lib/apps/flavored/web_view.f.dart +++ b/lib/flavored/web_view.f.dart @@ -7,7 +7,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:humhub/apps/flavored/models/humhub.f.dart'; +import 'package:humhub/flavored/models/humhub.f.dart'; import 'package:humhub/util/auth_in_app_browser.dart'; import 'package:humhub/models/channel_message.dart'; import 'package:humhub/util/extensions.dart'; @@ -179,7 +179,7 @@ class FlavoredWebViewState extends ConsumerState { LoadingProvider.of(ref).dismissAll(); } - Future _onLoadStart(InAppWebViewController controller, Uri? url) async { + void _onLoadStart(InAppWebViewController controller, Uri? url) async { _setAjaxHeadersJQuery(controller); LoadingProvider.of(ref).dismissAll(); } diff --git a/lib/main.dart b/lib/main.dart index 78c1d16..8fdfbc0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,12 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:humhub/apps/flavored_app.dart'; +import 'package:humhub/app_flavored.dart'; import 'package:humhub/util/log.dart'; import 'package:humhub/util/storage_service.dart'; import 'package:loggy/loggy.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'apps/opener_app.dart'; +import 'app_opener.dart'; main() async { Loggy.initLoggy( From d742b8ee6d7741b52a4033467d65bd11461b3319 Mon Sep 17 00:00:00 2001 From: primozratej Date: Sun, 26 May 2024 18:47:44 +0200 Subject: [PATCH 12/31] NotificationChannelF and bundle id --- .env | 8 +++ android/app/build.gradle | 8 +++ android/app/src/main/AndroidManifest.xml | 2 +- .../app/src/main/res/values-de/strings.xml | 4 ++ .../app/src/main/res/values-en/strings.xml | 4 ++ .../app/src/main/res/values-fr/strings.xml | 4 ++ android/app/src/main/res/values/strings.xml | 4 ++ android/app/src/omrade/AndroidManifest.xml | 55 ++++++++++++++++++ android/app/src/omrade/google-services.json | 46 +++++++++++++++ .../res/drawable-v21/launch_background.xml | 12 ++++ .../omrade/res/drawable/launch_background.xml | 12 ++++ .../omrade/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 1345 bytes .../omrade/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1009 bytes .../omrade/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 1695 bytes .../omrade/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 2275 bytes .../omrade/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 2806 bytes .../app/src/omrade/res/values-de/strings.xml | 4 ++ .../app/src/omrade/res/values-en/strings.xml | 4 ++ .../app/src/omrade/res/values-fr/strings.xml | 4 ++ android/app/src/omrade/res/values/strings.xml | 4 ++ .../res/values}/styles.xml | 6 +- lib/app_flavored.dart | 7 +++ lib/app_opener.dart | 2 + lib/flavored/models/humhub.f.dart | 16 +++++ lib/flavored/util/notifications/channel.dart | 39 +++++++++++++ lib/flavored/web_view.f.dart | 9 +-- lib/main.dart | 16 ++--- lib/models/hum_hub.dart | 12 ++++ lib/pages/opener.dart | 2 +- lib/pages/web_view.dart | 2 +- lib/util/notifications/channel.dart | 53 +++-------------- lib/util/notifications/init_from_push.dart | 13 +++++ lib/util/notifications/service.dart | 2 +- lib/util/push/push_plugin.dart | 50 ++++++++-------- 34 files changed, 312 insertions(+), 92 deletions(-) create mode 100644 .env create mode 100644 android/app/src/main/res/values-de/strings.xml create mode 100644 android/app/src/main/res/values-en/strings.xml create mode 100644 android/app/src/main/res/values-fr/strings.xml create mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 android/app/src/omrade/AndroidManifest.xml create mode 100644 android/app/src/omrade/google-services.json create mode 100644 android/app/src/omrade/res/drawable-v21/launch_background.xml create mode 100644 android/app/src/omrade/res/drawable/launch_background.xml create mode 100644 android/app/src/omrade/res/mipmap-hdpi/ic_launcher.png create mode 100644 android/app/src/omrade/res/mipmap-mdpi/ic_launcher.png create mode 100644 android/app/src/omrade/res/mipmap-xhdpi/ic_launcher.png create mode 100644 android/app/src/omrade/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 android/app/src/omrade/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 android/app/src/omrade/res/values-de/strings.xml create mode 100644 android/app/src/omrade/res/values-en/strings.xml create mode 100644 android/app/src/omrade/res/values-fr/strings.xml create mode 100644 android/app/src/omrade/res/values/strings.xml rename android/app/src/{main/res/values-night => omrade/res/values}/styles.xml (81%) create mode 100644 lib/flavored/util/notifications/channel.dart create mode 100644 lib/util/notifications/init_from_push.dart diff --git a/.env b/.env new file mode 100644 index 0000000..a86072d --- /dev/null +++ b/.env @@ -0,0 +1,8 @@ +GCM_SENDER_ID=103953800507 +DISPLAY=standalone +START_URL=https://intranet.omrade.co +MANIFEST_URL=https://intranet.omrade.co/manifest.json +SHORT_NAME=område +NAME=område +BACKGROUND_COLOR=2d3340 +THEME_COLOR=2d3340 \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 5008dff..92d1ffd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -80,6 +80,14 @@ android { } } } + + flavorDimensions "flavor" + productFlavors { + omrade { + dimension "flavor" + applicationId "com.humhub.omrade.app" + } + } } flutter { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 09fba76..68d22f3 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ + + Humhub + \ No newline at end of file diff --git a/android/app/src/main/res/values-en/strings.xml b/android/app/src/main/res/values-en/strings.xml new file mode 100644 index 0000000..ea59b9a --- /dev/null +++ b/android/app/src/main/res/values-en/strings.xml @@ -0,0 +1,4 @@ + + + Humhub + \ No newline at end of file diff --git a/android/app/src/main/res/values-fr/strings.xml b/android/app/src/main/res/values-fr/strings.xml new file mode 100644 index 0000000..ea59b9a --- /dev/null +++ b/android/app/src/main/res/values-fr/strings.xml @@ -0,0 +1,4 @@ + + + Humhub + \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..ea59b9a --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Humhub + \ No newline at end of file diff --git a/android/app/src/omrade/AndroidManifest.xml b/android/app/src/omrade/AndroidManifest.xml new file mode 100644 index 0000000..6479c38 --- /dev/null +++ b/android/app/src/omrade/AndroidManifest.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/omrade/google-services.json b/android/app/src/omrade/google-services.json new file mode 100644 index 0000000..99a1f4b --- /dev/null +++ b/android/app/src/omrade/google-services.json @@ -0,0 +1,46 @@ +{ + "project_info": { + "project_number": "21392898126", + "project_id": "humhub-push-service", + "storage_bucket": "humhub-push-service.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:21392898126:android:3a252132106213e008ab1f", + "android_client_info": { + "package_name": "com.humhub.omrade.app" + } + }, + "oauth_client": [ + { + "client_id": "21392898126-ds3289q62hgqucr3hhtujkanj6l1u8ee.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBm9okv_3wczFQzFt91Ksg33Tk9KPAMT4o" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "21392898126-ds3289q62hgqucr3hhtujkanj6l1u8ee.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "21392898126-filvre2lp06kebh2p7b788tqepqcvtqq.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.humhub.app" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/omrade/res/drawable-v21/launch_background.xml b/android/app/src/omrade/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/android/app/src/omrade/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/omrade/res/drawable/launch_background.xml b/android/app/src/omrade/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/android/app/src/omrade/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/omrade/res/mipmap-hdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..63de2d357b0bcdaa76a9da92b62772ced7cd9f75 GIT binary patch literal 1345 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAk#!vLQUSN8&+_p{aJ?emYgkppCu zpG$l!T_sR1F3{512TXrfh0r_NWu|Z3s??%UaFVYl*c%u?O9-X?UR!HrpJb%#TH_WD803~CnmFk3C4Ssg6{|94{i$k;~^V;OT6)3ftsV>(x>0^(^}q&O{>!AO?=mHUh&t|*Wg;! zubA%c{cH}q7#NtZdb&7zt_o;i7zgTT`%&LRSWBBCPsd#;_$6A~@GYyJN}duy^= zdcw7csr)OwZpxQ&FRQ)$H}1QSbD;U|n`i$qColPyaADevGtq$?avf9Fu^O&cUK-Q0 zW=+p3wLdfOM(vQwjok9=TiC1l2bZi0(pl>tmZcHex#-BX3$JpNw2#!A$)1ko6i@uI zs&9cx+LTjMMW-)VaP4B&qw5yFs@%fLwzhiqhkVajy}KL!B%~|5$yWB;?&;TUE~rhZ zoi}6JW%Y+L+kfY#oX@XZ;k(%LUJ@%M4r12=Q$ zFW++eb(y$xZkNK>O*cc&Rf@hY=Dc#~@Mmw9i8mg8UOpj&U-^#i3*)DCZtI25|J_wt zwffS-dvaA%TI5fQq{psO=+*|bs zx(m*gn0|M7p7^@FNNXLu=d&%BoMw`NysAwo{>#gJs zR=2w7qP5)4>YAXE2BY3vix*1*RMgGic8BmcPxYu;GCMGLn#eYWQ%k1XSvmAGcB-5{ z=2Bdspm0*j*IwbI+tr4gS63abm^v726%>3Cl-0u@6ue$dTCBe9jhvg=6!~n=F2$4i zF;o7BO!$5ykNd)=lLxPU@i?_=W>br7 zD}KJ*o~K$^Ji45Vcowj`O^iRFX|;X7x%yMH+`Hx;Gke#*Ie6>3;t|)N-y@met&1*rWbr zgD2-E0nW!f0%C`@U;oi`N4`&@xhel(wyy1ub7FJW)isySa*+A=uykh3&EJ2&75rg5 zA{ZL4JxA|;EIp>z;=jSLCr0ptaG5=q-{l9AQ>O~3s1^v5*w d-^ag6GmA%9#;d)$1S}>PJYD@<);T3K0RWAxd{qDd literal 0 HcmV?d00001 diff --git a/android/app/src/omrade/res/mipmap-mdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..6df86cb58aa13924aa74ad463e68a3375a0ab373 GIT binary patch literal 1009 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sKLdP1T-^(NB5vkJ+{g{Sl@BD} z%~pex?`Nw5+3#no0R`9W@C0#he4xS4lr zhEhPYKi9ak}Vx%1hLtAEySU&D~|f`Nf4!_&nv#N+tekjU~`4kB!-n@%if=wb>y$a+1a z=hhbA>Vn>jOEQ1|ulGq$oKX0(xZ3ZXBTlHP$nMCcJd2&v@?*F$%%onot2AHALU zUpXe7<HYe97?-o9?6IWh1?|Z=UpbWFZC)Z?a z)~BzxET}J3&^&uCm}}jVDQU%TgIW)X^)_a`h-X-~_Q8#7JeR|4^Iji4$eU`k!*PzF z)EsxVcIkQYOJ-gz_~}z*!*JMS@mu4MpDatRgeCpVa7+1Fvg@Afo_lF8EiP|AY#sGp zqv1{X%&*T1ei+=JFEE|&cjJ@F{u%}Ie}xYkKX~uX|J3xLraEeo{;s>WzqYep?RatQ zvSZU^w;&h&O3x;h4}EVHb32q$8PBKf(9GQyIV*DBrJll5sgv7E=APJdOV?ttUFx0X zDbr@o+Pp^aBDc%-n72lf;l~y`3M`q^>2%`8`!8*_cjum#+2QxlU6kQT&58XQ^$gvw W78GV!ojU?dz6_qOelF{r5}E*YX6y3+ literal 0 HcmV?d00001 diff --git a/android/app/src/omrade/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..02272133bcb67927906ff91367c1351eeade87d7 GIT binary patch literal 1695 zcmXw3dpr|rAD_$K7jew%Hn-eoCYPkl(WqBzMYQ@Ir~Y+5)u=1y*Vn;oGt z9pSj0&eUP`&h=n%Hft{7Y}7f({VctGKF{<0{hr_V@_e3uo-DMlr;3uU5&!^D@%BPu zr1jG0tsp1G-%n9L6MXb(tcU0I(~<{}^W)c~h@Xg-u3w%Wj~>4A|09nmot)c8X|w#m zT#8caGdq55dB53bzuI|U*{`xMIbW13`*vvpe*CI<-z#}wE~TUs9FMqCZuTYl3$mF< zx=T!wUg7cN{p%*8F=Wt+RLmoy$skOIYCzsW948o8Z9|}{PnDYH-3PM^4OujUM4CYm zMGe=DKKBgiNe_ifUwSMK;~N0jVyy0nfwD?#N@sP(5@8;~yh6QWM4)^_4W%`#YQ5|FR=Zj}!I4yH;C8>TLVJdpf zq+%oZ4zQaL^{wT0d{gCW7h|O*yRs*w%UNs3AyTKf_kB@w2_&WCS!eFXFn*1U1-OCk z3+^oEH;ETD`B3metLo~O;ksW8KU^5RW3^LzmvnxQEs{tQ)<1UkDEl`IFX&{&?a*Dj zFd!mRBVyj6jJdZ<)HX&F!mPB_G|E#A|6V3OQsA4*XARnFpW%XaD|q>|t!lNkYqy6R zu`o$v0@<_?L-xiLY`GdRN8C#-42AuYs;US&n! zu$VvIV~|h{O6=HjQx!Rvm*_jn3<(%B2i4>29zh;YHS>2j#Fof5mwGp5F1@fxP(@cL zkddj`ki8&)nvq8Rc%eO{70qyiW<0=Q0uOfs0Ti@21a=`_8F;o-8G~7*~e{< z!xPFlXn54A)=asZma~8v?Y8Zn+zSeFJ3cf34WD-T2(C{ABIV3ev}qZYKXjMi}B z^>F*W7ELPOFyK0h0XeRN8}p$Y@K4yw1*-QuKGJ8q%V3;a^$N(GVm;%tX(O0UW#7M^ z<5IdS^4!yzOHS6wl}B9dG#KDcVE{^3|HGL~#A17%slhi3_6&Ez$rrRabl<#&1*J1DQmYFL9C8~D%*b|vya`6cFS=-N+Q=<;nKPE_7l5U#KJJ0rYhHO_ znHLWFE44d{YCf3gQDC563+mC{|8>`4l4vEr-Rd=W(bp@hiI^xQmrm!z9@_j^O=qp= z&6WJA?|3h@suYwrH>7>^O|q|B)RP!fd6^jfzk=eBiCLCPH~2IP%UsBvOtwp_AlT<$ zd~cJJ``S{jy$C#nd`N}ik9Ccgtly#}ZLgehs4%}%guk@%Nc2g;z#e#UX6}G_p#FK1 z0bl*(w8-|yt$su*I-a%D7l<-oQxP|_H3K1zqYlw<;=LE1Vc*{&t$qr8)?DR_BX+zA z`>ruL6n#!vSqNWLq~Xw%$;7v(das6DSc0~xC_0>|SxU5=w4E&ve;G+@`mqsKch%C{ zI<=kaG&troE5^AzI%pA~g&|3*`Or;XS?tSKL|>kFzewO%7(Kf7^W)&qQLk2negle2 zWX6am-o{N&drC z9L|0qD6}Zb-7OG5#k?;X-AH*-oCJKA@}yz%cdq|2uF=3Yn(;8@gU55>fLXz5`~I08 bW0D-_o*%}XpmS3C4+FeCe34HOmookV1bH=$ literal 0 HcmV?d00001 diff --git a/android/app/src/omrade/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b56bacfd36febd744493aed90a098e3e81e12552 GIT binary patch literal 2275 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 M(#!@`V(J<9UuJ<`8UO$Q literal 0 HcmV?d00001 diff --git a/android/app/src/omrade/res/values-de/strings.xml b/android/app/src/omrade/res/values-de/strings.xml new file mode 100644 index 0000000..d9032cf --- /dev/null +++ b/android/app/src/omrade/res/values-de/strings.xml @@ -0,0 +1,4 @@ + + + Område + \ No newline at end of file diff --git a/android/app/src/omrade/res/values-en/strings.xml b/android/app/src/omrade/res/values-en/strings.xml new file mode 100644 index 0000000..d9032cf --- /dev/null +++ b/android/app/src/omrade/res/values-en/strings.xml @@ -0,0 +1,4 @@ + + + Område + \ No newline at end of file diff --git a/android/app/src/omrade/res/values-fr/strings.xml b/android/app/src/omrade/res/values-fr/strings.xml new file mode 100644 index 0000000..d9032cf --- /dev/null +++ b/android/app/src/omrade/res/values-fr/strings.xml @@ -0,0 +1,4 @@ + + + Område + \ No newline at end of file diff --git a/android/app/src/omrade/res/values/strings.xml b/android/app/src/omrade/res/values/strings.xml new file mode 100644 index 0000000..d9032cf --- /dev/null +++ b/android/app/src/omrade/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Område + \ No newline at end of file diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/omrade/res/values/styles.xml similarity index 81% rename from android/app/src/main/res/values-night/styles.xml rename to android/app/src/omrade/res/values/styles.xml index 06952be..cb1ef88 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/omrade/res/values/styles.xml @@ -1,7 +1,7 @@ - - diff --git a/lib/app_flavored.dart b/lib/app_flavored.dart index e318c43..9563840 100644 --- a/lib/app_flavored.dart +++ b/lib/app_flavored.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/flavored/models/humhub.f.dart'; +import 'package:humhub/flavored/util/notifications/channel.dart'; import 'package:humhub/flavored/util/router.f.dart'; import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/loading_provider.dart'; @@ -23,6 +25,7 @@ class FlavoredAppState extends ConsumerState { return IntentPlugin( child: NotificationPlugin( child: PushPlugin( + channel: NotificationChannelF(), child: OverrideLocale( builder: (overrideLocale) => Builder( builder: (context) => MaterialApp( @@ -46,3 +49,7 @@ class FlavoredAppState extends ConsumerState { ); } } + +final humHubFProvider = FutureProvider((ref) { + return HumHubF.initialize(); +}); diff --git a/lib/app_opener.dart b/lib/app_opener.dart index 71e7462..6a5537f 100644 --- a/lib/app_opener.dart +++ b/lib/app_opener.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/loading_provider.dart'; +import 'package:humhub/util/notifications/channel.dart'; import 'package:humhub/util/notifications/plugin.dart'; import 'package:humhub/util/override_locale.dart'; import 'package:humhub/util/push/push_plugin.dart'; @@ -23,6 +24,7 @@ class OpenerAppState extends ConsumerState { return IntentPlugin( child: NotificationPlugin( child: PushPlugin( + channel: NotificationChannel(), child: OverrideLocale( builder: (overrideLocale) => Builder( builder: (context) => FutureBuilder( diff --git a/lib/flavored/models/humhub.f.dart b/lib/flavored/models/humhub.f.dart index ecc0d55..9fb0203 100644 --- a/lib/flavored/models/humhub.f.dart +++ b/lib/flavored/models/humhub.f.dart @@ -1,21 +1,37 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:humhub/flavored/models/manifest.f.dart'; import 'package:humhub/models/hum_hub.dart'; +import 'package:package_info_plus/package_info_plus.dart'; class HumHubF extends HumHub{ @override ManifestF get manifest => ManifestF.fromEnv(); @override String get manifestUrl => dotenv.env['MANIFEST_URL']!; + final String bundleId; HumHubF({ bool isHideOpener = false, String? randomHash, String? appVersion, String? pushToken, + required this.bundleId, }) : super( isHideOpener: isHideOpener, randomHash: HumHub.generateHash(32), appVersion: appVersion, pushToken: pushToken); + + @override + Map get customHeaders => { + 'x-humhub-app-token': randomHash!, + 'x-humhub-app': appVersion ?? '1.0.0', + 'x-humhub-app-bundle-id': bundleId, + 'x-humhub-app-ostate': isHideOpener ? '1' : '0' + }; + + static Future initialize() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + return HumHubF(bundleId: packageInfo.packageName); + } } \ No newline at end of file diff --git a/lib/flavored/util/notifications/channel.dart b/lib/flavored/util/notifications/channel.dart new file mode 100644 index 0000000..9c98678 --- /dev/null +++ b/lib/flavored/util/notifications/channel.dart @@ -0,0 +1,39 @@ +import 'package:humhub/pages/web_view.dart'; +import 'package:humhub/util/notifications/channel.dart'; +import 'package:humhub/util/notifications/init_from_push.dart'; +import 'package:humhub/util/openers/universal_opener_controller.dart'; +import 'package:humhub/util/router.dart'; + +class NotificationChannelF extends NotificationChannel { + NotificationChannelF( + {super.id = 'redirect', + super.name = 'Redirect flavored app notifications', + super.description = 'These notifications redirect the user to specific url in a payload.'}); + + /// If the WebView is not opened yet or the app is not running the onTap will wake up the app or redirect to the WebView. + /// If app is already running in WebView mode then the state of [WebViewApp] will be updated with new url. + /// + @override + Future onTap(String? payload) async { + if (payload != null && navigatorKey.currentState != null) { + bool isNewRouteSameAsCurrent = false; + navigatorKey.currentState!.popUntil((route) { + if (route.settings.name == WebViewApp.path) { + isNewRouteSameAsCurrent = true; + } + return true; + }); + UniversalOpenerController opener = UniversalOpenerController(url: payload); + await opener.initHumHub(); + if (isNewRouteSameAsCurrent) { + navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + return; + } + navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + } else { + if (payload != null) { + InitFromPush.setPayload(payload); + } + } + } +} diff --git a/lib/flavored/web_view.f.dart b/lib/flavored/web_view.f.dart index ed70ea6..c5dc827 100644 --- a/lib/flavored/web_view.f.dart +++ b/lib/flavored/web_view.f.dart @@ -1,18 +1,18 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/app_flavored.dart'; import 'package:humhub/flavored/models/humhub.f.dart'; import 'package:humhub/util/auth_in_app_browser.dart'; import 'package:humhub/models/channel_message.dart'; import 'package:humhub/util/extensions.dart'; import 'package:humhub/util/loading_provider.dart'; -import 'package:humhub/util/notifications/channel.dart'; +import 'package:humhub/util/notifications/init_from_push.dart'; import 'package:humhub/util/notifications/plugin.dart'; import 'package:humhub/util/push/provider.dart'; import 'package:humhub/util/show_dialog.dart'; @@ -31,14 +31,15 @@ class WebViewF extends ConsumerStatefulWidget { } class FlavoredWebViewState extends ConsumerState { - HumHubF instance = HumHubF(); late AuthInAppBrowser _authBrowser; HeadlessInAppWebView? headlessWebView; + late HumHubF instance; @override void initState() { + instance = ref.read(humHubFProvider).value!; _authBrowser = AuthInAppBrowser( - manifest: instance.manifest, + manifest: ref.read(humHubFProvider).value!.manifest, concludeAuth: (URLRequest request) { _concludeAuth(request); }, diff --git a/lib/main.dart b/lib/main.dart index 8fdfbc0..6105b51 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,12 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:humhub/app_flavored.dart'; +import 'package:humhub/models/hum_hub.dart'; import 'package:humhub/util/log.dart'; import 'package:humhub/util/storage_service.dart'; import 'package:loggy/loggy.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'app_opener.dart'; main() async { Loggy.initLoggy( @@ -15,14 +14,9 @@ main() async { ); WidgetsFlutterBinding.ensureInitialized(); await SecureStorageService.clearSecureStorageOnReinstall(); - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - if (packageInfo.packageName == 'com.humhub.app') { - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) { - runApp(const ProviderScope(child: OpenerApp())); - }); - } else { - await dotenv.load(fileName: ".env"); - runApp(const ProviderScope(child: FlavoredApp())); - } + await dotenv.load(fileName: ".env"); + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) async { + runApp(ProviderScope(child: await HumHub.app(packageInfo.packageName))); + }); } diff --git a/lib/models/hum_hub.dart b/lib/models/hum_hub.dart index 8203dc9..1d71358 100644 --- a/lib/models/hum_hub.dart +++ b/lib/models/hum_hub.dart @@ -1,4 +1,7 @@ import 'dart:math'; +import 'package:flutter/material.dart'; +import 'package:humhub/app_flavored.dart'; +import 'package:humhub/app_opener.dart'; import 'package:humhub/models/manifest.dart'; import 'package:humhub/util/openers/universal_opener_controller.dart'; @@ -63,4 +66,13 @@ class HumHub { 'x-humhub-app': appVersion ?? '1.0.0', 'x-humhub-app-ostate': isHideOpener ? '1' : '0' }; + + static Future app(String bundleId) async { + switch (bundleId) { + case 'com.humhub.app': + return const OpenerApp(); + default: + return const FlavoredApp(); + } + } } diff --git a/lib/pages/opener.dart b/lib/pages/opener.dart index 2f0b7ad..ecf53e7 100644 --- a/lib/pages/opener.dart +++ b/lib/pages/opener.dart @@ -53,7 +53,7 @@ class OpenerState extends ConsumerState with SingleTickerProviderStateMi String? urlIntent = InitFromIntent.usePayloadForInit(); if (urlIntent != null) { - await RedirectNotificationChannel().onTap(urlIntent); + await NotificationChannel().onTap(urlIntent); } }); } diff --git a/lib/pages/web_view.dart b/lib/pages/web_view.dart index fd13666..3e18e07 100644 --- a/lib/pages/web_view.dart +++ b/lib/pages/web_view.dart @@ -15,7 +15,7 @@ import 'package:humhub/models/manifest.dart'; import 'package:humhub/pages/opener.dart'; import 'package:humhub/util/connectivity_plugin.dart'; import 'package:humhub/util/extensions.dart'; -import 'package:humhub/util/notifications/channel.dart'; +import 'package:humhub/util/notifications/init_from_push.dart'; import 'package:humhub/util/providers.dart'; import 'package:humhub/util/openers/universal_opener_controller.dart'; import 'package:humhub/util/push/provider.dart'; diff --git a/lib/util/notifications/channel.dart b/lib/util/notifications/channel.dart index 0e23786..ec31761 100644 --- a/lib/util/notifications/channel.dart +++ b/lib/util/notifications/channel.dart @@ -1,46 +1,21 @@ -import 'package:flutter/cupertino.dart'; import 'package:humhub/pages/web_view.dart'; +import 'package:humhub/util/notifications/init_from_push.dart'; import 'package:humhub/util/openers/universal_opener_controller.dart'; import 'package:humhub/util/router.dart'; -import 'package:loggy/loggy.dart'; -abstract class NotificationChannel { +class NotificationChannel { final String id; final String name; final String description; - NotificationChannel(this.id, this.name, this.description); - - Future onTap(String? payload); - - @protected - Future navigate(String route, {Object? arguments}) async { - logInfo('NotificationChannel navigate: $route'); - if (navigatorKey.currentState?.mounted ?? false) { - await navigatorKey.currentState?.pushNamed( - route, - arguments: arguments, - ); - } else { - queueRoute( - route, - arguments: arguments, - ); - } - } -} - -class RedirectNotificationChannel extends NotificationChannel { - RedirectNotificationChannel() - : super( - 'redirect', - 'Redirect app notifications', - 'These notifications are redirect the user to specific url in a payload.', - ); + NotificationChannel( + {this.id = 'redirect', + this.name = 'Redirect app notifications', + this.description = 'These notifications are redirect the user to specific url in a payload.'}); /// If the WebView is not opened yet or the app is not running the onTap will wake up the app or redirect to the WebView. /// If app is already running in WebView mode then the state of [WebViewApp] will be updated with new url. - @override + /// Future onTap(String? payload) async { if (payload != null && navigatorKey.currentState != null) { bool isNewRouteSameAsCurrent = false; @@ -64,17 +39,3 @@ class RedirectNotificationChannel extends NotificationChannel { } } } - -class InitFromPush { - static String? _redirectUrlFromInit; - - static setPayload(String payload) { - _redirectUrlFromInit = payload; - } - - static String? usePayload() { - String? payload = _redirectUrlFromInit; - _redirectUrlFromInit = null; - return payload; - } -} diff --git a/lib/util/notifications/init_from_push.dart b/lib/util/notifications/init_from_push.dart new file mode 100644 index 0000000..7f42313 --- /dev/null +++ b/lib/util/notifications/init_from_push.dart @@ -0,0 +1,13 @@ +class InitFromPush { + static String? _redirectUrlFromInit; + + static setPayload(String payload) { + _redirectUrlFromInit = payload; + } + + static String? usePayload() { + String? payload = _redirectUrlFromInit; + _redirectUrlFromInit = null; + return payload; + } +} \ No newline at end of file diff --git a/lib/util/notifications/service.dart b/lib/util/notifications/service.dart index 11cdba9..54818ae 100644 --- a/lib/util/notifications/service.dart +++ b/lib/util/notifications/service.dart @@ -48,7 +48,7 @@ class NotificationService { static void handleNotification(NotificationResponse response) async { final parsed = response.payload != null ? json.decode(response.payload!) : {}; if (parsed["redirectUrl"] != null) { - await RedirectNotificationChannel().onTap(parsed['redirectUrl']); + await NotificationChannel().onTap(parsed['redirectUrl']); return; } } diff --git a/lib/util/push/push_plugin.dart b/lib/util/push/push_plugin.dart index 43448db..1044f02 100644 --- a/lib/util/push/push_plugin.dart +++ b/lib/util/push/push_plugin.dart @@ -13,10 +13,12 @@ import 'package:loggy/loggy.dart'; class PushPlugin extends ConsumerStatefulWidget { final Widget child; + final NotificationChannel channel; const PushPlugin({ Key? key, required this.child, + required this.channel, }) : super(key: key); @override @@ -42,7 +44,7 @@ class PushPluginState extends ConsumerState { FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { logInfo("Firebase messaging onMessageOpenedApp"); final data = PushEvent(message).parsedData; - RedirectNotificationChannel().onTap(data.redirectUrl); + widget.channel.onTap(data.redirectUrl); }); //When the app is terminated, i.e., app is neither in foreground or background. @@ -64,6 +66,29 @@ class PushPluginState extends ConsumerState { super.initState(); } + _handleInitialMsg(RemoteMessage message) { + final data = PushEvent(message).parsedData; + if (data.redirectUrl != null) { + widget.channel.onTap(data.redirectUrl); + } + } + + Future _handleNotification(RemoteMessage message, NotificationService notificationService) async { + // Here we handle the notification that we get form an push notification. + final data = PushEvent(message).parsedData; + if (message.notification == null) return; + final title = message.notification?.title; + final body = message.notification?.body; + if (title == null || body == null) return; + await notificationService.showNotification( + widget.channel, + title, + body, + payload: data.channelPayload, + redirectUrl: data.redirectUrl, + ); + } + @override Widget build(BuildContext context) { return RegisterToken( @@ -72,29 +97,6 @@ class PushPluginState extends ConsumerState { } } -_handleInitialMsg(RemoteMessage message) { - final data = PushEvent(message).parsedData; - if (data.redirectUrl != null) { - RedirectNotificationChannel().onTap(data.redirectUrl); - } -} - -Future _handleNotification(RemoteMessage message, NotificationService notificationService) async { - // Here we handle the notification that we get form an push notification. - final data = PushEvent(message).parsedData; - if (message.notification == null) return; - final title = message.notification?.title; - final body = message.notification?.body; - if (title == null || body == null) return; - await notificationService.showNotification( - RedirectNotificationChannel(), - title, - body, - payload: data.channelPayload, - redirectUrl: data.redirectUrl, - ); -} - Future _handleData(RemoteMessage message, BuildContext context, WidgetRef ref) async { // Here we handle the data that we get form an push notification. PushEventData data = PushEvent(message).parsedData; From 2d92d2eaad13da8e6c7e94432f62236b4de99f25 Mon Sep 17 00:00:00 2001 From: primozratej Date: Sun, 26 May 2024 20:04:09 +0200 Subject: [PATCH 13/31] Handle push redirect for flavored web-view --- lib/app_flavored.dart | 2 -- lib/app_opener.dart | 2 -- lib/flavored/util/notifications/channel.dart | 19 ++++++++----------- lib/flavored/web_view.f.dart | 6 +++++- lib/main.dart | 2 +- lib/models/hum_hub.dart | 2 +- lib/pages/opener.dart | 2 +- lib/util/notifications/channel.dart | 20 +++++++++++++++++++- lib/util/notifications/service.dart | 3 ++- lib/util/push/push_plugin.dart | 13 ++++++------- 10 files changed, 43 insertions(+), 28 deletions(-) diff --git a/lib/app_flavored.dart b/lib/app_flavored.dart index 9563840..907803c 100644 --- a/lib/app_flavored.dart +++ b/lib/app_flavored.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/flavored/models/humhub.f.dart'; -import 'package:humhub/flavored/util/notifications/channel.dart'; import 'package:humhub/flavored/util/router.f.dart'; import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/loading_provider.dart'; @@ -25,7 +24,6 @@ class FlavoredAppState extends ConsumerState { return IntentPlugin( child: NotificationPlugin( child: PushPlugin( - channel: NotificationChannelF(), child: OverrideLocale( builder: (overrideLocale) => Builder( builder: (context) => MaterialApp( diff --git a/lib/app_opener.dart b/lib/app_opener.dart index 6a5537f..71e7462 100644 --- a/lib/app_opener.dart +++ b/lib/app_opener.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/loading_provider.dart'; -import 'package:humhub/util/notifications/channel.dart'; import 'package:humhub/util/notifications/plugin.dart'; import 'package:humhub/util/override_locale.dart'; import 'package:humhub/util/push/push_plugin.dart'; @@ -24,7 +23,6 @@ class OpenerAppState extends ConsumerState { return IntentPlugin( child: NotificationPlugin( child: PushPlugin( - channel: NotificationChannel(), child: OverrideLocale( builder: (overrideLocale) => Builder( builder: (context) => FutureBuilder( diff --git a/lib/flavored/util/notifications/channel.dart b/lib/flavored/util/notifications/channel.dart index 9c98678..196d769 100644 --- a/lib/flavored/util/notifications/channel.dart +++ b/lib/flavored/util/notifications/channel.dart @@ -1,11 +1,10 @@ -import 'package:humhub/pages/web_view.dart'; +import 'package:humhub/flavored/util/router.f.dart'; +import 'package:humhub/flavored/web_view.f.dart'; import 'package:humhub/util/notifications/channel.dart'; import 'package:humhub/util/notifications/init_from_push.dart'; -import 'package:humhub/util/openers/universal_opener_controller.dart'; -import 'package:humhub/util/router.dart'; class NotificationChannelF extends NotificationChannel { - NotificationChannelF( + const NotificationChannelF( {super.id = 'redirect', super.name = 'Redirect flavored app notifications', super.description = 'These notifications redirect the user to specific url in a payload.'}); @@ -15,21 +14,19 @@ class NotificationChannelF extends NotificationChannel { /// @override Future onTap(String? payload) async { - if (payload != null && navigatorKey.currentState != null) { + if (payload != null && navigatorKeyF.currentState != null) { bool isNewRouteSameAsCurrent = false; - navigatorKey.currentState!.popUntil((route) { - if (route.settings.name == WebViewApp.path) { + navigatorKeyF.currentState!.popUntil((route) { + if (route.settings.name == WebViewF.path) { isNewRouteSameAsCurrent = true; } return true; }); - UniversalOpenerController opener = UniversalOpenerController(url: payload); - await opener.initHumHub(); if (isNewRouteSameAsCurrent) { - navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + navigatorKeyF.currentState!.pushNamed(WebViewF.path, arguments: payload); return; } - navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + navigatorKeyF.currentState!.pushNamed(WebViewF.path, arguments: payload); } else { if (payload != null) { InitFromPush.setPayload(payload); diff --git a/lib/flavored/web_view.f.dart b/lib/flavored/web_view.f.dart index c5dc827..1c8dbd4 100644 --- a/lib/flavored/web_view.f.dart +++ b/lib/flavored/web_view.f.dart @@ -75,8 +75,12 @@ class FlavoredWebViewState extends ConsumerState { } URLRequest get _initialRequest { + var payload = ModalRoute.of(context)!.settings.arguments; String? url = instance.manifest.startUrl; - String? payloadFromPush = InitFromPush.usePayload(); + String? payloadForInitFromPush = InitFromPush.usePayload(); + String? payloadFromPush; + if (payload is String) payloadFromPush = payload; + if (payloadForInitFromPush != null) url = payloadForInitFromPush; if (payloadFromPush != null) url = payloadFromPush; return URLRequest(url: Uri.parse(url), headers: instance.customHeaders); } diff --git a/lib/main.dart b/lib/main.dart index 6105b51..7174a55 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,6 +17,6 @@ main() async { PackageInfo packageInfo = await PackageInfo.fromPlatform(); await dotenv.load(fileName: ".env"); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) async { - runApp(ProviderScope(child: await HumHub.app(packageInfo.packageName))); + runApp(ProviderScope(child: HumHub.app(packageInfo.packageName))); }); } diff --git a/lib/models/hum_hub.dart b/lib/models/hum_hub.dart index 1d71358..910c9f5 100644 --- a/lib/models/hum_hub.dart +++ b/lib/models/hum_hub.dart @@ -67,7 +67,7 @@ class HumHub { 'x-humhub-app-ostate': isHideOpener ? '1' : '0' }; - static Future app(String bundleId) async { + static Widget app(String bundleId) { switch (bundleId) { case 'com.humhub.app': return const OpenerApp(); diff --git a/lib/pages/opener.dart b/lib/pages/opener.dart index ecf53e7..b0d50be 100644 --- a/lib/pages/opener.dart +++ b/lib/pages/opener.dart @@ -53,7 +53,7 @@ class OpenerState extends ConsumerState with SingleTickerProviderStateMi String? urlIntent = InitFromIntent.usePayloadForInit(); if (urlIntent != null) { - await NotificationChannel().onTap(urlIntent); + await ref.read(notificationChannelProvider).value!.onTap(urlIntent); } }); } diff --git a/lib/util/notifications/channel.dart b/lib/util/notifications/channel.dart index ec31761..923d8bc 100644 --- a/lib/util/notifications/channel.dart +++ b/lib/util/notifications/channel.dart @@ -1,14 +1,17 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/flavored/util/notifications/channel.dart'; import 'package:humhub/pages/web_view.dart'; import 'package:humhub/util/notifications/init_from_push.dart'; import 'package:humhub/util/openers/universal_opener_controller.dart'; import 'package:humhub/util/router.dart'; +import 'package:package_info_plus/package_info_plus.dart'; class NotificationChannel { final String id; final String name; final String description; - NotificationChannel( + const NotificationChannel( {this.id = 'redirect', this.name = 'Redirect app notifications', this.description = 'These notifications are redirect the user to specific url in a payload.'}); @@ -38,4 +41,19 @@ class NotificationChannel { } } } + + static Future getChannel() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); // Replace this with the actual condition logic + switch (packageInfo.packageName) { + case 'com.humhub.app': + return const NotificationChannel(); + default: + return const NotificationChannelF(); + } + } } + +// Providers for NotificationChannel and NotificationChannelF +final notificationChannelProvider = FutureProvider((ref) { + return NotificationChannel.getChannel(); +}); diff --git a/lib/util/notifications/service.dart b/lib/util/notifications/service.dart index 54818ae..2ced421 100644 --- a/lib/util/notifications/service.dart +++ b/lib/util/notifications/service.dart @@ -48,7 +48,8 @@ class NotificationService { static void handleNotification(NotificationResponse response) async { final parsed = response.payload != null ? json.decode(response.payload!) : {}; if (parsed["redirectUrl"] != null) { - await NotificationChannel().onTap(parsed['redirectUrl']); + var channel = await NotificationChannel.getChannel(); + channel.onTap(parsed['redirectUrl']); return; } } diff --git a/lib/util/push/push_plugin.dart b/lib/util/push/push_plugin.dart index 1044f02..8d773fe 100644 --- a/lib/util/push/push_plugin.dart +++ b/lib/util/push/push_plugin.dart @@ -13,13 +13,11 @@ import 'package:loggy/loggy.dart'; class PushPlugin extends ConsumerStatefulWidget { final Widget child; - final NotificationChannel channel; - const PushPlugin({ + const PushPlugin({ Key? key, required this.child, - required this.channel, - }) : super(key: key); + }) : super(key: key, ); @override PushPluginState createState() => PushPluginState(); @@ -44,7 +42,7 @@ class PushPluginState extends ConsumerState { FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { logInfo("Firebase messaging onMessageOpenedApp"); final data = PushEvent(message).parsedData; - widget.channel.onTap(data.redirectUrl); + ref.read(notificationChannelProvider).value!.onTap(data.redirectUrl); }); //When the app is terminated, i.e., app is neither in foreground or background. @@ -62,6 +60,7 @@ class PushPluginState extends ConsumerState { @override void initState() { + ref.read(notificationChannelProvider); _init(); super.initState(); } @@ -69,7 +68,7 @@ class PushPluginState extends ConsumerState { _handleInitialMsg(RemoteMessage message) { final data = PushEvent(message).parsedData; if (data.redirectUrl != null) { - widget.channel.onTap(data.redirectUrl); + ref.read(notificationChannelProvider).value!.onTap(data.redirectUrl); } } @@ -81,7 +80,7 @@ class PushPluginState extends ConsumerState { final body = message.notification?.body; if (title == null || body == null) return; await notificationService.showNotification( - widget.channel, + ref.read(notificationChannelProvider).value!, title, body, payload: data.channelPayload, From 8ae05862847df03808f069efa60afab5f0f9de86 Mon Sep 17 00:00:00 2001 From: primozratej Date: Sun, 26 May 2024 20:30:08 +0200 Subject: [PATCH 14/31] Dismiss loader only on loadStop --- lib/flavored/web_view.f.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/flavored/web_view.f.dart b/lib/flavored/web_view.f.dart index 1c8dbd4..8fb17f6 100644 --- a/lib/flavored/web_view.f.dart +++ b/lib/flavored/web_view.f.dart @@ -166,7 +166,6 @@ class FlavoredWebViewState extends ConsumerState { } else { logError('Could not launch $urlToOpen'); } - LoadingProvider.of(ref).dismissAll(); return Future.value(true); // Allow creating a new window. } @@ -186,7 +185,6 @@ class FlavoredWebViewState extends ConsumerState { void _onLoadStart(InAppWebViewController controller, Uri? url) async { _setAjaxHeadersJQuery(controller); - LoadingProvider.of(ref).dismissAll(); } void _onLoadError(InAppWebViewController controller, Uri? url, int code, String message) async { From 9459277e2f497f65ccebca9c9be5a157c3cfbbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Primo=C5=BE=20Ratej?= Date: Mon, 27 May 2024 22:43:14 +0200 Subject: [PATCH 15/31] Config intent plugin --- lib/app_flavored.dart | 4 +- lib/flavored/util/intent_plugin.f.dart | 137 +++++++++++++++++++++++++ lib/pages/opener.dart | 2 +- lib/pages/web_view.dart | 6 +- lib/util/intent/intent_plugin.dart | 6 +- lib/util/notifications/channel.dart | 8 +- lib/util/router.dart | 6 +- 7 files changed, 153 insertions(+), 16 deletions(-) create mode 100644 lib/flavored/util/intent_plugin.f.dart diff --git a/lib/app_flavored.dart b/lib/app_flavored.dart index 907803c..759f132 100644 --- a/lib/app_flavored.dart +++ b/lib/app_flavored.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/flavored/models/humhub.f.dart'; +import 'package:humhub/flavored/util/intent_plugin.f.dart'; import 'package:humhub/flavored/util/router.f.dart'; -import 'package:humhub/util/intent/intent_plugin.dart'; import 'package:humhub/util/loading_provider.dart'; import 'package:humhub/util/notifications/plugin.dart'; import 'package:humhub/util/override_locale.dart'; @@ -21,7 +21,7 @@ class FlavoredAppState extends ConsumerState { @override Widget build(BuildContext context) { SecureStorageService.clearSecureStorageOnReinstall(); - return IntentPlugin( + return IntentPluginF( child: NotificationPlugin( child: PushPlugin( child: OverrideLocale( diff --git a/lib/flavored/util/intent_plugin.f.dart b/lib/flavored/util/intent_plugin.f.dart new file mode 100644 index 0000000..240b2a9 --- /dev/null +++ b/lib/flavored/util/intent_plugin.f.dart @@ -0,0 +1,137 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:humhub/flavored/util/router.f.dart'; +import 'package:humhub/flavored/web_view.f.dart'; +import 'package:humhub/util/loading_provider.dart'; +import 'package:loggy/loggy.dart'; +import 'package:receive_sharing_intent/receive_sharing_intent.dart'; +import 'package:uni_links/uni_links.dart'; + +bool _initialUriIsHandled = false; + +class IntentPluginF extends ConsumerStatefulWidget { + final Widget child; + + const IntentPluginF({ + Key? key, + required this.child, + }) : super(key: key); + + @override + IntentPluginFState createState() => IntentPluginFState(); +} + +class IntentPluginFState extends ConsumerState { + StreamSubscription? intentDataStreamSubscription; + List? sharedFiles; + Object? _err; + Uri? _initialUri; + Uri? _latestUri; + StreamSubscription? _sub; + + @override + void initState() { + logInfo([_err, _initialUri, _latestUri, _sub]); + super.initState(); + intentDataStreamSubscription = ReceiveSharingIntent.getMediaStream().listen((List value) { + setState(() { + sharedFiles = value; + }); + }); + + // For sharing images coming from outside the app while the app is closed + ReceiveSharingIntent.getInitialMedia().then((List value) { + setState(() { + sharedFiles = value; + }); + }); + _handleInitialUri(); + _handleIncomingLinks(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } + + /// Handle incoming links - the ones that the app will recieve from the OS + /// while already started. + Future _handleIncomingLinks() async { + if (!kIsWeb) { + // It will handle app links while the app is already started - be it in + // the foreground or in the background. + _sub = uriLinkStream.listen((Uri? uri) async { + if (!mounted) return; + _latestUri = uri; + String? redirectUrl = uri?.toString(); + if (redirectUrl != null && navigatorKeyF.currentState != null) { + tryNavigateWithOpener(redirectUrl); + } + _err = null; + }, onError: (err) { + if (kDebugMode) { + print(err); + } + }); + } + } + + /// Handle the initial Uri - the one the app was started with + /// + /// **ATTENTION**: `getInitialLink`/`getInitialUri` should be handled + /// ONLY ONCE in your app's lifetime, since it is not meant to change + /// throughout your app's life. + /// + /// We handle all exceptions, since it is called from initState. + Future _handleInitialUri() async { + // In this example app this is an almost useless guard, but it is here to + // show we are not going to call getInitialUri multiple times, even if this + // was a widget that will be disposed of (ex. a navigation route change). + + if (!_initialUriIsHandled) { + _initialUriIsHandled = true; + try { + final uri = await getInitialUri(); + if (uri == null || !mounted) return; + setState(() => _initialUri = uri); + if (!mounted) { + return; + } + _latestUri = uri; + String? redirectUrl = uri.queryParameters['url']; + if (redirectUrl != null && navigatorKeyF.currentState != null) { + tryNavigateWithOpener(redirectUrl); + } else { + if (redirectUrl != null) { + navigatorKeyF.currentState!.pushNamed(WebViewF.path, arguments: redirectUrl); + return; + } + } + } on PlatformException { + // Platform messages may fail but we ignore the exception + logError('Failed to get initial uri'); + } on FormatException catch (err) { + if (!mounted) return; + logError('Malformed initial uri'); + setState(() => _err = err); + } + } + } + + Future tryNavigateWithOpener(String redirectUrl) async { + LoadingProvider.of(ref).showLoading(); + bool isNewRouteSameAsCurrent = false; + navigatorKeyF.currentState!.popUntil((route) { + if (route.settings.name == WebViewF.path) { + isNewRouteSameAsCurrent = true; + } + return true; + }); + navigatorKeyF.currentState!.pushNamed(WebViewF.path, arguments: redirectUrl); + return isNewRouteSameAsCurrent; + } +} diff --git a/lib/pages/opener.dart b/lib/pages/opener.dart index b0d50be..028283c 100644 --- a/lib/pages/opener.dart +++ b/lib/pages/opener.dart @@ -246,7 +246,7 @@ class OpenerState extends ConsumerState with SingleTickerProviderStateMi await controlLer.initHumHub(); if (controlLer.allOk) { ref.read(humHubProvider).getInstance().then((value) { - Navigator.pushNamed(ref.context, WebViewApp.path, arguments: value.manifest); + Navigator.pushNamed(ref.context, WebView.path, arguments: value.manifest); }); } } diff --git a/lib/pages/web_view.dart b/lib/pages/web_view.dart index 3e18e07..1be265e 100644 --- a/lib/pages/web_view.dart +++ b/lib/pages/web_view.dart @@ -28,15 +28,15 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../util/web_view_global_controller.dart'; -class WebViewApp extends ConsumerStatefulWidget { - const WebViewApp({super.key}); +class WebView extends ConsumerStatefulWidget { + const WebView({super.key}); static const String path = '/web_view'; @override WebViewAppState createState() => WebViewAppState(); } -class WebViewAppState extends ConsumerState { +class WebViewAppState extends ConsumerState { late AuthInAppBrowser authBrowser; late Manifest manifest; late URLRequest _initialRequest; diff --git a/lib/util/intent/intent_plugin.dart b/lib/util/intent/intent_plugin.dart index 7b98b92..84668ca 100644 --- a/lib/util/intent/intent_plugin.dart +++ b/lib/util/intent/intent_plugin.dart @@ -110,7 +110,7 @@ class IntentPluginState extends ConsumerState { if (redirectUrl != null) { UniversalOpenerController opener = UniversalOpenerController(url: redirectUrl); await opener.initHumHub(); - navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + navigatorKey.currentState!.pushNamed(WebView.path, arguments: opener); return; } } @@ -129,7 +129,7 @@ class IntentPluginState extends ConsumerState { LoadingProvider.of(ref).showLoading(); bool isNewRouteSameAsCurrent = false; navigatorKey.currentState!.popUntil((route) { - if (route.settings.name == WebViewApp.path) { + if (route.settings.name == WebView.path) { isNewRouteSameAsCurrent = true; } return true; @@ -138,7 +138,7 @@ class IntentPluginState extends ConsumerState { await opener.initHumHub(); // Always pop the current instance and init the new one. LoadingProvider.of(ref).dismissAll(); - navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + navigatorKey.currentState!.pushNamed(WebView.path, arguments: opener); return isNewRouteSameAsCurrent; } } diff --git a/lib/util/notifications/channel.dart b/lib/util/notifications/channel.dart index 923d8bc..a9d3626 100644 --- a/lib/util/notifications/channel.dart +++ b/lib/util/notifications/channel.dart @@ -17,13 +17,13 @@ class NotificationChannel { this.description = 'These notifications are redirect the user to specific url in a payload.'}); /// If the WebView is not opened yet or the app is not running the onTap will wake up the app or redirect to the WebView. - /// If app is already running in WebView mode then the state of [WebViewApp] will be updated with new url. + /// If app is already running in WebView mode then the state of [WebView] will be updated with new url. /// Future onTap(String? payload) async { if (payload != null && navigatorKey.currentState != null) { bool isNewRouteSameAsCurrent = false; navigatorKey.currentState!.popUntil((route) { - if (route.settings.name == WebViewApp.path) { + if (route.settings.name == WebView.path) { isNewRouteSameAsCurrent = true; } return true; @@ -31,10 +31,10 @@ class NotificationChannel { UniversalOpenerController opener = UniversalOpenerController(url: payload); await opener.initHumHub(); if (isNewRouteSameAsCurrent) { - navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + navigatorKey.currentState!.pushNamed(WebView.path, arguments: opener); return; } - navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener); + navigatorKey.currentState!.pushNamed(WebView.path, arguments: opener); } else { if (payload != null) { InitFromPush.setPayload(payload); diff --git a/lib/util/router.dart b/lib/util/router.dart index 8fc58ce..0d69566 100644 --- a/lib/util/router.dart +++ b/lib/util/router.dart @@ -34,7 +34,7 @@ class MyRouter { static var routes = { Opener.path: (context) => const Opener(), - WebViewApp.path: (context) => const WebViewApp(), + WebView.path: (context) => const WebView(), '/help': (context) => Platform.isAndroid ? const HelpAndroid() : const HelpIos(), }; @@ -46,9 +46,9 @@ class MyRouter { initRoute = Opener.path; return Opener.path; case RedirectAction.webView: - initRoute = WebViewApp.path; + initRoute = WebView.path; initParams = humhub.manifest; - return WebViewApp.path; + return WebView.path; } } } From 0c2ff88fa91c862854fcb260e40a7f4783899605 Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 28 May 2024 18:30:02 +0200 Subject: [PATCH 16/31] Remove flavored config for android --- .env | 8 --- android/app/build.gradle | 8 --- android/app/src/main/AndroidManifest.xml | 2 +- .../app/src/main/res/values-de/strings.xml | 4 -- .../app/src/main/res/values-en/strings.xml | 4 -- .../app/src/main/res/values-fr/strings.xml | 4 -- .../res/values-night}/styles.xml | 6 +- android/app/src/main/res/values/strings.xml | 4 -- android/app/src/omrade/AndroidManifest.xml | 55 ------------------ android/app/src/omrade/google-services.json | 46 --------------- .../res/drawable-v21/launch_background.xml | 12 ---- .../omrade/res/drawable/launch_background.xml | 12 ---- .../omrade/res/mipmap-hdpi/ic_launcher.png | Bin 1345 -> 0 bytes .../omrade/res/mipmap-mdpi/ic_launcher.png | Bin 1009 -> 0 bytes .../omrade/res/mipmap-xhdpi/ic_launcher.png | Bin 1695 -> 0 bytes .../omrade/res/mipmap-xxhdpi/ic_launcher.png | Bin 2275 -> 0 bytes .../omrade/res/mipmap-xxxhdpi/ic_launcher.png | Bin 2806 -> 0 bytes .../app/src/omrade/res/values-de/strings.xml | 4 -- .../app/src/omrade/res/values-en/strings.xml | 4 -- .../app/src/omrade/res/values-fr/strings.xml | 4 -- android/app/src/omrade/res/values/strings.xml | 4 -- lib/main.dart | 4 +- lib/models/hum_hub.dart | 4 +- pubspec.yaml | 1 - 24 files changed, 9 insertions(+), 181 deletions(-) delete mode 100644 .env delete mode 100644 android/app/src/main/res/values-de/strings.xml delete mode 100644 android/app/src/main/res/values-en/strings.xml delete mode 100644 android/app/src/main/res/values-fr/strings.xml rename android/app/src/{omrade/res/values => main/res/values-night}/styles.xml (81%) delete mode 100644 android/app/src/main/res/values/strings.xml delete mode 100644 android/app/src/omrade/AndroidManifest.xml delete mode 100644 android/app/src/omrade/google-services.json delete mode 100644 android/app/src/omrade/res/drawable-v21/launch_background.xml delete mode 100644 android/app/src/omrade/res/drawable/launch_background.xml delete mode 100644 android/app/src/omrade/res/mipmap-hdpi/ic_launcher.png delete mode 100644 android/app/src/omrade/res/mipmap-mdpi/ic_launcher.png delete mode 100644 android/app/src/omrade/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 android/app/src/omrade/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 android/app/src/omrade/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 android/app/src/omrade/res/values-de/strings.xml delete mode 100644 android/app/src/omrade/res/values-en/strings.xml delete mode 100644 android/app/src/omrade/res/values-fr/strings.xml delete mode 100644 android/app/src/omrade/res/values/strings.xml diff --git a/.env b/.env deleted file mode 100644 index a86072d..0000000 --- a/.env +++ /dev/null @@ -1,8 +0,0 @@ -GCM_SENDER_ID=103953800507 -DISPLAY=standalone -START_URL=https://intranet.omrade.co -MANIFEST_URL=https://intranet.omrade.co/manifest.json -SHORT_NAME=område -NAME=område -BACKGROUND_COLOR=2d3340 -THEME_COLOR=2d3340 \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 92d1ffd..5008dff 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -80,14 +80,6 @@ android { } } } - - flavorDimensions "flavor" - productFlavors { - omrade { - dimension "flavor" - applicationId "com.humhub.omrade.app" - } - } } flutter { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 68d22f3..09fba76 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ - - Humhub - \ No newline at end of file diff --git a/android/app/src/main/res/values-en/strings.xml b/android/app/src/main/res/values-en/strings.xml deleted file mode 100644 index ea59b9a..0000000 --- a/android/app/src/main/res/values-en/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Humhub - \ No newline at end of file diff --git a/android/app/src/main/res/values-fr/strings.xml b/android/app/src/main/res/values-fr/strings.xml deleted file mode 100644 index ea59b9a..0000000 --- a/android/app/src/main/res/values-fr/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Humhub - \ No newline at end of file diff --git a/android/app/src/omrade/res/values/styles.xml b/android/app/src/main/res/values-night/styles.xml similarity index 81% rename from android/app/src/omrade/res/values/styles.xml rename to android/app/src/main/res/values-night/styles.xml index cb1ef88..06952be 100644 --- a/android/app/src/omrade/res/values/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -1,7 +1,7 @@ - - diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml deleted file mode 100644 index ea59b9a..0000000 --- a/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Humhub - \ No newline at end of file diff --git a/android/app/src/omrade/AndroidManifest.xml b/android/app/src/omrade/AndroidManifest.xml deleted file mode 100644 index 6479c38..0000000 --- a/android/app/src/omrade/AndroidManifest.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/app/src/omrade/google-services.json b/android/app/src/omrade/google-services.json deleted file mode 100644 index 99a1f4b..0000000 --- a/android/app/src/omrade/google-services.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "project_info": { - "project_number": "21392898126", - "project_id": "humhub-push-service", - "storage_bucket": "humhub-push-service.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:21392898126:android:3a252132106213e008ab1f", - "android_client_info": { - "package_name": "com.humhub.omrade.app" - } - }, - "oauth_client": [ - { - "client_id": "21392898126-ds3289q62hgqucr3hhtujkanj6l1u8ee.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBm9okv_3wczFQzFt91Ksg33Tk9KPAMT4o" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "21392898126-ds3289q62hgqucr3hhtujkanj6l1u8ee.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "21392898126-filvre2lp06kebh2p7b788tqepqcvtqq.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "com.humhub.app" - } - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/android/app/src/omrade/res/drawable-v21/launch_background.xml b/android/app/src/omrade/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f..0000000 --- a/android/app/src/omrade/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/android/app/src/omrade/res/drawable/launch_background.xml b/android/app/src/omrade/res/drawable/launch_background.xml deleted file mode 100644 index 304732f..0000000 --- a/android/app/src/omrade/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/android/app/src/omrade/res/mipmap-hdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 63de2d357b0bcdaa76a9da92b62772ced7cd9f75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1345 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAk#!vLQUSN8&+_p{aJ?emYgkppCu zpG$l!T_sR1F3{512TXrfh0r_NWu|Z3s??%UaFVYl*c%u?O9-X?UR!HrpJb%#TH_WD803~CnmFk3C4Ssg6{|94{i$k;~^V;OT6)3ftsV>(x>0^(^}q&O{>!AO?=mHUh&t|*Wg;! zubA%c{cH}q7#NtZdb&7zt_o;i7zgTT`%&LRSWBBCPsd#;_$6A~@GYyJN}duy^= zdcw7csr)OwZpxQ&FRQ)$H}1QSbD;U|n`i$qColPyaADevGtq$?avf9Fu^O&cUK-Q0 zW=+p3wLdfOM(vQwjok9=TiC1l2bZi0(pl>tmZcHex#-BX3$JpNw2#!A$)1ko6i@uI zs&9cx+LTjMMW-)VaP4B&qw5yFs@%fLwzhiqhkVajy}KL!B%~|5$yWB;?&;TUE~rhZ zoi}6JW%Y+L+kfY#oX@XZ;k(%LUJ@%M4r12=Q$ zFW++eb(y$xZkNK>O*cc&Rf@hY=Dc#~@Mmw9i8mg8UOpj&U-^#i3*)DCZtI25|J_wt zwffS-dvaA%TI5fQq{psO=+*|bs zx(m*gn0|M7p7^@FNNXLu=d&%BoMw`NysAwo{>#gJs zR=2w7qP5)4>YAXE2BY3vix*1*RMgGic8BmcPxYu;GCMGLn#eYWQ%k1XSvmAGcB-5{ z=2Bdspm0*j*IwbI+tr4gS63abm^v726%>3Cl-0u@6ue$dTCBe9jhvg=6!~n=F2$4i zF;o7BO!$5ykNd)=lLxPU@i?_=W>br7 zD}KJ*o~K$^Ji45Vcowj`O^iRFX|;X7x%yMH+`Hx;Gke#*Ie6>3;t|)N-y@met&1*rWbr zgD2-E0nW!f0%C`@U;oi`N4`&@xhel(wyy1ub7FJW)isySa*+A=uykh3&EJ2&75rg5 zA{ZL4JxA|;EIp>z;=jSLCr0ptaG5=q-{l9AQ>O~3s1^v5*w d-^ag6GmA%9#;d)$1S}>PJYD@<);T3K0RWAxd{qDd diff --git a/android/app/src/omrade/res/mipmap-mdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 6df86cb58aa13924aa74ad463e68a3375a0ab373..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1009 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sKLdP1T-^(NB5vkJ+{g{Sl@BD} z%~pex?`Nw5+3#no0R`9W@C0#he4xS4lr zhEhPYKi9ak}Vx%1hLtAEySU&D~|f`Nf4!_&nv#N+tekjU~`4kB!-n@%if=wb>y$a+1a z=hhbA>Vn>jOEQ1|ulGq$oKX0(xZ3ZXBTlHP$nMCcJd2&v@?*F$%%onot2AHALU zUpXe7<HYe97?-o9?6IWh1?|Z=UpbWFZC)Z?a z)~BzxET}J3&^&uCm}}jVDQU%TgIW)X^)_a`h-X-~_Q8#7JeR|4^Iji4$eU`k!*PzF z)EsxVcIkQYOJ-gz_~}z*!*JMS@mu4MpDatRgeCpVa7+1Fvg@Afo_lF8EiP|AY#sGp zqv1{X%&*T1ei+=JFEE|&cjJ@F{u%}Ie}xYkKX~uX|J3xLraEeo{;s>WzqYep?RatQ zvSZU^w;&h&O3x;h4}EVHb32q$8PBKf(9GQyIV*DBrJll5sgv7E=APJdOV?ttUFx0X zDbr@o+Pp^aBDc%-n72lf;l~y`3M`q^>2%`8`!8*_cjum#+2QxlU6kQT&58XQ^$gvw W78GV!ojU?dz6_qOelF{r5}E*YX6y3+ diff --git a/android/app/src/omrade/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 02272133bcb67927906ff91367c1351eeade87d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1695 zcmXw3dpr|rAD_$K7jew%Hn-eoCYPkl(WqBzMYQ@Ir~Y+5)u=1y*Vn;oGt z9pSj0&eUP`&h=n%Hft{7Y}7f({VctGKF{<0{hr_V@_e3uo-DMlr;3uU5&!^D@%BPu zr1jG0tsp1G-%n9L6MXb(tcU0I(~<{}^W)c~h@Xg-u3w%Wj~>4A|09nmot)c8X|w#m zT#8caGdq55dB53bzuI|U*{`xMIbW13`*vvpe*CI<-z#}wE~TUs9FMqCZuTYl3$mF< zx=T!wUg7cN{p%*8F=Wt+RLmoy$skOIYCzsW948o8Z9|}{PnDYH-3PM^4OujUM4CYm zMGe=DKKBgiNe_ifUwSMK;~N0jVyy0nfwD?#N@sP(5@8;~yh6QWM4)^_4W%`#YQ5|FR=Zj}!I4yH;C8>TLVJdpf zq+%oZ4zQaL^{wT0d{gCW7h|O*yRs*w%UNs3AyTKf_kB@w2_&WCS!eFXFn*1U1-OCk z3+^oEH;ETD`B3metLo~O;ksW8KU^5RW3^LzmvnxQEs{tQ)<1UkDEl`IFX&{&?a*Dj zFd!mRBVyj6jJdZ<)HX&F!mPB_G|E#A|6V3OQsA4*XARnFpW%XaD|q>|t!lNkYqy6R zu`o$v0@<_?L-xiLY`GdRN8C#-42AuYs;US&n! zu$VvIV~|h{O6=HjQx!Rvm*_jn3<(%B2i4>29zh;YHS>2j#Fof5mwGp5F1@fxP(@cL zkddj`ki8&)nvq8Rc%eO{70qyiW<0=Q0uOfs0Ti@21a=`_8F;o-8G~7*~e{< z!xPFlXn54A)=asZma~8v?Y8Zn+zSeFJ3cf34WD-T2(C{ABIV3ev}qZYKXjMi}B z^>F*W7ELPOFyK0h0XeRN8}p$Y@K4yw1*-QuKGJ8q%V3;a^$N(GVm;%tX(O0UW#7M^ z<5IdS^4!yzOHS6wl}B9dG#KDcVE{^3|HGL~#A17%slhi3_6&Ez$rrRabl<#&1*J1DQmYFL9C8~D%*b|vya`6cFS=-N+Q=<;nKPE_7l5U#KJJ0rYhHO_ znHLWFE44d{YCf3gQDC563+mC{|8>`4l4vEr-Rd=W(bp@hiI^xQmrm!z9@_j^O=qp= z&6WJA?|3h@suYwrH>7>^O|q|B)RP!fd6^jfzk=eBiCLCPH~2IP%UsBvOtwp_AlT<$ zd~cJJ``S{jy$C#nd`N}ik9Ccgtly#}ZLgehs4%}%guk@%Nc2g;z#e#UX6}G_p#FK1 z0bl*(w8-|yt$su*I-a%D7l<-oQxP|_H3K1zqYlw<;=LE1Vc*{&t$qr8)?DR_BX+zA z`>ruL6n#!vSqNWLq~Xw%$;7v(das6DSc0~xC_0>|SxU5=w4E&ve;G+@`mqsKch%C{ zI<=kaG&troE5^AzI%pA~g&|3*`Or;XS?tSKL|>kFzewO%7(Kf7^W)&qQLk2negle2 zWX6am-o{N&drC z9L|0qD6}Zb-7OG5#k?;X-AH*-oCJKA@}yz%cdq|2uF=3Yn(;8@gU55>fLXz5`~I08 bW0D-_o*%}XpmS3C4+FeCe34HOmookV1bH=$ diff --git a/android/app/src/omrade/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/omrade/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index b56bacfd36febd744493aed90a098e3e81e12552..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2275 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 M(#!@`V(J<9UuJ<`8UO$Q diff --git a/android/app/src/omrade/res/values-de/strings.xml b/android/app/src/omrade/res/values-de/strings.xml deleted file mode 100644 index d9032cf..0000000 --- a/android/app/src/omrade/res/values-de/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Område - \ No newline at end of file diff --git a/android/app/src/omrade/res/values-en/strings.xml b/android/app/src/omrade/res/values-en/strings.xml deleted file mode 100644 index d9032cf..0000000 --- a/android/app/src/omrade/res/values-en/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Område - \ No newline at end of file diff --git a/android/app/src/omrade/res/values-fr/strings.xml b/android/app/src/omrade/res/values-fr/strings.xml deleted file mode 100644 index d9032cf..0000000 --- a/android/app/src/omrade/res/values-fr/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Område - \ No newline at end of file diff --git a/android/app/src/omrade/res/values/strings.xml b/android/app/src/omrade/res/values/strings.xml deleted file mode 100644 index d9032cf..0000000 --- a/android/app/src/omrade/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Område - \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 7174a55..c1cd91f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,8 +15,8 @@ main() async { WidgetsFlutterBinding.ensureInitialized(); await SecureStorageService.clearSecureStorageOnReinstall(); PackageInfo packageInfo = await PackageInfo.fromPlatform(); - await dotenv.load(fileName: ".env"); + final app = await HumHub.app(packageInfo.packageName); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) async { - runApp(ProviderScope(child: HumHub.app(packageInfo.packageName))); + runApp(ProviderScope(child: app)); }); } diff --git a/lib/models/hum_hub.dart b/lib/models/hum_hub.dart index 910c9f5..515c216 100644 --- a/lib/models/hum_hub.dart +++ b/lib/models/hum_hub.dart @@ -1,5 +1,6 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:humhub/app_flavored.dart'; import 'package:humhub/app_opener.dart'; import 'package:humhub/models/manifest.dart'; @@ -67,11 +68,12 @@ class HumHub { 'x-humhub-app-ostate': isHideOpener ? '1' : '0' }; - static Widget app(String bundleId) { + static Future app(String bundleId) async { switch (bundleId) { case 'com.humhub.app': return const OpenerApp(); default: + await dotenv.load(fileName: ".env"); return const FlavoredApp(); } } diff --git a/pubspec.yaml b/pubspec.yaml index 68b43ab..f53ed75 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -91,7 +91,6 @@ flutter: - asset: assets/fonts/OpenSans-SemiBold.ttf assets: - - .env - assets/images/ - assets/images/locale/ - assets/opener_animation.riv From e0416667d6ac993c88308e76b01450105314fc3f Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 28 May 2024 18:50:48 +0200 Subject: [PATCH 17/31] Reformat with dart formater --- lib/flavored/models/humhub.f.dart | 22 +++++++++++----------- lib/flavored/models/manifest.f.dart | 27 ++++++++++++++++----------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/lib/flavored/models/humhub.f.dart b/lib/flavored/models/humhub.f.dart index 9fb0203..1250a32 100644 --- a/lib/flavored/models/humhub.f.dart +++ b/lib/flavored/models/humhub.f.dart @@ -3,7 +3,7 @@ import 'package:humhub/flavored/models/manifest.f.dart'; import 'package:humhub/models/hum_hub.dart'; import 'package:package_info_plus/package_info_plus.dart'; -class HumHubF extends HumHub{ +class HumHubF extends HumHub { @override ManifestF get manifest => ManifestF.fromEnv(); @override @@ -17,21 +17,21 @@ class HumHubF extends HumHub{ String? pushToken, required this.bundleId, }) : super( - isHideOpener: isHideOpener, - randomHash: HumHub.generateHash(32), - appVersion: appVersion, - pushToken: pushToken); + isHideOpener: isHideOpener, + randomHash: HumHub.generateHash(32), + appVersion: appVersion, + pushToken: pushToken); @override Map get customHeaders => { - 'x-humhub-app-token': randomHash!, - 'x-humhub-app': appVersion ?? '1.0.0', - 'x-humhub-app-bundle-id': bundleId, - 'x-humhub-app-ostate': isHideOpener ? '1' : '0' - }; + 'x-humhub-app-token': randomHash!, + 'x-humhub-app': appVersion ?? '1.0.0', + 'x-humhub-app-bundle-id': bundleId, + 'x-humhub-app-ostate': isHideOpener ? '1' : '0' + }; static Future initialize() async { PackageInfo packageInfo = await PackageInfo.fromPlatform(); return HumHubF(bundleId: packageInfo.packageName); } -} \ No newline at end of file +} diff --git a/lib/flavored/models/manifest.f.dart b/lib/flavored/models/manifest.f.dart index 6f6cbbc..677dbf5 100644 --- a/lib/flavored/models/manifest.f.dart +++ b/lib/flavored/models/manifest.f.dart @@ -1,16 +1,21 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:humhub/models/manifest.dart'; -class ManifestF extends Manifest{ - ManifestF({ - required String display, required String startUrl, required String shortName, required String name, required String backgroundColor, required String themeColor - }) : super( - display: display, - startUrl: startUrl, - shortName: shortName, - name: name, - backgroundColor: backgroundColor, - themeColor: themeColor); +class ManifestF extends Manifest { + ManifestF( + {required String display, + required String startUrl, + required String shortName, + required String name, + required String backgroundColor, + required String themeColor}) + : super( + display: display, + startUrl: startUrl, + shortName: shortName, + name: name, + backgroundColor: backgroundColor, + themeColor: themeColor); factory ManifestF.fromEnv() { return ManifestF( @@ -22,4 +27,4 @@ class ManifestF extends Manifest{ themeColor: dotenv.env['THEME_COLOR']!, ); } -} \ No newline at end of file +} From 9c8aa2202b2d11c5eeac55d79dd9b5fd88e3dba0 Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 28 May 2024 18:55:06 +0200 Subject: [PATCH 18/31] Remove unused imports --- lib/main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index c1cd91f..2ad0a1c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:humhub/models/hum_hub.dart'; import 'package:humhub/util/log.dart'; From f91250ecf9094a65885976400ec6483ee664fad3 Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 11 Jun 2024 20:36:56 +0200 Subject: [PATCH 19/31] Add DarwinNotificationDetails --- lib/util/notifications/service.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/util/notifications/service.dart b/lib/util/notifications/service.dart index 2ced421..ebfd9de 100644 --- a/lib/util/notifications/service.dart +++ b/lib/util/notifications/service.dart @@ -86,6 +86,15 @@ class NotificationService { largeIcon: const DrawableResourceAndroidBitmap('@mipmap/ic_launcher'), color: color, ), + iOS: DarwinNotificationDetails( + presentAlert: true, + presentBadge: true, + presentSound: true, + badgeNumber: 1, + subtitle: channel.description, + threadIdentifier: channel.id, + interruptionLevel: InterruptionLevel.critical, + ), ); } From 0d441de6f77486fcc01ef532276f3d949350cc55 Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 11 Jun 2024 20:41:00 +0200 Subject: [PATCH 20/31] Only sync base lib --- .github/sync.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index 4fcfea2..6ce9e5c 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,13 +1,7 @@ humhub/app@f-flavored: - - android/ - - ios/ - assets/ - lib/ - - linux - - macos/ - test/ - - web/ - - windows - .gitignore - .metadata - analysis_options.yaml @@ -15,15 +9,9 @@ humhub/app@f-flavored: - pubspec.lock - pubspec.yaml humhub/app-flavored@main: - - android/ - - ios/ - assets/ - lib/ - - linux - - macos/ - test/ - - web/ - - windows - .gitignore - .metadata - analysis_options.yaml From 9b6e78de58c053a251f29d7c87b67edc9f789cd4 Mon Sep 17 00:00:00 2001 From: primozratej Date: Tue, 11 Jun 2024 21:17:45 +0200 Subject: [PATCH 21/31] Notification proxy for ios --- ios/Runner/AppDelegate.swift | 3 +++ lib/util/notifications/service.dart | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 2fcdc7a..4833a48 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -8,6 +8,9 @@ import Firebase _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate + } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/lib/util/notifications/service.dart b/lib/util/notifications/service.dart index ebfd9de..aaf8908 100644 --- a/lib/util/notifications/service.dart +++ b/lib/util/notifications/service.dart @@ -90,10 +90,8 @@ class NotificationService { presentAlert: true, presentBadge: true, presentSound: true, - badgeNumber: 1, - subtitle: channel.description, threadIdentifier: channel.id, - interruptionLevel: InterruptionLevel.critical, + interruptionLevel: InterruptionLevel.timeSensitive, ), ); } From b82aca4fea67e0277fd2657f1d3f4780ac2b0919 Mon Sep 17 00:00:00 2001 From: primozratej Date: Sun, 16 Jun 2024 22:25:33 +0200 Subject: [PATCH 22/31] Fix pull to refresh for flavored --- lib/flavored/web_view.f.dart | 72 +++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/lib/flavored/web_view.f.dart b/lib/flavored/web_view.f.dart index 8fb17f6..38a4cdb 100644 --- a/lib/flavored/web_view.f.dart +++ b/lib/flavored/web_view.f.dart @@ -35,6 +35,8 @@ class FlavoredWebViewState extends ConsumerState { HeadlessInAppWebView? headlessWebView; late HumHubF instance; + late PullToRefreshController pullToRefreshController; + @override void initState() { instance = ref.read(humHubFProvider).value!; @@ -45,6 +47,20 @@ class FlavoredWebViewState extends ConsumerState { }, ); super.initState(); + + pullToRefreshController = PullToRefreshController( + options: PullToRefreshOptions( + color: HexColor(instance.manifest.themeColor), + ), + onRefresh: () async { + if (Platform.isAndroid) { + WebViewGlobalController.value?.reload(); + } else if (Platform.isIOS) { + WebViewGlobalController.value + ?.loadUrl(urlRequest: URLRequest(url: await WebViewGlobalController.value?.getUrl())); + } + }, + ); } @override @@ -59,7 +75,7 @@ class FlavoredWebViewState extends ConsumerState { child: InAppWebView( initialUrlRequest: _initialRequest, initialOptions: _options, - pullToRefreshController: _pullToRefreshController, + pullToRefreshController: pullToRefreshController, shouldOverrideUrlLoading: _shouldOverrideUrlLoading, shouldInterceptFetchRequest: _shouldInterceptFetchRequest, onWebViewCreated: _onWebViewCreated, @@ -86,34 +102,21 @@ class FlavoredWebViewState extends ConsumerState { } InAppWebViewGroupOptions get _options => InAppWebViewGroupOptions( - crossPlatform: InAppWebViewOptions( - useShouldOverrideUrlLoading: true, - useShouldInterceptFetchRequest: true, - javaScriptEnabled: true, - supportZoom: false, - javaScriptCanOpenWindowsAutomatically: true, - ), - android: AndroidInAppWebViewOptions( - supportMultipleWindows: true, - ), - ); - - PullToRefreshController get _pullToRefreshController => PullToRefreshController( - options: PullToRefreshOptions( - color: HexColor(instance.manifest.themeColor), - ), - onRefresh: () async { - Uri? url = await WebViewGlobalController.value!.getUrl(); - if (url != null) { - WebViewGlobalController.value!.loadUrl( - urlRequest: - URLRequest(url: await WebViewGlobalController.value!.getUrl(), headers: instance.customHeaders), - ); - } else { - WebViewGlobalController.value!.reload(); - } - }, - ); + crossPlatform: InAppWebViewOptions( + useShouldOverrideUrlLoading: true, + useShouldInterceptFetchRequest: true, + javaScriptEnabled: true, + supportZoom: false, + javaScriptCanOpenWindowsAutomatically: true, + ), + android: AndroidInAppWebViewOptions( + supportMultipleWindows: true, + useHybridComposition: true, + ), + ios: IOSInAppWebViewOptions( + allowsInlineMediaPlayback: true, + ), + ); Future _shouldOverrideUrlLoading( InAppWebViewController controller, NavigationAction action) async { @@ -176,11 +179,12 @@ class FlavoredWebViewState extends ConsumerState { .evaluateJavascript(source: "document.querySelector('#login-rememberme').checked=true"); WebViewGlobalController.value!.evaluateJavascript( source: - "document.querySelector('#account-login-form > div.form-group.field-login-rememberme').style.display='none';"); + "document.querySelector('#account-login-form > div.form-group.field-login-rememberme').style.display='none';"); } _setAjaxHeadersJQuery(controller); - await _pullToRefreshController.endRefreshing(); + pullToRefreshController.endRefreshing(); LoadingProvider.of(ref).dismissAll(); + setState(() {}); } void _onLoadStart(InAppWebViewController controller, Uri? url) async { @@ -189,12 +193,14 @@ class FlavoredWebViewState extends ConsumerState { void _onLoadError(InAppWebViewController controller, Uri? url, int code, String message) async { if (code == -1009) ShowDialog.of(context).noInternetPopup(); - await _pullToRefreshController.endRefreshing(); + pullToRefreshController.endRefreshing(); + setState(() {}); } void _onProgressChanged(controller, progress) async { if (progress == 100) { - await _pullToRefreshController.endRefreshing(); + pullToRefreshController.endRefreshing(); + setState(() {}); } } From d8ebc56c0fcd686dcfdd8f80125920b6cc140117 Mon Sep 17 00:00:00 2001 From: primozratej Date: Mon, 17 Jun 2024 17:42:51 +0200 Subject: [PATCH 23/31] Fix pull to refresh controller and add assets folder as a whole --- ios/Podfile.lock | 8 ++-- ios/Runner.xcodeproj/project.pbxproj | 18 ++++++++ lib/pages/web_view.dart | 64 ++++++++++++---------------- pubspec.yaml | 3 +- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 05c08c2..9560ef0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -81,7 +81,7 @@ PODS: - OrderedSet (5.0.0) - package_info_plus (0.4.5): - Flutter - - permission_handler_apple (9.0.4): + - permission_handler_apple (9.3.0): - Flutter - PromisesObjC (2.3.1) - ReachabilitySwift (5.0.0) @@ -174,7 +174,7 @@ SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_app_badger: b87fc231847b03b92ce1412aa351842e7e97932f flutter_inappwebview: 3d32228f1304635e7c028b0d4252937730bbc6cf - flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 + flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 flutter_native_timezone: 5f05b2de06c9776b4cc70e1839f03de178394d22 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2 @@ -182,7 +182,7 @@ SPEC CHECKSUMS: nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e - permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 receive_sharing_intent: c0d87310754e74c0f9542947e7cbdf3a0335a3b1 @@ -192,4 +192,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 548c8331f2ddb6f2f1e6ba81be1123190231f6e9 -COCOAPODS: 1.14.2 +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index a9a1e38..4e004d1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 1E133FF3E9A1AC81E5CA3EF3 /* [CP] Embed Pods Frameworks */, + 023992100ACEB29FB2946A93 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -209,6 +210,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 023992100ACEB29FB2946A93 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 1E133FF3E9A1AC81E5CA3EF3 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/lib/pages/web_view.dart b/lib/pages/web_view.dart index 1be265e..087bde4 100644 --- a/lib/pages/web_view.dart +++ b/lib/pages/web_view.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:app_settings/app_settings.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; @@ -53,25 +53,40 @@ class WebViewAppState extends ConsumerState { ), ); - PullToRefreshController? _pullToRefreshController; - late PullToRefreshOptions _pullToRefreshOptions; + late PullToRefreshController _pullToRefreshController; + HeadlessInAppWebView? headlessWebView; @override void initState() { super.initState(); + SchedulerBinding.instance.addPostFrameCallback((_) { + _initialRequest = _initRequest; + _pullToRefreshController = PullToRefreshController( + options: PullToRefreshOptions( + color: HexColor(manifest.themeColor), + ), + onRefresh: () async { + if (Platform.isAndroid) { + WebViewGlobalController.value?.reload(); + } else if (Platform.isIOS) { + WebViewGlobalController.value + ?.loadUrl(urlRequest: URLRequest(url: await WebViewGlobalController.value?.getUrl())); + } + }, + ); + authBrowser = AuthInAppBrowser( + manifest: manifest, + concludeAuth: (URLRequest request) { + _concludeAuth(request); + }, + ); + setState(() {}); + }); } @override Widget build(BuildContext context) { - _initialRequest = _initRequest; - _pullToRefreshController = initPullToRefreshController; - authBrowser = AuthInAppBrowser( - manifest: manifest, - concludeAuth: (URLRequest request) { - _concludeAuth(request); - }, - ); // ignore: deprecated_member_use return WillPopScope( onWillPop: () => exitApp(context, ref), @@ -199,38 +214,15 @@ class WebViewAppState extends ConsumerState { "document.querySelector('#account-login-form > div.form-group.field-login-rememberme').style.display='none';"); } _setAjaxHeadersJQuery(controller); - _pullToRefreshController?.endRefreshing(); + _pullToRefreshController.endRefreshing(); } _onProgressChanged(InAppWebViewController controller, int progress) { if (progress == 100) { - _pullToRefreshController?.endRefreshing(); + _pullToRefreshController.endRefreshing(); } } - PullToRefreshController? get initPullToRefreshController { - _pullToRefreshOptions = PullToRefreshOptions( - color: HexColor(manifest.themeColor), - ); - return kIsWeb - ? null - : PullToRefreshController( - options: _pullToRefreshOptions, - onRefresh: () async { - Uri? url = await WebViewGlobalController.value!.getUrl(); - if (url != null) { - WebViewGlobalController.value!.loadUrl( - urlRequest: URLRequest( - url: await WebViewGlobalController.value!.getUrl(), - headers: ref.read(humHubProvider).customHeaders), - ); - } else { - WebViewGlobalController.value!.reload(); - } - }, - ); - } - askForNotificationPermissions() { showDialog( context: context, diff --git a/pubspec.yaml b/pubspec.yaml index f53ed75..936f8c9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -91,10 +91,9 @@ flutter: - asset: assets/fonts/OpenSans-SemiBold.ttf assets: + - assets/ - assets/images/ - assets/images/locale/ - - assets/opener_animation.riv - - assets/opener_animation_reverse.riv # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg From b4e044a39def9f69fa9042e69bf727ab82f433bb Mon Sep 17 00:00:00 2001 From: primozratej Date: Mon, 17 Jun 2024 17:47:49 +0200 Subject: [PATCH 24/31] Support .env asset --- assets/{ => animations}/opener_animation.riv | Bin .../{ => animations}/opener_animation_reverse.riv | Bin assets/opener_animation_reverse_test.riv | Bin 562 -> 0 bytes lib/util/const.dart | 4 ++-- pubspec.yaml | 1 + 5 files changed, 3 insertions(+), 2 deletions(-) rename assets/{ => animations}/opener_animation.riv (100%) rename assets/{ => animations}/opener_animation_reverse.riv (100%) delete mode 100644 assets/opener_animation_reverse_test.riv diff --git a/assets/opener_animation.riv b/assets/animations/opener_animation.riv similarity index 100% rename from assets/opener_animation.riv rename to assets/animations/opener_animation.riv diff --git a/assets/opener_animation_reverse.riv b/assets/animations/opener_animation_reverse.riv similarity index 100% rename from assets/opener_animation_reverse.riv rename to assets/animations/opener_animation_reverse.riv diff --git a/assets/opener_animation_reverse_test.riv b/assets/opener_animation_reverse_test.riv deleted file mode 100644 index 9b711a4a6c3e1ebd9f21f0e2685a85a45e59d9c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 562 zcmXxiKS/zXg?tGUKTV-k_-9Z^rH;@}XCS6lp(Xg-UDwup+WoO;24MhJn@PMKQj z7_g#r>LR#^b!b3TNJ>f9B6JkN(IH?5DZ=%AKhK+f?|Tp5b9da#%lSz^c7JtT3Gmel z;Rim-dY~q0=WBf9yfw#j`NefRw~RWUHf?8}RSn^t?d?P)9zRS3fyc55g)@n;CQJcM zd(gK3)T-!RwX2FjcT;M0bG9IL_k5|MrkU7=)Z@2vQcaV?Uw-J$_mD)h7U-Th>~hhs z2^t!@UDpL#XlT)Z&Y?$kHnV2uGwWICaRI{$qaziS;srknv5(mPdxtqfoVp+yR>TVh z{?sMC(BFff_n~x}Xjnlngu-RY3jtMTj7|dnG5JtM!)m(Eqel`=b>}_v3A6Bt*{imn znfz!dd}ZDpxX&C^+au;Pm8~*W4S!O@3em_fxMxRCiCp86Yl?w~yycqf^!W*qYs#f> zOs**gJ}|kaTpD0<4F!&gR0C@$G@G~cj``YNTFGP`vmehlg#VTO&dHI-FuF Date: Mon, 17 Jun 2024 17:54:46 +0200 Subject: [PATCH 25/31] deleteOrphaned: true --- .github/sync.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index 6ce9e5c..4995022 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,7 +1,10 @@ humhub/app@f-flavored: - - assets/ - - lib/ - - test/ + - source: assets/ + deleteOrphaned: true + - source: lib/ + deleteOrphaned: true + - source: test/ + deleteOrphaned: true - .gitignore - .metadata - analysis_options.yaml @@ -9,9 +12,12 @@ humhub/app@f-flavored: - pubspec.lock - pubspec.yaml humhub/app-flavored@main: - - assets/ - - lib/ - - test/ + - source: assets/ + deleteOrphaned: true + - source: lib/ + deleteOrphaned: true + - source: test/ + deleteOrphaned: true - .gitignore - .metadata - analysis_options.yaml From f5a9dc0c6b552c09b2ebe149cf505dcb28c0196a Mon Sep 17 00:00:00 2001 From: primozratej Date: Mon, 17 Jun 2024 21:04:04 +0200 Subject: [PATCH 26/31] Remove USE_FULL_SCREEN_INTENT uses-permission --- android/app/src/main/AndroidManifest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 09fba76..69ae072 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -6,6 +6,9 @@ + Date: Mon, 17 Jun 2024 21:13:24 +0200 Subject: [PATCH 27/31] ignore: ["assets/.env"] --- .github/sync.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/sync.yml b/.github/sync.yml index 4995022..f7cf76a 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,6 +1,7 @@ humhub/app@f-flavored: - source: assets/ deleteOrphaned: true + ignore: ["assets/.env"] - source: lib/ deleteOrphaned: true - source: test/ @@ -14,6 +15,7 @@ humhub/app@f-flavored: humhub/app-flavored@main: - source: assets/ deleteOrphaned: true + ignore: ["assets/.env"] - source: lib/ deleteOrphaned: true - source: test/ From dea7fb007c004c5ac6d78d2295441147205daf16 Mon Sep 17 00:00:00 2001 From: primozratej Date: Mon, 17 Jun 2024 21:16:10 +0200 Subject: [PATCH 28/31] exclude: .env --- .github/sync.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index f7cf76a..c57aecd 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,7 +1,8 @@ humhub/app@f-flavored: - source: assets/ deleteOrphaned: true - ignore: ["assets/.env"] + exclude: | + .env - source: lib/ deleteOrphaned: true - source: test/ @@ -15,7 +16,8 @@ humhub/app@f-flavored: humhub/app-flavored@main: - source: assets/ deleteOrphaned: true - ignore: ["assets/.env"] + exclude: | + .env - source: lib/ deleteOrphaned: true - source: test/ From ff29357f3798d71edd33c2352d93b8c5f4959cf6 Mon Sep 17 00:00:00 2001 From: primozratej Date: Mon, 17 Jun 2024 21:18:06 +0200 Subject: [PATCH 29/31] Change route for env --- lib/models/hum_hub.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/models/hum_hub.dart b/lib/models/hum_hub.dart index 515c216..cafb177 100644 --- a/lib/models/hum_hub.dart +++ b/lib/models/hum_hub.dart @@ -73,7 +73,7 @@ class HumHub { case 'com.humhub.app': return const OpenerApp(); default: - await dotenv.load(fileName: ".env"); + await dotenv.load(fileName: "assets/.env"); return const FlavoredApp(); } } From 4be1ded169f5f4796c3ee00923cd4ee13447ae49 Mon Sep 17 00:00:00 2001 From: primozratej Date: Mon, 17 Jun 2024 21:55:20 +0200 Subject: [PATCH 30/31] Change sync branch. --- .github/sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/sync.yml b/.github/sync.yml index c57aecd..c35f4ab 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,4 +1,4 @@ -humhub/app@f-flavored: +humhub/app@main: - source: assets/ deleteOrphaned: true exclude: | From 4ef455bd490891d47f8592b140af64fa45ff9943 Mon Sep 17 00:00:00 2001 From: primozratej Date: Mon, 17 Jun 2024 21:57:08 +0200 Subject: [PATCH 31/31] Change to master. --- .github/sync.yml | 4 ++-- .github/workflows/sync-to-flavored-repos.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/sync.yml b/.github/sync.yml index c35f4ab..cd8991d 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,4 +1,4 @@ -humhub/app@main: +humhub/app@master: - source: assets/ deleteOrphaned: true exclude: | @@ -13,7 +13,7 @@ humhub/app@main: - l10n.yaml - pubspec.lock - pubspec.yaml -humhub/app-flavored@main: +humhub/app-flavored@master: - source: assets/ deleteOrphaned: true exclude: | diff --git a/.github/workflows/sync-to-flavored-repos.yml b/.github/workflows/sync-to-flavored-repos.yml index cb103c4..2047c2c 100644 --- a/.github/workflows/sync-to-flavored-repos.yml +++ b/.github/workflows/sync-to-flavored-repos.yml @@ -3,7 +3,7 @@ name: Sync HumHub app with app-flavored on: push: branches: - - 'f-flavored' + - 'master' jobs: sync: