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: credential status notifications #212

Merged
merged 45 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
06151d7
chore: provide bloc
sjoerdlmkns Jul 12, 2023
fc150a1
wip: NotificationsScreen, NotificationsCard, NotificationsBell
sjoerdlmkns Jul 13, 2023
1f29cd5
feat: empty notifications indicator
sjoerdlmkns Jul 13, 2023
d461e23
feat: IrmaDismissible
sjoerdlmkns Jul 13, 2023
05ccd39
feat: added timestamp to notification
sjoerdlmkns Jul 13, 2023
7f0a858
feat: build notifications according to bloc
sjoerdlmkns Jul 13, 2023
d5301a6
feat: add DeleteNotificationEvent on notification dismiss
sjoerdlmkns Jul 13, 2023
b61c762
test: reach NotificationsScreen
sjoerdlmkns Jul 13, 2023
f509fd3
test: empty notifications test
sjoerdlmkns Jul 13, 2023
5a3aac9
fix: timestamp json serialize
sjoerdlmkns Jul 14, 2023
254146f
refactor: removed serializedCredentialStatusNotifications pref
sjoerdlmkns Jul 14, 2023
3934da2
feat: reset notifications on corrupted cache
sjoerdlmkns Jul 14, 2023
fe2abbd
test: load valid/corrupted cache
sjoerdlmkns Jul 14, 2023
7086c62
fix: check empty string before serializing
sjoerdlmkns Jul 24, 2023
59717bb
test: notificaitons filled-state
sjoerdlmkns Jul 25, 2023
98d3dab
Merge branch 'master' into notifications-ui
sjoerdlmkns Jul 25, 2023
b34e480
feat: add read to notification
sjoerdlmkns Jul 25, 2023
1bc66a8
test: mark-notifications-as-read
sjoerdlmkns Jul 25, 2023
9cd01ea
feat: mark notifications as read when leaving NotificationsScreen
sjoerdlmkns Jul 26, 2023
081f496
test: read-all-notifications
sjoerdlmkns Jul 26, 2023
d832683
fix: serialize notification action
sjoerdlmkns Jul 26, 2023
81eadc3
fix: wrong json type key
sjoerdlmkns Jul 27, 2023
74fdcb6
test: reuse mocked serialized notifications
sjoerdlmkns Jul 27, 2023
583de3d
feat: handle CredentialDetailNavigationAction on NotificaitonsScreen
sjoerdlmkns Jul 27, 2023
e8109ed
test: also reuse mocked serialized notifications in integration tests
sjoerdlmkns Jul 27, 2023
5d2e7e7
test: dismiss notification integration test
sjoerdlmkns Jul 27, 2023
ceba972
chore: updated CHANGELOG
sjoerdlmkns Jul 27, 2023
6679312
feat: mark single notifiation as read on action
sjoerdlmkns Jul 27, 2023
1e9bb2a
test: mark single notfication as read
sjoerdlmkns Jul 27, 2023
7b399db
test: credential status notification action
sjoerdlmkns Jul 27, 2023
32d7a90
refactor: moved functions form build method to state
sjoerdlmkns Jul 31, 2023
9d28342
feat: NotificationBell semantics
sjoerdlmkns Jul 31, 2023
c0678b2
refactor: provide the NotificationsBloc higher in the widget tree
sjoerdlmkns Aug 1, 2023
bf30ddf
refactor: removed named notification screen route because the bloc ne…
sjoerdlmkns Aug 1, 2023
3442ed8
feat: reload notifications on AppLifecycleState.resumed
sjoerdlmkns Aug 1, 2023
2de1de0
test: reload-notifications
sjoerdlmkns Aug 1, 2023
70a0936
fix: use actual timestamp from notification
sjoerdlmkns Aug 1, 2023
a435669
refactor: updated comment
sjoerdlmkns Aug 1, 2023
2b2a7ad
feat: reload notifications with RefreshIndicator
sjoerdlmkns Aug 1, 2023
b720fa0
test: pull to reload notifications
sjoerdlmkns Aug 1, 2023
05bb099
Merge branch 'master' into notifications-ui
sjoerdlmkns Aug 1, 2023
85ac01e
refactor: made _onRefresh not return a future with Future.sync
sjoerdlmkns Aug 1, 2023
929680d
test: merged reload-notifications into revocation test
sjoerdlmkns Aug 1, 2023
158f2f6
Merge branch 'notifications-ui' of https://github.com/privacybydesign…
sjoerdlmkns Aug 1, 2023
2b28595
Merge branch 'master' into notifications-ui
sjoerdlmkns Aug 1, 2023
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
### Added
- Credential status notifications
### Fixed
- Voice over and accessibility tags are not correctly set on the PIN screen
- Required update screen refers to iTunes Store instead of Apple App Store
Expand Down
6 changes: 6 additions & 0 deletions assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,8 @@
"explanation": "Everything remained the same under the hood, you can log in with your old PIN code."
},
"notifications": {
"title": "Notifications",
"empty": "No notifications",
"credential_status": {
"revoked": {
"title": "Data revoked",
Expand All @@ -610,6 +612,10 @@
"title": "Data expiring soon",
"message": "This data is expiring soon: {credentialName}"
}
},
"bell": {
"new_notifications": "Notifications bell - New notifications",
"no_new_notifications": "Notifications bell - No new notifications"
}
}
}
8 changes: 7 additions & 1 deletion assets/locales/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,9 @@
"header": "IRMA heeft een nieuwe naam en een nieuw uiterlijk gekregen: Yivi",
"explanation": "Onder de motorkap is alles hetzelfde gebleven, je kunt gewoon inloggen met je oude PIN-code."
},
"nofitifcations": {
"notifications": {
"title": "Notificaties",
"empty": "Geen notificaties",
"credential_status": {
"revoked": {
"title": "Gegevens ingetrokken",
Expand All @@ -610,6 +612,10 @@
"title": "Gegevens verlopen bijna",
"message": "Deze gegevens verlopen bijna: {credentialName}"
}
},
"bell": {
"new_notifications": "Notificatiebel - Nieuwe notificaties",
"no_new_notifications": "Notificatiebel - Geen nieuwe notificaties"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:irmamobile/src/screens/data/credentials_detail_screen.dart';
import 'package:irmamobile/src/screens/notifications/widgets/notification_bell.dart';
import 'package:irmamobile/src/screens/notifications/widgets/notification_card.dart';

import 'package:irmamobile/src/screens/session/disclosure/widgets/disclosure_permission_choices_screen.dart';
import 'package:irmamobile/src/widgets/credential_card/irma_credential_card.dart';
Expand Down Expand Up @@ -44,7 +47,6 @@ Future<void> revocationTest(WidgetTester tester, IntegrationTestIrmaBinding irma
);

await revokeCredential('irma-demo.MijnOverheid.root', revocationKey);

await irmaBinding.repository.startTestSession('''
{
"@context": "https://irma.app/ld/request/disclosure/v2",
Expand Down Expand Up @@ -76,21 +78,45 @@ Future<void> revocationTest(WidgetTester tester, IntegrationTestIrmaBinding irma
find.text('Close'),
);

//Go to the data tab
await tester.tapAndSettle(find.byKey(const Key('nav_button_data')));
// The NotificationBell should be findable in the app bar
final notificationBellFinder = find.byType(NotificationBell);
expect(notificationBellFinder, findsOneWidget);
await tester.tapAndSettle(notificationBellFinder);

// Tap the card with the text Demo Root
final demoRootFinder = find.text('Demo Root');
await tester.scrollUntilVisible(demoRootFinder, 100);
await tester.tapAndSettle(demoRootFinder);
// Now pull to refresh and expect a notification card
await tester.drag(find.byType(RefreshIndicator), const Offset(0, 500));
await tester.pumpAndSettle();

// Find the credential card
final credentialCardFinder = find.byType(IrmaCredentialCard).first;
expect(credentialCardFinder, findsOneWidget);
final notificationCardsFinder = find.byType(NotificationCard);
expect(notificationCardsFinder, findsOneWidget);

await _evaluateDemoCredentialCard(
final notificationCardFinder = notificationCardsFinder.first;
await evaluateNotificationCard(
tester,
notificationCardFinder,
title: 'Data revoked',
content: 'Demo MijnOverheid.nl has revoked this data: Demo Root',
read: false,
);

// Tap the notification card to open the credential detail screen
await tester.tapAndSettle(notificationCardFinder);

// Expect the credential detail screen
final credentialDetailScreenFinder = find.byType(CredentialsDetailScreen);
expect(credentialDetailScreenFinder, findsOneWidget);

// Expect the actual credential card
final credentialCardsFinder = find.byType(IrmaCredentialCard);
expect(credentialCardsFinder, findsOneWidget);

final credentialCardFinder = credentialCardsFinder.first;
await evaluateCredentialCard(
tester,
credentialCardFinder,
credentialName: 'Demo Root',
issuerName: 'Demo MijnOverheid.nl',
attributes: {'BSN': '12345'},
isRevoked: true,
);

Expand Down
53 changes: 50 additions & 3 deletions integration_test/helpers/helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import 'package:irmamobile/app.dart';
import 'package:irmamobile/main.dart';
import 'package:irmamobile/src/data/irma_repository.dart';
import 'package:irmamobile/src/screens/home/home_tab.dart';
import 'package:irmamobile/src/screens/notifications/bloc/notifications_bloc.dart';
import 'package:irmamobile/src/screens/notifications/widgets/notification_card.dart';
import 'package:irmamobile/src/screens/session/widgets/issuance_permission.dart';
import 'package:irmamobile/src/widgets/credential_card/irma_credential_card.dart';
import 'package:irmamobile/src/widgets/credential_card/irma_credential_card_attribute_list.dart';
Expand Down Expand Up @@ -38,9 +40,15 @@ Future<void> enterPin(WidgetTester tester, String pin) async {
await tester.pumpAndSettle(const Duration(milliseconds: 1500));
}

Future<void> pumpIrmaApp(WidgetTester tester, IrmaRepository repo, [Locale? defaultLanguage]) async {
Future<void> pumpIrmaApp(
WidgetTester tester,
IrmaRepository repo, [
Locale? defaultLanguage,
NotificationsBloc? notificationsBloc,
]) async {
await tester.pumpWidgetAndSettle(IrmaApp(
repository: repo,
notificationsBloc: notificationsBloc ?? NotificationsBloc(repo: repo),
defaultLanguage: defaultLanguage ?? const Locale('en', 'EN'),
));

Expand All @@ -53,8 +61,9 @@ Future<void> pumpIrmaApp(WidgetTester tester, IrmaRepository repo, [Locale? defa
}

// Pump a new app and unlock it
Future<void> pumpAndUnlockApp(WidgetTester tester, IrmaRepository repo, [Locale? locale]) async {
await pumpIrmaApp(tester, repo, locale);
Future<void> pumpAndUnlockApp(WidgetTester tester, IrmaRepository repo,
[Locale? locale, NotificationsBloc? notificationsBloc]) async {
await pumpIrmaApp(tester, repo, locale, notificationsBloc);
await unlock(tester);
}

Expand Down Expand Up @@ -341,3 +350,41 @@ Future<void> evaluateCredentialCard(
}
}
}

Future<void> evaluateNotificationCard(
WidgetTester tester,
Finder notificationCardFinder, {
String? title,
String? content,
bool? read,
}) async {
expect(notificationCardFinder, findsOneWidget);

if (title != null) {
expect(
find.descendant(
of: notificationCardFinder,
matching: find.text(title),
),
findsOneWidget,
);
}

if (content != null) {
expect(
find.descendant(
of: notificationCardFinder,
matching: find.text(content),
),
findsOneWidget,
);
}

if (read != null) {
final notificationCardWidget = notificationCardFinder.evaluate().single.widget as NotificationCard;
expect(
notificationCardWidget.notification.read,
read,
);
}
}
9 changes: 9 additions & 0 deletions integration_test/helpers/issuance_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import 'package:flutter_test/flutter_test.dart';
import '../irma_binding.dart';
import 'helpers.dart';

Future<void> issueIrmaTubeMember(
WidgetTester tester,
IntegrationTestIrmaBinding irmaBinding,
) =>
issueCredentials(tester, irmaBinding, {
'irma-demo.IRMATube.member.type': 'USER',
'irma-demo.IRMATube.member.id': '123123',
});

Future<void> issueEmailAddress(
WidgetTester tester,
IntegrationTestIrmaBinding irmaBinding,
Expand Down
Loading