Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf59cf4621 |
@@ -27,6 +27,7 @@ abstract class EmailRepository {
|
|||||||
Future<EmailBody> getEmailBody(String emailId);
|
Future<EmailBody> getEmailBody(String emailId);
|
||||||
Future<SyncEmailsResult> syncEmails(String accountId, String mailboxPath);
|
Future<SyncEmailsResult> syncEmails(String accountId, String mailboxPath);
|
||||||
Future<void> setFlag(String emailId, {bool? seen, bool? flagged});
|
Future<void> setFlag(String emailId, {bool? seen, bool? flagged});
|
||||||
|
Future<void> markAllAsRead(String accountId, String mailboxPath);
|
||||||
Future<void> moveEmail(String emailId, String destMailboxPath);
|
Future<void> moveEmail(String emailId, String destMailboxPath);
|
||||||
|
|
||||||
/// Deletes the email. Returns the path of the mailbox it was moved to
|
/// Deletes the email. Returns the path of the mailbox it was moved to
|
||||||
|
|||||||
@@ -1520,6 +1520,63 @@ class EmailRepositoryImpl implements EmailRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> markAllAsRead(String accountId, String mailboxPath) async {
|
||||||
|
final account = (await _accounts.getAccount(accountId))!;
|
||||||
|
final unread = await (_db.select(_db.emails)
|
||||||
|
..where(
|
||||||
|
(t) =>
|
||||||
|
t.accountId.equals(accountId) &
|
||||||
|
t.mailboxPath.equals(mailboxPath) &
|
||||||
|
t.isSeen.equals(false),
|
||||||
|
))
|
||||||
|
.get();
|
||||||
|
if (unread.isEmpty) return;
|
||||||
|
|
||||||
|
await _db.transaction(() async {
|
||||||
|
for (final row in unread) {
|
||||||
|
if (account.type == account_model.AccountType.jmap) {
|
||||||
|
await _enqueueChange(
|
||||||
|
accountId,
|
||||||
|
row.id,
|
||||||
|
'flag_seen',
|
||||||
|
jsonEncode({'seen': true}),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await _enqueueChange(
|
||||||
|
accountId,
|
||||||
|
row.id,
|
||||||
|
'flag_seen',
|
||||||
|
jsonEncode({
|
||||||
|
'uid': row.uid,
|
||||||
|
'mailboxPath': row.mailboxPath,
|
||||||
|
'seen': true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bulk mark all unread emails in this mailbox as seen.
|
||||||
|
await (_db.update(_db.emails)
|
||||||
|
..where(
|
||||||
|
(t) =>
|
||||||
|
t.accountId.equals(accountId) &
|
||||||
|
t.mailboxPath.equals(mailboxPath) &
|
||||||
|
t.isSeen.equals(false),
|
||||||
|
))
|
||||||
|
.write(const EmailsCompanion(isSeen: Value(true)));
|
||||||
|
|
||||||
|
// Update all threads in this mailbox to reflect no unread.
|
||||||
|
await (_db.update(_db.threads)
|
||||||
|
..where(
|
||||||
|
(t) =>
|
||||||
|
t.accountId.equals(accountId) &
|
||||||
|
t.mailboxPath.equals(mailboxPath),
|
||||||
|
))
|
||||||
|
.write(const ThreadsCompanion(hasUnread: Value(false)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> moveEmail(String emailId, String destMailboxPath) async {
|
Future<void> moveEmail(String emailId, String destMailboxPath) async {
|
||||||
final row = await (_db.select(
|
final row = await (_db.select(
|
||||||
|
|||||||
@@ -193,6 +193,22 @@ class _EmailListScreenState extends ConsumerState<EmailListScreen> {
|
|||||||
extra: {'accountId': widget.accountId},
|
extra: {'accountId': widget.accountId},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
PopupMenuButton<String>(
|
||||||
|
onSelected: (value) async {
|
||||||
|
if (value == 'mark_all_read') {
|
||||||
|
await emailRepo.markAllAsRead(
|
||||||
|
widget.accountId,
|
||||||
|
widget.mailboxPath,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (_) => const [
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'mark_all_read',
|
||||||
|
child: Text('Mark all as read'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
bottom: PreferredSize(
|
bottom: PreferredSize(
|
||||||
preferredSize: const Size.fromHeight(60),
|
preferredSize: const Size.fromHeight(60),
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ class _FakeEmails implements EmailRepository {
|
|||||||
@override
|
@override
|
||||||
Future<void> setFlag(String id, {bool? seen, bool? flagged}) async {}
|
Future<void> setFlag(String id, {bool? seen, bool? flagged}) async {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> markAllAsRead(String accountId, String mailboxPath) async {}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> moveEmail(String id, String dest) async {}
|
Future<void> moveEmail(String id, String dest) async {}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ class FakeEmailRepository implements EmailRepository {
|
|||||||
@override
|
@override
|
||||||
Future<void> setFlag(String id, {bool? seen, bool? flagged}) async {}
|
Future<void> setFlag(String id, {bool? seen, bool? flagged}) async {}
|
||||||
@override
|
@override
|
||||||
|
Future<void> markAllAsRead(String accountId, String mailboxPath) async {}
|
||||||
|
@override
|
||||||
Future<void> moveEmail(String id, String dest) async {}
|
Future<void> moveEmail(String id, String dest) async {}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -215,9 +215,9 @@ class MockEmailRepository extends _i1.Mock implements _i9.EmailRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
_i4.Stream<List<_i2.Email>> observeEmails(
|
_i4.Stream<List<_i2.Email>> observeEmails(
|
||||||
String accountId,
|
String? accountId,
|
||||||
String mailboxPath, {
|
String? mailboxPath, {
|
||||||
int limit = 50,
|
int? limit = 50,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
@@ -233,9 +233,9 @@ class MockEmailRepository extends _i1.Mock implements _i9.EmailRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
_i4.Stream<List<_i2.EmailThread>> observeThreads(
|
_i4.Stream<List<_i2.EmailThread>> observeThreads(
|
||||||
String accountId,
|
String? accountId,
|
||||||
String mailboxPath, {
|
String? mailboxPath, {
|
||||||
int limit = 50,
|
int? limit = 50,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
@@ -337,6 +337,23 @@ class MockEmailRepository extends _i1.Mock implements _i9.EmailRepository {
|
|||||||
returnValueForMissingStub: _i4.Future<void>.value(),
|
returnValueForMissingStub: _i4.Future<void>.value(),
|
||||||
) as _i4.Future<void>);
|
) as _i4.Future<void>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i4.Future<void> markAllAsRead(
|
||||||
|
String? accountId,
|
||||||
|
String? mailboxPath,
|
||||||
|
) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#markAllAsRead,
|
||||||
|
[
|
||||||
|
accountId,
|
||||||
|
mailboxPath,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
returnValue: _i4.Future<void>.value(),
|
||||||
|
returnValueForMissingStub: _i4.Future<void>.value(),
|
||||||
|
) as _i4.Future<void>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i4.Future<void> moveEmail(
|
_i4.Future<void> moveEmail(
|
||||||
String? emailId,
|
String? emailId,
|
||||||
|
|||||||
@@ -126,6 +126,35 @@ abstract class EmailRepositoryContract {
|
|||||||
expect(email!.isFlagged, isTrue);
|
expect(email!.isFlagged, isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('markAllAsRead marks every unread email in the mailbox', () async {
|
||||||
|
final repo = await makeRepo();
|
||||||
|
await insertEmail(
|
||||||
|
repo,
|
||||||
|
id: 'er-acc:20',
|
||||||
|
mailboxPath: 'INBOX',
|
||||||
|
isSeen: false,
|
||||||
|
);
|
||||||
|
await insertEmail(
|
||||||
|
repo,
|
||||||
|
id: 'er-acc:21',
|
||||||
|
mailboxPath: 'INBOX',
|
||||||
|
isSeen: false,
|
||||||
|
);
|
||||||
|
await insertEmail(
|
||||||
|
repo,
|
||||||
|
id: 'er-acc:22',
|
||||||
|
mailboxPath: 'Sent',
|
||||||
|
isSeen: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
await repo.markAllAsRead(_account.id, 'INBOX');
|
||||||
|
|
||||||
|
expect((await repo.getEmail('er-acc:20'))!.isSeen, isTrue);
|
||||||
|
expect((await repo.getEmail('er-acc:21'))!.isSeen, isTrue);
|
||||||
|
// Email in a different mailbox should be untouched.
|
||||||
|
expect((await repo.getEmail('er-acc:22'))!.isSeen, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
test('observeThreads starts empty', () async {
|
test('observeThreads starts empty', () async {
|
||||||
final repo = await makeRepo();
|
final repo = await makeRepo();
|
||||||
expect(
|
expect(
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ class _CountingEmails implements EmailRepository {
|
|||||||
@override
|
@override
|
||||||
Future<void> setFlag(String id, {bool? seen, bool? flagged}) async {}
|
Future<void> setFlag(String id, {bool? seen, bool? flagged}) async {}
|
||||||
@override
|
@override
|
||||||
|
Future<void> markAllAsRead(String accountId, String mailboxPath) async {}
|
||||||
|
@override
|
||||||
Future<void> moveEmail(String id, String dest) async {}
|
Future<void> moveEmail(String id, String dest) async {}
|
||||||
@override
|
@override
|
||||||
Future<String?> deleteEmail(String id) async => null;
|
Future<String?> deleteEmail(String id) async => null;
|
||||||
|
|||||||
@@ -75,9 +75,9 @@ class MockEmailRepository extends _i1.Mock implements _i3.EmailRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
_i4.Stream<List<_i2.Email>> observeEmails(
|
_i4.Stream<List<_i2.Email>> observeEmails(
|
||||||
String accountId,
|
String? accountId,
|
||||||
String mailboxPath, {
|
String? mailboxPath, {
|
||||||
int limit = 50,
|
int? limit = 50,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
@@ -93,9 +93,9 @@ class MockEmailRepository extends _i1.Mock implements _i3.EmailRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
_i4.Stream<List<_i2.EmailThread>> observeThreads(
|
_i4.Stream<List<_i2.EmailThread>> observeThreads(
|
||||||
String accountId,
|
String? accountId,
|
||||||
String mailboxPath, {
|
String? mailboxPath, {
|
||||||
int limit = 50,
|
int? limit = 50,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
@@ -197,6 +197,23 @@ class MockEmailRepository extends _i1.Mock implements _i3.EmailRepository {
|
|||||||
returnValueForMissingStub: _i4.Future<void>.value(),
|
returnValueForMissingStub: _i4.Future<void>.value(),
|
||||||
) as _i4.Future<void>);
|
) as _i4.Future<void>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i4.Future<void> markAllAsRead(
|
||||||
|
String? accountId,
|
||||||
|
String? mailboxPath,
|
||||||
|
) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#markAllAsRead,
|
||||||
|
[
|
||||||
|
accountId,
|
||||||
|
mailboxPath,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
returnValue: _i4.Future<void>.value(),
|
||||||
|
returnValueForMissingStub: _i4.Future<void>.value(),
|
||||||
|
) as _i4.Future<void>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i4.Future<void> moveEmail(
|
_i4.Future<void> moveEmail(
|
||||||
String? emailId,
|
String? emailId,
|
||||||
|
|||||||
@@ -213,6 +213,8 @@ class FakeEmailRepository implements EmailRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setFlag(String emailId, {bool? seen, bool? flagged}) async {}
|
Future<void> setFlag(String emailId, {bool? seen, bool? flagged}) async {}
|
||||||
|
@override
|
||||||
|
Future<void> markAllAsRead(String accountId, String mailboxPath) async {}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> moveEmail(String emailId, String destMailboxPath) async {}
|
Future<void> moveEmail(String emailId, String destMailboxPath) async {}
|
||||||
|
|||||||
Reference in New Issue
Block a user