mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-21 03:32:06 +00:00
Merge pull request #544 from Schnitzel5/sync/upload-download
re-added full upload and download
This commit is contained in:
commit
22087752f1
18 changed files with 615 additions and 217 deletions
|
|
@ -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!",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 => 'تمكين المزامنة';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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 => 'Включить синхронизацию';
|
||||
|
||||
|
|
|
|||
|
|
@ -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 => 'เปิดการซิงค์';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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 => '启用同步';
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue