diff --git a/.github/workflows/google_release.yml b/.github/workflows/google_release.yml index 1223f3a..3b4a5d8 100644 --- a/.github/workflows/google_release.yml +++ b/.github/workflows/google_release.yml @@ -31,6 +31,10 @@ jobs: flutter-version: '3.27.2' # Specify your Flutter version channel: 'stable' + - name: Create .env file + run: | + echo "${{ secrets.ENV_FILE }}" > .env + - name: Install dependencies run: flutter pub get diff --git a/lib/features/auth/screens/splash_screen.dart b/lib/features/auth/screens/splash_screen.dart index 219d56a..e67a901 100644 --- a/lib/features/auth/screens/splash_screen.dart +++ b/lib/features/auth/screens/splash_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:in_app_update/in_app_update.dart'; import 'package:pulse/features/websites/screens/websites_screen.dart'; import 'package:pulse/utils/local_storage.dart'; import 'package:pulse/utils/navigation.dart'; @@ -18,7 +19,10 @@ class _SplashScreenState extends State { @override void initState() { Future.delayed(Duration(seconds: 2)).then((_) async { + checkForUpdate(); + String? token = prefs.getString(LocalStorage.jwt); + Navigation.go( screen: token != null ? WebsitesScreen() : SignInScreen(), context: context, @@ -28,6 +32,18 @@ class _SplashScreenState extends State { super.initState(); } + Future checkForUpdate() async { + InAppUpdate.checkForUpdate().then((info) { + if (info.updateAvailability == UpdateAvailability.updateAvailable) { + Toast.showToast( + message: 'New App Update Available! 🎉', context: context); + } + }).catchError((e) { + logger.e(e); + Toast.showToast(message: e.toString(), context: context); + }); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/features/sessions/cubit/sessions_cubit.dart b/lib/features/sessions/cubit/sessions_cubit.dart index 777534f..fb8c635 100644 --- a/lib/features/sessions/cubit/sessions_cubit.dart +++ b/lib/features/sessions/cubit/sessions_cubit.dart @@ -39,8 +39,8 @@ class SessionsCubit extends Cubit { Future getSessionEvents({ required String websiteId, required String id, - DateTime? start, - DateTime? end, + required DateTime start, + required DateTime end, }) async { emit(state.copyWith(appState: AppState.loading, events: [])); try { diff --git a/lib/features/sessions/repo/sessions_repo.dart b/lib/features/sessions/repo/sessions_repo.dart index 8cabf65..c4d9467 100644 --- a/lib/features/sessions/repo/sessions_repo.dart +++ b/lib/features/sessions/repo/sessions_repo.dart @@ -35,18 +35,15 @@ class SessionsRepo { Future> getSessionEvents({ required String websiteId, required String id, - DateTime? start, - DateTime? end, + required DateTime start, + required DateTime end, }) async { - var now = DateTime.now(); - int startAt = (start ?? now.subtract(const Duration(hours: 24))) - .millisecondsSinceEpoch; - int endAt = (end ?? now).millisecondsSinceEpoch; + int startAt = (start).millisecondsSinceEpoch; + int endAt = (end).millisecondsSinceEpoch; var res = await Requests.get( useKey: true, endpoint: '${Endpoints.websites.replaceAll(Endpoints.baseUrl, 'https://api.umami.is/v1')}/$websiteId/sessions/$id/activity?startAt=$startAt&endAt=$endAt'); - logger.i(res); return Event.toList(res); } } diff --git a/lib/features/sessions/screens/session_details_screen.dart b/lib/features/sessions/screens/session_details_screen.dart index fb33cc5..5b30169 100644 --- a/lib/features/sessions/screens/session_details_screen.dart +++ b/lib/features/sessions/screens/session_details_screen.dart @@ -31,13 +31,20 @@ class SessionDetailsScreen extends StatefulWidget { class _SessionDetailsScreenState extends State { Session? _session; - DateTimeRange? range; + + late DateTimeRange range; @override void initState() { + range = DateTimeRange( + start: widget.session.lastAt.subtract(const Duration(days: 5)), + end: widget.session.lastAt, + ); context.read().getSessionEvents( websiteId: widget.session.websiteId, id: widget.session.id, + end: range.end, + start: range.start, ); Future.delayed(Duration.zero).then((_) async { try { @@ -196,10 +203,7 @@ class _SessionDetailsScreenState extends State { DropDownBtn( click: () async { DateTimeRange? picked = await showDateRangePicker( - initialDateRange: range ?? - DateTimeRange( - start: DateTime.now().subtract(Duration(days: 3)), - end: DateTime.now()), + initialDateRange: range, context: context, firstDate: DateTime(2000), lastDate: DateTime.now(), @@ -210,14 +214,13 @@ class _SessionDetailsScreenState extends State { context.read().getSessionEvents( websiteId: widget.session.websiteId, id: widget.session.id, - end: range?.end, - start: range?.start, + end: range.end, + start: range.start, ); }, icon: Iconsax.timer_1_bold, - title: range == null - ? 'Last 24 hours' - : 'From ${DateFormat('EEE, MMM dd, yyyy').format(range!.start)} - ${DateFormat('EEE, MMM dd, yyyy').format(range!.end)}', + title: + 'From ${DateFormat('EEE, MMM dd, yyyy').format(range.start)} - ${DateFormat('EEE, MMM dd, yyyy').format(range.end)}', ), BlocConsumer( listener: (context, state) { @@ -271,12 +274,14 @@ class _SessionDetailsScreenState extends State { style: kBodyTitleTextStyle.copyWith(fontWeight: FontWeight.bold)), Row( spacing: 5, - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ if (icon != null) icon, - Text( - des, - style: kBodyTextStyle, + Expanded( + child: Text( + des, + style: kBodyTextStyle, + ), ), ], ), diff --git a/lib/features/settings/screens/settings_screen.dart b/lib/features/settings/screens/settings_screen.dart index 393c739..34bd027 100644 --- a/lib/features/settings/screens/settings_screen.dart +++ b/lib/features/settings/screens/settings_screen.dart @@ -93,10 +93,21 @@ class _SettingsScreenState extends State { //setting Btn( title: 'App version', - des: '${packageInfo?.version} (#${packageInfo?.buildNumber})', + des: _updateInfo?.updateAvailability == + UpdateAvailability.updateAvailable + ? 'Click to update the app 🚀' + : '${packageInfo?.version} (#${packageInfo?.buildNumber})', type: 'setting', icon: Icons.info_rounded, - click: () {}, + click: () async { + if (_updateInfo?.updateAvailability == + UpdateAvailability.updateAvailable) { + await InAppUpdate.performImmediateUpdate(); + } else { + Toast.showToast( + message: 'You are using the latest version!', context: context); + } + }, ), Btn( diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 1cb3bec..1df583a 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:in_app_update/in_app_update.dart'; import 'package:logger/logger.dart'; import 'package:pulse/utils/text.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -34,6 +35,13 @@ class Toast { } ScaffoldMessenger.of(context).showSnackBar( SnackBar( + action: message.contains('App Update') + ? SnackBarAction( + label: 'Update!', + onPressed: () async { + await InAppUpdate.performImmediateUpdate(); + }) + : null, behavior: SnackBarBehavior.floating, content: Text( errMessage.trim(), diff --git a/pubspec.yaml b/pubspec.yaml index a405f1a..c7cac43 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: "A new Flutter project." # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: "none" # Remove this line if you wish to publish to pub.dev -version: 1.0.3+4 +version: 1.0.4+5 environment: sdk: ^3.6.1