Fladder/lib/providers/edit_item_provider.dart
2024-09-20 10:01:13 +02:00

234 lines
7.7 KiB
Dart

import 'dart:convert';
import 'package:chopper/chopper.dart';
import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/item_editing_model.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
import 'package:fladder/providers/api_provider.dart';
final editItemProvider =
StateNotifierProvider.autoDispose<EditItemNotifier, ItemEditingModel>((ref) => EditItemNotifier(ref));
class EditItemNotifier extends StateNotifier<ItemEditingModel> {
EditItemNotifier(this.ref) : super(ItemEditingModel());
final Ref ref;
late final api = ref.read(jellyApiProvider);
Map<String, dynamic>? get getFields => state.editAbleFields();
Map<String, dynamic>? get advancedFields => state.editAdvancedAbleFields(ref);
Future<void> fetchInformation(String id) async {
state = ItemEditingModel();
final itemResponse = await api.usersUserIdItemsItemIdGet(
itemId: id,
);
final itemModel = itemResponse.body;
if (itemModel == null) return;
final images = await api.itemsItemIdImagesGet(itemId: itemModel.id);
state = state.copyWith(
item: () => itemModel,
json: () => jsonDecode(itemResponse.bodyString),
editedJson: () => jsonDecode(itemResponse.bodyString),
primary: state.primary.copyWith(
serverImages: images.body
?.where((element) => element.imageType == ImageType.primary)
.map((e) => EditingImageModel.fromImage(e, itemModel.id, ref))
.toList(),
),
logo: state.logo.copyWith(
serverImages: images.body
?.where((element) => element.imageType == ImageType.logo)
.map((e) => EditingImageModel.fromImage(e, itemModel.id, ref))
.toList(),
),
backdrop: state.backdrop.copyWith(
serverImages: images.body
?.where((element) => element.imageType == ImageType.backdrop)
.map((e) => EditingImageModel.fromImage(e, itemModel.id, ref))
.toList(),
),
);
final response = await api.itemsItemIdMetadataEditorGet(itemId: id);
state = state.copyWith(
editorInfo: () => response.bodyOrThrow,
);
}
Future<Response<dynamic>?> fetchRemoteImages({ImageType type = ImageType.primary}) async {
final currentItem = state.item;
if (currentItem == null) return null;
final response = await api.itemsItemIdRemoteImagesGet(
itemId: currentItem.id,
type: type,
includeAllLanguages: state.includeAllImages,
);
final newImages = (response.body?.images ?? []).map((e) => EditingImageModel.fromDto(e)).toList();
switch (type) {
case ImageType.backdrop:
state = state.copyWith(backdrop: state.backdrop.copyWith(images: newImages));
case ImageType.logo:
state = state.copyWith(logo: state.logo.copyWith(images: newImages));
case ImageType.primary:
default:
state = state.copyWith(primary: state.primary.copyWith(images: newImages));
}
return response;
}
Future<void> updateField(MapEntry<String, dynamic> field) async {
final editedJson = state.editedJson;
editedJson?.update(
field.key,
(value) => field.value,
ifAbsent: () => editedJson.addEntries({field}),
);
state = state.copyWith(
editedJson: () => editedJson,
);
}
Future<void> resetChanged() async {
state = state.copyWith(
editedJson: () => state.json,
);
}
Future<Response<ItemBaseModel>?> saveInformation() async {
final currentItem = state.item;
if (currentItem == null) return null;
final jsonBody = state.editedJson;
if (jsonBody == null) return null;
state = state.copyWith(saving: true);
final response = await api.itemsItemIdPost(
itemId: currentItem.id,
body: BaseItemDto.fromJson(jsonBody),
);
await state.primary.setImage(
ImageType.primary,
uploadData: uploadImage,
uploadUrl: _setImage,
);
await state.logo.setImage(
ImageType.logo,
uploadData: uploadImage,
uploadUrl: _setImage,
);
await state.backdrop.setImage(
ImageType.backdrop,
uploadData: uploadImage,
uploadUrl: _setImage,
);
final newItem = await api.usersUserIdItemsItemIdGet(itemId: currentItem.id);
state = state.copyWith(saving: false);
return response.copyWith(body: newItem.body);
}
Future<Response<dynamic>?> uploadImage(EditingImageModel? imageModel) async {
final currentItem = state.item;
if (currentItem == null || imageModel == null) return null;
final response = await api.itemIdImagesImageTypePost(
imageModel.type,
currentItem.id,
imageModel.imageData!,
);
return response;
}
Future<Response<dynamic>?> _setImage(EditingImageModel? imageModel) async {
final currentItem = state.item;
if (currentItem == null) return null;
if (imageModel == null) return null;
return await api.itemsItemIdRemoteImagesDownloadPost(
itemId: state.item?.id,
type: imageModel.type,
imageUrl: imageModel.url,
);
}
void selectImage(ImageType type, EditingImageModel? image) {
switch (type) {
case ImageType.primary:
state = state.copyWith(
primary: state.primary.copyWith(selected: () => state.primary.selected == image ? null : image));
case ImageType.logo:
state = state.copyWith(logo: state.logo.copyWith(selected: () => state.logo.selected == image ? null : image));
default:
if (image == null) return;
state = state.copyWith(
backdrop: state.backdrop.copyWith(
selection: state.backdrop.selection.contains(image)
? (List.of(state.backdrop.selection)..remove(image))
: [...state.backdrop.selection, image],
),
);
return;
}
}
void setIncludeImages(bool value) => state = state.copyWith(includeAllImages: value);
void addCustomImages(ImageType type, Iterable<EditingImageModel> list) {
switch (type) {
case ImageType.primary:
state = state.copyWith(
primary: state.primary.copyWith(
customImages: [...state.primary.customImages, ...list],
selected: () => list.firstOrNull,
),
);
return;
case ImageType.logo:
state = state.copyWith(
logo: state.logo.copyWith(
customImages: [...state.logo.customImages, ...list],
selected: () => list.firstOrNull,
),
);
return;
case ImageType.backdrop:
state = state.copyWith(
backdrop: state.backdrop.copyWith(
customImages: [...state.backdrop.customImages, ...list],
selection: [...state.backdrop.selection, ...list]),
);
default:
return;
}
}
Future<Response<dynamic>?> deleteImage(ImageType type, EditingImageModel image) async {
final currentItem = state.item;
if (currentItem == null) return null;
final response = await api.itemsItemIdImagesImageTypeDelete(
itemId: state.item?.id,
imageType: type,
imageIndex: image.index,
);
switch (type) {
case ImageType.primary:
state = state.copyWith(
primary: state.primary
.copyWith(serverImages: state.primary.serverImages..removeWhere((element) => element == image)),
);
case ImageType.logo:
state = state.copyWith(
logo: state.logo.copyWith(serverImages: state.logo.serverImages..removeWhere((element) => element == image)),
);
case ImageType.backdrop:
state = state.copyWith(
backdrop: state.backdrop
.copyWith(serverImages: state.backdrop.serverImages..removeWhere((element) => element == image)),
);
default:
}
return response;
}
}