From b890440f6b43742c2331ce8e9c97e53c4af569a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Tollk=C3=B6tter?= <1518021+atollk@users.noreply.github.com> Date: Mon, 9 Jun 2025 18:09:02 +0200 Subject: [PATCH] feat(mobile): enabled DCM (#17957) * enable DCM in CI * chore: up version * chore: up version --------- Co-authored-by: Alex --- .github/workflows/static_analysis.yml | 12 + mobile/README.md | 21 ++ mobile/analysis_options.yaml | 243 ++++++++++++------ mobile/dcm_global.yaml | 1 + mobile/lib/constants/filters.dart | 68 ++--- mobile/lib/main.dart | 1 - .../models/backup/available_album.model.dart | 3 - mobile/lib/models/map/map_event.model.dart | 2 - .../lib/pages/common/gallery_viewer.page.dart | 4 +- .../pages/dev/feat_in_development.page.dart | 4 - .../pages/dev/media_stat.page.dart | 2 - mobile/lib/providers/api.provider.dart | 2 +- mobile/lib/providers/api.provider.g.dart | 2 +- .../lib/providers/app_settings.provider.dart | 2 +- .../providers/app_settings.provider.g.dart | 2 +- .../asset_viewer/asset_stack.provider.dart | 2 +- .../asset_viewer/asset_stack.provider.g.dart | 155 +---------- .../asset_viewer/download.provider.dart | 2 +- .../lib/providers/immich_logo_provider.dart | 2 +- .../lib/providers/immich_logo_provider.g.dart | 2 +- mobile/lib/services/background.service.dart | 3 - .../services/backup_verification.service.dart | 6 +- mobile/lib/services/hash.service.dart | 2 - mobile/lib/utils/migration.dart | 2 - mobile/lib/utils/selection_handlers.dart | 7 +- .../widgets/asset_grid/asset_drag_region.dart | 4 +- .../lib/widgets/asset_grid/delete_dialog.dart | 2 - .../asset_grid/draggable_scrollbar.dart | 8 +- .../widgets/asset_grid/thumbnail_image.dart | 4 +- .../asset_viewer/bottom_gallery_bar.dart | 1 - .../widgets/asset_viewer/gallery_app_bar.dart | 2 +- .../widgets/common/thumbhash_placeholder.dart | 3 +- .../src/core/photo_view_hit_corners.dart | 7 +- 33 files changed, 271 insertions(+), 312 deletions(-) create mode 100644 mobile/dcm_global.yaml diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 754c0c38b3..62e84ac957 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -58,6 +58,14 @@ jobs: run: dart pub get working-directory: ./mobile + - name: Install DCM + run: | + sudo apt-get update + wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg + echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list + sudo apt-get update + sudo apt-get install dcm + - name: Generate translation file run: make translation working-directory: ./mobile @@ -100,6 +108,10 @@ jobs: run: dart run custom_lint working-directory: ./mobile + - name: Run DCM + run: dcm analyze lib + working-directory: ./mobile + zizmor: name: zizmor runs-on: ubuntu-latest diff --git a/mobile/README.md b/mobile/README.md index fb82b4de0c..436b0a4c34 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -17,6 +17,27 @@ To add a new translation text, enter the key-value pair in the `i18n/en.json` in make translation ``` +## Static Analysis + +The following checks of static analysis must pass for a contribution to the mobile app to be valid: + +```bash +dart format lib +dart analyze +dart run custom_lint +dcm analyze lib +``` + +[DCM](https://dcm.dev/) is a vendor tool that needs to be downloaded manually to run locally. +Immich was provided an open source license. +To use it, it is important that you do not have an active free tier license (can be verified with `dcm license`). +If you have write-access to the Immich repository directly, running dcm in your clone should just work. +If you are working on a clone of a fork, you need to connect to the main Immich repository as remote first: + +```bash +git remote add immich git@github.com:immich-app/immich.git +``` + ## Immich-Flutter Directory Structure Below are the directory inside the `lib` directory: diff --git a/mobile/analysis_options.yaml b/mobile/analysis_options.yaml index 4c06edc8c9..b338b7b758 100644 --- a/mobile/analysis_options.yaml +++ b/mobile/analysis_options.yaml @@ -128,82 +128,169 @@ custom_lint: - test/**.dart dart_code_metrics: - extends: - - recommended rules: - # Common - - arguments-ordering: - last: - - child - - children - - avoid-accessing-other-classes-private-members - - avoid-assigning-to-static-field - - avoid-assignments-as-conditions - - avoid-async-call-in-sync-function - - avoid-collapsible-if - - avoid-collection-equality-checks - - avoid-complex-loop-conditions - - avoid-declaring-call-method - - avoid-extensions-on-records - - avoid-function-type-in-records - - avoid-future-ignore - - avoid-global-state - - avoid-inverted-boolean-checks - - avoid-late-final-reassignment - - avoid-local-functions: - exclude: - - test/**.dart - - avoid-negated-conditions - - avoid-nested-streams-and-futures - - avoid-referencing-subclasses - - avoid-unnecessary-continue - - avoid-unnecessary-nullable-return-type: false - - binary-expression-operand-order - - pattern-fields-ordering - - prefer-abstract-final-static-class - - prefer-commenting-future-delayed - - prefer-early-return - - prefer-first - - prefer-immediate-return - - prefer-last - - prefer-simpler-boolean-expressions - - prefer-switch-expression - - prefer-type-over-var - - use-existing-destructuring - - use-existing-variable - # Flutter - - avoid-border-all - - avoid-complex-arithmetic-expressions - - avoid-expanded-as-spacer - - avoid-if-with-many-branches - - avoid-inherited-widget-in-initstate - - avoid-late-context - - avoid-returning-widgets - - avoid-shrink-wrap-in-lists - - avoid-single-child-column-or-row - - avoid-stateless-widget-initialized-fields - - avoid-wrapping-in-padding - - prefer-align-over-container - - prefer-const-border-radius - - prefer-correct-callback-field-name: false - - prefer-correct-edge-insets-constructor - - prefer-define-hero-tag - - prefer-extracting-callbacks - - prefer-for-loop-in-children - - prefer-match-file-name: false - - prefer-sliver-prefix - - prefer-spacing - - prefer-text-rich - - prefer-transform-over-container - - prefer-using-list-view - - prefer-widget-private-members: - ignore-static: true - - use-closest-build-context - # riverpod - - avoid-calling-notifier-members-inside-build - - avoid-notifier-constructors - - avoid-ref-read-inside-build - - avoid-ref-watch-outside-build - - avoid-unnecessary-consumer-widgets - - dispose-provided-instances - - use-ref-read-synchronously + # All rules from "recommended" preset + # Show potential errors + # - avoid-cascade-after-if-null + # - avoid-collection-methods-with-unrelated-types + # - avoid-duplicate-exports + # - avoid-dynamic + # - avoid-missing-enum-constant-in-map + # - avoid-passing-async-when-sync-expected + # - avoid-throw-in-catch-block + - avoid-unused-parameters + # - avoid-unnecessary-type-assertions + # - avoid-unnecessary-type-casts + # - avoid-unrelated-type-assertions + # - avoid-unrelated-type-casts + # - no-empty-block + # - no-equal-then-else + # - prefer-correct-test-file-name + # - prefer-match-file-name + # - prefer-return-await + # - avoid-self-assignment + # - avoid-self-compare + # - avoid-shadowing + # - prefer-iterable-of + # - no-equal-switch-case + # - no-equal-conditions + # - avoid-equal-expressions + # - avoid-missed-calls + # - avoid-unnecessary-negations + # - avoid-unused-generics + # - function-always-returns-null + # - avoid-throw-objects-without-tostring + # - avoid-unsafe-collection-methods + # - prefer-wildcard-pattern + # - no-equal-switch-expression-cases + # - avoid-future-tostring + # - avoid-unassigned-late-fields + # - avoid-nested-futures + # - avoid-generics-shadowing + # - prefer-parentheses-with-if-null + # - no-equal-nested-conditions + # - avoid-shadowed-extension-methods + # - avoid-unnecessary-conditionals + # - avoid-double-slash-imports + # - avoid-map-keys-contains + # - prefer-correct-json-casts + # - avoid-duplicate-mixins + # - avoid-nullable-interpolation + # - avoid-unused-instances + # - prefer-correct-for-loop-increment + # - prefer-public-exception-classes + # - avoid-uncaught-future-errors + # - always-remove-listener + # - avoid-unnecessary-setstate + # - check-for-equals-in-render-object-setters + # - consistent-update-render-object + # - use-setstate-synchronously + # - avoid-incomplete-copy-with + # - proper-super-calls + # - dispose-fields + # - avoid-empty-setstate + # - avoid-state-constructors + # - avoid-recursive-widget-calls + # - avoid-missing-image-alt + # - avoid-passing-self-as-argument + # - avoid-unnecessary-if + # - avoid-unconditional-break + # - avoid-referencing-discarded-variables + # - avoid-unnecessary-local-late + # - avoid-wildcard-cases-with-enums + # - match-getter-setter-field-names + # - avoid-accessing-collections-by-constant-index + # - prefer-unique-test-names + # - avoid-duplicate-cascades + # - prefer-specific-cases-first + # - avoid-duplicate-switch-case-conditions + # - prefer-explicit-function-type + # - avoid-misused-test-matchers + # - avoid-duplicate-test-assertions + # - prefer-switch-with-enums + # - prefer-any-or-every + # - avoid-duplicate-map-keys + # - avoid-nullable-tostring + # - avoid-undisposed-instances + # - avoid-duplicate-initializers + # - avoid-unassigned-stream-subscriptions + # - avoid-empty-test-groups + # - avoid-not-encodable-in-to-json + # - avoid-contradictory-expressions + # - avoid-excessive-expressions + # - prefer-private-extension-type-field + # - avoid-renaming-representation-getters + # - avoid-empty-spread + # - avoid-unnecessary-gesture-detector + # - avoid-missing-completer-stack-trace + # - avoid-casting-to-extension-type + # - prefer-overriding-parent-equality + # - avoid-missing-controller + # - avoid-unknown-pragma + # - avoid-conditions-with-boolean-literals + # - avoid-multi-assignment + # - avoid-collection-equality-checks + # - avoid-only-rethrow + # - avoid-incorrect-image-opacity + # - avoid-misused-set-literals + # - dispose-class-fields + # - avoid-suspicious-super-overrides + # - avoid-assignments-as-conditions + # - avoid-unused-assignment + # - avoid-unnecessary-overrides + # - avoid-implicitly-nullable-extension-types + # Enable with the next release + # - avoid-late-final-reassignment + # - avoid-duplicate-constant-values + # - function-always-returns-same-value + # - avoid-flexible-outside-flex + # - avoid-unnecessary-patterns + # - use-closest-build-context + # - avoid-commented-out-code + # - avoid-recursive-tostring + # - avoid-enum-values-by-index + # - avoid-constant-assert-conditions + # - avoid-inconsistent-digit-separators + # - pass-existing-future-to-future-builder + # - pass-existing-stream-to-stream-builder + + # Code simplification + # - avoid-redundant-async + # - avoid-redundant-else + # - avoid-unnecessary-nullable-return-type + # - avoid-redundant-pragma-inline + # - avoid-nested-records + # - avoid-redundant-positional-field-name + # - avoid-explicit-pattern-field-name + # - prefer-simpler-patterns-null-check + # - avoid-unnecessary-return + # - avoid-duplicate-patterns + # - avoid-keywords-in-wildcard-pattern + # - avoid-unnecessary-futures + # - avoid-unnecessary-reassignment + # - avoid-unnecessary-call + # - avoid-unnecessary-stateful-widgets + # - prefer-dedicated-media-query-methods + # - avoid-unnecessary-overrides-in-state + # - move-variable-closer-to-its-usage + # - avoid-nullable-parameters-with-default-values + # - prefer-null-aware-spread + # - avoid-inferrable-type-arguments + # - avoid-unnecessary-super + # - avoid-unnecessary-collections + # - avoid-unnecessary-extends + # - avoid-unnecessary-enum-arguments + # - prefer-contains + # Enable with the next release + # - prefer-simpler-boolean-expressions + # - prefer-spacing + # - avoid-unnecessary-continue + # - avoid-unnecessary-compare-to + + # Style + # - prefer-trailing-comma + # - unnecessary-trailing-comma + # - prefer-declaring-const-constructor + # - prefer-single-widget-per-file + # - prefer-prefixed-global-constants + # - prefer-correct-callback-field-name diff --git a/mobile/dcm_global.yaml b/mobile/dcm_global.yaml new file mode 100644 index 0000000000..d2465e64b6 --- /dev/null +++ b/mobile/dcm_global.yaml @@ -0,0 +1 @@ +version: '>=1.29.0 <1.30.0' diff --git a/mobile/lib/constants/filters.dart b/mobile/lib/constants/filters.dart index d9fa2920b7..61597f08d1 100644 --- a/mobile/lib/constants/filters.dart +++ b/mobile/lib/constants/filters.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; -List filters = [ +const List filters = [ //Original - const ColorFilter.matrix([ + ColorFilter.matrix([ 1, 0, 0, @@ -25,7 +25,7 @@ List filters = [ 0, ]), //Vintage - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.8, 0.1, 0.1, @@ -48,7 +48,7 @@ List filters = [ 0, ]), //Mood - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.2, 0.1, 0.1, @@ -71,7 +71,7 @@ List filters = [ 0, ]), //Crisp - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.2, 0, 0, @@ -94,7 +94,7 @@ List filters = [ 0, ]), //Cool - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.9, 0, 0.2, @@ -117,7 +117,7 @@ List filters = [ 0, ]), //Blush - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.1, 0.1, 0.1, @@ -140,7 +140,7 @@ List filters = [ 0, ]), //Sunkissed - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.3, 0, 0.1, @@ -163,7 +163,7 @@ List filters = [ 0, ]), //Fresh - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.2, 0, 0, @@ -186,7 +186,7 @@ List filters = [ 0, ]), //Classic - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.1, 0, -0.1, @@ -209,7 +209,7 @@ List filters = [ 0, ]), //Lomo-ish - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.5, 0, 0.1, @@ -232,7 +232,7 @@ List filters = [ 0, ]), //Nashville - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.2, 0.15, -0.15, @@ -255,7 +255,7 @@ List filters = [ 0, ]), //Valencia - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.15, 0.1, 0.1, @@ -278,7 +278,7 @@ List filters = [ 0, ]), //Clarendon - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.2, 0, 0, @@ -301,7 +301,7 @@ List filters = [ 0, ]), //Moon - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.33, 0.33, 0.33, @@ -324,7 +324,7 @@ List filters = [ 0, ]), //Willow - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.5, 0.5, 0.5, @@ -347,7 +347,7 @@ List filters = [ 0, ]), //Kodak - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.3, 0.1, -0.1, @@ -370,7 +370,7 @@ List filters = [ 0, ]), //Frost - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.8, 0.2, 0.1, @@ -393,7 +393,7 @@ List filters = [ 0, ]), //Night Vision - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.1, 0.95, 0.2, @@ -416,7 +416,7 @@ List filters = [ 0, ]), //Sunset - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.5, 0.2, 0, @@ -439,7 +439,7 @@ List filters = [ 0, ]), //Noir - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.3, -0.3, 0.1, @@ -462,7 +462,7 @@ List filters = [ 0, ]), //Dreamy - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.1, 0.1, 0.1, @@ -485,7 +485,7 @@ List filters = [ 0, ]), //Sepia - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.393, 0.769, 0.189, @@ -508,7 +508,7 @@ List filters = [ 0, ]), //Radium - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.438, -0.062, -0.062, @@ -531,7 +531,7 @@ List filters = [ 0, ]), //Aqua - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.2126, 0.7152, 0.0722, @@ -554,7 +554,7 @@ List filters = [ 0, ]), //Purple Haze - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.3, 0, 1.2, @@ -577,7 +577,7 @@ List filters = [ 0, ]), //Lemonade - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.2, 0.1, 0, @@ -600,7 +600,7 @@ List filters = [ 0, ]), //Caramel - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.6, 0.2, 0, @@ -623,7 +623,7 @@ List filters = [ 0, ]), //Peachy - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.3, 0.5, 0, @@ -646,7 +646,7 @@ List filters = [ 0, ]), //Neon - const ColorFilter.matrix([ + ColorFilter.matrix([ 1, 0, 1, @@ -669,7 +669,7 @@ List filters = [ 0, ]), //Cold Morning - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.9, 0.1, 0.2, @@ -692,7 +692,7 @@ List filters = [ 0, ]), //Lush - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.9, 0.2, 0, @@ -715,7 +715,7 @@ List filters = [ 0, ]), //Urban Neon - const ColorFilter.matrix([ + ColorFilter.matrix([ 1.1, 0, 0.3, @@ -738,7 +738,7 @@ List filters = [ 0, ]), //Monochrome - const ColorFilter.matrix([ + ColorFilter.matrix([ 0.6, 0.2, 0.2, diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index ae87c0f3ae..bc9edcd46e 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -229,7 +229,6 @@ class ImmichAppState extends ConsumerState } } -// ignore: prefer-single-widget-per-file class MainWidget extends StatelessWidget { const MainWidget({super.key}); diff --git a/mobile/lib/models/backup/available_album.model.dart b/mobile/lib/models/backup/available_album.model.dart index 59c57582ce..c75d6446d8 100644 --- a/mobile/lib/models/backup/available_album.model.dart +++ b/mobile/lib/models/backup/available_album.model.dart @@ -1,5 +1,3 @@ -import 'dart:typed_data'; - import 'package:immich_mobile/entities/album.entity.dart'; class AvailableAlbum { @@ -16,7 +14,6 @@ class AvailableAlbum { Album? album, int? assetCount, DateTime? lastBackup, - Uint8List? thumbnailData, }) { return AvailableAlbum( album: album ?? this.album, diff --git a/mobile/lib/models/map/map_event.model.dart b/mobile/lib/models/map/map_event.model.dart index 0baeefeceb..dd9fec06e6 100644 --- a/mobile/lib/models/map/map_event.model.dart +++ b/mobile/lib/models/map/map_event.model.dart @@ -1,5 +1,3 @@ -// ignore_for_file: add-copy-with - sealed class MapEvent { const MapEvent(); } diff --git a/mobile/lib/pages/common/gallery_viewer.page.dart b/mobile/lib/pages/common/gallery_viewer.page.dart index 09dac353fb..77b734ce0b 100644 --- a/mobile/lib/pages/common/gallery_viewer.page.dart +++ b/mobile/lib/pages/common/gallery_viewer.page.dart @@ -236,7 +236,7 @@ class GalleryViewerPage extends HookConsumerWidget { }); }); - PhotoViewGalleryPageOptions buildImage(BuildContext context, Asset asset) { + PhotoViewGalleryPageOptions buildImage(Asset asset) { return PhotoViewGalleryPageOptions( onDragStart: (_, details, __) { localPosition.value = details.localPosition; @@ -312,7 +312,7 @@ class GalleryViewerPage extends HookConsumerWidget { } if (newAsset.isImage && !isPlayingMotionVideo) { - return buildImage(context, newAsset); + return buildImage(newAsset); } return buildVideo(context, newAsset); } diff --git a/mobile/lib/presentation/pages/dev/feat_in_development.page.dart b/mobile/lib/presentation/pages/dev/feat_in_development.page.dart index 0e532375d0..08ead96e82 100644 --- a/mobile/lib/presentation/pages/dev/feat_in_development.page.dart +++ b/mobile/lib/presentation/pages/dev/feat_in_development.page.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid-local-functions - import 'dart:async'; import 'package:auto_route/auto_route.dart'; @@ -144,7 +142,6 @@ class _Feature { final Future Function(BuildContext, WidgetRef _) onTap; } -// ignore: prefer-single-widget-per-file class _DevLogs extends StatelessWidget { const _DevLogs(); @@ -172,7 +169,6 @@ class _DevLogs extends StatelessWidget { builder: (_, logMessages) { return ListView.separated( itemBuilder: (ctx, index) { - // ignore: avoid-unsafe-collection-methods final logMessage = logMessages.data![index]; return ListTile( title: Text( diff --git a/mobile/lib/presentation/pages/dev/media_stat.page.dart b/mobile/lib/presentation/pages/dev/media_stat.page.dart index 4a1562900e..360506e691 100644 --- a/mobile/lib/presentation/pages/dev/media_stat.page.dart +++ b/mobile/lib/presentation/pages/dev/media_stat.page.dart @@ -1,5 +1,3 @@ -// ignore_for_file: prefer-single-widget-per-file - import 'package:auto_route/auto_route.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; diff --git a/mobile/lib/providers/api.provider.dart b/mobile/lib/providers/api.provider.dart index a994dacf2f..a54496d94c 100644 --- a/mobile/lib/providers/api.provider.dart +++ b/mobile/lib/providers/api.provider.dart @@ -5,4 +5,4 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'api.provider.g.dart'; @Riverpod(keepAlive: true) -ApiService apiService(Ref ref) => ApiService(); +ApiService apiService(Ref _) => ApiService(); diff --git a/mobile/lib/providers/api.provider.g.dart b/mobile/lib/providers/api.provider.g.dart index 76ccb4ad6d..8a6f514ce6 100644 --- a/mobile/lib/providers/api.provider.g.dart +++ b/mobile/lib/providers/api.provider.g.dart @@ -6,7 +6,7 @@ part of 'api.provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$apiServiceHash() => r'93a7e3b4d3004741abc3061c4688239c3a72f9c4'; +String _$apiServiceHash() => r'187a7de59b064fab1104c23717f18ce0ae3e426c'; /// See also [apiService]. @ProviderFor(apiService) diff --git a/mobile/lib/providers/app_settings.provider.dart b/mobile/lib/providers/app_settings.provider.dart index 81c5c8e201..2d4bdd0eef 100644 --- a/mobile/lib/providers/app_settings.provider.dart +++ b/mobile/lib/providers/app_settings.provider.dart @@ -5,4 +5,4 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'app_settings.provider.g.dart'; @Riverpod(keepAlive: true) -AppSettingsService appSettingsService(Ref ref) => AppSettingsService(); +AppSettingsService appSettingsService(Ref _) => AppSettingsService(); diff --git a/mobile/lib/providers/app_settings.provider.g.dart b/mobile/lib/providers/app_settings.provider.g.dart index 88cab49c1b..66814abd49 100644 --- a/mobile/lib/providers/app_settings.provider.g.dart +++ b/mobile/lib/providers/app_settings.provider.g.dart @@ -7,7 +7,7 @@ part of 'app_settings.provider.dart'; // ************************************************************************** String _$appSettingsServiceHash() => - r'3736e0d384ec7b1f896938589656dd6eb1552d60'; + r'2aa16d76a8df869c39486325efc1d08b2d2c284c'; /// See also [appSettingsService]. @ProviderFor(appSettingsService) diff --git a/mobile/lib/providers/asset_viewer/asset_stack.provider.dart b/mobile/lib/providers/asset_viewer/asset_stack.provider.dart index 0edefde526..9bbbfb49aa 100644 --- a/mobile/lib/providers/asset_viewer/asset_stack.provider.dart +++ b/mobile/lib/providers/asset_viewer/asset_stack.provider.dart @@ -39,6 +39,6 @@ final assetStackStateProvider = StateNotifierProvider.autoDispose ); @riverpod -int assetStackIndex(Ref ref, Asset asset) { +int assetStackIndex(Ref _) { return -1; } diff --git a/mobile/lib/providers/asset_viewer/asset_stack.provider.g.dart b/mobile/lib/providers/asset_viewer/asset_stack.provider.g.dart index 5d4051b285..dcf82cdebd 100644 --- a/mobile/lib/providers/asset_viewer/asset_stack.provider.g.dart +++ b/mobile/lib/providers/asset_viewer/asset_stack.provider.g.dart @@ -6,155 +6,22 @@ part of 'asset_stack.provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$assetStackIndexHash() => r'38b4b0116e3e4592620b118ae01cf89b77da9cfe'; - -/// Copied from Dart SDK -class _SystemHash { - _SystemHash._(); - - static int combine(int hash, int value) { - // ignore: parameter_assignments - hash = 0x1fffffff & (hash + value); - // ignore: parameter_assignments - hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); - return hash ^ (hash >> 6); - } - - static int finish(int hash) { - // ignore: parameter_assignments - hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); - // ignore: parameter_assignments - hash = hash ^ (hash >> 11); - return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); - } -} +String _$assetStackIndexHash() => r'086ddb782e3eb38b80d755666fe35be8fe7322d7'; /// See also [assetStackIndex]. @ProviderFor(assetStackIndex) -const assetStackIndexProvider = AssetStackIndexFamily(); - -/// See also [assetStackIndex]. -class AssetStackIndexFamily extends Family { - /// See also [assetStackIndex]. - const AssetStackIndexFamily(); - - /// See also [assetStackIndex]. - AssetStackIndexProvider call( - Asset asset, - ) { - return AssetStackIndexProvider( - asset, - ); - } - - @override - AssetStackIndexProvider getProviderOverride( - covariant AssetStackIndexProvider provider, - ) { - return call( - provider.asset, - ); - } - - static const Iterable? _dependencies = null; - - @override - Iterable? get dependencies => _dependencies; - - static const Iterable? _allTransitiveDependencies = null; - - @override - Iterable? get allTransitiveDependencies => - _allTransitiveDependencies; - - @override - String? get name => r'assetStackIndexProvider'; -} - -/// See also [assetStackIndex]. -class AssetStackIndexProvider extends AutoDisposeProvider { - /// See also [assetStackIndex]. - AssetStackIndexProvider( - Asset asset, - ) : this._internal( - (ref) => assetStackIndex( - ref as AssetStackIndexRef, - asset, - ), - from: assetStackIndexProvider, - name: r'assetStackIndexProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$assetStackIndexHash, - dependencies: AssetStackIndexFamily._dependencies, - allTransitiveDependencies: - AssetStackIndexFamily._allTransitiveDependencies, - asset: asset, - ); - - AssetStackIndexProvider._internal( - super._createNotifier, { - required super.name, - required super.dependencies, - required super.allTransitiveDependencies, - required super.debugGetCreateSourceHash, - required super.from, - required this.asset, - }) : super.internal(); - - final Asset asset; - - @override - Override overrideWith( - int Function(AssetStackIndexRef provider) create, - ) { - return ProviderOverride( - origin: this, - override: AssetStackIndexProvider._internal( - (ref) => create(ref as AssetStackIndexRef), - from: from, - name: null, - dependencies: null, - allTransitiveDependencies: null, - debugGetCreateSourceHash: null, - asset: asset, - ), - ); - } - - @override - AutoDisposeProviderElement createElement() { - return _AssetStackIndexProviderElement(this); - } - - @override - bool operator ==(Object other) { - return other is AssetStackIndexProvider && other.asset == asset; - } - - @override - int get hashCode { - var hash = _SystemHash.combine(0, runtimeType.hashCode); - hash = _SystemHash.combine(hash, asset.hashCode); - - return _SystemHash.finish(hash); - } -} +final assetStackIndexProvider = AutoDisposeProvider.internal( + assetStackIndex, + name: r'assetStackIndexProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$assetStackIndexHash, + dependencies: null, + allTransitiveDependencies: null, +); @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element -mixin AssetStackIndexRef on AutoDisposeProviderRef { - /// The parameter `asset` of this provider. - Asset get asset; -} - -class _AssetStackIndexProviderElement extends AutoDisposeProviderElement - with AssetStackIndexRef { - _AssetStackIndexProviderElement(super.provider); - - @override - Asset get asset => (origin as AssetStackIndexProvider).asset; -} +typedef AssetStackIndexRef = AutoDisposeProviderRef; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/mobile/lib/providers/asset_viewer/download.provider.dart b/mobile/lib/providers/asset_viewer/download.provider.dart index f539a14a82..3daed6f686 100644 --- a/mobile/lib/providers/asset_viewer/download.provider.dart +++ b/mobile/lib/providers/asset_viewer/download.provider.dart @@ -144,7 +144,7 @@ class DownloadStateNotifier extends StateNotifier { return await _downloadService.downloadAll(assets); } - void downloadAsset(Asset asset, BuildContext context) async { + void downloadAsset(Asset asset) async { await _downloadService.download(asset); } diff --git a/mobile/lib/providers/immich_logo_provider.dart b/mobile/lib/providers/immich_logo_provider.dart index a52aba5f9e..b24294fc2e 100644 --- a/mobile/lib/providers/immich_logo_provider.dart +++ b/mobile/lib/providers/immich_logo_provider.dart @@ -7,7 +7,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'immich_logo_provider.g.dart'; @riverpod -Future immichLogo(Ref ref) async { +Future immichLogo(Ref _) async { final json = await rootBundle.loadString('assets/immich-logo.json'); final j = jsonDecode(json); return base64Decode(j['content']); diff --git a/mobile/lib/providers/immich_logo_provider.g.dart b/mobile/lib/providers/immich_logo_provider.g.dart index 0889e60fda..90b117d574 100644 --- a/mobile/lib/providers/immich_logo_provider.g.dart +++ b/mobile/lib/providers/immich_logo_provider.g.dart @@ -6,7 +6,7 @@ part of 'immich_logo_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$immichLogoHash() => r'6f23d217c44279537b7edee1ca80ebf47f69a4d0'; +String _$immichLogoHash() => r'6de7fcca1ef9acef6ab7398eb0c664080747e0ea'; /// See also [immichLogo]. @ProviderFor(immichLogo) diff --git a/mobile/lib/services/background.service.dart b/mobile/lib/services/background.service.dart index 335f71acab..4c4a9b1cff 100644 --- a/mobile/lib/services/background.service.dart +++ b/mobile/lib/services/background.service.dart @@ -18,7 +18,6 @@ import 'package:immich_mobile/interfaces/backup_album.interface.dart'; import 'package:immich_mobile/models/backup/backup_candidate.model.dart'; import 'package:immich_mobile/models/backup/current_upload_asset.model.dart'; import 'package:immich_mobile/models/backup/error_upload_asset.model.dart'; -import 'package:immich_mobile/models/backup/success_upload_asset.model.dart'; import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/providers/db.provider.dart'; @@ -489,7 +488,6 @@ class BackgroundService { _cancellationToken!, pmProgressHandler: pmProgressHandler, onSuccess: (result) => _onAssetUploaded( - result: result, shouldNotify: notifyTotalProgress, ), onProgress: (bytes, totalBytes) => @@ -511,7 +509,6 @@ class BackgroundService { } void _onAssetUploaded({ - required SuccessUploadAsset result, bool shouldNotify = false, }) async { if (!shouldNotify) { diff --git a/mobile/lib/services/backup_verification.service.dart b/mobile/lib/services/backup_verification.service.dart index 9aa021a324..408ac51d74 100644 --- a/mobile/lib/services/backup_verification.service.dart +++ b/mobile/lib/services/backup_verification.service.dart @@ -184,10 +184,10 @@ class BackupVerificationService { // for images: make sure they are pixel-wise identical // (skip first few KBs containing metadata) final Uint64List localImage = - _fakeDecodeImg(local, await file.readAsBytes()); + _fakeDecodeImg(await file.readAsBytes()); final res = await apiService.assetsApi .downloadAssetWithHttpInfo(remote.remoteId!); - final Uint64List remoteImage = _fakeDecodeImg(remote, res.bodyBytes); + final Uint64List remoteImage = _fakeDecodeImg(res.bodyBytes); final eq = const ListEquality().equals(remoteImage, localImage); return eq; @@ -198,7 +198,7 @@ class BackupVerificationService { return false; } - static Uint64List _fakeDecodeImg(Asset asset, Uint8List bytes) { + static Uint64List _fakeDecodeImg(Uint8List bytes) { const headerLength = 131072; // assume header is at most 128 KB final start = bytes.length < headerLength * 2 ? (bytes.length ~/ (4 * 8)) * 8 diff --git a/mobile/lib/services/hash.service.dart b/mobile/lib/services/hash.service.dart index ca2b0ee37e..f8a09471e4 100644 --- a/mobile/lib/services/hash.service.dart +++ b/mobile/lib/services/hash.service.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid-unsafe-collection-methods - import 'dart:convert'; import 'dart:io'; diff --git a/mobile/lib/utils/migration.dart b/mobile/lib/utils/migration.dart index a31e441b1f..52c2fc2306 100644 --- a/mobile/lib/utils/migration.dart +++ b/mobile/lib/utils/migration.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid-unsafe-collection-methods - import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/mobile/lib/utils/selection_handlers.dart b/mobile/lib/utils/selection_handlers.dart index fe6da80663..e22076aae9 100644 --- a/mobile/lib/utils/selection_handlers.dart +++ b/mobile/lib/utils/selection_handlers.dart @@ -94,7 +94,7 @@ Future handleFavoriteAssets( ImmichToast.show( context: context, msg: toastMessage, - gravity: ToastGravity.BOTTOM, + gravity: toastGravity, ); } } @@ -164,9 +164,8 @@ Future handleSetAssetsVisibility( WidgetRef ref, BuildContext context, AssetVisibilityEnum visibility, - List selection, { - ToastGravity toastGravity = ToastGravity.BOTTOM, -}) async { + List selection, +) async { if (selection.isNotEmpty) { await ref .watch(assetProvider.notifier) diff --git a/mobile/lib/widgets/asset_grid/asset_drag_region.dart b/mobile/lib/widgets/asset_grid/asset_drag_region.dart index d66220f1ab..6335a1d64d 100644 --- a/mobile/lib/widgets/asset_grid/asset_drag_region.dart +++ b/mobile/lib/widgets/asset_grid/asset_drag_region.dart @@ -1,4 +1,3 @@ -// ignore_for_file: library_private_types_in_public_api // Based on https://stackoverflow.com/a/52625182 import 'dart:async'; @@ -164,7 +163,6 @@ class _CustomLongPressGestureRecognizer extends LongPressGestureRecognizer { } } -// ignore: prefer-single-widget-per-file class AssetIndexWrapper extends SingleChildRenderObjectWidget { final int rowIndex; final int sectionIndex; @@ -177,6 +175,7 @@ class AssetIndexWrapper extends SingleChildRenderObjectWidget { }); @override + // ignore: library_private_types_in_public_api _AssetIndexProxy createRenderObject(BuildContext context) { return _AssetIndexProxy( index: AssetIndex(rowIndex: rowIndex, sectionIndex: sectionIndex), @@ -186,6 +185,7 @@ class AssetIndexWrapper extends SingleChildRenderObjectWidget { @override void updateRenderObject( BuildContext context, + // ignore: library_private_types_in_public_api _AssetIndexProxy renderObject, ) { renderObject.index = diff --git a/mobile/lib/widgets/asset_grid/delete_dialog.dart b/mobile/lib/widgets/asset_grid/delete_dialog.dart index 601f7a5e46..ecfb4130dc 100644 --- a/mobile/lib/widgets/asset_grid/delete_dialog.dart +++ b/mobile/lib/widgets/asset_grid/delete_dialog.dart @@ -1,5 +1,3 @@ -// ignore_for_file: prefer-single-widget-per-file - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; diff --git a/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart b/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart index 8bb45eeb7d..6eddf58adb 100644 --- a/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart +++ b/mobile/lib/widgets/asset_grid/draggable_scrollbar.dart @@ -80,8 +80,7 @@ class DraggableScrollbar extends StatefulWidget { this.labelTextBuilder, this.labelConstraints, }) : assert(child.scrollDirection == Axis.vertical), - scrollThumbBuilder = - _thumbRRectBuilder(scrollThumbKey, alwaysVisibleScrollThumb); + scrollThumbBuilder = _thumbRRectBuilder(alwaysVisibleScrollThumb); DraggableScrollbar.arrows({ super.key, @@ -97,8 +96,7 @@ class DraggableScrollbar extends StatefulWidget { this.labelTextBuilder, this.labelConstraints, }) : assert(child.scrollDirection == Axis.vertical), - scrollThumbBuilder = - _thumbArrowBuilder(scrollThumbKey, alwaysVisibleScrollThumb); + scrollThumbBuilder = _thumbArrowBuilder(alwaysVisibleScrollThumb); DraggableScrollbar.semicircle({ super.key, @@ -201,7 +199,6 @@ class DraggableScrollbar extends StatefulWidget { } static ScrollThumbBuilder _thumbArrowBuilder( - Key? scrollThumbKey, bool alwaysVisibleScrollThumb, ) { return ( @@ -239,7 +236,6 @@ class DraggableScrollbar extends StatefulWidget { } static ScrollThumbBuilder _thumbRRectBuilder( - Key? scrollThumbKey, bool alwaysVisibleScrollThumb, ) { return ( diff --git a/mobile/lib/widgets/asset_grid/thumbnail_image.dart b/mobile/lib/widgets/asset_grid/thumbnail_image.dart index d25b7a3e90..25f65b448c 100644 --- a/mobile/lib/widgets/asset_grid/thumbnail_image.dart +++ b/mobile/lib/widgets/asset_grid/thumbnail_image.dart @@ -48,7 +48,7 @@ class ThumbnailImage extends ConsumerWidget { // Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id final isFromDto = asset.id == noDbId; - Widget buildSelectionIcon(Asset asset) { + Widget buildSelectionIcon() { if (isSelected) { return Container( decoration: BoxDecoration( @@ -233,7 +233,7 @@ class ThumbnailImage extends ConsumerWidget { padding: const EdgeInsets.all(3.0), child: Align( alignment: Alignment.topLeft, - child: buildSelectionIcon(asset), + child: buildSelectionIcon(), ), ), ], diff --git a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart index 1ff8596c43..59d97bf0c7 100644 --- a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart +++ b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart @@ -235,7 +235,6 @@ class BottomGalleryBar extends ConsumerWidget { ref.read(downloadStateProvider.notifier).downloadAsset( asset, - context, ); } diff --git a/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart b/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart index 4354dceb4f..4ef55f4f76 100644 --- a/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart +++ b/mobile/lib/widgets/asset_viewer/gallery_app_bar.dart @@ -96,7 +96,7 @@ class GalleryAppBar extends ConsumerWidget { } handleDownloadAsset() { - ref.read(downloadStateProvider.notifier).downloadAsset(asset, context); + ref.read(downloadStateProvider.notifier).downloadAsset(asset); } handleLocateAsset() async { diff --git a/mobile/lib/widgets/common/thumbhash_placeholder.dart b/mobile/lib/widgets/common/thumbhash_placeholder.dart index 1f303c67c8..aa320f4230 100644 --- a/mobile/lib/widgets/common/thumbhash_placeholder.dart +++ b/mobile/lib/widgets/common/thumbhash_placeholder.dart @@ -13,7 +13,8 @@ OctoSet blurHashOrPlaceholder( }) { return OctoSet( placeholderBuilder: blurHashPlaceholderBuilder(blurhash, fit: fit), - errorBuilder: blurHashErrorBuilder(blurhash, fit: fit), + errorBuilder: + blurHashErrorBuilder(blurhash, fit: fit, message: errorMessage), ); } diff --git a/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart b/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart index b12b9a7634..768e5d9cc7 100644 --- a/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart +++ b/mobile/lib/widgets/photo_view/src/core/photo_view_hit_corners.dart @@ -28,7 +28,6 @@ mixin HitCornersDetector on PhotoViewControllerDelegate { bool _shouldMoveAxis( HitCorners hitCorners, double mainAxisMove, - double crossAxisMove, ) { if (mainAxisMove == 0) { return false; @@ -47,17 +46,15 @@ mixin HitCornersDetector on PhotoViewControllerDelegate { bool _shouldMoveX(Offset move) { final hitCornersX = _hitCornersX(); final mainAxisMove = move.dx; - final crossAxisMove = move.dy; - return _shouldMoveAxis(hitCornersX, mainAxisMove, crossAxisMove); + return _shouldMoveAxis(hitCornersX, mainAxisMove); } bool _shouldMoveY(Offset move) { final hitCornersY = _hitCornersY(); final mainAxisMove = move.dy; - final crossAxisMove = move.dx; - return _shouldMoveAxis(hitCornersY, mainAxisMove, crossAxisMove); + return _shouldMoveAxis(hitCornersY, mainAxisMove); } bool shouldMove(Offset move, Axis mainAxis) {