This commit is contained in:
randogoth 2025-02-24 21:46:40 +02:00
parent c065a013fc
commit a88a61cf01
5 changed files with 232 additions and 262 deletions

View file

@ -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
View 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
View 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
}
}

View file

@ -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:

View file

@ -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: