浏览代码

chore(mobile): Run dart analyze in CI (#1425)

* Run dart analyze in CI

* Add pub get

* Fix linter errors in mobile code
Matthias Rupp 2 年之前
父节点
当前提交
bcb0056b55

+ 31 - 0
.github/workflows/static_analysis.yml

@@ -0,0 +1,31 @@
+name: Static Code Analysis
+on:
+  workflow_dispatch:
+  pull_request:
+  push:
+    branches: [main]
+
+jobs:
+  mobile-dart-analyze:
+    name: Run Dart Code Analysis
+
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v3
+
+      - name: Setup Flutter SDK
+        uses: subosito/flutter-action@v2
+        with:
+          channel: 'stable'
+          flutter-version: '3.3.10'
+
+      - name: Install dependencies
+        run: dart pub get
+        working-directory: ./mobile
+
+      - name: Run dart analyze
+        run: dart analyze --fatal-infos
+        working-directory: ./mobile
+

+ 3 - 4
mobile/integration_test/module_login/login_input_validation_test.dart

@@ -2,7 +2,6 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter_test/flutter_test.dart';
 
 import '../test_utils/general_helper.dart';
-import '../test_utils/login_helper.dart';
 
 void main() async {
   await ImmichTestHelper.initialize();
@@ -13,7 +12,7 @@ void main() async {
       await helper.loginHelper.acknowledgeNewServerVersion();
 
       await helper.loginHelper.enterCredentials(
-        email: " demo@immich.app"
+        email: " demo@immich.app",
       );
 
       await tester.pump(const Duration(milliseconds: 300));
@@ -21,7 +20,7 @@ void main() async {
       expect(find.text("login_form_err_leading_whitespace".tr()), findsOneWidget);
 
       await helper.loginHelper.enterCredentials(
-          email: "demo@immich.app "
+          email: "demo@immich.app ",
       );
 
       await tester.pump(const Duration(milliseconds: 300));
@@ -34,7 +33,7 @@ void main() async {
       await helper.loginHelper.acknowledgeNewServerVersion();
 
       await helper.loginHelper.enterCredentials(
-          email: "demo.immich.app"
+          email: "demo.immich.app",
       );
 
       await tester.pump(const Duration(milliseconds: 300));

+ 9 - 7
mobile/integration_test/module_login/login_test.dart

@@ -1,5 +1,3 @@
-import 'dart:io';
-
 import 'package:flutter_test/flutter_test.dart';
 
 import '../test_utils/general_helper.dart';
@@ -12,8 +10,9 @@ void main() async {
     immichWidgetTest("Test correct credentials", (tester, helper) async {
       await helper.loginHelper.waitForLoginScreen();
       await helper.loginHelper.acknowledgeNewServerVersion();
-      await helper.loginHelper
-          .enterCredentialsOf(LoginCredentials.testInstance);
+      await helper.loginHelper.enterCredentialsOf(
+        LoginCredentials.testInstance,
+      );
       await helper.loginHelper.pressLoginButton();
       await helper.loginHelper.assertLoginSuccess();
     });
@@ -22,16 +21,19 @@ void main() async {
       await helper.loginHelper.waitForLoginScreen();
       await helper.loginHelper.acknowledgeNewServerVersion();
       await helper.loginHelper.enterCredentialsOf(
-          LoginCredentials.testInstanceButWithWrongPassword);
+        LoginCredentials.testInstanceButWithWrongPassword,
+      );
       await helper.loginHelper.pressLoginButton();
       await helper.loginHelper.assertLoginFailed();
     });
 
-    immichWidgetTest("Test login with wrong server URL", (tester, helper) async {
+    immichWidgetTest("Test login with wrong server URL",
+        (tester, helper) async {
       await helper.loginHelper.waitForLoginScreen();
       await helper.loginHelper.acknowledgeNewServerVersion();
       await helper.loginHelper.enterCredentialsOf(
-          LoginCredentials.wrongInstanceUrl);
+        LoginCredentials.wrongInstanceUrl,
+      );
       await helper.loginHelper.pressLoginButton();
       await helper.loginHelper.assertLoginFailed();
     });

+ 14 - 13
mobile/integration_test/test_utils/general_helper.dart

@@ -1,17 +1,14 @@
-
 import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/foundation.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:hive/hive.dart';
-import 'package:immich_mobile/main.dart';
 import 'package:integration_test/integration_test.dart';
+// ignore: depend_on_referenced_packages
 import 'package:meta/meta.dart';
 import 'package:immich_mobile/main.dart' as app;
 
 import 'login_helper.dart';
 
 class ImmichTestHelper {
-
   final WidgetTester tester;
 
   ImmichTestHelper(this.tester);
@@ -43,15 +40,19 @@ class ImmichTestHelper {
     await tester.pumpAndSettle();
     await EasyLocalization.ensureInitialized();
   }
-
 }
 
 @isTest
-void immichWidgetTest(String description, Future<void> Function(WidgetTester, ImmichTestHelper) test) {
-
-    testWidgets(description, (widgetTester) async {
-        await ImmichTestHelper.loadApp(widgetTester);
-        await test(widgetTester, ImmichTestHelper(widgetTester));
-    }, semanticsEnabled: false);
-
-}
+void immichWidgetTest(
+  String description,
+  Future<void> Function(WidgetTester, ImmichTestHelper) test,
+) {
+  testWidgets(
+    description,
+    (widgetTester) async {
+      await ImmichTestHelper.loadApp(widgetTester);
+      await test(widgetTester, ImmichTestHelper(widgetTester));
+    },
+    semanticsEnabled: false,
+  );
+}

+ 0 - 2
mobile/integration_test/test_utils/login_helper.dart

@@ -1,8 +1,6 @@
-import 'dart:async';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
-import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
 
 class ImmichTestLoginHelper {
   final WidgetTester tester;

+ 1 - 1
mobile/lib/modules/album/ui/album_viewer_appbar.dart

@@ -96,7 +96,7 @@ class AlbumViewerAppbar extends HookConsumerWidget with PreferredSizeWidget {
       if (isSuccess) {
         Navigator.pop(context);
         ref.watch(assetSelectionProvider.notifier).disableMultiselection();
-        ref.refresh(sharedAlbumDetailProvider(albumId));
+        ref.invalidate(sharedAlbumDetailProvider(albumId));
       } else {
         Navigator.pop(context);
         ImmichToast.show(

+ 2 - 2
mobile/lib/modules/album/views/album_viewer_page.dart

@@ -62,7 +62,7 @@ class AlbumViewerPage extends HookConsumerWidget {
 
           if (addAssetsResult != null &&
               addAssetsResult.successfullyAdded > 0) {
-            ref.refresh(sharedAlbumDetailProvider(albumId));
+            ref.invalidate(sharedAlbumDetailProvider(albumId));
           }
 
           ImmichLoadingOverlayController.appLoader.hide();
@@ -88,7 +88,7 @@ class AlbumViewerPage extends HookConsumerWidget {
             .addAdditionalUserToAlbum(sharedUserIds, albumId);
 
         if (isSuccess) {
-          ref.refresh(sharedAlbumDetailProvider(albumId));
+          ref.invalidate(sharedAlbumDetailProvider(albumId));
         }
 
         ImmichLoadingOverlayController.appLoader.hide();

+ 4 - 4
mobile/lib/modules/album/views/library_page.dart

@@ -22,7 +22,7 @@ class LibraryPage extends HookConsumerWidget {
       [],
     );
 
-    Widget _buildAppBar() {
+    Widget buildAppBar() {
       return const SliverAppBar(
         centerTitle: true,
         floating: true,
@@ -40,7 +40,7 @@ class LibraryPage extends HookConsumerWidget {
       );
     }
 
-    Widget _buildCreateAlbumButton() {
+    Widget buildCreateAlbumButton() {
       return GestureDetector(
         onTap: () {
           AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false));
@@ -83,7 +83,7 @@ class LibraryPage extends HookConsumerWidget {
     return Scaffold(
       body: CustomScrollView(
         slivers: [
-          _buildAppBar(),
+          buildAppBar(),
           SliverToBoxAdapter(
             child: Padding(
               padding: const EdgeInsets.all(12.0),
@@ -99,7 +99,7 @@ class LibraryPage extends HookConsumerWidget {
               child: Wrap(
                 spacing: 12,
                 children: [
-                  _buildCreateAlbumButton(),
+                  buildCreateAlbumButton(),
                   for (var album in albums)
                     AlbumThumbnailCard(
                       album: album,

+ 2 - 1
mobile/lib/modules/home/services/asset_cache.service.dart

@@ -8,7 +8,8 @@ class AssetCacheService extends JsonCache<List<Asset>> {
   AssetCacheService() : super("asset_cache");
 
   static Future<List<Map<String, dynamic>>> _computeSerialize(
-      List<Asset> assets) async {
+    List<Asset> assets,
+  ) async {
     return assets.map((e) => e.toJson()).toList();
   }
 

+ 9 - 3
mobile/lib/modules/home/ui/asset_grid/asset_grid_data_structure.dart

@@ -42,8 +42,13 @@ class _AssetGroupsToRenderListComputeParameters {
   final Map<String, List<Asset>> groups;
   final int perRow;
 
-  _AssetGroupsToRenderListComputeParameters(this.monthFormat, this.dayFormat,
-      this.dayFormatYear, this.groups, this.perRow);
+  _AssetGroupsToRenderListComputeParameters(
+    this.monthFormat,
+    this.dayFormat,
+    this.dayFormatYear,
+    this.groups,
+    this.perRow,
+  );
 }
 
 class RenderList {
@@ -52,7 +57,8 @@ class RenderList {
   RenderList(this.elements);
 
   static Future<RenderList> _processAssetGroupData(
-      _AssetGroupsToRenderListComputeParameters data) async {
+    _AssetGroupsToRenderListComputeParameters data,
+  ) async {
     final monthFormat = DateFormat(data.monthFormat);
     final dayFormatSameYear = DateFormat(data.dayFormat);
     final dayFormatOtherYear = DateFormat(data.dayFormatYear);

+ 0 - 1
mobile/lib/modules/home/ui/asset_grid/daily_title_text.dart

@@ -1,4 +1,3 @@
-import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 

+ 1 - 1
mobile/lib/modules/login/ui/login_form.dart

@@ -235,7 +235,7 @@ class ServerEndpointInput extends StatelessWidget {
         labelText: 'login_form_endpoint_url'.tr(),
         border: const OutlineInputBorder(),
         hintText: 'login_form_endpoint_hint'.tr(),
-        errorMaxLines: 4
+        errorMaxLines: 4,
       ),
       validator: _validateInput,
       autovalidateMode: AutovalidateMode.always,

+ 2 - 2
mobile/lib/routing/tab_navigation_observer.dart

@@ -30,8 +30,8 @@ class TabNavigationObserver extends AutoRouterObserver {
     // Perform tasks on re-visit to SearchRoute
     if (route.name == 'SearchRoute') {
       // Refresh Location State
-      ref.refresh(getCuratedLocationProvider);
-      ref.refresh(getCuratedObjectProvider);
+      ref.invalidate(getCuratedLocationProvider);
+      ref.invalidate(getCuratedObjectProvider);
     }
 
     if (route.name == 'SharingRoute') {

+ 1 - 0
mobile/lib/shared/services/immich_logger.service.dart

@@ -83,6 +83,7 @@ class ImmichLogger {
     }
 
     // Share file
+    // ignore: deprecated_member_use
     await Share.shareFiles(
       [filePath],
       subject: "Immich logs $dateTime",

+ 1 - 0
mobile/lib/shared/services/share.service.dart

@@ -40,6 +40,7 @@ class ShareService {
       }
     });
 
+    // ignore: deprecated_member_use
     Share.shareFiles(
       await Future.wait(downloadedFilePaths),
       sharePositionOrigin: Rect.zero,

+ 4 - 2
mobile/lib/utils/image_url_builder.dart

@@ -10,8 +10,10 @@ String getThumbnailUrl(
   return _getThumbnailUrl(asset.id, type: type);
 }
 
-String getThumbnailCacheKey(final AssetResponseDto asset,
-    {ThumbnailFormat type = ThumbnailFormat.WEBP}) {
+String getThumbnailCacheKey(
+  final AssetResponseDto asset, {
+  ThumbnailFormat type = ThumbnailFormat.WEBP,
+}) {
   return _getThumbnailCacheKey(asset.id, type);
 }
 

+ 3 - 1
mobile/lib/utils/openapi_extensions.dart

@@ -31,7 +31,9 @@ extension WithETag on AssetApi {
       final responseBody = await _decodeBodyBytes(response);
       final etag = response.headers[HttpHeaders.etagHeader];
       final data = (await apiClient.deserializeAsync(
-              responseBody, 'List<AssetResponseDto>') as List)
+        responseBody,
+        'List<AssetResponseDto>',
+      ) as List)
           .cast<AssetResponseDto>()
           .toList();
       return Pair(data, etag);