Skip to content

Commit

Permalink
Feature #120 #89 selective backup in app (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
alextran1502 authored May 6, 2022
1 parent f139676 commit 373b691
Show file tree
Hide file tree
Showing 38 changed files with 1,366 additions and 360 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ Loading ~4000 images/videos
## Screenshots

<p align="left">
<img src="design/nsc1.png" width="150" title="Login With Custom URL">
<img src="design/nsc2.png" width="150" title="Backup Setting Info">
<img src="design/login-screen.png" width="150" title="Login With Custom URL">
<img src="design/backup-screen.png" width="150" title="Backup Setting Info">
<img src="design/selective-backup-screen.png" width="150" title="Backup Setting Info">
<img src="design/home-screen.jpeg" width="150" title="Home Screen">
<img src="design/search-screen.jpeg" width="150" title="Curated Search Info">
<img src="design/shared-albums.png" width="150" title="Shared Albums">
Expand All @@ -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.
Expand All @@ -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

Expand Down
Binary file added design/backup-screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added design/login-screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed design/nsc1.png
Binary file not shown.
Binary file removed design/nsc2.png
Binary file not shown.
Binary file added design/selective-backup-screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions docker/docker-compose.gpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion mobile/ios/fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions mobile/lib/constants/hive_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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";
7 changes: 6 additions & 1 deletion mobile/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@ 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';
import 'constants/hive_box.dart';

void main() async {
await Hive.initFlutter();

Hive.registerAdapter(HiveSavedLoginInfoAdapter());
Hive.registerAdapter(HiveBackupAlbumsAdapter());

await Hive.openBox(userInfoBox);
await Hive.openBox<HiveSavedLoginInfo>(hiveLoginInfoBox);
await Hive.openBox<HiveBackupAlbums>(hiveBackupInfoBox);

SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
Expand Down
35 changes: 35 additions & 0 deletions mobile/lib/modules/backup/models/available_album.model.dart
Original file line number Diff line number Diff line change
@@ -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;
}
88 changes: 88 additions & 0 deletions mobile/lib/modules/backup/models/backup_state.model.dart
Original file line number Diff line number Diff line change
@@ -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<String> allAssetOnDatabase;
final double progressInPercentage;
final CancelToken cancelToken;
final ServerInfo serverInfo;

/// All available albums on the device
final List<AvailableAlbum> availableAlbums;
final Set<AssetPathEntity> selectedBackupAlbums;
final Set<AssetPathEntity> excludedBackupAlbums;

/// Assets that are not overlapping in selected backup albums and excluded backup albums
final Set<AssetEntity> allUniqueAssets;

/// All assets from the selected albums that have been backup
final Set<String> 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<String>? allAssetOnDatabase,
double? progressInPercentage,
CancelToken? cancelToken,
ServerInfo? serverInfo,
List<AvailableAlbum>? availableAlbums,
Set<AssetPathEntity>? selectedBackupAlbums,
Set<AssetPathEntity>? excludedBackupAlbums,
Set<AssetEntity>? allUniqueAssets,
Set<String>? 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<Object> get props {
return [
backupProgress,
allAssetOnDatabase,
progressInPercentage,
cancelToken,
serverInfo,
availableAlbums,
selectedBackupAlbums,
excludedBackupAlbums,
allUniqueAssets,
selectedAlbumsBackupAssetsIds,
];
}
}
66 changes: 66 additions & 0 deletions mobile/lib/modules/backup/models/hive_backup_albums.model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'dart:convert';

import 'package:collection/collection.dart';
import 'package:hive/hive.dart';

part 'hive_backup_albums.model.g.dart';

@HiveType(typeId: 1)
class HiveBackupAlbums {
@HiveField(0)
List<String> selectedAlbumIds;

@HiveField(1)
List<String> excludedAlbumsIds;

HiveBackupAlbums({
required this.selectedAlbumIds,
required this.excludedAlbumsIds,
});

@override
String toString() => 'HiveBackupAlbums(selectedAlbumIds: $selectedAlbumIds, excludedAlbumsIds: $excludedAlbumsIds)';

HiveBackupAlbums copyWith({
List<String>? selectedAlbumIds,
List<String>? excludedAlbumsIds,
}) {
return HiveBackupAlbums(
selectedAlbumIds: selectedAlbumIds ?? this.selectedAlbumIds,
excludedAlbumsIds: excludedAlbumsIds ?? this.excludedAlbumsIds,
);
}

Map<String, dynamic> toMap() {
final result = <String, dynamic>{};

result.addAll({'selectedAlbumIds': selectedAlbumIds});
result.addAll({'excludedAlbumsIds': excludedAlbumsIds});

return result;
}

factory HiveBackupAlbums.fromMap(Map<String, dynamic> map) {
return HiveBackupAlbums(
selectedAlbumIds: List<String>.from(map['selectedAlbumIds']),
excludedAlbumsIds: List<String>.from(map['excludedAlbumsIds']),
);
}

String toJson() => json.encode(toMap());

factory HiveBackupAlbums.fromJson(String source) => HiveBackupAlbums.fromMap(json.decode(source));

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
final listEquals = const DeepCollectionEquality().equals;

return other is HiveBackupAlbums &&
listEquals(other.selectedAlbumIds, selectedAlbumIds) &&
listEquals(other.excludedAlbumsIds, excludedAlbumsIds);
}

@override
int get hashCode => selectedAlbumIds.hashCode ^ excludedAlbumsIds.hashCode;
}
42 changes: 42 additions & 0 deletions mobile/lib/modules/backup/models/hive_backup_albums.model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 373b691

Please sign in to comment.