favorites, demoting
This commit is contained in:
parent
a88a61cf01
commit
dacfc1d059
1 changed files with 85 additions and 8 deletions
|
|
@ -55,7 +55,9 @@ class AppInfo {
|
||||||
final String name;
|
final String name;
|
||||||
final String packageName;
|
final String packageName;
|
||||||
final List<String> tags;
|
final List<String> tags;
|
||||||
DateTime? lastUsed; // New field to track last used time
|
DateTime? lastUsed;
|
||||||
|
bool isPinned;
|
||||||
|
bool isDemoted;
|
||||||
|
|
||||||
AppInfo({
|
AppInfo({
|
||||||
this.icon,
|
this.icon,
|
||||||
|
|
@ -63,6 +65,8 @@ class AppInfo {
|
||||||
required this.packageName,
|
required this.packageName,
|
||||||
required this.tags,
|
required this.tags,
|
||||||
this.lastUsed,
|
this.lastUsed,
|
||||||
|
this.isPinned = false,
|
||||||
|
this.isDemoted = false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,6 +118,9 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> with WidgetsBindi
|
||||||
List<AppInfo> loadedApps = installedApps.map((app) {
|
List<AppInfo> loadedApps = installedApps.map((app) {
|
||||||
final lastUsedMillis = SharedPreferencesService().getInt("lastUsed_${app.packageName}");
|
final lastUsedMillis = SharedPreferencesService().getInt("lastUsed_${app.packageName}");
|
||||||
final storedTags = SharedPreferencesService().getString("tags_${app.packageName}");
|
final storedTags = SharedPreferencesService().getString("tags_${app.packageName}");
|
||||||
|
final isPinned = SharedPreferencesService().getBool("isPinned_${app.packageName}", false);
|
||||||
|
final isDemoted = SharedPreferencesService().getBool("isDemoted_${app.packageName}", false);
|
||||||
|
|
||||||
List<String> tags = [];
|
List<String> tags = [];
|
||||||
|
|
||||||
if (storedTags != null && storedTags.trim().isNotEmpty) {
|
if (storedTags != null && storedTags.trim().isNotEmpty) {
|
||||||
|
|
@ -131,6 +138,8 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> with WidgetsBindi
|
||||||
packageName: app.packageName,
|
packageName: app.packageName,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
lastUsed: lastUsedMillis != null ? DateTime.fromMillisecondsSinceEpoch(lastUsedMillis) : null,
|
lastUsed: lastUsedMillis != null ? DateTime.fromMillisecondsSinceEpoch(lastUsedMillis) : null,
|
||||||
|
isPinned: isPinned,
|
||||||
|
isDemoted: isDemoted,
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
|
@ -151,16 +160,22 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> with WidgetsBindi
|
||||||
return matchesName || matchesTag;
|
return matchesName || matchesTag;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
if (context.read<AppSettings>().sortLastUsed) {
|
// Sort pinned apps first, then by last used or alphabetically, then demoted apps
|
||||||
filteredApps.sort((a, b) {
|
filteredApps.sort((a, b) {
|
||||||
|
if (a.isPinned && !b.isPinned) return -1;
|
||||||
|
if (!a.isPinned && b.isPinned) return 1;
|
||||||
|
if (a.isDemoted && !b.isDemoted) return 1;
|
||||||
|
if (!a.isDemoted && b.isDemoted) return -1;
|
||||||
|
|
||||||
|
if (context.read<AppSettings>().sortLastUsed) {
|
||||||
DateTime aTime = a.lastUsed ?? DateTime.fromMillisecondsSinceEpoch(0);
|
DateTime aTime = a.lastUsed ?? DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
DateTime bTime = b.lastUsed ?? DateTime.fromMillisecondsSinceEpoch(0);
|
DateTime bTime = b.lastUsed ?? DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
return bTime.compareTo(aTime);
|
return bTime.compareTo(aTime);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
filteredApps.sort((a, b) => a.name.compareTo(b.name));
|
return a.name.compareTo(b.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _launchApp(AppInfo app) async {
|
Future<void> _launchApp(AppInfo app) async {
|
||||||
|
|
@ -197,6 +212,57 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> with WidgetsBindi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showContextMenu(BuildContext context, AppInfo app) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(app.isPinned ? Icons.push_pin : Icons.push_pin_outlined),
|
||||||
|
title: Text(app.isPinned ? 'Unpin' : 'Pin'),
|
||||||
|
onTap: () async {
|
||||||
|
Navigator.pop(context); // Close the menu
|
||||||
|
await _togglePin(app);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(app.isDemoted ? Icons.arrow_upward : Icons.arrow_downward),
|
||||||
|
title: Text(app.isDemoted ? 'Reset' : 'Demote'),
|
||||||
|
onTap: () async {
|
||||||
|
Navigator.pop(context); // Close the menu
|
||||||
|
await _toggleDemote(app);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _togglePin(AppInfo app) async {
|
||||||
|
setState(() {
|
||||||
|
app.isPinned = !app.isPinned;
|
||||||
|
if (app.isPinned) {
|
||||||
|
app.isDemoted = false; // Cannot be pinned and demoted at the same time
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await SharedPreferencesService().setBool("isPinned_${app.packageName}", app.isPinned);
|
||||||
|
_filterApps();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _toggleDemote(AppInfo app) async {
|
||||||
|
setState(() {
|
||||||
|
app.isDemoted = !app.isDemoted;
|
||||||
|
if (app.isDemoted) {
|
||||||
|
app.isPinned = false; // Cannot be pinned and demoted at the same time
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await SharedPreferencesService().setBool("isDemoted_${app.packageName}", app.isDemoted);
|
||||||
|
_filterApps();
|
||||||
|
}
|
||||||
|
|
||||||
void _editAppTags(AppInfo app) {
|
void _editAppTags(AppInfo app) {
|
||||||
TextEditingController tagController = TextEditingController(text: app.tags.join(" "));
|
TextEditingController tagController = TextEditingController(text: app.tags.join(" "));
|
||||||
showDialog(
|
showDialog(
|
||||||
|
|
@ -303,6 +369,15 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> with WidgetsBindi
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildTrailingIcon(AppInfo app) {
|
||||||
|
if (app.isPinned) {
|
||||||
|
return Icon(Icons.push_pin, color: Colors.grey); // Pin icon for pinned apps
|
||||||
|
} else if (app.isDemoted) {
|
||||||
|
return Icon(Icons.disabled_by_default_outlined, color: Colors.grey); // Demote icon for demoted apps
|
||||||
|
}
|
||||||
|
return SizedBox.shrink(); // No icon for normal apps
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
@ -452,11 +527,13 @@ class _AppLauncherScreenState extends State<AppLauncherScreen> with WidgetsBindi
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
trailing: _buildTrailingIcon(app), // Add trailing icon
|
||||||
onTap: () => _launchApp(app),
|
onTap: () => _launchApp(app),
|
||||||
|
onLongPress: () => _showContextMenu(context, app),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue