Skip to content

Commit

Permalink
feat: connect ui
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-hector committed Dec 23, 2024
1 parent 906a984 commit 519632a
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 36 deletions.
30 changes: 30 additions & 0 deletions lib/app/components/app_update_handler/app_update_handler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/app_update_handler/hooks/use_app_update.dart';
import 'package:ion/app/features/core/model/app_update_type.dart';
import 'package:ion/app/features/core/views/pages/app_update_modal.dart';
import 'package:ion/app/router/app_routes.c.dart';
import 'package:ion/app/router/utils/show_simple_bottom_sheet.dart';

class AppUpdateHandler extends HookConsumerWidget {
const AppUpdateHandler({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final isModalShown = useAppUpdate(ref);

if (!isModalShown) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showSimpleBottomSheet<void>(
isDismissible: false,
context: rootNavigatorKey.currentContext!,
child: const AppUpdateModal(
appUpdateType: AppUpdateType.updateRequired,
),
);
});
}

return const SizedBox.shrink();
}
}
22 changes: 22 additions & 0 deletions lib/app/components/app_update_handler/hooks/use_app_update.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/features/config/providers/force_update_provider.c.dart';

bool useAppUpdate(WidgetRef ref) {
final isModalShown = useState(false);

final forceUpdateState = ref.watch(forceUpdateProvider);

useEffect(
() {
if (forceUpdateState.showUpdateModal && !isModalShown.value) {
isModalShown.value = true;
}

return null;
},
[forceUpdateState],
);

return isModalShown.value;
}
4 changes: 4 additions & 0 deletions lib/app/exceptions/exceptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,7 @@ class ForceUpdateCouldntLaunchUrlException extends IONException {
ForceUpdateCouldntLaunchUrlException({required String url})
: super(10042, 'Could not launch $url');
}

class ForceUpdateFetchConfigException extends IONException {
ForceUpdateFetchConfigException() : super(10043, 'Failed to get version config');
}
17 changes: 12 additions & 5 deletions lib/app/features/config/providers/config_provider.c.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,21 @@ class ConfigNotifier extends _$ConfigNotifier {
}
}

Future<Map<String, dynamic>> fetchConfigForCurrentPlatform() async {
Future<String> fetchConfigForCurrentPlatform() async {
final configName = _getPlatformConfigName();
final path = '${EnvVariable.ION_ORIGIN}/v1/config/$configName';

final dio = ref.read(dioProvider);
final response = await dio.get<Map<String, dynamic>>(path);
const baseUrl = EnvVariable.ION_ORIGIN;
final path = '$baseUrl/v1/config/$configName';

return response.data!;
try {
final response = await ref.read(dioProvider).get<String>(path);
if (response.data == null) {
throw ForceUpdateFetchConfigException();
}
return response.data!;
} catch (e) {
throw ForceUpdateFetchConfigException();
}
}
}

Expand Down
37 changes: 35 additions & 2 deletions lib/app/features/config/providers/force_update_provider.c.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,33 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:ion/app/features/config/providers/config_provider.c.dart';
import 'package:ion/app/features/config/providers/force_update_last_sync_date_provider.c.dart';
import 'package:ion/app/features/core/providers/app_lifecycle_provider.c.dart';
import 'package:ion/app/services/logger/logger.dart';
import 'package:ion/app/utils/force_update.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'force_update_provider.c.freezed.dart';
part 'force_update_provider.c.g.dart';

@freezed
class ForceUpdateState with _$ForceUpdateState {
const factory ForceUpdateState({
@Default(false) bool showUpdateModal,
}) = _ForceUpdateState;

const ForceUpdateState._();
}

