picker-first startup with per-project sticky override (T-115)
Boot used to auto-open app.lastProject and fall back to the CWD; new default is the welcome screen as the project picker. Sticky-open is opt-in: a checkbox on each recent-projects row toggles a startupSticky flag, and clide auto-opens iff exactly one row has it. Two-or-more, or none, ⇒ picker (unambiguous user intent). RecentProject gains the boolean (persisted in app.recentProjects); ProjectManager exposes stickyProjectPath, openStickyOrNothing, setStickyStartup, isStickyStartup, and preserves the flag across reopens. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -264,7 +264,13 @@ class _RecentColumn extends StatelessWidget {
|
||||
if (recents.isEmpty)
|
||||
const ClideText('No recent projects.', muted: true, fontSize: 14)
|
||||
else
|
||||
for (final r in recents) _RecentRow(project: r, tokens: tokens, onTap: () => _openRecent(r.path)),
|
||||
for (final r in recents)
|
||||
_RecentRow(
|
||||
project: r,
|
||||
tokens: tokens,
|
||||
onTap: () => _openRecent(r.path),
|
||||
onToggleSticky: () => kernel.project.setStickyStartup(r.path, !r.startupSticky),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -279,10 +285,16 @@ class _RecentColumn extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _RecentRow extends StatelessWidget {
|
||||
const _RecentRow({required this.project, required this.tokens, required this.onTap});
|
||||
const _RecentRow({
|
||||
required this.project,
|
||||
required this.tokens,
|
||||
required this.onTap,
|
||||
required this.onToggleSticky,
|
||||
});
|
||||
final RecentProject project;
|
||||
final SurfaceTokens tokens;
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback onToggleSticky;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -318,6 +330,8 @@ class _RecentRow extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
_StickyToggle(sticky: project.startupSticky, tokens: tokens, onTap: onToggleSticky),
|
||||
const SizedBox(width: 12),
|
||||
ClideText(project.timeAgo, muted: true, fontSize: 13),
|
||||
],
|
||||
),
|
||||
@@ -326,6 +340,41 @@ class _RecentRow extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sticky-startup checkbox shown on each recent-project row (T-115).
|
||||
/// When exactly one row is checked, clide opens that project on next
|
||||
/// launch instead of showing the picker. Tooltip explains the rule.
|
||||
class _StickyToggle extends StatelessWidget {
|
||||
const _StickyToggle({required this.sticky, required this.tokens, required this.onTap});
|
||||
final bool sticky;
|
||||
final SurfaceTokens tokens;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClideTooltip(
|
||||
message: sticky ? 'Always open this project on launch (uncheck to restore picker)' : 'Always open this project on launch',
|
||||
child: Semantics(
|
||||
button: true,
|
||||
checked: sticky,
|
||||
label: 'always open this project on launch',
|
||||
child: ClideTappable(
|
||||
onTap: onTap,
|
||||
builder: (context, hovered, _) => Container(
|
||||
width: 18,
|
||||
height: 18,
|
||||
decoration: BoxDecoration(
|
||||
color: sticky ? tokens.statusBarItemActiveBackground : null,
|
||||
border: Border.all(color: hovered || sticky ? tokens.panelActiveBorder : tokens.globalBorder),
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
child: sticky ? ClideIcon(PhosphorIcons.check, size: 12, color: tokens.buttonForeground) : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _StatusLine extends StatelessWidget {
|
||||
const _StatusLine({required this.tokens, required this.kernel});
|
||||
final SurfaceTokens tokens;
|
||||
|
||||
Reference in New Issue
Block a user