mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
chore(mobile): Run dart analyze in CI (#1425)
* Run dart analyze in CI * Add pub get * Fix linter errors in mobile code
This commit is contained in:
parent
b1311547b2
commit
bcb0056b55
31
.github/workflows/static_analysis.yml
vendored
Normal file
31
.github/workflows/static_analysis.yml
vendored
Normal file
@ -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
|
||||||
|
|
@ -2,7 +2,6 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../test_utils/general_helper.dart';
|
import '../test_utils/general_helper.dart';
|
||||||
import '../test_utils/login_helper.dart';
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
await ImmichTestHelper.initialize();
|
await ImmichTestHelper.initialize();
|
||||||
@ -13,7 +12,7 @@ void main() async {
|
|||||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||||
|
|
||||||
await helper.loginHelper.enterCredentials(
|
await helper.loginHelper.enterCredentials(
|
||||||
email: " demo@immich.app"
|
email: " demo@immich.app",
|
||||||
);
|
);
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 300));
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
@ -21,7 +20,7 @@ void main() async {
|
|||||||
expect(find.text("login_form_err_leading_whitespace".tr()), findsOneWidget);
|
expect(find.text("login_form_err_leading_whitespace".tr()), findsOneWidget);
|
||||||
|
|
||||||
await helper.loginHelper.enterCredentials(
|
await helper.loginHelper.enterCredentials(
|
||||||
email: "demo@immich.app "
|
email: "demo@immich.app ",
|
||||||
);
|
);
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 300));
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
@ -34,7 +33,7 @@ void main() async {
|
|||||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||||
|
|
||||||
await helper.loginHelper.enterCredentials(
|
await helper.loginHelper.enterCredentials(
|
||||||
email: "demo.immich.app"
|
email: "demo.immich.app",
|
||||||
);
|
);
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 300));
|
await tester.pump(const Duration(milliseconds: 300));
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../test_utils/general_helper.dart';
|
import '../test_utils/general_helper.dart';
|
||||||
@ -12,8 +10,9 @@ void main() async {
|
|||||||
immichWidgetTest("Test correct credentials", (tester, helper) async {
|
immichWidgetTest("Test correct credentials", (tester, helper) async {
|
||||||
await helper.loginHelper.waitForLoginScreen();
|
await helper.loginHelper.waitForLoginScreen();
|
||||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||||
await helper.loginHelper
|
await helper.loginHelper.enterCredentialsOf(
|
||||||
.enterCredentialsOf(LoginCredentials.testInstance);
|
LoginCredentials.testInstance,
|
||||||
|
);
|
||||||
await helper.loginHelper.pressLoginButton();
|
await helper.loginHelper.pressLoginButton();
|
||||||
await helper.loginHelper.assertLoginSuccess();
|
await helper.loginHelper.assertLoginSuccess();
|
||||||
});
|
});
|
||||||
@ -22,16 +21,19 @@ void main() async {
|
|||||||
await helper.loginHelper.waitForLoginScreen();
|
await helper.loginHelper.waitForLoginScreen();
|
||||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||||
await helper.loginHelper.enterCredentialsOf(
|
await helper.loginHelper.enterCredentialsOf(
|
||||||
LoginCredentials.testInstanceButWithWrongPassword);
|
LoginCredentials.testInstanceButWithWrongPassword,
|
||||||
|
);
|
||||||
await helper.loginHelper.pressLoginButton();
|
await helper.loginHelper.pressLoginButton();
|
||||||
await helper.loginHelper.assertLoginFailed();
|
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.waitForLoginScreen();
|
||||||
await helper.loginHelper.acknowledgeNewServerVersion();
|
await helper.loginHelper.acknowledgeNewServerVersion();
|
||||||
await helper.loginHelper.enterCredentialsOf(
|
await helper.loginHelper.enterCredentialsOf(
|
||||||
LoginCredentials.wrongInstanceUrl);
|
LoginCredentials.wrongInstanceUrl,
|
||||||
|
);
|
||||||
await helper.loginHelper.pressLoginButton();
|
await helper.loginHelper.pressLoginButton();
|
||||||
await helper.loginHelper.assertLoginFailed();
|
await helper.loginHelper.assertLoginFailed();
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:immich_mobile/main.dart';
|
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
// ignore: depend_on_referenced_packages
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:immich_mobile/main.dart' as app;
|
import 'package:immich_mobile/main.dart' as app;
|
||||||
|
|
||||||
import 'login_helper.dart';
|
import 'login_helper.dart';
|
||||||
|
|
||||||
class ImmichTestHelper {
|
class ImmichTestHelper {
|
||||||
|
|
||||||
final WidgetTester tester;
|
final WidgetTester tester;
|
||||||
|
|
||||||
ImmichTestHelper(this.tester);
|
ImmichTestHelper(this.tester);
|
||||||
@ -43,15 +40,19 @@ class ImmichTestHelper {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
await EasyLocalization.ensureInitialized();
|
await EasyLocalization.ensureInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@isTest
|
@isTest
|
||||||
void immichWidgetTest(String description, Future<void> Function(WidgetTester, ImmichTestHelper) test) {
|
void immichWidgetTest(
|
||||||
|
String description,
|
||||||
testWidgets(description, (widgetTester) async {
|
Future<void> Function(WidgetTester, ImmichTestHelper) test,
|
||||||
await ImmichTestHelper.loadApp(widgetTester);
|
) {
|
||||||
await test(widgetTester, ImmichTestHelper(widgetTester));
|
testWidgets(
|
||||||
}, semanticsEnabled: false);
|
description,
|
||||||
|
(widgetTester) async {
|
||||||
}
|
await ImmichTestHelper.loadApp(widgetTester);
|
||||||
|
await test(widgetTester, ImmichTestHelper(widgetTester));
|
||||||
|
},
|
||||||
|
semanticsEnabled: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
|
||||||
|
|
||||||
class ImmichTestLoginHelper {
|
class ImmichTestLoginHelper {
|
||||||
final WidgetTester tester;
|
final WidgetTester tester;
|
||||||
|
@ -96,7 +96,7 @@ class AlbumViewerAppbar extends HookConsumerWidget with PreferredSizeWidget {
|
|||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
ref.watch(assetSelectionProvider.notifier).disableMultiselection();
|
ref.watch(assetSelectionProvider.notifier).disableMultiselection();
|
||||||
ref.refresh(sharedAlbumDetailProvider(albumId));
|
ref.invalidate(sharedAlbumDetailProvider(albumId));
|
||||||
} else {
|
} else {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
|
@ -62,7 +62,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
if (addAssetsResult != null &&
|
if (addAssetsResult != null &&
|
||||||
addAssetsResult.successfullyAdded > 0) {
|
addAssetsResult.successfullyAdded > 0) {
|
||||||
ref.refresh(sharedAlbumDetailProvider(albumId));
|
ref.invalidate(sharedAlbumDetailProvider(albumId));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
ImmichLoadingOverlayController.appLoader.hide();
|
||||||
@ -88,7 +88,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
.addAdditionalUserToAlbum(sharedUserIds, albumId);
|
.addAdditionalUserToAlbum(sharedUserIds, albumId);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
ref.refresh(sharedAlbumDetailProvider(albumId));
|
ref.invalidate(sharedAlbumDetailProvider(albumId));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmichLoadingOverlayController.appLoader.hide();
|
ImmichLoadingOverlayController.appLoader.hide();
|
||||||
|
@ -22,7 +22,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar() {
|
Widget buildAppBar() {
|
||||||
return const SliverAppBar(
|
return const SliverAppBar(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
floating: true,
|
floating: true,
|
||||||
@ -40,7 +40,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCreateAlbumButton() {
|
Widget buildCreateAlbumButton() {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false));
|
AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false));
|
||||||
@ -83,7 +83,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: CustomScrollView(
|
body: CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
_buildAppBar(),
|
buildAppBar(),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
@ -99,7 +99,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
children: [
|
children: [
|
||||||
_buildCreateAlbumButton(),
|
buildCreateAlbumButton(),
|
||||||
for (var album in albums)
|
for (var album in albums)
|
||||||
AlbumThumbnailCard(
|
AlbumThumbnailCard(
|
||||||
album: album,
|
album: album,
|
||||||
|
@ -8,7 +8,8 @@ class AssetCacheService extends JsonCache<List<Asset>> {
|
|||||||
AssetCacheService() : super("asset_cache");
|
AssetCacheService() : super("asset_cache");
|
||||||
|
|
||||||
static Future<List<Map<String, dynamic>>> _computeSerialize(
|
static Future<List<Map<String, dynamic>>> _computeSerialize(
|
||||||
List<Asset> assets) async {
|
List<Asset> assets,
|
||||||
|
) async {
|
||||||
return assets.map((e) => e.toJson()).toList();
|
return assets.map((e) => e.toJson()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,13 @@ class _AssetGroupsToRenderListComputeParameters {
|
|||||||
final Map<String, List<Asset>> groups;
|
final Map<String, List<Asset>> groups;
|
||||||
final int perRow;
|
final int perRow;
|
||||||
|
|
||||||
_AssetGroupsToRenderListComputeParameters(this.monthFormat, this.dayFormat,
|
_AssetGroupsToRenderListComputeParameters(
|
||||||
this.dayFormatYear, this.groups, this.perRow);
|
this.monthFormat,
|
||||||
|
this.dayFormat,
|
||||||
|
this.dayFormatYear,
|
||||||
|
this.groups,
|
||||||
|
this.perRow,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class RenderList {
|
class RenderList {
|
||||||
@ -52,7 +57,8 @@ class RenderList {
|
|||||||
RenderList(this.elements);
|
RenderList(this.elements);
|
||||||
|
|
||||||
static Future<RenderList> _processAssetGroupData(
|
static Future<RenderList> _processAssetGroupData(
|
||||||
_AssetGroupsToRenderListComputeParameters data) async {
|
_AssetGroupsToRenderListComputeParameters data,
|
||||||
|
) async {
|
||||||
final monthFormat = DateFormat(data.monthFormat);
|
final monthFormat = DateFormat(data.monthFormat);
|
||||||
final dayFormatSameYear = DateFormat(data.dayFormat);
|
final dayFormatSameYear = DateFormat(data.dayFormat);
|
||||||
final dayFormatOtherYear = DateFormat(data.dayFormatYear);
|
final dayFormatOtherYear = DateFormat(data.dayFormatYear);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ class ServerEndpointInput extends StatelessWidget {
|
|||||||
labelText: 'login_form_endpoint_url'.tr(),
|
labelText: 'login_form_endpoint_url'.tr(),
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
hintText: 'login_form_endpoint_hint'.tr(),
|
hintText: 'login_form_endpoint_hint'.tr(),
|
||||||
errorMaxLines: 4
|
errorMaxLines: 4,
|
||||||
),
|
),
|
||||||
validator: _validateInput,
|
validator: _validateInput,
|
||||||
autovalidateMode: AutovalidateMode.always,
|
autovalidateMode: AutovalidateMode.always,
|
||||||
|
@ -30,8 +30,8 @@ class TabNavigationObserver extends AutoRouterObserver {
|
|||||||
// Perform tasks on re-visit to SearchRoute
|
// Perform tasks on re-visit to SearchRoute
|
||||||
if (route.name == 'SearchRoute') {
|
if (route.name == 'SearchRoute') {
|
||||||
// Refresh Location State
|
// Refresh Location State
|
||||||
ref.refresh(getCuratedLocationProvider);
|
ref.invalidate(getCuratedLocationProvider);
|
||||||
ref.refresh(getCuratedObjectProvider);
|
ref.invalidate(getCuratedObjectProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.name == 'SharingRoute') {
|
if (route.name == 'SharingRoute') {
|
||||||
|
@ -83,6 +83,7 @@ class ImmichLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Share file
|
// Share file
|
||||||
|
// ignore: deprecated_member_use
|
||||||
await Share.shareFiles(
|
await Share.shareFiles(
|
||||||
[filePath],
|
[filePath],
|
||||||
subject: "Immich logs $dateTime",
|
subject: "Immich logs $dateTime",
|
||||||
|
@ -40,6 +40,7 @@ class ShareService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ignore: deprecated_member_use
|
||||||
Share.shareFiles(
|
Share.shareFiles(
|
||||||
await Future.wait(downloadedFilePaths),
|
await Future.wait(downloadedFilePaths),
|
||||||
sharePositionOrigin: Rect.zero,
|
sharePositionOrigin: Rect.zero,
|
||||||
|
@ -10,8 +10,10 @@ String getThumbnailUrl(
|
|||||||
return _getThumbnailUrl(asset.id, type: type);
|
return _getThumbnailUrl(asset.id, type: type);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getThumbnailCacheKey(final AssetResponseDto asset,
|
String getThumbnailCacheKey(
|
||||||
{ThumbnailFormat type = ThumbnailFormat.WEBP}) {
|
final AssetResponseDto asset, {
|
||||||
|
ThumbnailFormat type = ThumbnailFormat.WEBP,
|
||||||
|
}) {
|
||||||
return _getThumbnailCacheKey(asset.id, type);
|
return _getThumbnailCacheKey(asset.id, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,9 @@ extension WithETag on AssetApi {
|
|||||||
final responseBody = await _decodeBodyBytes(response);
|
final responseBody = await _decodeBodyBytes(response);
|
||||||
final etag = response.headers[HttpHeaders.etagHeader];
|
final etag = response.headers[HttpHeaders.etagHeader];
|
||||||
final data = (await apiClient.deserializeAsync(
|
final data = (await apiClient.deserializeAsync(
|
||||||
responseBody, 'List<AssetResponseDto>') as List)
|
responseBody,
|
||||||
|
'List<AssetResponseDto>',
|
||||||
|
) as List)
|
||||||
.cast<AssetResponseDto>()
|
.cast<AssetResponseDto>()
|
||||||
.toList();
|
.toList();
|
||||||
return Pair(data, etag);
|
return Pair(data, etag);
|
||||||
|
Loading…
Reference in New Issue
Block a user