Added "Group by Category" setting

This commit is contained in:
Imran Remtulla
2023-03-30 23:40:32 -04:00
parent 814e269d1d
commit 4e17bbcfd1
13 changed files with 118 additions and 16 deletions

View File

@@ -220,6 +220,7 @@
"importFromURLsInFile": "Importieren von URLs aus Datei ( z.B. OPML)",
"versionDetection": "Versionserkennung",
"standardVersionDetection": "Standardversionserkennung",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "App entfernen?",
"other": "App entfernen?"

View File

@@ -220,6 +220,7 @@
"importFromURLsInFile": "Import from URLs in File (like OPML)",
"versionDetection": "Version Detection",
"standardVersionDetection": "Standard version detection",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "Remove App?",
"other": "Remove Apps?"

View File

@@ -220,6 +220,7 @@
"importFromURLsInFile": "وارد کردن از آدرس های اینترنتی موجود در فایل (مانند OPML)",
"versionDetection": "تشخیص نسخه",
"standardVersionDetection": "تشخیص نسخه استاندارد",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟"

View File

@@ -220,6 +220,7 @@
"importFromURLsInFile": "Importer à partir d'URL dans un fichier (comme OPML)",
"versionDetection": "Détection des versions",
"standardVersionDetection": "Détection de version standard",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "Supprimer l'application ?",
"other": "Supprimer les applications ?"

View File

@@ -219,6 +219,7 @@
"importFromURLsInFile": "Importálás fájlban található URL-ből (mint pl. OPML)",
"versionDetection": "Verzió érzékelés",
"standardVersionDetection": "Alapért. verzió érzékelés",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazást?"

View File

@@ -220,6 +220,7 @@
"importFromURLsInFile": "Importa da URL in file (come OPML)",
"versionDetection": "Rilevamento di versione",
"standardVersionDetection": "Rilevamento di versione standard",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "Rimuovere l'App?",
"other": "Rimuovere le App?"

View File

@@ -220,6 +220,7 @@
"importFromURLsInFile": "ファイルOPMLなど内のURLからインポート",
"versionDetection": "バージョン検出",
"standardVersionDetection": "標準のバージョン検出",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "アプリを削除しますか?",
"other": "アプリを削除しますか?"

View File

@@ -220,6 +220,7 @@
"importFromURLsInFile": "Import from URLs in File (like OPML)",
"versionDetection": "Version Detection",
"standardVersionDetection": "Standard version detection",
"groupByCategory": "Group by Category",
"removeAppQuestion": {
"one": "删除应用?",
"other": "删除应用?"

View File

@@ -21,7 +21,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart';
// ignore: implementation_imports
import 'package:easy_localization/src/localization.dart';
const String currentVersion = '0.11.16';
const String currentVersion = '0.11.17';
const String currentReleaseTag =
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES

View File

@@ -187,6 +187,25 @@ class AppsPageState extends State<AppsPage> {
}
listedApps = [...tempPinned, ...tempNotPinned];
List<String?> getListedCategories() {
var temp = listedApps
.map((e) => e.app.categories.isNotEmpty ? e.app.categories : [null]);
return temp.isNotEmpty
? {
...temp.reduce((v, e) => [...v, ...e])
}.toList()
: [];
}
var listedCategories = getListedCategories();
listedCategories.sort((a, b) {
return a != null && b != null
? a.compareTo(b)
: a == null
? 1
: -1;
});
showChangeLogDialog(
String? changesUrl, AppSource appSource, String changeLog, int index) {
showDialog(
@@ -402,17 +421,37 @@ class AppsPageState extends State<AppsPage> {
],
);
var transparent = const Color.fromARGB(0, 0, 0, 0).value;
var transparent =
Theme.of(context).colorScheme.background.withAlpha(0).value;
List<double> stops = [
...listedApps[index]
.app
.categories
.asMap()
.entries
.map((e) =>
((e.key / (listedApps[index].app.categories.length - 1))))
.toList(),
1
];
if (stops.length == 2) {
stops[0] = 1;
}
return Container(
decoration: BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(
width: 4,
color: Color(listedApps[index].app.categories.isNotEmpty
? settingsProvider.categories[
listedApps[index].app.categories.first] ??
transparent
: transparent)))),
gradient: LinearGradient(
stops: stops,
begin: const Alignment(-1, 0),
end: const Alignment(-0.97, 0),
colors: [
...listedApps[index]
.app
.categories
.map((e) =>
Color(settingsProvider.categories[e]!).withAlpha(255))
.toList(),
Color(transparent)
])),
child: ListTile(
tileColor: listedApps[index].app.pinned
? Colors.grey.withOpacity(0.1)
@@ -465,6 +504,28 @@ class AppsPageState extends State<AppsPage> {
));
}
getCategoryCollapsibleTile(int index) {
var tiles = listedApps
.asMap()
.entries
.where((e) =>
e.value.app.categories.contains(listedCategories[index]) ||
e.value.app.categories.isEmpty && listedCategories[index] == null)
.map((e) => getSingleAppHorizTile(e.key))
.toList();
capFirstChar(String str) => str[0].toUpperCase() + str.substring(1);
return ExpansionTile(
initiallyExpanded: true,
title: Text(
capFirstChar(listedCategories[index] ?? tr('noCategory')),
style: const TextStyle(fontWeight: FontWeight.bold),
),
controlAffinity: ListTileControlAffinity.leading,
trailing: Text(tiles.length.toString()),
children: tiles);
}
getSelectAllButton() {
return selectedApps.isEmpty
? TextButton.icon(
@@ -903,6 +964,22 @@ class AppsPageState extends State<AppsPage> {
);
}
getDisplayedList() {
return settingsProvider.groupByCategory &&
!(listedCategories.isEmpty ||
(listedCategories.length == 1 && listedCategories[0] == null))
? SliverList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index) {
return getCategoryCollapsibleTile(index);
}, childCount: listedCategories.length))
: SliverList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index) {
return getSingleAppHorizTile(index);
}, childCount: listedApps.length));
}
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.surface,
body: RefreshIndicator(
@@ -922,11 +999,7 @@ class AppsPageState extends State<AppsPage> {
child: CustomScrollView(slivers: <Widget>[
CustomAppBar(title: tr('appsString')),
...getLoadingWidgets(),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return getSingleAppHorizTile(index);
}, childCount: listedApps.length))
getDisplayedList()
])),
persistentFooterButtons: appsProvider.apps.isEmpty
? null

View File

@@ -262,6 +262,18 @@ class _SettingsPageState extends State<SettingsPage> {
})
],
),
height16,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(tr('groupByCategory')),
Switch(
value: settingsProvider.groupByCategory,
onChanged: (value) {
settingsProvider.groupByCategory = value;
})
],
),
const Divider(
height: 16,
),

View File

@@ -139,6 +139,15 @@ class SettingsProvider with ChangeNotifier {
notifyListeners();
}
bool get groupByCategory {
return prefs?.getBool('groupByCategory') ?? false;
}
set groupByCategory(bool show) {
prefs?.setBool('groupByCategory', show);
notifyListeners();
}
String? getSettingString(String settingId) {
return prefs?.getString(settingId);
}

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.11.16+138 # When changing this, update the tag in main() accordingly
version: 0.11.17+139 # When changing this, update the tag in main() accordingly
environment:
sdk: '>=2.18.2 <3.0.0'