Skip to content

Commit

Permalink
Merge pull request #1660 from ubuntu/refactor/migrate-away-from-old-p…
Browse files Browse the repository at this point in the history
…roviders

refactor: Migrate away snap model from old provider style
  • Loading branch information
spydon committed Jun 14, 2024
2 parents 55be591 + e8cb42e commit 3e81048
Show file tree
Hide file tree
Showing 37 changed files with 2,471 additions and 1,712 deletions.
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
flutter 3.19.3-stable
flutter 3.19.6-stable
4 changes: 2 additions & 2 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ command:
bootstrap:
environment:
sdk: '>=3.1.0 <4.0.0'
flutter: '>=3.19.0'
flutter: '>=3.19.6'

dev_dependencies:
ubuntu_lints: ^0.3.0
ubuntu_lints: ^0.3.1

scripts:
# analyze all packages
Expand Down
22 changes: 19 additions & 3 deletions packages/app_center/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:app_center/l10n.dart';
import 'package:app_center/packagekit.dart';
import 'package:app_center/ratings.dart';
import 'package:app_center/snapd.dart';
import 'package:app_center/src/providers/error_stream_provider.dart';
import 'package:app_center/store.dart';
import 'package:app_center_ratings_client/app_center_ratings_client.dart';
import 'package:flutter/material.dart';
Expand All @@ -21,9 +22,9 @@ import 'package:ubuntu_service/ubuntu_service.dart';
import 'package:xdg_directories/xdg_directories.dart' as xdg;
import 'package:yaru/yaru.dart';

