Skip to content

Commit

Permalink
Merge pull request #103 from humhub/95-notification-opens-the-dashboa…
Browse files Browse the repository at this point in the history
…rd-instead-of-the-related-content

Push redirect to correct page
  • Loading branch information
luke- committed Aug 14, 2023
2 parents 916825f + e6d86e7 commit 8daa5f5
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 74 deletions.
25 changes: 15 additions & 10 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:humhub/util/log.dart';
import 'package:humhub/util/notifications/plugin.dart';
import 'package:humhub/util/push/push_plugin.dart';
import 'package:humhub/util/router.dart';
import 'package:loggy/loggy.dart';

Expand All @@ -19,23 +21,26 @@ class MyApp extends ConsumerStatefulWidget {
MyAppState createState() => MyAppState();
}

class MyAppState extends ConsumerState<MyApp>{

class MyAppState extends ConsumerState<MyApp> {
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: MyRouter.getInitialRoute(ref),
builder: (context, snap) {
if (snap.hasData) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: snap.data,
routes: MyRouter.routes,
navigatorKey: navigatorKey,
theme: ThemeData(
fontFamily: 'OpenSans',
),
);
debugShowCheckedModeBanner: false,
initialRoute: snap.data,
routes: MyRouter.routes,
navigatorKey: navigatorKey,
theme: ThemeData(
fontFamily: 'OpenSans',
),
builder: (context, child) {
return NotificationPlugin(
child: PushPlugin(child: child!),
);
});
}
return const SizedBox.shrink();
},
Expand Down
6 changes: 6 additions & 0 deletions lib/models/hum_hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,10 @@ class HumHub {
return List.generate(
length, (_) => characters[random.nextInt(characters.length)]).join();
}

Map<String, String> get customHeaders =>{
'x-humhub-app-token': randomHash!,
'x-humhub-app': appVersion ?? '1.0.0',
'x-humhub-app-ostate': isHideOpener ? '1' : '0'
};
}
72 changes: 35 additions & 37 deletions lib/pages/web_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,25 @@ import 'package:humhub/models/channel_message.dart';
import 'package:humhub/models/manifest.dart';
import 'package:humhub/pages/opener.dart';
import 'package:humhub/util/extensions.dart';
import 'package:humhub/util/notifications/plugin.dart';
import 'package:humhub/util/push/push_plugin.dart';
import 'package:humhub/util/providers.dart';
import 'package:humhub/util/push_opener_controller.dart';
import 'package:loggy/loggy.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:humhub/util/router.dart' as m;

import '../components/auth_in_app_browser.dart';
import '../models/hum_hub.dart';
import '../util/connectivity_plugin.dart';

class WebViewGlobalController {
static InAppWebViewController? _value;

static InAppWebViewController? get value => _value;

static void setValue(InAppWebViewController newValue) {
_value = newValue;
}
}

