refactor
This commit is contained in:
parent
c065a013fc
commit
a88a61cf01
5 changed files with 232 additions and 262 deletions
290
lib/main.dart
290
lib/main.dart
|
|
@ -5,82 +5,29 @@ import 'package:device_apps/device_apps.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:plasmoid/preferences.dart';
|
||||||
import 'package:plasmoid/read_only.dart';
|
import 'package:plasmoid/read_only.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:plasmoid/settings.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'day.dart';
|
import 'day.dart';
|
||||||
import 'night.dart';
|
import 'night.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
LicenseRegistry.addLicense(() async* {
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
final license = await rootBundle.loadString('google_fonts/OFL.txt');
|
await SharedPreferencesService().initialize();
|
||||||
yield LicenseEntryWithLineBreaks(['google_fonts'], license);
|
runApp(
|
||||||
});
|
ChangeNotifierProvider(
|
||||||
runApp(MyApp());
|
create: (_) => AppSettings(),
|
||||||
}
|
child: MyApp(),
|
||||||
|
),
|
||||||
class AppSettings {
|
);
|
||||||
bool showTags;
|
|
||||||
bool showIcons;
|
|
||||||
bool colorIcons; // true = color icons; false = monochrome icons
|
|
||||||
bool darkTheme;
|
|
||||||
bool sortAlphabetically;
|
|
||||||
bool autoFocus; // new
|
|
||||||
|
|
||||||
AppSettings({
|
|
||||||
this.showTags = true,
|
|
||||||
this.showIcons = true,
|
|
||||||
this.colorIcons = true,
|
|
||||||
this.darkTheme = false,
|
|
||||||
this.sortAlphabetically = false,
|
|
||||||
this.autoFocus = true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyApp extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_MyAppState createState() => _MyAppState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
|
||||||
AppSettings settings = AppSettings();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_loadSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _loadSettings() async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _updateSetting(String key, bool value) async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
await prefs.setBool(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateSettings(AppSettings newSettings) {
|
|
||||||
setState(() {
|
|
||||||
settings = newSettings;
|
|
||||||
});
|
|
||||||
_updateSetting('showTags', settings.showTags);
|
|
||||||
_updateSetting('showIcons', settings.showIcons);
|
|
||||||
_updateSetting('colorIcons', settings.colorIcons);
|
|
||||||
_updateSetting('darkTheme', settings.darkTheme);
|
|
||||||
_updateSetting('sortAlphabetically', settings.sortAlphabetically);
|
|
||||||
_updateSetting('autoFocus', settings.autoFocus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer<AppSettings>(
|
||||||
|
builder: (context, settings, child) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Plasmoid Launcher',
|
title: 'Plasmoid Launcher',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
|
|
@ -96,10 +43,9 @@ class _MyAppState extends State<MyApp> {
|
||||||
textTheme: GoogleFonts.ibmPlexMonoTextTheme(nightText),
|
textTheme: GoogleFonts.ibmPlexMonoTextTheme(nightText),
|
||||||
),
|
),
|
||||||
themeMode: settings.darkTheme ? ThemeMode.dark : ThemeMode.light,
|
themeMode: settings.darkTheme ? ThemeMode.dark : ThemeMode.light,
|
||||||
home: AppLauncherScreen(
|
home: AppLauncherScreen(),
|
||||||
settings: settings,
|
);
|
||||||
onSettingsChanged: _updateSettings,
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,16 +67,11 @@ class AppInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppLauncherScreen extends StatefulWidget {
|
class AppLauncherScreen extends StatefulWidget {
|
||||||
final AppSettings settings;
|
|
||||||
final Function(AppSettings) onSettingsChanged;
|
|
||||||
|
|
||||||
AppLauncherScreen({required this.settings, required this.onSettingsChanged});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AppLauncherScreenState createState() => _AppLauncherScreenState();
|
_AppLauncherScreenState createState() => _AppLauncherScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
class _AppLauncherScreenState extends State<AppLauncherScreen> with WidgetsBindingObserver {
|
||||||
final TextEditingController searchController = TextEditingController();
|
final TextEditingController searchController = TextEditingController();
|
||||||
final FocusNode searchFocusNode = FocusNode();
|
final FocusNode searchFocusNode = FocusNode();
|
||||||
List<AppInfo> apps = [];
|
List<AppInfo> apps = [];
|
||||||
|
|
@ -140,38 +81,47 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
_loadInstalledApps();
|
_loadInstalledApps();
|
||||||
searchController.addListener(_filterApps);
|
searchController.addListener(_filterApps);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (widget.settings.autoFocus) {
|
if (context.read<AppSettings>().autoFocus) {
|
||||||
FocusScope.of(context).requestFocus(searchFocusNode);
|
FocusScope.of(context).requestFocus(searchFocusNode);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
if (state == AppLifecycleState.resumed) {
|
||||||
|
_loadInstalledApps();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _loadInstalledApps() async {
|
Future<void> _loadInstalledApps() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
List<Application> installedApps = await DeviceApps.getInstalledApplications(
|
List<Application> installedApps = await DeviceApps.getInstalledApplications(
|
||||||
includeAppIcons: true,
|
includeAppIcons: true,
|
||||||
onlyAppsWithLaunchIntent: true,
|
onlyAppsWithLaunchIntent: true,
|
||||||
includeSystemApps: true
|
includeSystemApps: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
List<AppInfo> loadedApps = installedApps.map((app) {
|
List<AppInfo> loadedApps = installedApps.map((app) {
|
||||||
final lastUsedMillis = prefs.getInt("lastUsed_${app.packageName}");
|
final lastUsedMillis = SharedPreferencesService().getInt("lastUsed_${app.packageName}");
|
||||||
final storedTags = prefs.getString("tags_${app.packageName}");
|
final storedTags = SharedPreferencesService().getString("tags_${app.packageName}");
|
||||||
List<String> tags = [];
|
List<String> tags = [];
|
||||||
|
|
||||||
if (storedTags != null && storedTags.trim().isNotEmpty) {
|
if (storedTags != null && storedTags.trim().isNotEmpty) {
|
||||||
// Use the stored user-edited tags.
|
|
||||||
tags = storedTags.split(" ");
|
tags = storedTags.split(" ");
|
||||||
} else {
|
} else if (app.category != null) {
|
||||||
// Fall back to using the auto-generated category tag.
|
|
||||||
if (app.category != null) {
|
|
||||||
String categoryStr = app.category.toString().split('.').last;
|
String categoryStr = app.category.toString().split('.').last;
|
||||||
if (categoryStr.toLowerCase() != 'undefined') {
|
if (categoryStr.toLowerCase() != 'undefined') {
|
||||||
tags.add('@' + categoryStr.toLowerCase());
|
tags.add('@${categoryStr.toLowerCase()}');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,9 +130,7 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
name: app.appName,
|
name: app.appName,
|
||||||
packageName: app.packageName,
|
packageName: app.packageName,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
lastUsed: lastUsedMillis != null
|
lastUsed: lastUsedMillis != null ? DateTime.fromMillisecondsSinceEpoch(lastUsedMillis) : null,
|
||||||
? DateTime.fromMillisecondsSinceEpoch(lastUsedMillis)
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
|
@ -203,24 +151,14 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
return matchesName || matchesTag;
|
return matchesName || matchesTag;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
if (widget.settings.sortAlphabetically) {
|
if (context.read<AppSettings>().sortLastUsed) {
|
||||||
filteredApps.sort((a, b) => a.name.compareTo(b.name));
|
|
||||||
print('Sorting alphabetically');
|
|
||||||
} else {
|
|
||||||
filteredApps.sort((a, b) {
|
filteredApps.sort((a, b) {
|
||||||
// If both have a lastUsed timestamp, sort descending.
|
DateTime aTime = a.lastUsed ?? DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
if (a.lastUsed != null && b.lastUsed != null) {
|
DateTime bTime = b.lastUsed ?? DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
int cmp = b.lastUsed!.compareTo(a.lastUsed!);
|
return bTime.compareTo(aTime);
|
||||||
if (cmp != 0) return cmp;
|
|
||||||
return a.name.compareTo(b.name);
|
|
||||||
}
|
|
||||||
// If one has a timestamp, that one comes first.
|
|
||||||
if (a.lastUsed != null) return -1;
|
|
||||||
if (b.lastUsed != null) return 1;
|
|
||||||
// Both null: fallback alphabetical.
|
|
||||||
return a.name.compareTo(b.name);
|
|
||||||
});
|
});
|
||||||
print('Sorting by last used, with fallback alphabetical');
|
} else {
|
||||||
|
filteredApps.sort((a, b) => a.name.compareTo(b.name));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -229,9 +167,7 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
bool launched = await DeviceApps.openApp(app.packageName);
|
bool launched = await DeviceApps.openApp(app.packageName);
|
||||||
if (launched) {
|
if (launched) {
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
await SharedPreferencesService().setInt("lastUsed_${app.packageName}", now.millisecondsSinceEpoch);
|
||||||
await prefs.setInt("lastUsed_${app.packageName}", now.millisecondsSinceEpoch);
|
|
||||||
// Update the lastUsed timestamp and re-sort immediately.
|
|
||||||
setState(() {
|
setState(() {
|
||||||
app.lastUsed = now;
|
app.lastUsed = now;
|
||||||
_filterApps();
|
_filterApps();
|
||||||
|
|
@ -262,8 +198,7 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _editAppTags(AppInfo app) {
|
void _editAppTags(AppInfo app) {
|
||||||
TextEditingController tagController =
|
TextEditingController tagController = TextEditingController(text: app.tags.join(" "));
|
||||||
TextEditingController(text: app.tags.join(" "));
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => AlertDialog(
|
builder: (_) => AlertDialog(
|
||||||
|
|
@ -282,9 +217,7 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
..clear()
|
..clear()
|
||||||
..addAll(tagController.text.split(" ").where((t) => t.isNotEmpty));
|
..addAll(tagController.text.split(" ").where((t) => t.isNotEmpty));
|
||||||
});
|
});
|
||||||
// Persist the updated tags.
|
await SharedPreferencesService().setString("tags_${app.packageName}", app.tags.join(" "));
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
await prefs.setString("tags_${app.packageName}", app.tags.join(" "));
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
_filterApps();
|
_filterApps();
|
||||||
},
|
},
|
||||||
|
|
@ -301,20 +234,19 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
|
|
||||||
List<InlineSpan> _formatTags(String content) {
|
List<InlineSpan> _formatTags(String content) {
|
||||||
final tagPattern = RegExp(r'([#@+][a-zA-Z0-9_]+)');
|
final tagPattern = RegExp(r'([#@+][a-zA-Z0-9_]+)');
|
||||||
final Set<String> tagSet = {}; // Avoid duplicate tags
|
final Set<String> tagSet = {};
|
||||||
|
|
||||||
for (final match in tagPattern.allMatches(content)) {
|
for (final match in tagPattern.allMatches(content)) {
|
||||||
tagSet.add(match.group(0)!);
|
tagSet.add(match.group(0)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort tags: +tags before @tags before #tags
|
|
||||||
final sortedTags = tagSet.toList()
|
final sortedTags = tagSet.toList()
|
||||||
..sort((a, b) {
|
..sort((a, b) {
|
||||||
if (a.startsWith('+') && !b.startsWith('+')) return -1;
|
if (a.startsWith('+') && !b.startsWith('+')) return -1;
|
||||||
if (b.startsWith('+') && !a.startsWith('+')) return 1;
|
if (b.startsWith('+') && !a.startsWith('+')) return 1;
|
||||||
if (a.startsWith('@') && !b.startsWith('@')) return -1;
|
if (a.startsWith('@') && !b.startsWith('@')) return -1;
|
||||||
if (b.startsWith('@') && !a.startsWith('@')) return 1;
|
if (b.startsWith('@') && !a.startsWith('@')) return 1;
|
||||||
return a.compareTo(b); // Default alphabetical order
|
return a.compareTo(b);
|
||||||
});
|
});
|
||||||
|
|
||||||
return sortedTags.map((tag) {
|
return sortedTags.map((tag) {
|
||||||
|
|
@ -343,7 +275,7 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
iconWidget = Icon(Icons.apps, size: 40);
|
iconWidget = Icon(Icons.apps, size: 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!widget.settings.colorIcons) {
|
if (!context.read<AppSettings>().colorIcons) {
|
||||||
iconWidget = ColorFiltered(
|
iconWidget = ColorFiltered(
|
||||||
colorFilter: ColorFilter.matrix(<double>[
|
colorFilter: ColorFilter.matrix(<double>[
|
||||||
0.2126, 0.7152, 0.0722, 0, 0,
|
0.2126, 0.7152, 0.0722, 0, 0,
|
||||||
|
|
@ -358,14 +290,14 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
return iconWidget;
|
return iconWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
_showInfoPage(BuildContext context, String title, String content) {
|
void _showInfoPage(BuildContext context, String title, String content) {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => ReadOnlyPage(
|
builder: (context) => ReadOnlyPage(
|
||||||
title: title,
|
title: title,
|
||||||
content: content,
|
content: content,
|
||||||
isDarkMode: widget.settings.darkTheme,
|
isDarkMode: context.read<AppSettings>().darkTheme,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -376,7 +308,7 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: TextField(
|
title: TextField(
|
||||||
focusNode: widget.settings.autoFocus ? searchFocusNode : null,
|
focusNode: context.read<AppSettings>().autoFocus ? searchFocusNode : null,
|
||||||
controller: searchController,
|
controller: searchController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Search apps...',
|
hintText: 'Search apps...',
|
||||||
|
|
@ -400,134 +332,77 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
width: 30,
|
width: 30,
|
||||||
color: Color(0xff38818a),
|
color: Color(0xff38818a),
|
||||||
),
|
),
|
||||||
onSelected: (String value) {
|
onSelected: (String value) async {
|
||||||
|
final settings = context.read<AppSettings>();
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 'Toggle Tags':
|
case 'Toggle Tags':
|
||||||
widget.onSettingsChanged(AppSettings(
|
settings.updateSetting('showTags', !settings.showTags);
|
||||||
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;
|
break;
|
||||||
case 'Toggle Icons':
|
case 'Toggle Icons':
|
||||||
widget.onSettingsChanged(AppSettings(
|
settings.updateSetting('showIcons', !settings.showIcons);
|
||||||
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;
|
break;
|
||||||
case 'Toggle Color Icons':
|
case 'Toggle Color Icons':
|
||||||
widget.onSettingsChanged(AppSettings(
|
settings.updateSetting('colorIcons', !settings.colorIcons);
|
||||||
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;
|
break;
|
||||||
case 'Toggle Theme':
|
case 'Toggle Theme':
|
||||||
widget.onSettingsChanged(AppSettings(
|
settings.updateSetting('darkTheme', !settings.darkTheme);
|
||||||
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;
|
break;
|
||||||
case 'Toggle Sorting':
|
case 'Toggle Sorting':
|
||||||
widget.onSettingsChanged(AppSettings(
|
settings.updateSetting('sortLastUsed', !settings.sortLastUsed);
|
||||||
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();
|
_filterApps();
|
||||||
break;
|
break;
|
||||||
case 'Toggle AutoFocus':
|
case 'Toggle AutoFocus':
|
||||||
widget.onSettingsChanged(AppSettings(
|
settings.updateSetting('autoFocus', !settings.autoFocus);
|
||||||
showTags: widget.settings.showTags,
|
if (!settings.autoFocus) FocusScope.of(context).unfocus();
|
||||||
showIcons: widget.settings.showIcons,
|
|
||||||
colorIcons: widget.settings.colorIcons,
|
|
||||||
darkTheme: widget.settings.darkTheme,
|
|
||||||
sortAlphabetically: widget.settings.sortAlphabetically,
|
|
||||||
autoFocus: !widget.settings.autoFocus,
|
|
||||||
));
|
|
||||||
if (!widget.settings.autoFocus) FocusScope.of(context).unfocus();
|
|
||||||
break;
|
break;
|
||||||
case 'About':
|
case 'About':
|
||||||
_showInfoPage(context, "About", aboutContent);
|
_showInfoPage(context, "About", aboutContent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
itemBuilder: (BuildContext context) => [
|
itemBuilder: (BuildContext context) {
|
||||||
|
final settings = context.read<AppSettings>();
|
||||||
|
return [
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'Toggle Tags',
|
value: 'Toggle Tags',
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(widget.settings.showTags
|
leading: Icon(settings.showTags ? Icons.short_text : Icons.tag),
|
||||||
? Icons.short_text
|
title: Text(settings.showTags ? 'Hide Tags' : 'Show Tags'),
|
||||||
: Icons.tag),
|
|
||||||
title: Text(widget.settings.showTags
|
|
||||||
? 'Hide Tags'
|
|
||||||
: 'Show Tags'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'Toggle Icons',
|
value: 'Toggle Icons',
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(widget.settings.showIcons
|
leading: Icon(settings.showIcons ? Icons.apps : Icons.apps_outlined),
|
||||||
? Icons.apps
|
title: Text(settings.showIcons ? 'Hide Icons' : 'Show Icons'),
|
||||||
: Icons.apps_outlined),
|
|
||||||
title: Text(widget.settings.showIcons
|
|
||||||
? 'Hide Icons'
|
|
||||||
: 'Show Icons'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'Toggle Color Icons',
|
value: 'Toggle Color Icons',
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(Icons.palette),
|
leading: Icon(Icons.palette),
|
||||||
title: Text(widget.settings.colorIcons
|
title: Text(settings.colorIcons ? 'Use Monochrome Icons' : 'Use Color Icons'),
|
||||||
? 'Use Monochrome Icons'
|
|
||||||
: 'Use Color Icons'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'Toggle Theme',
|
value: 'Toggle Theme',
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(widget.settings.darkTheme
|
leading: Icon(settings.darkTheme ? Icons.light_mode : Icons.dark_mode),
|
||||||
? Icons.light_mode
|
title: Text(settings.darkTheme ? 'Switch to Light Mode' : 'Switch to Dark Mode'),
|
||||||
: Icons.dark_mode),
|
|
||||||
title: Text(widget.settings.darkTheme
|
|
||||||
? 'Switch to Light Mode'
|
|
||||||
: 'Switch to Dark Mode'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'Toggle Sorting',
|
value: 'Toggle Sorting',
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(widget.settings.sortAlphabetically
|
leading: Icon(settings.sortLastUsed ? Icons.access_time : Icons.sort_by_alpha),
|
||||||
? Icons.access_time
|
title: Text(settings.sortLastUsed ? 'Sort Alphabetically' : 'Sort by Last Used'),
|
||||||
: Icons.sort_by_alpha),
|
|
||||||
title: Text(widget.settings.sortAlphabetically
|
|
||||||
? 'Sort Alphabetically'
|
|
||||||
: 'Sort by Last Used'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'Toggle AutoFocus',
|
value: 'Toggle AutoFocus',
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(Icons.center_focus_strong),
|
leading: Icon(Icons.center_focus_strong),
|
||||||
title: Text(widget.settings.autoFocus ? 'Disable Auto Focus' : 'Enable Auto Focus'),
|
title: Text(settings.autoFocus ? 'Disable Auto Focus' : 'Enable Auto Focus'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
|
|
@ -537,7 +412,8 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
title: Text('About'),
|
title: Text('About'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
];
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -565,15 +441,13 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> {
|
||||||
child: Icon(Icons.info, color: Colors.white),
|
child: Icon(Icons.info, color: Colors.white),
|
||||||
),
|
),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading:
|
leading: context.read<AppSettings>().showIcons ? _buildAppIcon(app) : null,
|
||||||
widget.settings.showIcons ? _buildAppIcon(app) : null,
|
|
||||||
title: Text(app.name),
|
title: Text(app.name),
|
||||||
subtitle:
|
subtitle: context.read<AppSettings>().showTags
|
||||||
widget.settings.showTags
|
|
||||||
? RichText(
|
? RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
style: DefaultTextStyle.of(context).style,
|
style: DefaultTextStyle.of(context).style,
|
||||||
children: _formatTags(app.tags.join(' ')), // ✅ Use stored tags
|
children: _formatTags(app.tags.join(' ')),
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
20
lib/preferences.dart
Normal file
20
lib/preferences.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class SharedPreferencesService {
|
||||||
|
static final SharedPreferencesService _instance = SharedPreferencesService._internal();
|
||||||
|
factory SharedPreferencesService() => _instance;
|
||||||
|
SharedPreferencesService._internal();
|
||||||
|
|
||||||
|
Future<void> initialize() async {
|
||||||
|
_prefs = await SharedPreferences.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
late SharedPreferences _prefs;
|
||||||
|
|
||||||
|
bool getBool(String key, bool defaultValue) => _prefs.getBool(key) ?? defaultValue;
|
||||||
|
Future<void> setBool(String key, bool value) => _prefs.setBool(key, value);
|
||||||
|
int? getInt(String key) => _prefs.getInt(key);
|
||||||
|
Future<void> setInt(String key, int value) => _prefs.setInt(key, value);
|
||||||
|
String? getString(String key) => _prefs.getString(key);
|
||||||
|
Future<void> setString(String key, String value) => _prefs.setString(key, value);
|
||||||
|
}
|
||||||
59
lib/settings.dart
Normal file
59
lib/settings.dart
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:plasmoid/preferences.dart';
|
||||||
|
|
||||||
|
class AppSettings extends ChangeNotifier {
|
||||||
|
bool _showTags = true;
|
||||||
|
bool _showIcons = true;
|
||||||
|
bool _colorIcons = true;
|
||||||
|
bool _darkTheme = false;
|
||||||
|
bool _sortLastUsed = true;
|
||||||
|
bool _autoFocus = true;
|
||||||
|
|
||||||
|
bool get showTags => _showTags;
|
||||||
|
bool get showIcons => _showIcons;
|
||||||
|
bool get colorIcons => _colorIcons;
|
||||||
|
bool get darkTheme => _darkTheme;
|
||||||
|
bool get sortLastUsed => _sortLastUsed;
|
||||||
|
bool get autoFocus => _autoFocus;
|
||||||
|
|
||||||
|
final SharedPreferencesService _prefsService = SharedPreferencesService();
|
||||||
|
|
||||||
|
AppSettings() {
|
||||||
|
_loadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadSettings() async {
|
||||||
|
_showTags = _prefsService.getBool('showTags', true);
|
||||||
|
_showIcons = _prefsService.getBool('showIcons', true);
|
||||||
|
_colorIcons = _prefsService.getBool('colorIcons', true);
|
||||||
|
_darkTheme = _prefsService.getBool('darkTheme', false);
|
||||||
|
_sortLastUsed = _prefsService.getBool('sortLastUsed', true);
|
||||||
|
_autoFocus = _prefsService.getBool('autoFocus', true);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateSetting(String key, bool value) async {
|
||||||
|
switch (key) {
|
||||||
|
case 'showTags':
|
||||||
|
_showTags = value;
|
||||||
|
break;
|
||||||
|
case 'showIcons':
|
||||||
|
_showIcons = value;
|
||||||
|
break;
|
||||||
|
case 'colorIcons':
|
||||||
|
_colorIcons = value;
|
||||||
|
break;
|
||||||
|
case 'darkTheme':
|
||||||
|
_darkTheme = value;
|
||||||
|
break;
|
||||||
|
case 'sortLastUsed':
|
||||||
|
_sortLastUsed = value;
|
||||||
|
break;
|
||||||
|
case 'autoFocus':
|
||||||
|
_autoFocus = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await _prefsService.setBool(key, value);
|
||||||
|
notifyListeners(); // Notify listeners after updating the setting
|
||||||
|
}
|
||||||
|
}
|
||||||
16
pubspec.lock
16
pubspec.lock
|
|
@ -328,6 +328,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -424,6 +432,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.1"
|
version: "6.0.1"
|
||||||
|
provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.2"
|
||||||
scrollable_positioned_list:
|
scrollable_positioned_list:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ dependencies:
|
||||||
google_fonts: ^6.2.1
|
google_fonts: ^6.2.1
|
||||||
flutter_launcher_icons: ^0.14.3
|
flutter_launcher_icons: ^0.14.3
|
||||||
flutter_code_editor: ^0.3.2
|
flutter_code_editor: ^0.3.2
|
||||||
|
provider: ^6.1.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue