|
@@ -6,9 +6,9 @@ import '../../core/widgets/app_icon.dart';
|
|
|
import '../../core/widgets/app_icon_image.dart';
|
|
import '../../core/widgets/app_icon_image.dart';
|
|
|
import '../../core/widgets/pressable.dart';
|
|
import '../../core/widgets/pressable.dart';
|
|
|
import '../../core/widgets/surface_card.dart';
|
|
import '../../core/widgets/surface_card.dart';
|
|
|
-import '../../data/models/app_entry.dart';
|
|
|
|
|
import '../../data/models/slot_assignment.dart';
|
|
import '../../data/models/slot_assignment.dart';
|
|
|
import 'launcher_controller.dart';
|
|
import 'launcher_controller.dart';
|
|
|
|
|
+import 'style_icon_choices.dart';
|
|
|
|
|
|
|
|
const _sheetBarrier = Color(0x8A000000);
|
|
const _sheetBarrier = Color(0x8A000000);
|
|
|
|
|
|
|
@@ -19,7 +19,6 @@ Future<void> showPinnedAppMenu(
|
|
|
) async {
|
|
) async {
|
|
|
final launcher = context.read<LauncherController>();
|
|
final launcher = context.read<LauncherController>();
|
|
|
final app = launcher.appForAssignment(assignment);
|
|
final app = launcher.appForAssignment(assignment);
|
|
|
- final iconApp = launcher.appForCustomIcon(assignment) ?? app;
|
|
|
|
|
|
|
|
|
|
await showModalBottomSheet<void>(
|
|
await showModalBottomSheet<void>(
|
|
|
context: context,
|
|
context: context,
|
|
@@ -51,7 +50,24 @@ Future<void> showPinnedAppMenu(
|
|
|
children: [
|
|
children: [
|
|
|
Row(
|
|
Row(
|
|
|
children: [
|
|
children: [
|
|
|
- AppIconImage(bytes: iconApp?.icon, size: 44),
|
|
|
|
|
|
|
+ if (assignment.iconAsset != null)
|
|
|
|
|
+ Container(
|
|
|
|
|
+ width: 44,
|
|
|
|
|
+ height: 44,
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: colors.surfaceStrong,
|
|
|
|
|
+ borderRadius: BorderRadius.circular(15),
|
|
|
|
|
+ border: Border.all(color: colors.border),
|
|
|
|
|
+ ),
|
|
|
|
|
+ alignment: Alignment.center,
|
|
|
|
|
+ child: AppIcon(
|
|
|
|
|
+ assignment.iconAsset!,
|
|
|
|
|
+ size: 22,
|
|
|
|
|
+ color: colors.ink,
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ else
|
|
|
|
|
+ AppIconImage(bytes: app?.icon, size: 44),
|
|
|
const SizedBox(width: 14),
|
|
const SizedBox(width: 14),
|
|
|
Expanded(
|
|
Expanded(
|
|
|
child: Column(
|
|
child: Column(
|
|
@@ -202,47 +218,16 @@ Future<void> showPinnedIconPicker(
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-class _PinnedIconSheet extends StatefulWidget {
|
|
|
|
|
|
|
+class _PinnedIconSheet extends StatelessWidget {
|
|
|
const _PinnedIconSheet({required this.assignment});
|
|
const _PinnedIconSheet({required this.assignment});
|
|
|
|
|
|
|
|
final SlotAssignment assignment;
|
|
final SlotAssignment assignment;
|
|
|
|
|
|
|
|
- @override
|
|
|
|
|
- State<_PinnedIconSheet> createState() => _PinnedIconSheetState();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-class _PinnedIconSheetState extends State<_PinnedIconSheet> {
|
|
|
|
|
- @override
|
|
|
|
|
- void initState() {
|
|
|
|
|
- super.initState();
|
|
|
|
|
- WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
|
|
- if (!mounted) return;
|
|
|
|
|
- final launcher = context.read<LauncherController>();
|
|
|
|
|
- if (!launcher.isLoadingApps) launcher.loadApps(force: true);
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
@override
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
|
final colors = context.colors;
|
|
final colors = context.colors;
|
|
|
final theme = Theme.of(context);
|
|
final theme = Theme.of(context);
|
|
|
- final launcher = context.watch<LauncherController>();
|
|
|
|
|
- final current = launcher.appForAssignment(widget.assignment);
|
|
|
|
|
- final choices = <AppEntry>[];
|
|
|
|
|
- final seen = <String>{};
|
|
|
|
|
-
|
|
|
|
|
- if (current != null) {
|
|
|
|
|
- choices.add(current);
|
|
|
|
|
- seen.add(current.componentId);
|
|
|
|
|
- }
|
|
|
|
|
- for (final app in launcher.apps) {
|
|
|
|
|
- if (choices.length >= 25) break;
|
|
|
|
|
- if (seen.add(app.componentId)) choices.add(app);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- final selectedComponent = widget.assignment.hasCustomIcon
|
|
|
|
|
- ? '${widget.assignment.iconPackageName}/${widget.assignment.iconActivityName}'
|
|
|
|
|
- : '${widget.assignment.packageName}/${widget.assignment.activityName}';
|
|
|
|
|
|
|
+ final selectedAsset = assignment.iconAsset;
|
|
|
|
|
|
|
|
return Container(
|
|
return Container(
|
|
|
height: MediaQuery.sizeOf(context).height * 0.86,
|
|
height: MediaQuery.sizeOf(context).height * 0.86,
|
|
@@ -272,7 +257,7 @@ class _PinnedIconSheetState extends State<_PinnedIconSheet> {
|
|
|
Text('Change icon', style: theme.textTheme.headlineSmall),
|
|
Text('Change icon', style: theme.textTheme.headlineSmall),
|
|
|
const SizedBox(height: 3),
|
|
const SizedBox(height: 3),
|
|
|
Text(
|
|
Text(
|
|
|
- 'Choose an icon for ${widget.assignment.label}.',
|
|
|
|
|
|
|
+ 'Choose a stylized icon for ${assignment.label}.',
|
|
|
maxLines: 1,
|
|
maxLines: 1,
|
|
|
overflow: TextOverflow.ellipsis,
|
|
overflow: TextOverflow.ellipsis,
|
|
|
style: theme.textTheme.bodySmall?.copyWith(
|
|
style: theme.textTheme.bodySmall?.copyWith(
|
|
@@ -307,70 +292,76 @@ class _PinnedIconSheetState extends State<_PinnedIconSheet> {
|
|
|
),
|
|
),
|
|
|
const SizedBox(height: 8),
|
|
const SizedBox(height: 8),
|
|
|
Expanded(
|
|
Expanded(
|
|
|
- child: choices.isEmpty
|
|
|
|
|
- ? Center(
|
|
|
|
|
- child: Text(
|
|
|
|
|
- 'No installed apps to choose from.',
|
|
|
|
|
- style: theme.textTheme.bodyMedium?.copyWith(
|
|
|
|
|
- color: colors.inkMuted,
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- )
|
|
|
|
|
- : GridView.builder(
|
|
|
|
|
- padding: const EdgeInsets.fromLTRB(24, 4, 24, 28),
|
|
|
|
|
- gridDelegate:
|
|
|
|
|
- const SliverGridDelegateWithMaxCrossAxisExtent(
|
|
|
|
|
- maxCrossAxisExtent: 116,
|
|
|
|
|
- mainAxisExtent: 112,
|
|
|
|
|
- crossAxisSpacing: 10,
|
|
|
|
|
- mainAxisSpacing: 10,
|
|
|
|
|
|
|
+ child: GridView.builder(
|
|
|
|
|
+ padding: const EdgeInsets.fromLTRB(24, 4, 24, 28),
|
|
|
|
|
+ gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
|
|
|
|
+ maxCrossAxisExtent: 116,
|
|
|
|
|
+ mainAxisExtent: 108,
|
|
|
|
|
+ crossAxisSpacing: 10,
|
|
|
|
|
+ mainAxisSpacing: 10,
|
|
|
|
|
+ ),
|
|
|
|
|
+ itemCount: styleIconChoices.length + 1,
|
|
|
|
|
+ itemBuilder: (context, index) {
|
|
|
|
|
+ final isDefault = index == 0;
|
|
|
|
|
+ final choice = isDefault ? null : styleIconChoices[index - 1];
|
|
|
|
|
+ final asset = isDefault
|
|
|
|
|
+ ? 'assets/icons/app-window.svg'
|
|
|
|
|
+ : choice!.asset;
|
|
|
|
|
+ final label = isDefault ? 'Default' : choice!.label;
|
|
|
|
|
+ final selected = isDefault
|
|
|
|
|
+ ? !assignment.hasCustomIcon
|
|
|
|
|
+ : selectedAsset == asset;
|
|
|
|
|
+
|
|
|
|
|
+ return Material(
|
|
|
|
|
+ color: Colors.transparent,
|
|
|
|
|
+ child: InkWell(
|
|
|
|
|
+ borderRadius: BorderRadius.circular(24),
|
|
|
|
|
+ onTap: () async {
|
|
|
|
|
+ final launcher = context.read<LauncherController>();
|
|
|
|
|
+ await launcher.setPinnedIcon(
|
|
|
|
|
+ assignment,
|
|
|
|
|
+ isDefault ? null : asset,
|
|
|
|
|
+ );
|
|
|
|
|
+ if (context.mounted) Navigator.of(context).pop();
|
|
|
|
|
+ },
|
|
|
|
|
+ child: Container(
|
|
|
|
|
+ padding: const EdgeInsets.fromLTRB(8, 10, 8, 8),
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: colors.surfaceStrong,
|
|
|
|
|
+ borderRadius: BorderRadius.circular(24),
|
|
|
|
|
+ border: Border.all(
|
|
|
|
|
+ color: selected ? colors.accent : colors.border,
|
|
|
|
|
+ width: selected ? 1.8 : 1,
|
|
|
),
|
|
),
|
|
|
- itemCount: choices.length,
|
|
|
|
|
- itemBuilder: (context, index) {
|
|
|
|
|
- final app = choices[index];
|
|
|
|
|
- final selected = app.componentId == selectedComponent;
|
|
|
|
|
- return Material(
|
|
|
|
|
- color: Colors.transparent,
|
|
|
|
|
- child: InkWell(
|
|
|
|
|
- borderRadius: BorderRadius.circular(24),
|
|
|
|
|
- onTap: () async {
|
|
|
|
|
- await launcher.setPinnedIcon(
|
|
|
|
|
- widget.assignment,
|
|
|
|
|
- app,
|
|
|
|
|
- );
|
|
|
|
|
- if (context.mounted) Navigator.of(context).pop();
|
|
|
|
|
- },
|
|
|
|
|
- child: Container(
|
|
|
|
|
- padding: const EdgeInsets.fromLTRB(8, 10, 8, 8),
|
|
|
|
|
- decoration: BoxDecoration(
|
|
|
|
|
- color: colors.surfaceStrong,
|
|
|
|
|
- borderRadius: BorderRadius.circular(24),
|
|
|
|
|
- border: Border.all(
|
|
|
|
|
- color: selected ? colors.accent : colors.border,
|
|
|
|
|
- width: selected ? 1.8 : 1,
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- child: Column(
|
|
|
|
|
- mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
- children: [
|
|
|
|
|
- AppIconImage(bytes: app.icon, size: 44),
|
|
|
|
|
- const SizedBox(height: 6),
|
|
|
|
|
- Text(
|
|
|
|
|
- app.label,
|
|
|
|
|
- maxLines: 1,
|
|
|
|
|
- overflow: TextOverflow.ellipsis,
|
|
|
|
|
- textAlign: TextAlign.center,
|
|
|
|
|
- style: theme.textTheme.bodySmall?.copyWith(
|
|
|
|
|
- color: colors.ink,
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ ),
|
|
|
|
|
+ child: Column(
|
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
+ children: [
|
|
|
|
|
+ AppIcon(
|
|
|
|
|
+ asset,
|
|
|
|
|
+ size: 30,
|
|
|
|
|
+ color: selected ? colors.accent : colors.ink,
|
|
|
|
|
+ ),
|
|
|
|
|
+ const SizedBox(height: 7),
|
|
|
|
|
+ Text(
|
|
|
|
|
+ label,
|
|
|
|
|
+ maxLines: 1,
|
|
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
|
|
+ textAlign: TextAlign.center,
|
|
|
|
|
+ style: theme.textTheme.bodySmall?.copyWith(
|
|
|
|
|
+ color: selected ? colors.accent : colors.ink,
|
|
|
|
|
+ fontWeight: selected
|
|
|
|
|
+ ? FontWeight.w600
|
|
|
|
|
+ : FontWeight.w400,
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
|
- ),
|
|
|
|
|
- );
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ ],
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
),
|
|
),
|
|
|
|
|
+ );
|
|
|
|
|
+ },
|
|
|
|
|
+ ),
|
|
|
),
|
|
),
|
|
|
],
|
|
],
|
|
|
),
|
|
),
|