re-added full upload and download

This commit is contained in:
Schnitzel5 2025-08-10 02:14:18 +02:00
parent 9f56555ec4
commit 57be3eec9a
18 changed files with 615 additions and 217 deletions

View file

@ -225,6 +225,10 @@
"sync_finished": "Sync finished",
"sync_failed": "Sync failed",
"sync_button_sync": "Sync progress",
"sync_button_upload": "Upload only",
"sync_button_upload_info": "This operation will fully replace the remote data with local data!",
"sync_button_download": "Download only",
"sync_button_download_info": "This operation will fully replace the local data with remote data!",
"sync_on": "Enable sync",
"sync_auto": "Auto Sync",
"sync_auto_warning": "Auto Sync is currently an experimental feature!",

View file

@ -1425,6 +1425,30 @@ abstract class AppLocalizations {
/// **'Sync progress'**
String get sync_button_sync;
/// No description provided for @sync_button_upload.
///
/// In en, this message translates to:
/// **'Upload only'**
String get sync_button_upload;
/// No description provided for @sync_button_upload_info.
///
/// In en, this message translates to:
/// **'This operation will fully replace the remote data with local data!'**
String get sync_button_upload_info;
/// No description provided for @sync_button_download.
///
/// In en, this message translates to:
/// **'Download only'**
String get sync_button_download;
/// No description provided for @sync_button_download_info.
///
/// In en, this message translates to:
/// **'This operation will fully replace the local data with remote data!'**
String get sync_button_download_info;
/// No description provided for @sync_on.
///
/// In en, this message translates to:

View file

@ -696,6 +696,20 @@ class AppLocalizationsAr extends AppLocalizations {
@override
String get sync_button_sync => 'مزامنة التقدم';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'تمكين المزامنة';

View file

@ -698,6 +698,20 @@ class AppLocalizationsAs extends AppLocalizations {
@override
String get sync_button_sync => 'Sync progress';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Enable sync';

View file

@ -700,6 +700,20 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get sync_button_sync => 'Jetzt synchronisieren';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Sync aktivieren';

View file

@ -698,6 +698,20 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get sync_button_sync => 'Sync progress';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Enable sync';

View file

@ -702,6 +702,20 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get sync_button_sync => 'Sincronizar progreso';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Habilitar sincronización';

View file

@ -705,6 +705,20 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get sync_button_sync => 'Synchroniser les progrès';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Activer la synchronisation';

View file

@ -698,6 +698,20 @@ class AppLocalizationsHi extends AppLocalizations {
@override
String get sync_button_sync => 'Sync progress';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Enable sync';

View file

@ -702,6 +702,20 @@ class AppLocalizationsId extends AppLocalizations {
@override
String get sync_button_sync => 'Sinkronkan progres';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Aktifkan sinkronisasi';

View file

@ -702,6 +702,20 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get sync_button_sync => 'Sincronizza progressi';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Abilita sincronizzazione';

View file

@ -702,6 +702,20 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get sync_button_sync => 'Sincronizar progresso';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Ativar sincronização';

View file

@ -704,6 +704,20 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get sync_button_sync => 'Синхронизировать прогресс';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Включить синхронизацию';

View file

@ -698,6 +698,20 @@ class AppLocalizationsTh extends AppLocalizations {
@override
String get sync_button_sync => 'ซิงค์ความคืบหน้า';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'เปิดการซิงค์';

View file

@ -698,6 +698,20 @@ class AppLocalizationsTr extends AppLocalizations {
@override
String get sync_button_sync => 'İlerlemeyi senkronize et';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => 'Senkronizasyonu etkinleştir';

View file

@ -690,6 +690,20 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get sync_button_sync => '同步进度';
@override
String get sync_button_upload => 'Upload only';
@override
String get sync_button_upload_info =>
'This operation will fully replace the remote data with local data!';
@override
String get sync_button_download => 'Download only';
@override
String get sync_button_download_info =>
'This operation will fully replace the local data with remote data!';
@override
String get sync_on => '启用同步';

View file

@ -116,7 +116,9 @@ class SyncScreen extends ConsumerWidget {
title: Text(l10n.sync_auto),
subtitle: Text(
autoSyncOptions.entries
.where((o) => o.value == syncPreference.autoSyncFrequency)
.where(
(o) => o.value == syncPreference.autoSyncFrequency,
)
.first
.key,
style: TextStyle(
@ -150,29 +152,35 @@ class SyncScreen extends ConsumerWidget {
SwitchListTile(
value: syncPreference.syncHistories,
title: Text(context.l10n.sync_enable_histories),
onChanged: syncPreference.syncOn ? (value) {
ref
.read(SynchingProvider(syncId: 1).notifier)
.setSyncHistories(value);
} : null,
onChanged: syncPreference.syncOn
? (value) {
ref
.read(SynchingProvider(syncId: 1).notifier)
.setSyncHistories(value);
}
: null,
),
SwitchListTile(
value: syncPreference.syncUpdates,
title: Text(context.l10n.sync_enable_updates),
onChanged: syncPreference.syncOn ? (value) {
ref
.read(SynchingProvider(syncId: 1).notifier)
.setSyncUpdates(value);
} : null,
onChanged: syncPreference.syncOn
? (value) {
ref
.read(SynchingProvider(syncId: 1).notifier)
.setSyncUpdates(value);
}
: null,
),
SwitchListTile(
value: syncPreference.syncSettings,
title: Text(context.l10n.sync_enable_settings),
onChanged: syncPreference.syncOn ? (value) {
ref
.read(SynchingProvider(syncId: 1).notifier)
.setSyncSettings(value);
} : null,
onChanged: syncPreference.syncOn
? (value) {
ref
.read(SynchingProvider(syncId: 1).notifier)
.setSyncSettings(value);
}
: null,
),
Padding(
padding: const EdgeInsets.only(
@ -288,6 +296,40 @@ class SyncScreen extends ConsumerWidget {
Text(l10n.sync_button_sync),
],
),
const SizedBox(width: 20),
Column(
children: [
IconButton(
onPressed: !syncPreference.syncOn || !isLogged
? null
: () => _showConfirmDialog(context, ref, true),
icon: Icon(
Icons.file_upload_outlined,
color: !syncPreference.syncOn || !isLogged
? context.secondaryColor
: context.primaryColor,
),
),
Text(l10n.sync_button_upload),
],
),
const SizedBox(width: 20),
Column(
children: [
IconButton(
onPressed: !syncPreference.syncOn || !isLogged
? null
: () => _showConfirmDialog(context, ref, false),
icon: Icon(
Icons.file_download_outlined,
color: !syncPreference.syncOn || !isLogged
? context.secondaryColor
: context.primaryColor,
),
),
Text(l10n.sync_button_download),
],
),
],
),
const SizedBox(height: 20),
@ -298,172 +340,220 @@ class SyncScreen extends ConsumerWidget {
),
);
}
}
void _showDialogLogin(
BuildContext context,
WidgetRef ref,
SyncPreference syncPreference,
) {
final serverController = TextEditingController(text: syncPreference.server);
final emailController = TextEditingController(text: syncPreference.email);
final passwordController = TextEditingController();
String server = "";
String email = "";
String password = "";
String errorMessage = "";
bool isLoading = false;
bool obscureText = true;
final l10n = l10nLocalizations(context)!;
showDialog(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setState) {
Future<void> _showConfirmDialog(
BuildContext context,
WidgetRef ref,
bool isUpload,
) async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
l10n.login_into("SyncServer"),
style: const TextStyle(fontSize: 30),
content: Text(
isUpload
? context.l10n.sync_button_upload_info
: context.l10n.sync_button_download_info,
style: TextStyle(fontWeight: FontWeight.bold),
),
content: SizedBox(
height: 400,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: serverController,
autofocus: true,
onChanged: (value) => setState(() {
server = value;
}),
decoration: InputDecoration(
hintText: l10n.sync_server,
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(context.l10n.cancel),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: emailController,
autofocus: true,
onChanged: (value) => setState(() {
email = value;
}),
decoration: InputDecoration(
hintText: l10n.email_adress,
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: passwordController,
obscureText: obscureText,
onChanged: (value) => setState(() {
password = value;
}),
decoration: InputDecoration(
hintText: l10n.sync_password,
suffixIcon: IconButton(
onPressed: () => setState(() {
obscureText = !obscureText;
}),
icon: Icon(
obscureText
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
),
),
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
const SizedBox(height: 10),
Text(errorMessage, style: const TextStyle(color: Colors.red)),
const SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: SizedBox(
width: context.width(1),
height: 50,
child: ElevatedButton(
onPressed: isLoading
? null
: () async {
setState(() {
isLoading = true;
});
final res = await ref
.read(syncServerProvider(syncId: 1).notifier)
.login(l10n, server, email, password);
if (!res.$1) {
setState(() {
isLoading = false;
errorMessage = res.$2;
});
} else {
if (context.mounted) {
Navigator.pop(context);
}
}
},
child: isLoading
? const CircularProgressIndicator()
: Text(l10n.login),
),
),
const SizedBox(width: 15),
ElevatedButton(
onPressed: () {
ref
.read(syncServerProvider(syncId: 1).notifier)
.startSync(
context.l10n,
false,
upload: isUpload,
download: !isUpload,
);
Navigator.pop(context);
},
child: Text(context.l10n.dialog_confirm),
),
],
),
),
],
);
},
),
);
);
}
void _showDialogLogin(
BuildContext context,
WidgetRef ref,
SyncPreference syncPreference,
) {
final serverController = TextEditingController(text: syncPreference.server);
final emailController = TextEditingController(text: syncPreference.email);
final passwordController = TextEditingController();
String server = "";
String email = "";
String password = "";
String errorMessage = "";
bool isLoading = false;
bool obscureText = true;
final l10n = l10nLocalizations(context)!;
showDialog(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
l10n.login_into("SyncServer"),
style: const TextStyle(fontSize: 30),
),
content: SizedBox(
height: 400,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: serverController,
autofocus: true,
onChanged: (value) => setState(() {
server = value;
}),
decoration: InputDecoration(
hintText: l10n.sync_server,
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: emailController,
autofocus: true,
onChanged: (value) => setState(() {
email = value;
}),
decoration: InputDecoration(
hintText: l10n.email_adress,
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
controller: passwordController,
obscureText: obscureText,
onChanged: (value) => setState(() {
password = value;
}),
decoration: InputDecoration(
hintText: l10n.sync_password,
suffixIcon: IconButton(
onPressed: () => setState(() {
obscureText = !obscureText;
}),
icon: Icon(
obscureText
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
),
),
filled: false,
contentPadding: const EdgeInsets.all(12),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 0.4),
borderRadius: BorderRadius.circular(5),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(),
borderRadius: BorderRadius.circular(5),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(),
),
),
),
),
const SizedBox(height: 10),
Text(errorMessage, style: const TextStyle(color: Colors.red)),
const SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: SizedBox(
width: context.width(1),
height: 50,
child: ElevatedButton(
onPressed: isLoading
? null
: () async {
setState(() {
isLoading = true;
});
final res = await ref
.read(
syncServerProvider(syncId: 1).notifier,
)
.login(l10n, server, email, password);
if (!res.$1) {
setState(() {
isLoading = false;
errorMessage = res.$2;
});
} else {
if (context.mounted) {
Navigator.pop(context);
}
}
},
child: isLoading
? const CircularProgressIndicator()
: Text(l10n.login),
),
),
),
],
),
),
);
},
),
);
}
}

