diff --git a/mobile/analysis_options.yaml b/mobile/analysis_options.yaml index fb5d96697b2e9..065b3d56d85b5 100644 --- a/mobile/analysis_options.yaml +++ b/mobile/analysis_options.yaml @@ -26,52 +26,59 @@ linter: # producing the lint. rules: - # Formatting - avoid_print: true - require_trailing_commas: true - unrelated_type_equality_checks: true - prefer_const_constructors: true - always_use_package_imports: true - always_put_control_body_on_new_line: true - unnecessary_null_checks: true - unnecessary_parenthesis: true - prefer_final_locals: true - prefer_const_declarations: true - prefer_const_literals_to_create_immutables: true - use_super_parameters: true - directives_ordering: true - no_leading_underscores_for_local_identifiers: true + # Correctness always_declare_return_types: true + avoid_type_to_string: true + avoid_unused_constructor_parameters: true avoid_void_async: true - noop_primitive_operations: true - use_named_constants: true - combinators_ordering: true - avoid_multiple_declarations_per_line: true - unnecessary_breaks: true - - # Correctness - no_adjacent_strings_in_list: true cancel_subscriptions: true + cast_nullable_to_non_nullable: true close_sinks: true - unawaited_futures: true + collection_methods_unrelated_type: true + deprecated_consistency: true discarded_futures: true + no_adjacent_strings_in_list: true no_self_assignments: true + noop_primitive_operations: true + only_throw_errors: true + parameter_assignments: true throw_in_finally: true - collection_methods_unrelated_type: true - cast_nullable_to_non_nullable: true + tighten_type_of_initializing_formals: true + unawaited_futures: true + unnecessary_ignore: true + unnecessary_null_checks: true + unnecessary_statements: true + unrelated_type_equality_checks: true - # Known issues + # Performance avoid_slow_async_io: true - avoid_type_to_string: true + prefer_const_constructors: true + prefer_const_declarations: true + prefer_const_literals_to_create_immutables: true # Flutter specific - use_build_context_synchronously: true + avoid_unnecessary_containers: true sized_box_for_whitespace: true + use_build_context_synchronously: true use_colored_box: true use_decorated_box: true - avoid_unnecessary_containers: true use_full_hex_values_for_flutter_colors: true + # Style + always_put_control_body_on_new_line: true + always_use_package_imports: true + avoid_multiple_declarations_per_line: true + avoid_print: true + combinators_ordering: true + directives_ordering: true + no_leading_underscores_for_local_identifiers: true + prefer_final_locals: true + require_trailing_commas: true + unnecessary_breaks: true + unnecessary_parenthesis: true + use_named_constants: true + use_super_parameters: true + # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options analyzer: diff --git a/mobile/lib/domain/models/memory.model.dart b/mobile/lib/domain/models/memory.model.dart index a75a4a4f0f698..1c556f382f04e 100644 --- a/mobile/lib/domain/models/memory.model.dart +++ b/mobile/lib/domain/models/memory.model.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/mobile/lib/domain/models/user.model.dart b/mobile/lib/domain/models/user.model.dart index 96e07137c98a3..181fddf581147 100644 --- a/mobile/lib/domain/models/user.model.dart +++ b/mobile/lib/domain/models/user.model.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:ui'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/mobile/lib/models/download/download_state.model.dart b/mobile/lib/models/download/download_state.model.dart index 7e47d60969f8a..5f04fcdfd4779 100644 --- a/mobile/lib/models/download/download_state.model.dart +++ b/mobile/lib/models/download/download_state.model.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first import 'package:background_downloader/background_downloader.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/mobile/lib/models/download/livephotos_medatada.model.dart b/mobile/lib/models/download/livephotos_medatada.model.dart index 228ad707da797..833a9ffca77c6 100644 --- a/mobile/lib/models/download/livephotos_medatada.model.dart +++ b/mobile/lib/models/download/livephotos_medatada.model.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; enum LivePhotosPart { video, image } diff --git a/mobile/lib/models/search/search_filter.model.dart b/mobile/lib/models/search/search_filter.model.dart index a9cc13ba6a196..03660204b92e4 100644 --- a/mobile/lib/models/search/search_filter.model.dart +++ b/mobile/lib/models/search/search_filter.model.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/mobile/lib/models/upload/share_intent_attachment.model.dart b/mobile/lib/models/upload/share_intent_attachment.model.dart index 0f9c3e4c29804..3643020bc8984 100644 --- a/mobile/lib/models/upload/share_intent_attachment.model.dart +++ b/mobile/lib/models/upload/share_intent_attachment.model.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; import 'dart:io'; diff --git a/mobile/lib/presentation/pages/drift_people_collection.page.dart b/mobile/lib/presentation/pages/drift_people_collection.page.dart index 569cb99b01d6b..92f1ff79ca629 100644 --- a/mobile/lib/presentation/pages/drift_people_collection.page.dart +++ b/mobile/lib/presentation/pages/drift_people_collection.page.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/domain/models/person.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/string_extensions.dart'; import 'package:immich_mobile/generated/translations.g.dart'; @@ -65,12 +66,15 @@ class _DriftPeopleCollectionPageState extends ConsumerState filtered; if (_search != null) { - people = people.where((person) { + filtered = people.where((person) { return person.name.toLowerCase().removeDiacritics().contains( _search!.toLowerCase().removeDiacritics(), ); }).toList(); + } else { + filtered = people; } return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( @@ -79,9 +83,9 @@ class _DriftPeopleCollectionPageState extends ConsumerState filtered; if (search.value != null) { - places = places.where((place) { + filtered = places.where((place) { return place.$1.toLowerCase().contains(search.value!.toLowerCase()); }).toList(); + } else { + filtered = places; } return SliverList.builder( - itemCount: places.length, + itemCount: filtered.length, itemBuilder: (context, index) { - final place = places[index]; + final place = filtered[index]; return _PlaceTile(place: place); }, ); diff --git a/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart b/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart index 2bafdc08438be..eb8ce1815a84f 100644 --- a/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart +++ b/mobile/lib/presentation/widgets/memory/memory_bottom_info.widget.dart @@ -1,5 +1,3 @@ -// ignore_for_file: require_trailing_commas - import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:immich_mobile/domain/models/events.model.dart'; diff --git a/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart b/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart index eb081a1e6a39b..a2298313ace72 100644 --- a/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart +++ b/mobile/lib/presentation/widgets/timeline/scrubber.widget.dart @@ -38,7 +38,6 @@ class Scrubber extends ConsumerStatefulWidget { Scrubber({ super.key, - Key? scrollThumbKey, required this.layoutSegments, required this.timelineHeight, this.topPadding = 0, diff --git a/mobile/lib/providers/backup/backup_album.provider.dart b/mobile/lib/providers/backup/backup_album.provider.dart index 25a4204928c84..5d167224186d9 100644 --- a/mobile/lib/providers/backup/backup_album.provider.dart +++ b/mobile/lib/providers/backup/backup_album.provider.dart @@ -22,40 +22,25 @@ class BackupAlbumNotifier extends StateNotifier> { } Future selectAlbum(LocalAlbum album) async { - album = album.copyWith(backupSelection: BackupSelection.selected); - await _localAlbumService.update(album); + final selectedAlbum = album.copyWith(backupSelection: BackupSelection.selected); + await _localAlbumService.update(selectedAlbum); - state = state - .map( - (currentAlbum) => currentAlbum.id == album.id - ? currentAlbum.copyWith(backupSelection: BackupSelection.selected) - : currentAlbum, - ) - .toList(); + state = state.map((currentAlbum) => currentAlbum.id == selectedAlbum.id ? selectedAlbum : currentAlbum).toList(); } Future deselectAlbum(LocalAlbum album) async { - album = album.copyWith(backupSelection: BackupSelection.none); - await _localAlbumService.update(album); + final deselectedAlbum = album.copyWith(backupSelection: BackupSelection.none); + await _localAlbumService.update(deselectedAlbum); state = state - .map( - (currentAlbum) => - currentAlbum.id == album.id ? currentAlbum.copyWith(backupSelection: BackupSelection.none) : currentAlbum, - ) + .map((currentAlbum) => currentAlbum.id == deselectedAlbum.id ? deselectedAlbum : currentAlbum) .toList(); } Future excludeAlbum(LocalAlbum album) async { - album = album.copyWith(backupSelection: BackupSelection.excluded); - await _localAlbumService.update(album); + final excludedAlbum = album.copyWith(backupSelection: BackupSelection.excluded); + await _localAlbumService.update(excludedAlbum); - state = state - .map( - (currentAlbum) => currentAlbum.id == album.id - ? currentAlbum.copyWith(backupSelection: BackupSelection.excluded) - : currentAlbum, - ) - .toList(); + state = state.map((currentAlbum) => currentAlbum.id == excludedAlbum.id ? excludedAlbum : currentAlbum).toList(); } } diff --git a/mobile/lib/routing/router.dart b/mobile/lib/routing/router.dart index 15d32192a0286..1d6455782c190 100644 --- a/mobile/lib/routing/router.dart +++ b/mobile/lib/routing/router.dart @@ -71,7 +71,6 @@ import 'package:immich_mobile/presentation/pages/profile/profile_picture_crop.pa import 'package:immich_mobile/presentation/pages/search/drift_search.page.dart'; import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.page.dart'; import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/providers/gallery_permission.provider.dart'; import 'package:immich_mobile/routing/auth_guard.dart'; import 'package:immich_mobile/routing/duplicate_guard.dart'; import 'package:immich_mobile/routing/locked_guard.dart'; @@ -88,7 +87,6 @@ final appRouterProvider = Provider( (ref) => AppRouter( ref.watch(apiServiceProvider), ref.watch(authServiceProvider), - ref.watch(galleryPermissionNotifier.notifier), ref.watch(secureStorageServiceProvider), ref.watch(localAuthServiceProvider), ), @@ -103,7 +101,6 @@ class AppRouter extends RootStackRouter { AppRouter( ApiService apiService, AuthService authService, - GalleryPermissionNotifier galleryPermissionNotifier, SecureStorageService secureStorageService, LocalAuthService localAuthService, ) { diff --git a/mobile/lib/services/api.service.dart b/mobile/lib/services/api.service.dart index f5e4c5c33e11f..d1aec9cc86fd9 100644 --- a/mobile/lib/services/api.service.dart +++ b/mobile/lib/services/api.service.dart @@ -113,12 +113,10 @@ class ApiService { } Future _isEndpointAvailable(String serverUrl) async { - if (!serverUrl.endsWith('/api')) { - serverUrl += '/api'; - } + final endpoint = serverUrl.endsWith('/api') ? serverUrl : '$serverUrl/api'; try { - setEndpoint(serverUrl); + setEndpoint(endpoint); await serverInfoApi.pingServer().timeout(const Duration(seconds: 5)); } on TimeoutException catch (_) { return false; diff --git a/mobile/lib/widgets/photo_view/photo_view_gallery.dart b/mobile/lib/widgets/photo_view/photo_view_gallery.dart index aa33d18403779..3c41b2ca19f42 100644 --- a/mobile/lib/widgets/photo_view/photo_view_gallery.dart +++ b/mobile/lib/widgets/photo_view/photo_view_gallery.dart @@ -128,8 +128,8 @@ class PhotoViewGallery extends StatefulWidget { /// The builder must return a [PhotoViewGalleryPageOptions]. const PhotoViewGallery.builder({ super.key, - required this.itemCount, - required this.builder, + required int this.itemCount, + required PhotoViewGalleryBuilder this.builder, this.loadingBuilder, this.backgroundDecoration, this.wantKeepAlive = false, @@ -145,9 +145,7 @@ class PhotoViewGallery extends StatefulWidget { this.customSize, this.allowImplicitScrolling = false, this.enablePanAlways = false, - }) : pageOptions = null, - assert(itemCount != null), - assert(builder != null); + }) : pageOptions = null; /// A list of options to describe the items in the gallery final List? pageOptions; @@ -352,9 +350,9 @@ class _PhotoViewGalleryState extends State { /// The [maxScale], [minScale] and [initialScale] options may be [double] or a [PhotoViewComputedScale] constant /// class PhotoViewGalleryPageOptions { - PhotoViewGalleryPageOptions({ + const PhotoViewGalleryPageOptions({ this.key, - required this.imageProvider, + required ImageProvider this.imageProvider, this.heroAttributes, this.semanticLabel, this.minScale, @@ -379,8 +377,7 @@ class PhotoViewGalleryPageOptions { this.disableGestures, this.errorBuilder, }) : child = null, - childSize = null, - assert(imageProvider != null); + childSize = null; const PhotoViewGalleryPageOptions.customChild({ this.key, diff --git a/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart b/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart index 7b55e0e37e254..8f408e043efa2 100644 --- a/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart +++ b/mobile/lib/widgets/photo_view/src/core/photo_view_gesture_detector.dart @@ -121,7 +121,6 @@ class PhotoViewGestureRecognizer extends ScaleGestureRecognizer { super.debugOwner, this.validateAxis, this.touchSlopFactor = 1, - PointerDeviceKind? kind, this.disableScaleGestures = false, }) : super(supportedDevices: null); final HitCornersDetector? hitDetector; diff --git a/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart b/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart index d120955250cf5..c1ee1ab769bf9 100644 --- a/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart +++ b/mobile/lib/widgets/photo_view/src/utils/photo_view_utils.dart @@ -32,12 +32,10 @@ class ScaleBoundaries { double get minScale { assert(_minScale is double || _minScale is PhotoViewComputedScale); if (_minScale == PhotoViewComputedScale.contained) { - return _scaleForContained(outerSize, childSize) * - (_minScale as PhotoViewComputedScale).multiplier; // ignore: avoid_as + return _scaleForContained(outerSize, childSize) * (_minScale as PhotoViewComputedScale).multiplier; } if (_minScale == PhotoViewComputedScale.covered) { - return _scaleForCovering(outerSize, childSize) * - (_minScale as PhotoViewComputedScale).multiplier; // ignore: avoid_as + return _scaleForCovering(outerSize, childSize) * (_minScale as PhotoViewComputedScale).multiplier; } assert(_minScale >= 0.0); return _minScale; @@ -46,16 +44,16 @@ class ScaleBoundaries { double get maxScale { assert(_maxScale is double || _maxScale is PhotoViewComputedScale); if (_maxScale == PhotoViewComputedScale.contained) { - return (_scaleForContained(outerSize, childSize) * - (_maxScale as PhotoViewComputedScale) // ignore: avoid_as - .multiplier) - .clamp(minScale, double.infinity); + return (_scaleForContained(outerSize, childSize) * (_maxScale as PhotoViewComputedScale).multiplier).clamp( + minScale, + double.infinity, + ); } if (_maxScale == PhotoViewComputedScale.covered) { - return (_scaleForCovering(outerSize, childSize) * - (_maxScale as PhotoViewComputedScale) // ignore: avoid_as - .multiplier) - .clamp(minScale, double.infinity); + return (_scaleForCovering(outerSize, childSize) * (_maxScale as PhotoViewComputedScale).multiplier).clamp( + minScale, + double.infinity, + ); } return _maxScale.clamp(minScale, double.infinity); } @@ -63,14 +61,10 @@ class ScaleBoundaries { double get initialScale { assert(_initialScale is double || _initialScale is PhotoViewComputedScale); if (_initialScale == PhotoViewComputedScale.contained) { - return _scaleForContained(outerSize, childSize) * - (_initialScale as PhotoViewComputedScale) // ignore: avoid_as - .multiplier; + return _scaleForContained(outerSize, childSize) * (_initialScale as PhotoViewComputedScale).multiplier; } if (_initialScale == PhotoViewComputedScale.covered) { - return _scaleForCovering(outerSize, childSize) * - (_initialScale as PhotoViewComputedScale) // ignore: avoid_as - .multiplier; + return _scaleForCovering(outerSize, childSize) * (_initialScale as PhotoViewComputedScale).multiplier; } return _initialScale.clamp(minScale, maxScale); } diff --git a/mobile/test/drift/main/migration_test.dart b/mobile/test/drift/main/migration_test.dart index 74467492ae92f..ce3f644b98852 100644 --- a/mobile/test/drift/main/migration_test.dart +++ b/mobile/test/drift/main/migration_test.dart @@ -1,5 +1,5 @@ // dart format width=80 -// ignore_for_file: unused_local_variable, unused_import +// ignore_for_file: unused_import import 'package:drift/drift.dart'; import 'package:drift_dev/api/migrations_native.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/mobile/test/unit/factories/local_album_factory.dart b/mobile/test/unit/factories/local_album_factory.dart index 447001f971275..639237c858175 100644 --- a/mobile/test/unit/factories/local_album_factory.dart +++ b/mobile/test/unit/factories/local_album_factory.dart @@ -14,10 +14,10 @@ class LocalAlbumFactory { String? linkedRemoteAlbumId, int? assetCount, }) { - id = TestUtils.uuid(id); + final albumId = TestUtils.uuid(id); return LocalAlbum( - id: id, - name: name ?? 'local_album_$id', + id: albumId, + name: name ?? 'local_album_$albumId', updatedAt: TestUtils.date(updatedAt), backupSelection: backupSelection ?? .none, isIosSharedAlbum: isIosSharedAlbum ?? false, diff --git a/mobile/test/unit/factories/local_asset_factory.dart b/mobile/test/unit/factories/local_asset_factory.dart index bebe24e5b934b..5b16635d48125 100644 --- a/mobile/test/unit/factories/local_asset_factory.dart +++ b/mobile/test/unit/factories/local_asset_factory.dart @@ -6,11 +6,11 @@ class LocalAssetFactory { const LocalAssetFactory(); static LocalAsset create({String? id, String? name, String? remoteId}) { - id = TestUtils.uuid(id); + final assetId = TestUtils.uuid(id); return LocalAsset( - id: id, - name: name ?? 'local_$id.jpg', + id: assetId, + name: name ?? 'local_$assetId.jpg', remoteId: remoteId, type: AssetType.image, createdAt: TestUtils.yesterday(), diff --git a/mobile/test/unit/factories/partner_user_factory.dart b/mobile/test/unit/factories/partner_user_factory.dart index 63f94608ad0f3..2ee0fa07735c3 100644 --- a/mobile/test/unit/factories/partner_user_factory.dart +++ b/mobile/test/unit/factories/partner_user_factory.dart @@ -6,11 +6,11 @@ class PartnerFactory { const PartnerFactory(); static Partner create({String? id, String? email, String? name, bool? inTimeline}) { - id = TestUtils.uuid(id); + final partnerId = TestUtils.uuid(id); return Partner( - id: id, - email: email ?? '$id@test.com', - name: name ?? 'user_$id', + id: partnerId, + email: email ?? '$partnerId@test.com', + name: name ?? 'user_$partnerId', inTimeline: inTimeline ?? false, hasProfileImage: false, profileChangedAt: DateTime.now(), diff --git a/mobile/test/unit/factories/remote_album_factory.dart b/mobile/test/unit/factories/remote_album_factory.dart index bffe62b651b6f..70976b4485f99 100644 --- a/mobile/test/unit/factories/remote_album_factory.dart +++ b/mobile/test/unit/factories/remote_album_factory.dart @@ -19,10 +19,10 @@ class RemoteAlbumFactory { String? ownerName, bool isShared = false, }) { - id = TestUtils.uuid(id); + final albumId = TestUtils.uuid(id); return RemoteAlbum( - id: id, - name: name ?? 'remote_album_$id', + id: albumId, + name: name ?? 'remote_album_$albumId', ownerId: TestUtils.uuid(ownerId), description: description ?? '', createdAt: TestUtils.date(createdAt), @@ -31,7 +31,7 @@ class RemoteAlbumFactory { isActivityEnabled: isActivityEnabled, order: order, assetCount: assetCount, - ownerName: ownerName ?? 'owner_$id', + ownerName: ownerName ?? 'owner_$albumId', isShared: isShared, ); } diff --git a/mobile/test/unit/factories/remote_asset_factory.dart b/mobile/test/unit/factories/remote_asset_factory.dart index 0876b9d793a5d..2936708ab43d8 100644 --- a/mobile/test/unit/factories/remote_asset_factory.dart +++ b/mobile/test/unit/factories/remote_asset_factory.dart @@ -16,13 +16,13 @@ class RemoteAssetFactory { DateTime? deletedAt, String? localId, }) { - id = TestUtils.uuid(id); + final assetId = TestUtils.uuid(id); return RemoteAsset( - id: id, - name: name ?? 'remote_$id.jpg', + id: assetId, + name: name ?? 'remote_$assetId.jpg', ownerId: TestUtils.uuid(ownerId), - checksum: 'checksum-$id', + checksum: 'checksum-$assetId', type: type, createdAt: TestUtils.yesterday(), updatedAt: TestUtils.now(), diff --git a/mobile/test/unit/factories/user_factory.dart b/mobile/test/unit/factories/user_factory.dart index 248e98dc6915e..d3df9556efa08 100644 --- a/mobile/test/unit/factories/user_factory.dart +++ b/mobile/test/unit/factories/user_factory.dart @@ -13,11 +13,11 @@ class UserFactory { bool? hasProfileImage, AvatarColor? avatarColor, }) { - id = TestUtils.uuid(id); + final userId = TestUtils.uuid(id); return User( - id: id, - name: name ?? 'user_$id', - email: email ?? '$id@test.com', + id: userId, + name: name ?? 'user_$userId', + email: email ?? '$userId@test.com', profileChangedAt: TestUtils.date(profileChangedAt), hasProfileImage: hasProfileImage ?? false, avatarColor: avatarColor ?? .primary, @@ -32,11 +32,11 @@ class UserFactory { bool? hasProfileImage, AvatarColor? avatarColor, }) { - id = TestUtils.uuid(id); + final userId = TestUtils.uuid(id); return UserDto( - id: id, - name: name ?? 'user_$id', - email: email ?? '$id@test.com', + id: userId, + name: name ?? 'user_$userId', + email: email ?? '$userId@test.com', profileChangedAt: TestUtils.date(profileChangedAt), hasProfileImage: hasProfileImage ?? false, avatarColor: avatarColor ?? .primary,