chore: beta flavor build (#19862)

* chore: beta flavor build

* make file

* beta flavor

* add build flavor to GHA

* add build flavor to GHA
This commit is contained in:
Alex 2025-07-10 21:42:29 -05:00 committed by GitHub
parent de345a9524
commit d087f7c870
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 91 additions and 41 deletions

View File

@ -122,17 +122,17 @@ jobs:
IS_MAIN: ${{ github.ref == 'refs/heads/main' }} IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
run: | run: |
if [[ $IS_MAIN == 'true' ]]; then if [[ $IS_MAIN == 'true' ]]; then
flutter build apk --release flutter build apk --release --flavor production
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64 flutter build apk --release --flavor production --split-per-abi --target-platform android-arm,android-arm64,android-x64
else else
flutter build apk --debug --split-per-abi --target-platform android-arm64 flutter build apk --debug --flavor production --split-per-abi --target-platform android-arm64
fi fi
- name: Publish Android Artifact - name: Publish Android Artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: release-apk-signed name: release-apk-signed
path: mobile/build/app/outputs/flutter-apk/*.apk path: mobile/build/app/outputs/flutter-apk/**/*.apk
- name: Save Gradle Cache - name: Save Gradle Cache
id: cache-gradle-save id: cache-gradle-save

View File

@ -66,6 +66,20 @@ android {
} }
} }
flavorDimensions "default"
productFlavors {
production {
dimension "default"
applicationId "app.alextran.immich"
}
beta {
dimension "default"
applicationId "app.alextran.immich.beta"
versionNameSuffix "-BETA"
}
}
buildTypes { buildTypes {
debug { debug {
applicationIdSuffix '.debug' applicationIdSuffix '.debug'

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application android:label="Immich Beta" tools:replace="android:label" />
</manifest>

View File

@ -3,6 +3,7 @@ import 'dart:async';
import 'package:immich_mobile/domain/models/sync_event.model.dart'; import 'package:immich_mobile/domain/models/sync_event.model.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_api.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/sync_api.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart'; import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:openapi/api.dart'; import 'package:openapi/api.dart';
@ -23,7 +24,12 @@ class SyncStreamService {
bool get isCancelled => _cancelChecker?.call() ?? false; bool get isCancelled => _cancelChecker?.call() ?? false;
Future<void> sync() => _syncApiRepository.streamChanges(_handleEvents); Future<void> sync() {
_logger.info("Remote sync request for userr");
DLog.log("Remote sync request for user");
// Start the sync stream and handle events
return _syncApiRepository.streamChanges(_handleEvents);
}
Future<void> _handleEvents(List<SyncEvent> events, Function() abort) async { Future<void> _handleEvents(List<SyncEvent> events, Function() abort) async {
List<SyncEvent> items = []; List<SyncEvent> items = [];

View File

@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/providers/asset_viewer/scroll_notifier.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/scroll_notifier.provider.dart';
import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
import 'package:immich_mobile/providers/search/search_input_focus.provider.dart'; import 'package:immich_mobile/providers/search/search_input_focus.provider.dart';
import 'package:immich_mobile/providers/tab.provider.dart'; import 'package:immich_mobile/providers/tab.provider.dart';
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
@ -164,6 +165,11 @@ void _onNavigationSelected(TabsRouter router, int index, WidgetRef ref) {
ref.read(searchInputFocusProvider).requestFocus(); ref.read(searchInputFocusProvider).requestFocus();
} }
// Album page
if (index == 2) {
ref.read(remoteAlbumProvider.notifier).getAll();
}
ref.read(hapticFeedbackProvider.notifier).selectionClick(); ref.read(hapticFeedbackProvider.notifier).selectionClick();
router.setActiveIndex(index); router.setActiveIndex(index);
ref.read(tabProvider.notifier).state = TabEnum.values[index]; ref.read(tabProvider.notifier).state = TabEnum.values[index];

View File

@ -17,6 +17,21 @@ import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
final _features = [ final _features = [
_Feature(
name: 'Main Timeline',
icon: Icons.timeline_rounded,
onTap: (ctx, _) => ctx.pushRoute(const TabShellRoute()),
),
_Feature(
name: 'Video',
icon: Icons.video_collection_outlined,
onTap: (ctx, _) => ctx.pushRoute(const DriftVideoRoute()),
),
_Feature(
name: 'Recently Taken',
icon: Icons.schedule_outlined,
onTap: (ctx, _) => ctx.pushRoute(const DriftRecentlyTakenRoute()),
),
_Feature( _Feature(
name: 'Selection Mode Timeline', name: 'Selection Mode Timeline',
icon: Icons.developer_mode_rounded, icon: Icons.developer_mode_rounded,
@ -42,23 +57,28 @@ final _features = [
return Future.value(); return Future.value();
}, },
), ),
_Feature(
name: '',
icon: Icons.vertical_align_center_sharp,
onTap: (_, __) => Future.value(),
),
_Feature( _Feature(
name: 'Sync Local', name: 'Sync Local',
icon: Icons.photo_album_rounded, icon: Icons.photo_album_rounded,
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncLocal(), onTap: (_, ref) => ref.read(backgroundSyncProvider).syncLocal(),
), ),
_Feature( _Feature(
name: 'Sync Local Full', name: 'Sync Local Full (1)',
icon: Icons.photo_library_rounded, icon: Icons.photo_library_rounded,
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncLocal(full: true), onTap: (_, ref) => ref.read(backgroundSyncProvider).syncLocal(full: true),
), ),
_Feature( _Feature(
name: 'Hash Local Assets', name: 'Hash Local Assets (2)',
icon: Icons.numbers_outlined, icon: Icons.numbers_outlined,
onTap: (_, ref) => ref.read(backgroundSyncProvider).hashAssets(), onTap: (_, ref) => ref.read(backgroundSyncProvider).hashAssets(),
), ),
_Feature( _Feature(
name: 'Sync Remote', name: 'Sync Remote (3)',
icon: Icons.refresh_rounded, icon: Icons.refresh_rounded,
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncRemote(), onTap: (_, ref) => ref.read(backgroundSyncProvider).syncRemote(),
), ),
@ -69,6 +89,11 @@ final _features = [
.read(driftProvider) .read(driftProvider)
.customStatement("pragma wal_checkpoint(truncate)"), .customStatement("pragma wal_checkpoint(truncate)"),
), ),
_Feature(
name: '',
icon: Icons.vertical_align_center_sharp,
onTap: (_, __) => Future.value(),
),
_Feature( _Feature(
name: 'Clear Delta Checkpoint', name: 'Clear Delta Checkpoint',
icon: Icons.delete_rounded, icon: Icons.delete_rounded,
@ -122,21 +147,6 @@ final _features = [
} }
}, },
), ),
_Feature(
name: 'Main Timeline',
icon: Icons.timeline_rounded,
onTap: (ctx, _) => ctx.pushRoute(const TabShellRoute()),
),
_Feature(
name: 'Video',
icon: Icons.video_collection_outlined,
onTap: (ctx, _) => ctx.pushRoute(const DriftVideoRoute()),
),
_Feature(
name: 'Recently Taken',
icon: Icons.schedule_outlined,
onTap: (ctx, _) => ctx.pushRoute(const DriftRecentlyTakenRoute()),
),
]; ];
@RoutePage() @RoutePage()

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
@ -185,7 +186,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
child: action, child: action,
), ),
), ),
if (kDebugMode || kProfileMode) if (kDebugMode || kProfileMode || appFlavor == 'beta')
IconButton( IconButton(
icon: const Icon(Icons.science_rounded), icon: const Icon(Icons.science_rounded),
onPressed: () => context.pushRoute(const FeatInDevRoute()), onPressed: () => context.pushRoute(const FeatInDevRoute()),

View File

@ -76,6 +76,11 @@ class ImmichSliverAppBar extends ConsumerWidget {
onPressed: () { onPressed: () {
ref.read(backgroundSyncProvider).syncLocal(full: true); ref.read(backgroundSyncProvider).syncLocal(full: true);
ref.read(backgroundSyncProvider).syncRemote(); ref.read(backgroundSyncProvider).syncRemote();
Future.delayed(
const Duration(seconds: 10),
() => ref.read(backgroundSyncProvider).hashAssets(),
);
}, },
icon: const Icon( icon: const Icon(
Icons.sync, Icons.sync,

View File

@ -29,3 +29,6 @@ translation:
dart run bin/generate_keys.dart dart run bin/generate_keys.dart
dart format lib/generated/codegen_loader.g.dart dart format lib/generated/codegen_loader.g.dart
dart format lib/generated/intl_keys.g.dart dart format lib/generated/intl_keys.g.dart
build-beta:
flutter build apk --flavor beta --release