UI improvements on app page

This commit is contained in:
Imran Remtulla
2024-01-19 19:57:28 -05:00
parent dc45334cb9
commit e2761ce284
20 changed files with 230 additions and 166 deletions

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Odstranit Apku?", "one": "Odstranit Apku?",
"other": "Odstranit Apky?" "other": "Odstranit Apky?"

View File

@@ -298,6 +298,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App entfernen?", "one": "App entfernen?",
"other": "Apps entfernen?" "other": "Apps entfernen?"

View File

@@ -298,6 +298,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove App?", "one": "Remove App?",
"other": "Remove Apps?" "other": "Remove Apps?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "¿Eliminar Aplicación?", "one": "¿Eliminar Aplicación?",
"other": "¿Eliminar Aplicaciones?" "other": "¿Eliminar Aplicaciones?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application ?", "one": "Supprimer l'application ?",
"other": "Supprimer les applications ?" "other": "Supprimer les applications ?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?", "one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazást?" "other": "Eltávolítja az alkalmazást?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Rimuovere l'app?", "one": "Rimuovere l'app?",
"other": "Rimuovere le app?" "other": "Rimuovere le app?"

View File

@@ -298,6 +298,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "アプリを削除しますか?", "one": "アプリを削除しますか?",
"other": "アプリを削除しますか?" "other": "アプリを削除しますか?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App verwijderen?", "one": "App verwijderen?",
"other": "Apps verwijderen?" "other": "Apps verwijderen?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Usunąć aplikację?", "one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?", "few": "Usunąć aplikacje?",

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remover aplicativo?", "one": "Remover aplicativo?",
"other": "Remover aplicativos?" "other": "Remover aplicativos?"

View File

@@ -298,6 +298,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"

View File

@@ -282,6 +282,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Ta Bort App?", "one": "Ta Bort App?",
"other": "Ta Bort Appar?" "other": "Ta Bort Appar?"

View File

@@ -296,6 +296,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Uygulamayı Kaldır?", "one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?" "other": "Uygulamaları Kaldır?"

View File

@@ -294,6 +294,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion":{ "removeAppQuestion":{
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?" "other": "Gỡ ứng dụng?"

View File

@@ -298,6 +298,9 @@
"partialAPKHash": "Partial APK Hash", "partialAPKHash": "Partial APK Hash",
"APKLinkHash": "APK Link Hash", "APKLinkHash": "APK Link Hash",
"directAPKLink": "Direct APK Link", "directAPKLink": "Direct APK Link",
"pseudoVersionInUse": "A Pseudo-Version is in Use",
"installed": "Installed",
"latest": "Latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "是否删除应用?", "one": "是否删除应用?",
"other": "是否删除应用?" "other": "是否删除应用?"

View File

