Apps now support multiple categories

This commit is contained in:
Imran Remtulla
2022-12-27 19:37:13 -05:00
parent 21cf9c98d9
commit 8ddeb3d776
6 changed files with 33 additions and 32 deletions

View File

@@ -30,7 +30,7 @@ class _AddAppPageState extends State<AddAppPage> {
AppSource? pickedSource; AppSource? pickedSource;
Map<String, dynamic> additionalSettings = {}; Map<String, dynamic> additionalSettings = {};
bool additionalSettingsValid = true; bool additionalSettingsValid = true;
String? category; List<String> pickedCategories = [];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -127,8 +127,8 @@ class _AddAppPageState extends State<AddAppPage> {
if (app.additionalSettings['trackOnly'] == true) { if (app.additionalSettings['trackOnly'] == true) {
app.installedVersion = app.latestVersion; app.installedVersion = app.latestVersion;
} }
if (category != null) { if (pickedCategories != null) {
app.category = category; app.categories = pickedCategories;
} }
await appsProvider.saveApps([app]); await appsProvider.saveApps([app]);
@@ -334,11 +334,8 @@ class _AddAppPageState extends State<AddAppPage> {
), ),
CategoryEditorSelector( CategoryEditorSelector(
alignment: WrapAlignment.start, alignment: WrapAlignment.start,
singleSelect: true,
onSelected: (categories) { onSelected: (categories) {
category = categories.isEmpty pickedCategories = categories;
? null
: categories.first;
}), }),
], ],
), ),

View File

@@ -156,15 +156,12 @@ class _AppPageState extends State<AppPage> {
), ),
CategoryEditorSelector( CategoryEditorSelector(
alignment: WrapAlignment.center, alignment: WrapAlignment.center,
singleSelect: true, preselected: app?.app.categories != null
preselected: app?.app.category != null ? app!.app.categories.toSet()
? {app!.app.category!}
: {}, : {},
onSelected: (categories) { onSelected: (categories) {
if (app != null) { if (app != null) {
app.app.category = categories.isNotEmpty app.app.categories = categories;
? categories[0]
: null;
appsProvider.saveApps([app.app]); appsProvider.saveApps([app.app]);
} }
}), }),

View File

@@ -102,7 +102,9 @@ class AppsPageState extends State<AppsPage> {
} }
} }
if (filter.categoryFilter.isNotEmpty && if (filter.categoryFilter.isNotEmpty &&
!filter.categoryFilter.contains(app.app.category)) { filter.categoryFilter
.intersection(app.app.categories.toSet())
.isEmpty) {
return false; return false;
} }
return true; return true;
@@ -224,14 +226,21 @@ class AppsPageState extends State<AppsPage> {
String? changesUrl = SourceProvider() String? changesUrl = SourceProvider()
.getSource(sortedApps[index].app.url) .getSource(sortedApps[index].app.url)
.changeLogPageFromStandardUrl(sortedApps[index].app.url); .changeLogPageFromStandardUrl(sortedApps[index].app.url);
var transparent = const Color.fromARGB(0, 0, 0, 0).value;
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.symmetric( border: Border.symmetric(
vertical: BorderSide( vertical: BorderSide(
width: 4, width: 4,
color: Color(settingsProvider.categories[ color: Color(
sortedApps[index].app.category] ?? sortedApps[index].app.categories.isNotEmpty
const Color.fromARGB(0, 0, 0, 0).value)))), ? settingsProvider.categories[
sortedApps[index]
.app
.categories
.first] ??
transparent
: transparent)))),
child: ListTile( child: ListTile(
tileColor: sortedApps[index].app.pinned tileColor: sortedApps[index].app.pinned
? Colors.grey.withOpacity(0.1) ? Colors.grey.withOpacity(0.1)

View File

@@ -436,7 +436,7 @@ class _CategoryEditorSelectorState extends State<CategoryEditorSelector> {
items: [ items: [
[ [
GeneratedFormTagInput('categories', GeneratedFormTagInput('categories',
label: tr('category'), label: tr('categories'),
emptyMessage: tr('noCategories'), emptyMessage: tr('noCategories'),
defaultValue: storedValues, defaultValue: storedValues,
alignment: widget.alignment, alignment: widget.alignment,

View File

@@ -157,15 +157,6 @@ class SettingsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
getCategoryFormItem({String initCategory = ''}) => GeneratedFormDropdown(
'category',
label: tr('category'),
[
MapEntry('', tr('noCategory')),
...categories.entries.map((e) => MapEntry(e.key, e.key)).toList()
],
defaultValue: initCategory);
String? get forcedLocale { String? get forcedLocale {
var fl = prefs?.getString('forcedLocale'); var fl = prefs?.getString('forcedLocale');
return supportedLocales return supportedLocales

View File

@@ -48,7 +48,7 @@ class App {
late Map<String, dynamic> additionalSettings; late Map<String, dynamic> additionalSettings;
late DateTime? lastUpdateCheck; late DateTime? lastUpdateCheck;
bool pinned = false; bool pinned = false;
String? category; List<String> categories;
App( App(
this.id, this.id,
this.url, this.url,
@@ -61,7 +61,7 @@ class App {
this.additionalSettings, this.additionalSettings,
this.lastUpdateCheck, this.lastUpdateCheck,
this.pinned, this.pinned,
{this.category}); {this.categories = const []});
@override @override
String toString() { String toString() {
@@ -103,6 +103,7 @@ class App {
item.ensureType(additionalSettings[item.key]); item.ensureType(additionalSettings[item.key]);
} }
} }
return App( return App(
json['id'] as String, json['id'] as String,
json['url'] as String, json['url'] as String,
@@ -123,7 +124,13 @@ class App {
? null ? null
: DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']), : DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']),
json['pinned'] ?? false, json['pinned'] ?? false,
category: json['category']); categories: json['categories'] != null
? (json['categories'] as List<dynamic>)
.map((e) => e.toString())
.toList()
: json['category'] != null
? [json['category'] as String]
: []);
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
@@ -138,7 +145,7 @@ class App {
'additionalSettings': jsonEncode(additionalSettings), 'additionalSettings': jsonEncode(additionalSettings),
'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch, 'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch,
'pinned': pinned, 'pinned': pinned,
'category': category 'categories': categories
}; };
} }
@@ -364,7 +371,7 @@ class SourceProvider {
additionalSettings, additionalSettings,
DateTime.now(), DateTime.now(),
currentApp?.pinned ?? false, currentApp?.pinned ?? false,
category: currentApp?.category); categories: currentApp?.categories ?? const []);
} }
// Returns errors in [results, errors] instead of throwing them // Returns errors in [results, errors] instead of throwing them