autofocus setting

This commit is contained in:
randogoth 2025-02-24 14:04:31 +02:00
parent f87e554df0
commit f0cf7b6af2

View file

@ -17,6 +17,7 @@ class AppSettings {
bool colorIcons; // true = color icons; false = monochrome icons bool colorIcons; // true = color icons; false = monochrome icons
bool darkTheme; bool darkTheme;
bool sortAlphabetically; bool sortAlphabetically;
bool autoFocus; // new
AppSettings({ AppSettings({
this.showTags = true, this.showTags = true,
@ -24,6 +25,7 @@ class AppSettings {
this.colorIcons = true, this.colorIcons = true,
this.darkTheme = false, this.darkTheme = false,
this.sortAlphabetically = false, this.sortAlphabetically = false,
this.autoFocus = true,
}); });
} }
@ -43,14 +45,13 @@ class _MyAppState extends State<MyApp> {
Future<void> _loadSettings() async { Future<void> _loadSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
bool? savedSorting = prefs.getBool('sortAlphabetically');
print('Saved sorting: $savedSorting'); // Debug print
setState(() { setState(() {
settings.showTags = prefs.getBool('showTags') ?? true; settings.showTags = prefs.getBool('showTags') ?? true;
settings.showIcons = prefs.getBool('showIcons') ?? true; settings.showIcons = prefs.getBool('showIcons') ?? true;
settings.colorIcons = prefs.getBool('colorIcons') ?? true; settings.colorIcons = prefs.getBool('colorIcons') ?? true;
settings.darkTheme = prefs.getBool('darkTheme') ?? false; settings.darkTheme = prefs.getBool('darkTheme') ?? false;
settings.sortAlphabetically = prefs.getBool('sortAlphabetically') ?? false; settings.sortAlphabetically = prefs.getBool('sortAlphabetically') ?? false;
settings.autoFocus = prefs.getBool('autoFocus') ?? true;
}); });
} }
@ -68,6 +69,7 @@ class _MyAppState extends State<MyApp> {
_updateSetting('colorIcons', settings.colorIcons); _updateSetting('colorIcons', settings.colorIcons);
_updateSetting('darkTheme', settings.darkTheme); _updateSetting('darkTheme', settings.darkTheme);
_updateSetting('sortAlphabetically', settings.sortAlphabetically); _updateSetting('sortAlphabetically', settings.sortAlphabetically);
_updateSetting('autoFocus', settings.autoFocus);
} }
@override @override
@ -123,6 +125,7 @@ class AppLauncherScreen extends StatefulWidget {
class _AppLauncherScreenState extends State<AppLauncherScreen> { class _AppLauncherScreenState extends State<AppLauncherScreen> {
final TextEditingController searchController = TextEditingController(); final TextEditingController searchController = TextEditingController();
final FocusNode searchFocusNode = FocusNode();
List<AppInfo> apps = []; List<AppInfo> apps = [];
List<AppInfo> filteredApps = []; List<AppInfo> filteredApps = [];
bool isLoading = true; bool isLoading = true;
@ -132,6 +135,11 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
super.initState(); super.initState();
_loadInstalledApps(); _loadInstalledApps();
searchController.addListener(_filterApps); searchController.addListener(_filterApps);
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.settings.autoFocus) {
FocusScope.of(context).requestFocus(searchFocusNode);
}
});
} }
Future<void> _loadInstalledApps() async { Future<void> _loadInstalledApps() async {
@ -143,11 +151,27 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
List<AppInfo> loadedApps = installedApps.map((app) { List<AppInfo> loadedApps = installedApps.map((app) {
final lastUsedMillis = prefs.getInt("lastUsed_${app.packageName}"); final lastUsedMillis = prefs.getInt("lastUsed_${app.packageName}");
final storedTags = prefs.getString("tags_${app.packageName}");
List<String> tags = [];
if (storedTags != null && storedTags.trim().isNotEmpty) {
// Use the stored user-edited tags.
tags = storedTags.split(" ");
} else {
// Fall back to using the auto-generated category tag.
if (app.category != null) {
String categoryStr = app.category.toString().split('.').last;
if (categoryStr.toLowerCase() != 'undefined') {
tags.add('@' + categoryStr.toLowerCase());
}
}
}
return AppInfo( return AppInfo(
icon: app is ApplicationWithIcon ? app.icon : null, icon: app is ApplicationWithIcon ? app.icon : null,
name: app.appName, name: app.appName,
packageName: app.packageName, packageName: app.packageName,
tags: [], tags: tags,
lastUsed: lastUsedMillis != null lastUsed: lastUsedMillis != null
? DateTime.fromMillisecondsSinceEpoch(lastUsedMillis) ? DateTime.fromMillisecondsSinceEpoch(lastUsedMillis)
: null, : null,
@ -156,9 +180,9 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
setState(() { setState(() {
apps = loadedApps; apps = loadedApps;
filteredApps = apps;
isLoading = false; isLoading = false;
}); });
// Force initial sorting (by last used if sortAlphabetically is false)
_filterApps(); _filterApps();
} }
@ -244,13 +268,15 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () async {
setState(() { setState(() {
app.tags app.tags
..clear() ..clear()
..addAll( ..addAll(tagController.text.split(" ").where((t) => t.isNotEmpty));
tagController.text.split(" ").where((t) => t.isNotEmpty));
}); });
// Persist the updated tags.
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("tags_${app.packageName}", app.tags.join(" "));
Navigator.of(context).pop(); Navigator.of(context).pop();
_filterApps(); _filterApps();
}, },
@ -265,6 +291,37 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
); );
} }
List<InlineSpan> _formatTags(String content) {
final tagPattern = RegExp(r'([#@+][a-zA-Z0-9_]+)');
final Set<String> tagSet = {}; // Avoid duplicate tags
for (final match in tagPattern.allMatches(content)) {
tagSet.add(match.group(0)!);
}
// Sort tags: +tags before @tags before #tags
final sortedTags = tagSet.toList()
..sort((a, b) {
if (a.startsWith('+') && !b.startsWith('+')) return -1;
if (b.startsWith('+') && !a.startsWith('+')) return 1;
if (a.startsWith('@') && !b.startsWith('@')) return -1;
if (b.startsWith('@') && !a.startsWith('@')) return 1;
return a.compareTo(b); // Default alphabetical order
});
return sortedTags.map((tag) {
Color tagColor = Colors.white;
if (tag.startsWith('#')) tagColor = Colors.pinkAccent;
if (tag.startsWith('+')) tagColor = Colors.cyan;
if (tag.startsWith('@')) tagColor = Colors.orange;
return TextSpan(
text: "$tag ",
style: TextStyle(color: tagColor, fontWeight: FontWeight.bold),
);
}).toList();
}
Widget _buildAppIcon(AppInfo app) { Widget _buildAppIcon(AppInfo app) {
Widget iconWidget; Widget iconWidget;
if (app.icon != null) { if (app.icon != null) {
@ -298,6 +355,7 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: TextField( title: TextField(
focusNode: widget.settings.autoFocus ? searchFocusNode : null,
controller: searchController, controller: searchController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: 'Search apps...', hintText: 'Search apps...',
@ -308,118 +366,147 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
actions: [ actions: [
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 15), padding: EdgeInsets.symmetric(horizontal: 15),
child: PopupMenuButton<String>( child: GestureDetector(
enabled: searchController.text.isEmpty, onTap: () {
icon: SvgPicture.asset( if (searchController.text.isNotEmpty) {
"assets/plasmoid.svg", searchController.clear();
width: 30,
color: Colors.orange,
),
onSelected: (String value) {
switch (value) {
case 'Toggle Tags':
widget.onSettingsChanged(AppSettings(
showTags: !widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
));
break;
case 'Toggle Icons':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: !widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
));
break;
case 'Toggle Color Icons':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: !widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
));
break;
case 'Toggle Theme':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: !widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
));
break;
case 'Toggle Sorting':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: !widget.settings.sortAlphabetically,
));
_filterApps();
break;
} }
}, },
itemBuilder: (BuildContext context) => [ child: PopupMenuButton<String>(
PopupMenuItem<String>( enabled: searchController.text.isEmpty,
value: 'Toggle Tags', icon: SvgPicture.asset(
child: ListTile( "assets/plasmoid.svg",
leading: Icon(widget.settings.showTags width: 30,
? Icons.short_text color: Colors.orange,
: Icons.tag),
title: Text(widget.settings.showTags
? 'Hide Tags'
: 'Show Tags'),
),
), ),
PopupMenuItem<String>( onSelected: (String value) {
value: 'Toggle Icons', switch (value) {
child: ListTile( case 'Toggle Tags':
leading: Icon(widget.settings.showIcons widget.onSettingsChanged(AppSettings(
? Icons.apps showTags: !widget.settings.showTags,
: Icons.apps_outlined), showIcons: widget.settings.showIcons,
title: Text(widget.settings.showIcons colorIcons: widget.settings.colorIcons,
? 'Hide Icons' darkTheme: widget.settings.darkTheme,
: 'Show Icons'), sortAlphabetically: widget.settings.sortAlphabetically,
autoFocus: widget.settings.autoFocus,
));
break;
case 'Toggle Icons':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: !widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
autoFocus: widget.settings.autoFocus,
));
break;
case 'Toggle Color Icons':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: !widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
autoFocus: widget.settings.autoFocus,
));
break;
case 'Toggle Theme':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: !widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
autoFocus: widget.settings.autoFocus,
));
break;
case 'Toggle Sorting':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: !widget.settings.sortAlphabetically,
autoFocus: widget.settings.autoFocus,
));
_filterApps();
break;
case 'Toggle AutoFocus':
widget.onSettingsChanged(AppSettings(
showTags: widget.settings.showTags,
showIcons: widget.settings.showIcons,
colorIcons: widget.settings.colorIcons,
darkTheme: widget.settings.darkTheme,
sortAlphabetically: widget.settings.sortAlphabetically,
autoFocus: !widget.settings.autoFocus,
));
break;
}
},
itemBuilder: (BuildContext context) => [
PopupMenuItem<String>(
value: 'Toggle Tags',
child: ListTile(
leading: Icon(widget.settings.showTags
? Icons.short_text
: Icons.tag),
title: Text(widget.settings.showTags
? 'Hide Tags'
: 'Show Tags'),
),
), ),
), PopupMenuItem<String>(
PopupMenuItem<String>( value: 'Toggle Icons',
value: 'Toggle Color Icons', child: ListTile(
child: ListTile( leading: Icon(widget.settings.showIcons
leading: Icon(Icons.palette), ? Icons.apps
title: Text(widget.settings.colorIcons : Icons.apps_outlined),
? 'Use Monochrome Icons' title: Text(widget.settings.showIcons
: 'Use Color Icons'), ? 'Hide Icons'
: 'Show Icons'),
),
), ),
), PopupMenuItem<String>(
PopupMenuItem<String>( value: 'Toggle Color Icons',
value: 'Toggle Theme', child: ListTile(
child: ListTile( leading: Icon(Icons.palette),
leading: Icon(widget.settings.darkTheme title: Text(widget.settings.colorIcons
? Icons.light_mode ? 'Use Monochrome Icons'
: Icons.dark_mode), : 'Use Color Icons'),
title: Text(widget.settings.darkTheme ),
? 'Switch to Light Mode'
: 'Switch to Dark Mode'),
), ),
), PopupMenuItem<String>(
PopupMenuItem<String>( value: 'Toggle Theme',
value: 'Toggle Sorting', child: ListTile(
child: ListTile( leading: Icon(widget.settings.darkTheme
leading: Icon(widget.settings.sortAlphabetically ? Icons.light_mode
? Icons.access_time : Icons.dark_mode),
: Icons.sort_by_alpha), title: Text(widget.settings.darkTheme
title: Text(widget.settings.sortAlphabetically ? 'Switch to Light Mode'
? 'Sort Alphabetically' : 'Switch to Dark Mode'),
: 'Sort by Last Used'), ),
), ),
), PopupMenuItem<String>(
], value: 'Toggle Sorting',
child: ListTile(
leading: Icon(widget.settings.sortAlphabetically
? Icons.access_time
: Icons.sort_by_alpha),
title: Text(widget.settings.sortAlphabetically
? 'Sort Alphabetically'
: 'Sort by Last Used'),
),
),
PopupMenuItem<String>(
value: 'Toggle AutoFocus',
child: ListTile(
leading: Icon(Icons.center_focus_strong),
title: Text(widget.settings.autoFocus ? 'Disable Auto Focus' : 'Enable Auto Focus'),
),
),
],
),
), ),
), ),
], ],
@ -450,7 +537,15 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
widget.settings.showIcons ? _buildAppIcon(app) : null, widget.settings.showIcons ? _buildAppIcon(app) : null,
title: Text(app.name), title: Text(app.name),
subtitle: subtitle:
widget.settings.showTags ? Text(app.tags.join(" ")) : null, widget.settings.showTags
? RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style,
children: _formatTags(app.tags.join(' ')), // Use stored tags
),
overflow: TextOverflow.ellipsis,
)
: null,
onTap: () => _launchApp(app), onTap: () => _launchApp(app),
), ),
); );