@@ -384,6 +384,39 @@ class _GeneratedFormState extends State<GeneratedForm> {
], ],
); );
} else if (widget.items[r][e] is GeneratedFormTagInput) { } else if (widget.items[r][e] is GeneratedFormTagInput) {
onAddPressed() {
showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: widget.items[r][e].label,
items: [
[GeneratedFormTextField('label', label: tr('label'))]
]);
}).then((value) {
String? label = value?['label'];
if (label != null) {
setState(() {
var temp =
values[fieldKey] as Map<String, MapEntry<int, bool>>?;
temp ??= {};
if (temp[label] == null) {
var singleSelect =
(widget.items[r][e] as GeneratedFormTagInput)
.singleSelect;
var someSelected = temp.entries
.where((element) => element.value.value)
.isNotEmpty;
temp[label] = MapEntry(generateRandomLightColor().value,
!(someSelected && singleSelect));
values[fieldKey] = temp;
someValueChanged();
}
});
}
});
}
formInputs[r][e] = formInputs[r][e] =
Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
if ((values[fieldKey] as Map<String, MapEntry<int, bool>>?) if ((values[fieldKey] as Map<String, MapEntry<int, bool>>?)
@@ -409,14 +442,14 @@ class _GeneratedFormState extends State<GeneratedForm> {
(widget.items[r][e] as GeneratedFormTagInput).alignment, (widget.items[r][e] as GeneratedFormTagInput).alignment,
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
children: [ children: [
(values[fieldKey] as Map<String, MapEntry<int, bool>>?) // (values[fieldKey] as Map<String, MapEntry<int, bool>>?)
?.isEmpty == // ?.isEmpty ==
true // true
? Text( // ? Text(
(widget.items[r][e] as GeneratedFormTagInput) // (widget.items[r][e] as GeneratedFormTagInput)
.emptyMessage, // .emptyMessage,
) // )
: const SizedBox.shrink(), // : const SizedBox.shrink(),
...(values[fieldKey] as Map<String, MapEntry<int, bool>>?) ...(values[fieldKey] as Map<String, MapEntry<int, bool>>?)
?.entries ?.entries
.map((e2) { .map((e2) {
@@ -540,49 +573,26 @@ class _GeneratedFormState extends State<GeneratedForm> {
tooltip: tr('remove'), tooltip: tr('remove'),
)) ))
: const SizedBox.shrink(), : const SizedBox.shrink(),
Padding( (values[fieldKey] as Map<String, MapEntry<int, bool>>?)
padding: const EdgeInsets.symmetric(horizontal: 4), ?.isEmpty ==
child: IconButton( true
onPressed: () { ? Padding(
showDialog<Map<String, dynamic>?>( padding: const EdgeInsets.symmetric(horizontal: 4),
context: context, child: TextButton.icon(
builder: (BuildContext ctx) { onPressed: onAddPressed,
return GeneratedFormModal( icon: const Icon(Icons.add),
title: widget.items[r][e].label, label: Text(
items: [ (widget.items[r][e] as GeneratedFormTagInput)
[ .label),
GeneratedFormTextField('label', ))
label: tr('label')) : Padding(
] padding: const EdgeInsets.symmetric(horizontal: 4),
]); child: IconButton(
}).then((value) { onPressed: onAddPressed,
String? label = value?['label']; icon: const Icon(Icons.add),
if (label != null) { visualDensity: VisualDensity.compact,
setState(() { tooltip: tr('add'),
var temp = values[fieldKey] )),
as Map<String, MapEntry<int, bool>>?;
temp ??= {};
if (temp[label] == null) {
var singleSelect = (widget.items[r][e]
as GeneratedFormTagInput)
.singleSelect;
var someSelected = temp.entries
.where((element) => element.value.value)
.isNotEmpty;
temp[label] = MapEntry(
generateRandomLightColor().value,
!(someSelected && singleSelect));
values[fieldKey] = temp;
someValueChanged();
}
});
}
});
},
icon: const Icon(Icons.add),
visualDensity: VisualDensity.compact,
tooltip: tr('add'),
)),
], ],
) )
]); ]);

View File

