finished snapshots and added auto sync

This commit is contained in:
Schnitzel5 2025-02-13 23:41:26 +01:00
parent 815ccbc19a
commit 7b00d0f7e4
13 changed files with 492 additions and 61 deletions

View file

@ -225,8 +225,26 @@
"sync_pending_track": "Ausstehende Änderungen für Trackings",
"sync_snapshot_creating": "Erstelle Snapshot...",
"sync_snapshot_created": "Snapshot wurde erstellt!",
"sync_snapshot_deleting": "Lösche Snapshot...",
"sync_snapshot_deleted": "Snapshot wurde gelöscht!",
"sync_snapshot_no_data": "Keine Daten zum Sichern! Lade erstmal alles hoch!",
"server_error": "Server error!",
"sync_browse_snapshots": "Durchsuche ältere Backups",
"sync_snapshots": "Snapshots",
"sync_load_snapshot": "Snapshot laden",
"sync_delete_snapshot": "Snapshot löschen",
"sync_auto": "Auto Sync",
"sync_auto_warning": "Auto Sync ist derzeit ein experimentelles Feature!",
"sync_auto_off": "Aus",
"sync_auto_30_seconds": "Alle 30 Sekunden",
"sync_auto_1_minute": "Jede Minute",
"sync_auto_5_minutes": "Alle 5 Minuten",
"sync_auto_10_minutes": "Alle 10 Minuten",
"sync_auto_30_minutes": "Alle 30 Minuten",
"sync_auto_1_hour": "Jede Stunde",
"sync_auto_3_hours": "Alle 3 Stunden",
"sync_auto_6_hours": "Alle 6 Stunden",
"sync_auto_12_hours": "Alle 12 Stunden",
"server_error": "Server Fehler!",
"dialog_confirm": "Fortfahren",
"description": "Beschreibung",
"full_screen_player": "Vollbildmodus aktivieren",

View file

@ -225,7 +225,25 @@
"sync_pending_track": "Track changes pending",
"sync_snapshot_creating": "Creating snapshot...",
"sync_snapshot_created": "Snapshot created!",
"sync_snapshot_deleting": "Deleting snapshot...",
"sync_snapshot_deleted": "Snapshot deleted!",
"sync_snapshot_no_data": "No data to create a snapshot! Do a full upload first!",
"sync_browse_snapshots": "Browse older backups",
"sync_snapshots": "Snapshots",
"sync_load_snapshot": "Load snapshot",
"sync_delete_snapshot": "Delete snapshot",
"sync_auto": "Auto Sync",
"sync_auto_warning": "Auto Sync is currently an experimental feature!",
"sync_auto_off": "Off",
"sync_auto_30_seconds": "Every 30 seconds",
"sync_auto_1_minute": "Every 1 minute",
"sync_auto_5_minutes": "Every 5 minutes",
"sync_auto_10_minutes": "Every 10 minutes",
"sync_auto_30_minutes": "Every 30 minutes",
"sync_auto_1_hour": "Every 1 hour",
"sync_auto_3_hours": "Every 3 hours",
"sync_auto_6_hours": "Every 6 hours",
"sync_auto_12_hours": "Every 12 hours",
"server_error": "Server error!",
"dialog_confirm": "Confirm",
"description": "Description",

View file

@ -20,6 +20,8 @@ class SyncPreference {
bool syncOn = false;
int autoSyncFrequency = 0;
SyncPreference({
this.syncId,
this.email,
@ -29,6 +31,7 @@ class SyncPreference {
this.lastDownload,
this.server,
this.syncOn = false,
this.autoSyncFrequency = 0,
});
SyncPreference.fromJson(Map<String, dynamic> json) {
@ -40,6 +43,7 @@ class SyncPreference {
lastDownload = json['lastDownload'];
server = json['server'];
syncOn = json['syncOn'] ?? false;
syncOn = json['autoSyncFrequency'] ?? 0;
}
Map<String, dynamic> toJson() => {
@ -49,6 +53,7 @@ class SyncPreference {
'lastSync': lastSync,
'lastUpload': lastUpload,
'lastDownload': lastDownload,
'syncOn': syncOn
'syncOn': syncOn,
'autoSyncFrequency': autoSyncFrequency,
};
}

View file

@ -22,33 +22,38 @@ const SyncPreferenceSchema = CollectionSchema(
name: r'authToken',
type: IsarType.string,
),
r'email': PropertySchema(
r'autoSyncFrequency': PropertySchema(
id: 1,
name: r'autoSyncFrequency',
type: IsarType.long,
),
r'email': PropertySchema(
id: 2,
name: r'email',
type: IsarType.string,
),
r'lastDownload': PropertySchema(
id: 2,
id: 3,
name: r'lastDownload',
type: IsarType.long,
),
r'lastSync': PropertySchema(
id: 3,
id: 4,
name: r'lastSync',
type: IsarType.long,
),
r'lastUpload': PropertySchema(
id: 4,
id: 5,
name: r'lastUpload',
type: IsarType.long,
),
r'server': PropertySchema(
id: 5,
id: 6,
name: r'server',
type: IsarType.string,
),
r'syncOn': PropertySchema(
id: 6,
id: 7,
name: r'syncOn',
type: IsarType.bool,
)
@ -101,12 +106,13 @@ void _syncPreferenceSerialize(
Map<Type, List<int>> allOffsets,
) {
writer.writeString(offsets[0], object.authToken);
writer.writeString(offsets[1], object.email);
writer.writeLong(offsets[2], object.lastDownload);
writer.writeLong(offsets[3], object.lastSync);
writer.writeLong(offsets[4], object.lastUpload);
writer.writeString(offsets[5], object.server);
writer.writeBool(offsets[6], object.syncOn);
writer.writeLong(offsets[1], object.autoSyncFrequency);
writer.writeString(offsets[2], object.email);
writer.writeLong(offsets[3], object.lastDownload);
writer.writeLong(offsets[4], object.lastSync);
writer.writeLong(offsets[5], object.lastUpload);
writer.writeString(offsets[6], object.server);
writer.writeBool(offsets[7], object.syncOn);
}
SyncPreference _syncPreferenceDeserialize(
@ -117,13 +123,14 @@ SyncPreference _syncPreferenceDeserialize(
) {
final object = SyncPreference(
authToken: reader.readStringOrNull(offsets[0]),
email: reader.readStringOrNull(offsets[1]),
lastDownload: reader.readLongOrNull(offsets[2]),
lastSync: reader.readLongOrNull(offsets[3]),
lastUpload: reader.readLongOrNull(offsets[4]),
server: reader.readStringOrNull(offsets[5]),
autoSyncFrequency: reader.readLongOrNull(offsets[1]) ?? 0,
email: reader.readStringOrNull(offsets[2]),
lastDownload: reader.readLongOrNull(offsets[3]),
lastSync: reader.readLongOrNull(offsets[4]),
lastUpload: reader.readLongOrNull(offsets[5]),
server: reader.readStringOrNull(offsets[6]),
syncId: id,
syncOn: reader.readBoolOrNull(offsets[6]) ?? false,
syncOn: reader.readBoolOrNull(offsets[7]) ?? false,
);
return object;
}
@ -138,16 +145,18 @@ P _syncPreferenceDeserializeProp<P>(
case 0:
return (reader.readStringOrNull(offset)) as P;
case 1:
return (reader.readStringOrNull(offset)) as P;
return (reader.readLongOrNull(offset) ?? 0) as P;
case 2:
return (reader.readLongOrNull(offset)) as P;
return (reader.readStringOrNull(offset)) as P;
case 3:
return (reader.readLongOrNull(offset)) as P;
case 4:
return (reader.readLongOrNull(offset)) as P;
case 5:
return (reader.readStringOrNull(offset)) as P;
return (reader.readLongOrNull(offset)) as P;
case 6:
return (reader.readStringOrNull(offset)) as P;
case 7:
return (reader.readBoolOrNull(offset) ?? false) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -402,6 +411,62 @@ extension SyncPreferenceQueryFilter
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterFilterCondition>
autoSyncFrequencyEqualTo(int value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'autoSyncFrequency',
value: value,
));
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterFilterCondition>
autoSyncFrequencyGreaterThan(
int value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'autoSyncFrequency',
value: value,
));
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterFilterCondition>
autoSyncFrequencyLessThan(
int value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'autoSyncFrequency',
value: value,
));
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterFilterCondition>
autoSyncFrequencyBetween(
int lower,
int upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'autoSyncFrequency',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterFilterCondition>
emailIsNull() {
return QueryBuilder.apply(this, (query) {
@ -1038,6 +1103,20 @@ extension SyncPreferenceQuerySortBy
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterSortBy>
sortByAutoSyncFrequency() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'autoSyncFrequency', Sort.asc);
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterSortBy>
sortByAutoSyncFrequencyDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'autoSyncFrequency', Sort.desc);
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterSortBy> sortByEmail() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'email', Sort.asc);
@ -1133,6 +1212,20 @@ extension SyncPreferenceQuerySortThenBy
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterSortBy>
thenByAutoSyncFrequency() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'autoSyncFrequency', Sort.asc);
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterSortBy>
thenByAutoSyncFrequencyDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'autoSyncFrequency', Sort.desc);
});
}
QueryBuilder<SyncPreference, SyncPreference, QAfterSortBy> thenByEmail() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'email', Sort.asc);
@ -1235,6 +1328,13 @@ extension SyncPreferenceQueryWhereDistinct
});
}
QueryBuilder<SyncPreference, SyncPreference, QDistinct>
distinctByAutoSyncFrequency() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'autoSyncFrequency');
});
}
QueryBuilder<SyncPreference, SyncPreference, QDistinct> distinctByEmail(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@ -1290,6 +1390,13 @@ extension SyncPreferenceQueryProperty
});
}
QueryBuilder<SyncPreference, int, QQueryOperations>
autoSyncFrequencyProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'autoSyncFrequency');
});
}
QueryBuilder<SyncPreference, String?, QQueryOperations> emailProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'email');

View file

@ -5,12 +5,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
import 'package:mangayomi/modules/widgets/loading_icon.dart';
import 'package:mangayomi/services/fetch_anime_sources.dart';
import 'package:mangayomi/services/fetch_manga_sources.dart';
@ -21,6 +23,7 @@ import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/router/router.dart';
import 'package:mangayomi/services/fetch_novel_sources.dart';
import 'package:mangayomi/services/fetch_sources_list.dart';
import 'package:mangayomi/services/sync_server.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:mangayomi/modules/library/providers/library_state_provider.dart';
import 'package:mangayomi/modules/more/providers/incognito_mode_state_provider.dart';
@ -52,6 +55,8 @@ class _MainScreenState extends ConsumerState<MainScreen> {
}
late final navigationOrder = ref.watch(navigationOrderStateProvider);
late final autoSyncFrequency =
ref.watch(synchingProvider(syncId: 1)).autoSyncFrequency;
late String? location =
ref.watch(routerCurrentLocationStateProvider(context));
late String defaultLocation = navigationOrder.first;
@ -63,6 +68,19 @@ class _MainScreenState extends ConsumerState<MainScreen> {
Timer.periodic(Duration(minutes: 5), (timer) {
ref.read(checkAndBackupProvider);
});
if (autoSyncFrequency != 0) {
final l10n = l10nLocalizations(context)!;
Timer.periodic(Duration(seconds: autoSyncFrequency), (timer) {
try {
ref.read(syncServerProvider(syncId: 1).notifier).startSync(l10n);
} catch (e) {
botToast(
"Failed to sync! Maybe the sync server is down. Restart the app to resume auto sync.");
timer.cancel();
}
});
}
ref.watch(checkForUpdateProvider(context: context));
ref.watch(fetchMangaSourcesListProvider(id: null, reFresh: false));
ref.watch(fetchAnimeSourcesListProvider(id: null, reFresh: false));

View file

@ -186,7 +186,7 @@ void restoreBackup(Ref ref, Map<String, dynamic> backup, {bool full = true}) {
}
}
if (full) {
ref.read(synchingProvider(syncId: 1).notifier).clearAllChangedParts();
ref.read(synchingProvider(syncId: 1).notifier).clearAllChangedParts(false);
ref.invalidate(themeModeStateProvider);
ref.invalidate(blendLevelStateProvider);
ref.invalidate(flexSchemeColorStateProvider);

View file

@ -173,7 +173,7 @@ class _DoRestoreProviderElement extends AutoDisposeProviderElement<void>
BuildContext get context => (origin as DoRestoreProvider).context;
}
String _$restoreBackupHash() => r'4285c4f788c892ddcedb48951284e181cc821541';
String _$restoreBackupHash() => r'0b6bdb8eff801da7efa7b3776f80e50bee4d4ad1';
/// See also [restoreBackup].
@ProviderFor(restoreBackup)

