mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 13:38:13 -08:00
fix: Sync leaving left over temp files (#73)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
c5e39db9ec
commit
8d15e319d3
15 changed files with 644 additions and 406 deletions
|
|
@ -267,8 +267,8 @@
|
||||||
"@hideEmpty": {},
|
"@hideEmpty": {},
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"@home": {},
|
"@home": {},
|
||||||
"homeBannerBanner": "Banner",
|
"homeBannerSlideshow": "Slideshow",
|
||||||
"@homeBannerBanner": {},
|
"@homeBannerSlideshow": {},
|
||||||
"homeBannerCarousel": "Carousel",
|
"homeBannerCarousel": "Carousel",
|
||||||
"@homeBannerCarousel": {},
|
"@homeBannerCarousel": {},
|
||||||
"identify": "Identify",
|
"identify": "Identify",
|
||||||
|
|
@ -947,5 +947,44 @@
|
||||||
"example": "1"
|
"example": "1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"syncStatusEnqueued": "Enqueued",
|
||||||
|
"syncStatusRunning": "Running",
|
||||||
|
"syncStatusComplete": "Complete",
|
||||||
|
"syncStatusNotFound": "Not Found",
|
||||||
|
"syncStatusFailed": "Failed",
|
||||||
|
"syncStatusCanceled": "Canceled",
|
||||||
|
"syncStatusWaitingToRetry": "Waiting to retry",
|
||||||
|
"syncStatusPaused": "Paused",
|
||||||
|
"syncStatusSynced": "Synced",
|
||||||
|
"syncStatusPartially": "Partially",
|
||||||
|
"syncOverlayDeleting": "Removing synced item",
|
||||||
|
"syncOverlaySyncing": "Syncing item details",
|
||||||
|
"syncSelectDownloadsFolder": "Select downloads folder",
|
||||||
|
"syncNoFolderSetup": "No sync folder setup",
|
||||||
|
"syncRemoveUnableToDeleteItem": "Unable to remove synced item, somethin went wrong",
|
||||||
|
"syncAddItemForSyncing": "Added {item} for syncing",
|
||||||
|
"@syncAddItemForSyncing":{
|
||||||
|
"placeholders": {
|
||||||
|
"item":{
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ,
|
||||||
|
"startedSyncingItem": "Started syncing {item}",
|
||||||
|
"@startedSyncingItem": {
|
||||||
|
"placeholders": {
|
||||||
|
"item":{
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unableToSyncItem": "Unable to sync {item}, something went wrong",
|
||||||
|
"@unableToSyncItem": {
|
||||||
|
"placeholders": {
|
||||||
|
"item":{
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ enum HomeBanner {
|
||||||
String label(BuildContext context) => switch (this) {
|
String label(BuildContext context) => switch (this) {
|
||||||
HomeBanner.hide => context.localized.hide,
|
HomeBanner.hide => context.localized.hide,
|
||||||
HomeBanner.carousel => context.localized.homeBannerCarousel,
|
HomeBanner.carousel => context.localized.homeBannerCarousel,
|
||||||
HomeBanner.banner => context.localized.homeBannerBanner,
|
HomeBanner.banner => context.localized.homeBannerSlideshow,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ part 'i_synced_item.g.dart';
|
||||||
class ISyncedItem {
|
class ISyncedItem {
|
||||||
String? userId;
|
String? userId;
|
||||||
String id;
|
String id;
|
||||||
|
bool syncing;
|
||||||
String? sortName;
|
String? sortName;
|
||||||
String? parentId;
|
String? parentId;
|
||||||
String? path;
|
String? path;
|
||||||
|
|
@ -42,6 +43,7 @@ class ISyncedItem {
|
||||||
ISyncedItem({
|
ISyncedItem({
|
||||||
this.userId,
|
this.userId,
|
||||||
required this.id,
|
required this.id,
|
||||||
|
required this.syncing,
|
||||||
this.sortName,
|
this.sortName,
|
||||||
this.parentId,
|
this.parentId,
|
||||||
this.path,
|
this.path,
|
||||||
|
|
@ -59,6 +61,7 @@ class ISyncedItem {
|
||||||
return ISyncedItem(
|
return ISyncedItem(
|
||||||
id: syncedItem.id,
|
id: syncedItem.id,
|
||||||
parentId: syncedItem.parentId,
|
parentId: syncedItem.parentId,
|
||||||
|
syncing: syncedItem.syncing,
|
||||||
userId: syncedItem.userId,
|
userId: syncedItem.userId,
|
||||||
path: syncedItem.path?.replaceAll(path ?? "", '').substring(1),
|
path: syncedItem.path?.replaceAll(path ?? "", '').substring(1),
|
||||||
fileSize: syncedItem.fileSize,
|
fileSize: syncedItem.fileSize,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -20,6 +20,7 @@ import 'package:fladder/models/items/trick_play_model.dart';
|
||||||
import 'package:fladder/models/syncing/i_synced_item.dart';
|
import 'package:fladder/models/syncing/i_synced_item.dart';
|
||||||
import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
||||||
import 'package:fladder/providers/sync_provider.dart';
|
import 'package:fladder/providers/sync_provider.dart';
|
||||||
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
|
|
||||||
part 'sync_item.freezed.dart';
|
part 'sync_item.freezed.dart';
|
||||||
|
|
||||||
|
|
@ -29,6 +30,7 @@ class SyncedItem with _$SyncedItem {
|
||||||
|
|
||||||
factory SyncedItem({
|
factory SyncedItem({
|
||||||
required String id,
|
required String id,
|
||||||
|
@Default(false) bool syncing,
|
||||||
String? parentId,
|
String? parentId,
|
||||||
required String userId,
|
required String userId,
|
||||||
String? path,
|
String? path,
|
||||||
|
|
@ -72,7 +74,7 @@ class SyncedItem with _$SyncedItem {
|
||||||
_ => SyncStatus.partially,
|
_ => SyncStatus.partially,
|
||||||
};
|
};
|
||||||
|
|
||||||
String? get taskId => null;
|
String? get taskId => task?.taskId;
|
||||||
|
|
||||||
bool get childHasTask => false;
|
bool get childHasTask => false;
|
||||||
|
|
||||||
|
|
@ -126,6 +128,7 @@ class SyncedItem with _$SyncedItem {
|
||||||
parentId: isarSyncedItem.parentId,
|
parentId: isarSyncedItem.parentId,
|
||||||
userId: isarSyncedItem.userId ?? "",
|
userId: isarSyncedItem.userId ?? "",
|
||||||
sortName: isarSyncedItem.sortName,
|
sortName: isarSyncedItem.sortName,
|
||||||
|
syncing: isarSyncedItem.syncing,
|
||||||
path: joinAll([savePath, isarSyncedItem.path ?? ""]),
|
path: joinAll([savePath, isarSyncedItem.path ?? ""]),
|
||||||
fileSize: isarSyncedItem.fileSize,
|
fileSize: isarSyncedItem.fileSize,
|
||||||
videoFileName: isarSyncedItem.videoFileName,
|
videoFileName: isarSyncedItem.videoFileName,
|
||||||
|
|
@ -155,21 +158,25 @@ class SyncedItem with _$SyncedItem {
|
||||||
|
|
||||||
enum SyncStatus {
|
enum SyncStatus {
|
||||||
complete(
|
complete(
|
||||||
"Synced",
|
|
||||||
Color.fromARGB(255, 141, 214, 58),
|
Color.fromARGB(255, 141, 214, 58),
|
||||||
IconsaxOutline.tick_circle,
|
IconsaxOutline.tick_circle,
|
||||||
),
|
),
|
||||||
partially(
|
partially(
|
||||||
"Partially",
|
|
||||||
Color.fromARGB(255, 221, 135, 23),
|
Color.fromARGB(255, 221, 135, 23),
|
||||||
IconsaxOutline.more_circle,
|
IconsaxOutline.more_circle,
|
||||||
),
|
),
|
||||||
;
|
;
|
||||||
|
|
||||||
const SyncStatus(this.label, this.color, this.icon);
|
const SyncStatus(this.color, this.icon);
|
||||||
|
|
||||||
final Color color;
|
final Color color;
|
||||||
final String label;
|
String label(BuildContext context) {
|
||||||
|
return switch (this) {
|
||||||
|
SyncStatus.partially => context.localized.syncStatusPartially,
|
||||||
|
SyncStatus.complete => context.localized.syncStatusSynced,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,14 +190,14 @@ extension StatusExtension on TaskStatus {
|
||||||
TaskStatus.paused => Colors.orangeAccent,
|
TaskStatus.paused => Colors.orangeAccent,
|
||||||
};
|
};
|
||||||
|
|
||||||
String get name => switch (this) {
|
String name(BuildContext context) => switch (this) {
|
||||||
TaskStatus.enqueued => 'Enqueued',
|
TaskStatus.enqueued => context.localized.syncStatusEnqueued,
|
||||||
TaskStatus.running => 'Running',
|
TaskStatus.running => context.localized.syncStatusRunning,
|
||||||
TaskStatus.complete => 'Complete',
|
TaskStatus.complete => context.localized.syncStatusComplete,
|
||||||
TaskStatus.notFound => 'Not Found',
|
TaskStatus.notFound => context.localized.syncStatusNotFound,
|
||||||
TaskStatus.failed => 'Failed',
|
TaskStatus.failed => context.localized.syncStatusFailed,
|
||||||
TaskStatus.canceled => 'Canceled',
|
TaskStatus.canceled => context.localized.syncStatusCanceled,
|
||||||
TaskStatus.waitingToRetry => 'Waiting To Retry',
|
TaskStatus.waitingToRetry => context.localized.syncStatusWaitingToRetry,
|
||||||
TaskStatus.paused => 'Paused',
|
TaskStatus.paused => context.localized.syncStatusPaused,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ final _privateConstructorUsedError = UnsupportedError(
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SyncedItem {
|
mixin _$SyncedItem {
|
||||||
String get id => throw _privateConstructorUsedError;
|
String get id => throw _privateConstructorUsedError;
|
||||||
|
bool get syncing => throw _privateConstructorUsedError;
|
||||||
String? get parentId => throw _privateConstructorUsedError;
|
String? get parentId => throw _privateConstructorUsedError;
|
||||||
String get userId => throw _privateConstructorUsedError;
|
String get userId => throw _privateConstructorUsedError;
|
||||||
String? get path => throw _privateConstructorUsedError;
|
String? get path => throw _privateConstructorUsedError;
|
||||||
|
|
@ -48,6 +49,7 @@ abstract class $SyncedItemCopyWith<$Res> {
|
||||||
@useResult
|
@useResult
|
||||||
$Res call(
|
$Res call(
|
||||||
{String id,
|
{String id,
|
||||||
|
bool syncing,
|
||||||
String? parentId,
|
String? parentId,
|
||||||
String userId,
|
String userId,
|
||||||
String? path,
|
String? path,
|
||||||
|
|
@ -82,6 +84,7 @@ class _$SyncedItemCopyWithImpl<$Res, $Val extends SyncedItem>
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? id = null,
|
Object? id = null,
|
||||||
|
Object? syncing = null,
|
||||||
Object? parentId = freezed,
|
Object? parentId = freezed,
|
||||||
Object? userId = null,
|
Object? userId = null,
|
||||||
Object? path = freezed,
|
Object? path = freezed,
|
||||||
|
|
@ -101,6 +104,10 @@ class _$SyncedItemCopyWithImpl<$Res, $Val extends SyncedItem>
|
||||||
? _value.id
|
? _value.id
|
||||||
: id // ignore: cast_nullable_to_non_nullable
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
|
syncing: null == syncing
|
||||||
|
? _value.syncing
|
||||||
|
: syncing // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
parentId: freezed == parentId
|
parentId: freezed == parentId
|
||||||
? _value.parentId
|
? _value.parentId
|
||||||
: parentId // ignore: cast_nullable_to_non_nullable
|
: parentId // ignore: cast_nullable_to_non_nullable
|
||||||
|
|
@ -195,6 +202,7 @@ abstract class _$$SyncItemImplCopyWith<$Res>
|
||||||
@useResult
|
@useResult
|
||||||
$Res call(
|
$Res call(
|
||||||
{String id,
|
{String id,
|
||||||
|
bool syncing,
|
||||||
String? parentId,
|
String? parentId,
|
||||||
String userId,
|
String userId,
|
||||||
String? path,
|
String? path,
|
||||||
|
|
@ -229,6 +237,7 @@ class __$$SyncItemImplCopyWithImpl<$Res>
|
||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? id = null,
|
Object? id = null,
|
||||||
|
Object? syncing = null,
|
||||||
Object? parentId = freezed,
|
Object? parentId = freezed,
|
||||||
Object? userId = null,
|
Object? userId = null,
|
||||||
Object? path = freezed,
|
Object? path = freezed,
|
||||||
|
|
@ -248,6 +257,10 @@ class __$$SyncItemImplCopyWithImpl<$Res>
|
||||||
? _value.id
|
? _value.id
|
||||||
: id // ignore: cast_nullable_to_non_nullable
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
|
syncing: null == syncing
|
||||||
|
? _value.syncing
|
||||||
|
: syncing // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
parentId: freezed == parentId
|
parentId: freezed == parentId
|
||||||
? _value.parentId
|
? _value.parentId
|
||||||
: parentId // ignore: cast_nullable_to_non_nullable
|
: parentId // ignore: cast_nullable_to_non_nullable
|
||||||
|
|
@ -309,6 +322,7 @@ class __$$SyncItemImplCopyWithImpl<$Res>
|
||||||
class _$SyncItemImpl extends _SyncItem {
|
class _$SyncItemImpl extends _SyncItem {
|
||||||
_$SyncItemImpl(
|
_$SyncItemImpl(
|
||||||
{required this.id,
|
{required this.id,
|
||||||
|
this.syncing = false,
|
||||||
this.parentId,
|
this.parentId,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
this.path,
|
this.path,
|
||||||
|
|
@ -329,6 +343,9 @@ class _$SyncItemImpl extends _SyncItem {
|
||||||
@override
|
@override
|
||||||
final String id;
|
final String id;
|
||||||
@override
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final bool syncing;
|
||||||
|
@override
|
||||||
final String? parentId;
|
final String? parentId;
|
||||||
@override
|
@override
|
||||||
final String userId;
|
final String userId;
|
||||||
|
|
@ -373,7 +390,7 @@ class _$SyncItemImpl extends _SyncItem {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SyncedItem(id: $id, parentId: $parentId, userId: $userId, path: $path, markedForDelete: $markedForDelete, sortName: $sortName, fileSize: $fileSize, videoFileName: $videoFileName, introOutSkipModel: $introOutSkipModel, fTrickPlayModel: $fTrickPlayModel, fImages: $fImages, fChapters: $fChapters, subtitles: $subtitles, userData: $userData)';
|
return 'SyncedItem(id: $id, syncing: $syncing, parentId: $parentId, userId: $userId, path: $path, markedForDelete: $markedForDelete, sortName: $sortName, fileSize: $fileSize, videoFileName: $videoFileName, introOutSkipModel: $introOutSkipModel, fTrickPlayModel: $fTrickPlayModel, fImages: $fImages, fChapters: $fChapters, subtitles: $subtitles, userData: $userData)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -382,6 +399,7 @@ class _$SyncItemImpl extends _SyncItem {
|
||||||
(other.runtimeType == runtimeType &&
|
(other.runtimeType == runtimeType &&
|
||||||
other is _$SyncItemImpl &&
|
other is _$SyncItemImpl &&
|
||||||
(identical(other.id, id) || other.id == id) &&
|
(identical(other.id, id) || other.id == id) &&
|
||||||
|
(identical(other.syncing, syncing) || other.syncing == syncing) &&
|
||||||
(identical(other.parentId, parentId) ||
|
(identical(other.parentId, parentId) ||
|
||||||
other.parentId == parentId) &&
|
other.parentId == parentId) &&
|
||||||
(identical(other.userId, userId) || other.userId == userId) &&
|
(identical(other.userId, userId) || other.userId == userId) &&
|
||||||
|
|
@ -411,6 +429,7 @@ class _$SyncItemImpl extends _SyncItem {
|
||||||
int get hashCode => Object.hash(
|
int get hashCode => Object.hash(
|
||||||
runtimeType,
|
runtimeType,
|
||||||
id,
|
id,
|
||||||
|
syncing,
|
||||||
parentId,
|
parentId,
|
||||||
userId,
|
userId,
|
||||||
path,
|
path,
|
||||||
|
|
@ -437,6 +456,7 @@ class _$SyncItemImpl extends _SyncItem {
|
||||||
abstract class _SyncItem extends SyncedItem {
|
abstract class _SyncItem extends SyncedItem {
|
||||||
factory _SyncItem(
|
factory _SyncItem(
|
||||||
{required final String id,
|
{required final String id,
|
||||||
|
final bool syncing,
|
||||||
final String? parentId,
|
final String? parentId,
|
||||||
required final String userId,
|
required final String userId,
|
||||||
final String? path,
|
final String? path,
|
||||||
|
|
@ -455,6 +475,8 @@ abstract class _SyncItem extends SyncedItem {
|
||||||
@override
|
@override
|
||||||
String get id;
|
String get id;
|
||||||
@override
|
@override
|
||||||
|
bool get syncing;
|
||||||
|
@override
|
||||||
String? get parentId;
|
String? get parentId;
|
||||||
@override
|
@override
|
||||||
String get userId;
|
String get userId;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
import 'package:fladder/jellyfin/jellyfin_open_api.swagger.dart';
|
||||||
import 'package:fladder/models/item_base_model.dart';
|
import 'package:fladder/models/item_base_model.dart';
|
||||||
|
|
@ -35,6 +36,7 @@ import 'package:fladder/providers/settings/client_settings_provider.dart';
|
||||||
import 'package:fladder/providers/sync/background_download_provider.dart';
|
import 'package:fladder/providers/sync/background_download_provider.dart';
|
||||||
import 'package:fladder/providers/user_provider.dart';
|
import 'package:fladder/providers/user_provider.dart';
|
||||||
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
||||||
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
|
|
||||||
final syncProvider = StateNotifierProvider<SyncNotifier, SyncSettingsModel>((ref) => throw UnimplementedError());
|
final syncProvider = StateNotifierProvider<SyncNotifier, SyncSettingsModel>((ref) => throw UnimplementedError());
|
||||||
|
|
||||||
|
|
@ -46,6 +48,7 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _init() {
|
void _init() {
|
||||||
|
cleanupTemporaryFiles();
|
||||||
ref.listen(
|
ref.listen(
|
||||||
userProvider,
|
userProvider,
|
||||||
(previous, next) {
|
(previous, next) {
|
||||||
|
|
@ -84,6 +87,35 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> cleanupTemporaryFiles() async {
|
||||||
|
// List of directories to check
|
||||||
|
final directories = [
|
||||||
|
//Desktop directory
|
||||||
|
await getTemporaryDirectory(),
|
||||||
|
//Mobile directory
|
||||||
|
await getApplicationSupportDirectory(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (final dir in directories) {
|
||||||
|
final List<FileSystemEntity> files = dir.listSync();
|
||||||
|
|
||||||
|
for (var file in files) {
|
||||||
|
if (file is File) {
|
||||||
|
final fileName = file.path.split(Platform.pathSeparator).last;
|
||||||
|
final fileSize = await file.length();
|
||||||
|
if (fileName.startsWith('com.bbflight.background_downloader') && fileSize != 0) {
|
||||||
|
try {
|
||||||
|
await file.delete();
|
||||||
|
log('Deleted temporary file: $fileName from ${dir.path}');
|
||||||
|
} catch (e) {
|
||||||
|
log('Failed to delete file $fileName: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final Ref ref;
|
final Ref ref;
|
||||||
final Isar? isar;
|
final Isar? isar;
|
||||||
final Directory mobileDirectory;
|
final Directory mobileDirectory;
|
||||||
|
|
@ -190,19 +222,20 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
||||||
return syncedItem.createItemModel(ref);
|
return syncedItem.createItemModel(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SyncedItem?> addSyncItem(BuildContext? context, ItemBaseModel item) async {
|
Future<void> addSyncItem(BuildContext? context, ItemBaseModel item) async {
|
||||||
if (context == null) return null;
|
if (context == null) return;
|
||||||
|
|
||||||
if (saveDirectory == null) {
|
if (saveDirectory == null) {
|
||||||
String? selectedDirectory = await FilePicker.platform.getDirectoryPath(dialogTitle: 'Select downloads folder');
|
String? selectedDirectory =
|
||||||
|
await FilePicker.platform.getDirectoryPath(dialogTitle: context.localized.syncSelectDownloadsFolder);
|
||||||
if (selectedDirectory?.isEmpty == true) {
|
if (selectedDirectory?.isEmpty == true) {
|
||||||
fladderSnackbar(context, title: "No sync folder setup");
|
fladderSnackbar(context, title: context.localized.syncNoFolderSetup);
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
ref.read(clientSettingsProvider.notifier).setSyncPath(selectedDirectory);
|
ref.read(clientSettingsProvider.notifier).setSyncPath(selectedDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
fladderSnackbar(context, title: "Added ${item.detailedName(context)} for syncing");
|
fladderSnackbar(context, title: context.localized.syncAddItemForSyncing(item.detailedName(context) ?? "Unknown"));
|
||||||
final newSync = switch (item) {
|
final newSync = switch (item) {
|
||||||
EpisodeModel episode => await syncSeries(item.parentBaseModel, episode: episode),
|
EpisodeModel episode => await syncSeries(item.parentBaseModel, episode: episode),
|
||||||
SeriesModel series => await syncSeries(series),
|
SeriesModel series => await syncSeries(series),
|
||||||
|
|
@ -211,12 +244,12 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
||||||
};
|
};
|
||||||
fladderSnackbar(context,
|
fladderSnackbar(context,
|
||||||
title: newSync != null
|
title: newSync != null
|
||||||
? "Started syncing ${item.detailedName(context)}"
|
? context.localized.startedSyncingItem(item.detailedName(context) ?? "Unknown")
|
||||||
: "Unable to sync ${item.detailedName(context)}, type not supported?");
|
: context.localized.unableToSyncItem(item.detailedName(context) ?? "Unknown"));
|
||||||
return newSync;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> removeSync(SyncedItem? item) async {
|
Future<bool> removeSync(BuildContext context, SyncedItem? item) async {
|
||||||
try {
|
try {
|
||||||
if (item == null) return false;
|
if (item == null) return false;
|
||||||
|
|
||||||
|
|
@ -259,6 +292,8 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Error deleting synced item');
|
log('Error deleting synced item');
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
|
state = state.copyWith(items: state.items.map((e) => e.copyWith(markedForDelete: false)).toList());
|
||||||
|
fladderSnackbar(context, title: context.localized.syncRemoveUnableToDeleteItem);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -366,14 +401,23 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
||||||
isar?.write((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncedItem, syncPath ?? "")));
|
isar?.write((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncedItem, syncPath ?? "")));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SyncedItem> deleteFullSyncFiles(SyncedItem syncedItem) async {
|
Future<SyncedItem> deleteFullSyncFiles(SyncedItem syncedItem, DownloadTask? task) async {
|
||||||
await syncedItem.deleteDatFiles(ref);
|
await syncedItem.deleteDatFiles(ref);
|
||||||
|
|
||||||
ref.read(downloadTasksProvider(syncedItem.id).notifier).update((state) => DownloadStream.empty());
|
ref.read(downloadTasksProvider(syncedItem.id).notifier).update((state) => DownloadStream.empty());
|
||||||
|
|
||||||
|
final taskId = task?.taskId;
|
||||||
|
if (taskId != null) {
|
||||||
|
ref.read(backgroundDownloaderProvider).cancelTaskWithId(taskId);
|
||||||
|
}
|
||||||
|
cleanupTemporaryFiles();
|
||||||
refresh();
|
refresh();
|
||||||
return syncedItem;
|
return syncedItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<DownloadStream?> syncVideoFile(SyncedItem syncItem, bool skipDownload) async {
|
Future<DownloadStream?> syncVideoFile(SyncedItem syncItem, bool skipDownload) async {
|
||||||
|
cleanupTemporaryFiles();
|
||||||
|
|
||||||
final playbackResponse = await api.itemsItemIdPlaybackInfoPost(
|
final playbackResponse = await api.itemsItemIdPlaybackInfoPost(
|
||||||
itemId: syncItem.id,
|
itemId: syncItem.id,
|
||||||
body: const PlaybackInfoDto(
|
body: const PlaybackInfoDto(
|
||||||
|
|
@ -480,27 +524,37 @@ extension SyncNotifierHelpers on SyncNotifier {
|
||||||
|
|
||||||
final Directory? parentDirectory = parent?.directory;
|
final Directory? parentDirectory = parent?.directory;
|
||||||
|
|
||||||
SyncedItem syncItem = SyncedItem(id: item.id, userId: ref.read(userProvider)?.id ?? "");
|
|
||||||
final directory = Directory(path.joinAll([(parentDirectory ?? saveDirectory)?.path ?? "", item.id]));
|
final directory = Directory(path.joinAll([(parentDirectory ?? saveDirectory)?.path ?? "", item.id]));
|
||||||
|
|
||||||
await directory.create(recursive: true);
|
await directory.create(recursive: true);
|
||||||
|
|
||||||
File dataFile = File(path.joinAll([directory.path, 'data.json']));
|
File dataFile = File(path.joinAll([directory.path, 'data.json']));
|
||||||
await dataFile.writeAsString(jsonEncode(response.toJson()));
|
await dataFile.writeAsString(jsonEncode(response.toJson()));
|
||||||
|
|
||||||
final imageData = await saveImageData(item.images, directory);
|
final imageData = await saveImageData(item.images, directory);
|
||||||
final origChapters = Chapter.chaptersFromInfo(item.id, response.chapters ?? [], ref);
|
|
||||||
|
|
||||||
return syncItem.copyWith(
|
SyncedItem syncItem = SyncedItem(
|
||||||
|
syncing: true,
|
||||||
id: item.id,
|
id: item.id,
|
||||||
parentId: parent?.id,
|
parentId: parent?.id,
|
||||||
sortName: response.sortName,
|
sortName: response.sortName,
|
||||||
|
fImages: imageData,
|
||||||
|
userId: ref.read(userProvider)?.id ?? "",
|
||||||
path: directory.path,
|
path: directory.path,
|
||||||
|
userData: item.userData,
|
||||||
|
);
|
||||||
|
|
||||||
|
//Save item if parent so the user is aware.
|
||||||
|
if (parent == null) {
|
||||||
|
isar?.write((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncItem, syncPath)));
|
||||||
|
}
|
||||||
|
|
||||||
|
final origChapters = Chapter.chaptersFromInfo(item.id, response.chapters ?? [], ref);
|
||||||
|
|
||||||
|
return syncItem.copyWith(
|
||||||
fChapters: await saveChapterImages(origChapters, directory) ?? [],
|
fChapters: await saveChapterImages(origChapters, directory) ?? [],
|
||||||
fileSize: response.mediaSources?.firstOrNull?.size ?? 0,
|
fileSize: response.mediaSources?.firstOrNull?.size ?? 0,
|
||||||
fImages: imageData,
|
syncing: false,
|
||||||
videoFileName: response.path?.split('/').lastOrNull ?? "",
|
videoFileName: response.path?.split('/').lastOrNull ?? "",
|
||||||
userData: item.userData,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -528,7 +582,7 @@ extension SyncNotifierHelpers on SyncNotifier {
|
||||||
|
|
||||||
await syncVideoFile(syncItem, skipDownload);
|
await syncVideoFile(syncItem, skipDownload);
|
||||||
|
|
||||||
await isar?.writeAsync((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncItem, syncPath)));
|
isar?.write((isar) => syncedItems?.put(ISyncedItem.fromSynced(syncItem, syncPath)));
|
||||||
|
|
||||||
return syncItem;
|
return syncItem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ import 'package:fladder/screens/shared/default_alert_dialog.dart';
|
||||||
import 'package:fladder/screens/shared/media/poster_widget.dart';
|
import 'package:fladder/screens/shared/media/poster_widget.dart';
|
||||||
import 'package:fladder/screens/syncing/sync_child_item.dart';
|
import 'package:fladder/screens/syncing/sync_child_item.dart';
|
||||||
import 'package:fladder/screens/syncing/sync_widgets.dart';
|
import 'package:fladder/screens/syncing/sync_widgets.dart';
|
||||||
import 'package:fladder/screens/syncing/widgets/sync_markedfordelete.dart';
|
|
||||||
import 'package:fladder/screens/syncing/widgets/sync_progress_builder.dart';
|
import 'package:fladder/screens/syncing/widgets/sync_progress_builder.dart';
|
||||||
|
import 'package:fladder/screens/syncing/widgets/sync_status_overlay.dart';
|
||||||
import 'package:fladder/util/adaptive_layout.dart';
|
import 'package:fladder/util/adaptive_layout.dart';
|
||||||
import 'package:fladder/util/list_padding.dart';
|
import 'package:fladder/util/list_padding.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
|
|
@ -55,7 +55,7 @@ class _SyncItemDetailsState extends ConsumerState<SyncItemDetails> {
|
||||||
final syncChildren = ref.read(syncProvider.notifier).getChildren(syncedItem);
|
final syncChildren = ref.read(syncProvider.notifier).getChildren(syncedItem);
|
||||||
final downloadTask = ref.read(downloadTasksProvider(syncedItem.id));
|
final downloadTask = ref.read(downloadTasksProvider(syncedItem.id));
|
||||||
|
|
||||||
return SyncMarkedForDelete(
|
return SyncStatusOverlay(
|
||||||
syncedItem: syncedItem,
|
syncedItem: syncedItem,
|
||||||
child: ActionContent(
|
child: ActionContent(
|
||||||
title: Row(
|
title: Row(
|
||||||
|
|
@ -135,7 +135,9 @@ class _SyncItemDetailsState extends ConsumerState<SyncItemDetails> {
|
||||||
icon: const Icon(IconsaxBold.play),
|
icon: const Icon(IconsaxBold.play),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem),
|
onPressed: () => ref
|
||||||
|
.read(syncProvider.notifier)
|
||||||
|
.deleteFullSyncFiles(syncedItem, combinedStream?.task),
|
||||||
icon: const Icon(IconsaxBold.stop),
|
icon: const Icon(IconsaxBold.stop),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -177,7 +179,7 @@ class _SyncItemDetailsState extends ConsumerState<SyncItemDetails> {
|
||||||
context.localized.syncRemoveDataTitle,
|
context.localized.syncRemoveDataTitle,
|
||||||
context.localized.syncRemoveDataDesc,
|
context.localized.syncRemoveDataDesc,
|
||||||
(context) {
|
(context) {
|
||||||
ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem);
|
ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem, downloadTask.task);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
context.localized.delete,
|
context.localized.delete,
|
||||||
|
|
@ -217,7 +219,7 @@ class _SyncItemDetailsState extends ConsumerState<SyncItemDetails> {
|
||||||
context.localized.syncDeleteItemTitle,
|
context.localized.syncDeleteItemTitle,
|
||||||
context.localized.syncDeleteItemDesc(baseItem?.detailedName(context) ?? ""),
|
context.localized.syncDeleteItemDesc(baseItem?.detailedName(context) ?? ""),
|
||||||
(context) async {
|
(context) async {
|
||||||
await ref.read(syncProvider.notifier).removeSync(syncedItem);
|
await ref.read(syncProvider.notifier).removeSync(context, syncedItem);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:ficonsax/ficonsax.dart';
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/syncing/sync_item.dart';
|
import 'package:fladder/models/syncing/sync_item.dart';
|
||||||
import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
||||||
import 'package:fladder/providers/sync_provider.dart';
|
import 'package:fladder/providers/sync_provider.dart';
|
||||||
import 'package:fladder/screens/shared/default_alert_dialog.dart';
|
import 'package:fladder/screens/shared/default_alert_dialog.dart';
|
||||||
import 'package:fladder/screens/syncing/sync_item_details.dart';
|
import 'package:fladder/screens/syncing/sync_item_details.dart';
|
||||||
import 'package:fladder/screens/syncing/sync_widgets.dart';
|
import 'package:fladder/screens/syncing/sync_widgets.dart';
|
||||||
import 'package:fladder/screens/syncing/widgets/sync_markedfordelete.dart';
|
|
||||||
import 'package:fladder/screens/syncing/widgets/sync_progress_builder.dart';
|
import 'package:fladder/screens/syncing/widgets/sync_progress_builder.dart';
|
||||||
|
import 'package:fladder/screens/syncing/widgets/sync_status_overlay.dart';
|
||||||
import 'package:fladder/util/fladder_image.dart';
|
import 'package:fladder/util/fladder_image.dart';
|
||||||
import 'package:fladder/util/list_padding.dart';
|
import 'package:fladder/util/list_padding.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/util/size_formatting.dart';
|
import 'package:fladder/util/size_formatting.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
|
|
||||||
class SyncListItem extends ConsumerStatefulWidget {
|
class SyncListItem extends ConsumerStatefulWidget {
|
||||||
final SyncedItem syncedItem;
|
final SyncedItem syncedItem;
|
||||||
|
|
@ -29,7 +31,7 @@ class SyncListItemState extends ConsumerState<SyncListItem> {
|
||||||
final baseItem = ref.read(syncProvider.notifier).getItem(syncedItem);
|
final baseItem = ref.read(syncProvider.notifier).getItem(syncedItem);
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: SyncMarkedForDelete(
|
child: SyncStatusOverlay(
|
||||||
syncedItem: syncedItem,
|
syncedItem: syncedItem,
|
||||||
child: Card(
|
child: Card(
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
|
|
@ -53,7 +55,7 @@ class SyncListItemState extends ConsumerState<SyncListItem> {
|
||||||
context.localized.deleteItem(baseItem?.detailedName(context) ?? ""),
|
context.localized.deleteItem(baseItem?.detailedName(context) ?? ""),
|
||||||
context.localized.syncDeletePopupPermanent,
|
context.localized.syncDeletePopupPermanent,
|
||||||
(context) async {
|
(context) async {
|
||||||
ref.read(syncProvider.notifier).removeSync(syncedItem);
|
ref.read(syncProvider.notifier).removeSync(context, syncedItem);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:background_downloader/background_downloader.dart';
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:ficonsax/ficonsax.dart';
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/items/episode_model.dart';
|
import 'package:fladder/models/items/episode_model.dart';
|
||||||
import 'package:fladder/models/items/season_model.dart';
|
import 'package:fladder/models/items/season_model.dart';
|
||||||
import 'package:fladder/models/items/series_model.dart';
|
import 'package:fladder/models/items/series_model.dart';
|
||||||
|
|
@ -10,8 +14,6 @@ import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
||||||
import 'package:fladder/providers/sync_provider.dart';
|
import 'package:fladder/providers/sync_provider.dart';
|
||||||
import 'package:fladder/util/list_padding.dart';
|
import 'package:fladder/util/list_padding.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
|
|
||||||
class SyncLabel extends ConsumerWidget {
|
class SyncLabel extends ConsumerWidget {
|
||||||
final String? label;
|
final String? label;
|
||||||
|
|
@ -28,7 +30,7 @@ class SyncLabel extends ConsumerWidget {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
child: Text(
|
child: Text(
|
||||||
label ?? status.label,
|
label ?? status.label(context),
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: status.color,
|
color: status.color,
|
||||||
|
|
@ -55,7 +57,7 @@ class SyncProgressBar extends ConsumerWidget {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(downloadStatus.name),
|
Text(downloadStatus.name(context)),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -82,7 +84,7 @@ class SyncProgressBar extends ConsumerWidget {
|
||||||
icon: const Icon(IconsaxBold.play),
|
icon: const Icon(IconsaxBold.play),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => ref.read(syncProvider.notifier).deleteFullSyncFiles(item),
|
onPressed: () => ref.read(syncProvider.notifier).deleteFullSyncFiles(item, downloadTask),
|
||||||
icon: const Icon(IconsaxBold.stop),
|
icon: const Icon(IconsaxBold.stop),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
@ -129,7 +131,7 @@ class SyncSubtitle extends ConsumerWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_ => Text(syncStatus.label),
|
_ => Text(syncStatus.label(context)),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/syncing/sync_item.dart';
|
import 'package:fladder/models/syncing/sync_item.dart';
|
||||||
import 'package:fladder/util/list_padding.dart';
|
import 'package:fladder/util/list_padding.dart';
|
||||||
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
|
|
||||||
///This is a wrapper widget for marking a synced item as deleted (while it is being deleted)
|
class SyncStatusOverlay extends ConsumerWidget {
|
||||||
class SyncMarkedForDelete extends ConsumerWidget {
|
|
||||||
final SyncedItem syncedItem;
|
final SyncedItem syncedItem;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const SyncMarkedForDelete({required this.syncedItem, required this.child, super.key});
|
const SyncStatusOverlay({required this.syncedItem, required this.child, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
|
@ -32,12 +32,35 @@ class SyncMarkedForDelete extends ConsumerWidget {
|
||||||
strokeCap: StrokeCap.round,
|
strokeCap: StrokeCap.round,
|
||||||
valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.error),
|
valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.error),
|
||||||
),
|
),
|
||||||
const Text("Deleting"),
|
Text(context.localized.syncOverlayDeleting),
|
||||||
const Icon(IconsaxOutline.trash)
|
const Icon(IconsaxOutline.trash)
|
||||||
].addPadding(const EdgeInsets.symmetric(horizontal: 16)),
|
].addPadding(const EdgeInsets.symmetric(horizontal: 16)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
if (syncedItem.syncing)
|
||||||
|
Positioned.fill(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: Card(
|
||||||
|
elevation: 0,
|
||||||
|
semanticContainer: false,
|
||||||
|
color: Colors.black.withOpacity(0.6),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
CircularProgressIndicator.adaptive(
|
||||||
|
strokeCap: StrokeCap.round,
|
||||||
|
valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.error),
|
||||||
|
),
|
||||||
|
Text(context.localized.syncOverlaySyncing),
|
||||||
|
const Icon(IconsaxOutline.cloud_notif)
|
||||||
|
].addPadding(const EdgeInsets.symmetric(horizontal: 16)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,8 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:ficonsax/ficonsax.dart';
|
import 'package:ficonsax/ficonsax.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import 'package:fladder/models/items/episode_model.dart';
|
import 'package:fladder/models/items/episode_model.dart';
|
||||||
import 'package:fladder/models/syncing/sync_item.dart';
|
import 'package:fladder/models/syncing/sync_item.dart';
|
||||||
import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
import 'package:fladder/providers/sync/sync_provider_helpers.dart';
|
||||||
|
|
@ -10,8 +14,6 @@ import 'package:fladder/util/list_padding.dart';
|
||||||
import 'package:fladder/util/localization_helper.dart';
|
import 'package:fladder/util/localization_helper.dart';
|
||||||
import 'package:fladder/util/size_formatting.dart';
|
import 'package:fladder/util/size_formatting.dart';
|
||||||
import 'package:fladder/widgets/shared/icon_button_await.dart';
|
import 'package:fladder/widgets/shared/icon_button_await.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
|
|
||||||
class SyncedEpisodeItem extends ConsumerStatefulWidget {
|
class SyncedEpisodeItem extends ConsumerStatefulWidget {
|
||||||
const SyncedEpisodeItem({
|
const SyncedEpisodeItem({
|
||||||
|
|
@ -106,7 +108,7 @@ class _SyncedEpisodeItemState extends ConsumerState<SyncedEpisodeItem> {
|
||||||
context.localized.syncRemoveDataTitle,
|
context.localized.syncRemoveDataTitle,
|
||||||
context.localized.syncRemoveDataDesc,
|
context.localized.syncRemoveDataDesc,
|
||||||
(context) async {
|
(context) async {
|
||||||
await ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem);
|
await ref.read(syncProvider.notifier).deleteFullSyncFiles(syncedItem, downloadTask.task);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
context.localized.delete,
|
context.localized.delete,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
|
||||||
set(BINARY_NAME "Fladder")
|
set(BINARY_NAME "Fladder")
|
||||||
# The unique GTK application identifier for this application. See:
|
# The unique GTK application identifier for this application. See:
|
||||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||||
set(APPLICATION_ID "com.example.fladder")
|
set(APPLICATION_ID "nl.jknaapen.fladder")
|
||||||
|
|
||||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||||
# versions of CMake.
|
# versions of CMake.
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,4 @@ PRODUCT_NAME = Fladder
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder
|
PRODUCT_BUNDLE_IDENTIFIER = nl.jknaapen.fladder
|
||||||
|
|
||||||
// The copyright displayed in application information
|
// The copyright displayed in application information
|
||||||
PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved.
|
PRODUCT_COPYRIGHT = Copyright © 2023 Donutware. All rights reserved.
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,11 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
BLOCK "040904e4"
|
BLOCK "040904e4"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "com.example" "\0"
|
VALUE "CompanyName", "DonutWare" "\0"
|
||||||
VALUE "FileDescription", "fladder" "\0"
|
VALUE "FileDescription", "fladder" "\0"
|
||||||
VALUE "FileVersion", VERSION_AS_STRING "\0"
|
VALUE "FileVersion", VERSION_AS_STRING "\0"
|
||||||
VALUE "InternalName", "nl.jknaapen.fladder" "\0"
|
VALUE "InternalName", "nl.jknaapen.fladder" "\0"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0"
|
VALUE "LegalCopyright", "Copyright (C) 2023 DonutWare. All rights reserved." "\0"
|
||||||
VALUE "OriginalFilename", "fladder.exe" "\0"
|
VALUE "OriginalFilename", "fladder.exe" "\0"
|
||||||
VALUE "ProductName", "fladder" "\0"
|
VALUE "ProductName", "fladder" "\0"
|
||||||
VALUE "ProductVersion", VERSION_AS_STRING "\0"
|
VALUE "ProductVersion", VERSION_AS_STRING "\0"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue