Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion lib/background/background.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ String currentLanguage = 'en';

@pragma('vm:entry-point')
Future<void> serviceMain(ServiceInstance service) async {
// Create a local logger for the background isolate
final logger = Logger(
printer: PrettyPrinter(
methodCount: 2,
errorMethodCount: 8,
lineLength: 120,
colors: true,
printEmojis: true,
dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart,
),
level: Level.debug,
);

final Map<String, Map<String, dynamic>> activeSubscriptions = {};
final nostrService = NostrService();
Expand Down Expand Up @@ -72,7 +84,7 @@ Future<void> serviceMain(ServiceInstance service) async {
if (await eventStore.hasItem(event.id!)) return;
await notification_service.retryNotification(event);
} catch (e) {
Logger().e('Error processing event', error: e);
logger.e('Error processing event', error: e);
}
});
});
Expand Down
15 changes: 14 additions & 1 deletion lib/background/desktop_background_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ class DesktopBackgroundService implements BackgroundService {
Future<void> init() async {}

static void isolateEntry(List<dynamic> args) async {
// Create a local logger for the desktop background isolate
final logger = Logger(
printer: PrettyPrinter(
methodCount: 2,
errorMethodCount: 8,
lineLength: 120,
colors: true,
printEmojis: true,
dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart,
),
level: Level.debug,
);

final isolateReceivePort = ReceivePort();
final mainSendPort = args[0] as SendPort;
final token = args[1] as RootIsolateToken;
Expand All @@ -28,7 +41,7 @@ class DesktopBackgroundService implements BackgroundService {
BackgroundIsolateBinaryMessenger.ensureInitialized(token);

final nostrService = NostrService();
final logger = Logger();

bool isAppForeground = true;

isolateReceivePort.listen((message) async {
Expand Down
18 changes: 9 additions & 9 deletions lib/background/mobile_background_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dart:async';

import 'package:dart_nostr/nostr/model/request/filter.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:logger/logger.dart';
import 'package:mostro_mobile/services/logger_service.dart';
import 'package:mostro_mobile/background/background.dart';
import 'package:mostro_mobile/features/settings/settings.dart';
import 'abstract_background_service.dart';
Expand All @@ -16,7 +16,7 @@ class MobileBackgroundService implements BackgroundService {

final _subscriptions = <String, Map<String, dynamic>>{};
bool _isRunning = false;
final _logger = Logger();

bool _serviceReady = false;
final List<Function> _pendingOperations = [];

Expand Down Expand Up @@ -45,18 +45,18 @@ class MobileBackgroundService implements BackgroundService {
service.invoke('start', {
'settings': _settings.toJson(),
});
_logger.d(
logger.d(
'Service started with settings: ${_settings.toJson()}',
);
});

service.on('on-stop').listen((event) {
_isRunning = false;
_logger.i('Service stopped');
logger.i('Service stopped');
});

service.on('service-ready').listen((data) {
_logger.i("Service confirmed it's ready");
logger.i("Service confirmed it's ready");
_serviceReady = true;
_processPendingOperations();
});
Expand All @@ -68,7 +68,7 @@ class MobileBackgroundService implements BackgroundService {
_subscriptions[subId] = {'filters': filters};

_executeWhenReady(() {
_logger.i("Sending subscription to service");
logger.i("Sending subscription to service");
service.invoke('create-subscription', {
'id': subId,
'filters': filters.map((f) => f.toMap()).toList(),
Expand Down Expand Up @@ -127,7 +127,7 @@ class MobileBackgroundService implements BackgroundService {
try {
await _startService();
} catch (e) {
_logger.e('Error starting service: $e');
logger.e('Error starting service: $e');
// Retry with a delay if needed
await Future.delayed(Duration(seconds: 1));
await _startService();
Expand All @@ -137,7 +137,7 @@ class MobileBackgroundService implements BackgroundService {
}

Future<void> _startService() async {
_logger.i("Starting service");
logger.i("Starting service");
await service.startService();
_serviceReady = false; // Reset ready state when starting

Expand All @@ -152,7 +152,7 @@ class MobileBackgroundService implements BackgroundService {
await Future.delayed(const Duration(milliseconds: 50));
}

_logger.i("Service running, sending settings");
logger.i("Service running, sending settings");
service.invoke('start', {
'settings': _settings.toJson(),
});
Expand Down
14 changes: 12 additions & 2 deletions lib/core/app_routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ import 'package:mostro_mobile/features/walkthrough/screens/walkthrough_screen.da
import 'package:mostro_mobile/features/disputes/screens/dispute_chat_screen.dart';

import 'package:mostro_mobile/features/notifications/screens/notifications_screen.dart';
import 'package:mostro_mobile/features/logs/screens/logs_screen.dart';

import 'package:mostro_mobile/features/walkthrough/providers/first_run_provider.dart';
import 'package:mostro_mobile/shared/widgets/navigation_listener_widget.dart';
import 'package:mostro_mobile/shared/widgets/notification_listener_widget.dart';
import 'package:logger/logger.dart';
import 'package:mostro_mobile/services/logger_service.dart';
import 'package:mostro_mobile/generated/l10n.dart';

GoRouter createRouter(WidgetRef ref) {
Expand Down Expand Up @@ -59,7 +60,7 @@ GoRouter createRouter(WidgetRef ref) {
);
},
errorBuilder: (context, state) {
final logger = Logger();

logger.w('GoRouter error: ${state.error}');

// For errors, show a generic error page
Expand Down Expand Up @@ -284,6 +285,15 @@ GoRouter createRouter(WidgetRef ref) {
child: const NotificationsScreen(),
),
),
GoRoute(
path: '/logs',
pageBuilder: (context, state) =>
buildPageWithDefaultTransition<void>(
context: context,
state: state,
child: const LogsScreen(),
),
),
],
),
],
Expand Down
5 changes: 5 additions & 0 deletions lib/core/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ class Config {
// Notification configuration
static String notificationChannelId = 'mostro_mobile';
static int notificationId = 38383;

// Logger configuration
static const int logMaxEntries = 1000;
static const int logBatchDeleteSize = 100;
static bool fullLogsInfo = true; // false = simple logs in console, true = full Logger format in console
}
21 changes: 10 additions & 11 deletions lib/core/deep_link_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:logger/logger.dart';
import 'package:mostro_mobile/services/logger_service.dart';
import 'package:mostro_mobile/generated/l10n.dart';
import 'package:mostro_mobile/services/deep_link_service.dart';
import 'package:mostro_mobile/shared/providers/nostr_service_provider.dart';

class DeepLinkHandler {
final Ref _ref;
final Logger _logger = Logger();
StreamSubscription<Uri>? _subscription;

DeepLinkHandler(this._ref);

/// Initializes deep link handling for the app
void initialize(GoRouter router) {
_logger.i('Initializing DeepLinkHandler');
logger.i('Initializing DeepLinkHandler');

// Get the deep link service instance
final deepLinkService = _ref.read(deepLinkServiceProvider);
Expand All @@ -27,7 +26,7 @@ class DeepLinkHandler {
// Listen for deep link events
_subscription = deepLinkService.deepLinkStream.listen(
(Uri uri) => _handleDeepLink(uri, router),
onError: (error) => _logger.e('Deep link stream error: $error'),
onError: (error) => logger.e('Deep link stream error: $error'),
);
}

Expand All @@ -42,20 +41,20 @@ class DeepLinkHandler {
GoRouter router,
) async {
try {
_logger.i('Handling deep link: $uri');
logger.i('Handling deep link: $uri');

// Check if it's a mostro: scheme
if (uri.scheme == 'mostro') {
await _handleMostroDeepLink(uri.toString(), router);
} else {
_logger.w('Unsupported deep link scheme: ${uri.scheme}');
logger.w('Unsupported deep link scheme: ${uri.scheme}');
final context = router.routerDelegate.navigatorKey.currentContext;
if (context != null && context.mounted) {
_showErrorSnackBar(context, S.of(context)!.unsupportedLinkFormat);
}
}
} catch (e) {
_logger.e('Error handling deep link: $e');
logger.e('Error handling deep link: $e');
final context = router.routerDelegate.navigatorKey.currentContext;
if (context != null && context.mounted) {
_showErrorSnackBar(context, S.of(context)!.failedToOpenLink);
Expand Down Expand Up @@ -83,7 +82,7 @@ class DeepLinkHandler {
// Ensure we have a valid context for processing
final processingContext = context ?? router.routerDelegate.navigatorKey.currentContext;
if (processingContext == null || !processingContext.mounted) {
_logger.e('No valid context available for deep link processing');
logger.e('No valid context available for deep link processing');
return;
}

Expand All @@ -103,17 +102,17 @@ class DeepLinkHandler {
WidgetsBinding.instance.addPostFrameCallback((_) {
deepLinkService.navigateToOrder(router, result.orderInfo!);
});
_logger.i('Successfully navigated to order: ${result.orderInfo!.orderId} (${result.orderInfo!.orderType.value})');
logger.i('Successfully navigated to order: ${result.orderInfo!.orderId} (${result.orderInfo!.orderType.value})');
} else {
final errorContext = router.routerDelegate.navigatorKey.currentContext;
if (errorContext != null && errorContext.mounted) {
final errorMessage = result.error ?? S.of(errorContext)!.failedToLoadOrder;
_showErrorSnackBar(errorContext, errorMessage);
}
_logger.w('Failed to process mostro link: ${result.error}');
logger.w('Failed to process mostro link: ${result.error}');
}
} catch (e) {
_logger.e('Error processing mostro deep link: $e');
logger.e('Error processing mostro deep link: $e');
final errorContext = router.routerDelegate.navigatorKey.currentContext;
if (errorContext != null && errorContext.mounted) {
Navigator.of(errorContext).pop(); // Hide loading if still showing
Expand Down
21 changes: 10 additions & 11 deletions lib/core/deep_link_interceptor.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:logger/logger.dart';
import 'package:mostro_mobile/services/logger_service.dart';

/// A deep link interceptor that prevents custom schemes from reaching GoRouter
/// This prevents assertion failures when the system tries to parse mostro: URLs
class DeepLinkInterceptor extends WidgetsBindingObserver {
final Logger _logger = Logger();
final StreamController<String> _customUrlController =
final StreamController<String> _customUrlController =
StreamController<String>.broadcast();

/// Stream for custom URLs that were intercepted
Expand All @@ -15,17 +14,17 @@ class DeepLinkInterceptor extends WidgetsBindingObserver {
/// Initialize the interceptor
void initialize() {
WidgetsBinding.instance.addObserver(this);
_logger.i('DeepLinkInterceptor initialized');
logger.i('DeepLinkInterceptor initialized');
}

@override
Future<bool> didPushRouteInformation(RouteInformation routeInformation) async {
final uri = routeInformation.uri;
_logger.i('DeepLinkInterceptor: Route information received: $uri');
logger.i('DeepLinkInterceptor: Route information received: $uri');

// Check if this is a custom scheme URL
if (_isCustomScheme(uri)) {
_logger.i('DeepLinkInterceptor: Custom scheme detected: ${uri.scheme}, intercepting and preventing GoRouter processing');
logger.i('DeepLinkInterceptor: Custom scheme detected: ${uri.scheme}, intercepting and preventing GoRouter processing');

// Emit the custom URL for processing
_customUrlController.add(uri.toString());
Expand All @@ -35,7 +34,7 @@ class DeepLinkInterceptor extends WidgetsBindingObserver {
return true;
}

_logger.i('DeepLinkInterceptor: Allowing normal URL to pass through: $uri');
logger.i('DeepLinkInterceptor: Allowing normal URL to pass through: $uri');
// Let normal URLs pass through to GoRouter
return super.didPushRouteInformation(routeInformation);
}
Expand All @@ -45,17 +44,17 @@ class DeepLinkInterceptor extends WidgetsBindingObserver {
@override
// ignore: deprecated_member_use
Future<bool> didPushRoute(String route) async {
_logger.i('DeepLinkInterceptor: didPushRoute called with: $route');
logger.i('DeepLinkInterceptor: didPushRoute called with: $route');

try {
final uri = Uri.parse(route);
if (_isCustomScheme(uri)) {
_logger.i('DeepLinkInterceptor: Custom scheme detected in didPushRoute: ${uri.scheme}, intercepting');
logger.i('DeepLinkInterceptor: Custom scheme detected in didPushRoute: ${uri.scheme}, intercepting');
_customUrlController.add(route);
return true;
}
} catch (e) {
_logger.w('DeepLinkInterceptor: Error parsing route in didPushRoute: $e');
logger.w('DeepLinkInterceptor: Error parsing route in didPushRoute: $e');
}

// ignore: deprecated_member_use
Expand All @@ -72,6 +71,6 @@ class DeepLinkInterceptor extends WidgetsBindingObserver {
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_customUrlController.close();
_logger.i('DeepLinkInterceptor disposed');
logger.i('DeepLinkInterceptor disposed');
}
}
Loading