From 202ab20747bdaf8dee441a80616a475ca3f32e36 Mon Sep 17 00:00:00 2001 From: Adrian Baumgart Date: Fri, 26 Jul 2024 20:30:13 +0200 Subject: [PATCH] a bit of refactoring --- lib/global_theme.dart | 4 +- lib/util/build_api_error_snackbar.dart | 22 ++ lib/views/home_view.dart | 32 +- lib/views/redirect_rules_detail_view.dart | 32 +- lib/views/settings_view.dart | 18 +- lib/views/short_url_edit_view.dart | 386 +++++++++++----------- lib/views/url_detail_view.dart | 17 +- lib/views/url_list_view.dart | 17 +- 8 files changed, 237 insertions(+), 291 deletions(-) create mode 100644 lib/util/build_api_error_snackbar.dart diff --git a/lib/global_theme.dart b/lib/global_theme.dart index fde5df5..5895300 100644 --- a/lib/global_theme.dart +++ b/lib/global_theme.dart @@ -33,7 +33,7 @@ class GlobalTheme { return ColorScheme( primary: Color(0xff747ab5), onPrimary: Colors.white, - secondary: Color(0x445d63a6),// Color(0xFFDDE0E0), + secondary: Color(0x335d63a6),// Color(0xFFDDE0E0), onSecondary: Color(0xFF322942), tertiary: Colors.grey[300], onTertiary: Colors.grey[700], @@ -44,7 +44,7 @@ class GlobalTheme { surface: Color(0xFFFAFBFB), onSurface: Color(0xFF241E30), brightness: Brightness.light, - ).harmonized(); + ); } static ColorScheme get darkColorScheme { diff --git a/lib/util/build_api_error_snackbar.dart b/lib/util/build_api_error_snackbar.dart new file mode 100644 index 0000000..5e4e38f --- /dev/null +++ b/lib/util/build_api_error_snackbar.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:shlink_app/API/server_manager.dart'; + +SnackBar buildApiErrorSnackbar(Failure r, BuildContext context) { + var text = ""; + + if (r is RequestFailure) { + text = r.description; + } else { + text = (r as ApiFailure).detail; + if ((r).invalidElements != null) { + text = "$text: ${(r).invalidElements}"; + } + } + + final snackBar = SnackBar( + content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), + backgroundColor: Theme.of(context).colorScheme.error, + behavior: SnackBarBehavior.floating); + + return snackBar; +} \ No newline at end of file diff --git a/lib/views/home_view.dart b/lib/views/home_view.dart index 6270249..a78667a 100644 --- a/lib/views/home_view.dart +++ b/lib/views/home_view.dart @@ -5,7 +5,7 @@ import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; import 'package:flutter_sharing_intent/model/sharing_file.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:shlink_app/API/Classes/ShlinkStats/shlink_stats.dart'; -import 'package:shlink_app/API/server_manager.dart'; +import 'package:shlink_app/util/build_api_error_snackbar.dart'; import 'package:shlink_app/views/short_url_edit_view.dart'; import 'package:shlink_app/views/url_list_view.dart'; import 'package:shlink_app/widgets/available_servers_bottom_sheet.dart'; @@ -68,18 +68,9 @@ class _HomeViewState extends State { shlinkStats = l; }); }, (r) { - var text = ""; - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - } - - final snackBar = SnackBar( - content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); }); } @@ -91,18 +82,9 @@ class _HomeViewState extends State { shortUrlsLoaded = true; }); }, (r) { - var text = ""; - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - } - - final snackBar = SnackBar( - content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); }); } diff --git a/lib/views/redirect_rules_detail_view.dart b/lib/views/redirect_rules_detail_view.dart index bdf49f6..2135f5d 100644 --- a/lib/views/redirect_rules_detail_view.dart +++ b/lib/views/redirect_rules_detail_view.dart @@ -3,7 +3,7 @@ import 'package:shlink_app/API/Classes/ShortURL/RedirectRule/condition_device_ty import 'package:shlink_app/API/Classes/ShortURL/RedirectRule/redirect_rule_condition.dart'; import 'package:shlink_app/API/Classes/ShortURL/RedirectRule/redirect_rule_condition_type.dart'; import 'package:shlink_app/API/Classes/ShortURL/short_url.dart'; -import 'package:shlink_app/API/server_manager.dart'; +import 'package:shlink_app/util/build_api_error_snackbar.dart'; import '../globals.dart' as globals; import '../API/Classes/ShortURL/RedirectRule/redirect_rule.dart'; @@ -41,18 +41,9 @@ class _RedirectRulesDetailViewState extends State { _sortListByPriority(); return true; }, (r) { - var text = ""; - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - } - - final snackBar = SnackBar( - content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); return false; }); } @@ -63,18 +54,9 @@ class _RedirectRulesDetailViewState extends State { response.fold((l) { Navigator.pop(context); }, (r) { - var text = ""; - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - } - - final snackBar = SnackBar( - content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); return false; }); } diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index af18411..736d142 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:shlink_app/API/server_manager.dart'; +import 'package:shlink_app/util/build_api_error_snackbar.dart'; import 'package:shlink_app/views/opensource_licenses_view.dart'; import 'package:shlink_app/widgets/available_servers_bottom_sheet.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -43,19 +43,9 @@ class _SettingsViewState extends State { setState(() { _serverStatus = ServerStatus.disconnected; }); - - var text = ""; - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - } - - final snackBar = SnackBar( - content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); }); } diff --git a/lib/views/short_url_edit_view.dart b/lib/views/short_url_edit_view.dart index b3dd83c..f650510 100644 --- a/lib/views/short_url_edit_view.dart +++ b/lib/views/short_url_edit_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'package:shlink_app/API/Classes/ShortURL/short_url.dart'; import 'package:shlink_app/API/Classes/ShortURLSubmission/short_url_submission.dart'; import 'package:shlink_app/API/server_manager.dart'; +import 'package:shlink_app/util/build_api_error_snackbar.dart'; import '../globals.dart' as globals; class ShortURLEditView extends StatefulWidget { @@ -72,6 +73,34 @@ class _ShortURLEditViewState extends State } } + void _saveButtonPressed() { + if (!isSaving) { + setState(() { + isSaving = true; + longUrlError = ""; + randomSlugLengthError = ""; + }); + if (longUrlController.text == "") { + setState(() { + longUrlError = "URL cannot be empty"; + isSaving = false; + }); + return; + } else if (int.tryParse(randomSlugLengthController.text) == + null || + int.tryParse(randomSlugLengthController.text)! < 1 || + int.tryParse(randomSlugLengthController.text)! > 50) { + setState(() { + randomSlugLengthError = "invalid number"; + isSaving = false; + }); + return; + } else { + _submitShortUrl(); + } + } + } + void _submitShortUrl() async { var newSubmission = ShortURLSubmission( longUrl: longUrlController.text, @@ -119,22 +148,9 @@ class _ShortURLEditViewState extends State isSaving = false; }); - var text = ""; - - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - if ((r).invalidElements != null) { - text = "$text: ${(r).invalidElements}"; - } - } - - final snackBar = SnackBar( - content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); return false; }); } @@ -149,200 +165,172 @@ class _ShortURLEditViewState extends State style: const TextStyle(fontWeight: FontWeight.bold)), ), SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.only(left: 16, right: 16, top: 16), - child: Column( - children: [ - TextField( - controller: longUrlController, - decoration: InputDecoration( - errorText: longUrlError != "" ? longUrlError : null, - border: const OutlineInputBorder(), - label: const Row( - children: [ - Icon(Icons.public), - SizedBox(width: 8), - Text("Long URL") - ], - )), - ), - const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: TextField( - enabled: !disableSlugEditor, - controller: customSlugController, - style: TextStyle( - color: randomSlug - ? Theme.of(context).colorScheme.onTertiary - : Theme.of(context).colorScheme.onPrimary), - onChanged: (_) { - if (randomSlug) { - setState(() { - randomSlug = false; - }); - } - }, - decoration: InputDecoration( - border: const OutlineInputBorder(), - label: Row( - children: [ - const Icon(Icons.link), - const SizedBox(width: 8), - Text( - "${randomSlug ? "Random" : "Custom"} slug", - style: TextStyle( - fontStyle: randomSlug - ? FontStyle.italic - : FontStyle.normal), - ) - ], - )), + child: Padding( + padding: EdgeInsets.only(top: 16, left: 8, right: 8), + child: Wrap( + runSpacing: 16, + children: [ + TextField( + controller: longUrlController, + decoration: InputDecoration( + errorText: longUrlError != "" ? longUrlError : null, + border: const OutlineInputBorder(), + label: const Row( + children: [ + Icon(Icons.public), + SizedBox(width: 8), + Text("Long URL") + ], + )), + ), + Row( + children: [ + Expanded( + child: TextField( + enabled: !disableSlugEditor, + controller: customSlugController, + style: TextStyle( + color: randomSlug + ? Theme.of(context).colorScheme.onTertiary + : Theme.of(context).colorScheme.onPrimary), + onChanged: (_) { + if (randomSlug) { + setState(() { + randomSlug = false; + }); + } + }, + decoration: InputDecoration( + border: const OutlineInputBorder(), + label: Row( + children: [ + const Icon(Icons.link), + const SizedBox(width: 8), + Text( + "${randomSlug ? "Random" : "Custom"} slug", + style: TextStyle( + fontStyle: randomSlug + ? FontStyle.italic + : FontStyle.normal), + ) + ], + )), + ), ), + const SizedBox(width: 8), + RotationTransition( + turns: Tween(begin: 0.0, end: 3.0).animate( + CurvedAnimation( + parent: _customSlugDiceAnimationController, + curve: Curves.easeInOutExpo)), + child: IconButton( + onPressed: disableSlugEditor + ? null + : () { + if (randomSlug) { + _customSlugDiceAnimationController.reverse( + from: 1); + } else { + _customSlugDiceAnimationController.forward( + from: 0); + } + setState(() { + randomSlug = !randomSlug; + }); + }, + icon: Icon( + randomSlug ? Icons.casino : Icons.casino_outlined, + color: randomSlug ? Colors.green : Colors.grey)), + ) + ], + ), + if (randomSlug) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text("Random slug length"), + SizedBox( + width: 100, + child: TextField( + controller: randomSlugLengthController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + errorText: + randomSlugLengthError != "" ? "" : null, + border: const OutlineInputBorder(), + label: const Row( + children: [ + Icon(Icons.tag), + SizedBox(width: 8), + Text("Length") + ], + )), + )) + ], ), - const SizedBox(width: 8), - RotationTransition( - turns: Tween(begin: 0.0, end: 3.0).animate( - CurvedAnimation( - parent: _customSlugDiceAnimationController, - curve: Curves.easeInOutExpo)), - child: IconButton( - onPressed: disableSlugEditor - ? null - : () { - if (randomSlug) { - _customSlugDiceAnimationController.reverse( - from: 1); - } else { - _customSlugDiceAnimationController.forward( - from: 0); - } - setState(() { - randomSlug = !randomSlug; - }); - }, - icon: Icon( - randomSlug ? Icons.casino : Icons.casino_outlined, - color: randomSlug ? Colors.green : Colors.grey)), - ) - ], - ), - if (randomSlug) const SizedBox(height: 16), - if (randomSlug) + TextField( + controller: titleController, + decoration: const InputDecoration( + border: OutlineInputBorder(), + label: Row( + children: [ + Icon(Icons.badge), + SizedBox(width: 8), + Text("Title") + ], + )), + ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Text("Random slug length"), - SizedBox( - width: 100, - child: TextField( - controller: randomSlugLengthController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - errorText: - randomSlugLengthError != "" ? "" : null, - border: const OutlineInputBorder(), - label: const Row( - children: [ - Icon(Icons.tag), - SizedBox(width: 8), - Text("Length") - ], - )), - )) + const Text("Crawlable"), + Switch( + value: isCrawlable, + onChanged: (_) { + setState(() { + isCrawlable = !isCrawlable; + }); + }, + ) ], ), - const SizedBox(height: 16), - TextField( - controller: titleController, - decoration: const InputDecoration( - border: OutlineInputBorder(), - label: Row( - children: [ - Icon(Icons.badge), - SizedBox(width: 8), - Text("Title") - ], - )), - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Crawlable"), - Switch( - value: isCrawlable, - onChanged: (_) { - setState(() { - isCrawlable = !isCrawlable; - }); - }, - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Forward query params"), - Switch( - value: forwardQuery, - onChanged: (_) { - setState(() { - forwardQuery = !forwardQuery; - }); - }, - ) - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text("Copy to clipboard"), - Switch( - value: copyToClipboard, - onChanged: (_) { - setState(() { - copyToClipboard = !copyToClipboard; - }); - }, - ) - ], - ), - ], - ), - )) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text("Forward query params"), + Switch( + value: forwardQuery, + onChanged: (_) { + setState(() { + forwardQuery = !forwardQuery; + }); + }, + ) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text("Copy to clipboard"), + Switch( + value: copyToClipboard, + onChanged: (_) { + setState(() { + copyToClipboard = !copyToClipboard; + }); + }, + ) + ], + ), + ], + ), + ) + ) ], ), floatingActionButton: FloatingActionButton( onPressed: () { - if (!isSaving) { - setState(() { - isSaving = true; - longUrlError = ""; - randomSlugLengthError = ""; - }); - if (longUrlController.text == "") { - setState(() { - longUrlError = "URL cannot be empty"; - isSaving = false; - }); - return; - } else if (int.tryParse(randomSlugLengthController.text) == - null || - int.tryParse(randomSlugLengthController.text)! < 1 || - int.tryParse(randomSlugLengthController.text)! > 50) { - setState(() { - randomSlugLengthError = "invalid number"; - isSaving = false; - }); - return; - } else { - _submitShortUrl(); - } - } + _saveButtonPressed(); }, child: isSaving ? const Padding( diff --git a/lib/views/url_detail_view.dart b/lib/views/url_detail_view.dart index 7984af9..eac8068 100644 --- a/lib/views/url_detail_view.dart +++ b/lib/views/url_detail_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:shlink_app/API/Classes/ShortURL/short_url.dart'; import 'package:intl/intl.dart'; -import 'package:shlink_app/API/server_manager.dart'; +import 'package:shlink_app/util/build_api_error_snackbar.dart'; import 'package:shlink_app/views/redirect_rules_detail_view.dart'; import 'package:shlink_app/views/short_url_edit_view.dart'; import 'package:shlink_app/widgets/url_tags_list_widget.dart'; @@ -67,18 +67,9 @@ class _URLDetailViewState extends State { ScaffoldMessenger.of(context).showSnackBar(snackBar); return true; }, (r) { - var text = ""; - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - } - - final snackBar = SnackBar( - content: Text(text, style: TextStyle(color: Theme.of(context).colorScheme.onError)), - backgroundColor: Theme.of(context).colorScheme.error, - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); return false; }); }, diff --git a/lib/views/url_list_view.dart b/lib/views/url_list_view.dart index f015b02..740af62 100644 --- a/lib/views/url_list_view.dart +++ b/lib/views/url_list_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:shlink_app/API/Classes/ShortURL/short_url.dart'; -import 'package:shlink_app/API/server_manager.dart'; +import 'package:shlink_app/util/build_api_error_snackbar.dart'; import 'package:shlink_app/views/short_url_edit_view.dart'; import 'package:shlink_app/views/url_detail_view.dart'; import 'package:shlink_app/widgets/url_tags_list_widget.dart'; @@ -38,18 +38,9 @@ class _URLListViewState extends State { }); return true; }, (r) { - var text = ""; - if (r is RequestFailure) { - text = r.description; - } else { - text = (r as ApiFailure).detail; - } - - final snackBar = SnackBar( - content: Text(text), - backgroundColor: Colors.red[400], - behavior: SnackBarBehavior.floating); - ScaffoldMessenger.of(context).showSnackBar(snackBar); + ScaffoldMessenger.of(context).showSnackBar( + buildApiErrorSnackbar(r, context) + ); return false; }); }