diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml
index a048536b2f..ca24e33b52 100644
--- a/.github/workflows/build-mobile.yml
+++ b/.github/workflows/build-mobile.yml
@@ -122,17 +122,17 @@ jobs:
IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
run: |
if [[ $IS_MAIN == 'true' ]]; then
- flutter build apk --release
- flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
+ flutter build apk --release --flavor production
+ flutter build apk --release --flavor production --split-per-abi --target-platform android-arm,android-arm64,android-x64
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
- name: Publish Android Artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: release-apk-signed
- path: mobile/build/app/outputs/flutter-apk/*.apk
+ path: mobile/build/app/outputs/flutter-apk/**/*.apk
- name: Save Gradle Cache
id: cache-gradle-save
diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle
index 0d07228252..870e424461 100644
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -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 {
debug {
applicationIdSuffix '.debug'
diff --git a/mobile/android/app/src/beta/AndroidManifest.xml b/mobile/android/app/src/beta/AndroidManifest.xml
new file mode 100644
index 0000000000..d4f7b5bc80
--- /dev/null
+++ b/mobile/android/app/src/beta/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml
index 6a96aa68e4..cf3b7ee719 100644
--- a/mobile/android/app/src/main/AndroidManifest.xml
+++ b/mobile/android/app/src/main/AndroidManifest.xml
@@ -100,24 +100,24 @@
-
-
-
+
+
+
-
+
-
-
-
-
+
+
+
+
diff --git a/mobile/lib/domain/services/sync_stream.service.dart b/mobile/lib/domain/services/sync_stream.service.dart
index ee0ec6c44f..29066195f2 100644
--- a/mobile/lib/domain/services/sync_stream.service.dart
+++ b/mobile/lib/domain/services/sync_stream.service.dart
@@ -3,6 +3,7 @@ import 'dart:async';
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_stream.repository.dart';
+import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
@@ -23,7 +24,12 @@ class SyncStreamService {
bool get isCancelled => _cancelChecker?.call() ?? false;
- Future sync() => _syncApiRepository.streamChanges(_handleEvents);
+ Future 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 _handleEvents(List events, Function() abort) async {
List items = [];
diff --git a/mobile/lib/pages/common/tab_shell.page.dart b/mobile/lib/pages/common/tab_shell.page.dart
index 4eab0e32cf..edaec6d336 100644
--- a/mobile/lib/pages/common/tab_shell.page.dart
+++ b/mobile/lib/pages/common/tab_shell.page.dart
@@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.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/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/tab.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();
}
+ // Album page
+ if (index == 2) {
+ ref.read(remoteAlbumProvider.notifier).getAll();
+ }
+
ref.read(hapticFeedbackProvider.notifier).selectionClick();
router.setActiveIndex(index);
ref.read(tabProvider.notifier).state = TabEnum.values[index];
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 566c10c70a..bdb426fe22 100644
--- a/mobile/lib/presentation/pages/dev/feat_in_development.page.dart
+++ b/mobile/lib/presentation/pages/dev/feat_in_development.page.dart
@@ -17,6 +17,21 @@ import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/routing/router.dart';
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(
name: 'Selection Mode Timeline',
icon: Icons.developer_mode_rounded,
@@ -42,23 +57,28 @@ final _features = [
return Future.value();
},
),
+ _Feature(
+ name: '',
+ icon: Icons.vertical_align_center_sharp,
+ onTap: (_, __) => Future.value(),
+ ),
_Feature(
name: 'Sync Local',
icon: Icons.photo_album_rounded,
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncLocal(),
),
_Feature(
- name: 'Sync Local Full',
+ name: 'Sync Local Full (1)',
icon: Icons.photo_library_rounded,
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncLocal(full: true),
),
_Feature(
- name: 'Hash Local Assets',
+ name: 'Hash Local Assets (2)',
icon: Icons.numbers_outlined,
onTap: (_, ref) => ref.read(backgroundSyncProvider).hashAssets(),
),
_Feature(
- name: 'Sync Remote',
+ name: 'Sync Remote (3)',
icon: Icons.refresh_rounded,
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncRemote(),
),
@@ -69,6 +89,11 @@ final _features = [
.read(driftProvider)
.customStatement("pragma wal_checkpoint(truncate)"),
),
+ _Feature(
+ name: '',
+ icon: Icons.vertical_align_center_sharp,
+ onTap: (_, __) => Future.value(),
+ ),
_Feature(
name: 'Clear Delta Checkpoint',
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()
diff --git a/mobile/lib/widgets/common/immich_app_bar.dart b/mobile/lib/widgets/common/immich_app_bar.dart
index dbf088c112..799cf17f3f 100644
--- a/mobile/lib/widgets/common/immich_app_bar.dart
+++ b/mobile/lib/widgets/common/immich_app_bar.dart
@@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
@@ -185,7 +186,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
child: action,
),
),
- if (kDebugMode || kProfileMode)
+ if (kDebugMode || kProfileMode || appFlavor == 'beta')
IconButton(
icon: const Icon(Icons.science_rounded),
onPressed: () => context.pushRoute(const FeatInDevRoute()),
diff --git a/mobile/lib/widgets/common/immich_sliver_app_bar.dart b/mobile/lib/widgets/common/immich_sliver_app_bar.dart
index bff1ab4bb1..c2c5b79753 100644
--- a/mobile/lib/widgets/common/immich_sliver_app_bar.dart
+++ b/mobile/lib/widgets/common/immich_sliver_app_bar.dart
@@ -76,6 +76,11 @@ class ImmichSliverAppBar extends ConsumerWidget {
onPressed: () {
ref.read(backgroundSyncProvider).syncLocal(full: true);
ref.read(backgroundSyncProvider).syncRemote();
+
+ Future.delayed(
+ const Duration(seconds: 10),
+ () => ref.read(backgroundSyncProvider).hashAssets(),
+ );
},
icon: const Icon(
Icons.sync,
diff --git a/mobile/makefile b/mobile/makefile
index 64992ec946..37d33fa817 100644
--- a/mobile/makefile
+++ b/mobile/makefile
@@ -28,4 +28,7 @@ translation:
dart run easy_localization:generate -S ../i18n
dart run bin/generate_keys.dart
dart format lib/generated/codegen_loader.g.dart
- dart format lib/generated/intl_keys.g.dart
\ No newline at end of file
+ dart format lib/generated/intl_keys.g.dart
+
+build-beta:
+ flutter build apk --flavor beta --release