Future<void> main(List<String> args) async {
await YaruWindowTitleBar.ensureInitialized();
final log = Logger('main');

Future<void> main(List<String> args) async {
final binaryName = p.basename(Platform.resolvedExecutable);
Logger.setup(
path: p.join(
Expand Down Expand Up @@ -66,8 +67,23 @@ Future<void> main(List<String> args) async {
registerService(PackageKitClient.new);
registerService(PackageKitService.new,
dispose: (service) => service.dispose());
registerService(
ErrorStreamController.new,
dispose: (controller) => controller.close(),
);

await initDefaultLocale();

runApp(const ProviderScope(child: StoreApp()));
await runZonedGuarded(
() async {
await YaruWindowTitleBar.ensureInitialized();
runApp(const ProviderScope(child: StoreApp()));
},
(error, stackTrace) {
log.error('Error propagated to top-level', error, stackTrace);
if (error is Exception) {
getService<ErrorStreamController>().add(error);
}
},
);
}
2 changes: 2 additions & 0 deletions packages/app_center/lib/src/games/games_page_featured.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class _CarouselCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return YaruBanner(
// TODO: Remove color once we have upgraded to a yaru version > 4.1.0
color: Theme.of(context).cardColor,
padding: EdgeInsets.zero,
onTap: () => onTap(snap),
child: ClipRRect(
Expand Down
141 changes: 73 additions & 68 deletions packages/app_center/lib/src/manage/manage_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,9 @@ class _ActionButtons extends ConsumerWidget {
child: updatesModel.activeChangeId != null
? Consumer(
builder: (context, ref, child) {
final change = ref
.watch(changeProvider(updatesModel.activeChangeId))
.whenOrNull(data: (data) => data);
final change = ref.watch(
activeChangeProvider(updatesModel.activeChangeId),
);
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Expand Down Expand Up @@ -340,7 +340,6 @@ class _ManageSnapTile extends ConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final snapLauncher = ref.watch(launchProvider(snap));
final l10n = AppLocalizations.of(context);
final border = BorderSide(color: Theme.of(context).colorScheme.outline);
final dateTimeSinceUpdate = snap.installDate != null
Expand Down Expand Up @@ -470,75 +469,71 @@ class _ManageSnapTile extends ConsumerWidget {
],
),
trailing: showUpdateButton
? buildButtonBarForUpdate(ref, l10n, snapLauncher, context)
: buildButtonBarForOpen(ref, l10n, snapLauncher, context),
? _ButtonBarForUpdate(snap)
: _ButtonBarForOpen(snap),
),
);
}
}

class _ButtonBarForUpdate extends ConsumerWidget {
const _ButtonBarForUpdate(this.snap);

final Snap snap;

@override
Widget build(BuildContext context, WidgetRef ref) {
final snapLauncher = ref.watch(launchProvider(snap));
final l10n = AppLocalizations.of(context);
final snapModel = ref.watch(snapModelProvider(snap.name));
final updatesModel = ref.watch(updatesModelProvider);
final activeChangeId = snapModel.value?.activeChangeId;
final change = activeChangeId != null
? ref.watch(activeChangeProvider(activeChangeId))
: null;

ButtonBar buildButtonBarForUpdate(WidgetRef ref, AppLocalizations l10n,
SnapLauncher snapLauncher, BuildContext context) {
return ButtonBar(
mainAxisSize: MainAxisSize.min,
children: [
Consumer(
builder: (context, ref, child) {
final snapModel = ref.watch(snapModelProvider(snap.name));
final updatesModel = ref.watch(updatesModelProvider);

return PushButton.outlined(
style: const ButtonStyle(
padding: MaterialStatePropertyAll(EdgeInsets.zero)),
onPressed: updatesModel.activeChangeId != null
? null
: () {
ref.read(snapModelProvider(snap.name)).refresh();
},
child: snapModel.activeChangeId != null
? Consumer(
builder: (context, ref, child) {
final change = ref
.watch(changeProvider(snapModel.activeChangeId))
.whenOrNull(data: (data) => data);
return Row(
children: [
SizedBox.square(
dimension: kCircularProgressIndicatorHeight,
child: YaruCircularProgressIndicator(
value: change?.progress,
strokeWidth: 2,
),
),
if (change != null) ...[
const SizedBox(width: 8),
Flexible(
child: Text(
change.localize(l10n) ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
]
],
);
},
)
: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(YaruIcons.download),
const SizedBox(width: 8),
Flexible(
child: Text(
l10n.snapActionUpdateLabel,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
PushButton.outlined(
style: const ButtonStyle(
padding: MaterialStatePropertyAll(EdgeInsets.zero),
),
onPressed: updatesModel.activeChangeId != null || !snapModel.hasValue
? null
: ref.read(snapModelProvider(snap.name).notifier).refresh,
child: snapModel.value?.activeChangeId != null
? Row(
children: [
SizedBox.square(
dimension: kCircularProgressIndicatorHeight,
child: YaruCircularProgressIndicator(
value: change?.progress,
strokeWidth: 2,
),
),
if (change != null) ...[
const SizedBox(width: 8),
Text(
change.localize(l10n) ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
]
],
)
: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(YaruIcons.download),
const SizedBox(width: 8),
Text(
l10n.snapActionUpdateLabel,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
);
},
],
),
),
MenuAnchor(
menuChildren: [
Expand Down Expand Up @@ -575,9 +570,18 @@ class _ManageSnapTile extends ConsumerWidget {
],
);
}
}

class _ButtonBarForOpen extends ConsumerWidget {
const _ButtonBarForOpen(this.snap);

final Snap snap;

@override
Widget build(BuildContext context, WidgetRef ref) {
final snapLauncher = ref.watch(launchProvider(snap));
final l10n = AppLocalizations.of(context);

ButtonBar buildButtonBarForOpen(WidgetRef ref, AppLocalizations l10n,
SnapLauncher snapLauncher, BuildContext context) {
return ButtonBar(
mainAxisSize: MainAxisSize.min,
children: [
Expand All @@ -588,7 +592,8 @@ class _ManageSnapTile extends ConsumerWidget {
visible: snapLauncher.isLaunchable,
child: OutlinedButton(
style: const ButtonStyle(
padding: MaterialStatePropertyAll(EdgeInsets.zero)),
padding: MaterialStatePropertyAll(EdgeInsets.zero),
),
onPressed: snapLauncher.open,
child: Text(
l10n.snapActionOpenLabel,
Expand Down
11 changes: 11 additions & 0 deletions packages/app_center/lib/src/providers/error_stream_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'dart:async';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ubuntu_service/ubuntu_service.dart';

/// Used to listen to incoming errors to show them to the user.
final errorStreamProvider = StreamProvider<Exception>(
(ref) => getService<ErrorStreamController>().stream,
);

typedef ErrorStreamController = StreamController<Exception>;
15 changes: 15 additions & 0 deletions packages/app_center/lib/src/providers/file_system_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'dart:io';

import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:file/memory.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

/// Provides the correct file system to use for the environment.
/// The file system is a [MemoryFileSystem] when running widget tests and a
/// [LocalFileSystem] otherwise.
final fileSystemProvider = Provider<FileSystem>(
(_) => Platform.environment.containsKey('FLUTTER_TEST')
? MemoryFileSystem()
: const LocalFileSystem(),
);
Loading

0 comments on commit 3e81048

Please sign in to comment.