View file

@ -41,7 +41,7 @@ class SyncServer extends _$SyncServer {
String username,
String password,
) async {
server = server[server.length - 1] == '/'
server = server.isNotEmpty && server[server.length - 1] == '/'
? server.substring(0, server.length - 1)
: server;
try {
@ -67,7 +67,12 @@ class SyncServer extends _$SyncServer {
}
}
Future<void> startSync(AppLocalizations l10n, bool silent) async {
Future<void> startSync(
AppLocalizations l10n,
bool silent, {
bool upload = false,
bool download = false,
}) async {
if (!silent) {
botToast(l10n.sync_starting, second: 500);
}
@ -75,27 +80,46 @@ class SyncServer extends _$SyncServer {
final syncPreference = ref.read(synchingProvider(syncId: syncId));
final syncNotifier = ref.read(synchingProvider(syncId: syncId).notifier);
final resultManga = await _syncManga(l10n, syncNotifier);
final resultManga = await _syncManga(
l10n,
syncNotifier,
download: download,
upload: upload,
);
if (!resultManga) {
botToast(l10n.sync_failed, second: 5);
return;
}
if (syncPreference.syncHistories) {
final resultHistory = await _syncHistory(l10n, syncNotifier);
final resultHistory = await _syncHistory(
l10n,
syncNotifier,
download: download,
upload: upload,
);
if (!resultHistory) {
botToast(l10n.sync_failed, second: 5);
return;
}
}
if (syncPreference.syncUpdates) {
final resultUpdate = await _syncUpdate(l10n, syncNotifier);
final resultUpdate = await _syncUpdate(
l10n,
syncNotifier,
download: download,
upload: upload,
);
if (!resultUpdate) {
botToast(l10n.sync_failed, second: 5);
return;
}
}
if (syncPreference.syncSettings) {
final resultSettings = await _syncSettings(l10n);
final resultSettings = await _syncSettings(
l10n,
download: download,
upload: upload,
);
if (!resultSettings) {
botToast(l10n.sync_failed, second: 5);
return;
@ -111,8 +135,13 @@ class SyncServer extends _$SyncServer {
}
}
Future<bool> _syncManga(AppLocalizations l10n, Synching syncNotifier) async {
final mangaData = _getMangaData();
Future<bool> _syncManga(
AppLocalizations l10n,
Synching syncNotifier, {
bool upload = false,
bool download = false,
}) async {
final mangaData = _getMangaData(upload: upload, download: download);
final accessToken = _getAccessToken();
var response = await http.post(
Uri.parse('${_getServer()}$_syncMangaUrl'),
@ -127,11 +156,20 @@ class SyncServer extends _$SyncServer {
return false;
}
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertCategories(jsonData, syncNotifier);
await _upsertManga(jsonData, syncNotifier);
await _upsertChapters(jsonData, syncNotifier);
await _upsertTracks(jsonData, syncNotifier);
if (!upload) {
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertCategories(jsonData, syncNotifier);
await _upsertManga(jsonData, syncNotifier);
await _upsertChapters(jsonData, syncNotifier);
await _upsertTracks(jsonData, syncNotifier);
} else {
await syncNotifier.clearChangedParts([
ActionType.removeCategory,
ActionType.removeItem,
ActionType.removeChapter,
ActionType.removeTrack,
], true);
}
syncNotifier.setLastSyncManga(DateTime.now().millisecondsSinceEpoch);
@ -140,9 +178,11 @@ class SyncServer extends _$SyncServer {
Future<bool> _syncHistory(
AppLocalizations l10n,
Synching syncNotifier,
) async {
final historyData = _getHistoryData();
Synching syncNotifier, {
bool upload = false,
bool download = false,
}) async {
final historyData = _getHistoryData(upload: upload, download: download);
final accessToken = _getAccessToken();
var response = await http.post(
Uri.parse('${_getServer()}$_syncHistoryUrl'),
@ -157,16 +197,25 @@ class SyncServer extends _$SyncServer {
return false;
}
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertHistories(jsonData, syncNotifier);
if (!upload) {
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertHistories(jsonData, syncNotifier);
} else {
await syncNotifier.clearChangedParts([ActionType.removeHistory], true);
}
syncNotifier.setLastSyncHistory(DateTime.now().millisecondsSinceEpoch);
return true;
}
Future<bool> _syncUpdate(AppLocalizations l10n, Synching syncNotifier) async {
final updateData = _getUpdateData();
Future<bool> _syncUpdate(
AppLocalizations l10n,
Synching syncNotifier, {
bool upload = false,
bool download = false,
}) async {
final updateData = _getUpdateData(upload: upload, download: download);
final accessToken = _getAccessToken();
var response = await http.post(
Uri.parse('${_getServer()}$_syncUpdateUrl'),
@ -181,16 +230,24 @@ class SyncServer extends _$SyncServer {
return false;
}
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertUpdates(jsonData, syncNotifier);
if (!upload) {
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertUpdates(jsonData, syncNotifier);
} else {
await syncNotifier.clearChangedParts([ActionType.removeUpdate], true);
}
syncNotifier.setLastSyncUpdate(DateTime.now().millisecondsSinceEpoch);
return true;
}
Future<bool> _syncSettings(AppLocalizations l10n) async {
final settingsData = _getSettingsData();
Future<bool> _syncSettings(
AppLocalizations l10n, {
bool upload = false,
bool download = false,
}) async {
final settingsData = _getSettingsData(download: download);
final accessToken = _getAccessToken();
var response = await http.post(
Uri.parse('${_getServer()}$_syncSettingsUrl'),
@ -205,8 +262,10 @@ class SyncServer extends _$SyncServer {
return false;
}
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertSettings(jsonData);
if (!upload) {
final jsonData = jsonDecode(response.body) as Map<String, dynamic>;
await _upsertSettings(jsonData);
}
return true;
}
@ -424,36 +483,61 @@ class SyncServer extends _$SyncServer {
});
}
String _getMangaData() {
String _getMangaData({bool upload = false, bool download = false}) {
Map<String, dynamic> data = {};
data["categories"] = _getCategories();
data["deleted_categories"] = _getDeletedObjects(ActionType.removeCategory);
data["manga"] = _getManga();
data["deleted_manga"] = _getDeletedObjects(ActionType.removeItem);
data["chapters"] = _getChapters();
data["deleted_chapters"] = _getDeletedObjects(ActionType.removeChapter);
data["tracks"] = _getTracks();
data["deleted_tracks"] = _getDeletedObjects(ActionType.removeTrack);
data["categories"] = download ? [] : _getCategories();
data["deleted_categories"] = download
? []
: _getDeletedObjects(ActionType.removeCategory);
data["manga"] = download ? [] : _getManga();
data["deleted_manga"] = download
? []
: _getDeletedObjects(ActionType.removeItem);
data["chapters"] = download ? [] : _getChapters();
data["deleted_chapters"] = download
? []
: _getDeletedObjects(ActionType.removeChapter);
data["tracks"] = download ? [] : _getTracks();
data["deleted_tracks"] = download
? []
: _getDeletedObjects(ActionType.removeTrack);
if (upload) {
data["resetAll"] = true;
}
return jsonEncode(data);
}
String _getHistoryData() {
String _getHistoryData({bool upload = false, bool download = false}) {
Map<String, dynamic> data = {};
data["histories"] = _getHistories();
data["deleted_histories"] = _getDeletedObjects(ActionType.removeHistory);
data["histories"] = download ? [] : _getHistories();
data["deleted_histories"] = download
? []
: _getDeletedObjects(ActionType.removeHistory);
if (upload) {
data["resetAll"] = true;
}
return jsonEncode(data);
}
String _getUpdateData() {
String _getUpdateData({bool upload = false, bool download = false}) {
Map<String, dynamic> data = {};
data["updates"] = _getUpdates();
data["deleted_updates"] = _getDeletedObjects(ActionType.removeUpdate);
data["updates"] = download ? [] : _getUpdates();
data["deleted_updates"] = download
? []
: _getDeletedObjects(ActionType.removeUpdate);
if (upload) {
data["resetAll"] = true;
}
return jsonEncode(data);
}
String _getSettingsData() {
String _getSettingsData({bool download = false}) {
Map<String, dynamic> data = {};
data["settings"] = isar.settings.getSync(227)!..updatedAt ??= DateTime.now().millisecondsSinceEpoch..cookiesList = [];
if (!download) {
data["settings"] = isar.settings.getSync(227)!
..updatedAt ??= DateTime.now().millisecondsSinceEpoch
..cookiesList = [];
}
return jsonEncode(data);
}