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

fix: Allow cancelling updates in manage page #1536

Merged
merged 9 commits into from
Dec 30, 2023
15 changes: 15 additions & 0 deletions packages/app_center/lib/src/manage/manage_page.dart
Original file line number Diff line number Diff line change
@@ -304,6 +304,21 @@ class _ActionButtons extends ConsumerWidget {
],
),
),
const SizedBox(width: 8),
PushButton.outlined(
onPressed: updatesModel.refreshableSnapNames.isNotEmpty &&
!updatesModel.state.isLoading &&
updatesModel.activeChangeId != null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this out to a variable with a good name so that the code gets more readability

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for suggestion, made the change to extract a variable.

Ran melos generate, and it fixed the missing mock definition. Thanks.

? () => ref
.read(updatesModelProvider)
.cancelChange(updatesModel.activeChangeId!)
: null,
child: Text(
l10n.snapActionCancelLabel,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
);
}
21 changes: 21 additions & 0 deletions packages/app_center/lib/src/snapd/updates_model.dart
Original file line number Diff line number Diff line change
@@ -63,4 +63,25 @@ class UpdatesModel extends ChangeNotifier {
_activeChangeId = null;
await refresh();
}

Future<void> cancelChange(String changeId) async {
if (changeId.isEmpty) return;

try {
final changeDetails = await snapd.getChange(changeId);

// If the change is already completed, ignore silently.
// Otherwise an erorr will be displayed to user, which might be confusing.
codinesh marked this conversation as resolved.
Show resolved Hide resolved
if (changeDetails.ready) {
return;
}

final abortChange = await snapd.abortChange(changeId);
await snapd.waitChange(abortChange.id);
_activeChangeId = null;
notifyListeners();
} on SnapdException catch (e) {
_handleError(e);
}
}
}
27 changes: 27 additions & 0 deletions packages/app_center/test/manage_page_test.dart
Original file line number Diff line number Diff line change
@@ -235,6 +235,33 @@ void main() {
);
});

testWidgets('cancel refresh all', (tester) async {
final mockUpdatesModel = createMockUpdatesModel(
refreshableSnapNames: refreshableSnaps.map((snap) => snap.name),
isBusy: true,
);

await tester.pumpApp(
(_) => ProviderScope(
overrides: [
launchProvider.overrideWith((_, __) => createMockSnapLauncher()),
manageModelProvider.overrideWith(
(_) => createMockManageModel(
refreshableSnaps: refreshableSnaps,
),
),
updatesModelProvider.overrideWith((_) => mockUpdatesModel),
],
child: const ManagePage(),
),
);
await tester.pump();

final cancelButton = find.buttonWithText(tester.l10n.snapActionCancelLabel);
expect(cancelButton, findsOneWidget);
expect(cancelButton, isEnabled);
});

testWidgets('error dialog', (tester) async {
await tester.pumpApp(
(_) => ProviderScope(
1 change: 1 addition & 0 deletions packages/app_center/test/test_utils.dart
Original file line number Diff line number Diff line change
@@ -230,6 +230,7 @@ MockUpdatesModel createMockUpdatesModel({
when(model.activeChangeId).thenReturn(isBusy ? 'changeId' : null);
when(model.errorStream)
.thenAnswer((_) => errorStream ?? const Stream.empty());
when(model.activeChangeId).thenReturn('activeChangeId');
return model;
}