View file

@ -19,7 +19,7 @@ class Synching extends _$Synching {
isar.writeTxnSync(() {
isar.syncPreferences.putSync(syncPreference);
});
ref.invalidate(synchingProvider(syncId: syncId));
ref.invalidateSelf();
ref.invalidate(syncServerProvider(syncId: syncId!));
}
@ -27,7 +27,7 @@ class Synching extends _$Synching {
isar.writeTxnSync(() {
isar.syncPreferences.putSync(state..authToken = null);
});
ref.invalidate(synchingProvider(syncId: syncId));
ref.invalidateSelf();
ref.invalidate(syncServerProvider(syncId: syncId!));
}
@ -61,6 +61,13 @@ class Synching extends _$Synching {
});
}
void setAutoSyncFrequency(int value) {
isar.writeTxnSync(() {
isar.syncPreferences.putSync(state..autoSyncFrequency = value);
});
ref.invalidateSelf();
}
List<ChangedPart> getAllChangedParts() {
return isar.changedParts.filter().idIsNotNull().findAllSync();
}
@ -170,9 +177,13 @@ class Synching extends _$Synching {
});
}
void clearAllChangedParts() {
isar.writeTxnSync(() {
void clearAllChangedParts(bool txn) {
if (txn) {
isar.writeTxnSync(() {
isar.changedParts.clearSync();
});
} else {
isar.changedParts.clearSync();
});
}
}
}

View file

@ -6,7 +6,7 @@ part of 'sync_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$synchingHash() => r'abef3be5c474e8bf6f9d2b5af7587caf061d1fbd';
String _$synchingHash() => r'8a4f7f408bf0ac26f4a21368620051ecba3adf53';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -10,17 +10,29 @@ import 'package:mangayomi/modules/more/settings/sync/widgets/sync_listile.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/sync_server.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:mangayomi/utils/language.dart';
class SyncScreen extends ConsumerWidget {
const SyncScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final autoSyncOptions = [0, 30, 60, 300, 600, 1800, 3600];
final syncProvider = ref.watch(synchingProvider(syncId: 1));
final changedParts = ref.watch(synchingProvider(syncId: 1).notifier);
final autoSyncFrequency =
ref.watch(synchingProvider(syncId: 1)).autoSyncFrequency;
final l10n = l10nLocalizations(context)!;
final autoSyncOptions = {
l10n.sync_auto_off: 0,
l10n.sync_auto_30_seconds: 30,
l10n.sync_auto_1_minute: 60,
l10n.sync_auto_5_minutes: 300,
l10n.sync_auto_10_minutes: 600,
l10n.sync_auto_30_minutes: 1800,
l10n.sync_auto_1_hour: 3600,
l10n.sync_auto_3_hours: 10800,
l10n.sync_auto_6_hours: 21600,
l10n.sync_auto_12_hours: 43200,
};
return Scaffold(
appBar: AppBar(
title: Text(l10nLocalizations(context)!.syncing),
@ -56,7 +68,7 @@ class SyncScreen extends ConsumerWidget {
builder: (context) {
return AlertDialog(
title: Text(
l10n.app_language,
l10n.sync_auto,
),
content: SizedBox(
width: context.width(0.8),
@ -64,20 +76,23 @@ class SyncScreen extends ConsumerWidget {
shrinkWrap: true,
itemCount: autoSyncOptions.length,
itemBuilder: (context, index) {
final option = autoSyncOptions[index];
final optionName =
autoSyncOptions.keys.elementAt(index);
final optionValue = autoSyncOptions.values
.elementAt(index);
return RadioListTile(
dense: true,
contentPadding: const EdgeInsets.all(0),
value: option,
groupValue: 0,
value: optionValue,
groupValue: autoSyncFrequency,
onChanged: (value) {
/*ref
.read(l10nLocaleStateProvider
ref
.read(synchingProvider(syncId: 1)
.notifier)
.setLocale(locale);*/
.setAutoSyncFrequency(value!);
Navigator.pop(context);
},
title: Text(completeLanguageName("")),
title: Text(optionName),
);
},
)),
@ -100,13 +115,34 @@ class SyncScreen extends ConsumerWidget {
);
});
},
title: Text(l10n.app_language),
title: Text(l10n.sync_auto),
subtitle: Text(
completeLanguageName(""),
autoSyncOptions.entries
.where((o) => o.value == autoSyncFrequency)
.first
.key,
style: TextStyle(
fontSize: 11, color: context.secondaryColor),
),
),
ListTile(
title: Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: [
Icon(
Icons.warning_amber_outlined,
color: context.secondaryColor,
),
const SizedBox(width: 10),
Text(l10n.sync_auto_warning,
softWrap: true,
style: TextStyle(
fontSize: 11, color: context.secondaryColor))
],
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 15, right: 15, bottom: 10, top: 5),
@ -531,13 +567,197 @@ class SyncScreen extends ConsumerWidget {
ElevatedButton(
onPressed: !isLogged
? null
: () {
ref
: () async {
final snapshots = await ref
.read(syncServerProvider(syncId: 1)
.notifier)
.getSnapshots(l10n);
if (context.mounted) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.sync_snapshots,
),
content: SizedBox(
width: context.width(0.8),
child: ListView.builder(
shrinkWrap: true,
itemCount: snapshots.length,
itemBuilder:
(context, index) {
return Padding(
padding:
const EdgeInsets
.symmetric(
horizontal: 5),
child: Card(
child: Column(
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
Colors
.transparent,
elevation:
0,
shadowColor:
Colors
.transparent,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(0),
bottomRight: Radius.circular(0),
topRight: Radius.circular(10),
topLeft: Radius.circular(10)))),
onPressed: () {},
child: Row(
crossAxisAlignment:
CrossAxisAlignment
.end,
children: [
const Icon(
Icons
.save),
const SizedBox(
width:
10,
),
Expanded(
child:
Text("${dateFormat((snapshots[index].createdAt!).toString(), ref: ref, context: context)} ${dateFormatHour((snapshots[index].createdAt!).toString(), context)}"))
],
)),
Row(
mainAxisAlignment:
MainAxisAlignment
.end,
children: [
Row(
children: [
IconButton(
onPressed:
() {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
l10n.sync_load_snapshot,
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () async {
await ref.read(SyncServerProvider(syncId: 1).notifier).downloadSnapshot(l10n, snapshots[index].uuid!);
if (context.mounted) {
Navigator.pop(context);
}
},
child: Text(
l10n.ok,
)),
],
)
],
);
},
);
});
},
icon:
const Icon(Icons.cloud_download_outlined)),
IconButton(
onPressed:
() {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
l10n.sync_delete_snapshot,
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: () async {
await ref.read(syncServerProvider(syncId: 1).notifier).deleteSnapshot(l10n, snapshots[index].uuid!);
if (context.mounted) {
Navigator.pop(context);
}
},
child: Text(
l10n.ok,
)),
],
)
],
);
},
);
});
},
icon:
const Icon(Icons.delete_outlined))
],
),
],
)
],
),
),
);
},
)),
actions: [
Row(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
TextButton(
onPressed: () async {
Navigator.pop(
context);
},
child: Text(
l10n.cancel,
style: TextStyle(
color: context
.primaryColor),
)),
],
)
],
);
});
}
},
child: Text("Browse / Download older backups")),
child: Text(l10n.sync_browse_snapshots)),
],
),
),

View file

