From de2b7fa7a13ac2e46c188c5e059d2dabe36d2836 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 22 Apr 2023 23:49:55 -0400 Subject: [PATCH] URL selection modal improvements (incl. #460) --- lib/pages/import_export.dart | 78 +++++++++++++++++++++--------- lib/providers/apps_provider.dart | 2 +- lib/providers/source_provider.dart | 7 ++- 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index 3234919..d8fe3d2 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -506,7 +506,7 @@ class _UrlSelectionModalState extends State { widget.onlyOneSelectionAllowed ? tr('selectURL') : tr('selectURLs')), content: Column(children: [ ...urlWithDescriptionSelections.keys.map((urlWithD) { - select(bool? value) { + selectThis(bool? value) { setState(() { value ??= false; if (value! && widget.onlyOneSelectionAllowed) { @@ -517,11 +517,56 @@ class _UrlSelectionModalState extends State { }); } - return Row(children: [ + var urlLink = GestureDetector( + onTap: () { + launchUrlString(urlWithD.key, + mode: LaunchMode.externalApplication); + }, + child: Text( + Uri.parse(urlWithD.key).path.substring(1), + style: const TextStyle(decoration: TextDecoration.underline), + textAlign: TextAlign.start, + )); + + var descriptionText = Text( + urlWithD.value.length > 128 + ? '${urlWithD.value.substring(0, 128)}...' + : urlWithD.value, + style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12), + ); + + var selectedUrlsWithDs = urlWithDescriptionSelections.entries + .where((e) => e.value) + .toList(); + + var singleSelectTile = ListTile( + title: urlLink, + subtitle: GestureDetector( + onTap: () { + setState(() { + selectOnlyOne(urlWithD.key); + }); + }, + child: descriptionText, + ), + leading: Radio( + value: urlWithD.key, + groupValue: selectedUrlsWithDs.isEmpty + ? null + : selectedUrlsWithDs.first.key.key, + onChanged: (value) { + setState(() { + selectOnlyOne(urlWithD.key); + }); + }, + ), + ); + + var multiSelectTile = Row(children: [ Checkbox( value: urlWithDescriptionSelections[urlWithD], onChanged: (value) { - select(value); + selectThis(value); }), const SizedBox( width: 8, @@ -534,28 +579,13 @@ class _UrlSelectionModalState extends State { const SizedBox( height: 8, ), - GestureDetector( - onTap: () { - launchUrlString(urlWithD.key, - mode: LaunchMode.externalApplication); - }, - child: Text( - Uri.parse(urlWithD.key).path.substring(1), - style: - const TextStyle(decoration: TextDecoration.underline), - textAlign: TextAlign.start, - )), + urlLink, GestureDetector( onTap: () { - select(!(urlWithDescriptionSelections[urlWithD] ?? false)); + selectThis( + !(urlWithDescriptionSelections[urlWithD] ?? false)); }, - child: Text( - urlWithD.value.length > 128 - ? '${urlWithD.value.substring(0, 128)}...' - : urlWithD.value, - style: const TextStyle( - fontStyle: FontStyle.italic, fontSize: 12), - ), + child: descriptionText, ), const SizedBox( height: 8, @@ -563,6 +593,10 @@ class _UrlSelectionModalState extends State { ], )) ]); + + return widget.onlyOneSelectionAllowed + ? singleSelectTile + : multiSelectTile; }) ]), actions: [ diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index aa6719b..a5b6154 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -913,7 +913,7 @@ class AppsProvider with ChangeNotifier { Future>> addAppsByURL(List urls) async { List results = await SourceProvider().getAppsByURLNaive(urls, - ignoreUrls: apps.values.map((e) => e.app.url).toList()); + alreadyAddedUrls: apps.values.map((e) => e.app.url).toList()); List pps = results[0]; Map errorsMap = results[1]; for (var app in pps) { diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index da871cd..8670216 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -519,11 +519,14 @@ class SourceProvider { // Returns errors in [results, errors] instead of throwing them Future> getAppsByURLNaive(List urls, - {List ignoreUrls = const []}) async { + {List alreadyAddedUrls = const []}) async { List apps = []; Map errors = {}; - for (var url in urls.where((element) => !ignoreUrls.contains(element))) { + for (var url in urls) { try { + if (alreadyAddedUrls.contains(url)) { + throw ObtainiumError(tr('appAlreadyAdded')); + } var source = getSource(url); apps.add(await getApp( source,