class WebViewApp extends ConsumerStatefulWidget {
const WebViewApp({super.key});
static const String path = '/web_view';
Expand All @@ -46,7 +54,7 @@ class WebViewAppState extends ConsumerState<WebViewApp> {

PullToRefreshController? _pullToRefreshController;
late PullToRefreshOptions _pullToRefreshOptions;
late HeadlessInAppWebView? headlessWebView;
HeadlessInAppWebView? headlessWebView;

@override
void initState() {
Expand All @@ -67,36 +75,23 @@ class WebViewAppState extends ConsumerState<WebViewApp> {
onWillPop: () => webViewController.exitApp(context, ref),
child: Scaffold(
backgroundColor: HexColor(manifest.themeColor),
body: NotificationPlugin(
child: PushPlugin(
child: SafeArea(
bottom: false,
child: InAppWebView(
initialUrlRequest: _initialRequest,
initialOptions: _options,
pullToRefreshController: _pullToRefreshController,
shouldOverrideUrlLoading: _shouldOverrideUrlLoading,
onWebViewCreated: _onWebViewCreated,
shouldInterceptFetchRequest: _shouldInterceptFetchRequest,
onLoadStop: _onLoadStop,
onLoadStart: (controller, uri) async {
_setAjaxHeadersJQuery(controller);
},
onProgressChanged: _onProgressChanged,
onConsoleMessage: (controller, msg) {
// Handle the web resource error here
log('Console Message: $msg');
},
onLoadHttpError: (InAppWebViewController controller, Uri? url, int statusCode, String description) {
// Handle the web resource error here
log('Http Error: $description');
},
onLoadError: (InAppWebViewController controller, Uri? url, int code, String message) {
if (code == -1009) NoConnectionDialog.show(context);
log('Load Error: $message');
},
),
),
body: SafeArea(
bottom: false,
child: InAppWebView(
initialUrlRequest: _initialRequest,
initialOptions: _options,
pullToRefreshController: _pullToRefreshController,
shouldOverrideUrlLoading: _shouldOverrideUrlLoading,
onWebViewCreated: _onWebViewCreated,
shouldInterceptFetchRequest: _shouldInterceptFetchRequest,
onLoadStop: _onLoadStop,
onLoadStart: (controller, uri) async {
_setAjaxHeadersJQuery(controller);
},
onProgressChanged: _onProgressChanged,
onLoadError: (InAppWebViewController controller, Uri? url, int code, String message) {
if (code == -1009) NoConnectionDialog.show(context);
},
),
),
),
Expand Down Expand Up @@ -173,6 +168,7 @@ class WebViewAppState extends ConsumerState<WebViewApp> {
),
);
webViewController = controller;
WebViewGlobalController.setValue(controller);
}

Future<FetchRequest?> _shouldInterceptFetchRequest(InAppWebViewController controller, FetchRequest request) async {
Expand All @@ -186,9 +182,11 @@ class WebViewAppState extends ConsumerState<WebViewApp> {
if (args is Manifest) {
manifest = args;
}
if (args is String) {
manifest = m.MyRouter.initParams;
url = args;
if (args is PushOpenerController) {
PushOpenerController controller = args;
ref.read(humHubProvider).setInstance(controller.humhub);
manifest = controller.humhub.manifest!;
url = controller.url;
}
if (args == null) {
manifest = m.MyRouter.initParams;
Expand Down
32 changes: 24 additions & 8 deletions lib/util/api_provider.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:humhub/models/manifest.dart';

class APIProvider {
final WidgetRef _ref;

APIProvider(this._ref);

static Map<String, String> get jsonContent => {
'content-type': 'application/json',
'accept': 'application/json',
};
'content-type': 'application/json',
'accept': 'application/json',
};

static APIProvider of(WidgetRef ref) => APIProvider(ref);

Future<AsyncValue<T>> request<T>(
Future<T> Function(Dio dio) fetcher, {
Dio? dio,
}) async {
Future<T> Function(Dio dio) fetcher, {
Dio? dio,
}) async {
dio = dio ?? _ref.read(dioProvider);
try {
final value = await fetcher(dio!);
Expand All @@ -32,4 +33,19 @@ class APIProvider {
));
return api;
});
}

static Future<AsyncValue<Manifest>> requestBasic(
Future Function(Dio dio) fetcher, {
Dio? dio,
}) async {
dio = Dio(BaseOptions(
headers: APIProvider.jsonContent,
));
try {
final value = await fetcher(dio);
return AsyncValue.data(value);
} catch (err, stackTrace) {
return AsyncValue.error(err, stackTrace);
}
}
}
24 changes: 16 additions & 8 deletions lib/util/notifications/channel.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:humhub/pages/web_view.dart';
import 'package:humhub/util/push_opener_controller.dart';
import 'package:humhub/util/router.dart';
import 'package:loggy/loggy.dart';

Expand Down Expand Up @@ -69,11 +71,13 @@ class GeneralNotificationChannel extends NotificationChannel {
class RedirectNotificationChannel extends NotificationChannel {
RedirectNotificationChannel()
: super(
'general',
'General app notifications',
'These notifications don\'t belong to any other category.',
);
'general',
'General app notifications',
'These notifications don\'t belong to any other category.',
);

/// 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<void> onTap(String? payload) async {
if (payload != null && navigatorKey.currentState != null) {
Expand All @@ -84,10 +88,14 @@ class RedirectNotificationChannel extends NotificationChannel {
}
return true;
});
if (!isNewRouteSameAsCurrent) {
navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: payload);
PushOpenerController opener = PushOpenerController(url: payload);
await opener.initHumHub();
if (isNewRouteSameAsCurrent) {
WebViewGlobalController.value!
.loadUrl(urlRequest: URLRequest(url: Uri.parse(opener.url), headers: opener.humhub.customHeaders));
return;
}
navigatorKey.currentState!.popAndPushNamed(WebViewApp.path, arguments: payload);
navigatorKey.currentState!.pushNamed(WebViewApp.path, arguments: opener);
}
}
}
9 changes: 3 additions & 6 deletions lib/util/providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,16 @@ class HumHubNotifier extends ChangeNotifier {
String? get randomHash => _humHubInstance.randomHash;
String? get appVersion => _humHubInstance.appVersion;
String? get pushToken => _humHubInstance.pushToken;

Map<String, String> get customHeaders =>{
'x-humhub-app-token': randomHash!,
'x-humhub-app': appVersion!,
'x-humhub-app-ostate': isHideDialog ? '1' : '0'
};
Map<String, String> get customHeaders => _humHubInstance.customHeaders;

void setIsHideOpener(bool isHide) {
_humHubInstance.isHideOpener = isHide;
_updateSafeStorage();
notifyListeners();
}



void setManifest(Manifest manifest) {
_humHubInstance.manifest = manifest;
_updateSafeStorage();
Expand Down
71 changes: 71 additions & 0 deletions lib/util/push_opener_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
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';

class PushOpenerController {
late AsyncValue<Manifest>? asyncData;
bool doesViewExist = false;
final String url;
late HumHub humhub;

PushOpenerController({required this.url});

findManifest(String url) async {
Uri uri = assumeUrl(url);
for (var i = uri.pathSegments.length - 1; i >= 0; i--) {
String urlIn = "${uri.origin}/${uri.pathSegments.getRange(0, i).join('/')}";
asyncData = await APIProvider.requestBasic(Manifest.get(i != 0 ? urlIn : uri.origin));
if (!asyncData!.hasError) break;
}
if (uri.pathSegments.isEmpty) {
asyncData = await APIProvider.requestBasic(Manifest.get(uri.origin));
}
await checkHumHubModuleView(uri);
}

checkHumHubModuleView(Uri uri) async {
Response? response;
response = await http.Client().get(Uri.parse(uri.origin)).catchError((err) {
return Response("Found manifest but not humhub.modules.ui.view tag", 404);
});

doesViewExist = response.statusCode == 200 && response.body.contains('humhub.modules.ui.view');
}

Future<HumHub?> initHumHub() async {
var hasConnection = await ConnectivityPlugin.hasConnectivity;
if (!hasConnection) {
asyncData = null;
return null;
}
await findManifest(url);
if (asyncData!.hasError || !doesViewExist) {
asyncData = null;
return null;
} else {
Manifest manifest = asyncData!.value!;
String hash = HumHub.generateHash(32);
HumHub instance = HumHub(manifest: manifest, randomHash: hash);
humhub = instance;
return instance;
}
}

bool get allOk => !(asyncData == null || asyncData!.hasError || !doesViewExist);

Uri assumeUrl(String url) {
if (url.startsWith("https://") || url.startsWith("http://")) return Uri.parse(url);
return Uri.parse("https://$url");
}

String? validateUrl(String? value) {
if (value == null || value.isEmpty) {
return 'Specify you HumHub location';
}
return null;
}
}
10 changes: 5 additions & 5 deletions lib/util/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ List<Map> _pendingRoutes = [];
/// Queue any route, this route is pushed on stack after app has initialized.
/// This usually means after user is logged in and assets are downloaded
void queueRoute(
String routeName, {
Object? arguments,
}) {
String routeName, {
Object? arguments,
}) {
_pendingRoutes.add({
'route': routeName,
'arguments': arguments,
});
}

class MyRouter{
class MyRouter {
static String? initRoute;
static dynamic initParams;

Expand All @@ -47,4 +47,4 @@ class MyRouter{
return WebViewApp.path;
}
}
}
}

0 comments on commit 8daa5f5

Please sign in to comment.