refactor: enforce always_use_package_imports across all lib files

Added lint rule to analysis_options.yaml and ran dart fix --apply to convert
125 relative imports in 33 files to package:sharedinbox/... style.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas Güttler
2026-04-24 16:30:59 +02:00
co-authored by Claude Sonnet 4.6
parent 281acdf665
commit e3ba18285d
36 changed files with 130 additions and 129 deletions
+5
View File
@@ -6,6 +6,11 @@ Tasks get moved from NEXT.md to DONE.md
## Tasks
## Enable always_use_package_imports lint rule
Added rule to `analysis_options.yaml`; `dart fix --apply` converted 125 relative
imports across 33 files to `package:sharedinbox/...` style automatically.
## Replace silent catch (_) with logged errors
5 `catch (_)` blocks in JMAP push stream setup and 2 in UI screens now use
-4
View File
@@ -18,10 +18,6 @@ Then commit.
## Tasks
## Enable always_use_package_imports lint rule
Add `always_use_package_imports: true` to `analysis_options.yaml`, then fix all relative imports across `lib/` to use `package:sharedinbox3/...` style.
## Extract _batchMoveToRole helper in email_list_screen
`_batchArchive()` and `_batchMarkSpam()` in `lib/ui/screens/email_list_screen.dart` (~lines 249313) share the same pattern: look up a mailbox role, validate, iterate selected ids, call repo method. Extract a shared `_batchMoveToRole(String role)` helper.
+1
View File
@@ -60,6 +60,7 @@ linter:
- avoid_positional_boolean_parameters
# Imports and style
- always_use_package_imports
- directives_ordering
- curly_braces_in_flow_control_structures
- require_trailing_commas
@@ -1,4 +1,4 @@
import '../models/account.dart';
import 'package:sharedinbox/core/models/account.dart';
abstract class AccountRepository {
Stream<List<Account>> observeAccounts();
+1 -1
View File
@@ -1,4 +1,4 @@
import '../models/draft.dart';
import 'package:sharedinbox/core/models/draft.dart';
abstract class DraftRepository {
/// Inserts or updates a draft. Pass [id] to update; omit to create new.
+1 -1
View File
@@ -1,4 +1,4 @@
import '../models/email.dart';
import 'package:sharedinbox/core/models/email.dart';
abstract class EmailRepository {
Stream<List<Email>> observeEmails(String accountId, String mailboxPath);
@@ -1,4 +1,4 @@
import '../models/mailbox.dart';
import 'package:sharedinbox/core/models/mailbox.dart';
abstract class MailboxRepository {
Stream<List<Mailbox>> observeMailboxes(String accountId);
@@ -1,6 +1,6 @@
import 'package:http/http.dart' as http;
import '../models/discovery_result.dart';
import 'package:sharedinbox/core/models/discovery_result.dart';
abstract class AccountDiscoveryService {
Future<DiscoveryResult> discover(String email);
@@ -2,9 +2,8 @@ import 'dart:convert';
import 'package:enough_mail/enough_mail.dart' as imap;
import 'package:http/http.dart' as http;
import '../../data/imap/imap_client_factory.dart';
import '../models/account.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/data/imap/imap_client_factory.dart';
typedef ImapConnectForTestFn = Future<imap.ImapClient> Function(
Account,
+8 -9
View File
@@ -1,16 +1,15 @@
import 'dart:async';
import 'package:enough_mail/enough_mail.dart' as imap;
import '../../data/imap/imap_client_factory.dart'
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/email.dart' show SyncEmailsResult;
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/core/repositories/email_repository.dart';
import 'package:sharedinbox/core/repositories/mailbox_repository.dart';
import 'package:sharedinbox/core/repositories/sync_log_repository.dart';
import 'package:sharedinbox/core/utils/logger.dart';
import 'package:sharedinbox/data/imap/imap_client_factory.dart'
show ImapConnectFn, connectImap, verboseLogKey;
import '../models/account.dart';
import '../models/email.dart' show SyncEmailsResult;
import '../repositories/account_repository.dart';
import '../repositories/email_repository.dart';
import '../repositories/mailbox_repository.dart';
import '../repositories/sync_log_repository.dart';
import '../utils/logger.dart';
/// Manages background sync for all accounts.
///
+1 -1
View File
@@ -2,7 +2,7 @@ import 'dart:async';
import 'package:enough_mail/enough_mail.dart';
import '../../core/models/account.dart';
import 'package:sharedinbox/core/models/account.dart';
typedef ImapConnectFn = Future<ImapClient> Function(
Account account,
+2 -1
View File
@@ -4,7 +4,8 @@ import 'dart:typed_data';
import 'package:http/http.dart' as http;
import '../imap/imap_client_factory.dart' show verboseLogKey;
import 'package:sharedinbox/data/imap/imap_client_factory.dart'
show verboseLogKey;
const _coreUsing = [
'urn:ietf:params:jmap:core',
+4 -4
View File
@@ -3,10 +3,10 @@ import 'dart:typed_data';
import 'package:http/http.dart' as http;
import '../../core/models/account.dart';
import '../../core/models/sieve_script.dart';
import '../../core/repositories/account_repository.dart';
import 'jmap_client.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/sieve_script.dart';
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/data/jmap/jmap_client.dart';
class SieveRepository {
SieveRepository(this._accounts, this._httpClient);
@@ -1,9 +1,9 @@
import 'package:drift/drift.dart' show Value;
import '../../core/models/account.dart' as model;
import '../../core/repositories/account_repository.dart';
import '../../core/storage/secure_storage.dart';
import '../db/database.dart';
import 'package:sharedinbox/core/models/account.dart' as model;
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/core/storage/secure_storage.dart';
import 'package:sharedinbox/data/db/database.dart';
class AccountRepositoryImpl implements AccountRepository {
AccountRepositoryImpl(this._db, this._storage);
@@ -1,8 +1,8 @@
import 'package:drift/drift.dart';
import '../../core/models/draft.dart';
import '../../core/repositories/draft_repository.dart';
import '../db/database.dart';
import 'package:sharedinbox/core/models/draft.dart';
import 'package:sharedinbox/core/repositories/draft_repository.dart';
import 'package:sharedinbox/data/db/database.dart';
class DraftRepositoryImpl implements DraftRepository {
DraftRepositoryImpl(this._db);
@@ -9,14 +9,14 @@ import 'package:http/http.dart' as http;
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../../core/models/account.dart' as account_model;
import '../../core/models/email.dart' as model;
import '../../core/repositories/account_repository.dart';
import '../../core/repositories/email_repository.dart';
import '../../core/utils/logger.dart';
import '../db/database.dart';
import '../imap/imap_client_factory.dart';
import '../jmap/jmap_client.dart';
import 'package:sharedinbox/core/models/account.dart' as account_model;
import 'package:sharedinbox/core/models/email.dart' as model;
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/core/repositories/email_repository.dart';
import 'package:sharedinbox/core/utils/logger.dart';
import 'package:sharedinbox/data/db/database.dart';
import 'package:sharedinbox/data/imap/imap_client_factory.dart';
import 'package:sharedinbox/data/jmap/jmap_client.dart';
typedef SmtpConnectFn = Future<imap.SmtpClient> Function(
account_model.Account account,
@@ -2,14 +2,14 @@ import 'package:drift/drift.dart';
import 'package:enough_mail/enough_mail.dart' as imap;
import 'package:http/http.dart' as http;
import '../../core/models/account.dart' as account_model;
import '../../core/models/mailbox.dart' as model;
import '../../core/repositories/account_repository.dart';
import '../../core/repositories/mailbox_repository.dart';
import '../../core/utils/logger.dart';
import '../db/database.dart';
import '../imap/imap_client_factory.dart';
import '../jmap/jmap_client.dart';
import 'package:sharedinbox/core/models/account.dart' as account_model;
import 'package:sharedinbox/core/models/mailbox.dart' as model;
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/core/repositories/mailbox_repository.dart';
import 'package:sharedinbox/core/utils/logger.dart';
import 'package:sharedinbox/data/db/database.dart';
import 'package:sharedinbox/data/imap/imap_client_factory.dart';
import 'package:sharedinbox/data/jmap/jmap_client.dart';
class MailboxRepositoryImpl implements MailboxRepository {
MailboxRepositoryImpl(
@@ -1,7 +1,7 @@
import 'package:drift/drift.dart';
import '../../core/repositories/sync_log_repository.dart';
import '../db/database.dart';
import 'package:sharedinbox/core/repositories/sync_log_repository.dart';
import 'package:sharedinbox/data/db/database.dart';
class SyncLogRepositoryImpl implements SyncLogRepository {
SyncLogRepositoryImpl(this._db);
@@ -1,6 +1,6 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../../core/storage/secure_storage.dart';
import 'package:sharedinbox/core/storage/secure_storage.dart';
class FlutterSecureStorageImpl implements SecureStorage {
const FlutterSecureStorageImpl();
+17 -17
View File
@@ -1,23 +1,23 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'core/models/account.dart' as model;
import 'core/repositories/account_repository.dart';
import 'core/repositories/draft_repository.dart';
import 'core/repositories/email_repository.dart';
import 'core/repositories/mailbox_repository.dart';
import 'core/services/account_discovery_service.dart';
import 'core/services/connection_test_service.dart';
import 'core/storage/secure_storage.dart';
import 'core/sync/account_sync_manager.dart';
import 'data/db/database.dart';
import 'data/jmap/sieve_repository.dart';
import 'data/repositories/account_repository_impl.dart';
import 'data/repositories/draft_repository_impl.dart';
import 'data/repositories/email_repository_impl.dart';
import 'data/repositories/mailbox_repository_impl.dart';
import 'data/repositories/sync_log_repository_impl.dart';
import 'data/storage/flutter_secure_storage_impl.dart';
import 'package:sharedinbox/core/models/account.dart' as model;
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/core/repositories/draft_repository.dart';
import 'package:sharedinbox/core/repositories/email_repository.dart';
import 'package:sharedinbox/core/repositories/mailbox_repository.dart';
import 'package:sharedinbox/core/services/account_discovery_service.dart';
import 'package:sharedinbox/core/services/connection_test_service.dart';
import 'package:sharedinbox/core/storage/secure_storage.dart';
import 'package:sharedinbox/core/sync/account_sync_manager.dart';
import 'package:sharedinbox/data/db/database.dart';
import 'package:sharedinbox/data/jmap/sieve_repository.dart';
import 'package:sharedinbox/data/repositories/account_repository_impl.dart';
import 'package:sharedinbox/data/repositories/draft_repository_impl.dart';
import 'package:sharedinbox/data/repositories/email_repository_impl.dart';
import 'package:sharedinbox/data/repositories/mailbox_repository_impl.dart';
import 'package:sharedinbox/data/repositories/sync_log_repository_impl.dart';
import 'package:sharedinbox/data/storage/flutter_secure_storage_impl.dart';
final dbProvider = Provider<AppDatabase>((ref) {
final db = AppDatabase();
+2 -2
View File
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'di.dart';
import 'ui/router.dart';
import 'package:sharedinbox/di.dart';
import 'package:sharedinbox/ui/router.dart';
void main({List<Override> overrides = const []}) {
runApp(ProviderScope(overrides: overrides, child: const SharedInboxApp()));
+14 -14
View File
@@ -1,20 +1,20 @@
import 'package:go_router/go_router.dart';
import '../core/models/sieve_script.dart';
import 'package:sharedinbox/core/models/sieve_script.dart';
import 'screens/account_list_screen.dart';
import 'screens/add_account_screen.dart';
import 'screens/address_emails_screen.dart';
import 'screens/compose_screen.dart';
import 'screens/edit_account_screen.dart';
import 'screens/email_detail_screen.dart';
import 'screens/email_list_screen.dart';
import 'screens/mailbox_list_screen.dart';
import 'screens/search_screen.dart';
import 'screens/sieve_script_edit_screen.dart';
import 'screens/sieve_scripts_screen.dart';
import 'screens/sync_log_screen.dart';
import 'screens/thread_detail_screen.dart';
import 'package:sharedinbox/ui/screens/account_list_screen.dart';
import 'package:sharedinbox/ui/screens/add_account_screen.dart';
import 'package:sharedinbox/ui/screens/address_emails_screen.dart';
import 'package:sharedinbox/ui/screens/compose_screen.dart';
import 'package:sharedinbox/ui/screens/edit_account_screen.dart';
import 'package:sharedinbox/ui/screens/email_detail_screen.dart';
import 'package:sharedinbox/ui/screens/email_list_screen.dart';
import 'package:sharedinbox/ui/screens/mailbox_list_screen.dart';
import 'package:sharedinbox/ui/screens/search_screen.dart';
import 'package:sharedinbox/ui/screens/sieve_script_edit_screen.dart';
import 'package:sharedinbox/ui/screens/sieve_scripts_screen.dart';
import 'package:sharedinbox/ui/screens/sync_log_screen.dart';
import 'package:sharedinbox/ui/screens/thread_detail_screen.dart';
final router = GoRouter(
initialLocation: '/accounts',
+2 -2
View File
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/account.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/di.dart';
class AccountListScreen extends ConsumerWidget {
const AccountListScreen({super.key});
+4 -4
View File
@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/account.dart';
import '../../core/models/discovery_result.dart';
import '../../core/utils/logger.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/discovery_result.dart';
import 'package:sharedinbox/core/utils/logger.dart';
import 'package:sharedinbox/di.dart';
enum _Step { email, detecting, chooseType, jmapForm, imapForm, connecting }
+2 -2
View File
@@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/email.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/di.dart';
class AddressEmailsScreen extends ConsumerStatefulWidget {
const AddressEmailsScreen({
+5 -5
View File
@@ -8,11 +8,11 @@ import 'package:go_router/go_router.dart';
import 'package:mime/mime.dart';
import 'package:open_filex/open_filex.dart';
import '../../core/models/account.dart';
import '../../core/models/email.dart';
import '../../core/repositories/draft_repository.dart';
import '../../core/utils/format_utils.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/core/repositories/draft_repository.dart';
import 'package:sharedinbox/core/utils/format_utils.dart';
import 'package:sharedinbox/di.dart';
class ComposeScreen extends ConsumerStatefulWidget {
const ComposeScreen({
+2 -2
View File
@@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/account.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/di.dart';
class EditAccountScreen extends ConsumerStatefulWidget {
const EditAccountScreen({super.key, required this.accountId});
+4 -4
View File
@@ -6,10 +6,10 @@ import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:open_filex/open_filex.dart';
import '../../core/models/email.dart';
import '../../core/utils/format_utils.dart';
import '../../core/utils/html_utils.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/core/utils/format_utils.dart';
import 'package:sharedinbox/core/utils/html_utils.dart';
import 'package:sharedinbox/di.dart';
final _dateFmt = DateFormat('EEE, MMM d yyyy, HH:mm');
+5 -5
View File
@@ -3,11 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import '../../core/models/account.dart';
import '../../core/models/email.dart';
import '../../core/repositories/email_repository.dart';
import '../../di.dart';
import '../widgets/folder_drawer.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/core/repositories/email_repository.dart';
import 'package:sharedinbox/di.dart';
import 'package:sharedinbox/ui/widgets/folder_drawer.dart';
final _dateFmt = DateFormat('MMM d');
+4 -4
View File
@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/email.dart';
import '../../core/repositories/email_repository.dart';
import '../../di.dart';
import '../widgets/folder_drawer.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/core/repositories/email_repository.dart';
import 'package:sharedinbox/di.dart';
import 'package:sharedinbox/ui/widgets/folder_drawer.dart';
class MailboxListScreen extends ConsumerWidget {
const MailboxListScreen({super.key, required this.accountId});
+5 -5
View File
@@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/email.dart';
import '../../core/models/mailbox.dart';
import '../../core/utils/logger.dart';
import '../../di.dart';
import '../widgets/folder_drawer.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/core/models/mailbox.dart';
import 'package:sharedinbox/core/utils/logger.dart';
import 'package:sharedinbox/di.dart';
import 'package:sharedinbox/ui/widgets/folder_drawer.dart';
class SearchScreen extends ConsumerStatefulWidget {
const SearchScreen({super.key, required this.accountId});
+2 -2
View File
@@ -3,8 +3,8 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/models/sieve_script.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/sieve_script.dart';
import 'package:sharedinbox/di.dart';
class SieveScriptEditScreen extends ConsumerStatefulWidget {
const SieveScriptEditScreen({
+2 -2
View File
@@ -4,8 +4,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/sieve_script.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/sieve_script.dart';
import 'package:sharedinbox/di.dart';
class SieveScriptsScreen extends ConsumerStatefulWidget {
const SieveScriptsScreen({super.key, required this.accountId});
+2 -2
View File
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
import '../../core/repositories/sync_log_repository.dart';
import '../../di.dart';
import 'package:sharedinbox/core/repositories/sync_log_repository.dart';
import 'package:sharedinbox/di.dart';
final _timeFmt = DateFormat('MMM d, HH:mm:ss');
+2 -2
View File
@@ -3,8 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import '../../core/models/email.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/di.dart';
final _dateFmt = DateFormat('MMM d');
+2 -2
View File
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/models/mailbox.dart';
import '../../di.dart';
import 'package:sharedinbox/core/models/mailbox.dart';
import 'package:sharedinbox/di.dart';
/// Sorts INBOX first, Drafts second, then alphabetically.
int compareMailboxes(Mailbox a, Mailbox b) {