From f0cf7b6af29c216cffba0324c20185c445dc73b6 Mon Sep 17 00:00:00 2001 From: randogoth Date: Mon, 24 Feb 2025 14:04:31 +0200 Subject: [PATCH] autofocus setting --- lib/main.dart | 321 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 208 insertions(+), 113 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 7083d3b..064389a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,6 +17,7 @@ class AppSettings { bool colorIcons; // true = color icons; false = monochrome icons bool darkTheme; bool sortAlphabetically; + bool autoFocus; // new AppSettings({ this.showTags = true, @@ -24,6 +25,7 @@ class AppSettings { this.colorIcons = true, this.darkTheme = false, this.sortAlphabetically = false, + this.autoFocus = true, }); } @@ -43,14 +45,13 @@ class _MyAppState extends State { Future _loadSettings() async { SharedPreferences prefs = await SharedPreferences.getInstance(); - bool? savedSorting = prefs.getBool('sortAlphabetically'); - print('Saved sorting: $savedSorting'); // Debug print setState(() { settings.showTags = prefs.getBool('showTags') ?? true; settings.showIcons = prefs.getBool('showIcons') ?? true; settings.colorIcons = prefs.getBool('colorIcons') ?? true; settings.darkTheme = prefs.getBool('darkTheme') ?? false; settings.sortAlphabetically = prefs.getBool('sortAlphabetically') ?? false; + settings.autoFocus = prefs.getBool('autoFocus') ?? true; }); } @@ -68,6 +69,7 @@ class _MyAppState extends State { _updateSetting('colorIcons', settings.colorIcons); _updateSetting('darkTheme', settings.darkTheme); _updateSetting('sortAlphabetically', settings.sortAlphabetically); + _updateSetting('autoFocus', settings.autoFocus); } @override @@ -123,6 +125,7 @@ class AppLauncherScreen extends StatefulWidget { class _AppLauncherScreenState extends State { final TextEditingController searchController = TextEditingController(); + final FocusNode searchFocusNode = FocusNode(); List apps = []; List filteredApps = []; bool isLoading = true; @@ -132,6 +135,11 @@ class _AppLauncherScreenState extends State { super.initState(); _loadInstalledApps(); searchController.addListener(_filterApps); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (widget.settings.autoFocus) { + FocusScope.of(context).requestFocus(searchFocusNode); + } + }); } Future _loadInstalledApps() async { @@ -143,11 +151,27 @@ class _AppLauncherScreenState extends State { List loadedApps = installedApps.map((app) { final lastUsedMillis = prefs.getInt("lastUsed_${app.packageName}"); + final storedTags = prefs.getString("tags_${app.packageName}"); + List 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( icon: app is ApplicationWithIcon ? app.icon : null, name: app.appName, packageName: app.packageName, - tags: [], + tags: tags, lastUsed: lastUsedMillis != null ? DateTime.fromMillisecondsSinceEpoch(lastUsedMillis) : null, @@ -156,9 +180,9 @@ class _AppLauncherScreenState extends State { setState(() { apps = loadedApps; + filteredApps = apps; isLoading = false; }); - // Force initial sorting (by last used if sortAlphabetically is false) _filterApps(); } @@ -244,13 +268,15 @@ class _AppLauncherScreenState extends State { ), actions: [ TextButton( - onPressed: () { + onPressed: () async { setState(() { app.tags ..clear() - ..addAll( - tagController.text.split(" ").where((t) => t.isNotEmpty)); + ..addAll(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(); _filterApps(); }, @@ -265,6 +291,37 @@ class _AppLauncherScreenState extends State { ); } + List _formatTags(String content) { + final tagPattern = RegExp(r'([#@+][a-zA-Z0-9_]+)'); + final Set 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 iconWidget; if (app.icon != null) { @@ -298,6 +355,7 @@ class _AppLauncherScreenState extends State { return Scaffold( appBar: AppBar( title: TextField( + focusNode: widget.settings.autoFocus ? searchFocusNode : null, controller: searchController, decoration: InputDecoration( hintText: 'Search apps...', @@ -308,118 +366,147 @@ class _AppLauncherScreenState extends State { actions: [ Padding( padding: EdgeInsets.symmetric(horizontal: 15), - child: PopupMenuButton( - enabled: searchController.text.isEmpty, - icon: SvgPicture.asset( - "assets/plasmoid.svg", - 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; + child: GestureDetector( + onTap: () { + if (searchController.text.isNotEmpty) { + searchController.clear(); } }, - itemBuilder: (BuildContext context) => [ - PopupMenuItem( - value: 'Toggle Tags', - child: ListTile( - leading: Icon(widget.settings.showTags - ? Icons.short_text - : Icons.tag), - title: Text(widget.settings.showTags - ? 'Hide Tags' - : 'Show Tags'), - ), + child: PopupMenuButton( + enabled: searchController.text.isEmpty, + icon: SvgPicture.asset( + "assets/plasmoid.svg", + width: 30, + color: Colors.orange, ), - PopupMenuItem( - value: 'Toggle Icons', - child: ListTile( - leading: Icon(widget.settings.showIcons - ? Icons.apps - : Icons.apps_outlined), - title: Text(widget.settings.showIcons - ? 'Hide Icons' - : 'Show Icons'), + 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, + 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( + 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( - value: 'Toggle Color Icons', - child: ListTile( - leading: Icon(Icons.palette), - title: Text(widget.settings.colorIcons - ? 'Use Monochrome Icons' - : 'Use Color Icons'), + PopupMenuItem( + value: 'Toggle Icons', + child: ListTile( + leading: Icon(widget.settings.showIcons + ? Icons.apps + : Icons.apps_outlined), + title: Text(widget.settings.showIcons + ? 'Hide Icons' + : 'Show Icons'), + ), ), - ), - PopupMenuItem( - value: 'Toggle Theme', - child: ListTile( - leading: Icon(widget.settings.darkTheme - ? Icons.light_mode - : Icons.dark_mode), - title: Text(widget.settings.darkTheme - ? 'Switch to Light Mode' - : 'Switch to Dark Mode'), + PopupMenuItem( + value: 'Toggle Color Icons', + child: ListTile( + leading: Icon(Icons.palette), + title: Text(widget.settings.colorIcons + ? 'Use Monochrome Icons' + : 'Use Color Icons'), + ), ), - ), - PopupMenuItem( - 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( + value: 'Toggle Theme', + child: ListTile( + leading: Icon(widget.settings.darkTheme + ? Icons.light_mode + : Icons.dark_mode), + title: Text(widget.settings.darkTheme + ? 'Switch to Light Mode' + : 'Switch to Dark Mode'), + ), ), - ), - ], + PopupMenuItem( + 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( + 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 { widget.settings.showIcons ? _buildAppIcon(app) : null, title: Text(app.name), 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), ), );