@@ -69,112 +69,107 @@ class _AppPageState extends State<AppPage> {
(app?.app.installedVersion != null && (app?.app.installedVersion != null &&
app?.app.additionalSettings['versionDetection'] != true); app?.app.additionalSettings['versionDetection'] != true);
getInfoColumn() => Column( getInfoColumn() {
mainAxisAlignment: MainAxisAlignment.center, String versionLines = '';
crossAxisAlignment: CrossAxisAlignment.stretch, bool installed = app?.app.installedVersion != null;
children: [ bool upToDate = app?.app.installedVersion == app?.app.latestVersion;
GestureDetector( if (installed) {
onTap: () { versionLines = '${app?.app.installedVersion} ${tr('installed')}';
if (app?.app.url != null) { if (upToDate) {
launchUrlString(app?.app.url ?? '', versionLines += '/${tr('latest')}';
mode: LaunchMode.externalApplication); }
} } else {
}, versionLines = tr('notInstalled');
onLongPress: () { }
Clipboard.setData(ClipboardData(text: app?.app.url ?? '')); if (!upToDate) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( versionLines += '\n${app?.app.latestVersion} ${tr('latest')}';
content: Text(tr('copiedToClipboard')), }
)); String infoLines = tr('lastUpdateCheckX', args: [
}, app?.app.lastUpdateCheck == null
child: Text( ? tr('never')
app?.app.url ?? '', : '${app?.app.lastUpdateCheck?.toLocal()}'
textAlign: TextAlign.center, ]);
style: const TextStyle( if (trackOnly) {
decoration: TextDecoration.underline, infoLines = '${tr('xIsTrackOnly', args: [tr('app')])}\n$infoLines';
fontStyle: FontStyle.italic, }
fontSize: 12), if (installedVersionIsEstimate) {
)), infoLines = '${tr('pseudoVersionInUse')}\n$infoLines';
const SizedBox( }
height: 32, return Column(
), mainAxisAlignment: MainAxisAlignment.center,
Column( crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 24),
child: Column(
children: [ children: [
Text( const SizedBox(
'${tr('latestVersionX', args: [ height: 8,
app?.app.latestVersion ?? tr('unknown') ),
])}\n${tr('installedVersionX', args: [ Text(versionLines,
app?.app.installedVersion ?? tr('none') textAlign: TextAlign.start,
])}${installedVersionIsEstimate ? '\n(${tr('pseudoVersion')})' : ''}', style: Theme.of(context)
textAlign: TextAlign.end, .textTheme
style: Theme.of(context).textTheme.bodyLarge!, .bodyLarge!
.copyWith(fontWeight: FontWeight.bold)),
app?.app.releaseDate == null
? const SizedBox.shrink()
: Text(
app!.app.releaseDate.toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelSmall,
),
const SizedBox(
height: 8,
), ),
], ],
), ),
if (app?.app.installedVersion != null && ),
!isVersionDetectionStandard) Text(
Column( infoLines,
children: [ textAlign: TextAlign.center,
const SizedBox( style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12),
height: 16, ),
), const SizedBox(
Text( height: 48,
trackOnly ? tr('xIsTrackOnly', args: [tr('app')]) : '', ),
style: Theme.of(context).textTheme.labelSmall, CategoryEditorSelector(
alignment: WrapAlignment.center,
preselected: app?.app.categories != null
? app!.app.categories.toSet()
: {},
onSelected: (categories) {
if (app != null) {
app.app.categories = categories;
appsProvider.saveApps([app.app]);
}
}),
if (app?.app.additionalSettings['about'] is String &&
app?.app.additionalSettings['about'].isNotEmpty)
Column(
children: [
const SizedBox(
height: 48,
),
GestureDetector(
onLongPress: () {
Clipboard.setData(ClipboardData(
text: app?.app.additionalSettings['about'] ?? ''));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(tr('copiedToClipboard')),
));
},
child: Text(
app?.app.additionalSettings['about'],
textAlign: TextAlign.center, textAlign: TextAlign.center,
) style: const TextStyle(fontStyle: FontStyle.italic),
],
),
const SizedBox(
height: 32,
),
Text(
tr('lastUpdateCheckX', args: [
app?.app.lastUpdateCheck == null
? tr('never')
: '\n${app?.app.lastUpdateCheck?.toLocal()}'
]),
textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic, fontSize: 12),
),
const SizedBox(
height: 48,
),
CategoryEditorSelector(
alignment: WrapAlignment.center,
preselected: app?.app.categories != null
? app!.app.categories.toSet()
: {},
onSelected: (categories) {
if (app != null) {
app.app.categories = categories;
appsProvider.saveApps([app.app]);
}
}),
if (app?.app.additionalSettings['about'] is String &&
app?.app.additionalSettings['about'].isNotEmpty)
Column(
children: [
const SizedBox(
height: 48,
), ),
GestureDetector( )
onLongPress: () { ],
Clipboard.setData(ClipboardData( ),
text: app?.app.additionalSettings['about'] ?? '')); ],
ScaffoldMessenger.of(context).showSnackBar(SnackBar( );
content: Text(tr('copiedToClipboard')), }
));
},
child: Text(
app?.app.additionalSettings['about'],
textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic),
),
)
],
),
],
);
getFullInfoColumn() => Column( getFullInfoColumn() => Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -201,11 +196,26 @@ class _AppPageState extends State<AppPage> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.displayLarge, style: Theme.of(context).textTheme.displayLarge,
), ),
Text( GestureDetector(
tr('byX', args: [app?.app.author ?? tr('unknown')]), onTap: () {
textAlign: TextAlign.center, if (app?.app.url != null) {
style: Theme.of(context).textTheme.headlineMedium, launchUrlString(app?.app.url ?? '',
), mode: LaunchMode.externalApplication);
}
},
onLongPress: () {
Clipboard.setData(ClipboardData(text: app?.app.url ?? ''));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(tr('copiedToClipboard')),
));
},
child: Text(
tr('byX', args: [app?.app.author ?? tr('unknown')]),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineMedium!.copyWith(
decoration: TextDecoration.underline,
fontStyle: FontStyle.italic),
)),
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
@@ -214,16 +224,6 @@ class _AppPageState extends State<AppPage> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelSmall, style: Theme.of(context).textTheme.labelSmall,
), ),
app?.app.releaseDate == null
? const SizedBox.shrink()
: Text(
app!.app.releaseDate.toString(),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.labelSmall,
),
const SizedBox(
height: 32,
),
getInfoColumn(), getInfoColumn(),
const SizedBox(height: 150) const SizedBox(height: 150)
], ],