Compare commits

...

4 Commits

Author SHA1 Message Date
868ba84c9a Tiny bugfix 2022-11-20 11:05:33 -05:00
602f0c3bb2 Increment version 2022-11-19 16:26:44 -05:00
00721e8ac4 Added days filter to logs dialog (#117) 2022-11-19 16:20:42 -05:00
d19f9101d6 Added dropdown support to generated form 2022-11-19 15:42:20 -05:00
9 changed files with 115 additions and 34 deletions

View File

@ -1,6 +1,5 @@
import 'dart:convert';
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';

View File

@ -1,4 +1,3 @@
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/app_sources/fdroid.dart';
import 'package:obtainium/custom_errors.dart';

View File

@ -2,7 +2,8 @@ import 'package:flutter/material.dart';
enum FormItemType { string, bool }
typedef OnValueChanges = void Function(List<String> values, bool valid);
typedef OnValueChanges = void Function(
List<String> values, bool valid, bool isBuilding);
class GeneratedFormItem {
late String label;
@ -13,6 +14,7 @@ class GeneratedFormItem {
late String id;
late List<Widget> belowWidgets;
late String? hint;
late List<String>? opts;
GeneratedFormItem(
{this.label = 'Input',
@ -22,7 +24,8 @@ class GeneratedFormItem {
this.additionalValidators = const [],
this.id = 'input',
this.belowWidgets = const [],
this.hint});
this.hint,
this.opts});
}
class GeneratedForm extends StatefulWidget {
@ -47,7 +50,7 @@ class _GeneratedFormState extends State<GeneratedForm> {
List<List<Widget>> rows = [];
// If any value changes, call this to update the parent with value and validity
void someValueChanged() {
void someValueChanged({bool isBuilding = false}) {
List<String> returnValues = [];
var valid = true;
for (int r = 0; r < values.length; r++) {
@ -62,7 +65,7 @@ class _GeneratedFormState extends State<GeneratedForm> {
}
}
}
widget.onValueChanges(returnValues, valid);
widget.onValueChanges(returnValues, valid, isBuilding);
}
@override
@ -75,14 +78,16 @@ class _GeneratedFormState extends State<GeneratedForm> {
.map((row) => row.map((e) {
return j < widget.defaultValues.length
? widget.defaultValues[j++]
: '';
: e.opts != null
? e.opts!.first
: '';
}).toList())
.toList();
// Dynamically create form inputs
formInputs = widget.items.asMap().entries.map((row) {
return row.value.asMap().entries.map((e) {
if (e.value.type == FormItemType.string) {
if (e.value.type == FormItemType.string && e.value.opts == null) {
final formFieldKey = GlobalKey<FormFieldState>();
return TextFormField(
key: formFieldKey,
@ -112,11 +117,29 @@ class _GeneratedFormState extends State<GeneratedForm> {
return null;
},
);
} else if (e.value.type == FormItemType.string &&
e.value.opts != null) {
if (e.value.opts!.isEmpty) {
return const Text('ERROR: DROPDOWN MUST HAVE AT LEAST ONE OPT.');
}
return DropdownButtonFormField(
decoration: const InputDecoration(labelText: 'Colour'),
value: values[row.key][e.key],
items: e.value.opts!
.map((e) => DropdownMenuItem(value: e, child: Text(e)))
.toList(),
onChanged: (value) {
setState(() {
values[row.key][e.key] = value ?? e.value.opts!.first;
someValueChanged();
});
});
} else {
return Container(); // Some input types added in build
}
}).toList();
}).toList();
someValueChanged(isBuilding: true);
}
@override

View File

@ -46,11 +46,16 @@ class _GeneratedFormModalState extends State<GeneratedFormModal> {
),
GeneratedForm(
items: widget.items,
onValueChanges: (values, valid) {
setState(() {
onValueChanges: (values, valid, isBuilding) {
if (isBuilding) {
this.values = values;
this.valid = valid;
});
} else {
setState(() {
this.values = values;
this.valid = valid;
});
}
},
defaultValues: widget.defaultValues)
]),

View File

@ -16,7 +16,7 @@ import 'package:dynamic_color/dynamic_color.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
const String currentVersion = '0.7.4';
const String currentVersion = '0.7.6';
const String currentReleaseTag =
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES

View File

@ -66,7 +66,7 @@ class _AddAppPageState extends State<AddAppPage> {
])
]
],
onValueChanges: (values, valid) {
onValueChanges: (values, valid, isBuilding) {
setState(() {
userInput = values[0];
var source = valid
@ -179,7 +179,7 @@ class _AddAppPageState extends State<AddAppPage> {
.additionalDataFormItems.isNotEmpty)
GeneratedForm(
items: pickedSource!.additionalDataFormItems,
onValueChanges: (values, valid) {
onValueChanges: (values, valid, isBuilding) {
setState(() {
additionalData = values;
validAdditionalData = valid;

View File

@ -388,6 +388,9 @@ class AppsPageState extends State<AppsPage> {
);
}).then((values) {
if (values != null) {
if (values.isEmpty) {
values = ['true', 'true'];
}
bool shouldInstallUpdates = values[0] == 'true';
bool shouldInstallNew = values[1] == 'true';
settingsProvider

View File

@ -142,7 +142,7 @@ class _SettingsPageState extends State<SettingsPage> {
if (e.moreSourceSettingsFormItems.isNotEmpty) {
return GeneratedForm(
items: e.moreSourceSettingsFormItems.map((e) => [e]).toList(),
onValueChanges: (values, valid) {
onValueChanges: (values, valid, isBuilding) {
if (valid) {
for (var i = 0; i < values.length; i++) {
settingsProvider.setSettingString(
@ -264,27 +264,11 @@ class _SettingsPageState extends State<SettingsPage> {
if (logs.isEmpty) {
showError(ObtainiumError('No Logs'), context);
} else {
String logString =
logs.map((e) => e.toString()).join('\n\n');
showDialog(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: 'Obtainium App Logs',
items: const [],
defaultValues: const [],
message: logString,
initValid: true,
);
}).then((value) {
if (value != null) {
Share.share(
logs
.map((e) => e.toString())
.join('\n\n'),
subject: 'Obtainium App Logs');
}
});
return const LogsDialog();
});
}
});
},
@ -299,3 +283,71 @@ class _SettingsPageState extends State<SettingsPage> {
]));
}
}
class LogsDialog extends StatefulWidget {
const LogsDialog({super.key});
@override
State<LogsDialog> createState() => _LogsDialogState();
}
class _LogsDialogState extends State<LogsDialog> {
String? logString;
List<int> days = [7, 5, 4, 3, 2, 1];
@override
Widget build(BuildContext context) {
var logsProvider = context.read<LogsProvider>();
void filterLogs(int days) {
logsProvider
.get(after: DateTime.now().subtract(Duration(days: days)))
.then((value) {
setState(() {
String l = value.map((e) => e.toString()).join('\n\n');
logString = l.isNotEmpty ? l : 'No Logs';
});
});
}
if (logString == null) {
filterLogs(days.first);
}
return AlertDialog(
scrollable: true,
title: const Text('Obtainium App Logs'),
content: Column(
children: [
DropdownButtonFormField(
value: days.first,
items: days
.map((e) => DropdownMenuItem(
value: e,
child: Text('$e Day${e == 1 ? '' : 's'}'),
))
.toList(),
onChanged: (d) {
filterLogs(d ?? 7);
}),
const SizedBox(
height: 32,
),
Text(logString ?? '')
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Close')),
TextButton(
onPressed: () {
Share.share(logString ?? '', subject: 'Obtainium App Logs');
Navigator.of(context).pop();
},
child: const Text('Share'))
],
);
}
}

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 0.7.4+60 # When changing this, update the tag in main() accordingly
version: 0.7.6+62 # When changing this, update the tag in main() accordingly
environment:
sdk: '>=2.18.2 <3.0.0'