chore: more dart lints

The lints are regrouped and sorted. Also, added the following new lints:
- unnecessary_ignore
- parameter_assignments
- avoid_unused_constructor_parameters
- tighten_type_of_initializing_formals
- only_throw_errors
- deprecated_consistency
- unnecessary_statements
This commit is contained in:
shenlong-tanwen 2026-08-09 12:11:58 +05:30 committed by GitHub
parent 2099ebe945
commit 86da77693a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 112 additions and 137 deletions

View file

@ -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
# Correctness
always_declare_return_types: true
avoid_type_to_string: true
avoid_unused_constructor_parameters: true
avoid_void_async: true
cancel_subscriptions: true
cast_nullable_to_non_nullable: true
close_sinks: 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
tighten_type_of_initializing_formals: true
unawaited_futures: true
unnecessary_ignore: true
unnecessary_null_checks: true
unnecessary_parenthesis: true
prefer_final_locals: true
unnecessary_statements: true
unrelated_type_equality_checks: true
# Performance
avoid_slow_async_io: true
prefer_const_constructors: 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
always_declare_return_types: 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
close_sinks: true
unawaited_futures: true
discarded_futures: true
no_self_assignments: true
throw_in_finally: true
collection_methods_unrelated_type: true
cast_nullable_to_non_nullable: true
# Known issues
avoid_slow_async_io: true
avoid_type_to_string: 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:

View file

@ -1,4 +1,3 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';

View file

@ -1,4 +1,3 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:ui';
import 'package:freezed_annotation/freezed_annotation.dart';

View file

@ -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';

View file

@ -1,4 +1,3 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
enum LivePhotosPart { video, image }

View file

@ -1,4 +1,3 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';

View file

@ -1,4 +1,3 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'dart:io';

View file

@ -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<DriftPeopleCollectio
body: SafeArea(
child: people.when(
data: (people) {
final List<Person> 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<DriftPeopleCollectio
mainAxisSpacing: isPortrait && isTablet ? 36 : 0,
),
padding: const EdgeInsets.symmetric(vertical: 32),
itemCount: people.length,
itemCount: filtered.length,
itemBuilder: (context, index) {
final person = people[index];
final person = filtered[index];
return Column(
key: ValueKey(person.id),

View file

@ -134,16 +134,19 @@ class _PlaceList extends ConsumerWidget {
),
),
data: (places) {
final List<(String, String)> 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);
},
);

View file

@ -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';

View file

@ -38,7 +38,6 @@ class Scrubber extends ConsumerStatefulWidget {
Scrubber({
super.key,
Key? scrollThumbKey,
required this.layoutSegments,
required this.timelineHeight,
this.topPadding = 0,

View file

@ -22,40 +22,25 @@ class BackupAlbumNotifier extends StateNotifier<List<LocalAlbum>> {
}
Future<void> 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<void> 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<void> 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();
}
}

View file

@ -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,
) {

View file

@ -113,12 +113,10 @@ class ApiService {
}
Future<bool> _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;

View file

@ -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<PhotoViewGalleryPageOptions>? pageOptions;
@ -352,9 +350,9 @@ class _PhotoViewGalleryState extends State<PhotoViewGallery> {
/// 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,

View file

@ -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;

View file

@ -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);
}

View file

@ -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';

View file

@ -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,

View file

@ -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(),

View file

@ -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(),

View file

@ -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,
);
}

View file

@ -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(),

View file

@ -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,