Bugfix es+ new category picker on App page

This commit is contained in:
Imran Remtulla
2022-12-22 02:13:21 -05:00
parent a3f9947f28
commit fa4d46b622
9 changed files with 81 additions and 63 deletions

View File

@ -203,8 +203,9 @@
"categories": "Categories", "categories": "Categories",
"category": "Category", "category": "Category",
"noCategory": "No Category", "noCategory": "No Category",
"deleteCategoryQuestion": "Delete Category?", "noCategories": "No Categories",
"categoryDeleteWarning": "All Apps in {} will be set to uncategorized.", "deleteCategoriesQuestion": "Delete Categories?",
"categoryDeleteWarning": "All Apps in deleted categories will be set to uncategorized.",
"addCategory": "Add Category", "addCategory": "Add Category",
"label": "Label", "label": "Label",
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {

View File

@ -203,8 +203,9 @@
"categories": "Categories", "categories": "Categories",
"category": "Category", "category": "Category",
"noCategory": "No Category", "noCategory": "No Category",
"deleteCategoryQuestion": "Delete Category?", "noCategories": "No Categories",
"categoryDeleteWarning": "All Apps in {} will be set to uncategorized.", "deleteCategoriesQuestion": "Delete Categories?",
"categoryDeleteWarning": "All Apps in deleted categories will be set to uncategorized.",
"addCategory": "Add Category", "addCategory": "Add Category",
"label": "Label", "label": "Label",
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {

View File

@ -203,8 +203,9 @@
"categories": "Categories", "categories": "Categories",
"category": "Category", "category": "Category",
"noCategory": "No Category", "noCategory": "No Category",
"deleteCategoryQuestion": "Delete Category?", "noCategories": "No Categories",
"categoryDeleteWarning": "All Apps in {} will be set to uncategorized.", "deleteCategoriesQuestion": "Delete Categories?",
"categoryDeleteWarning": "All Apps in deleted categories will be set to uncategorized.",
"addCategory": "Add Category", "addCategory": "Add Category",
"label": "Label", "label": "Label",
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {

View File

@ -203,8 +203,9 @@
"categories": "Categories", "categories": "Categories",
"category": "Category", "category": "Category",
"noCategory": "No Category", "noCategory": "No Category",
"deleteCategoryQuestion": "Delete Category?", "noCategories": "No Categories",
"categoryDeleteWarning": "All Apps in {} will be set to uncategorized.", "deleteCategoriesQuestion": "Delete Categories?",
"categoryDeleteWarning": "All Apps in deleted categories will be set to uncategorized.",
"addCategory": "Add Category", "addCategory": "Add Category",
"label": "Label", "label": "Label",
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {

View File

@ -203,8 +203,9 @@
"categories": "カテゴリ", "categories": "カテゴリ",
"category": "カテゴリ", "category": "カテゴリ",
"noCategory": "カテゴリなし", "noCategory": "カテゴリなし",
"deleteCategoryQuestion": "カテゴリを削除しますか?", "noCategories": "No Categories",
"categoryDeleteWarning": "「{}」内のすべてのアプリは未分類に設定されます。", "deleteCategoriesQuestion": "Delete Categories?",
"categoryDeleteWarning": "All Apps in deleted categories will be set to uncategorized.",
"addCategory": "カテゴリを追加", "addCategory": "カテゴリを追加",
"label": "ラベル", "label": "ラベル",
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {

View File

@ -203,8 +203,9 @@
"categories": "Categories", "categories": "Categories",
"category": "Category", "category": "Category",
"noCategory": "No Category", "noCategory": "No Category",
"deleteCategoryQuestion": "Delete Category?", "noCategories": "No Categories",
"categoryDeleteWarning": "All Apps in {} will be set to uncategorized.", "deleteCategoriesQuestion": "Delete Categories?",
"categoryDeleteWarning": "All Apps in deleted categories will be set to uncategorized.",
"addCategory": "Add Category", "addCategory": "Add Category",
"label": "Label", "label": "Label",
"tooManyRequestsTryAgainInMinutes": { "tooManyRequestsTryAgainInMinutes": {

View File

@ -89,6 +89,8 @@ class GeneratedFormSwitch extends GeneratedFormItem {
class GeneratedFormTagInput extends GeneratedFormItem { class GeneratedFormTagInput extends GeneratedFormItem {
late MapEntry<String, String>? deleteConfirmationMessage; late MapEntry<String, String>? deleteConfirmationMessage;
late bool singleSelect; late bool singleSelect;
late WrapAlignment alignment;
late String emptyMessage;
GeneratedFormTagInput(String key, GeneratedFormTagInput(String key,
{String label = 'Input', {String label = 'Input',
List<Widget> belowWidgets = const [], List<Widget> belowWidgets = const [],
@ -96,7 +98,9 @@ class GeneratedFormTagInput extends GeneratedFormItem {
List<String? Function(Map<String, MapEntry<int, bool>> value)> List<String? Function(Map<String, MapEntry<int, bool>> value)>
additionalValidators = const [], additionalValidators = const [],
this.deleteConfirmationMessage, this.deleteConfirmationMessage,
this.singleSelect = false}) this.singleSelect = false,
this.alignment = WrapAlignment.start,
this.emptyMessage = 'Input'})
: super(key, : super(key,
label: label, label: label,
belowWidgets: belowWidgets, belowWidgets: belowWidgets,
@ -256,7 +260,19 @@ class _GeneratedFormState extends State<GeneratedForm> {
); );
} else if (widget.items[r][e] is GeneratedFormTagInput) { } else if (widget.items[r][e] is GeneratedFormTagInput) {
formInputs[r][e] = Wrap( formInputs[r][e] = Wrap(
alignment: (widget.items[r][e] as GeneratedFormTagInput).alignment,
crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
(values[widget.items[r][e].key]
as Map<String, MapEntry<int, bool>>?)
?.isEmpty ==
true
? Text(
(widget.items[r][e] as GeneratedFormTagInput)
.emptyMessage,
style: const TextStyle(fontWeight: FontWeight.bold),
)
: const SizedBox.shrink(),
...(values[widget.items[r][e].key] ...(values[widget.items[r][e].key]
as Map<String, MapEntry<int, bool>>?) as Map<String, MapEntry<int, bool>>?)
?.entries ?.entries
@ -265,7 +281,7 @@ class _GeneratedFormState extends State<GeneratedForm> {
padding: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(horizontal: 4),
child: ChoiceChip( child: ChoiceChip(
label: Text(e2.key), label: Text(e2.key),
backgroundColor: Color(e2.value.key).withAlpha(200), backgroundColor: Color(e2.value.key).withAlpha(50),
selectedColor: Color(e2.value.key), selectedColor: Color(e2.value.key),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
selected: e2.value.value, selected: e2.value.value,
@ -327,12 +343,15 @@ class _GeneratedFormState extends State<GeneratedForm> {
if ((widget.items[r][e] as GeneratedFormTagInput) if ((widget.items[r][e] as GeneratedFormTagInput)
.deleteConfirmationMessage != .deleteConfirmationMessage !=
null) { null) {
var message =
(widget.items[r][e] as GeneratedFormTagInput)
.deleteConfirmationMessage!;
showDialog<Map<String, dynamic>?>( showDialog<Map<String, dynamic>?>(
context: context, context: context,
builder: (BuildContext ctx) { builder: (BuildContext ctx) {
return GeneratedFormModal( return GeneratedFormModal(
title: tr('deleteCategoryQuestion'), title: message.key,
message: tr('categoryDeleteWarning'), message: message.value,
items: const []); items: const []);
}).then((value) { }).then((value) {
if (value != null) { if (value != null) {
@ -370,8 +389,15 @@ class _GeneratedFormState extends State<GeneratedForm> {
var temp = values[widget.items[r][e].key] var temp = values[widget.items[r][e].key]
as Map<String, MapEntry<int, bool>>?; as Map<String, MapEntry<int, bool>>?;
temp ??= {}; temp ??= {};
var singleSelect =
(widget.items[r][e] as GeneratedFormTagInput)
.singleSelect;
var someSelected = temp.entries
.where((element) => element.value.value)
.isNotEmpty;
temp[label] = MapEntry( temp[label] = MapEntry(
generateRandomLightColor().value, false); generateRandomLightColor().value,
!(someSelected && singleSelect));
values[widget.items[r][e].key] = temp; values[widget.items[r][e].key] = temp;
someValueChanged(); someValueChanged();
}); });

View File

@ -5,6 +5,7 @@ import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/components/generated_form_modal.dart'; import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/main.dart'; import 'package:obtainium/main.dart';
import 'package:obtainium/pages/settings.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
@ -152,49 +153,22 @@ class _AppPageState extends State<AppPage> {
fontStyle: FontStyle.italic, fontSize: 12), fontStyle: FontStyle.italic, fontSize: 12),
), ),
const SizedBox( const SizedBox(
height: 32, height: 48,
), ),
app?.app.category != null CategoryEditorSelector(
? Chip( alignment: WrapAlignment.center,
label: Text(app!.app.category!), singleSelect: true,
backgroundColor: preselected: app?.app.category != null
Color(categories[app.app.category!] ?? 0x0), ? {app!.app.category!}
onDeleted: () { : {},
app.app.category = null; onSelected: (categories) {
appsProvider.saveApps([app.app]); if (app != null) {
}, app.app.category = categories.isNotEmpty
visualDensity: VisualDensity.compact, ? categories[0]
) : null;
: Row( appsProvider.saveApps([app.app]);
mainAxisAlignment: MainAxisAlignment.center, }
children: [ })
TextButton(
onPressed: () {
showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: 'Pick a Category',
items: [
[
settingsProvider
.getCategoryFormItem()
]
]);
}).then((value) {
if (value != null && app != null) {
String? cat = (value['category']
?.isNotEmpty ??
false)
? value['category']
: null;
app.app.category = cat;
appsProvider.saveApps([app.app]);
}
});
},
child: Text(tr('categorize')))
])
], ],
)), )),
], ],

View File

@ -380,8 +380,14 @@ class _LogsDialogState extends State<LogsDialog> {
class CategoryEditorSelector extends StatefulWidget { class CategoryEditorSelector extends StatefulWidget {
final void Function(List<String> categories)? onSelected; final void Function(List<String> categories)? onSelected;
final bool singleSelect; final bool singleSelect;
final Set<String> preselected;
final WrapAlignment alignment;
const CategoryEditorSelector( const CategoryEditorSelector(
{super.key, this.onSelected, this.singleSelect = false}); {super.key,
this.onSelected,
this.singleSelect = false,
this.preselected = const {},
this.alignment = WrapAlignment.start});
@override @override
State<CategoryEditorSelector> createState() => _CategoryEditorSelectorState(); State<CategoryEditorSelector> createState() => _CategoryEditorSelectorState();
@ -393,15 +399,21 @@ class _CategoryEditorSelectorState extends State<CategoryEditorSelector> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var settingsProvider = context.watch<SettingsProvider>(); var settingsProvider = context.watch<SettingsProvider>();
storedValues = settingsProvider.categories.map((key, value) => storedValues = settingsProvider.categories.map((key, value) => MapEntry(
MapEntry(key, MapEntry(value, storedValues[key]?.value ?? false))); key,
MapEntry(value,
storedValues[key]?.value ?? widget.preselected.contains(key))));
return GeneratedForm( return GeneratedForm(
items: [ items: [
[ [
GeneratedFormTagInput('categories', GeneratedFormTagInput('categories',
label: tr('category'),
emptyMessage: tr('noCategories'),
defaultValue: storedValues, defaultValue: storedValues,
alignment: widget.alignment,
deleteConfirmationMessage: MapEntry( deleteConfirmationMessage: MapEntry(
tr('deleteCategoryQuestion'), tr('categoryDeleteWarning')), tr('deleteCategoriesQuestion'),
tr('categoryDeleteWarning')),
singleSelect: widget.singleSelect) singleSelect: widget.singleSelect)
] ]
], ],