mirror of
https://github.com/immich-app/immich.git
synced 2024-09-22 11:07:28 +00:00
Add service provider (#250)
* optimize android side gradle settings * android minsdk back to 21 * remove unused package, update linter and fix lint error * clean code of 'shared module' with offical dart style guide * restore uploadProfileImage method in UserService * add service provider * fix searchFocusNode init error
This commit is contained in:
parent
485b152beb
commit
d02b97e1c1
@ -20,20 +20,26 @@ class ImageViewerPage extends HookConsumerWidget {
|
|||||||
final String heroTag;
|
final String heroTag;
|
||||||
final String thumbnailUrl;
|
final String thumbnailUrl;
|
||||||
final ImmichAsset asset;
|
final ImmichAsset asset;
|
||||||
final AssetService _assetService = AssetService();
|
|
||||||
ImmichAssetWithExif? assetDetail;
|
ImmichAssetWithExif? assetDetail;
|
||||||
|
|
||||||
ImageViewerPage(
|
ImageViewerPage({
|
||||||
{Key? key, required this.imageUrl, required this.heroTag, required this.thumbnailUrl, required this.asset})
|
Key? key,
|
||||||
: super(key: key);
|
required this.imageUrl,
|
||||||
|
required this.heroTag,
|
||||||
|
required this.thumbnailUrl,
|
||||||
|
required this.asset,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final downloadAssetStatus = ref.watch(imageViewerStateProvider).downloadAssetStatus;
|
final downloadAssetStatus =
|
||||||
|
ref.watch(imageViewerStateProvider).downloadAssetStatus;
|
||||||
var box = Hive.box(userInfoBox);
|
var box = Hive.box(userInfoBox);
|
||||||
|
|
||||||
getAssetExif() async {
|
getAssetExif() async {
|
||||||
assetDetail = await _assetService.getAssetById(asset.id);
|
assetDetail =
|
||||||
|
await ref.watch(assetServiceProvider).getAssetById(asset.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
showInfo() {
|
showInfo() {
|
||||||
@ -59,31 +65,32 @@ class ImageViewerPage extends HookConsumerWidget {
|
|||||||
asset: asset,
|
asset: asset,
|
||||||
onMoreInfoPressed: showInfo,
|
onMoreInfoPressed: showInfo,
|
||||||
onDownloadPressed: () {
|
onDownloadPressed: () {
|
||||||
ref.watch(imageViewerStateProvider.notifier).downloadAsset(asset, context);
|
ref
|
||||||
|
.watch(imageViewerStateProvider.notifier)
|
||||||
|
.downloadAsset(asset, context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: Hero(
|
child: Hero(
|
||||||
tag: heroTag,
|
tag: heroTag,
|
||||||
child: RemotePhotoView(
|
child: RemotePhotoView(
|
||||||
thumbnailUrl: thumbnailUrl,
|
thumbnailUrl: thumbnailUrl,
|
||||||
imageUrl: imageUrl,
|
imageUrl: imageUrl,
|
||||||
authToken: "Bearer ${box.get(accessTokenKey)}",
|
authToken: "Bearer ${box.get(accessTokenKey)}",
|
||||||
onSwipeDown: () => AutoRouter.of(context).pop(),
|
onSwipeDown: () => AutoRouter.of(context).pop(),
|
||||||
onSwipeUp: () => showInfo(),
|
onSwipeUp: () => showInfo(),
|
||||||
)
|
)),
|
||||||
),
|
),
|
||||||
|
if (downloadAssetStatus == DownloadAssetStatus.loading)
|
||||||
|
const Center(
|
||||||
|
child: DownloadLoadingIndicator(),
|
||||||
),
|
),
|
||||||
if (downloadAssetStatus == DownloadAssetStatus.loading)
|
],
|
||||||
const Center(
|
|
||||||
child: DownloadLoadingIndicator(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,14 @@ class VideoViewerPage extends HookConsumerWidget {
|
|||||||
final String videoUrl;
|
final String videoUrl;
|
||||||
final ImmichAsset asset;
|
final ImmichAsset asset;
|
||||||
ImmichAssetWithExif? assetDetail;
|
ImmichAssetWithExif? assetDetail;
|
||||||
final AssetService _assetService = AssetService();
|
|
||||||
|
|
||||||
VideoViewerPage({Key? key, required this.videoUrl, required this.asset}) : super(key: key);
|
VideoViewerPage({Key? key, required this.videoUrl, required this.asset})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final downloadAssetStatus = ref.watch(imageViewerStateProvider).downloadAssetStatus;
|
final downloadAssetStatus =
|
||||||
|
ref.watch(imageViewerStateProvider).downloadAssetStatus;
|
||||||
|
|
||||||
String jwtToken = Hive.box(userInfoBox).get(accessTokenKey);
|
String jwtToken = Hive.box(userInfoBox).get(accessTokenKey);
|
||||||
|
|
||||||
@ -44,7 +45,8 @@ class VideoViewerPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAssetExif() async {
|
getAssetExif() async {
|
||||||
assetDetail = await _assetService.getAssetById(asset.id);
|
assetDetail =
|
||||||
|
await ref.watch(assetServiceProvider).getAssetById(asset.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
@ -60,7 +62,9 @@ class VideoViewerPage extends HookConsumerWidget {
|
|||||||
showInfo();
|
showInfo();
|
||||||
},
|
},
|
||||||
onDownloadPressed: () {
|
onDownloadPressed: () {
|
||||||
ref.watch(imageViewerStateProvider.notifier).downloadAsset(asset, context);
|
ref
|
||||||
|
.watch(imageViewerStateProvider.notifier)
|
||||||
|
.downloadAsset(asset, context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
body: SwipeDetector(
|
body: SwipeDetector(
|
||||||
@ -93,7 +97,8 @@ class VideoThumbnailPlayer extends StatefulWidget {
|
|||||||
final String url;
|
final String url;
|
||||||
final String? jwtToken;
|
final String? jwtToken;
|
||||||
|
|
||||||
const VideoThumbnailPlayer({Key? key, required this.url, this.jwtToken}) : super(key: key);
|
const VideoThumbnailPlayer({Key? key, required this.url, this.jwtToken})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<VideoThumbnailPlayer> createState() => _VideoThumbnailPlayerState();
|
State<VideoThumbnailPlayer> createState() => _VideoThumbnailPlayerState();
|
||||||
@ -111,8 +116,8 @@ class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
|
|||||||
|
|
||||||
Future<void> initializePlayer() async {
|
Future<void> initializePlayer() async {
|
||||||
try {
|
try {
|
||||||
videoPlayerController =
|
videoPlayerController = VideoPlayerController.network(widget.url,
|
||||||
VideoPlayerController.network(widget.url, httpHeaders: {"Authorization": "Bearer ${widget.jwtToken}"});
|
httpHeaders: {"Authorization": "Bearer ${widget.jwtToken}"});
|
||||||
|
|
||||||
await videoPlayerController.initialize();
|
await videoPlayerController.initialize();
|
||||||
_createChewieController();
|
_createChewieController();
|
||||||
@ -142,7 +147,8 @@ class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return chewieController != null && chewieController!.videoPlayerController.value.isInitialized
|
return chewieController != null &&
|
||||||
|
chewieController!.videoPlayerController.value.isInitialized
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
child: Chewie(
|
child: Chewie(
|
||||||
controller: chewieController!,
|
controller: chewieController!,
|
||||||
|
@ -7,13 +7,14 @@ import 'package:immich_mobile/modules/backup/models/available_album.model.dart';
|
|||||||
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
|
import 'package:immich_mobile/modules/backup/models/backup_state.model.dart';
|
||||||
import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart';
|
import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart';
|
||||||
import 'package:immich_mobile/modules/backup/services/backup.service.dart';
|
import 'package:immich_mobile/modules/backup/services/backup.service.dart';
|
||||||
|
import 'package:immich_mobile/modules/login/models/authentication_state.model.dart';
|
||||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||||
import 'package:immich_mobile/shared/models/server_info.model.dart';
|
import 'package:immich_mobile/shared/models/server_info.model.dart';
|
||||||
import 'package:immich_mobile/shared/services/server_info.service.dart';
|
import 'package:immich_mobile/shared/services/server_info.service.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
class BackupNotifier extends StateNotifier<BackUpState> {
|
class BackupNotifier extends StateNotifier<BackUpState> {
|
||||||
BackupNotifier({this.ref})
|
BackupNotifier(this._backupService, this._serverInfoService, this._authState)
|
||||||
: super(
|
: super(
|
||||||
BackUpState(
|
BackUpState(
|
||||||
backupProgress: BackUpProgressEnum.idle,
|
backupProgress: BackUpProgressEnum.idle,
|
||||||
@ -37,9 +38,9 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ref? ref;
|
final BackupService _backupService;
|
||||||
final BackupService _backupService = BackupService();
|
final ServerInfoService _serverInfoService;
|
||||||
final ServerInfoService _serverInfoService = ServerInfoService();
|
final AuthenticationState _authState;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// UI INTERACTION
|
/// UI INTERACTION
|
||||||
@ -338,38 +339,38 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void resumeBackup() {
|
void resumeBackup() {
|
||||||
var authState = ref?.read(authenticationProvider);
|
|
||||||
|
|
||||||
// Check if user is login
|
// Check if user is login
|
||||||
var accessKey = Hive.box(userInfoBox).get(accessTokenKey);
|
var accessKey = Hive.box(userInfoBox).get(accessTokenKey);
|
||||||
|
|
||||||
// User has been logged out return
|
// User has been logged out return
|
||||||
if (authState != null) {
|
if (accessKey == null || !_authState.isAuthenticated) {
|
||||||
if (accessKey == null || !authState.isAuthenticated) {
|
debugPrint("[resumeBackup] not authenticated - abort");
|
||||||
debugPrint("[resumeBackup] not authenticated - abort");
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this device is enable backup by the user
|
||||||
|
if ((_authState.deviceInfo.deviceId == _authState.deviceId) &&
|
||||||
|
_authState.deviceInfo.isAutoBackup) {
|
||||||
|
// check if backup is alreayd in process - then return
|
||||||
|
if (state.backupProgress == BackUpProgressEnum.inProgress) {
|
||||||
|
debugPrint("[resumeBackup] Backup is already in progress - abort");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this device is enable backup by the user
|
// Run backup
|
||||||
if ((authState.deviceInfo.deviceId == authState.deviceId) &&
|
debugPrint("[resumeBackup] Start back up");
|
||||||
authState.deviceInfo.isAutoBackup) {
|
startBackupProcess();
|
||||||
// check if backup is alreayd in process - then return
|
|
||||||
if (state.backupProgress == BackUpProgressEnum.inProgress) {
|
|
||||||
debugPrint("[resumeBackup] Backup is already in progress - abort");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run backup
|
|
||||||
debugPrint("[resumeBackup] Start back up");
|
|
||||||
startBackupProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final backupProvider =
|
final backupProvider =
|
||||||
StateNotifierProvider<BackupNotifier, BackUpState>((ref) {
|
StateNotifierProvider<BackupNotifier, BackUpState>((ref) {
|
||||||
return BackupNotifier(ref: ref);
|
return BackupNotifier(
|
||||||
|
ref.watch(backupServiceProvider),
|
||||||
|
ref.watch(serverInfoServiceProvider),
|
||||||
|
ref.watch(authenticationProvider),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -5,6 +5,7 @@ import 'dart:io';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/hive_box.dart';
|
import 'package:immich_mobile/constants/hive_box.dart';
|
||||||
import 'package:immich_mobile/shared/services/network.service.dart';
|
import 'package:immich_mobile/shared/services/network.service.dart';
|
||||||
import 'package:immich_mobile/shared/models/device_info.model.dart';
|
import 'package:immich_mobile/shared/models/device_info.model.dart';
|
||||||
@ -14,20 +15,28 @@ import 'package:http_parser/http_parser.dart';
|
|||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:cancellation_token_http/http.dart' as http;
|
import 'package:cancellation_token_http/http.dart' as http;
|
||||||
|
|
||||||
|
final backupServiceProvider =
|
||||||
|
Provider((ref) => BackupService(ref.watch(networkServiceProvider)));
|
||||||
|
|
||||||
class BackupService {
|
class BackupService {
|
||||||
final NetworkService _networkService = NetworkService();
|
final NetworkService _networkService;
|
||||||
|
BackupService(this._networkService);
|
||||||
|
|
||||||
Future<List<String>> getDeviceBackupAsset() async {
|
Future<List<String>> getDeviceBackupAsset() async {
|
||||||
String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
|
String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
|
||||||
|
|
||||||
Response response = await _networkService.getRequest(url: "asset/$deviceId");
|
Response response =
|
||||||
|
await _networkService.getRequest(url: "asset/$deviceId");
|
||||||
List<dynamic> result = jsonDecode(response.toString());
|
List<dynamic> result = jsonDecode(response.toString());
|
||||||
|
|
||||||
return result.cast<String>();
|
return result.cast<String>();
|
||||||
}
|
}
|
||||||
|
|
||||||
backupAsset(Set<AssetEntity> assetList, http.CancellationToken cancelToken,
|
backupAsset(
|
||||||
Function(String, String) singleAssetDoneCb, Function(int, int) uploadProgress) async {
|
Set<AssetEntity> assetList,
|
||||||
|
http.CancellationToken cancelToken,
|
||||||
|
Function(String, String) singleAssetDoneCb,
|
||||||
|
Function(int, int) uploadProgress) async {
|
||||||
String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
|
String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
|
||||||
String savedEndpoint = Hive.box(userInfoBox).get(serverEndpointKey);
|
String savedEndpoint = Hive.box(userInfoBox).get(serverEndpointKey);
|
||||||
File? file;
|
File? file;
|
||||||
@ -44,7 +53,8 @@ class BackupService {
|
|||||||
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
String originalFileName = await entity.titleAsync;
|
String originalFileName = await entity.titleAsync;
|
||||||
String fileNameWithoutPath = originalFileName.toString().split(".")[0];
|
String fileNameWithoutPath =
|
||||||
|
originalFileName.toString().split(".")[0];
|
||||||
var fileExtension = p.extension(file.path);
|
var fileExtension = p.extension(file.path);
|
||||||
var mimeType = FileHelper.getMimeType(file.path);
|
var mimeType = FileHelper.getMimeType(file.path);
|
||||||
var fileStream = file.openRead();
|
var fileStream = file.openRead();
|
||||||
@ -60,7 +70,8 @@ class BackupService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Build thumbnail multipart data
|
// Build thumbnail multipart data
|
||||||
var thumbnailData = await entity.thumbnailDataWithSize(const ThumbnailSize(1440, 2560));
|
var thumbnailData = await entity
|
||||||
|
.thumbnailDataWithSize(const ThumbnailSize(1440, 2560));
|
||||||
if (thumbnailData != null) {
|
if (thumbnailData != null) {
|
||||||
thumbnailUploadData = http.MultipartFile.fromBytes(
|
thumbnailUploadData = http.MultipartFile.fromBytes(
|
||||||
"thumbnailData",
|
"thumbnailData",
|
||||||
@ -75,8 +86,10 @@ class BackupService {
|
|||||||
|
|
||||||
var box = Hive.box(userInfoBox);
|
var box = Hive.box(userInfoBox);
|
||||||
|
|
||||||
var req = MultipartRequest('POST', Uri.parse('$savedEndpoint/asset/upload'),
|
var req = MultipartRequest(
|
||||||
onProgress: ((bytes, totalBytes) => uploadProgress(bytes, totalBytes)));
|
'POST', Uri.parse('$savedEndpoint/asset/upload'),
|
||||||
|
onProgress: ((bytes, totalBytes) =>
|
||||||
|
uploadProgress(bytes, totalBytes)));
|
||||||
req.headers["Authorization"] = "Bearer ${box.get(accessTokenKey)}";
|
req.headers["Authorization"] = "Bearer ${box.get(accessTokenKey)}";
|
||||||
|
|
||||||
req.fields['deviceAssetId'] = entity.id;
|
req.fields['deviceAssetId'] = entity.id;
|
||||||
@ -126,7 +139,8 @@ class BackupService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<DeviceInfoRemote> setAutoBackup(bool status, String deviceId, String deviceType) async {
|
Future<DeviceInfoRemote> setAutoBackup(
|
||||||
|
bool status, String deviceId, String deviceType) async {
|
||||||
var res = await _networkService.patchRequest(url: 'device-info', data: {
|
var res = await _networkService.patchRequest(url: 'device-info', data: {
|
||||||
"isAutoBackup": status,
|
"isAutoBackup": status,
|
||||||
"deviceId": deviceId,
|
"deviceId": deviceId,
|
||||||
|
@ -50,37 +50,46 @@ class UploadProfileImageState {
|
|||||||
|
|
||||||
String toJson() => json.encode(toMap());
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
factory UploadProfileImageState.fromJson(String source) => UploadProfileImageState.fromMap(json.decode(source));
|
factory UploadProfileImageState.fromJson(String source) =>
|
||||||
|
UploadProfileImageState.fromMap(json.decode(source));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'UploadProfileImageState(status: $status, profileImagePath: $profileImagePath)';
|
String toString() =>
|
||||||
|
'UploadProfileImageState(status: $status, profileImagePath: $profileImagePath)';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
if (identical(this, other)) return true;
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
return other is UploadProfileImageState && other.status == status && other.profileImagePath == profileImagePath;
|
return other is UploadProfileImageState &&
|
||||||
|
other.status == status &&
|
||||||
|
other.profileImagePath == profileImagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => status.hashCode ^ profileImagePath.hashCode;
|
int get hashCode => status.hashCode ^ profileImagePath.hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UploadProfileImageNotifier extends StateNotifier<UploadProfileImageState> {
|
class UploadProfileImageNotifier
|
||||||
UploadProfileImageNotifier()
|
extends StateNotifier<UploadProfileImageState> {
|
||||||
|
UploadProfileImageNotifier(this._userSErvice)
|
||||||
: super(UploadProfileImageState(
|
: super(UploadProfileImageState(
|
||||||
profileImagePath: '',
|
profileImagePath: '',
|
||||||
status: UploadProfileStatus.idle,
|
status: UploadProfileStatus.idle,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
final UserService _userSErvice;
|
||||||
|
|
||||||
Future<bool> upload(XFile file) async {
|
Future<bool> upload(XFile file) async {
|
||||||
state = state.copyWith(status: UploadProfileStatus.loading);
|
state = state.copyWith(status: UploadProfileStatus.loading);
|
||||||
|
|
||||||
var res = await UserService().uploadProfileImage(file);
|
var res = await _userSErvice.uploadProfileImage(file);
|
||||||
|
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
debugPrint("Succesfully upload profile image");
|
debugPrint("Succesfully upload profile image");
|
||||||
state = state.copyWith(status: UploadProfileStatus.success, profileImagePath: res.profileImagePath);
|
state = state.copyWith(
|
||||||
|
status: UploadProfileStatus.success,
|
||||||
|
profileImagePath: res.profileImagePath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,4 +99,5 @@ class UploadProfileImageNotifier extends StateNotifier<UploadProfileImageState>
|
|||||||
}
|
}
|
||||||
|
|
||||||
final uploadProfileImageProvider =
|
final uploadProfileImageProvider =
|
||||||
StateNotifierProvider<UploadProfileImageNotifier, UploadProfileImageState>(((ref) => UploadProfileImageNotifier()));
|
StateNotifierProvider<UploadProfileImageNotifier, UploadProfileImageState>(
|
||||||
|
((ref) => UploadProfileImageNotifier(ref.watch(userServiceProvider))));
|
||||||
|
@ -1,21 +1,27 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/modules/home/models/delete_asset_response.model.dart';
|
import 'package:immich_mobile/modules/home/models/delete_asset_response.model.dart';
|
||||||
import 'package:immich_mobile/modules/home/models/get_all_asset_response.model.dart';
|
import 'package:immich_mobile/modules/home/models/get_all_asset_response.model.dart';
|
||||||
import 'package:immich_mobile/shared/models/immich_asset.model.dart';
|
import 'package:immich_mobile/shared/models/immich_asset.model.dart';
|
||||||
import 'package:immich_mobile/shared/models/immich_asset_with_exif.model.dart';
|
import 'package:immich_mobile/shared/models/immich_asset_with_exif.model.dart';
|
||||||
import 'package:immich_mobile/shared/services/network.service.dart';
|
import 'package:immich_mobile/shared/services/network.service.dart';
|
||||||
|
|
||||||
|
final assetServiceProvider =
|
||||||
|
Provider((ref) => AssetService(ref.watch(networkServiceProvider)));
|
||||||
|
|
||||||
class AssetService {
|
class AssetService {
|
||||||
final NetworkService _networkService = NetworkService();
|
final NetworkService _networkService;
|
||||||
|
AssetService(this._networkService);
|
||||||
|
|
||||||
Future<List<ImmichAsset>?> getAllAsset() async {
|
Future<List<ImmichAsset>?> getAllAsset() async {
|
||||||
var res = await _networkService.getRequest(url: "asset/");
|
var res = await _networkService.getRequest(url: "asset/");
|
||||||
try {
|
try {
|
||||||
List<dynamic> decodedData = jsonDecode(res.toString());
|
List<dynamic> decodedData = jsonDecode(res.toString());
|
||||||
|
|
||||||
List<ImmichAsset> result = List.from(decodedData.map((a) => ImmichAsset.fromMap(a)));
|
List<ImmichAsset> result =
|
||||||
|
List.from(decodedData.map((a) => ImmichAsset.fromMap(a)));
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint("Error getAllAsset ${e.toString()}");
|
debugPrint("Error getAllAsset ${e.toString()}");
|
||||||
@ -62,7 +68,8 @@ class AssetService {
|
|||||||
|
|
||||||
List<dynamic> decodedData = jsonDecode(res.toString());
|
List<dynamic> decodedData = jsonDecode(res.toString());
|
||||||
|
|
||||||
List<ImmichAsset> result = List.from(decodedData.map((a) => ImmichAsset.fromMap(a)));
|
List<ImmichAsset> result =
|
||||||
|
List.from(decodedData.map((a) => ImmichAsset.fromMap(a)));
|
||||||
if (result.isNotEmpty) {
|
if (result.isNotEmpty) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -90,7 +97,8 @@ class AssetService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<DeleteAssetResponse>?> deleteAssets(Set<ImmichAsset> deleteAssets) async {
|
Future<List<DeleteAssetResponse>?> deleteAssets(
|
||||||
|
Set<ImmichAsset> deleteAssets) async {
|
||||||
try {
|
try {
|
||||||
var payload = [];
|
var payload = [];
|
||||||
|
|
||||||
@ -98,11 +106,13 @@ class AssetService {
|
|||||||
payload.add(asset.id);
|
payload.add(asset.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = await _networkService.deleteRequest(url: "asset/", data: {"ids": payload});
|
var res = await _networkService
|
||||||
|
.deleteRequest(url: "asset/", data: {"ids": payload});
|
||||||
|
|
||||||
List<dynamic> decodedData = jsonDecode(res.toString());
|
List<dynamic> decodedData = jsonDecode(res.toString());
|
||||||
|
|
||||||
List<DeleteAssetResponse> result = List.from(decodedData.map((a) => DeleteAssetResponse.fromMap(a)));
|
List<DeleteAssetResponse> result =
|
||||||
|
List.from(decodedData.map((a) => DeleteAssetResponse.fromMap(a)));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -12,7 +12,8 @@ import 'package:immich_mobile/shared/services/network.service.dart';
|
|||||||
import 'package:immich_mobile/shared/models/device_info.model.dart';
|
import 'package:immich_mobile/shared/models/device_info.model.dart';
|
||||||
|
|
||||||
class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
||||||
AuthenticationNotifier(this.ref)
|
AuthenticationNotifier(
|
||||||
|
this._deviceInfoService, this._backupService, this._networkService)
|
||||||
: super(
|
: super(
|
||||||
AuthenticationState(
|
AuthenticationState(
|
||||||
deviceId: "",
|
deviceId: "",
|
||||||
@ -37,12 +38,12 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final Ref ref;
|
final DeviceInfoService _deviceInfoService;
|
||||||
final DeviceInfoService _deviceInfoService = DeviceInfoService();
|
final BackupService _backupService;
|
||||||
final BackupService _backupService = BackupService();
|
final NetworkService _networkService;
|
||||||
final NetworkService _networkService = NetworkService();
|
|
||||||
|
|
||||||
Future<bool> login(String email, String password, String serverEndpoint, bool isSavedLoginInfo) async {
|
Future<bool> login(String email, String password, String serverEndpoint,
|
||||||
|
bool isSavedLoginInfo) async {
|
||||||
// Store server endpoint to Hive and test endpoint
|
// Store server endpoint to Hive and test endpoint
|
||||||
if (serverEndpoint[serverEndpoint.length - 1] == "/") {
|
if (serverEndpoint[serverEndpoint.length - 1] == "/") {
|
||||||
var validUrl = serverEndpoint.substring(0, serverEndpoint.length - 1);
|
var validUrl = serverEndpoint.substring(0, serverEndpoint.length - 1);
|
||||||
@ -71,7 +72,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
|
|
||||||
// Make sign-in request
|
// Make sign-in request
|
||||||
try {
|
try {
|
||||||
Response res = await _networkService.postRequest(url: 'auth/login', data: {'email': email, 'password': password});
|
Response res = await _networkService.postRequest(
|
||||||
|
url: 'auth/login', data: {'email': email, 'password': password});
|
||||||
|
|
||||||
var payload = LogInReponse.fromJson(res.toString());
|
var payload = LogInReponse.fromJson(res.toString());
|
||||||
|
|
||||||
@ -99,7 +101,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
serverUrl: Hive.box(userInfoBox).get(serverEndpointKey)),
|
serverUrl: Hive.box(userInfoBox).get(serverEndpointKey)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox).delete(savedLoginInfoKey);
|
Hive.box<HiveSavedLoginInfo>(hiveLoginInfoBox)
|
||||||
|
.delete(savedLoginInfoKey);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@ -107,8 +110,9 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
|
|
||||||
// Register device info
|
// Register device info
|
||||||
try {
|
try {
|
||||||
Response res = await _networkService
|
Response res = await _networkService.postRequest(
|
||||||
.postRequest(url: 'device-info', data: {'deviceId': state.deviceId, 'deviceType': state.deviceType});
|
url: 'device-info',
|
||||||
|
data: {'deviceId': state.deviceId, 'deviceType': state.deviceType});
|
||||||
|
|
||||||
DeviceInfoRemote deviceInfo = DeviceInfoRemote.fromJson(res.toString());
|
DeviceInfoRemote deviceInfo = DeviceInfoRemote.fromJson(res.toString());
|
||||||
state = state.copyWith(deviceInfo: deviceInfo);
|
state = state.copyWith(deviceInfo: deviceInfo);
|
||||||
@ -151,7 +155,8 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
var deviceId = deviceInfo["deviceId"];
|
var deviceId = deviceInfo["deviceId"];
|
||||||
var deviceType = deviceInfo["deviceType"];
|
var deviceType = deviceInfo["deviceType"];
|
||||||
|
|
||||||
DeviceInfoRemote deviceInfoRemote = await _backupService.setAutoBackup(backupState, deviceId, deviceType);
|
DeviceInfoRemote deviceInfoRemote =
|
||||||
|
await _backupService.setAutoBackup(backupState, deviceId, deviceType);
|
||||||
state = state.copyWith(deviceInfo: deviceInfoRemote);
|
state = state.copyWith(deviceInfo: deviceInfoRemote);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +165,11 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final authenticationProvider = StateNotifierProvider<AuthenticationNotifier, AuthenticationState>((ref) {
|
final authenticationProvider =
|
||||||
return AuthenticationNotifier(ref);
|
StateNotifierProvider<AuthenticationNotifier, AuthenticationState>((ref) {
|
||||||
|
return AuthenticationNotifier(
|
||||||
|
ref.watch(deviceInfoServiceProvider),
|
||||||
|
ref.watch(backupServiceProvider),
|
||||||
|
ref.watch(networkServiceProvider),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,7 @@ import 'package:immich_mobile/modules/search/models/search_page_state.model.dart
|
|||||||
import 'package:immich_mobile/modules/search/services/search.service.dart';
|
import 'package:immich_mobile/modules/search/services/search.service.dart';
|
||||||
|
|
||||||
class SearchPageStateNotifier extends StateNotifier<SearchPageState> {
|
class SearchPageStateNotifier extends StateNotifier<SearchPageState> {
|
||||||
SearchPageStateNotifier()
|
SearchPageStateNotifier(this._searchService)
|
||||||
: super(
|
: super(
|
||||||
SearchPageState(
|
SearchPageState(
|
||||||
searchTerm: "",
|
searchTerm: "",
|
||||||
@ -16,7 +16,7 @@ class SearchPageStateNotifier extends StateNotifier<SearchPageState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final SearchService _searchService = SearchService();
|
final SearchService _searchService;
|
||||||
|
|
||||||
void enableSearch() {
|
void enableSearch() {
|
||||||
state = state.copyWith(isSearchEnabled: true);
|
state = state.copyWith(isSearchEnabled: true);
|
||||||
@ -54,12 +54,12 @@ class SearchPageStateNotifier extends StateNotifier<SearchPageState> {
|
|||||||
|
|
||||||
final searchPageStateProvider =
|
final searchPageStateProvider =
|
||||||
StateNotifierProvider<SearchPageStateNotifier, SearchPageState>((ref) {
|
StateNotifierProvider<SearchPageStateNotifier, SearchPageState>((ref) {
|
||||||
return SearchPageStateNotifier();
|
return SearchPageStateNotifier(ref.watch(searchServiceProvider));
|
||||||
});
|
});
|
||||||
|
|
||||||
final getCuratedLocationProvider =
|
final getCuratedLocationProvider =
|
||||||
FutureProvider.autoDispose<List<CuratedLocation>>((ref) async {
|
FutureProvider.autoDispose<List<CuratedLocation>>((ref) async {
|
||||||
final SearchService searchService = SearchService();
|
final SearchService searchService = ref.watch(searchServiceProvider);
|
||||||
|
|
||||||
var curatedLocation = await searchService.getCuratedLocation();
|
var curatedLocation = await searchService.getCuratedLocation();
|
||||||
if (curatedLocation != null) {
|
if (curatedLocation != null) {
|
||||||
@ -71,7 +71,7 @@ final getCuratedLocationProvider =
|
|||||||
|
|
||||||
final getCuratedObjectProvider =
|
final getCuratedObjectProvider =
|
||||||
FutureProvider.autoDispose<List<CuratedObject>>((ref) async {
|
FutureProvider.autoDispose<List<CuratedObject>>((ref) async {
|
||||||
final SearchService searchService = SearchService();
|
final SearchService searchService = ref.watch(searchServiceProvider);
|
||||||
|
|
||||||
var curatedObject = await searchService.getCuratedObjects();
|
var curatedObject = await searchService.getCuratedObjects();
|
||||||
if (curatedObject != null) {
|
if (curatedObject != null) {
|
||||||
|
@ -7,31 +7,48 @@ import 'package:immich_mobile/shared/models/immich_asset.model.dart';
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class SearchResultPageNotifier extends StateNotifier<SearchResultPageState> {
|
class SearchResultPageNotifier extends StateNotifier<SearchResultPageState> {
|
||||||
SearchResultPageNotifier()
|
SearchResultPageNotifier(this._searchService)
|
||||||
: super(SearchResultPageState(searchResult: [], isError: false, isLoading: true, isSuccess: false));
|
: super(
|
||||||
|
SearchResultPageState(
|
||||||
|
searchResult: [],
|
||||||
|
isError: false,
|
||||||
|
isLoading: true,
|
||||||
|
isSuccess: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final SearchService _searchService = SearchService();
|
final SearchService _searchService;
|
||||||
|
|
||||||
void search(String searchTerm) async {
|
void search(String searchTerm) async {
|
||||||
state = state.copyWith(searchResult: [], isError: false, isLoading: true, isSuccess: false);
|
state = state.copyWith(
|
||||||
|
searchResult: [], isError: false, isLoading: true, isSuccess: false);
|
||||||
|
|
||||||
List<ImmichAsset>? assets = await _searchService.searchAsset(searchTerm);
|
List<ImmichAsset>? assets = await _searchService.searchAsset(searchTerm);
|
||||||
|
|
||||||
if (assets != null) {
|
if (assets != null) {
|
||||||
state = state.copyWith(searchResult: assets, isError: false, isLoading: false, isSuccess: true);
|
state = state.copyWith(
|
||||||
|
searchResult: assets,
|
||||||
|
isError: false,
|
||||||
|
isLoading: false,
|
||||||
|
isSuccess: true);
|
||||||
} else {
|
} else {
|
||||||
state = state.copyWith(searchResult: [], isError: true, isLoading: false, isSuccess: false);
|
state = state.copyWith(
|
||||||
|
searchResult: [], isError: true, isLoading: false, isSuccess: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final searchResultPageProvider = StateNotifierProvider<SearchResultPageNotifier, SearchResultPageState>((ref) {
|
final searchResultPageProvider =
|
||||||
return SearchResultPageNotifier();
|
StateNotifierProvider<SearchResultPageNotifier, SearchResultPageState>(
|
||||||
|
(ref) {
|
||||||
|
return SearchResultPageNotifier(ref.watch(searchServiceProvider));
|
||||||
});
|
});
|
||||||
|
|
||||||
final searchResultGroupByDateTimeProvider = StateProvider((ref) {
|
final searchResultGroupByDateTimeProvider = StateProvider((ref) {
|
||||||
var assets = ref.watch(searchResultPageProvider).searchResult;
|
var assets = ref.watch(searchResultPageProvider).searchResult;
|
||||||
|
|
||||||
assets.sortByCompare<DateTime>((e) => DateTime.parse(e.createdAt), (a, b) => b.compareTo(a));
|
assets.sortByCompare<DateTime>(
|
||||||
return assets.groupListsBy((element) => DateFormat('y-MM-dd').format(DateTime.parse(element.createdAt)));
|
(e) => DateTime.parse(e.createdAt), (a, b) => b.compareTo(a));
|
||||||
|
return assets.groupListsBy((element) =>
|
||||||
|
DateFormat('y-MM-dd').format(DateTime.parse(element.createdAt)));
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/modules/search/models/curated_location.model.dart';
|
import 'package:immich_mobile/modules/search/models/curated_location.model.dart';
|
||||||
import 'package:immich_mobile/modules/search/models/curated_object.model.dart';
|
import 'package:immich_mobile/modules/search/models/curated_object.model.dart';
|
||||||
import 'package:immich_mobile/shared/models/immich_asset.model.dart';
|
import 'package:immich_mobile/shared/models/immich_asset.model.dart';
|
||||||
import 'package:immich_mobile/shared/services/network.service.dart';
|
import 'package:immich_mobile/shared/services/network.service.dart';
|
||||||
|
|
||||||
|
final searchServiceProvider =
|
||||||
|
Provider((ref) => SearchService(ref.watch(networkServiceProvider)));
|
||||||
|
|
||||||
class SearchService {
|
class SearchService {
|
||||||
final NetworkService _networkService = NetworkService();
|
final NetworkService _networkService;
|
||||||
|
SearchService(this._networkService);
|
||||||
|
|
||||||
Future<List<String>?> getUserSuggestedSearchTerms() async {
|
Future<List<String>?> getUserSuggestedSearchTerms() async {
|
||||||
try {
|
try {
|
||||||
@ -30,7 +35,8 @@ class SearchService {
|
|||||||
|
|
||||||
List<dynamic> decodedData = jsonDecode(res.toString());
|
List<dynamic> decodedData = jsonDecode(res.toString());
|
||||||
|
|
||||||
List<ImmichAsset> result = List.from(decodedData.map((a) => ImmichAsset.fromMap(a)));
|
List<ImmichAsset> result =
|
||||||
|
List.from(decodedData.map((a) => ImmichAsset.fromMap(a)));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -45,7 +51,8 @@ class SearchService {
|
|||||||
|
|
||||||
List<dynamic> decodedData = jsonDecode(res.toString());
|
List<dynamic> decodedData = jsonDecode(res.toString());
|
||||||
|
|
||||||
List<CuratedLocation> result = List.from(decodedData.map((a) => CuratedLocation.fromMap(a)));
|
List<CuratedLocation> result =
|
||||||
|
List.from(decodedData.map((a) => CuratedLocation.fromMap(a)));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -60,7 +67,8 @@ class SearchService {
|
|||||||
|
|
||||||
List<dynamic> decodedData = jsonDecode(res.toString());
|
List<dynamic> decodedData = jsonDecode(res.toString());
|
||||||
|
|
||||||
List<CuratedObject> result = List.from(decodedData.map((a) => CuratedObject.fromMap(a)));
|
List<CuratedObject> result =
|
||||||
|
List.from(decodedData.map((a) => CuratedObject.fromMap(a)));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -18,7 +18,7 @@ import 'package:immich_mobile/utils/capitalize_first_letter.dart';
|
|||||||
class SearchPage extends HookConsumerWidget {
|
class SearchPage extends HookConsumerWidget {
|
||||||
SearchPage({Key? key}) : super(key: key);
|
SearchPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
late FocusNode searchFocusNode;
|
FocusNode searchFocusNode = FocusNode();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
@ -4,7 +4,8 @@ import 'package:immich_mobile/modules/sharing/providers/shared_album.provider.da
|
|||||||
import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart';
|
import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart';
|
||||||
|
|
||||||
class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
||||||
AlbumViewerNotifier(this.ref) : super(AlbumViewerPageState(editTitleText: "", isEditAlbum: false));
|
AlbumViewerNotifier(this.ref)
|
||||||
|
: super(AlbumViewerPageState(editTitleText: "", isEditAlbum: false));
|
||||||
|
|
||||||
final Ref ref;
|
final Ref ref;
|
||||||
|
|
||||||
@ -28,10 +29,12 @@ class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
|||||||
state = state.copyWith(editTitleText: "", isEditAlbum: false);
|
state = state.copyWith(editTitleText: "", isEditAlbum: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> changeAlbumTitle(String albumId, String ownerId, String newAlbumTitle) async {
|
Future<bool> changeAlbumTitle(
|
||||||
SharedAlbumService service = SharedAlbumService();
|
String albumId, String ownerId, String newAlbumTitle) async {
|
||||||
|
SharedAlbumService service = ref.watch(sharedAlbumServiceProvider);
|
||||||
|
|
||||||
bool isSuccess = await service.changeTitleAlbum(albumId, ownerId, newAlbumTitle);
|
bool isSuccess =
|
||||||
|
await service.changeTitleAlbum(albumId, ownerId, newAlbumTitle);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
state = state.copyWith(editTitleText: "", isEditAlbum: false);
|
state = state.copyWith(editTitleText: "", isEditAlbum: false);
|
||||||
@ -45,6 +48,7 @@ class AlbumViewerNotifier extends StateNotifier<AlbumViewerPageState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final albumViewerProvider = StateNotifierProvider<AlbumViewerNotifier, AlbumViewerPageState>((ref) {
|
final albumViewerProvider =
|
||||||
|
StateNotifierProvider<AlbumViewerNotifier, AlbumViewerPageState>((ref) {
|
||||||
return AlbumViewerNotifier(ref);
|
return AlbumViewerNotifier(ref);
|
||||||
});
|
});
|
||||||
|
@ -3,9 +3,9 @@ import 'package:immich_mobile/modules/sharing/models/shared_album.model.dart';
|
|||||||
import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart';
|
import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart';
|
||||||
|
|
||||||
class SharedAlbumNotifier extends StateNotifier<List<SharedAlbum>> {
|
class SharedAlbumNotifier extends StateNotifier<List<SharedAlbum>> {
|
||||||
SharedAlbumNotifier() : super([]);
|
SharedAlbumNotifier(this._sharedAlbumService) : super([]);
|
||||||
|
|
||||||
final SharedAlbumService _sharedAlbumService = SharedAlbumService();
|
final SharedAlbumService _sharedAlbumService;
|
||||||
|
|
||||||
getAllSharedAlbums() async {
|
getAllSharedAlbums() async {
|
||||||
List<SharedAlbum> sharedAlbums =
|
List<SharedAlbum> sharedAlbums =
|
||||||
@ -50,12 +50,13 @@ class SharedAlbumNotifier extends StateNotifier<List<SharedAlbum>> {
|
|||||||
|
|
||||||
final sharedAlbumProvider =
|
final sharedAlbumProvider =
|
||||||
StateNotifierProvider<SharedAlbumNotifier, List<SharedAlbum>>((ref) {
|
StateNotifierProvider<SharedAlbumNotifier, List<SharedAlbum>>((ref) {
|
||||||
return SharedAlbumNotifier();
|
return SharedAlbumNotifier(ref.watch(sharedAlbumServiceProvider));
|
||||||
});
|
});
|
||||||
|
|
||||||
final sharedAlbumDetailProvider = FutureProvider.autoDispose
|
final sharedAlbumDetailProvider = FutureProvider.autoDispose
|
||||||
.family<SharedAlbum, String>((ref, albumId) async {
|
.family<SharedAlbum, String>((ref, albumId) async {
|
||||||
final SharedAlbumService sharedAlbumService = SharedAlbumService();
|
final SharedAlbumService sharedAlbumService =
|
||||||
|
ref.watch(sharedAlbumServiceProvider);
|
||||||
|
|
||||||
return await sharedAlbumService.getAlbumDetail(albumId);
|
return await sharedAlbumService.getAlbumDetail(albumId);
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:immich_mobile/shared/models/user.model.dart';
|
import 'package:immich_mobile/shared/models/user.model.dart';
|
||||||
import 'package:immich_mobile/shared/services/user.service.dart';
|
import 'package:immich_mobile/shared/services/user.service.dart';
|
||||||
|
|
||||||
final suggestedSharedUsersProvider = FutureProvider.autoDispose<List<User>>((ref) async {
|
final suggestedSharedUsersProvider =
|
||||||
UserService userService = UserService();
|
FutureProvider.autoDispose<List<User>>((ref) async {
|
||||||
|
UserService userService = ref.watch(userServiceProvider);
|
||||||
|
|
||||||
return await userService.getAllUsersInfo();
|
return await userService.getAllUsersInfo();
|
||||||
});
|
});
|
||||||
|
@ -3,12 +3,17 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/modules/sharing/models/shared_album.model.dart';
|
import 'package:immich_mobile/modules/sharing/models/shared_album.model.dart';
|
||||||
import 'package:immich_mobile/shared/models/immich_asset.model.dart';
|
import 'package:immich_mobile/shared/models/immich_asset.model.dart';
|
||||||
import 'package:immich_mobile/shared/services/network.service.dart';
|
import 'package:immich_mobile/shared/services/network.service.dart';
|
||||||
|
|
||||||
|
final sharedAlbumServiceProvider =
|
||||||
|
Provider((ref) => SharedAlbumService(ref.watch(networkServiceProvider)));
|
||||||
|
|
||||||
class SharedAlbumService {
|
class SharedAlbumService {
|
||||||
final NetworkService _networkService = NetworkService();
|
final NetworkService _networkService;
|
||||||
|
SharedAlbumService(this._networkService);
|
||||||
|
|
||||||
Future<List<SharedAlbum>> getAllSharedAlbum() async {
|
Future<List<SharedAlbum>> getAllSharedAlbum() async {
|
||||||
try {
|
try {
|
||||||
|
@ -53,8 +53,10 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
if (returnPayload.selectedAdditionalAsset.isNotEmpty) {
|
if (returnPayload.selectedAdditionalAsset.isNotEmpty) {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
ImmichLoadingOverlayController.appLoader.show();
|
||||||
|
|
||||||
var isSuccess = await SharedAlbumService().addAdditionalAssetToAlbum(
|
var isSuccess = await ref
|
||||||
returnPayload.selectedAdditionalAsset, albumId);
|
.watch(sharedAlbumServiceProvider)
|
||||||
|
.addAdditionalAssetToAlbum(
|
||||||
|
returnPayload.selectedAdditionalAsset, albumId);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
ref.refresh(sharedAlbumDetailProvider(albumId));
|
ref.refresh(sharedAlbumDetailProvider(albumId));
|
||||||
@ -77,7 +79,8 @@ class AlbumViewerPage extends HookConsumerWidget {
|
|||||||
if (sharedUserIds != null) {
|
if (sharedUserIds != null) {
|
||||||
ImmichLoadingOverlayController.appLoader.show();
|
ImmichLoadingOverlayController.appLoader.show();
|
||||||
|
|
||||||
var isSuccess = await SharedAlbumService()
|
var isSuccess = await ref
|
||||||
|
.watch(sharedAlbumServiceProvider)
|
||||||
.addAdditionalUserToAlbum(sharedUserIds, albumId);
|
.addAdditionalUserToAlbum(sharedUserIds, albumId);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
|
@ -16,24 +16,28 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final sharedUsersList = useState<Set<User>>({});
|
final sharedUsersList = useState<Set<User>>({});
|
||||||
AsyncValue<List<User>> suggestedShareUsers = ref.watch(suggestedSharedUsersProvider);
|
AsyncValue<List<User>> suggestedShareUsers =
|
||||||
|
ref.watch(suggestedSharedUsersProvider);
|
||||||
|
|
||||||
_createSharedAlbum() async {
|
_createSharedAlbum() async {
|
||||||
var isSuccess = await SharedAlbumService().createSharedAlbum(
|
var isSuccess =
|
||||||
ref.watch(albumTitleProvider),
|
await ref.watch(sharedAlbumServiceProvider).createSharedAlbum(
|
||||||
ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum,
|
ref.watch(albumTitleProvider),
|
||||||
sharedUsersList.value.map((userInfo) => userInfo.id).toList(),
|
ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum,
|
||||||
);
|
sharedUsersList.value.map((userInfo) => userInfo.id).toList(),
|
||||||
|
);
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
||||||
ref.watch(assetSelectionProvider.notifier).removeAll();
|
ref.watch(assetSelectionProvider.notifier).removeAll();
|
||||||
ref.watch(albumTitleProvider.notifier).clearAlbumTitle();
|
ref.watch(albumTitleProvider.notifier).clearAlbumTitle();
|
||||||
|
|
||||||
AutoRouter.of(context).navigate(const TabControllerRoute(children: [SharingRoute()]));
|
AutoRouter.of(context)
|
||||||
|
.navigate(const TabControllerRoute(children: [SharingRoute()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScaffoldMessenger(child: SnackBar(content: Text('Failed to create album')));
|
const ScaffoldMessenger(
|
||||||
|
child: SnackBar(content: Text('Failed to create album')));
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildTileIcon(User user) {
|
_buildTileIcon(User user) {
|
||||||
@ -47,7 +51,8 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundImage: const AssetImage('assets/immich-logo-no-outline.png'),
|
backgroundImage:
|
||||||
|
const AssetImage('assets/immich-logo-no-outline.png'),
|
||||||
backgroundColor: Theme.of(context).primaryColor.withAlpha(50),
|
backgroundColor: Theme.of(context).primaryColor.withAlpha(50),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -64,7 +69,10 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.15),
|
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.15),
|
||||||
label: Text(
|
label: Text(
|
||||||
user.email,
|
user.email,
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.black87, fontWeight: FontWeight.bold),
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.black87,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -80,7 +88,10 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
padding: EdgeInsets.all(16.0),
|
padding: EdgeInsets.all(16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Suggestions',
|
'Suggestions',
|
||||||
style: TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold),
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
@ -90,14 +101,20 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
leading: _buildTileIcon(users[index]),
|
leading: _buildTileIcon(users[index]),
|
||||||
title: Text(
|
title: Text(
|
||||||
users[index].email,
|
users[index].email,
|
||||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
|
style: const TextStyle(
|
||||||
|
fontSize: 14, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (sharedUsersList.value.contains(users[index])) {
|
if (sharedUsersList.value.contains(users[index])) {
|
||||||
sharedUsersList.value =
|
sharedUsersList.value = sharedUsersList.value
|
||||||
sharedUsersList.value.where((selectedUser) => selectedUser.id != users[index].id).toSet();
|
.where((selectedUser) =>
|
||||||
|
selectedUser.id != users[index].id)
|
||||||
|
.toSet();
|
||||||
} else {
|
} else {
|
||||||
sharedUsersList.value = {...sharedUsersList.value, users[index]};
|
sharedUsersList.value = {
|
||||||
|
...sharedUsersList.value,
|
||||||
|
users[index]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -124,7 +141,8 @@ class SelectUserForSharingPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: sharedUsersList.value.isEmpty ? null : _createSharedAlbum,
|
onPressed:
|
||||||
|
sharedUsersList.value.isEmpty ? null : _createSharedAlbum,
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"Create Album",
|
"Create Album",
|
||||||
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
|
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
|
||||||
|
@ -9,11 +9,10 @@ import 'package:intl/intl.dart';
|
|||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
class AssetNotifier extends StateNotifier<List<ImmichAsset>> {
|
class AssetNotifier extends StateNotifier<List<ImmichAsset>> {
|
||||||
final AssetService _assetService = AssetService();
|
final AssetService _assetService;
|
||||||
final DeviceInfoService _deviceInfoService = DeviceInfoService();
|
final DeviceInfoService _deviceInfoService = DeviceInfoService();
|
||||||
final Ref ref;
|
|
||||||
|
|
||||||
AssetNotifier(this.ref) : super([]);
|
AssetNotifier(this._assetService) : super([]);
|
||||||
|
|
||||||
getAllAsset() async {
|
getAllAsset() async {
|
||||||
List<ImmichAsset>? allAssets = await _assetService.getAllAsset();
|
List<ImmichAsset>? allAssets = await _assetService.getAllAsset();
|
||||||
@ -71,7 +70,7 @@ class AssetNotifier extends StateNotifier<List<ImmichAsset>> {
|
|||||||
|
|
||||||
final assetProvider =
|
final assetProvider =
|
||||||
StateNotifierProvider<AssetNotifier, List<ImmichAsset>>((ref) {
|
StateNotifierProvider<AssetNotifier, List<ImmichAsset>>((ref) {
|
||||||
return AssetNotifier(ref);
|
return AssetNotifier(ref.watch(assetServiceProvider));
|
||||||
});
|
});
|
||||||
|
|
||||||
final assetGroupByDateTimeProvider = StateProvider((ref) {
|
final assetGroupByDateTimeProvider = StateProvider((ref) {
|
||||||
|
@ -7,7 +7,7 @@ import 'package:immich_mobile/shared/services/server_info.service.dart';
|
|||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
||||||
ServerInfoNotifier()
|
ServerInfoNotifier(this._serverInfoService)
|
||||||
: super(
|
: super(
|
||||||
ServerInfoState(
|
ServerInfoState(
|
||||||
mapboxInfo: MapboxInfo(isEnable: false, mapboxSecret: ""),
|
mapboxInfo: MapboxInfo(isEnable: false, mapboxSecret: ""),
|
||||||
@ -18,7 +18,7 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final ServerInfoService _serverInfoService = ServerInfoService();
|
final ServerInfoService _serverInfoService;
|
||||||
|
|
||||||
getServerVersion() async {
|
getServerVersion() async {
|
||||||
ServerVersion? serverVersion = await _serverInfoService.getServerVersion();
|
ServerVersion? serverVersion = await _serverInfoService.getServerVersion();
|
||||||
@ -79,5 +79,5 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
|||||||
|
|
||||||
final serverInfoProvider =
|
final serverInfoProvider =
|
||||||
StateNotifierProvider<ServerInfoNotifier, ServerInfoState>((ref) {
|
StateNotifierProvider<ServerInfoNotifier, ServerInfoState>((ref) {
|
||||||
return ServerInfoNotifier();
|
return ServerInfoNotifier(ref.watch(serverInfoServiceProvider));
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import 'package:flutter_udid/flutter_udid.dart';
|
import 'package:flutter_udid/flutter_udid.dart';
|
||||||
import 'dart:io' show Platform;
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
final deviceInfoServiceProvider = Provider((_) => DeviceInfoService());
|
||||||
|
|
||||||
class DeviceInfoService {
|
class DeviceInfoService {
|
||||||
Future<Map<String, dynamic>> getDeviceInfo() async {
|
Future<Map<String, dynamic>> getDeviceInfo() async {
|
||||||
// Get device info
|
// Get device info
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/hive_box.dart';
|
import 'package:immich_mobile/constants/hive_box.dart';
|
||||||
|
|
||||||
|
final localStorageServiceProvider = Provider((_) => LocalStorageService());
|
||||||
|
|
||||||
class LocalStorageService {
|
class LocalStorageService {
|
||||||
late Box _box;
|
late Box _box;
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@ import 'dart:convert';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:http_parser/http_parser.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
|
||||||
import 'package:immich_mobile/constants/hive_box.dart';
|
import 'package:immich_mobile/constants/hive_box.dart';
|
||||||
import 'package:immich_mobile/utils/dio_http_interceptor.dart';
|
import 'package:immich_mobile/utils/dio_http_interceptor.dart';
|
||||||
import 'package:immich_mobile/utils/files_helper.dart';
|
|
||||||
|
final networkServiceProvider = Provider((_) => NetworkService());
|
||||||
|
|
||||||
class NetworkService {
|
class NetworkService {
|
||||||
late final Dio dio;
|
late final Dio dio;
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/shared/models/server_info.model.dart';
|
import 'package:immich_mobile/shared/models/server_info.model.dart';
|
||||||
import 'package:immich_mobile/shared/models/server_version.model.dart';
|
import 'package:immich_mobile/shared/models/server_version.model.dart';
|
||||||
import 'package:immich_mobile/shared/services/network.service.dart';
|
import 'package:immich_mobile/shared/services/network.service.dart';
|
||||||
|
|
||||||
|
final serverInfoServiceProvider =
|
||||||
|
Provider((ref) => ServerInfoService(ref.watch(networkServiceProvider)));
|
||||||
|
|
||||||
class ServerInfoService {
|
class ServerInfoService {
|
||||||
final NetworkService _networkService = NetworkService();
|
final NetworkService _networkService;
|
||||||
|
ServerInfoService(this._networkService);
|
||||||
|
|
||||||
Future<ServerInfo> getServerInfo() async {
|
Future<ServerInfo> getServerInfo() async {
|
||||||
Response response = await _networkService.getRequest(url: 'server-info');
|
Response response = await _networkService.getRequest(url: 'server-info');
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:http_parser/http_parser.dart';
|
import 'package:http_parser/http_parser.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:immich_mobile/constants/hive_box.dart';
|
import 'package:immich_mobile/constants/hive_box.dart';
|
||||||
@ -12,8 +13,12 @@ import 'package:immich_mobile/shared/services/network.service.dart';
|
|||||||
import 'package:immich_mobile/utils/dio_http_interceptor.dart';
|
import 'package:immich_mobile/utils/dio_http_interceptor.dart';
|
||||||
import 'package:immich_mobile/utils/files_helper.dart';
|
import 'package:immich_mobile/utils/files_helper.dart';
|
||||||
|
|
||||||
|
final userServiceProvider =
|
||||||
|
Provider((ref) => UserService(ref.watch(networkServiceProvider)));
|
||||||
|
|
||||||
class UserService {
|
class UserService {
|
||||||
final NetworkService _networkService = NetworkService();
|
final NetworkService _networkService;
|
||||||
|
UserService(this._networkService);
|
||||||
|
|
||||||
Future<List<User>> getAllUsersInfo() async {
|
Future<List<User>> getAllUsersInfo() async {
|
||||||
try {
|
try {
|
||||||
|
Loading…
Reference in New Issue
Block a user