@Riverpod(keepAlive: true)
class ForceUpdate extends _$ForceUpdate {
static const int eightHoursInMilliseconds = 8 * 60 * 60 * 1000;

@override
FutureOr<void> build() {
ForceUpdateState build() {
ref.listen<AppLifecycleState>(
appLifecycleProvider,
(previous, next) {
Expand All @@ -24,15 +38,34 @@ class ForceUpdate extends _$ForceUpdate {
}
},
);

return const ForceUpdateState();
}

Future<void> _checkAndUpdateConfig() async {
final lastSyncDate = ref.read(forceUpdateLastSyncDateNotifierProvider);

Logger.log('lastSyncDate: $lastSyncDate');

if (lastSyncDate == null ||
DateTime.now().difference(lastSyncDate).inMilliseconds >= eightHoursInMilliseconds) {
await ref.read(configNotifierProvider.notifier).fetchConfigForCurrentPlatform();
final remoteVersion =
await ref.read(configNotifierProvider.notifier).fetchConfigForCurrentPlatform();

final packageInfo = await PackageInfo.fromPlatform();
final localVersion = packageInfo.version;

if (ForceUpdateUtil.isVersionOutdated(localVersion, remoteVersion)) {
state = state.copyWith(showUpdateModal: true);
} else {
state = state.copyWith(showUpdateModal: false);
}

ref.read(forceUpdateLastSyncDateNotifierProvider.notifier).updateLastSyncDate(DateTime.now());
}
}

void resetUpdateModal() {
state = state.copyWith(showUpdateModal: false);
}
}
10 changes: 2 additions & 8 deletions lib/app/features/core/views/pages/app_update_modal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:ion/app/components/screen_offset/screen_bottom_offset.dart';
import 'package:ion/app/components/screen_offset/screen_side_offset.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/core/model/app_update_type.dart';
import 'package:ion/app/router/utils/show_simple_bottom_sheet.dart';
import 'package:ion/app/utils/force_update.dart';

class AppUpdateModal extends StatelessWidget {
const AppUpdateModal({
Expand Down Expand Up @@ -37,14 +37,8 @@ class AppUpdateModal extends StatelessWidget {
color: context.theme.appColors.onPrimaryAccent,
),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
if (appUpdateType == AppUpdateType.updateRequired) {
showSimpleBottomSheet<void>(
context: context,
child: const AppUpdateModal(
appUpdateType: AppUpdateType.upToDate,
),
);
ForceUpdateUtil.handleForceUpdateRedirect();
}
},
label: Text(appUpdateType.getActionTitle(context)),
Expand Down
21 changes: 0 additions & 21 deletions lib/app/features/feed/views/pages/feed_page/feed_page.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
// SPDX-License-Identifier: ice License 1.0

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/screen_offset/screen_top_offset.dart';
import 'package:ion/app/components/scroll_view/load_more_builder.dart';
import 'package:ion/app/components/scroll_view/pull_to_refresh_builder.dart';
import 'package:ion/app/extensions/extensions.dart';
import 'package:ion/app/features/core/model/app_update_type.dart';
import 'package:ion/app/features/core/views/pages/app_update_modal.dart';
import 'package:ion/app/features/feed/data/models/feed_category.dart';
import 'package:ion/app/features/feed/providers/feed_current_filter_provider.c.dart';
import 'package:ion/app/features/feed/providers/feed_posts_data_source_provider.c.dart';
Expand All @@ -22,10 +18,8 @@ import 'package:ion/app/features/feed/views/pages/feed_page/components/feed_post
import 'package:ion/app/features/feed/views/pages/feed_page/components/stories/stories.dart';
import 'package:ion/app/features/feed/views/pages/feed_page/components/trending_videos/trending_videos.dart';
import 'package:ion/app/features/nostr/providers/entities_paged_data_provider.c.dart';
import 'package:ion/app/hooks/use_on_init.dart';
import 'package:ion/app/hooks/use_scroll_top_on_tab_press.dart';
import 'package:ion/app/router/components/navigation_app_bar/collapsing_app_bar.dart';
import 'package:ion/app/router/utils/show_simple_bottom_sheet.dart';

class FeedPage extends HookConsumerWidget {
const FeedPage({super.key});
Expand All @@ -39,21 +33,6 @@ class FeedPage extends HookConsumerWidget {
.select((state) => (state?.hasMore).falseOrValue),
);

useOnInit(
() {
if (Random().nextInt(10) == 0) {
showSimpleBottomSheet<void>(
isDismissible: false,
context: context,
child: const AppUpdateModal(
appUpdateType: AppUpdateType.updateRequired,
),
);
}
},
<Object>[],
);

useScrollTopOnTabPress(context, scrollController: scrollController);

final slivers = [
Expand Down
2 changes: 2 additions & 0 deletions lib/app/router/components/app_router_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:ion/app/components/app_update_handler/app_update_handler.dart';
import 'package:ion/app/components/global_notification_bar/global_notification_bar.dart';
import 'package:ion/app/components/global_notification_bar/providers/global_notification_provider.c.dart';
import 'package:ion/app/extensions/extensions.dart';
Expand Down Expand Up @@ -40,6 +41,7 @@ class AppRouterBuilder extends HookConsumerWidget {
Expanded(
child: child ?? const SizedBox.shrink(),
),
const AppUpdateHandler(),
],
),
),
Expand Down
14 changes: 14 additions & 0 deletions lib/app/utils/force_update.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,18 @@ class ForceUpdateUtil {
const fallbackWebsite = 'https://example.com'; //TODO: Replace with the actual website
await _openUrl(fallbackWebsite);
}

static bool isVersionOutdated(String localVersion, String remoteVersion) {
final localParts = localVersion.split('.').map(int.parse).toList();
final remoteParts = remoteVersion.split('.').map(int.parse).toList();

for (var i = 0; i < remoteParts.length; i++) {
if (localParts.length <= i || localParts[i] < remoteParts[i]) {
return true;
} else if (localParts[i] > remoteParts[i]) {
return false;
}
}
return false;
}
}

0 comments on commit 519632a

Please sign in to comment.