@ -173,9 +173,11 @@ void checkIfSourceIsObsolete(
sourceList.where((e) => e.id != null).map((e) => e.id).toList();
if (ids.isNotEmpty) {
isar.writeTxnSync(() {
if (source.isObsolete != !ids.contains(source.id)) {
ref.read(synchingProvider(syncId: 1).notifier).addChangedPart(
ActionType.updateExtension, source.id, source.toJson(), false);
}
isar.sources.putSync(source..isObsolete = !ids.contains(source.id));
ref.read(synchingProvider(syncId: 1).notifier).addChangedPart(
ActionType.updateExtension, source.id, source.toJson(), false);
});
}
}

View file

@ -97,7 +97,7 @@ class SyncServer extends _$SyncServer {
final syncNotifier = ref.read(synchingProvider(syncId: syncId).notifier);
syncNotifier.setLastSync(DateTime.now().millisecondsSinceEpoch);
syncNotifier.clearAllChangedParts();
syncNotifier.clearAllChangedParts(true);
ref.invalidate(synchingProvider(syncId: syncId));
botToast(l10n.sync_download_finished, second: 2);
@ -136,7 +136,7 @@ class SyncServer extends _$SyncServer {
}
}
Future<List> getSnapshots(AppLocalizations l10n) async {
Future<List<Snapshot>> getSnapshots(AppLocalizations l10n) async {
try {
final accessToken = _getAccessToken();
@ -151,10 +151,10 @@ class SyncServer extends _$SyncServer {
botToast(l10n.server_error, second: 5);
return List.empty();
}
var snapshots = jsonDecode(response.body) as List;
for (final snapshot in snapshots) {
print(
"${snapshot["id"]} - ${DateTime.parse(snapshot["dbCreatedAt"]).millisecondsSinceEpoch}");
var temp = jsonDecode(response.body) as List;
final snapshots = List<Snapshot>.empty(growable: true);
for (final snapshot in temp) {
snapshots.add(Snapshot.fromJson(snapshot));
}
return snapshots;
} catch (error) {
@ -221,6 +221,28 @@ class SyncServer extends _$SyncServer {
}
}
Future<void> deleteSnapshot(AppLocalizations l10n, String snapshotId) async {
botToast(l10n.sync_snapshot_deleting, second: 2);
try {
final accessToken = _getAccessToken();
var response = await http.delete(
Uri.parse('${_getServer()}$_snapshotUrl/$snapshotId'),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $accessToken'
},
);
if (response.statusCode != 200) {
botToast(l10n.server_error, second: 5);
return;
}
botToast(l10n.sync_snapshot_deleted, second: 2);
} catch (error) {
botToast(error.toString(), second: 5);
}
}
Future<void> uploadToServer(AppLocalizations l10n) async {
botToast(l10n.sync_uploading, second: 2);
try {
@ -239,12 +261,11 @@ class SyncServer extends _$SyncServer {
botToast(l10n.sync_upload_failed, second: 5);
return;
}
ref
.read(synchingProvider(syncId: syncId).notifier)
.setLastUpload(DateTime.now().millisecondsSinceEpoch);
ref
.read(synchingProvider(syncId: syncId).notifier)
.clearAllChangedParts();
final syncNotifier = ref.read(synchingProvider(syncId: syncId).notifier);
syncNotifier.setLastUpload(DateTime.now().millisecondsSinceEpoch);
syncNotifier.clearAllChangedParts(true);
ref.invalidate(synchingProvider(syncId: syncId));
botToast(l10n.sync_upload_finished, second: 2);
} catch (error) {
@ -407,3 +428,14 @@ class SyncServer extends _$SyncServer {
return syncPrefs.server ?? "";
}
}
class Snapshot {
String? uuid;
int? createdAt;
Snapshot({required this.uuid, required this.createdAt});
Snapshot.fromJson(Map<String, dynamic> json) {
uuid = json['id'];
createdAt = DateTime.parse(json["dbCreatedAt"]).millisecondsSinceEpoch;
}
}

View file

@ -6,7 +6,7 @@ part of 'sync_server.dart';
// RiverpodGenerator
// **************************************************************************
String _$syncServerHash() => r'b1d19a01737badaa79b42a7a39f2f7782463ee63';
String _$syncServerHash() => r'd13b5d6eaded02a9256e64550e98983b17ab70f4';
/// Copied from Dart SDK
class _SystemHash {