Routines: workout, meditation and must-do routines with timed, rep and tick steps, sets and rest. A library screen, a builder with templates and drag-to-reorder steps, and a full-screen player that auto-advances timed phases, counts backgrounding and logs broken chains as partial. Goals: a goal editor (deadline, colour, category, default class, archive), routines linked to goals, and a goal field on tasks and routines. Tasks added from inside a goal are now actually attached to it via parentId. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KhQh614DMeYoQEH9SoMRUw
128 lines
4.0 KiB
Dart
128 lines
4.0 KiB
Dart
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../about/external/data/Goal.dart';
|
|
import '../about/internal/application/TextType.dart';
|
|
import '../utils/Colors.dart';
|
|
import '../utils/CommonUtils.dart';
|
|
import 'text/Text.dart';
|
|
|
|
/// The goal chooser, shared by the task form and the routine builder. Opened
|
|
/// only once the goals have been loaded — `selectField` loads on tap.
|
|
///
|
|
/// Resolves to the chosen goal, to a bare `Goal()` (no id) for "no goal", or
|
|
/// to null when dismissed without a choice.
|
|
Future<Goal?> showGoalPicker(
|
|
BuildContext context,
|
|
List<Goal> goals, {
|
|
String? selectedId,
|
|
}) {
|
|
return showModalBottomSheet<Goal>(
|
|
context: context,
|
|
isScrollControlled: true,
|
|
backgroundColor: Colors.transparent,
|
|
barrierColor: colorBlack.withValues(alpha: 0.55),
|
|
builder: (BuildContext sheetContext) {
|
|
final List<Goal> active = goals.where((goal) => !goal.archived).toList();
|
|
|
|
return Container(
|
|
constraints: BoxConstraints(
|
|
maxHeight: MediaQuery.of(sheetContext).size.height * 0.75,
|
|
),
|
|
decoration: const BoxDecoration(
|
|
color: colorSheetBackground,
|
|
borderRadius: BorderRadius.only(
|
|
topLeft: Radius.circular(28),
|
|
topRight: Radius.circular(28),
|
|
),
|
|
),
|
|
child: ListView(
|
|
shrinkWrap: true,
|
|
padding: const EdgeInsets.fromLTRB(24, 24, 24, 32),
|
|
children: [
|
|
text("BELONGS TO", 9, TextType.Bold,
|
|
color: colorGrey2, letterSpacing: 1.2),
|
|
const SizedBox(height: 8),
|
|
text("Which goal is this for?", 24, TextType.Light,
|
|
color: colorPrimaryDark),
|
|
const SizedBox(height: 18),
|
|
_goalOption(
|
|
sheetContext,
|
|
Goal(),
|
|
"No goal",
|
|
"Stands on its own",
|
|
colorGrey,
|
|
selectedId == null,
|
|
),
|
|
...active.map((goal) => _goalOption(
|
|
sheetContext,
|
|
goal,
|
|
goal.title,
|
|
goal.targetDate == null
|
|
? "${goal.remainingTasks} open"
|
|
: "${goal.remainingTasks} open · ${targetLabel(goal.targetDate)}",
|
|
goalColor(goal.colourHex),
|
|
goal.id == selectedId,
|
|
)),
|
|
if (active.isEmpty) ...[
|
|
const SizedBox(height: 8),
|
|
text("No goals yet. Create one from the Goals screen.", 12,
|
|
TextType.Regular,
|
|
color: colorGrey2),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _goalOption(
|
|
BuildContext sheetContext,
|
|
Goal goal,
|
|
String title,
|
|
String caption,
|
|
Color accent,
|
|
bool selected,
|
|
) {
|
|
return GestureDetector(
|
|
onTap: () => Navigator.pop(sheetContext, goal),
|
|
behavior: HitTestBehavior.opaque,
|
|
child: Container(
|
|
margin: const EdgeInsets.only(bottom: 8),
|
|
padding: const EdgeInsets.fromLTRB(14, 13, 14, 13),
|
|
decoration: BoxDecoration(
|
|
color: colorWhite,
|
|
borderRadius: BorderRadius.circular(14),
|
|
border: Border.all(
|
|
color: selected ? accent.withValues(alpha: 0.5) : colorBorder,
|
|
width: selected ? 1.5 : 1,
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Container(
|
|
width: 12,
|
|
height: 12,
|
|
decoration: BoxDecoration(color: accent, shape: BoxShape.circle),
|
|
),
|
|
const SizedBox(width: 14),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
text(title, 14, TextType.Medium, color: colorPrimaryDark),
|
|
const SizedBox(height: 3),
|
|
text(caption, 11, TextType.Regular, color: colorGrey2),
|
|
],
|
|
),
|
|
),
|
|
if (selected)
|
|
Icon(CupertinoIcons.checkmark_alt, size: 17, color: accent),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|