mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-08-16 19:58:09 +02:00
Apps now support multiple categories
This commit is contained in:
@@ -30,7 +30,7 @@ class _AddAppPageState extends State<AddAppPage> {
|
||||
AppSource? pickedSource;
|
||||
Map<String, dynamic> additionalSettings = {};
|
||||
bool additionalSettingsValid = true;
|
||||
String? category;
|
||||
List<String> pickedCategories = [];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -127,8 +127,8 @@ class _AddAppPageState extends State<AddAppPage> {
|
||||
if (app.additionalSettings['trackOnly'] == true) {
|
||||
app.installedVersion = app.latestVersion;
|
||||
}
|
||||
if (category != null) {
|
||||
app.category = category;
|
||||
if (pickedCategories != null) {
|
||||
app.categories = pickedCategories;
|
||||
}
|
||||
await appsProvider.saveApps([app]);
|
||||
|
||||
@@ -334,11 +334,8 @@ class _AddAppPageState extends State<AddAppPage> {
|
||||
),
|
||||
CategoryEditorSelector(
|
||||
alignment: WrapAlignment.start,
|
||||
singleSelect: true,
|
||||
onSelected: (categories) {
|
||||
category = categories.isEmpty
|
||||
? null
|
||||
: categories.first;
|
||||
pickedCategories = categories;
|
||||
}),
|
||||
],
|
||||
),
|
||||
|
@@ -156,15 +156,12 @@ class _AppPageState extends State<AppPage> {
|
||||
),
|
||||
CategoryEditorSelector(
|
||||
alignment: WrapAlignment.center,
|
||||
singleSelect: true,
|
||||
preselected: app?.app.category != null
|
||||
? {app!.app.category!}
|
||||
preselected: app?.app.categories != null
|
||||
? app!.app.categories.toSet()
|
||||
: {},
|
||||
onSelected: (categories) {
|
||||
if (app != null) {
|
||||
app.app.category = categories.isNotEmpty
|
||||
? categories[0]
|
||||
: null;
|
||||
app.app.categories = categories;
|
||||
appsProvider.saveApps([app.app]);
|
||||
}
|
||||
}),
|
||||
|
@@ -102,7 +102,9 @@ class AppsPageState extends State<AppsPage> {
|
||||
}
|
||||
}
|
||||
if (filter.categoryFilter.isNotEmpty &&
|
||||
!filter.categoryFilter.contains(app.app.category)) {
|
||||
filter.categoryFilter
|
||||
.intersection(app.app.categories.toSet())
|
||||
.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -224,14 +226,21 @@ class AppsPageState extends State<AppsPage> {
|
||||
String? changesUrl = SourceProvider()
|
||||
.getSource(sortedApps[index].app.url)
|
||||
.changeLogPageFromStandardUrl(sortedApps[index].app.url);
|
||||
var transparent = const Color.fromARGB(0, 0, 0, 0).value;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.symmetric(
|
||||
vertical: BorderSide(
|
||||
width: 4,
|
||||
color: Color(settingsProvider.categories[
|
||||
sortedApps[index].app.category] ??
|
||||
const Color.fromARGB(0, 0, 0, 0).value)))),
|
||||
color: Color(
|
||||
sortedApps[index].app.categories.isNotEmpty
|
||||
? settingsProvider.categories[
|
||||
sortedApps[index]
|
||||
.app
|
||||
.categories
|
||||
.first] ??
|
||||
transparent
|
||||
: transparent)))),
|
||||
child: ListTile(
|
||||
tileColor: sortedApps[index].app.pinned
|
||||
? Colors.grey.withOpacity(0.1)
|
||||
|
@@ -436,7 +436,7 @@ class _CategoryEditorSelectorState extends State<CategoryEditorSelector> {
|
||||
items: [
|
||||
[
|
||||
GeneratedFormTagInput('categories',
|
||||
label: tr('category'),
|
||||
label: tr('categories'),
|
||||
emptyMessage: tr('noCategories'),
|
||||
defaultValue: storedValues,
|
||||
alignment: widget.alignment,
|
||||
|
@@ -157,15 +157,6 @@ class SettingsProvider with ChangeNotifier {
|
||||
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 {
|
||||
var fl = prefs?.getString('forcedLocale');
|
||||
return supportedLocales
|
||||
|
@@ -48,7 +48,7 @@ class App {
|
||||
late Map<String, dynamic> additionalSettings;
|
||||
late DateTime? lastUpdateCheck;
|
||||
bool pinned = false;
|
||||
String? category;
|
||||
List<String> categories;
|
||||
App(
|
||||
this.id,
|
||||
this.url,
|
||||
@@ -61,7 +61,7 @@ class App {
|
||||
this.additionalSettings,
|
||||
this.lastUpdateCheck,
|
||||
this.pinned,
|
||||
{this.category});
|
||||
{this.categories = const []});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@@ -103,6 +103,7 @@ class App {
|
||||
item.ensureType(additionalSettings[item.key]);
|
||||
}
|
||||
}
|
||||
|
||||
return App(
|
||||
json['id'] as String,
|
||||
json['url'] as String,
|
||||
@@ -123,7 +124,13 @@ class App {
|
||||
? null
|
||||
: DateTime.fromMicrosecondsSinceEpoch(json['lastUpdateCheck']),
|
||||
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() => {
|
||||
@@ -138,7 +145,7 @@ class App {
|
||||
'additionalSettings': jsonEncode(additionalSettings),
|
||||
'lastUpdateCheck': lastUpdateCheck?.microsecondsSinceEpoch,
|
||||
'pinned': pinned,
|
||||
'category': category
|
||||
'categories': categories
|
||||
};
|
||||
}
|
||||
|
||||
@@ -364,7 +371,7 @@ class SourceProvider {
|
||||
additionalSettings,
|
||||
DateTime.now(),
|
||||
currentApp?.pinned ?? false,
|
||||
category: currentApp?.category);
|
||||
categories: currentApp?.categories ?? const []);
|
||||
}
|
||||
|
||||
// Returns errors in [results, errors] instead of throwing them
|
||||
|
Reference in New Issue
Block a user