diff --git a/README.md b/README.md
index 461e60cc94..6db1ee01de 100644
--- a/README.md
+++ b/README.md
@@ -32,8 +32,9 @@ Loading ~4000 images/videos
## Screenshots
-
-
+
+
+
@@ -50,10 +51,10 @@ This project is under heavy development, there will be continous functions, feat
# Features
- Upload and view assets (videos/images).
+- Auto Backup.
- Download asset to local device.
- Multi-user supported.
- Quick navigation with drag scroll bar.
-- Auto Backup.
- Support HEIC/HEIF Backup.
- Extract and display EXIF info.
- Real-time render from multi-device upload event.
@@ -65,14 +66,20 @@ This project is under heavy development, there will be continous functions, feat
- Show curated places on the search page
- Show curated objects on the search page
- Shared album with users on the same server
+- Selective backup - albums can be included and excluded during the backup process.
+
# System Requirement
-**OS**: Preferred Linux-based operating system (Ubuntu, Debian, MacOS...etc). I haven't tested with `Docker for Windows` as well as `WSL` on Windows
+**OS**: Preferred Linux-based operating system (Ubuntu, Debian, MacOS...etc).
+
+I haven't tested with `Docker for Windows` as well as `WSL` on Windows
+
+*Raspberry Pi can be used but `microservices` container has to be comment out in `docker-compose` since TensorFlow has not been supported in Dockec image on arm64v7 yet.*
**RAM**: At least 2GB, preffered 4GB.
-**Cores**: At least 2 cores, preffered 4 cores.
+**Core**: At least 2 cores, preffered 4 cores.
# Development and Testing out the application
diff --git a/design/backup-screen.png b/design/backup-screen.png
new file mode 100644
index 0000000000..d70669a9d6
Binary files /dev/null and b/design/backup-screen.png differ
diff --git a/design/login-screen.png b/design/login-screen.png
new file mode 100644
index 0000000000..a3687fb12a
Binary files /dev/null and b/design/login-screen.png differ
diff --git a/design/nsc1.png b/design/nsc1.png
deleted file mode 100644
index c4eaa711b5..0000000000
Binary files a/design/nsc1.png and /dev/null differ
diff --git a/design/nsc2.png b/design/nsc2.png
deleted file mode 100644
index bdcf015403..0000000000
Binary files a/design/nsc2.png and /dev/null differ
diff --git a/design/selective-backup-screen.png b/design/selective-backup-screen.png
new file mode 100644
index 0000000000..7b3d1ed047
Binary files /dev/null and b/design/selective-backup-screen.png differ
diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml
index 12349fbb7f..08566b0017 100644
--- a/docker/docker-compose.dev.yml
+++ b/docker/docker-compose.dev.yml
@@ -2,7 +2,7 @@ version: "3.8"
services:
immich_server:
- image: immich-server-dev:1.8.0
+ image: immich-server-dev:1.9.0
build:
context: ../server
dockerfile: Dockerfile
@@ -24,7 +24,7 @@ services:
- immich_network
immich_microservices:
- image: immich-microservices-dev:1.8.0
+ image: immich-microservices-dev:1.9.0
build:
context: ../microservices
dockerfile: Dockerfile
diff --git a/docker/docker-compose.gpu.yml b/docker/docker-compose.gpu.yml
index 1c289986fd..c2dde0c809 100644
--- a/docker/docker-compose.gpu.yml
+++ b/docker/docker-compose.gpu.yml
@@ -2,7 +2,7 @@ version: "3.8"
services:
immich_server:
- image: immich-server-dev:1.8.0
+ image: immich-server-dev:1.9.0
build:
context: ../server
dockerfile: Dockerfile
@@ -22,7 +22,7 @@ services:
- immich_network
immich_microservices:
- image: immich-microservices-dev:1.8.0
+ image: immich-microservices-dev:1.9.0
build:
context: ../microservices
dockerfile: Dockerfile
diff --git a/mobile/android/fastlane/metadata/android/en-US/changelogs/13.txt b/mobile/android/fastlane/metadata/android/en-US/changelogs/13.txt
new file mode 100644
index 0000000000..d3ac68755c
--- /dev/null
+++ b/mobile/android/fastlane/metadata/android/en-US/changelogs/13.txt
@@ -0,0 +1,2 @@
+* New Feature - Selection backup. User can now select a combination of albums to be included or excluded during the backup process, and only unique photos, and videos that are not overlapping between the two groups will be backup.
+* Bug fix - Show correct count of backup and remainder assets.
\ No newline at end of file
diff --git a/mobile/android/metadata/en-US/images/phoneScreenshots/3_en-US.png b/mobile/android/metadata/en-US/images/phoneScreenshots/3_en-US.png
index d5ac2595a2..7b3d1ed047 100644
Binary files a/mobile/android/metadata/en-US/images/phoneScreenshots/3_en-US.png and b/mobile/android/metadata/en-US/images/phoneScreenshots/3_en-US.png differ
diff --git a/mobile/android/metadata/en-US/images/phoneScreenshots/4_en-US.png b/mobile/android/metadata/en-US/images/phoneScreenshots/4_en-US.png
index b313b8da51..d70669a9d6 100644
Binary files a/mobile/android/metadata/en-US/images/phoneScreenshots/4_en-US.png and b/mobile/android/metadata/en-US/images/phoneScreenshots/4_en-US.png differ
diff --git a/mobile/android/metadata/en-US/images/phoneScreenshots/5_en-US.png b/mobile/android/metadata/en-US/images/phoneScreenshots/5_en-US.png
index 81f620959d..b313b8da51 100644
Binary files a/mobile/android/metadata/en-US/images/phoneScreenshots/5_en-US.png and b/mobile/android/metadata/en-US/images/phoneScreenshots/5_en-US.png differ
diff --git a/mobile/android/metadata/en-US/images/phoneScreenshots/6_en-US.png b/mobile/android/metadata/en-US/images/phoneScreenshots/6_en-US.png
new file mode 100644
index 0000000000..81f620959d
Binary files /dev/null and b/mobile/android/metadata/en-US/images/phoneScreenshots/6_en-US.png differ
diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile
index 72888b6123..bb117c9dff 100644
--- a/mobile/ios/fastlane/Fastfile
+++ b/mobile/ios/fastlane/Fastfile
@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta"
lane :beta do
increment_version_number(
- version_number: "1.8.0"
+ version_number: "1.9.0"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,
diff --git a/mobile/lib/constants/hive_box.dart b/mobile/lib/constants/hive_box.dart
index 4c000524a8..397680dd39 100644
--- a/mobile/lib/constants/hive_box.dart
+++ b/mobile/lib/constants/hive_box.dart
@@ -9,3 +9,7 @@ const String serverEndpointKey = 'immichBoxServerEndpoint';
// Login Info
const String hiveLoginInfoBox = "immichLoginInfoBox";
const String savedLoginInfoKey = "immichSavedLoginInfoKey";
+
+// Backup Info
+const String hiveBackupInfoBox = "immichBackupAlbumInfoBox";
+const String backupInfoKey = "immichBackupAlbumInfoKey";
diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart
index 836571913b..69fdf359a5 100644
--- a/mobile/lib/main.dart
+++ b/mobile/lib/main.dart
@@ -3,12 +3,13 @@ import 'package:flutter/services.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
+import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart';
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
import 'package:immich_mobile/shared/providers/asset.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/routing/tab_navigation_observer.dart';
import 'package:immich_mobile/shared/providers/app_state.provider.dart';
-import 'package:immich_mobile/shared/providers/backup.provider.dart';
+import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
@@ -16,9 +17,13 @@ import 'constants/hive_box.dart';
void main() async {
await Hive.initFlutter();
+
Hive.registerAdapter(HiveSavedLoginInfoAdapter());
+ Hive.registerAdapter(HiveBackupAlbumsAdapter());
+
await Hive.openBox(userInfoBox);
await Hive.openBox(hiveLoginInfoBox);
+ await Hive.openBox(hiveBackupInfoBox);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
diff --git a/mobile/lib/modules/backup/models/available_album.model.dart b/mobile/lib/modules/backup/models/available_album.model.dart
new file mode 100644
index 0000000000..d202efd19e
--- /dev/null
+++ b/mobile/lib/modules/backup/models/available_album.model.dart
@@ -0,0 +1,35 @@
+import 'dart:typed_data';
+
+import 'package:photo_manager/photo_manager.dart';
+
+class AvailableAlbum {
+ final AssetPathEntity albumEntity;
+ final Uint8List? thumbnailData;
+ AvailableAlbum({
+ required this.albumEntity,
+ this.thumbnailData,
+ });
+
+ AvailableAlbum copyWith({
+ AssetPathEntity? albumEntity,
+ Uint8List? thumbnailData,
+ }) {
+ return AvailableAlbum(
+ albumEntity: albumEntity ?? this.albumEntity,
+ thumbnailData: thumbnailData ?? this.thumbnailData,
+ );
+ }
+
+ @override
+ String toString() => 'AvailableAlbum(albumEntity: $albumEntity, thumbnailData: $thumbnailData)';
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+
+ return other is AvailableAlbum && other.albumEntity == albumEntity && other.thumbnailData == thumbnailData;
+ }
+
+ @override
+ int get hashCode => albumEntity.hashCode ^ thumbnailData.hashCode;
+}
diff --git a/mobile/lib/modules/backup/models/backup_state.model.dart b/mobile/lib/modules/backup/models/backup_state.model.dart
new file mode 100644
index 0000000000..a1bc20c01a
--- /dev/null
+++ b/mobile/lib/modules/backup/models/backup_state.model.dart
@@ -0,0 +1,88 @@
+import 'package:dio/dio.dart';
+import 'package:equatable/equatable.dart';
+import 'package:photo_manager/photo_manager.dart';
+
+import 'package:immich_mobile/modules/backup/models/available_album.model.dart';
+import 'package:immich_mobile/shared/models/server_info.model.dart';
+
+enum BackUpProgressEnum { idle, inProgress, done }
+
+class BackUpState extends Equatable {
+ // enum
+ final BackUpProgressEnum backupProgress;
+ final List allAssetOnDatabase;
+ final double progressInPercentage;
+ final CancelToken cancelToken;
+ final ServerInfo serverInfo;
+
+ /// All available albums on the device
+ final List availableAlbums;
+ final Set selectedBackupAlbums;
+ final Set excludedBackupAlbums;
+
+ /// Assets that are not overlapping in selected backup albums and excluded backup albums
+ final Set allUniqueAssets;
+
+ /// All assets from the selected albums that have been backup
+ final Set selectedAlbumsBackupAssetsIds;
+
+ const BackUpState({
+ required this.backupProgress,
+ required this.allAssetOnDatabase,
+ required this.progressInPercentage,
+ required this.cancelToken,
+ required this.serverInfo,
+ required this.availableAlbums,
+ required this.selectedBackupAlbums,
+ required this.excludedBackupAlbums,
+ required this.allUniqueAssets,
+ required this.selectedAlbumsBackupAssetsIds,
+ });
+
+ BackUpState copyWith({
+ BackUpProgressEnum? backupProgress,
+ List? allAssetOnDatabase,
+ double? progressInPercentage,
+ CancelToken? cancelToken,
+ ServerInfo? serverInfo,
+ List? availableAlbums,
+ Set? selectedBackupAlbums,
+ Set? excludedBackupAlbums,
+ Set? allUniqueAssets,
+ Set? selectedAlbumsBackupAssetsIds,
+ }) {
+ return BackUpState(
+ backupProgress: backupProgress ?? this.backupProgress,
+ allAssetOnDatabase: allAssetOnDatabase ?? this.allAssetOnDatabase,
+ progressInPercentage: progressInPercentage ?? this.progressInPercentage,
+ cancelToken: cancelToken ?? this.cancelToken,
+ serverInfo: serverInfo ?? this.serverInfo,
+ availableAlbums: availableAlbums ?? this.availableAlbums,
+ selectedBackupAlbums: selectedBackupAlbums ?? this.selectedBackupAlbums,
+ excludedBackupAlbums: excludedBackupAlbums ?? this.excludedBackupAlbums,
+ allUniqueAssets: allUniqueAssets ?? this.allUniqueAssets,
+ selectedAlbumsBackupAssetsIds: selectedAlbumsBackupAssetsIds ?? this.selectedAlbumsBackupAssetsIds,
+ );
+ }
+
+ @override
+ String toString() {
+ return 'BackUpState(backupProgress: $backupProgress, allAssetOnDatabase: $allAssetOnDatabase, progressInPercentage: $progressInPercentage, cancelToken: $cancelToken, serverInfo: $serverInfo, availableAlbums: $availableAlbums, selectedBackupAlbums: $selectedBackupAlbums, excludedBackupAlbums: $excludedBackupAlbums, allUniqueAssets: $allUniqueAssets, selectedAlbumsBackupAssetsIds: $selectedAlbumsBackupAssetsIds)';
+ }
+
+ @override
+ List