diff --git a/lib/components/message.dart b/lib/components/message.dart index 777ec92..1a67f61 100644 --- a/lib/components/message.dart +++ b/lib/components/message.dart @@ -125,11 +125,11 @@ class OverlayWidgetState extends State { void showDialogMessage(BuildContext context, String title, String message) { showDialog( context: context, - builder: (context) => AlertDialog( - title: Text(title), - content: Text(message), + builder: (context) => ContentDialog( + title: title, + content: Text(message).paddingHorizontal(16), actions: [ - TextButton( + FilledButton( onPressed: context.pop, child: Text("OK".tl), ) diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index c715e22..b513911 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -162,16 +162,50 @@ class _SyncDataWidgetState extends State<_SyncDataWidget> trailing: Row( mainAxisSize: MainAxisSize.min, children: [ + if (DataSync().lastError != null) + InkWell( + borderRadius: BorderRadius.circular(16), + onTap: () { + showDialogMessage( + App.rootContext, + "Error".tl, + DataSync().lastError!, + ); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: context.colorScheme.errorContainer, + borderRadius: BorderRadius.circular(16), + ), + child: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.red, + size: 18, + ), + const SizedBox(width: 4), + Text('Error'.tl, style: ts.s12), + ], + ), + ), + ).paddingRight(4), IconButton( - icon: const Icon(Icons.cloud_upload_outlined), - onPressed: () async { - DataSync().uploadData(); - }), + icon: const Icon(Icons.cloud_upload_outlined), + onPressed: () async { + DataSync().uploadData(); + }, + ), IconButton( - icon: const Icon(Icons.cloud_download_outlined), - onPressed: () async { - DataSync().downloadData(); - }), + icon: const Icon(Icons.cloud_download_outlined), + onPressed: () async { + DataSync().downloadData(); + }, + ), ], ), ), @@ -538,7 +572,8 @@ class _ImportComicsWidgetState extends State<_ImportComicsWidget> { ], ), onPressed: () { - launchUrlString("https://github.com/venera-app/venera/blob/master/doc/import_comic.md"); + launchUrlString( + "https://github.com/venera-app/venera/blob/master/doc/import_comic.md"); }, ).fixWidth(90).paddingRight(8), Button.filled( @@ -697,14 +732,24 @@ class _ComicSourceWidgetState extends State<_ComicSourceWidget> { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(Icons.update, color: context.colorScheme.primary, size: 20,), + Icon( + Icons.update, + color: context.colorScheme.primary, + size: 20, + ), const SizedBox(width: 8), - Text("@c updates".tlParams({ - 'c': _availableUpdates, - }), style: ts.withColor(context.colorScheme.primary),), + Text( + "@c updates".tlParams({ + 'c': _availableUpdates, + }), + style: ts.withColor(context.colorScheme.primary), + ), ], ), - ).toAlign(Alignment.centerLeft).paddingHorizontal(16).paddingBottom(8), + ) + .toAlign(Alignment.centerLeft) + .paddingHorizontal(16) + .paddingBottom(8), ], ), ), @@ -844,7 +889,8 @@ class _ImageFavoritesState extends State { padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.secondaryContainer, + color: + Theme.of(context).colorScheme.secondaryContainer, borderRadius: BorderRadius.circular(8), ), child: Text( diff --git a/lib/utils/data_sync.dart b/lib/utils/data_sync.dart index e73cd9f..193ce5a 100644 --- a/lib/utils/data_sync.dart +++ b/lib/utils/data_sync.dart @@ -40,7 +40,11 @@ class DataSync with ChangeNotifier { bool get isUploading => _isUploading; - bool haveWaitingTask = false; + bool _haveWaitingTask = false; + + String? _lastError; + + String? get lastError => _lastError; bool get isEnabled { var config = appdata.settings['webdav']; @@ -64,17 +68,19 @@ class DataSync with ChangeNotifier { Future> uploadData() async { if (isDownloading) return const Res(true); - if (haveWaitingTask) return const Res(true); + if (_haveWaitingTask) return const Res(true); while (isUploading) { - haveWaitingTask = true; + _haveWaitingTask = true; await Future.delayed(const Duration(milliseconds: 100)); } - haveWaitingTask = false; + _haveWaitingTask = false; _isUploading = true; + _lastError = null; notifyListeners(); try { var config = _validateConfig(); if (config == null) { + _lastError = 'Invalid WebDAV configuration'; return const Res.error('Invalid WebDAV configuration'); } if (config.isEmpty) { @@ -98,13 +104,6 @@ class DataSync with ChangeNotifier { ), ); - try { - await client.ping(); - } catch (e) { - Log.error("Upload Data", 'Failed to connect to WebDAV server'); - return const Res.error('Failed to connect to WebDAV server'); - } - try { appdata.settings['dataVersion']++; await appdata.saveData(false); @@ -131,6 +130,7 @@ class DataSync with ChangeNotifier { return const Res(true); } catch (e, s) { Log.error("Upload Data", e, s); + _lastError = e.toString(); return Res.error(e.toString()); } } finally { @@ -140,17 +140,19 @@ class DataSync with ChangeNotifier { } Future> downloadData() async { - if (haveWaitingTask) return const Res(true); + if (_haveWaitingTask) return const Res(true); while (isDownloading || isUploading) { - haveWaitingTask = true; + _haveWaitingTask = true; await Future.delayed(const Duration(milliseconds: 100)); } - haveWaitingTask = false; + _haveWaitingTask = false; _isDownloading = true; + _lastError = null; notifyListeners(); try { var config = _validateConfig(); if (config == null) { + _lastError = 'Invalid WebDAV configuration'; return const Res.error('Invalid WebDAV configuration'); } if (config.isEmpty) { @@ -174,13 +176,6 @@ class DataSync with ChangeNotifier { ), ); - try { - await client.ping(); - } catch (e) { - Log.error("Data Sync", 'Failed to connect to WebDAV server'); - return const Res.error('Failed to connect to WebDAV server'); - } - try { var files = await client.readDir('/'); files.sort((a, b) => b.name!.compareTo(a.name!)); @@ -206,6 +201,7 @@ class DataSync with ChangeNotifier { return const Res(true); } catch (e, s) { Log.error("Data Sync", e, s); + _lastError = e.toString(); return Res.error(e.toString()); } } finally {