Skip to content

Commit

Permalink
Setup push notifications only when device is online
Browse files Browse the repository at this point in the history
  • Loading branch information
veloce committed Aug 3, 2024
1 parent 7249bfc commit 5a54921
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 35 deletions.
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Future<void> _startFlutterApp() async {
observers: [
ProviderLogger(),
],
child: const LoadingAppScreen(),
child: const AppInitializationScreen(),
),
);
}
Expand Down
38 changes: 34 additions & 4 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ import 'package:lichess_mobile/src/utils/screen.dart';
import 'package:lichess_mobile/src/utils/system.dart';
import 'package:lichess_mobile/src/view/game/game_screen.dart';

class LoadingAppScreen extends ConsumerWidget {
const LoadingAppScreen({super.key});
/// Application initialization and main entry point.
class AppInitializationScreen extends ConsumerWidget {
const AppInitializationScreen({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
Expand Down Expand Up @@ -85,6 +86,10 @@ class LoadingAppScreen extends ConsumerWidget {
}
}

/// The main application widget.
///
/// This widget is the root of the application and is responsible for setting up
/// the theme, locale, and other global settings.
class Application extends ConsumerStatefulWidget {
const Application({super.key});

Expand Down Expand Up @@ -265,6 +270,15 @@ class _AppState extends ConsumerState<Application> {
}
}

/// The entry point widget for the application.
///
/// This widget needs to be a desendant of [MaterialApp] to be able to handle
/// the [Navigator] properly.
///
/// This widget is responsible for setting up the bottom navigation scaffold and
/// the main navigation routes.
///
/// It also sets up the push notifications and handles incoming messages.
class _EntryPointWidget extends ConsumerStatefulWidget {
const _EntryPointWidget();

Expand All @@ -274,6 +288,10 @@ class _EntryPointWidget extends ConsumerStatefulWidget {

class _EntryPointState extends ConsumerState<_EntryPointWidget> {
StreamSubscription<String>? _fcmTokenRefreshSubscription;
ProviderSubscription<AsyncValue<ConnectivityStatus>>?
_connectivitySubscription;

bool _pushNotificationsSetup = false;

@override
Widget build(BuildContext context) {
Expand All @@ -284,12 +302,24 @@ class _EntryPointState extends ConsumerState<_EntryPointWidget> {
void initState() {
super.initState();

_setupPushNotifications();
_connectivitySubscription =
ref.listenManual(connectivityChangesProvider, (prev, current) async {
// setup push notifications once when the app comes online
if (current.value?.isOnline == true && !_pushNotificationsSetup) {
try {
await _setupPushNotifications();
_pushNotificationsSetup = true;
} catch (e, st) {
debugPrint('Could not sync correspondence games; $e\n$st');
}
}
});
}

@override
void dispose() {
_fcmTokenRefreshSubscription?.cancel();
_connectivitySubscription?.close();
super.dispose();
}

Expand Down Expand Up @@ -321,7 +351,7 @@ class _EntryPointState extends ConsumerState<_EntryPointWidget> {
});

// Register the device with the server.
ref.read(notificationServiceProvider).registerDevice();
await ref.read(notificationServiceProvider).registerDevice();

// Get any messages which caused the application to open from
// a terminated state.
Expand Down
2 changes: 2 additions & 0 deletions lib/src/model/common/http.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Uri lichessUri(String unencodedPath, [Map<String, dynamic>? queryParameters]) =>
: Uri.https(kLichessHost, unencodedPath, queryParameters);

/// Creates the appropriate http client for the platform.
///
/// Do not use directly, use [defaultClient] or [lichessClient] instead.
Client httpClientFactory() {
const userAgent = 'Lichess Mobile';
if (Platform.isAndroid) {
Expand Down
52 changes: 22 additions & 30 deletions lib/src/utils/connectivity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ConnectivityChanges extends _$ConnectivityChanges {

final _connectivityChangesDebouncer = Debouncer(const Duration(seconds: 5));

Client get _defaultClient => ref.read(defaultClientProvider);

@override
Future<ConnectivityStatus> build() {
ref.onDispose(() {
Expand Down Expand Up @@ -74,42 +76,31 @@ class ConnectivityChanges extends _$ConnectivityChanges {

final wasOnline = state.requireValue.isOnline;

final client = httpClientFactory();
try {
_logger.fine('Connectivity changed: $result');
final isOnline = await _onlineCheck(client);
_logger.fine('Online check result: $isOnline');

if (isOnline != wasOnline) {
_logger.info('Connectivity status: $result, isOnline: $isOnline');
state = AsyncValue.data(
ConnectivityStatus(
isOnline: isOnline,
appState: state.valueOrNull?.appState,
),
);
}
} finally {
client.close();
_logger.fine('Connectivity changed: $result');
final newIsOnline = await isOnline(_defaultClient);
_logger.fine('Online check result: $isOnline');

if (newIsOnline != wasOnline) {
_logger.info('Connectivity status: $result, isOnline: $isOnline');
state = AsyncValue.data(
ConnectivityStatus(
isOnline: newIsOnline,
appState: state.valueOrNull?.appState,
),
);
}
}

Future<ConnectivityStatus> _getConnectivityStatus(
List<ConnectivityResult> result,
AppLifecycleState? appState,
) async {
final client = httpClientFactory();
try {
final status = ConnectivityStatus(
isOnline: await _onlineCheck(client),
appState: appState,
);
_logger
.info('Connectivity status: $result, isOnline: ${status.isOnline}');
return status;
} finally {
client.close();
}
final status = ConnectivityStatus(
isOnline: await isOnline(_defaultClient),
appState: appState,
);
_logger.info('Connectivity status: $result, isOnline: ${status.isOnline}');
return status;
}
}

Expand All @@ -126,7 +117,8 @@ final _internetCheckUris = [
Uri.parse('$kLichessCDNHost/assets/logo/lichess-favicon-32.png'),
];

Future<bool> _onlineCheck(Client client) {
/// Checks if the device is online by making a HEAD request to a list of URIs.
Future<bool> isOnline(Client client) {
final completer = Completer<bool>();
try {
int remaining = _internetCheckUris.length;
Expand Down

0 comments on commit 5a54921

Please sign in to comment.