What's new and the updater come from AppGraph (no new singleton; singletons_test back at its baseline)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5bc252bf02
commit
d48915dc47
6 files changed
+29
-16
No files matched your search
@@ -16,7 +16,7 @@ import 'src/platform/smoke.dart';
|
||||
import 'src/screens/home/ui.dart';
|
||||
import 'src/session/app_events.dart' show UpdateAvailable;
|
||||
import 'src/state/settings.dart';
|
||||
import 'src/update/update_controller.dart' show UpdateController, UpdatePhase, launchArgs;
|
||||
import 'src/update/update_controller.dart' show UpdatePhase, launchArgs;
|
||||
|
||||
Future<void> main(List<String> args) async {
|
||||
launchArgs = List.unmodifiable(args);
|
||||
@@ -77,7 +77,7 @@ Future<void> main(List<String> args) async {
|
||||
// Linux: the launcher entry and icon Wayland needs (release installs).
|
||||
unawaited(installDesktopEntry());
|
||||
// A found update is an event too (the band shows it).
|
||||
final updates = UpdateController.instance;
|
||||
final updates = graph.updates;
|
||||
updates.status.addListener(() {
|
||||
final s = updates.status.value;
|
||||
final version = s.manifest?.version;
|
||||
|
||||
@@ -21,6 +21,8 @@ import '../sfx/sound_bank.dart';
|
||||
import '../sfx/synth_sfx.dart';
|
||||
import '../state/connect_prefs.dart';
|
||||
import '../state/settings.dart';
|
||||
import '../update/update_controller.dart';
|
||||
import '../update/whats_new.dart';
|
||||
import '../watch/watch_history.dart';
|
||||
import '../watch/watch_tracker.dart';
|
||||
|
||||
@@ -57,6 +59,12 @@ class AppGraph {
|
||||
/// Watch tracking and the device's watch history (D3).
|
||||
final WatchTracker watch;
|
||||
|
||||
/// The app's updater (checks, the update band, install and restart).
|
||||
final UpdateController updates;
|
||||
|
||||
/// What's new once after an update; keeps the notes the updater saves.
|
||||
final WhatsNew whatsNew;
|
||||
|
||||
AppGraph._({
|
||||
required this.ports,
|
||||
required this.sfx,
|
||||
@@ -68,6 +76,8 @@ class AppGraph {
|
||||
required this.navigation,
|
||||
required this.library,
|
||||
required this.watch,
|
||||
required this.updates,
|
||||
required this.whatsNew,
|
||||
});
|
||||
|
||||
/// The desktop app's graph. Tests pass their own [ports], [identity]
|
||||
@@ -146,6 +156,9 @@ class AppGraph {
|
||||
..push = ({String? name, String? avatar}) {
|
||||
if (navigation.online.peek()) coordinator.updateProfile(name: name, avatar: avatar);
|
||||
};
|
||||
final updates = UpdateController.instance;
|
||||
final whatsNew = WhatsNew(store: SettingsWhatsNewStore(settings));
|
||||
updates.beforeRestart ??= whatsNew.installing;
|
||||
return AppGraph._(
|
||||
ports: p,
|
||||
sfx: sfx,
|
||||
@@ -157,6 +170,8 @@ class AppGraph {
|
||||
navigation: navigation,
|
||||
library: matcher,
|
||||
watch: watch,
|
||||
updates: updates,
|
||||
whatsNew: whatsNew,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,9 +83,9 @@ class AboutPanel extends StatelessWidget {
|
||||
UpdateStatusLine(controller: updates),
|
||||
// This version's notes, once kept (the install, a check).
|
||||
ValueListenableBuilder(
|
||||
valueListenable: (updates ?? UpdateController.instance).latest,
|
||||
valueListenable: (updates ?? AppScope.of(context).updates).latest,
|
||||
builder: (context, _, _) {
|
||||
final notes = (whatsNew ?? WhatsNew.instance).current;
|
||||
final notes = (whatsNew ?? AppScope.of(context).whatsNew).current;
|
||||
if (notes == null) return const SizedBox.shrink();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
|
||||
@@ -56,7 +56,7 @@ import 'welcome.dart';
|
||||
class AppShell extends StatefulWidget {
|
||||
final UpdateController? updates;
|
||||
final bool autoUpdateCheck;
|
||||
/// The card once after an update; defaults to [WhatsNew.instance] when
|
||||
/// The card once after an update; defaults to the graph's [WhatsNew] when
|
||||
/// [autoUpdateCheck] is on (off in tests unless given).
|
||||
final WhatsNew? whatsNew;
|
||||
/// Off in tests: the drag area, window buttons and fullscreen need
|
||||
@@ -293,16 +293,16 @@ class AppShellState extends State<AppShell> with SingleTickerProviderStateMixin
|
||||
/// What's new once after an update: due now (notes kept by the install)
|
||||
/// or once a check reads this version's manifest.
|
||||
Future<void> _startWhatsNew() async {
|
||||
await AppSettings.instance.ensureLoaded();
|
||||
await _graph.coordinator.settings.ensureLoaded();
|
||||
if (!mounted) return;
|
||||
final w = _whatsNewSource = widget.whatsNew ?? WhatsNew.instance;
|
||||
final w = _whatsNewSource = widget.whatsNew ?? _graph.whatsNew;
|
||||
w.due.addListener(_maybeWhatsNew);
|
||||
// Not over the full player while a video is on: once it ends or minimises.
|
||||
_stops.add(effect(() {
|
||||
_watching.value;
|
||||
untracked(() => _later(_maybeWhatsNew));
|
||||
}));
|
||||
w.start(widget.updates ?? UpdateController.instance);
|
||||
w.start(widget.updates ?? _graph.updates);
|
||||
_maybeWhatsNew();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:hive_ce_flutter/hive_flutter.dart';
|
||||
import 'package:sync_relay_core/core.dart';
|
||||
|
||||
import '../platform/app_shutdown.dart';
|
||||
import 'whats_new.dart';
|
||||
|
||||
// In-app update flow behind the update bar (UpdateBar). Same code path as
|
||||
// `--upgrade` (core's updater, downloadAndApply); this adds state for the
|
||||
@@ -60,8 +59,8 @@ class UpdateController {
|
||||
final RestartFn restart;
|
||||
final bool skipDevBuilds;
|
||||
/// Awaited after the apply, before [restart]: keeps the new version's
|
||||
/// notes for its first start ([WhatsNew.installing]).
|
||||
final Future<void> Function(UpdateManifest manifest)? beforeRestart;
|
||||
/// notes for its first start ([WhatsNew.installing], wired by `AppGraph`).
|
||||
Future<void> Function(UpdateManifest manifest)? beforeRestart;
|
||||
|
||||
UpdateController(
|
||||
{this.currentVersion = appVersion,
|
||||
@@ -70,8 +69,7 @@ class UpdateController {
|
||||
this.installRoot,
|
||||
this.restart = _closeAndRestart,
|
||||
this.skipDevBuilds = true,
|
||||
Future<void> Function(UpdateManifest manifest)? beforeRestart})
|
||||
: beforeRestart = beforeRestart ?? WhatsNew.instance.installing;
|
||||
this.beforeRestart});
|
||||
|
||||
final status = ValueNotifier(const UpdateStatus(UpdatePhase.idle));
|
||||
/// The manifest of the last check that read one, newer or not (What's
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class WhatsNewStore {
|
||||
|
||||
class SettingsWhatsNewStore implements WhatsNewStore {
|
||||
final AppSettings settings;
|
||||
SettingsWhatsNewStore([AppSettings? settings]) : settings = settings ?? AppSettings.instance;
|
||||
SettingsWhatsNewStore(this.settings);
|
||||
@override
|
||||
String? get seen => settings.whatsNewSeen;
|
||||
@override
|
||||
@@ -88,14 +88,14 @@ class MemoryWhatsNewStore implements WhatsNewStore {
|
||||
Future<void> setNotes(ReleaseNotes notes) async => this.notes = notes;
|
||||
}
|
||||
|
||||
/// Made once by `AppGraph` (the shell and About read it from there).
|
||||
class WhatsNew {
|
||||
static final instance = WhatsNew();
|
||||
|
||||
final String currentVersion;
|
||||
|
||||
final WhatsNewStore store;
|
||||
|
||||
WhatsNew({this.currentVersion = appVersion, WhatsNewStore? store}) : store = store ?? SettingsWhatsNewStore();
|
||||
WhatsNew({this.currentVersion = appVersion, required this.store});
|
||||
|
||||
/// The card to show now (once); null when there is none.
|
||||
final due = ValueNotifier<ReleaseNotes?>(null);
|
||||
|
||||
Reference in new issue
Block a user