Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: hot restart on prod #26

Merged
merged 3 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all 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: 0 additions & 14 deletions .github/workflows/conferenceapp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,6 @@ env:
ENV_BASE64: ${{ secrets.ENV_BASE64 }}

jobs:
validate-inputs:
runs-on: ubuntu-latest
steps:
- name: Validate Inputs
run: |
if [[ -z "${{ github.event.inputs['build-version'] }}" ]]; then
echo "Error: build-version is required for a release."
exit 1
fi
if [[ -z "${{ github.event.inputs['build-number'] }}" ]]; then
echo "Error: build-number is required for a release."
exit 1
fi

check-formatting:
if: github.event_name == 'pull_request'
uses: ./.github/workflows/shared-workflow.yaml
Expand Down
6 changes: 6 additions & 0 deletions packages/conferenceapp/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ PODS:
- Flutter
- FlutterMacOS
- PromisesObjC (2.4.0)
- restart_app (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
Expand All @@ -92,6 +94,7 @@ DEPENDENCIES:
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- restart_app (from `.symlinks/plugins/restart_app/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
Expand Down Expand Up @@ -129,6 +132,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
restart_app:
:path: ".symlinks/plugins/restart_app/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin:
Expand Down Expand Up @@ -159,6 +164,7 @@ SPEC CHECKSUMS:
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
restart_app: 806659942bf932f6ce51c5372f91ce5e81c8c14a
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite_darwin: a553b1fd6fe66f53bbb0fe5b4f5bab93f08d7a13
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
Expand Down
11 changes: 7 additions & 4 deletions packages/conferenceapp/lib/conference_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'src/features/more/application/theme_vm.dart';
import 'src/features/onboarding/presentation/presentation.dart';
import 'src/features/updater/widgets/update_listener.dart';

class ConferenceApp extends ConsumerStatefulWidget {
const ConferenceApp({super.key});
Expand Down Expand Up @@ -54,10 +55,12 @@ class _ConferenceAppState extends ConsumerState<ConferenceApp> {
navigatorKey: Devfest2024Router.rootNavigatorKey,
initialRoute: Devfest2024Router.initialRoute,
onGenerateRoute: Devfest2024Router.instance.onGenerateRoutes,
builder: (context, child) => AccessibilityTools(
minimumTapAreas: const MinimumTapAreas(mobile: 30, desktop: 44),
checkFontOverflows: true,
child: child,
builder: (context, child) => UpdateListener(
child: AccessibilityTools(
minimumTapAreas: const MinimumTapAreas(mobile: 30, desktop: 44),
checkFontOverflows: true,
child: child,
),
),
themeMode: themeMode.theme,
theme: ThemeData(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:equatable/equatable.dart';

enum UpdaterStatus { idle, updateCheckInProgress, downloadInProgress }

final class UpdaterState extends Equatable {
const UpdaterState({
this.status = UpdaterStatus.idle,
this.updateAvailable = false,
this.isNewPatchReadyToInstall = false,
});

final UpdaterStatus status;
final bool updateAvailable;
final bool isNewPatchReadyToInstall;

UpdaterState copyWith({
UpdaterStatus? status,
bool? updateAvailable,
bool? isNewPatchReadyToInstall,
}) {
return UpdaterState(
status: status ?? this.status,
updateAvailable: updateAvailable ?? this.updateAvailable,
isNewPatchReadyToInstall:
isNewPatchReadyToInstall ?? this.isNewPatchReadyToInstall,
);
}

@override
List<Object?> get props => [
status,
updateAvailable,
isNewPatchReadyToInstall,
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:equatable/equatable.dart';
import 'package:shorebird_code_push/shorebird_code_push.dart';

enum UpdaterStatus {
idle,
updateCheckInProgress,
downloadInProgress,
}

class UpdaterState extends Equatable {
final UpdaterStatus status;
final bool updateAvailable;
final bool isNewPatchReadyToInstall;

const UpdaterState({
this.status = UpdaterStatus.idle,
this.updateAvailable = false,
this.isNewPatchReadyToInstall = false,
});

UpdaterState copyWith({
UpdaterStatus? status,
bool? updateAvailable,
bool? isNewPatchReadyToInstall,
}) {
return UpdaterState(
status: status ?? this.status,
updateAvailable: updateAvailable ?? this.updateAvailable,
isNewPatchReadyToInstall:
isNewPatchReadyToInstall ?? this.isNewPatchReadyToInstall,
);
}

@override
List<Object?> get props =>
[status, updateAvailable, isNewPatchReadyToInstall];
}

class UpdaterNotifier extends StateNotifier<UpdaterState> {
UpdaterNotifier({ShorebirdCodePush? codePush})
: _codePush = codePush ?? ShorebirdCodePush(),
super(const UpdaterState()) {
Future.microtask(() => init());
}

final ShorebirdCodePush _codePush;

Future<void> init() async {
await checkForUpdates();
}

Future<void> checkForUpdates() async {
state = state.copyWith(status: UpdaterStatus.updateCheckInProgress);
try {
final updateAvailable = await _codePush.isNewPatchAvailableForDownload();
state = state.copyWith(
status: UpdaterStatus.idle,
updateAvailable: updateAvailable,
);
if (updateAvailable) await _downloadUpdate();
} catch (error, _) {
// Handle error (e.g., log it)
state = state.copyWith(
status: UpdaterStatus.idle,
updateAvailable: true,
);
}
}

Future<void> _downloadUpdate() async {
state = state.copyWith(status: UpdaterStatus.downloadInProgress);
try {
await _codePush.downloadUpdateIfAvailable();
} catch (error, _) {
// Handle error (e.g., log it)
}
try {
final isNewPatchReadyToInstall =
await _codePush.isNewPatchReadyToInstall();
state = state.copyWith(
isNewPatchReadyToInstall: isNewPatchReadyToInstall,
status: UpdaterStatus.idle,
);
} catch (error, _) {
// Handle error (e.g., log it)
state = state.copyWith(
isNewPatchReadyToInstall: false,
status: UpdaterStatus.idle,
);
}
}
}

final updaterProvider =
StateNotifierProvider<UpdaterNotifier, UpdaterState>((ref) {
return UpdaterNotifier();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:restart_app/restart_app.dart';

import '../application/updater_vm.dart';

class UpdateListener extends ConsumerWidget {
const UpdateListener({required this.child, super.key});
final Widget child;

@override
Widget build(BuildContext context, WidgetRef ref) {
ref.listen<UpdaterState>(updaterProvider, (previous, current) {
if (previous?.status == UpdaterStatus.downloadInProgress &&
current.status == UpdaterStatus.idle &&
current.isNewPatchReadyToInstall) {
WidgetsBinding.instance.addPostFrameCallback((_) {
ScaffoldMessenger.of(context)
..hideCurrentMaterialBanner()
..showMaterialBanner(
MaterialBanner(
content: const Text('An update is available!'),
actions: [
TextButton(
onPressed: Restart.restartApp,
child: const Text('Restart Now'),
),
],
),
);
});
}
});

return child;
}
}
18 changes: 17 additions & 1 deletion packages/conferenceapp/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.1.0"
restart_app:
dependency: "direct main"
description:
name: restart_app
sha256: "00d5ec3e9de871cedbe552fc41e615b042b5ec654385e090e0983f6d02f655ed"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
riverpod:
dependency: transitive
description:
Expand Down Expand Up @@ -703,6 +711,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.0"
shorebird_code_push:
dependency: "direct main"
description:
name: shorebird_code_push
sha256: "77511427c51906dd39d3bb1e6b0a8c49777975f9b0a5d073e35c9087a8a36bb6"
url: "https://pub.dev"
source: hosted
version: "1.1.6"
sky_engine:
dependency: transitive
description: flutter
Expand Down Expand Up @@ -989,5 +1005,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.5.0 <4.0.0"
dart: ">=3.5.1 <4.0.0"
flutter: ">=3.24.0"
2 changes: 2 additions & 0 deletions packages/conferenceapp/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ dependencies:
mesh: ^0.4.1
package_info_plus: ^8.0.2
path_provider: ^2.1.4
restart_app: ^1.3.2
shared_preferences: ^2.3.3
shorebird_code_push: ^1.1.6
url_launcher: ^6.3.1

dependency_overrides:
Expand Down
2 changes: 1 addition & 1 deletion packages/conferenceapp/shorebird.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ app_id: 85a91995-2ca3-4ce0-bd34-a85590d78140
# If auto_update: false, you will need to use package:shorebird_code_push to trigger updates.
# https://pub.dev/packages/shorebird_code_push
# Uncomment the following line to disable automatic updates.
# auto_update: false
auto_update: false