From 78fd23f69f62070cf81edda27c845d5b3b7c1a37 Mon Sep 17 00:00:00 2001 From: davmar Date: Fri, 18 Sep 2026 00:01:42 +0200 Subject: [PATCH] full app done --- README.md | 89 +-- assets/data/values_deck.json | 500 ++++++++++++++++ assets/images/emblem.png | Bin 0 -> 34010 bytes lib/data/values_deck.dart | 17 + lib/main.dart | 27 +- lib/models/item.dart | 130 ----- lib/models/value_card.dart | 33 ++ lib/models/value_pile.dart | 68 +++ lib/providers/item_provider.dart | 93 --- lib/providers/theme_provider.dart | 37 +- lib/providers/values_sort_provider.dart | 455 +++++++++++++++ lib/screens/add_item_screen.dart | 142 ----- lib/screens/card_sorting_screen.dart | 190 +++++++ lib/screens/home_screen.dart | 212 ------- lib/screens/item_detail_screen.dart | 82 --- lib/screens/main_shell.dart | 64 --- lib/screens/pile_review_screen.dart | 129 +++++ lib/screens/practice_flow_screen.dart | 66 +++ lib/screens/practice_hub_screen.dart | 447 +++++++++++++++ lib/screens/profile_screen.dart | 142 ----- lib/screens/rank_order_screen.dart | 191 +++++++ lib/screens/reflection_screen.dart | 298 ++++++++++ lib/screens/search_screen.dart | 104 ---- lib/screens/settings_screen.dart | 104 ---- lib/screens/sorted_overview_screen.dart | 289 ++++++++++ lib/screens/splash_screen.dart | 70 ++- lib/screens/welcome_screen.dart | 360 ++++++++++++ lib/services/fake_item_data.dart | 97 ---- lib/services/item_api.dart | 61 -- lib/services/item_repository.dart | 50 -- lib/services/storage_service.dart | 13 +- lib/utils/app_theme.dart | 397 +++++++++---- lib/utils/constants.dart | 22 +- lib/utils/helpers.dart | 59 -- lib/widgets/app_text_field.dart | 44 -- lib/widgets/empty_state.dart | 51 -- lib/widgets/item_card.dart | 127 ----- lib/widgets/item_hero_badge.dart | 54 -- lib/widgets/loading_view.dart | 24 - lib/widgets/practice_chrome.dart | 168 ++++++ lib/widgets/responsive_body.dart | 34 -- lib/widgets/theme_toggle_button.dart | 35 ++ lib/widgets/value_card_tile.dart | 100 ++++ pubspec.lock | 138 ++++- pubspec.yaml | 15 +- stitch/DESIGN.md | 214 +++++++ stitch/design-theme.json | 154 +++++ stitch/manifest.json | 110 ++++ stitch/project.json | 303 ++++++++++ stitch/screens/card-sorting.html | 391 +++++++++++++ stitch/screens/card-sorting.json | 16 + stitch/screens/card-sorting.png | Bin 0 -> 75318 bytes stitch/screens/important-cards.html | 467 +++++++++++++++ stitch/screens/important-cards.json | 16 + stitch/screens/important-cards.png | Bin 0 -> 47590 bytes stitch/screens/most-important.html | 722 ++++++++++++++++++++++++ stitch/screens/most-important.json | 16 + stitch/screens/most-important.png | Bin 0 -> 24782 bytes stitch/screens/practice-hub.html | 191 +++++++ stitch/screens/practice-hub.json | 16 + stitch/screens/practice-hub.png | Bin 0 -> 5851 bytes stitch/screens/rank-order.html | 547 ++++++++++++++++++ stitch/screens/rank-order.json | 16 + stitch/screens/rank-order.png | Bin 0 -> 2676 bytes stitch/screens/reflect-top-values.html | 299 ++++++++++ stitch/screens/reflect-top-values.json | 16 + stitch/screens/reflect-top-values.png | Bin 0 -> 4038 bytes stitch/screens/reflection-journal.html | 391 +++++++++++++ stitch/screens/reflection-journal.json | 16 + stitch/screens/reflection-journal.png | Bin 0 -> 4968 bytes stitch/screens/welcome.html | 223 ++++++++ stitch/screens/welcome.json | 16 + stitch/screens/welcome.png | Bin 0 -> 35118 bytes test/widget_test.dart | 99 ++-- 74 files changed, 8104 insertions(+), 1963 deletions(-) create mode 100644 assets/data/values_deck.json create mode 100644 assets/images/emblem.png create mode 100644 lib/data/values_deck.dart delete mode 100644 lib/models/item.dart create mode 100644 lib/models/value_card.dart create mode 100644 lib/models/value_pile.dart delete mode 100644 lib/providers/item_provider.dart create mode 100644 lib/providers/values_sort_provider.dart delete mode 100644 lib/screens/add_item_screen.dart create mode 100644 lib/screens/card_sorting_screen.dart delete mode 100644 lib/screens/home_screen.dart delete mode 100644 lib/screens/item_detail_screen.dart delete mode 100644 lib/screens/main_shell.dart create mode 100644 lib/screens/pile_review_screen.dart create mode 100644 lib/screens/practice_flow_screen.dart create mode 100644 lib/screens/practice_hub_screen.dart delete mode 100644 lib/screens/profile_screen.dart create mode 100644 lib/screens/rank_order_screen.dart create mode 100644 lib/screens/reflection_screen.dart delete mode 100644 lib/screens/search_screen.dart delete mode 100644 lib/screens/settings_screen.dart create mode 100644 lib/screens/sorted_overview_screen.dart create mode 100644 lib/screens/welcome_screen.dart delete mode 100644 lib/services/fake_item_data.dart delete mode 100644 lib/services/item_api.dart delete mode 100644 lib/services/item_repository.dart delete mode 100644 lib/utils/helpers.dart delete mode 100644 lib/widgets/app_text_field.dart delete mode 100644 lib/widgets/empty_state.dart delete mode 100644 lib/widgets/item_card.dart delete mode 100644 lib/widgets/item_hero_badge.dart delete mode 100644 lib/widgets/loading_view.dart create mode 100644 lib/widgets/practice_chrome.dart delete mode 100644 lib/widgets/responsive_body.dart create mode 100644 lib/widgets/theme_toggle_button.dart create mode 100644 lib/widgets/value_card_tile.dart create mode 100644 stitch/DESIGN.md create mode 100644 stitch/design-theme.json create mode 100644 stitch/manifest.json create mode 100644 stitch/project.json create mode 100644 stitch/screens/card-sorting.html create mode 100644 stitch/screens/card-sorting.json create mode 100644 stitch/screens/card-sorting.png create mode 100644 stitch/screens/important-cards.html create mode 100644 stitch/screens/important-cards.json create mode 100644 stitch/screens/important-cards.png create mode 100644 stitch/screens/most-important.html create mode 100644 stitch/screens/most-important.json create mode 100644 stitch/screens/most-important.png create mode 100644 stitch/screens/practice-hub.html create mode 100644 stitch/screens/practice-hub.json create mode 100644 stitch/screens/practice-hub.png create mode 100644 stitch/screens/rank-order.html create mode 100644 stitch/screens/rank-order.json create mode 100644 stitch/screens/rank-order.png create mode 100644 stitch/screens/reflect-top-values.html create mode 100644 stitch/screens/reflect-top-values.json create mode 100644 stitch/screens/reflect-top-values.png create mode 100644 stitch/screens/reflection-journal.html create mode 100644 stitch/screens/reflection-journal.json create mode 100644 stitch/screens/reflection-journal.png create mode 100644 stitch/screens/welcome.html create mode 100644 stitch/screens/welcome.json create mode 100644 stitch/screens/welcome.png diff --git a/README.md b/README.md index 8055eea..d747db3 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,41 @@ -# MyApp +# Values Sort -Generic Flutter Android starter built with Flutter **3.47** (Dart **3.13**), Material 3, null safety, and [Provider](https://pub.dev/packages/provider) for state management. +Flutter Android app for a guided personal-values card-sort practice. +Built with Flutter **3.47** (Dart **3.13**), Material 3, Provider, and local persistence. Package name: `com.example.myapp` -## Features +## Practice flow -- Splash screen that fades into the main shell -- Bottom navigation: Home, Search, Profile, Settings -- `ListView.builder` catalog with rounded, shadowed cards -- Detail screen with a matching `Hero` animation -- Light / dark / system theme, persisted with `shared_preferences` -- Add-item form with validation -- Mock catalog plus an `http` client aimed at JSONPlaceholder (toggle in Settings) +1. Welcome (+ how-it-works guide) +2. Sort each value into five reflective piles +3. Review / refine piles +4. Rank your most important values +5. Reflect with journal prompts + +Progress (stage, piles, ranking, reflections) is saved on device with `shared_preferences`. ## Folder structure ``` -android-flutter-app-generic/ -├── android/ # Android embedding, Gradle, manifest -├── lib/ -│ ├── main.dart # Entry point, Provider scope, MaterialApp -│ ├── models/ -│ │ └── item.dart # Item + ItemCategory -│ ├── providers/ -│ │ ├── item_provider.dart # Catalog ChangeNotifier -│ │ └── theme_provider.dart # ThemeMode ChangeNotifier -│ ├── screens/ -│ │ ├── splash_screen.dart -│ │ ├── main_shell.dart # NavigationBar host -│ │ ├── home_screen.dart -│ │ ├── search_screen.dart -│ │ ├── profile_screen.dart -│ │ ├── settings_screen.dart -│ │ ├── item_detail_screen.dart -│ │ └── add_item_screen.dart -│ ├── services/ -│ │ ├── storage_service.dart # shared_preferences wrapper -│ │ ├── item_api.dart # http placeholder -│ │ ├── fake_item_data.dart # Offline sample catalog -│ │ └── item_repository.dart # Mock vs remote switch -│ ├── utils/ -│ │ ├── app_theme.dart # Material 3 light/dark themes -│ │ ├── constants.dart -│ │ └── helpers.dart -│ └── widgets/ -│ ├── app_text_field.dart -│ ├── empty_state.dart -│ ├── item_card.dart -│ ├── item_hero_badge.dart -│ ├── loading_view.dart -│ └── responsive_body.dart -├── test/ -│ └── widget_test.dart -└── pubspec.yaml +lib/ +├── main.dart +├── data/values_deck.dart +├── models/ +├── providers/ +├── screens/ # welcome → sort → overview → rank → reflect +├── services/storage_service.dart +├── utils/ +└── widgets/ +assets/ +├── data/values_deck.json +└── images/emblem.png +stitch/ # exported Stitch HTML/PNG design references ``` -## Run the app - -You need the [Flutter SDK](https://docs.flutter.dev/get-started/install) (3.47 or newer) and an Android emulator or device. +## Run ```bash -cd android-flutter-app-generic flutter pub get flutter run ``` @@ -69,15 +43,6 @@ flutter run Useful extras: ```bash -flutter devices # list emulators / devices -flutter run -d android # target Android explicitly -flutter analyze # static analysis -flutter test # widget + unit tests +flutter analyze +flutter test ``` - -On first Android run, Flutter will download a Gradle distribution and compile the app. Accept any Android licenses with `flutter doctor --android-licenses` if prompted. - -## Theme and data - -- Open **Settings** to switch System / Light / Dark. The choice is stored locally. -- Turn on **Use remote sample API** to fetch posts from `https://jsonplaceholder.typicode.com/posts` through the `http` package. If the request fails, the app falls back to the bundled mock list. diff --git a/assets/data/values_deck.json b/assets/data/values_deck.json new file mode 100644 index 0000000..8d6d468 --- /dev/null +++ b/assets/data/values_deck.json @@ -0,0 +1,500 @@ +[ + { + "id": "v001", + "title": "Acceptance", + "description": "To be accepted as I am", + "domain": "Values" + }, + { + "id": "v002", + "title": "Accuracy", + "description": "To be accurate in my opinions and beliefs", + "domain": "Values" + }, + { + "id": "v003", + "title": "Achievement", + "description": "To have important accomplishments", + "domain": "Values" + }, + { + "id": "v004", + "title": "Adventure", + "description": "To have new and exciting experiences", + "domain": "Values" + }, + { + "id": "v005", + "title": "Attractiveness", + "description": "To be physically attractive", + "domain": "Values" + }, + { + "id": "v006", + "title": "Authority", + "description": "To be in charge of and responsible for others", + "domain": "Values" + }, + { + "id": "v007", + "title": "Autonomy", + "description": "To be self-determined and independent", + "domain": "Values" + }, + { + "id": "v008", + "title": "Beauty", + "description": "To appreciate beauty around me", + "domain": "Values" + }, + { + "id": "v009", + "title": "Caring", + "description": "To take care of others", + "domain": "Values" + }, + { + "id": "v010", + "title": "Challenge", + "description": "To take on difficult tasks and problems", + "domain": "Values" + }, + { + "id": "v011", + "title": "Comfort", + "description": "To have a pleasant and comfortable life", + "domain": "Values" + }, + { + "id": "v012", + "title": "Change", + "description": "To have a life full of change and variety", + "domain": "Values" + }, + { + "id": "v013", + "title": "Commitment", + "description": "To make enduring, meaningful commitments", + "domain": "Values" + }, + { + "id": "v014", + "title": "Compassion", + "description": "To feel and act on concern for others", + "domain": "Values" + }, + { + "id": "v015", + "title": "Contribution", + "description": "To make a lasting contribution in the world", + "domain": "Values" + }, + { + "id": "v016", + "title": "Cooperation", + "description": "To work collaboratively with others", + "domain": "Values" + }, + { + "id": "v017", + "title": "Courtesy", + "description": "To be considerate and polite toward others", + "domain": "Values" + }, + { + "id": "v018", + "title": "Creativity", + "description": "To have new and original ideas", + "domain": "Values" + }, + { + "id": "v019", + "title": "Dependability", + "description": "To be reliable and trustworthy", + "domain": "Values" + }, + { + "id": "v020", + "title": "Duty", + "description": "To carry out my duties and obligations", + "domain": "Values" + }, + { + "id": "v021", + "title": "Ecology", + "description": "To live in harmony with the environment", + "domain": "Values" + }, + { + "id": "v022", + "title": "Excitement", + "description": "To have a life full of thrills and stimulation", + "domain": "Values" + }, + { + "id": "v023", + "title": "Faithfulness", + "description": "To be loyal and true in relationships", + "domain": "Values" + }, + { + "id": "v024", + "title": "Fame", + "description": "To be known and recognized", + "domain": "Values" + }, + { + "id": "v025", + "title": "Family", + "description": "To have a happy, loving family", + "domain": "Values" + }, + { + "id": "v026", + "title": "Fitness", + "description": "To be physically fit and strong", + "domain": "Values" + }, + { + "id": "v027", + "title": "Flexibility", + "description": "To adjust to new circumstances easily", + "domain": "Values" + }, + { + "id": "v028", + "title": "Forgiveness", + "description": "To be forgiving of others", + "domain": "Values" + }, + { + "id": "v029", + "title": "Friendship", + "description": "To have close, supportive friends", + "domain": "Values" + }, + { + "id": "v030", + "title": "Fun", + "description": "To play and have fun", + "domain": "Values" + }, + { + "id": "v031", + "title": "Generosity", + "description": "To give what I have to others", + "domain": "Values" + }, + { + "id": "v032", + "title": "Genuineness", + "description": "To act in a manner that is true to who I am", + "domain": "Values" + }, + { + "id": "v033", + "title": "God's Will", + "description": "To seek and obey the will of God", + "domain": "Values" + }, + { + "id": "v034", + "title": "Growth", + "description": "To keep changing and growing", + "domain": "Values" + }, + { + "id": "v035", + "title": "Health", + "description": "To be physically well and healthy", + "domain": "Values" + }, + { + "id": "v036", + "title": "Helpfulness", + "description": "To be helpful to others", + "domain": "Values" + }, + { + "id": "v037", + "title": "Honesty", + "description": "To be honest and truthful", + "domain": "Values" + }, + { + "id": "v038", + "title": "Hope", + "description": "To maintain a positive and optimistic outlook", + "domain": "Values" + }, + { + "id": "v039", + "title": "Humility", + "description": "To be modest and unassuming", + "domain": "Values" + }, + { + "id": "v040", + "title": "Humor", + "description": "To see the humorous side of myself and the world", + "domain": "Values" + }, + { + "id": "v041", + "title": "Independence", + "description": "To be free from dependence on others", + "domain": "Values" + }, + { + "id": "v042", + "title": "Industry", + "description": "To work hard and well at my life tasks", + "domain": "Values" + }, + { + "id": "v043", + "title": "Inner Peace", + "description": "To experience personal peace", + "domain": "Values" + }, + { + "id": "v044", + "title": "Intimacy", + "description": "To share my innermost experiences with others", + "domain": "Values" + }, + { + "id": "v045", + "title": "Justice", + "description": "To promote fair and equal treatment for all", + "domain": "Values" + }, + { + "id": "v046", + "title": "Knowledge", + "description": "To learn and contribute valuable knowledge", + "domain": "Values" + }, + { + "id": "v047", + "title": "Leisure", + "description": "To take time to relax and enjoy", + "domain": "Values" + }, + { + "id": "v048", + "title": "Loved", + "description": "To be loved by those close to me", + "domain": "Values" + }, + { + "id": "v049", + "title": "Loving", + "description": "To give love to others", + "domain": "Values" + }, + { + "id": "v050", + "title": "Mastery", + "description": "To be competent in my everyday activities", + "domain": "Values" + }, + { + "id": "v051", + "title": "Mindfulness", + "description": "To live conscious and mindful of the present moment", + "domain": "Values" + }, + { + "id": "v052", + "title": "Moderation", + "description": "To avoid excesses and find a middle ground", + "domain": "Values" + }, + { + "id": "v053", + "title": "Monogamy", + "description": "To have one close, loving relationship", + "domain": "Values" + }, + { + "id": "v054", + "title": "Non-Conformity", + "description": "To question or challenge authority and norms", + "domain": "Values" + }, + { + "id": "v055", + "title": "Nurturance", + "description": "To take care of and nurture others", + "domain": "Values" + }, + { + "id": "v056", + "title": "Openness", + "description": "To be open to new experiences, ideas, and options", + "domain": "Values" + }, + { + "id": "v057", + "title": "Order", + "description": "To have a life that is well-ordered and organized", + "domain": "Values" + }, + { + "id": "v058", + "title": "Passion", + "description": "To have deep feelings about ideas, activities, or people", + "domain": "Values" + }, + { + "id": "v059", + "title": "Pleasure", + "description": "To feel good", + "domain": "Values" + }, + { + "id": "v060", + "title": "Popularity", + "description": "To be well-liked by many people", + "domain": "Values" + }, + { + "id": "v061", + "title": "Power", + "description": "To have control over others", + "domain": "Values" + }, + { + "id": "v062", + "title": "Purpose", + "description": "To have meaning and direction in my life", + "domain": "Values" + }, + { + "id": "v063", + "title": "Rationality", + "description": "To be guided by reason and logic", + "domain": "Values" + }, + { + "id": "v064", + "title": "Realism", + "description": "To see and act realistically and practically", + "domain": "Values" + }, + { + "id": "v065", + "title": "Responsibility", + "description": "To make and carry out responsible decisions", + "domain": "Values" + }, + { + "id": "v066", + "title": "Risk", + "description": "To take risks and chances", + "domain": "Values" + }, + { + "id": "v067", + "title": "Romance", + "description": "To have intense, exciting love in my life", + "domain": "Values" + }, + { + "id": "v068", + "title": "Safety", + "description": "To be safe and secure", + "domain": "Values" + }, + { + "id": "v069", + "title": "Self-Acceptance", + "description": "To accept myself as I am", + "domain": "Values" + }, + { + "id": "v070", + "title": "Self-Control", + "description": "To be disciplined in my own actions", + "domain": "Values" + }, + { + "id": "v071", + "title": "Self-Esteem", + "description": "To feel good about myself", + "domain": "Values" + }, + { + "id": "v072", + "title": "Self-Knowledge", + "description": "To have a deep and honest understanding of myself", + "domain": "Values" + }, + { + "id": "v073", + "title": "Service", + "description": "To be of service to others", + "domain": "Values" + }, + { + "id": "v074", + "title": "Sexuality", + "description": "To have an active and satisfying sex life", + "domain": "Values" + }, + { + "id": "v075", + "title": "Simplicity", + "description": "To live life simply, with minimal needs", + "domain": "Values" + }, + { + "id": "v076", + "title": "Solitude", + "description": "To have time and space where I can be apart from others", + "domain": "Values" + }, + { + "id": "v077", + "title": "Spirituality", + "description": "To grow and mature spiritually", + "domain": "Values" + }, + { + "id": "v078", + "title": "Stability", + "description": "To have a life that stays fairly consistent", + "domain": "Values" + }, + { + "id": "v079", + "title": "Tolerance", + "description": "To accept and respect those who differ from me", + "domain": "Values" + }, + { + "id": "v080", + "title": "Tradition", + "description": "To follow respected patterns of the past", + "domain": "Values" + }, + { + "id": "v081", + "title": "Virtue", + "description": "To live a morally pure and excellent life", + "domain": "Values" + }, + { + "id": "v082", + "title": "Wealth", + "description": "To have plenty of money", + "domain": "Values" + }, + { + "id": "v083", + "title": "World Peace", + "description": "To work to promote peace in the world", + "domain": "Values" + } +] diff --git a/assets/images/emblem.png b/assets/images/emblem.png new file mode 100644 index 0000000000000000000000000000000000000000..c13f513357fe80439bbeb7c1c4cd9b1081e5b375 GIT binary patch literal 34010 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 loadValuesDeck() async { + final raw = await rootBundle.loadString('assets/data/values_deck.json'); + final list = jsonDecode(raw) as List; + return list + .map((e) => ValueCard.fromJson(e as Map)) + .toList(growable: false); +} diff --git a/lib/main.dart b/lib/main.dart index 850cfb3..539fcba 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,13 +1,12 @@ -/// Application entry point: wires services, Provider, and [MaterialApp]. +/// Application entry point: wires Provider and the Values Sort practice. library; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'providers/item_provider.dart'; import 'providers/theme_provider.dart'; +import 'providers/values_sort_provider.dart'; import 'screens/splash_screen.dart'; -import 'services/item_repository.dart'; import 'services/storage_service.dart'; import 'utils/app_theme.dart'; import 'utils/constants.dart'; @@ -18,25 +17,14 @@ Future main() async { final storage = StorageService(); await storage.init(); - runApp( - MyApp( - storage: storage, - repository: ItemRepository(useRemoteData: storage.useRemoteData), - ), - ); + runApp(MyApp(storage: storage)); } -/// Root widget. Theme and catalog controllers live here so every route -/// can `context.watch` them. +/// Root widget. Theme and sort session live here so every route can watch them. class MyApp extends StatelessWidget { - const MyApp({ - super.key, - required this.storage, - required this.repository, - }); + const MyApp({super.key, required this.storage}); final StorageService storage; - final ItemRepository repository; @override Widget build(BuildContext context) { @@ -44,10 +32,7 @@ class MyApp extends StatelessWidget { providers: [ ChangeNotifierProvider(create: (_) => ThemeController(storage)), ChangeNotifierProvider( - create: (_) => ItemController( - repository: repository, - storage: storage, - )..loadItems(), + create: (_) => ValuesSortController(storage: storage)..load(), ), ], child: const _MaterialRoot(), diff --git a/lib/models/item.dart b/lib/models/item.dart deleted file mode 100644 index e5e06ad..0000000 --- a/lib/models/item.dart +++ /dev/null @@ -1,130 +0,0 @@ -/// Domain models for catalog items shown in lists and detail screens. -library; - -import 'package:flutter/material.dart'; - -/// High-level grouping used for filters, icons, and accent colors. -enum ItemCategory { - design, - development, - productivity, - lifestyle, -} - -extension ItemCategoryX on ItemCategory { - String get label => switch (this) { - ItemCategory.design => 'Design', - ItemCategory.development => 'Development', - ItemCategory.productivity => 'Productivity', - ItemCategory.lifestyle => 'Lifestyle', - }; - - IconData get icon => switch (this) { - ItemCategory.design => Icons.palette_outlined, - ItemCategory.development => Icons.code, - ItemCategory.productivity => Icons.bolt_outlined, - ItemCategory.lifestyle => Icons.spa_outlined, - }; - - /// Stable accent used by [Hero] tiles so the animation has a colored target. - Color get accent => switch (this) { - ItemCategory.design => const Color(0xFF7C3AED), - ItemCategory.development => const Color(0xFF0F766E), - ItemCategory.productivity => const Color(0xFFC2410C), - ItemCategory.lifestyle => const Color(0xFF0369A1), - }; - - static ItemCategory fromName(String name) { - return ItemCategory.values.firstWhere( - (category) => category.name == name, - orElse: () => ItemCategory.productivity, - ); - } - - static ItemCategory fromIndex(int index) { - return ItemCategory.values[index.abs() % ItemCategory.values.length]; - } -} - -/// A catalog entry displayed on Home / Search and opened on the detail route. -class Item { - const Item({ - required this.id, - required this.title, - required this.subtitle, - required this.description, - required this.category, - required this.createdAt, - }); - - final String id; - final String title; - final String subtitle; - final String description; - final ItemCategory category; - final DateTime createdAt; - - /// Tag used by the list-to-detail [Hero] animation. - String get heroTag => 'item-hero-$id'; - - Item copyWith({ - String? id, - String? title, - String? subtitle, - String? description, - ItemCategory? category, - DateTime? createdAt, - }) { - return Item( - id: id ?? this.id, - title: title ?? this.title, - subtitle: subtitle ?? this.subtitle, - description: description ?? this.description, - category: category ?? this.category, - createdAt: createdAt ?? this.createdAt, - ); - } - - /// Maps a JSONPlaceholder `/posts` payload (or any similar JSON object). - factory Item.fromJson(Map json) { - final id = json['id']?.toString() ?? '0'; - final title = (json['title'] as String? ?? 'Untitled').trim(); - final body = (json['body'] as String? ?? '').trim(); - final numericId = int.tryParse(id) ?? 0; - - return Item( - id: 'remote-$id', - title: _titleCase(title), - subtitle: _firstSentence(body), - description: body.replaceAll('\n', ' '), - category: ItemCategoryX.fromIndex(numericId), - createdAt: DateTime(2026, 1, 1).add(Duration(days: numericId)), - ); - } - - Map toJson() { - return { - 'id': id, - 'title': title, - 'subtitle': subtitle, - 'description': description, - 'category': category.name, - 'createdAt': createdAt.toIso8601String(), - }; - } - - static String _titleCase(String value) { - if (value.isEmpty) return value; - return value[0].toUpperCase() + value.substring(1); - } - - static String _firstSentence(String value) { - if (value.isEmpty) return 'No summary available.'; - final cleaned = value.replaceAll('\n', ' '); - final period = cleaned.indexOf('.'); - if (period <= 0) { - return cleaned.length > 80 ? '${cleaned.substring(0, 77)}…' : cleaned; - } - return cleaned.substring(0, period + 1); - } -} diff --git a/lib/models/value_card.dart b/lib/models/value_card.dart new file mode 100644 index 0000000..f4b0091 --- /dev/null +++ b/lib/models/value_card.dart @@ -0,0 +1,33 @@ +/// A single values-sort card with title, description, and optional domain. +library; + +/// Immutable card drawn from the values deck. +class ValueCard { + const ValueCard({ + required this.id, + required this.title, + required this.description, + this.domain = 'Values', + }); + + final String id; + final String title; + final String description; + final String domain; + + factory ValueCard.fromJson(Map json) { + return ValueCard( + id: json['id'] as String, + title: json['title'] as String, + description: json['description'] as String? ?? '', + domain: json['domain'] as String? ?? 'Values', + ); + } + + Map toJson() => { + 'id': id, + 'title': title, + 'description': description, + 'domain': domain, + }; +} diff --git a/lib/models/value_pile.dart b/lib/models/value_pile.dart new file mode 100644 index 0000000..21abc51 --- /dev/null +++ b/lib/models/value_pile.dart @@ -0,0 +1,68 @@ +/// The five reflective piles used during the initial card sort. +library; + +import 'package:flutter/material.dart'; + +/// Pile ranks from most to least important (design labels 5→1). +enum ValuePile { + mostImportant, + veryImportant, + important, + somewhatImportant, + notImportant, +} + +extension ValuePileX on ValuePile { + /// Short UI label (e.g. "Most Important"). + String get label => switch (this) { + ValuePile.mostImportant => 'Most Important', + ValuePile.veryImportant => 'Very Important', + ValuePile.important => 'Important', + ValuePile.somewhatImportant => 'Somewhat Important', + ValuePile.notImportant => 'Not Important', + }; + + /// Compact chip label used in filters and progress bars. + String get shortLabel => switch (this) { + ValuePile.mostImportant => 'Most', + ValuePile.veryImportant => 'Very', + ValuePile.important => 'Important', + ValuePile.somewhatImportant => 'Somewhat', + ValuePile.notImportant => 'Not', + }; + + /// Supporting line under pile buttons on the sort screen. + String get subtitle => switch (this) { + ValuePile.mostImportant => 'Non-negotiable core', + ValuePile.veryImportant => 'Deeply held guide', + ValuePile.important => 'Valued aspect', + ValuePile.somewhatImportant => 'Contextual', + ValuePile.notImportant => 'Not a current compass', + }; + + /// Numeric rank shown in the Stitch designs (5 = most). + int get rank => switch (this) { + ValuePile.mostImportant => 5, + ValuePile.veryImportant => 4, + ValuePile.important => 3, + ValuePile.somewhatImportant => 2, + ValuePile.notImportant => 1, + }; + + /// Accent color for this pile. + Color get accent => switch (this) { + ValuePile.mostImportant => const Color(0xFFC45C3E), + ValuePile.veryImportant => const Color(0xFFC87D55), + ValuePile.important => const Color(0xFF6B8168), + ValuePile.somewhatImportant => const Color(0xFF5B7A8C), + ValuePile.notImportant => const Color(0xFF8A847C), + }; + + static ValuePile? fromName(String? name) { + if (name == null) return null; + for (final pile in ValuePile.values) { + if (pile.name == name) return pile; + } + return null; + } +} diff --git a/lib/providers/item_provider.dart b/lib/providers/item_provider.dart deleted file mode 100644 index e44e7ea..0000000 --- a/lib/providers/item_provider.dart +++ /dev/null @@ -1,93 +0,0 @@ -/// [ChangeNotifier] that loads, filters, and mutates the in-memory item list. -library; - -import 'package:flutter/foundation.dart'; - -import '../models/item.dart'; -import '../services/item_repository.dart'; -import '../services/storage_service.dart'; - -/// App-wide catalog state. Screens call [loadItems], [addItem], and [search]. -class ItemController extends ChangeNotifier { - ItemController({ - required this._repository, - required this._storage, - }) { - _repository.useRemoteData = _storage.useRemoteData; - } - - final ItemRepository _repository; - final StorageService _storage; - - List _items = const []; - bool _isLoading = false; - String? _error; - - List get items => List.unmodifiable(_items); - bool get isLoading => _isLoading; - String? get error => _error; - bool get useRemoteData => _repository.useRemoteData; - int get count => _items.length; - - Future loadItems() async { - _isLoading = true; - _error = null; - notifyListeners(); - - try { - // Small delay so the loading indicator is visible with local data. - await Future.delayed(const Duration(milliseconds: 250)); - _items = await _repository.fetchItems(); - } catch (error, stackTrace) { - _error = 'Could not load items.'; - debugPrint('ItemController.loadItems failed: $error\n$stackTrace'); - } finally { - _isLoading = false; - notifyListeners(); - } - } - - Future setUseRemoteData(bool value) async { - if (value == _repository.useRemoteData) return; - _repository.useRemoteData = value; - await _storage.setUseRemoteData(value); - notifyListeners(); - await loadItems(); - } - - /// Case-insensitive match against title, subtitle, and category. - List search(String query) { - final needle = query.trim().toLowerCase(); - if (needle.isEmpty) return items; - - return _items.where((item) { - return item.title.toLowerCase().contains(needle) || - item.subtitle.toLowerCase().contains(needle) || - item.category.label.toLowerCase().contains(needle); - }).toList(growable: false); - } - - Item addItem({ - required String title, - required String subtitle, - required String description, - required ItemCategory category, - }) { - final created = _repository.createLocal( - title: title, - subtitle: subtitle, - description: description, - category: category, - ); - _items = [created, ..._items]; - notifyListeners(); - return created; - } - - Item? findById(String id) { - for (final item in _items) { - if (item.id == id) return item; - } - return null; - } -} diff --git a/lib/providers/theme_provider.dart b/lib/providers/theme_provider.dart index 1cecdcd..8e9a31b 100644 --- a/lib/providers/theme_provider.dart +++ b/lib/providers/theme_provider.dart @@ -4,12 +4,11 @@ library; import 'package:flutter/material.dart'; import '../services/storage_service.dart'; -import '../utils/helpers.dart'; /// Provides [themeMode] to [MaterialApp] and writes changes to storage. class ThemeController extends ChangeNotifier { ThemeController(this._storage) { - _themeMode = themeModeFromName(_storage.themeModeName); + _themeMode = _fromName(_storage.themeModeName); } final StorageService _storage; @@ -17,21 +16,37 @@ class ThemeController extends ChangeNotifier { ThemeMode get themeMode => _themeMode; - bool get isDark => _themeMode == ThemeMode.dark; + bool get isDark => + _themeMode == ThemeMode.dark || + (_themeMode == ThemeMode.system && + WidgetsBinding.instance.platformDispatcher.platformBrightness == + Brightness.dark); Future setThemeMode(ThemeMode mode) async { if (mode == _themeMode) return; _themeMode = mode; notifyListeners(); - await _storage.setThemeModeName(nameFromThemeMode(mode)); + await _storage.setThemeModeName(_toName(mode)); } - Future cycleThemeMode() { - final next = switch (_themeMode) { - ThemeMode.system => ThemeMode.light, - ThemeMode.light => ThemeMode.dark, - ThemeMode.dark => ThemeMode.system, - }; - return setThemeMode(next); + /// Toggles between light and dark (moon / sun control). + Future toggleLightDark() { + return setThemeMode(isDark ? ThemeMode.light : ThemeMode.dark); } } + +ThemeMode _fromName(String name) { + return switch (name) { + 'dark' => ThemeMode.dark, + 'system' => ThemeMode.system, + _ => ThemeMode.light, + }; +} + +String _toName(ThemeMode mode) { + return switch (mode) { + ThemeMode.light => 'light', + ThemeMode.dark => 'dark', + ThemeMode.system => 'system', + }; +} diff --git a/lib/providers/values_sort_provider.dart b/lib/providers/values_sort_provider.dart new file mode 100644 index 0000000..de71ce1 --- /dev/null +++ b/lib/providers/values_sort_provider.dart @@ -0,0 +1,455 @@ +/// Session state for the Values Sort practice: sorting, ranking, reflection. +library; + +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; + +import '../data/values_deck.dart'; +import '../models/value_card.dart'; +import '../models/value_pile.dart'; +import '../services/storage_service.dart'; + +/// Contemplative prompts shown during the reflection stage. +const List kReflectionPrompts = [ + 'What does this value mean to you?', + 'Why did you choose this as important?', + 'When do you live this value most fully?', + 'What gets in the way of honoring this value?', +]; + +/// Stages in the guided practice flow. +enum SortStage { + welcome, + sorting, + hub, + overview, + pileReview, + ranking, + reflection, +} + +/// ChangeNotifier that owns the deck, pile assignments, ranking, and journals. +class ValuesSortController extends ChangeNotifier { + ValuesSortController({required StorageService this._storage}); + + final StorageService _storage; + + bool _loading = true; + bool get loading => _loading; + + String? _error; + String? get error => _error; + + SortStage _stage = SortStage.welcome; + SortStage get stage => _stage; + + List _deck = const []; + List get deck => _deck; + + /// Remaining unsorted cards (front of list is current). + final List _unsorted = []; + List get unsorted => List.unmodifiable(_unsorted); + + ValueCard? get currentCard => + _unsorted.isEmpty ? null : _unsorted.first; + + final Map _assignments = {}; + Map get assignments => Map.unmodifiable(_assignments); + + /// Ordered top values (index 0 = #1 / North Star). + final List _rankedIds = []; + List get rankedIds => List.unmodifiable(_rankedIds); + + /// Reflections keyed by `valueId|promptIndex`. + final Map _reflections = {}; + + ValuePile? _reviewPile; + ValuePile? get reviewPile => _reviewPile; + + String? _activeReflectionValueId; + String? get activeReflectionValueId => _activeReflectionValueId; + + int _activePromptIndex = 0; + int get activePromptIndex => _activePromptIndex; + + final List _undoStack = []; + + bool _restoring = false; + + /// True when a non-welcome session is on disk / in memory. + bool get hasInProgressSession => + _stage != SortStage.welcome || + _assignments.isNotEmpty || + _reflections.isNotEmpty; + + Future load({List? seedDeck}) async { + _loading = true; + _error = null; + notifyListeners(); + try { + final cards = seedDeck ?? await loadValuesDeck(); + _deck = cards; + _resetSortState(); + await _restoreSession(); + } catch (e) { + _error = e.toString(); + } finally { + _loading = false; + notifyListeners(); + } + } + + String get _deckFingerprint => + _deck.map((c) => c.id).join('|'); + + void _resetSortState() { + _assignments.clear(); + _undoStack.clear(); + _unsorted + ..clear() + ..addAll(_deck); + _rankedIds.clear(); + _reflections.clear(); + _reviewPile = null; + _activeReflectionValueId = null; + _activePromptIndex = 0; + } + + void beginPractice() { + if (_deck.isEmpty) return; + _resetSortState(); + _stage = SortStage.sorting; + _commit(); + } + + void restart() { + _resetSortState(); + _stage = SortStage.welcome; + _commit(clear: true); + } + + int get sortedCount => _assignments.length; + int get totalCount => _deck.length; + double get sortProgress => + totalCount == 0 ? 0 : sortedCount / totalCount; + + bool get isSortComplete => + _unsorted.isEmpty && _assignments.length == _deck.length; + + List cardsInPile(ValuePile pile) { + return _deck + .where((c) => _assignments[c.id] == pile) + .toList(growable: false); + } + + int countInPile(ValuePile pile) => cardsInPile(pile).length; + + ValueCard? cardById(String id) { + for (final c in _deck) { + if (c.id == id) return c; + } + return null; + } + + void assignCurrent(ValuePile pile) { + final card = currentCard; + if (card == null) return; + _undoStack.add(card.id); + _assignments[card.id] = pile; + _unsorted.removeAt(0); + if (isSortComplete) { + _seedRankingFromMostImportant(); + _stage = SortStage.hub; + } + _commit(); + } + + void undoLastSort() { + if (_undoStack.isEmpty) return; + final id = _undoStack.removeLast(); + _assignments.remove(id); + final card = cardById(id); + if (card != null) { + _unsorted.insert(0, card); + } + if (_stage != SortStage.sorting) { + _stage = SortStage.sorting; + } + _commit(); + } + + void moveCard(String id, ValuePile pile) { + if (!_assignments.containsKey(id) && + !_unsorted.any((c) => c.id == id)) { + return; + } + _unsorted.removeWhere((c) => c.id == id); + _assignments[id] = pile; + _rankedIds.remove(id); + _syncRankingWithMostImportant(); + _commit(); + } + + void _seedRankingFromMostImportant() { + _rankedIds + ..clear() + ..addAll(cardsInPile(ValuePile.mostImportant).map((c) => c.id)); + } + + void _syncRankingWithMostImportant() { + final most = cardsInPile(ValuePile.mostImportant).map((c) => c.id).toSet(); + _rankedIds.removeWhere((id) => !most.contains(id)); + for (final id in most) { + if (!_rankedIds.contains(id)) { + _rankedIds.add(id); + } + } + } + + void goToHub() { + _stage = SortStage.hub; + _commit(); + } + + void goToOverview() { + _stage = SortStage.overview; + _commit(); + } + + void openPileReview(ValuePile pile) { + _reviewPile = pile; + _stage = SortStage.pileReview; + _commit(); + } + + void goToRanking() { + _syncRankingWithMostImportant(); + if (_rankedIds.isEmpty) { + final fallback = cardsInPile(ValuePile.veryImportant); + for (final c in fallback.take(8)) { + _assignments[c.id] = ValuePile.mostImportant; + _rankedIds.add(c.id); + } + } + _stage = SortStage.ranking; + _commit(); + } + + void reorderRanked(int oldIndex, int newIndex) { + final id = _rankedIds.removeAt(oldIndex); + _rankedIds.insert(newIndex, id); + _commit(); + } + + void moveRank(int index, {required bool up}) { + final target = up ? index - 1 : index + 1; + if (target < 0 || target >= _rankedIds.length) return; + final id = _rankedIds.removeAt(index); + _rankedIds.insert(target, id); + _commit(); + } + + List get rankedCards => _rankedIds + .map(cardById) + .whereType() + .toList(growable: false); + + /// Top values used for reflection (up to 5). + List get coreValues => rankedCards.take(5).toList(growable: false); + + void goToReflection({String? valueId}) { + final cores = coreValues; + if (valueId != null && cores.any((c) => c.id == valueId)) { + _activeReflectionValueId = valueId; + } else { + _activeReflectionValueId = cores.isEmpty ? null : cores.first.id; + } + _activePromptIndex = 0; + _stage = SortStage.reflection; + _commit(); + } + + void selectReflectionValue(String id) { + _activeReflectionValueId = id; + _activePromptIndex = 0; + _commit(); + } + + void selectPrompt(int index) { + _activePromptIndex = index.clamp(0, kReflectionPrompts.length - 1); + _commit(); + } + + String reflectionKey(String valueId, int promptIndex) => + '$valueId|$promptIndex'; + + String reflectionFor(String valueId, int promptIndex) => + _reflections[reflectionKey(valueId, promptIndex)] ?? ''; + + void setReflection(String valueId, int promptIndex, String text) { + final key = reflectionKey(valueId, promptIndex); + if (text.trim().isEmpty) { + _reflections.remove(key); + } else { + _reflections[key] = text.trim(); + } + _commit(); + } + + int answeredPromptCount(String valueId) { + var n = 0; + for (var i = 0; i < kReflectionPrompts.length; i++) { + if (reflectionFor(valueId, i).isNotEmpty) n++; + } + return n; + } + + int get totalAnsweredReflections { + var n = 0; + for (final c in coreValues) { + n += answeredPromptCount(c.id); + } + return n; + } + + int get totalReflectionSlots => + coreValues.length * kReflectionPrompts.length; + + void _commit({bool clear = false}) { + notifyListeners(); + if (_restoring) return; + if (clear || (_stage == SortStage.welcome && _assignments.isEmpty)) { + unawaited(_storage.clearSortSession()); + return; + } + unawaited(_persistNow()); + } + + Future _persistNow() async { + try { + final payload = { + 'version': 1, + 'deckFingerprint': _deckFingerprint, + 'stage': _stage.name, + 'reviewPile': _reviewPile?.name, + 'assignments': { + for (final e in _assignments.entries) e.key: e.value.name, + }, + 'unsortedIds': _unsorted.map((c) => c.id).toList(growable: false), + 'rankedIds': List.from(_rankedIds), + 'reflections': Map.from(_reflections), + 'activeReflectionValueId': _activeReflectionValueId, + 'activePromptIndex': _activePromptIndex, + 'undoStack': List.from(_undoStack), + }; + await _storage.setSortSessionJson(jsonEncode(payload)); + } catch (_) { + // Persistence failures should not break the practice UI. + } + } + + Future _restoreSession() async { + final raw = _storage.sortSessionJson; + if (raw == null || raw.isEmpty) return; + + try { + final data = jsonDecode(raw) as Map; + if (data['deckFingerprint'] != _deckFingerprint) { + await _storage.clearSortSession(); + return; + } + + _restoring = true; + + final knownIds = _deck.map((c) => c.id).toSet(); + final assignmentsRaw = + (data['assignments'] as Map?)?.cast() ?? {}; + _assignments.clear(); + for (final e in assignmentsRaw.entries) { + final pile = ValuePileX.fromName('${e.value}'); + if (pile != null && knownIds.contains(e.key)) { + _assignments[e.key] = pile; + } + } + + final unsortedIds = + (data['unsortedIds'] as List?)?.cast() ?? const []; + _unsorted + ..clear() + ..addAll( + unsortedIds + .map(cardById) + .whereType(), + ); + + // Recover any deck cards missing from both maps (deck updates / corruption). + final present = {..._assignments.keys, ..._unsorted.map((c) => c.id)}; + for (final card in _deck) { + if (!present.contains(card.id)) { + _unsorted.add(card); + } + } + + _rankedIds + ..clear() + ..addAll( + ((data['rankedIds'] as List?)?.cast() ?? const []) + .where(knownIds.contains), + ); + _syncRankingWithMostImportant(); + + _reflections + ..clear() + ..addAll( + ((data['reflections'] as Map?)?.cast() ?? {}) + .map((k, v) => MapEntry(k, '$v')), + ); + + _undoStack + ..clear() + ..addAll( + ((data['undoStack'] as List?)?.cast() ?? const []) + .where(knownIds.contains), + ); + + _reviewPile = ValuePileX.fromName(data['reviewPile'] as String?); + _activeReflectionValueId = data['activeReflectionValueId'] as String?; + if (_activeReflectionValueId != null && + !knownIds.contains(_activeReflectionValueId)) { + _activeReflectionValueId = null; + } + _activePromptIndex = (data['activePromptIndex'] as num?)?.toInt() ?? 0; + + final stageName = data['stage'] as String? ?? SortStage.welcome.name; + _stage = SortStage.values.firstWhere( + (s) => s.name == stageName, + orElse: () => SortStage.welcome, + ); + + // If restored mid-sort but nothing left unsorted, land on the hub. + if (_stage == SortStage.sorting && isSortComplete) { + _seedRankingFromMostImportant(); + _stage = SortStage.hub; + } + if (_stage == SortStage.pileReview && _reviewPile == null) { + _stage = SortStage.hub; + } + } catch (_) { + await _storage.clearSortSession(); + _resetSortState(); + _stage = SortStage.welcome; + } finally { + _restoring = false; + } + } + + @override + void dispose() { + if (!_restoring && hasInProgressSession) { + unawaited(_persistNow()); + } + super.dispose(); + } +} diff --git a/lib/screens/add_item_screen.dart b/lib/screens/add_item_screen.dart deleted file mode 100644 index f77f91e..0000000 --- a/lib/screens/add_item_screen.dart +++ /dev/null @@ -1,142 +0,0 @@ -/// Validated form that inserts a new [Item] into [ItemController]. -library; - -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import '../models/item.dart'; -import '../providers/item_provider.dart'; -import '../widgets/app_text_field.dart'; -import '../widgets/responsive_body.dart'; - -class AddItemScreen extends StatefulWidget { - const AddItemScreen({super.key}); - - @override - State createState() => _AddItemScreenState(); -} - -class _AddItemScreenState extends State { - final _formKey = GlobalKey(); - final _title = TextEditingController(); - final _subtitle = TextEditingController(); - final _description = TextEditingController(); - ItemCategory? _category; - bool _submitted = false; - - @override - void dispose() { - _title.dispose(); - _subtitle.dispose(); - _description.dispose(); - super.dispose(); - } - - String? _requiredLength(String? value, {required int min, String? label}) { - final text = value?.trim() ?? ''; - if (text.isEmpty) return 'Enter a ${label ?? 'value'}.'; - if (text.length < min) { - return '${label ?? 'This field'} must be at least $min characters.'; - } - return null; - } - - void _submit() { - setState(() => _submitted = true); - final form = _formKey.currentState; - if (form == null || !form.validate() || _category == null) return; - - context.read().addItem( - title: _title.text, - subtitle: _subtitle.text, - description: _description.text, - category: _category!, - ); - - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Added “${_title.text.trim()}”')), - ); - Navigator.of(context).pop(); - } - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - return Scaffold( - appBar: AppBar(title: const Text('Add item')), - body: ResponsiveBody( - child: Form( - key: _formKey, - autovalidateMode: _submitted - ? AutovalidateMode.onUserInteraction - : AutovalidateMode.disabled, - child: ListView( - children: [ - const SizedBox(height: 8), - Text( - 'Create a catalog entry. All fields are required.', - style: theme.textTheme.bodyMedium, - ), - const SizedBox(height: 20), - AppTextField( - controller: _title, - label: 'Title', - hint: 'Give it a short name', - autofocus: true, - textInputAction: TextInputAction.next, - validator: (value) => - _requiredLength(value, min: 3, label: 'Title'), - ), - const SizedBox(height: 16), - AppTextField( - controller: _subtitle, - label: 'Summary', - hint: 'One sentence overview', - textInputAction: TextInputAction.next, - validator: (value) => - _requiredLength(value, min: 8, label: 'Summary'), - ), - const SizedBox(height: 16), - DropdownButtonFormField( - initialValue: _category, - decoration: const InputDecoration(labelText: 'Category'), - items: [ - for (final category in ItemCategory.values) - DropdownMenuItem( - value: category, - child: Text(category.label), - ), - ], - onChanged: (value) => setState(() => _category = value), - validator: (value) => - value == null ? 'Choose a category.' : null, - ), - const SizedBox(height: 16), - AppTextField( - controller: _description, - label: 'Description', - hint: 'A longer note the detail screen will show', - maxLines: 5, - keyboardType: TextInputType.multiline, - validator: (value) => - _requiredLength(value, min: 16, label: 'Description'), - ), - const SizedBox(height: 24), - FilledButton( - onPressed: _submit, - child: const Text('Save item'), - ), - const SizedBox(height: 12), - OutlinedButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text('Cancel'), - ), - const SizedBox(height: 24), - ], - ), - ), - ), - ); - } -} diff --git a/lib/screens/card_sorting_screen.dart b/lib/screens/card_sorting_screen.dart new file mode 100644 index 0000000..f2300e6 --- /dev/null +++ b/lib/screens/card_sorting_screen.dart @@ -0,0 +1,190 @@ +/// Stage 1 — assign each value card into one of five reflective piles. +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../models/value_pile.dart'; +import '../providers/values_sort_provider.dart'; +import '../widgets/practice_chrome.dart'; +import '../widgets/value_card_tile.dart'; + +class CardSortingScreen extends StatelessWidget { + const CardSortingScreen({super.key}); + + @override + Widget build(BuildContext context) { + final sort = context.watch(); + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + final card = sort.currentCard; + + return PracticeScaffold( + padding: const EdgeInsets.fromLTRB(20, 4, 20, 8), + header: Padding( + padding: const EdgeInsets.fromLTRB(12, 4, 12, 0), + child: Row( + children: [ + TextButton.icon( + onPressed: sort.sortedCount == 0 ? null : sort.undoLastSort, + icon: const Icon(Icons.undo, size: 18), + label: const Text('Undo'), + ), + const Spacer(), + Text( + 'Stage 1 · Initial Sort', + style: text.labelMedium, + ), + ], + ), + ), + child: Column( + children: [ + Row( + children: [ + Icon(Icons.bookmark_border, size: 18, color: colors.onSurfaceVariant), + const SizedBox(width: 6), + Expanded( + child: Text( + '${sort.sortedCount} of ${sort.totalCount} values sorted', + style: text.labelMedium, + ), + ), + Text( + '${(sort.sortProgress * 100).round()}%', + style: text.labelMedium?.copyWith( + color: colors.primary, + fontWeight: FontWeight.w700, + ), + ), + ], + ), + const SizedBox(height: 8), + ClipRRect( + borderRadius: BorderRadius.circular(999), + child: LinearProgressIndicator( + value: sort.sortProgress, + minHeight: 6, + backgroundColor: colors.surfaceContainerHigh, + color: colors.secondary, + ), + ), + const SizedBox(height: 12), + Expanded( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 280), + child: card == null + ? Center( + key: const ValueKey('empty'), + child: Text('All sorted', style: text.headlineMedium), + ) + : SingleChildScrollView( + key: ValueKey(card.id), + child: Column( + children: [ + ValueCardTile(card: card, elevation: 2), + const SizedBox(height: 14), + Text( + 'Tap a pile to sort', + style: text.labelMedium?.copyWith( + color: colors.onSurfaceVariant, + ), + ), + const SizedBox(height: 8), + ...ValuePile.values.map((pile) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: _PileButton( + pile: pile, + count: sort.countInPile(pile), + onTap: () => sort.assignCurrent(pile), + ), + ); + }), + ], + ), + ), + ), + ), + ], + ), + ); + } +} + +class _PileButton extends StatelessWidget { + const _PileButton({ + required this.pile, + required this.count, + required this.onTap, + }); + + final ValuePile pile; + final int count; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return Material( + color: colors.surfaceContainerLow, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18), + side: BorderSide(color: pile.accent.withValues(alpha: 0.35)), + ), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(18), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), + child: Row( + children: [ + Container( + width: 28, + height: 28, + alignment: Alignment.center, + decoration: BoxDecoration( + color: pile.accent.withValues(alpha: 0.15), + shape: BoxShape.circle, + ), + child: Text( + '${pile.rank}', + style: text.labelMedium?.copyWith( + color: pile.accent, + fontWeight: FontWeight.w700, + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + pile.label, + style: text.titleMedium?.copyWith( + color: colors.onSurface, + ), + ), + Text( + pile.subtitle, + style: text.bodySmall?.copyWith( + color: colors.onSurfaceVariant, + ), + ), + ], + ), + ), + Text( + '$count', + style: text.labelMedium?.copyWith(color: pile.accent), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart deleted file mode 100644 index a713562..0000000 --- a/lib/screens/home_screen.dart +++ /dev/null @@ -1,212 +0,0 @@ -/// Home tab: greeting, stats, and a [ListView.builder] of catalog items. -library; - -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import '../providers/item_provider.dart'; -import '../widgets/empty_state.dart'; -import '../widgets/item_card.dart'; -import '../widgets/loading_view.dart'; -import '../widgets/responsive_body.dart'; -import 'add_item_screen.dart'; - -class HomeScreen extends StatelessWidget { - const HomeScreen({super.key}); - - @override - Widget build(BuildContext context) { - final controller = context.watch(); - final theme = Theme.of(context); - - return Scaffold( - appBar: AppBar(title: const Text('Home')), - floatingActionButton: FloatingActionButton.extended( - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const AddItemScreen()), - ); - }, - icon: const Icon(Icons.add), - label: const Text('Add item'), - ), - body: RefreshIndicator( - onRefresh: controller.loadItems, - child: ResponsiveBody( - child: _HomeBody(controller: controller, theme: theme), - ), - ), - ); - } -} - -class _HomeBody extends StatelessWidget { - const _HomeBody({ - required this.controller, - required this.theme, - }); - - final ItemController controller; - final ThemeData theme; - - @override - Widget build(BuildContext context) { - if (controller.isLoading && controller.items.isEmpty) { - return const LoadingView(message: 'Fetching catalog…'); - } - - if (controller.error != null && controller.items.isEmpty) { - return ListView( - physics: const AlwaysScrollableScrollPhysics(), - children: [ - EmptyState( - icon: Icons.error_outline, - title: 'Something went wrong', - message: controller.error!, - actionLabel: 'Retry', - onAction: controller.loadItems, - ), - ], - ); - } - - if (controller.items.isEmpty) { - return ListView( - physics: const AlwaysScrollableScrollPhysics(), - children: const [ - EmptyState( - icon: Icons.inbox_outlined, - title: 'No items yet', - message: 'Add your first item with the button below.', - ), - ], - ); - } - - // Header occupies the first slot; remaining slots are catalog cards. - return ListView.builder( - physics: const AlwaysScrollableScrollPhysics(), - padding: const EdgeInsets.only(top: 8, bottom: 96), - itemCount: controller.items.length + 1, - itemBuilder: (context, index) { - if (index == 0) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _WelcomeBanner(itemCount: controller.count), - const SizedBox(height: 20), - Text('Featured items', style: theme.textTheme.titleMedium), - const SizedBox(height: 12), - ], - ); - } - - final item = controller.items[index - 1]; - return Padding( - padding: const EdgeInsets.only(bottom: 12), - child: ItemCard(item: item, heroScope: 'home'), - ); - }, - ); - } -} - -class _WelcomeBanner extends StatelessWidget { - const _WelcomeBanner({required this.itemCount}); - - final int itemCount; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final colors = theme.colorScheme; - - return Container( - width: double.infinity, - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: LinearGradient( - colors: [colors.primary, colors.tertiary], - ), - boxShadow: [ - BoxShadow( - color: colors.primary.withValues(alpha: 0.28), - blurRadius: 20, - offset: const Offset(0, 10), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Welcome back', - style: theme.textTheme.labelMedium?.copyWith( - color: colors.onPrimary.withValues(alpha: 0.8), - ), - ), - const SizedBox(height: 4), - Text( - 'Your catalog at a glance', - style: theme.textTheme.headlineMedium?.copyWith( - color: colors.onPrimary, - ), - ), - const SizedBox(height: 16), - Row( - children: [ - _StatPill( - label: 'Items', - value: '$itemCount', - icon: Icons.collections_bookmark_outlined, - ), - const SizedBox(width: 10), - const _StatPill( - label: 'Theme', - value: 'M3', - icon: Icons.palette_outlined, - ), - ], - ), - ], - ), - ); - } -} - -class _StatPill extends StatelessWidget { - const _StatPill({ - required this.label, - required this.value, - required this.icon, - }); - - final String label; - final String value; - final IconData icon; - - @override - Widget build(BuildContext context) { - final onPrimary = Theme.of(context).colorScheme.onPrimary; - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: onPrimary.withValues(alpha: 0.14), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - Icon(icon, size: 16, color: onPrimary), - const SizedBox(width: 8), - Text( - '$value $label', - style: Theme.of(context).textTheme.labelMedium?.copyWith( - color: onPrimary, - ), - ), - ], - ), - ); - } -} diff --git a/lib/screens/item_detail_screen.dart b/lib/screens/item_detail_screen.dart deleted file mode 100644 index 794fc15..0000000 --- a/lib/screens/item_detail_screen.dart +++ /dev/null @@ -1,82 +0,0 @@ -/// Detail route opened from a list card, with a [Hero] matching the list badge. -library; - -import 'package:flutter/material.dart'; - -import '../models/item.dart'; -import '../utils/helpers.dart'; -import '../widgets/item_hero_badge.dart'; -import '../widgets/responsive_body.dart'; - -class ItemDetailScreen extends StatelessWidget { - const ItemDetailScreen({ - super.key, - required this.item, - required this.heroTag, - }); - - final Item item; - final String heroTag; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final colors = theme.colorScheme; - - return Scaffold( - appBar: AppBar(title: const Text('Details')), - body: ResponsiveBody( - child: ListView( - children: [ - const SizedBox(height: 16), - Center( - child: ItemHeroBadge(item: item, size: 96, heroTag: heroTag), - ), - const SizedBox(height: 24), - Text(item.title, style: theme.textTheme.headlineMedium), - const SizedBox(height: 12), - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - Chip( - avatar: Icon( - item.category.icon, - size: 16, - color: item.category.accent, - ), - label: Text(item.category.label), - side: BorderSide( - color: item.category.accent.withValues(alpha: 0.4), - ), - ), - Chip( - avatar: Icon( - Icons.calendar_today_outlined, - size: 16, - color: colors.onSurfaceVariant, - ), - label: Text(formatDate(item.createdAt)), - ), - ], - ), - const SizedBox(height: 20), - Text('Summary', style: theme.textTheme.titleMedium), - const SizedBox(height: 8), - Text(item.subtitle, style: theme.textTheme.bodyLarge), - const SizedBox(height: 20), - Text('Description', style: theme.textTheme.titleMedium), - const SizedBox(height: 8), - Text(item.description, style: theme.textTheme.bodyLarge), - const SizedBox(height: 32), - FilledButton.tonal( - onPressed: () => Navigator.of(context).pop(), - child: const Text('Back to list'), - ), - const SizedBox(height: 24), - ], - ), - ), - ); - } -} diff --git a/lib/screens/main_shell.dart b/lib/screens/main_shell.dart deleted file mode 100644 index 5878dbd..0000000 --- a/lib/screens/main_shell.dart +++ /dev/null @@ -1,64 +0,0 @@ -/// Host scaffold that owns the bottom navigation bar and its four tabs. -library; - -import 'package:flutter/material.dart'; - -import 'home_screen.dart'; -import 'profile_screen.dart'; -import 'search_screen.dart'; -import 'settings_screen.dart'; - -/// Switches between Home, Search, Profile, and Settings without stacking routes. -class MainShell extends StatefulWidget { - const MainShell({super.key}); - - @override - State createState() => _MainShellState(); -} - -class _MainShellState extends State { - int _index = 0; - - static const _pages = [ - HomeScreen(), - SearchScreen(), - ProfileScreen(), - SettingsScreen(), - ]; - - @override - Widget build(BuildContext context) { - return Scaffold( - body: IndexedStack( - index: _index, - children: _pages, - ), - bottomNavigationBar: NavigationBar( - selectedIndex: _index, - onDestinationSelected: (index) => setState(() => _index = index), - destinations: const [ - NavigationDestination( - icon: Icon(Icons.home_outlined), - selectedIcon: Icon(Icons.home), - label: 'Home', - ), - NavigationDestination( - icon: Icon(Icons.search_outlined), - selectedIcon: Icon(Icons.search), - label: 'Search', - ), - NavigationDestination( - icon: Icon(Icons.person_outline), - selectedIcon: Icon(Icons.person), - label: 'Profile', - ), - NavigationDestination( - icon: Icon(Icons.settings_outlined), - selectedIcon: Icon(Icons.settings), - label: 'Settings', - ), - ], - ), - ); - } -} diff --git a/lib/screens/pile_review_screen.dart b/lib/screens/pile_review_screen.dart new file mode 100644 index 0000000..e91ecfb --- /dev/null +++ b/lib/screens/pile_review_screen.dart @@ -0,0 +1,129 @@ +/// Refine a single pile — promote / demote cards (Important Cards pattern). +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../models/value_pile.dart'; +import '../providers/values_sort_provider.dart'; +import '../widgets/practice_chrome.dart'; +import '../widgets/value_card_tile.dart'; +import '../utils/app_theme.dart'; + +class PileReviewScreen extends StatelessWidget { + const PileReviewScreen({super.key}); + + @override + Widget build(BuildContext context) { + final sort = context.watch(); + final pile = sort.reviewPile ?? ValuePile.important; + final cards = sort.cardsInPile(pile); + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return PracticeScaffold( + header: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 0), + child: Row( + children: [ + IconButton( + onPressed: sort.goToOverview, + icon: const Icon(Icons.arrow_back), + ), + Expanded( + child: Text( + 'Reviewing · ${pile.label}', + style: text.labelMedium, + ), + ), + ], + ), + ), + footer: PrimaryPillButton( + label: 'Back to overview', + onPressed: sort.goToOverview, + ), + child: ListView( + children: [ + Text(pile.label, style: text.displaySmall), + const SizedBox(height: 6), + Text( + '${cards.length} values in this pile. Promote toward your core or demote when something feels less essential.', + style: text.bodyMedium, + ), + const SizedBox(height: 12), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: ValuePile.values.map((p) { + return Padding( + padding: const EdgeInsets.only(right: 8), + child: ActionChip( + avatar: CircleAvatar( + backgroundColor: p.accent.withValues(alpha: 0.2), + radius: 8, + ), + label: Text('${p.shortLabel} ${sort.countInPile(p)}'), + onPressed: () => sort.openPileReview(p), + backgroundColor: p == pile + ? AppTheme.surfaceContainerHigh + : AppTheme.surfaceContainerLow, + ), + ); + }).toList(), + ), + ), + const SizedBox(height: 16), + if (cards.isEmpty) + Padding( + padding: const EdgeInsets.symmetric(vertical: 40), + child: Text( + 'No cards in this pile yet.', + style: text.bodyLarge?.copyWith(color: colors.onSurfaceVariant), + textAlign: TextAlign.center, + ), + ) + else + ...cards.map((card) { + return Padding( + padding: const EdgeInsets.only(bottom: 12), + child: ValueCardTile( + card: card, + compact: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + tooltip: 'Promote', + onPressed: () => _shift(sort, card.id, pile, up: true), + icon: const Icon(Icons.arrow_upward), + ), + IconButton( + tooltip: 'Demote', + onPressed: () => + _shift(sort, card.id, pile, up: false), + icon: const Icon(Icons.arrow_downward), + ), + ], + ), + ), + ); + }), + ], + ), + ); + } + + void _shift( + ValuesSortController sort, + String id, + ValuePile current, { + required bool up, + }) { + final values = ValuePile.values; + final index = values.indexOf(current); + final next = up ? index - 1 : index + 1; + if (next < 0 || next >= values.length) return; + sort.moveCard(id, values[next]); + } +} diff --git a/lib/screens/practice_flow_screen.dart b/lib/screens/practice_flow_screen.dart new file mode 100644 index 0000000..3a70cd9 --- /dev/null +++ b/lib/screens/practice_flow_screen.dart @@ -0,0 +1,66 @@ +/// Host that swaps practice stages from [ValuesSortController]. +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../providers/values_sort_provider.dart'; +import 'card_sorting_screen.dart'; +import 'pile_review_screen.dart'; +import 'practice_hub_screen.dart'; +import 'rank_order_screen.dart'; +import 'reflection_screen.dart'; +import 'sorted_overview_screen.dart'; +import 'welcome_screen.dart'; + +class PracticeFlowScreen extends StatelessWidget { + const PracticeFlowScreen({super.key}); + + @override + Widget build(BuildContext context) { + final sort = context.watch(); + + if (sort.loading) { + return const Scaffold( + body: Center(child: CircularProgressIndicator()), + ); + } + + if (sort.error != null) { + return Scaffold( + body: Center( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('Could not load the values deck.\n${sort.error}'), + const SizedBox(height: 12), + FilledButton( + onPressed: sort.load, + child: const Text('Retry'), + ), + ], + ), + ), + ), + ); + } + + return AnimatedSwitcher( + duration: const Duration(milliseconds: 320), + child: KeyedSubtree( + key: ValueKey(sort.stage), + child: switch (sort.stage) { + SortStage.welcome => const WelcomeScreen(), + SortStage.sorting => const CardSortingScreen(), + SortStage.hub => const PracticeHubScreen(), + SortStage.overview => const SortedOverviewScreen(), + SortStage.pileReview => const PileReviewScreen(), + SortStage.ranking => const RankOrderScreen(), + SortStage.reflection => const ReflectionScreen(), + }, + ), + ); + } +} diff --git a/lib/screens/practice_hub_screen.dart b/lib/screens/practice_hub_screen.dart new file mode 100644 index 0000000..ba1b679 --- /dev/null +++ b/lib/screens/practice_hub_screen.dart @@ -0,0 +1,447 @@ +/// Post-sort home — landscape summary and gateways (Stitch Practice Hub). +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../models/value_card.dart'; +import '../providers/values_sort_provider.dart'; +import '../widgets/practice_chrome.dart'; + +class PracticeHubScreen extends StatelessWidget { + const PracticeHubScreen({super.key}); + + @override + Widget build(BuildContext context) { + final sort = context.watch(); + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + final answered = sort.totalAnsweredReflections; + final slots = sort.totalReflectionSlots; + final progress = slots == 0 ? 0.0 : answered / slots; + final core = sort.rankedCards.take(5).toList(growable: false); + + return PracticeScaffold( + padding: const EdgeInsets.fromLTRB(20, 4, 20, 8), + footer: FilledButton.tonal( + onPressed: () => _confirmReset(context, sort), + style: FilledButton.styleFrom( + minimumSize: const Size.fromHeight(52), + backgroundColor: colors.surfaceContainerHigh, + foregroundColor: colors.onSurface, + shape: const StadiumBorder(), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.restart_alt, size: 18, color: colors.outline), + const SizedBox(width: 8), + Text( + 'Finish Practice (Reset All)', + style: text.labelLarge?.copyWith(color: colors.onSurface), + ), + ], + ), + ), + child: ListView( + children: [ + Text( + 'Your Values Landscape', + style: text.displaySmall?.copyWith(color: colors.onSurface), + ), + const SizedBox(height: 18), + _CoreValuesCard( + values: core, + onValueTap: (card) => sort.goToReflection(valueId: card.id), + ), + const SizedBox(height: 20), + _GatewayCard( + icon: Icons.layers_outlined, + iconColor: colors.primary, + title: 'All Sorted Values', + onTap: sort.goToOverview, + ), + const SizedBox(height: 12), + _GatewayCard( + icon: Icons.format_list_numbered, + iconColor: colors.secondary, + title: 'Order Top Values', + onTap: sort.goToRanking, + ), + const SizedBox(height: 12), + _GatewayCard( + icon: Icons.edit_note, + iconColor: colors.tertiary, + title: 'Reflect & Inquire', + meta: slots == 0 + ? 'Rank top values first' + : '$answered of $slots Answered (${(progress * 100).round()}%)', + metaBackground: colors.tertiaryContainer.withValues(alpha: 0.45), + metaForeground: colors.onTertiaryContainer, + progress: slots == 0 ? null : progress, + onTap: sort.coreValues.isEmpty ? null : sort.goToReflection, + ), + const SizedBox(height: 8), + ], + ), + ); + } + + Future _confirmReset( + BuildContext context, + ValuesSortController sort, + ) async { + final ok = await showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (ctx) { + final text = Theme.of(ctx).textTheme; + final c = Theme.of(ctx).colorScheme; + return SafeArea( + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(24, 8, 24, 24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + CircleAvatar( + backgroundColor: c.errorContainer.withValues(alpha: 0.5), + child: Icon(Icons.hourglass_empty, color: c.error), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Reset Entire Practice?', style: text.titleLarge), + Text( + 'Clean slate contemplation', + style: text.labelSmall, + ), + ], + ), + ), + ], + ), + const SizedBox(height: 14), + Text( + 'This deliberate action will clear all 5 categorized piles, ' + 'your prioritized hierarchy, and stored reflection notes. ' + 'You will begin this mindful exploration from the initial deck.', + style: text.bodyMedium, + ), + const SizedBox(height: 14), + Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: c.surfaceContainer, + borderRadius: BorderRadius.circular(16), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.lightbulb_outline, + size: 18, color: c.secondary), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Tip: You can pause here and revisit your values whenever you need clarity in daily choices without resetting.', + style: text.bodySmall, + ), + ), + ], + ), + ), + const SizedBox(height: 18), + PrimaryPillButton( + label: 'Yes, Reset All ${sort.totalCount} Cards', + onPressed: () => Navigator.pop(ctx, true), + ), + const SizedBox(height: 8), + GhostPillButton( + label: 'Keep My Current Landscape', + onPressed: () => Navigator.pop(ctx, false), + ), + ], + ), + ), + ); + }, + ); + if (ok == true) sort.restart(); + } +} + +class _CoreValuesCard extends StatelessWidget { + const _CoreValuesCard({ + required this.values, + required this.onValueTap, + }); + + final List values; + final void Function(ValueCard card) onValueTap; + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + final accent = colors.secondary; + + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: colors.surfaceContainerLow, + borderRadius: BorderRadius.circular(22), + border: Border.all(color: colors.outlineVariant.withValues(alpha: 0.7)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: 28, + height: 28, + decoration: BoxDecoration( + color: accent.withValues(alpha: 0.18), + shape: BoxShape.circle, + ), + child: Icon(Icons.star, size: 15, color: accent), + ), + const SizedBox(width: 10), + Expanded( + child: Text( + 'Your Core Values', + style: text.titleLarge?.copyWith( + color: colors.onSurface, + fontWeight: FontWeight.w400, + ), + ), + ), + ], + ), + const SizedBox(height: 14), + if (values.isEmpty) + Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Text( + 'Rank your Most Important values to distill your core set here.', + style: text.bodyMedium?.copyWith( + color: colors.onSurfaceVariant, + ), + ), + ) + else + LayoutBuilder( + builder: (context, constraints) { + final gap = 8.0; + final chipWidth = (constraints.maxWidth - gap) / 2; + return Wrap( + spacing: gap, + runSpacing: gap, + children: [ + for (var i = 0; i < values.length; i++) + SizedBox( + width: chipWidth, + child: _CoreValueChip( + rank: i + 1, + title: values[i].title, + accent: accent, + onTap: () => onValueTap(values[i]), + ), + ), + ], + ); + }, + ), + ], + ), + ); + } +} + +class _CoreValueChip extends StatelessWidget { + const _CoreValueChip({ + required this.rank, + required this.title, + required this.accent, + required this.onTap, + }); + + final int rank; + final String title; + final Color accent; + final VoidCallback onTap; + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return Material( + color: colors.surfaceContainer, + borderRadius: BorderRadius.circular(14), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(14), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), + child: Row( + children: [ + Container( + width: 22, + height: 22, + alignment: Alignment.center, + decoration: BoxDecoration( + color: accent.withValues(alpha: 0.18), + shape: BoxShape.circle, + ), + child: Text( + '$rank', + style: text.labelSmall?.copyWith( + color: accent, + fontWeight: FontWeight.w700, + ), + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: text.labelMedium?.copyWith( + color: colors.onSurface, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + ), + ); + } +} + +class _GatewayCard extends StatelessWidget { + const _GatewayCard({ + required this.icon, + required this.iconColor, + required this.title, + required this.onTap, + this.meta, + this.metaBackground, + this.metaForeground, + this.progress, + }); + + final IconData icon; + final Color iconColor; + final String title; + final String? meta; + final Color? metaBackground; + final Color? metaForeground; + final VoidCallback? onTap; + final double? progress; + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + final enabled = onTap != null; + final hasMeta = meta != null && meta!.isNotEmpty; + + return Opacity( + opacity: enabled ? 1 : 0.55, + child: Material( + color: colors.surfaceContainerLow, + elevation: 0, + shadowColor: colors.shadow.withValues(alpha: 0.08), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(20), + child: Padding( + padding: const EdgeInsets.all(18), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: colors.surfaceContainerHigh, + shape: BoxShape.circle, + ), + child: Icon(icon, color: iconColor, size: 22), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + title, + style: text.titleLarge?.copyWith( + color: colors.onSurface, + fontWeight: FontWeight.w400, + ), + ), + if (hasMeta) ...[ + const SizedBox(height: 6), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 3, + ), + decoration: BoxDecoration( + color: metaBackground ?? colors.surfaceContainer, + borderRadius: BorderRadius.circular(999), + ), + child: Text( + meta!, + style: text.labelSmall?.copyWith( + color: metaForeground ?? colors.onSurfaceVariant, + ), + ), + ), + ], + ], + ), + ), + Icon( + Icons.arrow_forward, + color: colors.primary, + size: 22, + ), + ], + ), + if (progress != null) ...[ + const SizedBox(height: 14), + ClipRRect( + borderRadius: BorderRadius.circular(999), + child: LinearProgressIndicator( + value: progress, + minHeight: 6, + backgroundColor: colors.surfaceContainerHighest, + color: colors.tertiary, + ), + ), + ], + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/profile_screen.dart b/lib/screens/profile_screen.dart deleted file mode 100644 index b727639..0000000 --- a/lib/screens/profile_screen.dart +++ /dev/null @@ -1,142 +0,0 @@ -/// Profile tab: avatar, stats, and a shortcut to the add-item form. -library; - -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import '../providers/item_provider.dart'; -import '../providers/theme_provider.dart'; -import '../utils/constants.dart'; -import '../utils/helpers.dart'; -import '../widgets/responsive_body.dart'; -import 'add_item_screen.dart'; - -class ProfileScreen extends StatelessWidget { - const ProfileScreen({super.key}); - - @override - Widget build(BuildContext context) { - final items = context.watch(); - final themeController = context.watch(); - final theme = Theme.of(context); - final colors = theme.colorScheme; - - return Scaffold( - appBar: AppBar(title: const Text('Profile')), - body: ResponsiveBody( - child: ListView( - children: [ - const SizedBox(height: 12), - Center( - child: CircleAvatar( - radius: 44, - backgroundColor: colors.primaryContainer, - child: Icon( - Icons.person, - size: 44, - color: colors.onPrimaryContainer, - ), - ), - ), - const SizedBox(height: 16), - Text( - 'Alex Rivera', - textAlign: TextAlign.center, - style: theme.textTheme.headlineMedium, - ), - const SizedBox(height: 4), - Text( - 'alex@example.com', - textAlign: TextAlign.center, - style: theme.textTheme.bodyMedium, - ), - const SizedBox(height: 24), - Row( - children: [ - Expanded( - child: _ProfileStat( - label: 'Items', - value: '${items.count}', - ), - ), - const SizedBox(width: 12), - Expanded( - child: _ProfileStat( - label: 'Theme', - value: labelForThemeMode(themeController.themeMode), - ), - ), - const SizedBox(width: 12), - Expanded( - child: _ProfileStat( - label: 'Source', - value: items.useRemoteData ? 'Remote' : 'Local', - ), - ), - ], - ), - const SizedBox(height: 24), - Card( - child: Column( - children: [ - ListTile( - leading: const Icon(Icons.add_box_outlined), - title: const Text('Add a catalog item'), - subtitle: const Text('Validated form with category picker'), - trailing: const Icon(Icons.chevron_right), - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => const AddItemScreen(), - ), - ); - }, - ), - const Divider(height: 1), - const ListTile( - leading: Icon(Icons.info_outline), - title: Text('About'), - subtitle: Text('$kAppName · $kPackageName'), - ), - ], - ), - ), - ], - ), - ), - ); - } -} - -class _ProfileStat extends StatelessWidget { - const _ProfileStat({required this.label, required this.value}); - - final String label; - final String value; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - return Container( - padding: const EdgeInsets.symmetric(vertical: 16), - decoration: BoxDecoration( - color: theme.colorScheme.surfaceContainerLow, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: theme.shadowColor.withValues(alpha: 0.06), - blurRadius: 12, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - Text(value, style: theme.textTheme.titleLarge), - const SizedBox(height: 4), - Text(label, style: theme.textTheme.labelMedium), - ], - ), - ); - } -} diff --git a/lib/screens/rank_order_screen.dart b/lib/screens/rank_order_screen.dart new file mode 100644 index 0000000..25ba0d0 --- /dev/null +++ b/lib/screens/rank_order_screen.dart @@ -0,0 +1,191 @@ +/// Rank-order the Most Important nominees into a personal hierarchy. +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../providers/values_sort_provider.dart'; +import '../widgets/practice_chrome.dart'; + +class RankOrderScreen extends StatelessWidget { + const RankOrderScreen({super.key}); + + @override + Widget build(BuildContext context) { + final sort = context.watch(); + final ranked = sort.rankedCards; + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return PracticeScaffold( + header: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 0), + child: Row( + children: [ + IconButton( + onPressed: sort.goToHub, + icon: const Icon(Icons.arrow_back), + ), + Expanded( + child: Text( + 'Stage 3 · Prioritization', + style: text.labelMedium, + ), + ), + ], + ), + ), + footer: PrimaryPillButton( + label: 'Reflect on top values', + icon: Icons.spa_outlined, + onPressed: ranked.isEmpty ? null : sort.goToReflection, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Order Your Core Values', style: text.displaySmall), + const SizedBox(height: 6), + Text( + 'Drag or reorder your finalists. Let #1 represent your non-negotiable value.', + style: text.bodyMedium, + ), + const SizedBox(height: 12), + if (ranked.isEmpty) + Expanded( + child: Center( + child: Text( + 'Promote a few values into Most Important first.', + style: text.bodyLarge?.copyWith(color: colors.onSurfaceVariant), + textAlign: TextAlign.center, + ), + ), + ) + else + Expanded( + child: ReorderableListView.builder( + itemCount: ranked.length, + onReorderItem: sort.reorderRanked, + proxyDecorator: (child, index, animation) { + return Material( + elevation: 6, + color: Colors.transparent, + shadowColor: const Color(0x332C2825), + child: child, + ); + }, + itemBuilder: (context, index) { + final card = ranked[index]; + final isPrimary = index == 0; + return Container( + key: ValueKey(card.id), + margin: const EdgeInsets.only(bottom: 10), + padding: const EdgeInsets.fromLTRB(12, 12, 4, 12), + decoration: BoxDecoration( + color: isPrimary + ? colors.surfaceContainerLowest + : colors.surfaceContainerLow, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: isPrimary + ? colors.secondary.withValues(alpha: 0.5) + : colors.outlineVariant, + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 36, + child: Column( + children: [ + Text( + '${index + 1}', + style: text.titleLarge?.copyWith( + color: isPrimary + ? colors.secondary + : colors.primary, + ), + ), + if (isPrimary) + Icon( + Icons.star, + size: 14, + color: colors.secondary, + ), + ], + ), + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + card.title, + style: text.titleLarge?.copyWith( + color: colors.onSurface, + ), + ), + const SizedBox(height: 4), + Text( + card.description, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: text.bodyMedium?.copyWith( + color: colors.onSurfaceVariant, + ), + ), + const SizedBox(height: 4), + Text( + 'Pillar: ${card.domain}', + style: text.labelSmall?.copyWith( + color: colors.onSurfaceVariant, + ), + ), + + ], + ), + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints( + minWidth: 32, + minHeight: 28, + ), + onPressed: () => sort.moveRank(index, up: true), + icon: const Icon(Icons.keyboard_arrow_up, size: 22), + ), + ReorderableDragStartListener( + index: index, + child: const Padding( + padding: EdgeInsets.symmetric(vertical: 2), + child: Icon(Icons.drag_indicator, size: 22), + ), + ), + IconButton( + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints( + minWidth: 32, + minHeight: 28, + ), + onPressed: () => sort.moveRank(index, up: false), + icon: const Icon(Icons.keyboard_arrow_down, size: 22), + ), + ], + ), + ], + ), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/reflection_screen.dart b/lib/screens/reflection_screen.dart new file mode 100644 index 0000000..c4e09ac --- /dev/null +++ b/lib/screens/reflection_screen.dart @@ -0,0 +1,298 @@ +/// Deep reflection on top values, with optional full-screen journal sheet. +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../providers/values_sort_provider.dart'; +import '../widgets/practice_chrome.dart'; + +class ReflectionScreen extends StatelessWidget { + const ReflectionScreen({super.key}); + + @override + Widget build(BuildContext context) { + final sort = context.watch(); + final cores = sort.coreValues; + final activeId = sort.activeReflectionValueId ?? + (cores.isEmpty ? null : cores.first.id); + final active = activeId == null ? null : sort.cardById(activeId); + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return PracticeScaffold( + header: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 0), + child: Row( + children: [ + IconButton( + onPressed: sort.goToHub, + icon: const Icon(Icons.arrow_back), + ), + Expanded( + child: Text( + 'Step 5 · Deep Reflection', + style: text.labelMedium, + ), + ), + ], + ), + ), + child: cores.isEmpty || active == null + ? Center( + child: Text( + 'Rank at least one core value to reflect.', + style: text.bodyLarge, + ), + ) + : ListView( + children: [ + Text('Your Core Values', style: text.displaySmall), + const SizedBox(height: 4), + Text( + '${cores.length} core anchors · ' + '${sort.totalAnsweredReflections} of ${sort.totalReflectionSlots} answered', + style: text.bodyMedium, + ), + const SizedBox(height: 14), + SizedBox( + height: 88, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: cores.length, + separatorBuilder: (_, _) => const SizedBox(width: 8), + itemBuilder: (context, index) { + final card = cores[index]; + final selected = card.id == active.id; + final answered = sort.answeredPromptCount(card.id); + final rankColor = + selected ? colors.onPrimary : colors.secondary; + final titleColor = + selected ? colors.onPrimary : colors.onSurface; + final metaColor = selected + ? colors.onPrimary.withValues(alpha: 0.85) + : colors.onSurfaceVariant; + return InkWell( + onTap: () => sort.selectReflectionValue(card.id), + borderRadius: BorderRadius.circular(16), + child: Container( + width: 120, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: selected + ? colors.primary + : colors.surfaceContainerLow, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: selected + ? colors.primary + : colors.outlineVariant, + width: selected ? 2 : 1, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '#${index + 1}', + style: text.labelSmall?.copyWith( + color: rankColor, + fontWeight: FontWeight.w700, + ), + ), + Text( + card.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: text.titleMedium?.copyWith( + color: titleColor, + fontWeight: selected + ? FontWeight.w700 + : FontWeight.w500, + ), + ), + Text( + '$answered/${kReflectionPrompts.length}', + style: text.labelSmall?.copyWith( + color: metaColor, + ), + ), + ], + ), + ), + ); + }, + ), + ), + const SizedBox(height: 18), + Text(active.title, style: text.headlineMedium), + const SizedBox(height: 4), + Text( + '"${active.description}"', + style: text.bodyMedium?.copyWith(fontStyle: FontStyle.italic), + ), + const SizedBox(height: 16), + ...List.generate(kReflectionPrompts.length, (index) { + final answer = sort.reflectionFor(active.id, index); + final answered = answer.isNotEmpty; + return Padding( + padding: const EdgeInsets.only(bottom: 10), + child: Material( + color: colors.surfaceContainerLow, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18), + side: BorderSide(color: colors.outlineVariant), + ), + child: ListTile( + leading: Icon( + answered ? Icons.check_circle : Icons.circle_outlined, + color: answered + ? colors.tertiary + : colors.onSurfaceVariant, + ), + title: Text( + kReflectionPrompts[index], + style: text.titleMedium, + ), + subtitle: answered + ? Text( + answer, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ) + : null, + trailing: Icon( + answered ? Icons.edit_outlined : Icons.open_in_full, + ), + onTap: () => _openJournal( + context, + sort, + active.id, + index, + ), + ), + ), + ); + }), + ], + ), + ); + } + + Future _openJournal( + BuildContext context, + ValuesSortController sort, + String valueId, + int promptIndex, + ) async { + sort.selectPrompt(promptIndex); + final card = sort.cardById(valueId); + if (card == null) return; + + await showModalBottomSheet( + context: context, + isScrollControlled: true, + useSafeArea: true, + builder: (ctx) => _ReflectionJournalSheet( + cardTitle: card.title, + prompt: kReflectionPrompts[promptIndex], + initialText: sort.reflectionFor(valueId, promptIndex), + onSave: (text) { + sort.setReflection(valueId, promptIndex, text); + }, + ), + ); + } +} + +class _ReflectionJournalSheet extends StatefulWidget { + const _ReflectionJournalSheet({ + required this.cardTitle, + required this.prompt, + required this.initialText, + required this.onSave, + }); + + final String cardTitle; + final String prompt; + final String initialText; + final ValueChanged onSave; + + @override + State<_ReflectionJournalSheet> createState() => + _ReflectionJournalSheetState(); +} + +class _ReflectionJournalSheetState extends State<_ReflectionJournalSheet> { + late final TextEditingController _controller; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(text: widget.initialText); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + void _saveAndClose() { + widget.onSave(_controller.text); + Navigator.of(context).pop(); + } + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + final bottom = MediaQuery.viewInsetsOf(context).bottom; + + return Padding( + padding: EdgeInsets.fromLTRB(20, 8, 20, bottom + 20), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Text( + 'Reflection · ${widget.cardTitle}', + style: text.titleLarge, + ), + ), + IconButton( + onPressed: () => Navigator.pop(context), + icon: const Icon(Icons.close), + ), + ], + ), + Align( + alignment: Alignment.centerLeft, + child: Text( + widget.prompt, + style: text.bodyLarge?.copyWith(color: colors.onSurfaceVariant), + ), + ), + const SizedBox(height: 12), + Expanded( + child: TextField( + controller: _controller, + expands: true, + maxLines: null, + textAlignVertical: TextAlignVertical.top, + decoration: const InputDecoration( + hintText: 'Write freely. This stays on your device.', + ), + ), + ), + const SizedBox(height: 12), + PrimaryPillButton( + label: 'Save reflection', + onPressed: _saveAndClose, + ), + ], + ), + ); + } +} diff --git a/lib/screens/search_screen.dart b/lib/screens/search_screen.dart deleted file mode 100644 index fcabda3..0000000 --- a/lib/screens/search_screen.dart +++ /dev/null @@ -1,104 +0,0 @@ -/// Search tab: query field plus a [ListView.builder] of matching items. -library; - -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import '../models/item.dart'; -import '../providers/item_provider.dart'; -import '../widgets/empty_state.dart'; -import '../widgets/item_card.dart'; -import '../widgets/responsive_body.dart'; - -class SearchScreen extends StatefulWidget { - const SearchScreen({super.key}); - - @override - State createState() => _SearchScreenState(); -} - -class _SearchScreenState extends State { - final _query = TextEditingController(); - - @override - void dispose() { - _query.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final results = context.watch().search(_query.text); - - return Scaffold( - appBar: AppBar(title: const Text('Search')), - body: ResponsiveBody( - child: Column( - children: [ - const SizedBox(height: 8), - TextField( - controller: _query, - textInputAction: TextInputAction.search, - onChanged: (_) => setState(() {}), - decoration: InputDecoration( - hintText: 'Title, summary, or category', - prefixIcon: const Icon(Icons.search), - suffixIcon: _query.text.isEmpty - ? null - : IconButton( - tooltip: 'Clear', - onPressed: () { - _query.clear(); - setState(() {}); - }, - icon: const Icon(Icons.close), - ), - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: Text( - '${results.length} result${results.length == 1 ? '' : 's'}', - style: Theme.of(context).textTheme.labelMedium, - ), - ), - const SizedBox(height: 8), - Expanded(child: _ResultsList(results: results, query: _query.text)), - ], - ), - ), - ); - } -} - -class _ResultsList extends StatelessWidget { - const _ResultsList({required this.results, required this.query}); - - final List results; - final String query; - - @override - Widget build(BuildContext context) { - if (results.isEmpty) { - return EmptyState( - icon: Icons.search_off, - title: query.trim().isEmpty ? 'Start typing' : 'No matches', - message: query.trim().isEmpty - ? 'Search the catalog by title, summary, or category.' - : 'Try a different keyword.', - ); - } - - return ListView.builder( - padding: const EdgeInsets.only(bottom: 24), - itemCount: results.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(bottom: 12), - child: ItemCard(item: results[index], heroScope: 'search'), - ); - }, - ); - } -} diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart deleted file mode 100644 index 35b0c9b..0000000 --- a/lib/screens/settings_screen.dart +++ /dev/null @@ -1,104 +0,0 @@ -/// Settings tab: theme mode, data source, and about information. -library; - -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import '../providers/item_provider.dart'; -import '../providers/theme_provider.dart'; -import '../utils/constants.dart'; -import '../utils/helpers.dart'; -import '../widgets/responsive_body.dart'; - -class SettingsScreen extends StatelessWidget { - const SettingsScreen({super.key}); - - @override - Widget build(BuildContext context) { - final themeController = context.watch(); - final items = context.watch(); - final theme = Theme.of(context); - - return Scaffold( - appBar: AppBar(title: const Text('Settings')), - body: ResponsiveBody( - child: ListView( - children: [ - const SizedBox(height: 8), - Text('Appearance', style: theme.textTheme.titleMedium), - const SizedBox(height: 8), - Text( - 'Theme is saved with shared_preferences and restored on launch.', - style: theme.textTheme.bodyMedium, - ), - const SizedBox(height: 16), - SegmentedButton( - segments: const [ - ButtonSegment( - value: ThemeMode.system, - label: Text('System'), - icon: Icon(Icons.brightness_auto), - ), - ButtonSegment( - value: ThemeMode.light, - label: Text('Light'), - icon: Icon(Icons.light_mode_outlined), - ), - ButtonSegment( - value: ThemeMode.dark, - label: Text('Dark'), - icon: Icon(Icons.dark_mode_outlined), - ), - ], - selected: {themeController.themeMode}, - onSelectionChanged: (selection) { - themeController.setThemeMode(selection.first); - }, - ), - const SizedBox(height: 28), - Text('Data', style: theme.textTheme.titleMedium), - const SizedBox(height: 8), - Card( - child: SwitchListTile( - title: const Text('Use remote sample API'), - subtitle: const Text( - 'When on, items are fetched with the http package from ' - 'JSONPlaceholder. Failures fall back to local mock data.', - ), - value: items.useRemoteData, - onChanged: (value) => items.setUseRemoteData(value), - ), - ), - const SizedBox(height: 28), - Text('About', style: theme.textTheme.titleMedium), - const SizedBox(height: 8), - Card( - child: Column( - children: [ - const ListTile( - leading: Icon(Icons.apps), - title: Text(kAppName), - subtitle: Text('Generic Flutter Android starter'), - ), - const Divider(height: 1), - const ListTile( - leading: Icon(Icons.fingerprint), - title: Text('Package'), - subtitle: Text(kPackageName), - ), - const Divider(height: 1), - ListTile( - leading: const Icon(Icons.contrast), - title: const Text('Active theme'), - subtitle: Text(labelForThemeMode(themeController.themeMode)), - ), - ], - ), - ), - const SizedBox(height: 24), - ], - ), - ), - ); - } -} diff --git a/lib/screens/sorted_overview_screen.dart b/lib/screens/sorted_overview_screen.dart new file mode 100644 index 0000000..ceabdc7 --- /dev/null +++ b/lib/screens/sorted_overview_screen.dart @@ -0,0 +1,289 @@ +/// Bird's-eye overview of all five piles with demote / refine actions. +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../models/value_card.dart'; +import '../models/value_pile.dart'; +import '../providers/values_sort_provider.dart'; +import '../widgets/practice_chrome.dart'; +import '../widgets/value_card_tile.dart'; + +class SortedOverviewScreen extends StatefulWidget { + const SortedOverviewScreen({super.key}); + + @override + State createState() => _SortedOverviewScreenState(); +} + +class _SortedOverviewScreenState extends State { + String _query = ''; + ValuePile? _filter; + + @override + Widget build(BuildContext context) { + final sort = context.watch(); + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return PracticeScaffold( + header: Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 12, 0), + child: Row( + children: [ + IconButton( + onPressed: sort.goToHub, + icon: const Icon(Icons.arrow_back), + ), + Expanded( + child: Text( + 'All Sorted Values', + style: text.labelMedium, + ), + ), + ], + ), + ), + child: ListView( + children: [ + Text('All Sorted Values', style: text.displaySmall), + const SizedBox(height: 16), + TextField( + onChanged: (v) => setState(() => _query = v.trim().toLowerCase()), + decoration: const InputDecoration( + hintText: 'Find a value (e.g., Creativity)', + prefixIcon: Icon(Icons.search), + ), + ), + const SizedBox(height: 10), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + _FilterChip( + label: 'All (${sort.totalCount})', + selected: _filter == null, + onTap: () => setState(() => _filter = null), + ), + ...ValuePile.values.map((pile) { + return _FilterChip( + label: '${pile.shortLabel} (${sort.countInPile(pile)})', + selected: _filter == pile, + accent: pile.accent, + onTap: () => setState(() => _filter = pile), + ); + }), + ], + ), + ), + const SizedBox(height: 18), + ...ValuePile.values + .where((p) => _filter == null || _filter == p) + .map((pile) { + final cards = sort.cardsInPile(pile).where((c) { + if (_query.isEmpty) return true; + return c.title.toLowerCase().contains(_query) || + c.description.toLowerCase().contains(_query); + }).toList(); + + return _PileSection( + pile: pile, + cards: cards, + onDemote: (card) => _showDemoteSheet(context, sort, card), + ); + }), + const SizedBox(height: 12), + Text( + 'Tip: refine any pile before ranking your core values.', + style: text.bodySmall?.copyWith(color: colors.onSurfaceVariant), + textAlign: TextAlign.center, + ), + ], + ), + ); + } + + Future _showDemoteSheet( + BuildContext context, + ValuesSortController sort, + ValueCard card, + ) async { + await showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (ctx) { + final text = Theme.of(ctx).textTheme; + final colors = Theme.of(ctx).colorScheme; + final maxHeight = MediaQuery.sizeOf(ctx).height * 0.75; + return SafeArea( + child: ConstrainedBox( + constraints: BoxConstraints(maxHeight: maxHeight), + child: SingleChildScrollView( + padding: EdgeInsets.fromLTRB( + 24, + 8, + 24, + MediaQuery.paddingOf(ctx).bottom + 24, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + 'Reorder ${card.title}', + style: text.titleLarge, + ), + ), + IconButton( + onPressed: () => Navigator.pop(ctx), + icon: const Icon(Icons.close), + ), + ], + ), + Text('Move to pile:', style: text.bodyMedium), + const SizedBox(height: 8), + ...ValuePile.values.map((pile) { + final current = sort.assignments[card.id] == pile; + return ListTile( + contentPadding: EdgeInsets.zero, + enabled: !current, + leading: CircleAvatar( + backgroundColor: pile.accent.withValues(alpha: 0.2), + child: Text( + '${pile.rank}', + style: text.labelMedium?.copyWith(color: pile.accent), + ), + ), + title: Text(pile.label), + subtitle: Text(pile.subtitle), + trailing: current + ? Icon(Icons.check, color: colors.primary) + : Icon(Icons.arrow_forward, color: colors.onSurfaceVariant), + onTap: current + ? null + : () { + sort.moveCard(card.id, pile); + Navigator.pop(ctx); + }, + ); + }), + ], + ), + ), + ), + ); + }, + ); + } +} + +class _FilterChip extends StatelessWidget { + const _FilterChip({ + required this.label, + required this.selected, + required this.onTap, + this.accent, + }); + + final String label; + final bool selected; + final VoidCallback onTap; + final Color? accent; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + final labelColor = selected ? colors.onPrimary : colors.onSurface; + return Padding( + padding: const EdgeInsets.only(right: 8), + child: ChoiceChip( + label: Text(label), + selected: selected, + onSelected: (_) => onTap(), + showCheckmark: true, + checkmarkColor: colors.onPrimary, + selectedColor: colors.primary, + backgroundColor: colors.surfaceContainer, + labelStyle: Theme.of(context).textTheme.labelMedium?.copyWith( + color: labelColor, + fontWeight: selected ? FontWeight.w700 : FontWeight.w500, + ), + side: BorderSide( + color: selected + ? colors.primary + : (accent ?? colors.outlineVariant), + ), + ), + ); + } +} + +class _PileSection extends StatelessWidget { + const _PileSection({ + required this.pile, + required this.cards, + required this.onDemote, + }); + + final ValuePile pile; + final List cards; + final void Function(ValueCard card) onDemote; + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + + return Padding( + padding: const EdgeInsets.only(bottom: 22), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.circle, size: 12, color: pile.accent), + const SizedBox(width: 8), + Expanded( + child: Text( + '${pile.label} · ${cards.length} cards', + style: text.titleLarge, + ), + ), + ], + ), + const SizedBox(height: 8), + if (pile == ValuePile.mostImportant) + ...cards.map( + (card) => Padding( + padding: const EdgeInsets.only(bottom: 10), + child: ValueCardTile( + card: card, + compact: true, + trailing: TextButton( + onPressed: () => onDemote(card), + child: const Text('Reorder'), + ), + ), + ), + ) + else + Wrap( + spacing: 8, + runSpacing: 8, + children: cards + .map( + (c) => ValueChip( + title: c.title, + onTap: () => onDemote(c), + ), + ) + .toList(), + ), + ], + ), + ); + } +} diff --git a/lib/screens/splash_screen.dart b/lib/screens/splash_screen.dart index 3e7df2d..e32bc98 100644 --- a/lib/screens/splash_screen.dart +++ b/lib/screens/splash_screen.dart @@ -1,12 +1,12 @@ -/// First route shown after launch. Hands off to [MainShell] after a short delay. +/// First route shown after launch. Hands off to the practice flow. library; import 'package:flutter/material.dart'; import '../utils/constants.dart'; -import 'main_shell.dart'; +import 'practice_flow_screen.dart'; -/// Branded splash with a fade-in logo. Replaced by the bottom-nav shell. +/// Soft branded splash before the welcome screen. class SplashScreen extends StatefulWidget { const SplashScreen({super.key}); @@ -32,17 +32,17 @@ class _SplashScreenState extends State CurvedAnimation(parent: _controller, curve: Curves.easeOutBack), ); _controller.forward(); - _goToShell(); + _goToPractice(); } - Future _goToShell() async { + Future _goToPractice() async { await Future.delayed(kSplashDuration); if (!mounted) return; Navigator.of(context).pushReplacement( PageRouteBuilder( pageBuilder: (_, animation, _) => FadeTransition( opacity: animation, - child: const MainShell(), + child: const PracticeFlowScreen(), ), transitionDuration: const Duration(milliseconds: 400), ), @@ -57,20 +57,27 @@ class _SplashScreenState extends State @override Widget build(BuildContext context) { - final colors = Theme.of(context).colorScheme; final textTheme = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + final isDark = colors.brightness == Brightness.dark; return Scaffold( body: DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - colors.primary, - colors.primaryContainer, - colors.tertiary, - ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: isDark + ? [ + colors.surface, + colors.surfaceContainerLow, + colors.surfaceContainer, + ] + : [ + colors.surface, + colors.surfaceContainerLow, + const Color(0xFFE8DFD2), + ], ), ), child: SafeArea( @@ -82,31 +89,36 @@ class _SplashScreenState extends State child: Column( mainAxisSize: MainAxisSize.min, children: [ - Container( - width: 88, - height: 88, - decoration: BoxDecoration( - color: colors.onPrimary.withValues(alpha: 0.16), - borderRadius: BorderRadius.circular(24), - ), - child: Icon( - Icons.layers_rounded, - size: 44, - color: colors.onPrimary, + ClipOval( + child: Image.asset( + 'assets/images/emblem.png', + width: 88, + height: 88, + fit: BoxFit.cover, + errorBuilder: (_, _, _) => Container( + width: 88, + height: 88, + color: colors.primaryContainer, + child: const Icon( + Icons.spa, + size: 44, + color: Colors.white, + ), + ), ), ), const SizedBox(height: 24), Text( kAppName, style: textTheme.displaySmall?.copyWith( - color: colors.onPrimary, + color: colors.onSurface, ), ), const SizedBox(height: 8), Text( - 'A Material 3 starter template', + 'Clarify what guides you', style: textTheme.bodyLarge?.copyWith( - color: colors.onPrimary.withValues(alpha: 0.85), + color: colors.onSurfaceVariant, ), ), const SizedBox(height: 40), @@ -115,7 +127,7 @@ class _SplashScreenState extends State height: 28, child: CircularProgressIndicator( strokeWidth: 3, - color: colors.onPrimary, + color: colors.primary, ), ), ], diff --git a/lib/screens/welcome_screen.dart b/lib/screens/welcome_screen.dart new file mode 100644 index 0000000..e380f4b --- /dev/null +++ b/lib/screens/welcome_screen.dart @@ -0,0 +1,360 @@ +/// Welcome screen with stacked sample cards and guide drawer. +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../providers/values_sort_provider.dart'; +import '../utils/app_theme.dart'; +import '../widgets/practice_chrome.dart'; + +class WelcomeScreen extends StatelessWidget { + const WelcomeScreen({super.key}); + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return PracticeScaffold( + header: const Padding( + padding: EdgeInsets.fromLTRB(12, 0, 12, 0), + child: BrandMark(), + ), + footer: Column( + children: [ + GhostPillButton( + label: 'How this practice works', + icon: Icons.info_outline, + onPressed: () => _showGuide(context), + ), + PrimaryPillButton( + label: 'Begin Reflection', + icon: Icons.arrow_forward, + onPressed: () => + context.read().beginPractice(), + ), + ], + ), + child: ListView( + children: [ + const SizedBox(height: 8), + const _CardFan(), + const SizedBox(height: 20), + Text( + 'Discover what matters most to you', + textAlign: TextAlign.center, + style: text.displaySmall, + ), + const SizedBox(height: 10), + Text( + 'Through a gentle, guided card-sort practice, clarify your intrinsic ' + 'values and illuminate the principles that guide your everyday decisions.', + textAlign: TextAlign.center, + style: text.bodyLarge?.copyWith(color: colors.onSurfaceVariant), + ), + const SizedBox(height: 18), + Wrap( + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 8, + runSpacing: 6, + children: [ + _Meta(icon: Icons.schedule, label: '10–15 min'), + Text('•', style: text.labelMedium), + _Meta(icon: Icons.timelapse, label: 'Self-paced'), + Text('•', style: text.labelMedium), + _Meta(icon: Icons.lock_outline, label: 'Private & reflective'), + ], + ), + ], + ), + ); + } + + Future _showGuide(BuildContext context) async { + final controller = context.read(); + await showModalBottomSheet( + context: context, + isScrollControlled: true, + builder: (ctx) { + final text = Theme.of(ctx).textTheme; + final colors = Theme.of(ctx).colorScheme; + return Padding( + padding: EdgeInsets.only( + left: 24, + right: 24, + top: 8, + bottom: MediaQuery.paddingOf(ctx).bottom + 24, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.diversity_3, color: colors.tertiary), + const SizedBox(width: 8), + Expanded( + child: Text( + 'The Practice of Sorting', + style: text.titleLarge, + ), + ), + IconButton( + onPressed: () => Navigator.pop(ctx), + icon: const Icon(Icons.close), + ), + ], + ), + const SizedBox(height: 8), + Text( + 'Grounded in contemplative psychology, this sorting practice ' + 'helps clarify the core tenets that give your life meaning and direction.', + style: text.bodyLarge?.copyWith(color: colors.onSurfaceVariant), + ), + const SizedBox(height: 16), + const _GuideStep( + index: 1, + title: 'One card at a time', + body: + 'Review cards with diverse values one at a time, checking in with your intuition without overthinking.', + ), + const _GuideStep( + index: 2, + title: 'Sort into reflective piles', + body: + 'Place each card into Most, Very, Important, Somewhat, or Not Important — trusting your first honest response.', + ), + const _GuideStep( + index: 3, + title: 'Distill your top values', + body: + 'Narrow down to your core top values, then reflect so they can guide daily decisions with clarity.', + ), + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: AppTheme.surfaceContainerLow, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: AppTheme.outlineVariant), + ), + child: Row( + children: [ + Icon(Icons.spa, color: colors.tertiary, size: 18), + const SizedBox(width: 10), + Expanded( + child: Text( + 'There are no right or wrong answers—only your authentic presence.', + style: text.bodyMedium?.copyWith( + fontStyle: FontStyle.italic, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + PrimaryPillButton( + label: "Got it, let's begin", + onPressed: () { + Navigator.pop(ctx); + controller.beginPractice(); + }, + ), + ], + ), + ); + }, + ); + } +} + +class _Meta extends StatelessWidget { + const _Meta({required this.icon, required this.label}); + + final IconData icon; + final String label; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + final text = Theme.of(context).textTheme; + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(icon, size: 15, color: colors.tertiary), + const SizedBox(width: 4), + Text(label, style: text.labelMedium), + ], + ); + } +} + +class _GuideStep extends StatelessWidget { + const _GuideStep({ + required this.index, + required this.title, + required this.body, + }); + + final int index; + final String title; + final String body; + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + return Padding( + padding: const EdgeInsets.only(bottom: 14), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 12, + backgroundColor: AppTheme.surfaceContainerHigh, + child: Text( + '$index', + style: text.labelMedium?.copyWith( + color: colors.primary, + fontWeight: FontWeight.w700, + ), + ), + ), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: text.titleMedium), + const SizedBox(height: 2), + Text(body, style: text.bodyMedium), + ], + ), + ), + ], + ), + ); + } +} + +class _CardFan extends StatelessWidget { + const _CardFan(); + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + Widget mini({ + required String domain, + required String title, + required String body, + required double angle, + required double dx, + required double dy, + bool hero = false, + }) { + return Transform.translate( + offset: Offset(dx, dy), + child: Transform.rotate( + angle: angle, + child: Container( + width: hero ? 210 : 180, + height: hero ? 155 : 135, + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: hero ? Colors.white : AppTheme.surfaceContainer, + borderRadius: BorderRadius.circular(20), + border: Border.all(color: AppTheme.outlineVariant), + boxShadow: [ + BoxShadow( + color: const Color(0x142C2825), + blurRadius: hero ? 16 : 8, + offset: const Offset(0, 4), + ), + ], + ), + child: ClipRect( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + domain.toUpperCase(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: text.labelSmall?.copyWith( + color: hero ? colors.secondary : colors.onSurfaceVariant, + letterSpacing: 1.2, + ), + ), + ), + if (hero) + Icon(Icons.spa, size: 16, color: colors.primary), + ], + ), + const SizedBox(height: 4), + Text( + title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: (hero ? text.headlineMedium : text.titleLarge) + ?.copyWith(fontSize: hero ? 22 : 18, height: 1.1), + ), + const SizedBox(height: 4), + Expanded( + child: Text( + body, + maxLines: 3, + overflow: TextOverflow.ellipsis, + style: text.bodySmall, + ), + ), + ], + ), + ), + ), + ), + ); + } + + return SizedBox( + height: 210, + child: Stack( + alignment: Alignment.center, + children: [ + mini( + domain: 'Experience', + title: 'Adventure', + body: 'To have new and exciting experiences.', + angle: -0.21, + dx: -48, + dy: 10, + ), + mini( + domain: 'Relation', + title: 'Compassion', + body: 'To feel and act on concern for others.', + angle: 0.21, + dx: 48, + dy: 8, + ), + mini( + domain: 'Core Ground', + title: 'Genuineness', + body: 'To act in a manner that is true to who I am.', + angle: 0.02, + dx: 0, + dy: 4, + hero: true, + ), + ], + ), + ); + } +} diff --git a/lib/services/fake_item_data.dart b/lib/services/fake_item_data.dart deleted file mode 100644 index 9dbcdf9..0000000 --- a/lib/services/fake_item_data.dart +++ /dev/null @@ -1,97 +0,0 @@ -/// In-memory sample catalog used when the app is offline or in mock mode. -library; - -import '../models/item.dart'; - -/// Static starter data so the UI is useful without a network. -abstract final class FakeItemData { - static final List items = [ - Item( - id: 'local-1', - title: 'Material 3 surfaces', - subtitle: 'Use tonal layers instead of heavy drop shadows.', - description: - 'Material 3 prefers surface tints and short, soft shadows. Keep cards ' - 'on surfaceContainerLow, bump the hero to surfaceContainerHighest, and ' - 'reserve elevation for sheets and dialogs.', - category: ItemCategory.design, - createdAt: DateTime(2026, 4, 12), - ), - Item( - id: 'local-2', - title: 'Provider at the root', - subtitle: 'Lift shared state above the widget that consumes it.', - description: - 'Wrap MaterialApp with MultiProvider so ThemeController and ' - 'ItemController survive route changes. Keep UI widgets dumb: they ' - 'read context.watch and call controller methods.', - category: ItemCategory.development, - createdAt: DateTime(2026, 5, 3), - ), - Item( - id: 'local-3', - title: 'Focus on one task', - subtitle: 'A short list beats an overflowing dashboard.', - description: - 'The home screen shows a greeting, a compact stat strip, and a ' - 'ListView.builder of items. Extra tools live one tap away on Search, ' - 'Profile, and Settings.', - category: ItemCategory.productivity, - createdAt: DateTime(2026, 6, 18), - ), - Item( - id: 'local-4', - title: 'Breathable spacing', - subtitle: '16–24px padding and 12px gaps keep cards from crowding.', - description: - 'On compact phones use 16px page padding. From 600px up, step to 24px ' - 'and cap the content width so lines stay readable on tablets.', - category: ItemCategory.lifestyle, - createdAt: DateTime(2026, 7, 1), - ), - Item( - id: 'local-5', - title: 'Hero transitions', - subtitle: 'Match a tag on the list tile and the detail header.', - description: - 'Wrap the leading glyph in a Hero with a stable tag derived from the ' - 'item id. The detail screen reuses the same widget so Flutter can ' - 'animate size and position.', - category: ItemCategory.design, - createdAt: DateTime(2026, 7, 22), - ), - Item( - id: 'local-6', - title: 'Mock first, HTTP later', - subtitle: 'A repository hides whether data is fake or remote.', - description: - 'ItemRepository serves FakeItemData by default and can switch to ' - 'ItemApi (http + JSONPlaceholder) from Settings. Failures fall back ' - 'to the mock list so the UI never goes empty on a demo device.', - category: ItemCategory.development, - createdAt: DateTime(2026, 8, 4), - ), - Item( - id: 'local-7', - title: 'Capture ideas quickly', - subtitle: 'The add-item form validates before it writes.', - description: - 'Title, summary, and description each have a length rule. Category is ' - 'a required dropdown. On success the new item is inserted at the top ' - 'of ItemController so Home and Search update immediately.', - category: ItemCategory.productivity, - createdAt: DateTime(2026, 8, 15), - ), - Item( - id: 'local-8', - title: 'Light and dark equally', - subtitle: 'Seeded ColorSchemes keep contrast in both modes.', - description: - 'ThemeController persists ThemeMode in shared_preferences. The ' - 'settings screen offers System, Light, and Dark. Both schemes come ' - 'from the same teal seed color.', - category: ItemCategory.lifestyle, - createdAt: DateTime(2026, 8, 20), - ), - ]; -} diff --git a/lib/services/item_api.dart b/lib/services/item_api.dart deleted file mode 100644 index 56a417c..0000000 --- a/lib/services/item_api.dart +++ /dev/null @@ -1,61 +0,0 @@ -/// HTTP client placeholder that talks to a public sample API. -library; - -import 'dart:convert'; - -import 'package:http/http.dart' as http; - -import '../models/item.dart'; - -/// Fetches catalog items from JSONPlaceholder. -/// -/// This is intentionally a thin, replaceable client. Swap [baseUrl] and -/// [Item.fromJson] when you point the app at a real backend. -class ItemApi { - ItemApi({http.Client? client, this.baseUrl = defaultBaseUrl}) - : _client = client ?? http.Client(); - - static const defaultBaseUrl = 'https://jsonplaceholder.typicode.com'; - - final http.Client _client; - final String baseUrl; - - /// GET `/posts` and map each record to an [Item]. - Future> fetchItems({int limit = 12}) async { - final uri = Uri.parse('$baseUrl/posts'); - final response = await _client.get( - uri, - headers: const {'Accept': 'application/json'}, - ); - - if (response.statusCode < 200 || response.statusCode >= 300) { - throw ItemApiException( - 'Request failed (${response.statusCode})', - statusCode: response.statusCode, - ); - } - - final decoded = jsonDecode(response.body); - if (decoded is! List) { - throw const ItemApiException('Unexpected response shape'); - } - - return decoded - .whereType>() - .take(limit) - .map(Item.fromJson) - .toList(growable: false); - } - - void close() => _client.close(); -} - -class ItemApiException implements Exception { - const ItemApiException(this.message, {this.statusCode}); - - final String message; - final int? statusCode; - - @override - String toString() => message; -} diff --git a/lib/services/item_repository.dart b/lib/services/item_repository.dart deleted file mode 100644 index 4ae8b48..0000000 --- a/lib/services/item_repository.dart +++ /dev/null @@ -1,50 +0,0 @@ -/// Chooses between mock data and the HTTP client, then returns [Item] lists. -library; - -import '../models/item.dart'; -import 'fake_item_data.dart'; -import 'item_api.dart'; - -/// Single entry point for catalog data. UI code should depend on this type, -/// not on [ItemApi] or [FakeItemData] directly. -class ItemRepository { - ItemRepository({ - ItemApi? api, - this.useRemoteData = false, - }) : _api = api ?? ItemApi(); - - final ItemApi _api; - - /// When true, [fetchItems] hits the network; otherwise it returns local fakes. - bool useRemoteData; - - Future> fetchItems() async { - if (!useRemoteData) { - return List.from(FakeItemData.items); - } - - try { - return await _api.fetchItems(); - } catch (_) { - // Keep the demo usable if the device is offline or the API fails. - return List.from(FakeItemData.items); - } - } - - /// Builds a locally-created item (no network round-trip). - Item createLocal({ - required String title, - required String subtitle, - required String description, - required ItemCategory category, - }) { - return Item( - id: 'local-${DateTime.now().microsecondsSinceEpoch}', - title: title.trim(), - subtitle: subtitle.trim(), - description: description.trim(), - category: category, - createdAt: DateTime.now(), - ); - } -} diff --git a/lib/services/storage_service.dart b/lib/services/storage_service.dart index ea525a5..fef3955 100644 --- a/lib/services/storage_service.dart +++ b/lib/services/storage_service.dart @@ -24,15 +24,20 @@ class StorageService { } String get themeModeName => - _prefs.getString(StorageKeys.themeMode) ?? 'system'; + _prefs.getString(StorageKeys.themeMode) ?? 'light'; Future setThemeModeName(String value) { return _prefs.setString(StorageKeys.themeMode, value); } - bool get useRemoteData => _prefs.getBool(StorageKeys.useRemoteData) ?? false; + /// Serialized Values Sort session JSON, or null when none saved. + String? get sortSessionJson => _prefs.getString(StorageKeys.sortSession); - Future setUseRemoteData(bool value) { - return _prefs.setBool(StorageKeys.useRemoteData, value); + Future setSortSessionJson(String json) { + return _prefs.setString(StorageKeys.sortSession, json); + } + + Future clearSortSession() { + return _prefs.remove(StorageKeys.sortSession); } } diff --git a/lib/utils/app_theme.dart b/lib/utils/app_theme.dart index 2b8d926..fb65ee5 100644 --- a/lib/utils/app_theme.dart +++ b/lib/utils/app_theme.dart @@ -1,75 +1,116 @@ -/// Material 3 light and dark themes, including typography and component styles. +/// Mindful Values Architecture theme — warm surfaces with high-contrast type. library; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; -/// Builds the [ThemeData] used by [MaterialApp] for light and dark mode. -/// -/// Colors are generated from a single seed so both schemes stay consistent -/// with Material 3 tonal palettes. +/// Builds [ThemeData] tuned for readable contrast on warm paper surfaces. abstract final class AppTheme { - static const Color seed = Color(0xFF0F766E); + /// Page canvas — light paper, clearly lighter than elevated cards. + static const Color surface = Color(0xFFFFFBF5); - static ThemeData light() => _build(Brightness.light); + /// Elevated cards / sheets — distinct from the canvas. + static const Color surfaceContainerLow = Color(0xFFFFFFFF); + static const Color surfaceContainer = Color(0xFFF3EDE4); + static const Color surfaceContainerHigh = Color(0xFFE9E2D7); + static const Color surfaceContainerHighest = Color(0xFFDED6C9); - static ThemeData dark() => _build(Brightness.dark); + /// Near-black espresso for primary copy (≈16:1 on surface). + static const Color onSurface = Color(0xFF1A1612); - static ThemeData _build(Brightness brightness) { - final colorScheme = ColorScheme.fromSeed( - seedColor: seed, - brightness: brightness, + /// Secondary copy — still strong on cream (≈9:1). + static const Color onSurfaceVariant = Color(0xFF3F3832); + + /// Icons / meta — darker than the old stone grey. + static const Color outline = Color(0xFF5C534B); + static const Color outlineVariant = Color(0xFFC4B8AA); + + static const Color primary = Color(0xFF4F4032); + static const Color primaryContainer = Color(0xFF6B5848); + static const Color onPrimary = Color(0xFFFFFBF5); + static const Color secondary = Color(0xFF8A3F1C); + static const Color secondaryContainer = Color(0xFFFFD4BC); + static const Color tertiary = Color(0xFF3A5238); + static const Color inverseSurface = Color(0xFF25211D); + + static ThemeData light() { + const colorScheme = ColorScheme( + brightness: Brightness.light, + primary: primary, + onPrimary: onPrimary, + primaryContainer: primaryContainer, + onPrimaryContainer: Color(0xFFFFF3E8), + secondary: secondary, + onSecondary: onPrimary, + secondaryContainer: secondaryContainer, + onSecondaryContainer: Color(0xFF4A1E08), + tertiary: tertiary, + onTertiary: onPrimary, + tertiaryContainer: Color(0xFF5A7358), + onTertiaryContainer: Color(0xFFEAF6E7), + error: Color(0xFFB3261E), + onError: onPrimary, + errorContainer: Color(0xFFFFDAD6), + onErrorContainer: Color(0xFF410002), + surface: surface, + onSurface: onSurface, + surfaceContainerHighest: surfaceContainerHighest, + surfaceContainerHigh: surfaceContainerHigh, + surfaceContainer: surfaceContainer, + surfaceContainerLow: surfaceContainerLow, + surfaceContainerLowest: Color(0xFFFFFFFF), + onSurfaceVariant: onSurfaceVariant, + outline: outline, + outlineVariant: outlineVariant, + inverseSurface: inverseSurface, + onInverseSurface: Color(0xFFF7F1E8), + inversePrimary: Color(0xFFDCC4A8), + shadow: Color(0xFF1A1612), + scrim: Color(0xFF1A1612), ); - final isDark = brightness == Brightness.dark; final textTheme = _textTheme(colorScheme); return ThemeData( useMaterial3: true, colorScheme: colorScheme, textTheme: textTheme, - scaffoldBackgroundColor: colorScheme.surface, + scaffoldBackgroundColor: surface, appBarTheme: AppBarTheme( centerTitle: false, elevation: 0, - scrolledUnderElevation: 1, - backgroundColor: colorScheme.surface, - foregroundColor: colorScheme.onSurface, + scrolledUnderElevation: 0, + backgroundColor: surface, + foregroundColor: onSurface, titleTextStyle: textTheme.titleLarge, ), cardTheme: CardThemeData( elevation: 0, - color: colorScheme.surfaceContainerLow, + color: surfaceContainerLow, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(24), + side: const BorderSide(color: outlineVariant, width: 1.2), ), clipBehavior: Clip.antiAlias, margin: EdgeInsets.zero, ), - navigationBarTheme: NavigationBarThemeData( - elevation: 0, - height: 72, - backgroundColor: colorScheme.surfaceContainer, - indicatorColor: colorScheme.secondaryContainer, - labelTextStyle: WidgetStateProperty.resolveWith((states) { - final selected = states.contains(WidgetState.selected); - return textTheme.labelMedium?.copyWith( - fontWeight: selected ? FontWeight.w600 : FontWeight.w500, - ); - }), - ), inputDecorationTheme: InputDecorationTheme( filled: true, - fillColor: colorScheme.surfaceContainerHighest.withValues(alpha: 0.6), + fillColor: Colors.white, + hintStyle: textTheme.bodyMedium?.copyWith( + color: outline.withValues(alpha: 0.85), + ), border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(16), + borderSide: const BorderSide(color: outlineVariant, width: 1.2), ), enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: colorScheme.outlineVariant), + borderRadius: BorderRadius.circular(16), + borderSide: const BorderSide(color: outlineVariant, width: 1.2), ), focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: colorScheme.primary, width: 2), + borderRadius: BorderRadius.circular(16), + borderSide: const BorderSide(color: primary, width: 1.8), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, @@ -78,93 +119,259 @@ abstract final class AppTheme { ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( - minimumSize: const Size.fromHeight(48), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - textStyle: textTheme.labelLarge, + minimumSize: const Size.fromHeight(52), + backgroundColor: primary, + foregroundColor: onPrimary, + shape: const StadiumBorder(), + textStyle: textTheme.labelLarge?.copyWith(color: onPrimary), + elevation: 0, ), ), - floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: colorScheme.primary, - foregroundColor: colorScheme.onPrimary, + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: onSurface, + textStyle: textTheme.labelMedium?.copyWith( + color: onSurface, + fontWeight: FontWeight.w600, + ), + shape: const StadiumBorder(), + ), + ), + chipTheme: ChipThemeData( + backgroundColor: Colors.white, + selectedColor: surfaceContainerHigh, + side: const BorderSide(color: outlineVariant, width: 1.2), + shape: const StadiumBorder(), + labelStyle: textTheme.labelMedium?.copyWith(color: onSurface), + secondaryLabelStyle: textTheme.labelMedium?.copyWith(color: onSurface), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 2), + ), + bottomSheetTheme: const BottomSheetThemeData( + backgroundColor: surfaceContainerLow, + surfaceTintColor: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(32)), + ), + showDragHandle: true, + ), + dividerTheme: const DividerThemeData( + color: outlineVariant, + space: 1, + thickness: 1, + ), + listTileTheme: const ListTileThemeData( + textColor: onSurface, + iconColor: onSurfaceVariant, + ), + snackBarTheme: SnackBarThemeData( + behavior: SnackBarBehavior.floating, + backgroundColor: inverseSurface, + contentTextStyle: textTheme.bodyMedium?.copyWith( + color: const Color(0xFFF7F1E8), + ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), ), - dividerTheme: DividerThemeData( - color: colorScheme.outlineVariant, - space: 1, - ), - snackBarTheme: SnackBarThemeData( - behavior: SnackBarBehavior.floating, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - listTileTheme: ListTileThemeData( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - iconColor: colorScheme.primary, - ), - shadowColor: isDark ? Colors.black : const Color(0x1A0F172A), ); } - /// Slightly tighter, more editorial type scale than the Material defaults. + /// Soft dark mirror — elevated cards stay darker than text for contrast. + static ThemeData dark() { + const darkScheme = ColorScheme( + brightness: Brightness.dark, + primary: Color(0xFFE2CDB6), + onPrimary: Color(0xFF2A2118), + primaryContainer: Color(0xFF6B5848), + onPrimaryContainer: Color(0xFFFFF3E8), + secondary: Color(0xFFFFB691), + onSecondary: Color(0xFF4A1E08), + secondaryContainer: Color(0xFF6B3014), + onSecondaryContainer: Color(0xFFFFD4BC), + tertiary: Color(0xFFB5CDB0), + onTertiary: Color(0xFF1A2A1A), + tertiaryContainer: Color(0xFF3A5238), + onTertiaryContainer: Color(0xFFEAF6E7), + error: Color(0xFFFFB4AB), + onError: Color(0xFF690005), + errorContainer: Color(0xFF93000A), + onErrorContainer: Color(0xFFFFDAD6), + surface: Color(0xFF161310), + onSurface: Color(0xFFF5EFE6), + surfaceContainerHighest: Color(0xFF3A342E), + surfaceContainerHigh: Color(0xFF302B26), + surfaceContainer: Color(0xFF26221E), + surfaceContainerLow: Color(0xFF221E1A), + surfaceContainerLowest: Color(0xFF0E0C0A), + onSurfaceVariant: Color(0xFFD9CEC2), + outline: Color(0xFFB0A397), + outlineVariant: Color(0xFF4A433C), + inverseSurface: Color(0xFFF5EFE6), + onInverseSurface: Color(0xFF1C1916), + inversePrimary: Color(0xFF4F4032), + shadow: Color(0xFF000000), + scrim: Color(0xFF000000), + ); + + final textTheme = _textTheme(darkScheme); + return ThemeData( + useMaterial3: true, + colorScheme: darkScheme, + textTheme: textTheme, + scaffoldBackgroundColor: darkScheme.surface, + appBarTheme: AppBarTheme( + centerTitle: false, + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: darkScheme.surface, + foregroundColor: darkScheme.onSurface, + titleTextStyle: textTheme.titleLarge, + ), + cardTheme: CardThemeData( + elevation: 0, + color: darkScheme.surfaceContainerLow, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + side: BorderSide(color: darkScheme.outlineVariant, width: 1.2), + ), + ), + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: darkScheme.surfaceContainer, + hintStyle: textTheme.bodyMedium?.copyWith( + color: darkScheme.outline.withValues(alpha: 0.9), + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide(color: darkScheme.outlineVariant, width: 1.2), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide(color: darkScheme.outlineVariant, width: 1.2), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: BorderSide(color: darkScheme.primary, width: 1.8), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 14, + ), + ), + filledButtonTheme: FilledButtonThemeData( + style: FilledButton.styleFrom( + minimumSize: const Size.fromHeight(52), + backgroundColor: darkScheme.primary, + foregroundColor: darkScheme.onPrimary, + shape: const StadiumBorder(), + textStyle: textTheme.labelLarge?.copyWith(color: darkScheme.onPrimary), + elevation: 0, + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: darkScheme.onSurface, + textStyle: textTheme.labelMedium?.copyWith( + color: darkScheme.onSurface, + fontWeight: FontWeight.w600, + ), + shape: const StadiumBorder(), + ), + ), + chipTheme: ChipThemeData( + backgroundColor: darkScheme.surfaceContainer, + selectedColor: darkScheme.surfaceContainerHigh, + side: BorderSide(color: darkScheme.outlineVariant, width: 1.2), + shape: const StadiumBorder(), + labelStyle: textTheme.labelMedium?.copyWith(color: darkScheme.onSurface), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 2), + ), + bottomSheetTheme: BottomSheetThemeData( + backgroundColor: darkScheme.surfaceContainerLow, + surfaceTintColor: Colors.transparent, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(32)), + ), + showDragHandle: true, + ), + listTileTheme: ListTileThemeData( + textColor: darkScheme.onSurface, + iconColor: darkScheme.onSurfaceVariant, + ), + ); + } + static TextTheme _textTheme(ColorScheme colors) { - const family = 'Roboto'; + final newsreader = GoogleFonts.newsreaderTextTheme(); + final jakarta = GoogleFonts.plusJakartaSansTextTheme(); + return TextTheme( - displaySmall: TextStyle( - fontFamily: family, - fontSize: 36, - fontWeight: FontWeight.w700, - letterSpacing: -0.5, + displaySmall: newsreader.displaySmall?.copyWith( + fontSize: 32, + height: 40 / 32, + fontWeight: FontWeight.w500, + letterSpacing: -0.32, color: colors.onSurface, ), - headlineMedium: TextStyle( - fontFamily: family, - fontSize: 28, - fontWeight: FontWeight.w600, - letterSpacing: -0.3, + headlineMedium: newsreader.headlineMedium?.copyWith( + fontSize: 26, + height: 34 / 26, + fontWeight: FontWeight.w500, color: colors.onSurface, ), - titleLarge: TextStyle( - fontFamily: family, + headlineSmall: newsreader.headlineSmall?.copyWith( fontSize: 22, - fontWeight: FontWeight.w600, + height: 30 / 22, + fontWeight: FontWeight.w500, color: colors.onSurface, ), - titleMedium: TextStyle( - fontFamily: family, + titleLarge: newsreader.titleLarge?.copyWith( + fontSize: 22, + height: 30 / 22, + fontWeight: FontWeight.w500, + color: colors.onSurface, + ), + titleMedium: jakarta.titleMedium?.copyWith( fontSize: 16, - fontWeight: FontWeight.w600, + fontWeight: FontWeight.w700, color: colors.onSurface, ), - bodyLarge: TextStyle( - fontFamily: family, + bodyLarge: jakarta.bodyLarge?.copyWith( fontSize: 16, - height: 1.45, + height: 24 / 16, + fontWeight: FontWeight.w500, color: colors.onSurface, ), - bodyMedium: TextStyle( - fontFamily: family, + bodyMedium: jakarta.bodyMedium?.copyWith( fontSize: 14, - height: 1.4, + height: 20 / 14, + fontWeight: FontWeight.w500, color: colors.onSurfaceVariant, ), - labelLarge: TextStyle( - fontFamily: family, - fontSize: 14, - fontWeight: FontWeight.w600, - letterSpacing: 0.1, + bodySmall: jakarta.bodySmall?.copyWith( + fontSize: 12, + height: 16 / 12, + fontWeight: FontWeight.w500, + color: colors.onSurfaceVariant, + ), + labelLarge: jakarta.labelLarge?.copyWith( + fontSize: 15, + height: 20 / 15, + fontWeight: FontWeight.w700, + letterSpacing: 0.15, color: colors.onPrimary, ), - labelMedium: TextStyle( - fontFamily: family, - fontSize: 12, - fontWeight: FontWeight.w500, + labelMedium: jakarta.labelMedium?.copyWith( + fontSize: 13, + height: 18 / 13, + fontWeight: FontWeight.w600, + letterSpacing: 0.2, + color: colors.onSurfaceVariant, + ), + labelSmall: jakarta.labelSmall?.copyWith( + fontSize: 11, + height: 16 / 11, + fontWeight: FontWeight.w700, letterSpacing: 0.4, color: colors.onSurfaceVariant, ), diff --git a/lib/utils/constants.dart b/lib/utils/constants.dart index dcacb69..0a271ab 100644 --- a/lib/utils/constants.dart +++ b/lib/utils/constants.dart @@ -1,27 +1,19 @@ /// Shared string keys, timings, and layout breakpoints used across the app. library; -/// Human-readable name shown in the splash screen, app bars, and About tile. -const String kAppName = 'MyApp'; +/// Human-readable name shown in the splash screen and brand chrome. +const String kAppName = 'Values Sort'; /// Package / Android application id. const String kPackageName = 'com.example.myapp'; -/// How long the splash screen stays visible before navigating to the shell. -const Duration kSplashDuration = Duration(seconds: 2); +/// How long the splash screen stays visible before navigating onward. +const Duration kSplashDuration = Duration(milliseconds: 1400); /// SharedPreferences keys. abstract final class StorageKeys { static const themeMode = 'theme_mode'; - static const useRemoteData = 'use_remote_data'; -} - -/// Named routes registered on [MaterialApp]. -abstract final class AppRoutes { - static const splash = '/'; - static const shell = '/shell'; - static const itemDetail = '/item'; - static const addItem = '/add-item'; + static const sortSession = 'values_sort_session_v1'; } /// Width thresholds used to adapt padding and card density. @@ -30,5 +22,5 @@ abstract final class Breakpoints { static const medium = 840.0; } -/// Maximum content width on tablets / large phones so lists stay readable. -const double kMaxContentWidth = 720.0; +/// Maximum content width on tablets so reflective flows stay readable. +const double kMaxContentWidth = 600.0; diff --git a/lib/utils/helpers.dart b/lib/utils/helpers.dart deleted file mode 100644 index 4d6e0fb..0000000 --- a/lib/utils/helpers.dart +++ /dev/null @@ -1,59 +0,0 @@ -/// Small pure helpers for layout, formatting, and user-facing strings. -library; - -import 'package:flutter/material.dart'; - -import 'constants.dart'; - -/// Horizontal padding that grows a little on wider screens. -double pagePadding(double width) { - if (width >= Breakpoints.medium) return 32; - if (width >= Breakpoints.compact) return 24; - return 16; -} - -/// Formats [date] as `MMM d, y` without pulling in `intl`. -String formatDate(DateTime date) { - const months = [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'May', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', - ]; - return '${months[date.month - 1]} ${date.day}, ${date.year}'; -} - -/// Converts a stored theme key into a [ThemeMode]. -ThemeMode themeModeFromName(String name) { - return switch (name) { - 'light' => ThemeMode.light, - 'dark' => ThemeMode.dark, - _ => ThemeMode.system, - }; -} - -/// Inverse of [themeModeFromName] for persistence. -String nameFromThemeMode(ThemeMode mode) { - return switch (mode) { - ThemeMode.light => 'light', - ThemeMode.dark => 'dark', - ThemeMode.system => 'system', - }; -} - -/// Title-cases a [ThemeMode] for settings labels. -String labelForThemeMode(ThemeMode mode) { - return switch (mode) { - ThemeMode.light => 'Light', - ThemeMode.dark => 'Dark', - ThemeMode.system => 'System', - }; -} diff --git a/lib/widgets/app_text_field.dart b/lib/widgets/app_text_field.dart deleted file mode 100644 index 4cdeb3e..0000000 --- a/lib/widgets/app_text_field.dart +++ /dev/null @@ -1,44 +0,0 @@ -/// Labeled text field with a shared decoration used by the add-item form. -library; - -import 'package:flutter/material.dart'; - -class AppTextField extends StatelessWidget { - const AppTextField({ - super.key, - required this.controller, - required this.label, - this.hint, - this.maxLines = 1, - this.textInputAction, - this.keyboardType, - this.validator, - this.autofocus = false, - }); - - final TextEditingController controller; - final String label; - final String? hint; - final int maxLines; - final TextInputAction? textInputAction; - final TextInputType? keyboardType; - final String? Function(String?)? validator; - final bool autofocus; - - @override - Widget build(BuildContext context) { - return TextFormField( - controller: controller, - maxLines: maxLines, - autofocus: autofocus, - textInputAction: textInputAction, - keyboardType: keyboardType, - validator: validator, - decoration: InputDecoration( - labelText: label, - hintText: hint, - alignLabelWithHint: maxLines > 1, - ), - ); - } -} diff --git a/lib/widgets/empty_state.dart b/lib/widgets/empty_state.dart deleted file mode 100644 index 088c92e..0000000 --- a/lib/widgets/empty_state.dart +++ /dev/null @@ -1,51 +0,0 @@ -/// Placeholder shown when a list or search has nothing to display. -library; - -import 'package:flutter/material.dart'; - -class EmptyState extends StatelessWidget { - const EmptyState({ - super.key, - required this.icon, - required this.title, - required this.message, - this.actionLabel, - this.onAction, - }); - - final IconData icon; - final String title; - final String message; - final String? actionLabel; - final VoidCallback? onAction; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final colors = theme.colorScheme; - - return Center( - child: Padding( - padding: const EdgeInsets.all(32), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(icon, size: 48, color: colors.outline), - const SizedBox(height: 16), - Text(title, style: theme.textTheme.titleMedium), - const SizedBox(height: 8), - Text( - message, - textAlign: TextAlign.center, - style: theme.textTheme.bodyMedium, - ), - if (actionLabel != null && onAction != null) ...[ - const SizedBox(height: 20), - FilledButton(onPressed: onAction, child: Text(actionLabel!)), - ], - ], - ), - ), - ); - } -} diff --git a/lib/widgets/item_card.dart b/lib/widgets/item_card.dart deleted file mode 100644 index 71ed062..0000000 --- a/lib/widgets/item_card.dart +++ /dev/null @@ -1,127 +0,0 @@ -/// Tappable card used inside [ListView.builder] on Home and Search. -library; - -import 'package:flutter/material.dart'; - -import '../models/item.dart'; -import '../screens/item_detail_screen.dart'; -import '../utils/helpers.dart'; -import 'item_hero_badge.dart'; - -/// Displays one [Item] as a rounded, shadowed card that opens the detail route. -class ItemCard extends StatelessWidget { - const ItemCard({ - super.key, - required this.item, - this.heroScope = 'home', - }); - - final Item item; - - /// Prefix so Home and Search can show the same item without colliding Heroes. - final String heroScope; - - String get heroTag => '$heroScope-${item.heroTag}'; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final colors = theme.colorScheme; - - return DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: theme.shadowColor.withValues(alpha: 0.08), - blurRadius: 18, - offset: const Offset(0, 8), - ), - ], - ), - child: Material( - color: colors.surfaceContainerLow, - borderRadius: BorderRadius.circular(16), - child: InkWell( - borderRadius: BorderRadius.circular(16), - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => ItemDetailScreen( - item: item, - heroTag: heroTag, - ), - ), - ); - }, - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ItemHeroBadge(item: item, heroTag: heroTag), - const SizedBox(width: 14), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(item.title, style: theme.textTheme.titleMedium), - const SizedBox(height: 4), - Text( - item.subtitle, - style: theme.textTheme.bodyMedium, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 10), - Wrap( - spacing: 8, - runSpacing: 4, - children: [ - _MetaChip( - label: item.category.label, - color: item.category.accent, - ), - _MetaChip( - label: formatDate(item.createdAt), - color: colors.outline, - ), - ], - ), - ], - ), - ), - Icon( - Icons.chevron_right, - color: colors.outline, - ), - ], - ), - ), - ), - ), - ); - } -} - -class _MetaChip extends StatelessWidget { - const _MetaChip({required this.label, required this.color}); - - final String label; - final Color color; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), - decoration: BoxDecoration( - color: color.withValues(alpha: 0.12), - borderRadius: BorderRadius.circular(8), - ), - child: Text( - label, - style: Theme.of(context).textTheme.labelMedium?.copyWith(color: color), - ), - ); - } -} diff --git a/lib/widgets/item_hero_badge.dart b/lib/widgets/item_hero_badge.dart deleted file mode 100644 index fbbb30b..0000000 --- a/lib/widgets/item_hero_badge.dart +++ /dev/null @@ -1,54 +0,0 @@ -/// Colored glyph used as the [Hero] flight target for an [Item]. -library; - -import 'package:flutter/material.dart'; - -import '../models/item.dart'; - -/// Rounded square that carries the category icon. Size is animated by [Hero]. -class ItemHeroBadge extends StatelessWidget { - const ItemHeroBadge({ - super.key, - required this.item, - required this.heroTag, - this.size = 48, - }); - - final Item item; - final double size; - - /// Unique among on-screen Heroes. Home and Search both list the same items, - /// so callers pass a scoped tag (for example `home-item-hero-1`). - final String heroTag; - - @override - Widget build(BuildContext context) { - final radius = size * 0.28; - return Hero( - tag: heroTag, - child: Material( - color: Colors.transparent, - child: Container( - width: size, - height: size, - decoration: BoxDecoration( - color: item.category.accent, - borderRadius: BorderRadius.circular(radius), - boxShadow: [ - BoxShadow( - color: item.category.accent.withValues(alpha: 0.35), - blurRadius: size * 0.18, - offset: Offset(0, size * 0.08), - ), - ], - ), - child: Icon( - item.category.icon, - color: Colors.white, - size: size * 0.5, - ), - ), - ), - ); - } -} diff --git a/lib/widgets/loading_view.dart b/lib/widgets/loading_view.dart deleted file mode 100644 index 1ad7652..0000000 --- a/lib/widgets/loading_view.dart +++ /dev/null @@ -1,24 +0,0 @@ -/// Centered spinner used while [ItemController] is fetching data. -library; - -import 'package:flutter/material.dart'; - -class LoadingView extends StatelessWidget { - const LoadingView({super.key, this.message = 'Loading…'}); - - final String message; - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const CircularProgressIndicator(), - const SizedBox(height: 16), - Text(message, style: Theme.of(context).textTheme.bodyMedium), - ], - ), - ); - } -} diff --git a/lib/widgets/practice_chrome.dart b/lib/widgets/practice_chrome.dart new file mode 100644 index 0000000..cb4ce43 --- /dev/null +++ b/lib/widgets/practice_chrome.dart @@ -0,0 +1,168 @@ +/// Shared layout chrome for Values Sort screens. +library; + +import 'package:flutter/material.dart'; + +import '../utils/constants.dart'; +import 'theme_toggle_button.dart'; + +/// Centers content and applies mobile margins from the design system. +class PracticeScaffold extends StatelessWidget { + const PracticeScaffold({ + super.key, + required this.child, + this.header, + this.footer, + this.padding, + this.showThemeToggle = true, + }); + + final Widget child; + final Widget? header; + final Widget? footer; + final EdgeInsetsGeometry? padding; + final bool showThemeToggle; + + @override + Widget build(BuildContext context) { + final pad = padding ?? + const EdgeInsets.fromLTRB(20, 8, 20, 16); + + return Scaffold( + body: SafeArea( + child: Align( + alignment: Alignment.topCenter, + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: kMaxContentWidth), + child: Column( + children: [ + if (showThemeToggle) + const Padding( + padding: EdgeInsets.fromLTRB(12, 4, 12, 0), + child: Align( + alignment: Alignment.centerRight, + child: ThemeToggleButton(), + ), + ), + if (header != null) header!, + Expanded( + child: Padding( + padding: pad, + child: child, + ), + ), + if (footer != null) + Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 12), + child: footer!, + ), + ], + ), + ), + ), + ), + ); + } +} + +/// Compact brand row used on the welcome screen. +class BrandMark extends StatelessWidget { + const BrandMark({super.key}); + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + final labels = Theme.of(context).textTheme; + + return Row( + children: [ + ClipOval( + child: Image.asset( + 'assets/images/emblem.png', + width: 32, + height: 32, + fit: BoxFit.cover, + errorBuilder: (_, _, _) => Container( + width: 32, + height: 32, + color: colors.primaryContainer, + child: Icon(Icons.spa, size: 18, color: colors.onPrimary), + ), + ), + ), + const SizedBox(width: 8), + Text( + 'VALUES SORT', + style: labels.labelSmall?.copyWith( + letterSpacing: 2.2, + color: colors.onSurfaceVariant, + ), + ), + ], + ); + } +} + +/// Full-width primary pill CTA. +class PrimaryPillButton extends StatelessWidget { + const PrimaryPillButton({ + super.key, + required this.label, + required this.onPressed, + this.icon, + }); + + final String label; + final VoidCallback? onPressed; + final IconData? icon; + + @override + Widget build(BuildContext context) { + return FilledButton( + onPressed: onPressed, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible(child: Text(label, overflow: TextOverflow.ellipsis)), + if (icon != null) ...[ + const SizedBox(width: 8), + Icon(icon, size: 18), + ], + ], + ), + ); + } +} + +/// Quiet secondary text action. +class GhostPillButton extends StatelessWidget { + const GhostPillButton({ + super.key, + required this.label, + required this.onPressed, + this.icon, + }); + + final String label; + final VoidCallback? onPressed; + final IconData? icon; + + @override + Widget build(BuildContext context) { + return TextButton( + onPressed: onPressed, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text(label), + if (icon != null) ...[ + const SizedBox(width: 6), + Icon(icon, size: 18), + ], + ], + ), + ); + } +} diff --git a/lib/widgets/responsive_body.dart b/lib/widgets/responsive_body.dart deleted file mode 100644 index 089fea2..0000000 --- a/lib/widgets/responsive_body.dart +++ /dev/null @@ -1,34 +0,0 @@ -/// Shared layout helper that centers content and caps width on large screens. -library; - -import 'package:flutter/material.dart'; - -import '../utils/constants.dart'; -import '../utils/helpers.dart'; - -/// Wraps [child] with responsive horizontal padding and an optional max width. -class ResponsiveBody extends StatelessWidget { - const ResponsiveBody({ - super.key, - required this.child, - this.maxWidth = kMaxContentWidth, - }); - - final Widget child; - final double maxWidth; - - @override - Widget build(BuildContext context) { - final width = MediaQuery.sizeOf(context).width; - return Align( - alignment: Alignment.topCenter, - child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: maxWidth), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: pagePadding(width)), - child: child, - ), - ), - ); - } -} diff --git a/lib/widgets/theme_toggle_button.dart b/lib/widgets/theme_toggle_button.dart new file mode 100644 index 0000000..3e51448 --- /dev/null +++ b/lib/widgets/theme_toggle_button.dart @@ -0,0 +1,35 @@ +/// Moon / sun control for switching light and dark themes. +library; + +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../providers/theme_provider.dart'; + +class ThemeToggleButton extends StatelessWidget { + const ThemeToggleButton({super.key}); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final colors = Theme.of(context).colorScheme; + final dark = theme.isDark; + + return IconButton( + tooltip: dark ? 'Switch to light mode' : 'Switch to dark mode', + onPressed: theme.toggleLightDark, + visualDensity: VisualDensity.compact, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(minWidth: 32, minHeight: 32), + style: IconButton.styleFrom( + backgroundColor: colors.surfaceContainer, + foregroundColor: colors.onSurfaceVariant, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + icon: Icon( + dark ? Icons.light_mode_outlined : Icons.dark_mode_outlined, + size: 16, + ), + ); + } +} diff --git a/lib/widgets/value_card_tile.dart b/lib/widgets/value_card_tile.dart new file mode 100644 index 0000000..0b3515a --- /dev/null +++ b/lib/widgets/value_card_tile.dart @@ -0,0 +1,100 @@ +/// Visual tiles for a [ValueCard] in hero, sort, and list contexts. +library; + +import 'package:flutter/material.dart'; + +import '../models/value_card.dart'; + +/// Elevated paper card used during sorting and as list detail rows. +class ValueCardTile extends StatelessWidget { + const ValueCardTile({ + super.key, + required this.card, + this.compact = false, + this.trailing, + this.onTap, + this.elevation = 0, + }); + + final ValueCard card; + final bool compact; + final Widget? trailing; + final VoidCallback? onTap; + final double elevation; + + @override + Widget build(BuildContext context) { + final text = Theme.of(context).textTheme; + final colors = Theme.of(context).colorScheme; + + return Material( + color: colors.surfaceContainerLow, + elevation: elevation, + shadowColor: colors.shadow.withValues(alpha: 0.12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + side: BorderSide(color: colors.outlineVariant), + ), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(24), + child: Padding( + padding: EdgeInsets.all(compact ? 14 : 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Text( + card.title, + style: (compact ? text.titleLarge : text.headlineMedium) + ?.copyWith(color: colors.onSurface), + ), + ), + if (trailing != null) ...[ + const SizedBox(width: 8), + trailing!, + ], + ], + ), + if (card.description.isNotEmpty) ...[ + const SizedBox(height: 8), + Text( + card.description, + style: text.bodyMedium?.copyWith( + color: colors.onSurfaceVariant, + ), + maxLines: compact ? 3 : 5, + overflow: TextOverflow.ellipsis, + ), + ], + ], + ), + ), + ), + ); + } +} + +/// Small chip used in overview grids. +class ValueChip extends StatelessWidget { + const ValueChip({ + super.key, + required this.title, + this.onTap, + }); + + final String title; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + return ActionChip( + label: Text(title), + onPressed: onTap, + visualDensity: VisualDensity.compact, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 5600031..4f18a1f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" async: dependency: transitive description: @@ -33,6 +41,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 + url: "https://pub.dev" + source: hosted + version: "1.2.1" collection: dependency: transitive description: @@ -41,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" cupertino_icons: dependency: "direct main" description: @@ -96,8 +120,24 @@ packages: description: flutter source: sdk version: "0.0.0" - http: + google_fonts: dependency: "direct main" + description: + name: google_fonts + sha256: e3cb3ee6b47fd2472c23de6da5744796a4da195137759ddb3fbcc9467b7b3c7d + url: "https://pub.dev" + source: hosted + version: "8.2.1" + hooks: + dependency: transitive + description: + name: hooks + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + http: + dependency: transitive description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" @@ -112,6 +152,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + jni: + dependency: transitive + description: + name: jni + sha256: f038e58b4dc2c9037f50e233175086337e0b305e356d28211bf55f21c504cbd3 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: b2310cdd4c18c65c081ab141a41efa94aa26c65431803703ece51996f174f351 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + jni_util: + dependency: transitive + description: + name: jni_util + sha256: "1ba86da04a5f2bf18fde2edb235587e70c5b0fc5bd4ba955f46b00942c3fc35f" + url: "https://pub.dev" + source: hosted + version: "1.0.0" leak_tracker: dependency: transitive description: @@ -144,6 +208,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: @@ -176,6 +248,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: b7fb95a6d9a4f009edd63dc5ac69f07420b23a16161c6dd8660290b59c602e8e + url: "https://pub.dev" + source: hosted + version: "9.5.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: ffcf4cf3d6c0b74ac43708d9f56625506e8a68aa935abe9d267a7330f320eb5d + url: "https://pub.dev" + source: hosted + version: "3.0.0" path: dependency: transitive description: @@ -184,6 +272,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: a7f4874f987173da295a61c181b8ee71dab59b332a486b391babf26a1b884825 + url: "https://pub.dev" + source: hosted + version: "2.1.6" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" + source: hosted + version: "2.6.0" path_provider_linux: dependency: transitive description: @@ -232,6 +344,22 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "261236774e8b1d69cfc6b9eabbc96c40f25e7a2d6b171f3385d4f65d5734fb24" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.dev" + source: hosted + version: "0.6.0" shared_preferences: dependency: "direct main" description: @@ -381,6 +509,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: f67cdd8e07d3c6329146aaef1ba043542b3134c12489f553ca9a7435d1068aea + url: "https://pub.dev" + source: hosted + version: "3.1.4" sdks: dart: ">=3.13.2 <4.0.0" flutter: ">=3.44.0" diff --git a/pubspec.yaml b/pubspec.yaml index 20fabd9..3af2132 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: myapp -description: Generic Flutter Android starter with Material 3, Provider, and local persistence. +description: Values Sort — a guided card-sort practice for clarifying personal values. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev @@ -34,9 +34,9 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 - provider: ^6.1.5+1 # ChangeNotifier state for theme and catalog - http: ^1.6.0 # Placeholder network client (JSONPlaceholder) - shared_preferences: ^2.5.5 # Persist theme mode and data-source toggle + provider: ^6.1.5+1 + shared_preferences: ^2.5.5 + google_fonts: ^8.2.1 dev_dependencies: flutter_test: @@ -60,10 +60,9 @@ flutter: # the material Icons class. uses-material-design: true - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - assets/data/values_deck.json + - assets/images/emblem.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images diff --git a/stitch/DESIGN.md b/stitch/DESIGN.md new file mode 100644 index 0000000..46fb466 --- /dev/null +++ b/stitch/DESIGN.md @@ -0,0 +1,214 @@ +--- +name: Mindful Values Architecture +colors: + surface: '#fdf9f2' + surface-dim: '#dddad3' + surface-bright: '#fdf9f2' + surface-container-lowest: '#ffffff' + surface-container-low: '#f7f3ec' + surface-container: '#f1ede6' + surface-container-high: '#ece8e1' + surface-container-highest: '#e6e2db' + on-surface: '#1c1c18' + on-surface-variant: '#4d453e' + inverse-surface: '#31302c' + inverse-on-surface: '#f4f0e9' + outline: '#7f756d' + outline-variant: '#d0c4ba' + surface-tint: '#6c5b49' + primary: '#635341' + on-primary: '#ffffff' + primary-container: '#7d6b58' + on-primary-container: '#ffefe1' + inverse-primary: '#d9c3ac' + secondary: '#8e4d2a' + on-secondary: '#ffffff' + secondary-container: '#feaa7f' + on-secondary-container: '#783d1a' + tertiary: '#465b44' + on-tertiary: '#ffffff' + tertiary-container: '#5e745c' + on-tertiary-container: '#e1f9db' + error: '#ba1a1a' + on-error: '#ffffff' + error-container: '#ffdad6' + on-error-container: '#93000a' + primary-fixed: '#f6dfc7' + primary-fixed-dim: '#d9c3ac' + on-primary-fixed: '#25190b' + on-primary-fixed-variant: '#544433' + secondary-fixed: '#ffdbcb' + secondary-fixed-dim: '#ffb691' + on-secondary-fixed: '#341100' + on-secondary-fixed-variant: '#713714' + tertiary-fixed: '#d1e9cc' + tertiary-fixed-dim: '#b5cdb0' + on-tertiary-fixed: '#0d200d' + on-tertiary-fixed-variant: '#374c36' + background: '#fdf9f2' + on-background: '#1c1c18' + surface-variant: '#e6e2db' +typography: + headline-xl: + fontFamily: Newsreader + fontSize: 40px + fontWeight: '400' + lineHeight: 48px + letterSpacing: -0.02em + headline-xl-mobile: + fontFamily: Newsreader + fontSize: 32px + fontWeight: '400' + lineHeight: 40px + letterSpacing: -0.01em + headline-lg: + fontFamily: Newsreader + fontSize: 30px + fontWeight: '400' + lineHeight: 38px + letterSpacing: -0.01em + headline-lg-mobile: + fontFamily: Newsreader + fontSize: 26px + fontWeight: '400' + lineHeight: 34px + letterSpacing: 0em + headline-md: + fontFamily: Newsreader + fontSize: 22px + fontWeight: '400' + lineHeight: 30px + body-lg: + fontFamily: Plus Jakarta Sans + fontSize: 18px + fontWeight: '400' + lineHeight: 28px + body-md: + fontFamily: Plus Jakarta Sans + fontSize: 16px + fontWeight: '400' + lineHeight: 24px + body-sm: + fontFamily: Plus Jakarta Sans + fontSize: 14px + fontWeight: '400' + lineHeight: 20px + label-lg: + fontFamily: Plus Jakarta Sans + fontSize: 15px + fontWeight: '600' + lineHeight: 20px + letterSpacing: 0.01em + label-md: + fontFamily: Plus Jakarta Sans + fontSize: 13px + fontWeight: '500' + lineHeight: 18px + letterSpacing: 0.02em + label-sm: + fontFamily: Plus Jakarta Sans + fontSize: 11px + fontWeight: '600' + lineHeight: 16px + letterSpacing: 0.04em +rounded: + sm: 0.5rem + DEFAULT: 1rem + md: 1.5rem + lg: 2rem + xl: 3rem + full: 9999px +spacing: + gutter: 1rem + gutter-mobile: 0.75rem + margin: 1.5rem + margin-mobile: 1.25rem + space-xs: 0.25rem + space-sm: 0.5rem + space-md: 1rem + space-lg: 1.5rem + space-xl: 2.5rem +--- + +## Brand & Style + +This design system is crafted for deep introspection, intentional decision-making, and personal grounding. It serves individuals navigating life transitions, therapeutic exercises, and values-clarification practices. The experience is designed to feel unhurried, quietly reverent, and deeply personal—eschewing addictive loops, loud notifications, and superficial gamification in favor of sustained focus and calm contemplation. + +The visual style blends **warm editorial minimalism** with **tactile paper-like depth**. It draws inspiration from artisanal bookbinding, linen stationery, and modern contemplative journals: +- **Atmosphere:** Serene, grounded, deliberate, and emotionally secure. +- **Rhythm:** Generous breathing room with relaxed vertical pacing, inviting the eye to linger and pause. +- **Materiality:** Soft stone surfaces, delicate warm contours, and nuanced diffuse shadows that ground elements without feeling synthetic or rigid. + +## Colors + +The palette is rooted in the natural world: mineral sands, quiet clay, sun-bleached stone, and muted foliage. The dynamic range avoids stark pure whites and abrasive digital blacks, fostering an environment free of eye strain and cognitive fatigue. + +### Color Tiers & Intent +- **Canvas Base (`#FBF9F5`):** The primary view background; evokes raw, unbleached cotton paper. +- **Surface Elevation (`#F5F1EA`):** Neutral surface for raised cards, value tiles, and interactive sheets. +- **Subtle Surface & Dividers (`#E8E2D8`):** Restful borders, inset surfaces, and non-intrusive separators. +- **Primary / Earth Ground (`#7D6B58`):** A balanced warm taupe-stone that grounds primary interactive states and contemplative highlights. +- **Secondary / Terracotta Accent (`#C87D55`):** A soft, sun-dried clay tone used selectively for active selections, progress markers, and reflective milestones. +- **Tertiary / Sage Accent (`#6B8168`):** A muted eucalyptus green designated for affirmation states, grounded confirmations, and calm categorization. +- **Text & Contrast (`#2C2825` Primary, `#4A443F` Secondary):** Deep espresso and soft slate hues that preserve crisp readability with none of the harshness of pure black. + +## Typography + +The typographic hierarchy balances literary gravitas with clean, approachable utility. + +- **Display & Headlines (`Newsreader`):** An editorial, high-character serif that confers an intellectual, gentle, book-like presence. Headlines use standard weight and slightly negative tracking to evoke printed literary works. +- **Body & Labels (`Plus Jakarta Sans`):** A soft, humanist geometric sans-serif that balances modern legibility with rounded, friendly terminal strokes. It delivers effortless readability across reflection prompts, explanatory texts, and compact mobile UI controls. +- **Rhythm & Formatting:** Line heights remain generous across all tiers to safeguard vertical breathing room and prevent visual crowding during dense contemplative sessions. + +## Layout & Spacing + +The layout is built around spacious, open single-column and modular card streams suited for portrait handheld usage. It prioritizes focus by presenting a limited number of elements on screen at any given time. + +### Grid & Form Factors +- **Mobile (<640px):** Single-column layout with fluid full-width cards anchored by `1.25rem` outer canvas padding. Component stacks maintain `space-md` gaps. +- **Tablet (640px–1024px):** Centered max-width canvas (600px for reflective sort flows, 768px for summary balance views) with `1.5rem` outer margins. +- **Sorting Viewports:** Sorting columns or buckets utilize vertical flex stacks with `space-sm` or `space-md` separation to maintain clear tactile drop zones and distinct groupings. + +## Elevation & Depth + +Visual depth is achieved through layered warm surfaces paired with whisper-soft, colored ambient shadows rather than synthetic gray blurs. + +- **Flat / Ground Level:** Page background (`#FBF9F5`) with no shadow. +- **Elevated Tiles & Cards:** Surface color `#F5F1EA` wrapped in a 1px border of `#E8E2D8`, elevated by a warm, diffuse ambient shadow: `box-shadow: 0 4px 16px -2px rgba(44, 40, 37, 0.04), 0 1px 4px 0 rgba(44, 40, 37, 0.02)`. +- **Floating Controls & Active Drags:** While dragging or floating above other content, cards subtly lift: `box-shadow: 0 12px 28px -4px rgba(44, 40, 37, 0.08), 0 2px 8px 0 rgba(44, 40, 37, 0.03)`. +- **Borders as Tone:** In place of strong contrast lines, borders act as quiet edge definitions using `#E8E2D8` to cleanly separate panels without fragmenting the canvas. + +## Shapes + +The design system embraces a high-radius, organic shape language (`roundedness: 3`). + +- **Pill Geometry:** Interactive buttons, category filters, and selection pills utilize complete capsule geometry (`rounded-full`), reinforcing physical softness and comfort in the hand. +- **Cards & Value Containers:** Larger surfaces utilize relaxed, generous border radii (`1.5rem` to `2rem` / `rounded-xl` to `rounded-2xl`), eliminating aggressive edges and providing an organic, pebble-like quality to draggable cards. +- **Inset Wells & Modals:** Droppable sort regions adopt matching rounded corners to establish a natural visual container for nested items. + +## Components + +### Buttons +- **Primary:** Full capsule (`rounded-full`) pill button with a `#2C2825` or `#7D6B58` background, `#FBF9F5` typography, and generous horizontal padding (`1.75rem`). No heavy drop shadows; tactile feedback relies on soft tonal lightening on press. +- **Secondary / Gentle:** Subtle stone pill surface (`#F5F1EA`) with a 1px `#E8E2D8` border and `#2C2825` text. +- **Ghost / Reflective:** Borderless with `#4A443F` text, emphasizing deliberate, low-urgency actions (e.g., "Skip for now", "Pause reflection"). + +### Value Cards (Sorting Unit) +- **Resting:** Background `#F5F1EA`, border 1px solid `#E8E2D8`, padding `space-lg`, radius `1.5rem`. Title set in `Newsreader` (`headline-md`) with an optional single-sentence descriptor below in `Plus Jakarta Sans` (`body-sm`, `#4A443F`). +- **Dragging / Active:** Slight scale increase (1.02x) with ambient shadow lift and an accent border transition to `#C87D55`. + +### Chips & Sort Buckets +- **Chips:** Capsule pills with `0.5rem` vertical and `1rem` horizontal padding. Selected states transition from background `#F5F1EA` to `#E8E2D8` with text shifting to `#2C2825`. +- **Sort Buckets (Drop Zones):** Spacious containers framed in dashed or soft solid lines of `#E8E2D8` with background `#FBF9F5`. Labelled with serene, muted headers (e.g., *Always True for Me*, *Important to Me*, *Rarely Considered*). + +### Lists & Prompts +- Framed in full-width soft-edged tiles or separated by subtle `#E8E2D8` hairline dividers. Touch targets remain large (`min-height: 52px`), accompanied by relaxed vertical spacing. + +### Checkboxes & Radio Buttons +- Rounded indicators (circular radios, `6px` radius checkboxes) using `#E8E2D8` borders that fill with muted sage (`#6B8168`) or terracotta (`#C87D55`) when selected, accompanied by a soft white icon check. + +### Input Fields +- Understated input panels with background `#F5F1EA`, bordered in `#E8E2D8`, rounding to `1rem`. Active focus shifts border tone smoothly to `#7D6B58` with no high-contrast glow rings. + +### Specialized Component: Contemplative Reflection Sheet +- A bottom sheet modal featuring a soft drag handle, `2rem` top border radii, linen-stone background (`#F5F1EA`), and generous whitespace designed specifically for writing personal rationales during deep values prioritization. \ No newline at end of file diff --git a/stitch/design-theme.json b/stitch/design-theme.json new file mode 100644 index 0000000..a08f816 --- /dev/null +++ b/stitch/design-theme.json @@ -0,0 +1,154 @@ +{ + "colorMode": "LIGHT", + "font": "NEWSREADER", + "roundness": "ROUND_FULL", + "customColor": "#7d6b58", + "headlineFont": "NEWSREADER", + "bodyFont": "PLUS_JAKARTA_SANS", + "labelFont": "PLUS_JAKARTA_SANS", + "namedColors": { + "surface_container_low": "#f7f3ec", + "secondary_container": "#feaa7f", + "on_error": "#ffffff", + "on_background": "#1c1c18", + "surface_bright": "#fdf9f2", + "surface_container_high": "#ece8e1", + "on_tertiary_fixed_variant": "#374c36", + "on_error_container": "#93000a", + "on_primary": "#ffffff", + "inverse_surface": "#31302c", + "on_primary_fixed_variant": "#544433", + "primary_fixed_dim": "#d9c3ac", + "on_tertiary_container": "#e1f9db", + "secondary_fixed_dim": "#ffb691", + "primary": "#635341", + "surface_container_highest": "#e6e2db", + "background": "#fdf9f2", + "surface_container_lowest": "#ffffff", + "surface_variant": "#e6e2db", + "error": "#ba1a1a", + "on_secondary_container": "#783d1a", + "on_secondary": "#ffffff", + "tertiary": "#465b44", + "tertiary_container": "#5e745c", + "on_primary_fixed": "#25190b", + "on_primary_container": "#ffefe1", + "on_secondary_fixed": "#341100", + "primary_fixed": "#f6dfc7", + "outline_variant": "#d0c4ba", + "surface_tint": "#6c5b49", + "error_container": "#ffdad6", + "surface_dim": "#dddad3", + "inverse_primary": "#d9c3ac", + "on_surface": "#1c1c18", + "secondary_fixed": "#ffdbcb", + "tertiary_fixed": "#d1e9cc", + "on_secondary_fixed_variant": "#713714", + "primary_container": "#7d6b58", + "tertiary_fixed_dim": "#b5cdb0", + "on_tertiary": "#ffffff", + "secondary": "#8e4d2a", + "on_surface_variant": "#4d453e", + "surface": "#fdf9f2", + "outline": "#7f756d", + "on_tertiary_fixed": "#0d200d", + "inverse_on_surface": "#f4f0e9", + "surface_container": "#f1ede6" + }, + "designMd": "---\nname: Mindful Values Architecture\ncolors:\n surface: '#fdf9f2'\n surface-dim: '#dddad3'\n surface-bright: '#fdf9f2'\n surface-container-lowest: '#ffffff'\n surface-container-low: '#f7f3ec'\n surface-container: '#f1ede6'\n surface-container-high: '#ece8e1'\n surface-container-highest: '#e6e2db'\n on-surface: '#1c1c18'\n on-surface-variant: '#4d453e'\n inverse-surface: '#31302c'\n inverse-on-surface: '#f4f0e9'\n outline: '#7f756d'\n outline-variant: '#d0c4ba'\n surface-tint: '#6c5b49'\n primary: '#635341'\n on-primary: '#ffffff'\n primary-container: '#7d6b58'\n on-primary-container: '#ffefe1'\n inverse-primary: '#d9c3ac'\n secondary: '#8e4d2a'\n on-secondary: '#ffffff'\n secondary-container: '#feaa7f'\n on-secondary-container: '#783d1a'\n tertiary: '#465b44'\n on-tertiary: '#ffffff'\n tertiary-container: '#5e745c'\n on-tertiary-container: '#e1f9db'\n error: '#ba1a1a'\n on-error: '#ffffff'\n error-container: '#ffdad6'\n on-error-container: '#93000a'\n primary-fixed: '#f6dfc7'\n primary-fixed-dim: '#d9c3ac'\n on-primary-fixed: '#25190b'\n on-primary-fixed-variant: '#544433'\n secondary-fixed: '#ffdbcb'\n secondary-fixed-dim: '#ffb691'\n on-secondary-fixed: '#341100'\n on-secondary-fixed-variant: '#713714'\n tertiary-fixed: '#d1e9cc'\n tertiary-fixed-dim: '#b5cdb0'\n on-tertiary-fixed: '#0d200d'\n on-tertiary-fixed-variant: '#374c36'\n background: '#fdf9f2'\n on-background: '#1c1c18'\n surface-variant: '#e6e2db'\ntypography:\n headline-xl:\n fontFamily: Newsreader\n fontSize: 40px\n fontWeight: '400'\n lineHeight: 48px\n letterSpacing: -0.02em\n headline-xl-mobile:\n fontFamily: Newsreader\n fontSize: 32px\n fontWeight: '400'\n lineHeight: 40px\n letterSpacing: -0.01em\n headline-lg:\n fontFamily: Newsreader\n fontSize: 30px\n fontWeight: '400'\n lineHeight: 38px\n letterSpacing: -0.01em\n headline-lg-mobile:\n fontFamily: Newsreader\n fontSize: 26px\n fontWeight: '400'\n lineHeight: 34px\n letterSpacing: 0em\n headline-md:\n fontFamily: Newsreader\n fontSize: 22px\n fontWeight: '400'\n lineHeight: 30px\n body-lg:\n fontFamily: Plus Jakarta Sans\n fontSize: 18px\n fontWeight: '400'\n lineHeight: 28px\n body-md:\n fontFamily: Plus Jakarta Sans\n fontSize: 16px\n fontWeight: '400'\n lineHeight: 24px\n body-sm:\n fontFamily: Plus Jakarta Sans\n fontSize: 14px\n fontWeight: '400'\n lineHeight: 20px\n label-lg:\n fontFamily: Plus Jakarta Sans\n fontSize: 15px\n fontWeight: '600'\n lineHeight: 20px\n letterSpacing: 0.01em\n label-md:\n fontFamily: Plus Jakarta Sans\n fontSize: 13px\n fontWeight: '500'\n lineHeight: 18px\n letterSpacing: 0.02em\n label-sm:\n fontFamily: Plus Jakarta Sans\n fontSize: 11px\n fontWeight: '600'\n lineHeight: 16px\n letterSpacing: 0.04em\nrounded:\n sm: 0.5rem\n DEFAULT: 1rem\n md: 1.5rem\n lg: 2rem\n xl: 3rem\n full: 9999px\nspacing:\n gutter: 1rem\n gutter-mobile: 0.75rem\n margin: 1.5rem\n margin-mobile: 1.25rem\n space-xs: 0.25rem\n space-sm: 0.5rem\n space-md: 1rem\n space-lg: 1.5rem\n space-xl: 2.5rem\n---\n\n## Brand & Style\n\nThis design system is crafted for deep introspection, intentional decision-making, and personal grounding. It serves individuals navigating life transitions, therapeutic exercises, and values-clarification practices. The experience is designed to feel unhurried, quietly reverent, and deeply personal\u2014eschewing addictive loops, loud notifications, and superficial gamification in favor of sustained focus and calm contemplation.\n\nThe visual style blends **warm editorial minimalism** with **tactile paper-like depth**. It draws inspiration from artisanal bookbinding, linen stationery, and modern contemplative journals:\n- **Atmosphere:** Serene, grounded, deliberate, and emotionally secure.\n- **Rhythm:** Generous breathing room with relaxed vertical pacing, inviting the eye to linger and pause.\n- **Materiality:** Soft stone surfaces, delicate warm contours, and nuanced diffuse shadows that ground elements without feeling synthetic or rigid.\n\n## Colors\n\nThe palette is rooted in the natural world: mineral sands, quiet clay, sun-bleached stone, and muted foliage. The dynamic range avoids stark pure whites and abrasive digital blacks, fostering an environment free of eye strain and cognitive fatigue.\n\n### Color Tiers & Intent\n- **Canvas Base (`#FBF9F5`):** The primary view background; evokes raw, unbleached cotton paper.\n- **Surface Elevation (`#F5F1EA`):** Neutral surface for raised cards, value tiles, and interactive sheets.\n- **Subtle Surface & Dividers (`#E8E2D8`):** Restful borders, inset surfaces, and non-intrusive separators.\n- **Primary / Earth Ground (`#7D6B58`):** A balanced warm taupe-stone that grounds primary interactive states and contemplative highlights.\n- **Secondary / Terracotta Accent (`#C87D55`):** A soft, sun-dried clay tone used selectively for active selections, progress markers, and reflective milestones.\n- **Tertiary / Sage Accent (`#6B8168`):** A muted eucalyptus green designated for affirmation states, grounded confirmations, and calm categorization.\n- **Text & Contrast (`#2C2825` Primary, `#4A443F` Secondary):** Deep espresso and soft slate hues that preserve crisp readability with none of the harshness of pure black.\n\n## Typography\n\nThe typographic hierarchy balances literary gravitas with clean, approachable utility. \n\n- **Display & Headlines (`Newsreader`):** An editorial, high-character serif that confers an intellectual, gentle, book-like presence. Headlines use standard weight and slightly negative tracking to evoke printed literary works.\n- **Body & Labels (`Plus Jakarta Sans`):** A soft, humanist geometric sans-serif that balances modern legibility with rounded, friendly terminal strokes. It delivers effortless readability across reflection prompts, explanatory texts, and compact mobile UI controls.\n- **Rhythm & Formatting:** Line heights remain generous across all tiers to safeguard vertical breathing room and prevent visual crowding during dense contemplative sessions.\n\n## Layout & Spacing\n\nThe layout is built around spacious, open single-column and modular card streams suited for portrait handheld usage. It prioritizes focus by presenting a limited number of elements on screen at any given time.\n\n### Grid & Form Factors\n- **Mobile (<640px):** Single-column layout with fluid full-width cards anchored by `1.25rem` outer canvas padding. Component stacks maintain `space-md` gaps.\n- **Tablet (640px\u20131024px):** Centered max-width canvas (600px for reflective sort flows, 768px for summary balance views) with `1.5rem` outer margins.\n- **Sorting Viewports:** Sorting columns or buckets utilize vertical flex stacks with `space-sm` or `space-md` separation to maintain clear tactile drop zones and distinct groupings.\n\n## Elevation & Depth\n\nVisual depth is achieved through layered warm surfaces paired with whisper-soft, colored ambient shadows rather than synthetic gray blurs.\n\n- **Flat / Ground Level:** Page background (`#FBF9F5`) with no shadow.\n- **Elevated Tiles & Cards:** Surface color `#F5F1EA` wrapped in a 1px border of `#E8E2D8`, elevated by a warm, diffuse ambient shadow: `box-shadow: 0 4px 16px -2px rgba(44, 40, 37, 0.04), 0 1px 4px 0 rgba(44, 40, 37, 0.02)`.\n- **Floating Controls & Active Drags:** While dragging or floating above other content, cards subtly lift: `box-shadow: 0 12px 28px -4px rgba(44, 40, 37, 0.08), 0 2px 8px 0 rgba(44, 40, 37, 0.03)`.\n- **Borders as Tone:** In place of strong contrast lines, borders act as quiet edge definitions using `#E8E2D8` to cleanly separate panels without fragmenting the canvas.\n\n## Shapes\n\nThe design system embraces a high-radius, organic shape language (`roundedness: 3`).\n\n- **Pill Geometry:** Interactive buttons, category filters, and selection pills utilize complete capsule geometry (`rounded-full`), reinforcing physical softness and comfort in the hand.\n- **Cards & Value Containers:** Larger surfaces utilize relaxed, generous border radii (`1.5rem` to `2rem` / `rounded-xl` to `rounded-2xl`), eliminating aggressive edges and providing an organic, pebble-like quality to draggable cards.\n- **Inset Wells & Modals:** Droppable sort regions adopt matching rounded corners to establish a natural visual container for nested items.\n\n## Components\n\n### Buttons\n- **Primary:** Full capsule (`rounded-full`) pill button with a `#2C2825` or `#7D6B58` background, `#FBF9F5` typography, and generous horizontal padding (`1.75rem`). No heavy drop shadows; tactile feedback relies on soft tonal lightening on press.\n- **Secondary / Gentle:** Subtle stone pill surface (`#F5F1EA`) with a 1px `#E8E2D8` border and `#2C2825` text.\n- **Ghost / Reflective:** Borderless with `#4A443F` text, emphasizing deliberate, low-urgency actions (e.g., \"Skip for now\", \"Pause reflection\").\n\n### Value Cards (Sorting Unit)\n- **Resting:** Background `#F5F1EA`, border 1px solid `#E8E2D8`, padding `space-lg`, radius `1.5rem`. Title set in `Newsreader` (`headline-md`) with an optional single-sentence descriptor below in `Plus Jakarta Sans` (`body-sm`, `#4A443F`).\n- **Dragging / Active:** Slight scale increase (1.02x) with ambient shadow lift and an accent border transition to `#C87D55`.\n\n### Chips & Sort Buckets\n- **Chips:** Capsule pills with `0.5rem` vertical and `1rem` horizontal padding. Selected states transition from background `#F5F1EA` to `#E8E2D8` with text shifting to `#2C2825`.\n- **Sort Buckets (Drop Zones):** Spacious containers framed in dashed or soft solid lines of `#E8E2D8` with background `#FBF9F5`. Labelled with serene, muted headers (e.g., *Always True for Me*, *Important to Me*, *Rarely Considered*).\n\n### Lists & Prompts\n- Framed in full-width soft-edged tiles or separated by subtle `#E8E2D8` hairline dividers. Touch targets remain large (`min-height: 52px`), accompanied by relaxed vertical spacing.\n\n### Checkboxes & Radio Buttons\n- Rounded indicators (circular radios, `6px` radius checkboxes) using `#E8E2D8` borders that fill with muted sage (`#6B8168`) or terracotta (`#C87D55`) when selected, accompanied by a soft white icon check.\n\n### Input Fields\n- Understated input panels with background `#F5F1EA`, bordered in `#E8E2D8`, rounding to `1rem`. Active focus shifts border tone smoothly to `#7D6B58` with no high-contrast glow rings.\n\n### Specialized Component: Contemplative Reflection Sheet\n- A bottom sheet modal featuring a soft drag handle, `2rem` top border radii, linen-stone background (`#F5F1EA`), and generous whitespace designed specifically for writing personal rationales during deep values prioritization.", + "colorVariant": "FIDELITY", + "overridePrimaryColor": "#7d6b58", + "overrideSecondaryColor": "#c87d55", + "overrideTertiaryColor": "#6b8168", + "overrideNeutralColor": "#f5f1ea", + "spacingScale": 2, + "typography": { + "label-lg": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "15px", + "fontWeight": "600", + "lineHeight": "20px", + "letterSpacing": "0.01em" + }, + "headline-lg": { + "fontFamily": "Newsreader", + "fontSize": "30px", + "fontWeight": "400", + "lineHeight": "38px", + "letterSpacing": "-0.01em" + }, + "label-md": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "13px", + "fontWeight": "500", + "lineHeight": "18px", + "letterSpacing": "0.02em" + }, + "body-md": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "16px", + "fontWeight": "400", + "lineHeight": "24px" + }, + "headline-xl": { + "fontFamily": "Newsreader", + "fontSize": "40px", + "fontWeight": "400", + "lineHeight": "48px", + "letterSpacing": "-0.02em" + }, + "headline-lg-mobile": { + "fontFamily": "Newsreader", + "fontSize": "26px", + "fontWeight": "400", + "lineHeight": "34px", + "letterSpacing": "0em" + }, + "headline-md": { + "fontFamily": "Newsreader", + "fontSize": "22px", + "fontWeight": "400", + "lineHeight": "30px" + }, + "body-lg": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "18px", + "fontWeight": "400", + "lineHeight": "28px" + }, + "body-sm": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "14px", + "fontWeight": "400", + "lineHeight": "20px" + }, + "headline-xl-mobile": { + "fontFamily": "Newsreader", + "fontSize": "32px", + "fontWeight": "400", + "lineHeight": "40px", + "letterSpacing": "-0.01em" + }, + "label-sm": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "11px", + "fontWeight": "600", + "lineHeight": "16px", + "letterSpacing": "0.04em" + } + }, + "spacing": { + "space-xs": "0.25rem", + "margin-mobile": "1.25rem", + "space-md": "1rem", + "space-lg": "1.5rem", + "margin": "1.5rem", + "gutter-mobile": "0.75rem", + "gutter": "1rem", + "space-xl": "2.5rem", + "space-sm": "0.5rem" + }, + "headlineFontFamily": "Newsreader", + "bodyFontFamily": "Plus Jakarta Sans", + "labelFontFamily": "Plus Jakarta Sans" +} \ No newline at end of file diff --git a/stitch/manifest.json b/stitch/manifest.json new file mode 100644 index 0000000..f8a1a8a --- /dev/null +++ b/stitch/manifest.json @@ -0,0 +1,110 @@ +[ + { + "id": "e3940f39a073450299cb3024914064c6", + "slug": "welcome", + "title": "Values Sort \u2014 Welcome (with Guide Drawer)", + "width": "780", + "height": "1768", + "deviceType": "MOBILE", + "htmlUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyNTQwYmQ5N2IwMjNiZTk5NjE2MDEzZDgzEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "screenshotUrl": "https://lh3.googleusercontent.com/aida/AEtjO1XxoE8CbYmmotxXpSsZdC3wUE-E_xSas8nAxp_8GIUsaVeT2TjBeYVAwZM64nKp2KiGgcv4OGIq2noOJzxbWuzc-L2mitY9iU_fmiwGqgff0u7RpyjXlC0eRZlhvcRybK_E_dFQ_b8Q3GBOP06crg0MlaWtIPMS9WT-WIwmui7yJkqcEDsjlJlU8reI8HinfJtzvxK1gfOfEWbLDV5gPc7T_ypo6WR-fM3lZ35FSrkH4NQoX2e-d1-DlO0", + "htmlFile": "welcome.html", + "htmlBytes": 17353, + "screenshotFile": "welcome.png", + "screenshotBytes": 35118 + }, + { + "id": "07a9fc8b113c479db7ece5398a017a9e", + "slug": "rank-order", + "title": "Values Sort \u2014 Rank Order Top Values", + "width": "780", + "height": "4408", + "deviceType": "MOBILE", + "htmlUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyY2VlNWY5MzgwMjNiZWU1MjMxMjVjMzFhEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "screenshotUrl": "https://lh3.googleusercontent.com/aida/AEtjO1WpFA576TA5wf1HnZIoIBm8m5-S0M9LlUvAz8ujVYmbkVydsAdUAmtOpQKsY9nixUIwZEd5bqrDTe6ITlJfFFRhDRxkehFVmgcdAZksW9L89pME6e2gTYuO-qqFQKwD-XAXg_PDunjOg8XZeYs5p1dIVenclfxkXwSQ4Y0IIDTHtIMONRE4S07sHY7skqnnL-f2vmbEBg3ah1WyjcLXIUFIL4AINmYK-vTMCxwwsQ_ev3qhq909m7CdoQ", + "htmlFile": "rank-order.html", + "htmlBytes": 35244, + "screenshotFile": "rank-order.png", + "screenshotBytes": 2676 + }, + { + "id": "73272c6039864978bcec444c7df2973f", + "slug": "most-important", + "title": "Values Sort \u2014 Most Important (with Demote Drawer)", + "width": "780", + "height": "6564", + "deviceType": "MOBILE", + "htmlUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyNzZkYjg4ZjgwNWYxMzVmZTYyMDcyNzBkEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "screenshotUrl": "https://lh3.googleusercontent.com/aida/AEtjO1Xhu39G6wcAy9suH2BL28jVCSboZ_ydBY69b4vlY9-gtnbu66RyRiHaRDF8MkiSVfcjYFtlIVfpFgyN856OBgA4qenmijh6Uii1vIm22lmUNWElTOI1GSSUyOF_NMNLN7N3HKNwLY6pc0PlrUBoB--DVbW6-RcnqfBG-CIAFWWzuOn0YEXUIbLzFLfecIwxJbbHEblBtC8m7q0RR140TUxcbtxtzHRX_km3es8xnlabSjh1DMxb3K1Efg", + "htmlFile": "most-important.html", + "htmlBytes": 55201, + "screenshotFile": "most-important.png", + "screenshotBytes": 24782 + }, + { + "id": "8ca48b5fb47f46efb62882151cf3966d", + "slug": "card-sorting", + "title": "Values Sort \u2014 Card Sorting (5 Piles)", + "width": "780", + "height": "1768", + "deviceType": "MOBILE", + "htmlUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyNTNlZWY1YjEwNGU3NTljNGQwMzgyZWUzEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "screenshotUrl": "https://lh3.googleusercontent.com/aida/AEtjO1UKPd2AvYz_Ucd2ae0AXKkL1mf0yGN6F1_AxDfBFGuduAa3Glzo-QZSGEM9bnNThdbJBwaLp6-YZKG96EL79UjeMqDwutbANo2j2Xxdxyo3S-P2kEfS5WsFqdk99nTzvphFypQtiFa5uF_CftoMwJRKKFm1D8Xo3YaGT07BEPrl09YGNSZR0wytLyEJUkl9Y2epmCJMJ_NiudNMLR-JxcsXqk5XndAVRz09mkUI3A8JitbLiv6Z3QlZDSU", + "htmlFile": "card-sorting.html", + "htmlBytes": 18377, + "screenshotFile": "card-sorting.png", + "screenshotBytes": 75318 + }, + { + "id": "12809277486904866316", + "slug": "important-cards", + "title": "Values Sort \u2014 Important Cards (Pile 3)", + "width": "780", + "height": "2766", + "deviceType": "MOBILE", + "htmlUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyODM5NjZmMWUwNGU3NThiMjE2MDFkYWQxEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "screenshotUrl": "https://lh3.googleusercontent.com/aida/AEtjO1XQVoRrEK9mxF3gFjm9RD-lkFg-pwyvf_kJsLOREyZzFD3UWWWPbcivFX2aIvhiewCkv3Rw4SWGxq3AtN-TbfKPD2L4R0QKA3XPc_RImmva7z66yTUJo8bvozFBpwKdHXo5vPaxqB2-UyjVDLrfiCY75WYAkp6P0BF4W3xqoRy8mWUqe5ljCtjlIwbyo2GyR66wkPSOAeUqFl6s0jLycyB7MAaiBbBPOejz27uo2xYdbppL0Bzc7XVrpeE", + "htmlFile": "important-cards.html", + "htmlBytes": 30492, + "screenshotFile": "important-cards.png", + "screenshotBytes": 47590 + }, + { + "id": "7bb00b6022b14dd9a687b9a31ec6b1f5", + "slug": "reflection-journal", + "title": "Values Sort \u2014 Reflection (Full-Screen Journal Drawer)", + "width": "780", + "height": "3596", + "deviceType": "MOBILE", + "htmlUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyYWE0ZDI3M2IwMjNiZWU1MjMxMjVjMzFhEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "screenshotUrl": "https://lh3.googleusercontent.com/aida/AEtjO1UAeYCnBIII639-PoE0tFfV3LHW2yIsQ2XGm0L6YPETkrpzkMplK_QGvg-8F8PSLt_oJCS-3Uajl851y6H1IkywclVOp_OG34ANFKKEmKIyGFxXYg-XXlWWlanu_22zhpb_lhiO4auBOIFSxwwFc2NbU3b6qlsAIlBGONtInErxesAiJILt6j1yKKM1OkGJIrh4sWabbDoAfBNaJlu_hDywInGjs4j-d6SZOEvzgunjmwSjLStHmjuQoVk", + "htmlFile": "reflection-journal.html", + "htmlBytes": 27117, + "screenshotFile": "reflection-journal.png", + "screenshotBytes": 4968 + }, + { + "id": "3064045350829608185", + "slug": "reflect-top-values", + "title": "Values Sort \u2014 Reflect on Top Values", + "width": "780", + "height": "3384", + "deviceType": "MOBILE", + "htmlUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyOWJmZTJmY2UwOTY4YTAzNjNmMGQ1ODhmEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "screenshotUrl": "https://lh3.googleusercontent.com/aida/AEtjO1Uwhwbp12i_K453L9y11FLMvbRC4yDVlY0fdRpaqI4rBUKKwEFBEzO2fbvVyKER5fnk5X11ceImXKtx6h37TpNJIYr6CZNuNhJc1LNKbOGiV_CO3ee7AVc0nOez48-19Q7vf8_H6Q1DlfjZj3B3v2X23in3GCgyxo5rAa-NsMkS9_G4oCvnWSIioTblp-viQRuJhyq3jIlEldpfZPkU5FQh7hr6lH9RMVXv2Pdy_sviQJK_4R2KOQJxAUc", + "htmlFile": "reflect-top-values.html", + "htmlBytes": 20710, + "screenshotFile": "reflect-top-values.png", + "screenshotBytes": 4038 + }, + { + "id": "7247b606c08a44ef906836e5ab250fd1", + "slug": "practice-hub", + "title": "Values Sort \u2014 Practice Hub", + "width": "780", + "height": "3234", + "deviceType": "MOBILE", + "htmlFile": "practice-hub.html", + "screenshotFile": "practice-hub.png" + } +] \ No newline at end of file diff --git a/stitch/project.json b/stitch/project.json new file mode 100644 index 0000000..80c4c16 --- /dev/null +++ b/stitch/project.json @@ -0,0 +1,303 @@ +{ + "name": "projects/9343387512370733994", + "title": "Values Sort Mobile App", + "visibility": "PRIVATE", + "createTime": "2026-09-17T18:22:37.967958Z", + "updateTime": "2026-09-17T19:32:15.071439Z", + "projectType": "TEXT_TO_UI_PRO", + "thumbnailScreenshot": { + "name": "projects/9343387512370733994/screens/05c62dda94e39f4e2cb65bb50b9ec87d86c39268fc039c1f7ebc10b52944e933/fileEntries/screenshot", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1WAKWJpnfMBurZlT--UYRl0Dz9CevwxR_CIsiqZClT3GGTRynx9-KJ0fYv-JWeD-ymxbKoNpCCx-e3YybnPF-_cnlVPsht0qgChcKBG0PFxvAhgz6Xk0ceCi-zF0cCe4zd_KPQDCbNgMOg17zkUl0WO-qTqcfOjYZd1r38i9f77X-BRNyf2LOcLl3BtxXCJDbf2uv4CatP7UI0S0O8pHz54rbvBC8gOPzESLT1BRtLAjgO4aF6T5QI0Cg" + }, + "origin": "STITCH", + "deviceType": "DESKTOP", + "designTheme": { + "colorMode": "LIGHT", + "font": "NEWSREADER", + "roundness": "ROUND_FULL", + "customColor": "#7d6b58", + "headlineFont": "NEWSREADER", + "bodyFont": "PLUS_JAKARTA_SANS", + "labelFont": "PLUS_JAKARTA_SANS", + "namedColors": { + "surface_container_low": "#f7f3ec", + "secondary_container": "#feaa7f", + "on_error": "#ffffff", + "on_background": "#1c1c18", + "surface_bright": "#fdf9f2", + "surface_container_high": "#ece8e1", + "on_tertiary_fixed_variant": "#374c36", + "on_error_container": "#93000a", + "on_primary": "#ffffff", + "inverse_surface": "#31302c", + "on_primary_fixed_variant": "#544433", + "primary_fixed_dim": "#d9c3ac", + "on_tertiary_container": "#e1f9db", + "secondary_fixed_dim": "#ffb691", + "primary": "#635341", + "surface_container_highest": "#e6e2db", + "background": "#fdf9f2", + "surface_container_lowest": "#ffffff", + "surface_variant": "#e6e2db", + "error": "#ba1a1a", + "on_secondary_container": "#783d1a", + "on_secondary": "#ffffff", + "tertiary": "#465b44", + "tertiary_container": "#5e745c", + "on_primary_fixed": "#25190b", + "on_primary_container": "#ffefe1", + "on_secondary_fixed": "#341100", + "primary_fixed": "#f6dfc7", + "outline_variant": "#d0c4ba", + "surface_tint": "#6c5b49", + "error_container": "#ffdad6", + "surface_dim": "#dddad3", + "inverse_primary": "#d9c3ac", + "on_surface": "#1c1c18", + "secondary_fixed": "#ffdbcb", + "tertiary_fixed": "#d1e9cc", + "on_secondary_fixed_variant": "#713714", + "primary_container": "#7d6b58", + "tertiary_fixed_dim": "#b5cdb0", + "on_tertiary": "#ffffff", + "secondary": "#8e4d2a", + "on_surface_variant": "#4d453e", + "surface": "#fdf9f2", + "outline": "#7f756d", + "on_tertiary_fixed": "#0d200d", + "inverse_on_surface": "#f4f0e9", + "surface_container": "#f1ede6" + }, + "designMd": "---\nname: Mindful Values Architecture\ncolors:\n surface: '#fdf9f2'\n surface-dim: '#dddad3'\n surface-bright: '#fdf9f2'\n surface-container-lowest: '#ffffff'\n surface-container-low: '#f7f3ec'\n surface-container: '#f1ede6'\n surface-container-high: '#ece8e1'\n surface-container-highest: '#e6e2db'\n on-surface: '#1c1c18'\n on-surface-variant: '#4d453e'\n inverse-surface: '#31302c'\n inverse-on-surface: '#f4f0e9'\n outline: '#7f756d'\n outline-variant: '#d0c4ba'\n surface-tint: '#6c5b49'\n primary: '#635341'\n on-primary: '#ffffff'\n primary-container: '#7d6b58'\n on-primary-container: '#ffefe1'\n inverse-primary: '#d9c3ac'\n secondary: '#8e4d2a'\n on-secondary: '#ffffff'\n secondary-container: '#feaa7f'\n on-secondary-container: '#783d1a'\n tertiary: '#465b44'\n on-tertiary: '#ffffff'\n tertiary-container: '#5e745c'\n on-tertiary-container: '#e1f9db'\n error: '#ba1a1a'\n on-error: '#ffffff'\n error-container: '#ffdad6'\n on-error-container: '#93000a'\n primary-fixed: '#f6dfc7'\n primary-fixed-dim: '#d9c3ac'\n on-primary-fixed: '#25190b'\n on-primary-fixed-variant: '#544433'\n secondary-fixed: '#ffdbcb'\n secondary-fixed-dim: '#ffb691'\n on-secondary-fixed: '#341100'\n on-secondary-fixed-variant: '#713714'\n tertiary-fixed: '#d1e9cc'\n tertiary-fixed-dim: '#b5cdb0'\n on-tertiary-fixed: '#0d200d'\n on-tertiary-fixed-variant: '#374c36'\n background: '#fdf9f2'\n on-background: '#1c1c18'\n surface-variant: '#e6e2db'\ntypography:\n headline-xl:\n fontFamily: Newsreader\n fontSize: 40px\n fontWeight: '400'\n lineHeight: 48px\n letterSpacing: -0.02em\n headline-xl-mobile:\n fontFamily: Newsreader\n fontSize: 32px\n fontWeight: '400'\n lineHeight: 40px\n letterSpacing: -0.01em\n headline-lg:\n fontFamily: Newsreader\n fontSize: 30px\n fontWeight: '400'\n lineHeight: 38px\n letterSpacing: -0.01em\n headline-lg-mobile:\n fontFamily: Newsreader\n fontSize: 26px\n fontWeight: '400'\n lineHeight: 34px\n letterSpacing: 0em\n headline-md:\n fontFamily: Newsreader\n fontSize: 22px\n fontWeight: '400'\n lineHeight: 30px\n body-lg:\n fontFamily: Plus Jakarta Sans\n fontSize: 18px\n fontWeight: '400'\n lineHeight: 28px\n body-md:\n fontFamily: Plus Jakarta Sans\n fontSize: 16px\n fontWeight: '400'\n lineHeight: 24px\n body-sm:\n fontFamily: Plus Jakarta Sans\n fontSize: 14px\n fontWeight: '400'\n lineHeight: 20px\n label-lg:\n fontFamily: Plus Jakarta Sans\n fontSize: 15px\n fontWeight: '600'\n lineHeight: 20px\n letterSpacing: 0.01em\n label-md:\n fontFamily: Plus Jakarta Sans\n fontSize: 13px\n fontWeight: '500'\n lineHeight: 18px\n letterSpacing: 0.02em\n label-sm:\n fontFamily: Plus Jakarta Sans\n fontSize: 11px\n fontWeight: '600'\n lineHeight: 16px\n letterSpacing: 0.04em\nrounded:\n sm: 0.5rem\n DEFAULT: 1rem\n md: 1.5rem\n lg: 2rem\n xl: 3rem\n full: 9999px\nspacing:\n gutter: 1rem\n gutter-mobile: 0.75rem\n margin: 1.5rem\n margin-mobile: 1.25rem\n space-xs: 0.25rem\n space-sm: 0.5rem\n space-md: 1rem\n space-lg: 1.5rem\n space-xl: 2.5rem\n---\n\n## Brand & Style\n\nThis design system is crafted for deep introspection, intentional decision-making, and personal grounding. It serves individuals navigating life transitions, therapeutic exercises, and values-clarification practices. The experience is designed to feel unhurried, quietly reverent, and deeply personal\u2014eschewing addictive loops, loud notifications, and superficial gamification in favor of sustained focus and calm contemplation.\n\nThe visual style blends **warm editorial minimalism** with **tactile paper-like depth**. It draws inspiration from artisanal bookbinding, linen stationery, and modern contemplative journals:\n- **Atmosphere:** Serene, grounded, deliberate, and emotionally secure.\n- **Rhythm:** Generous breathing room with relaxed vertical pacing, inviting the eye to linger and pause.\n- **Materiality:** Soft stone surfaces, delicate warm contours, and nuanced diffuse shadows that ground elements without feeling synthetic or rigid.\n\n## Colors\n\nThe palette is rooted in the natural world: mineral sands, quiet clay, sun-bleached stone, and muted foliage. The dynamic range avoids stark pure whites and abrasive digital blacks, fostering an environment free of eye strain and cognitive fatigue.\n\n### Color Tiers & Intent\n- **Canvas Base (`#FBF9F5`):** The primary view background; evokes raw, unbleached cotton paper.\n- **Surface Elevation (`#F5F1EA`):** Neutral surface for raised cards, value tiles, and interactive sheets.\n- **Subtle Surface & Dividers (`#E8E2D8`):** Restful borders, inset surfaces, and non-intrusive separators.\n- **Primary / Earth Ground (`#7D6B58`):** A balanced warm taupe-stone that grounds primary interactive states and contemplative highlights.\n- **Secondary / Terracotta Accent (`#C87D55`):** A soft, sun-dried clay tone used selectively for active selections, progress markers, and reflective milestones.\n- **Tertiary / Sage Accent (`#6B8168`):** A muted eucalyptus green designated for affirmation states, grounded confirmations, and calm categorization.\n- **Text & Contrast (`#2C2825` Primary, `#4A443F` Secondary):** Deep espresso and soft slate hues that preserve crisp readability with none of the harshness of pure black.\n\n## Typography\n\nThe typographic hierarchy balances literary gravitas with clean, approachable utility. \n\n- **Display & Headlines (`Newsreader`):** An editorial, high-character serif that confers an intellectual, gentle, book-like presence. Headlines use standard weight and slightly negative tracking to evoke printed literary works.\n- **Body & Labels (`Plus Jakarta Sans`):** A soft, humanist geometric sans-serif that balances modern legibility with rounded, friendly terminal strokes. It delivers effortless readability across reflection prompts, explanatory texts, and compact mobile UI controls.\n- **Rhythm & Formatting:** Line heights remain generous across all tiers to safeguard vertical breathing room and prevent visual crowding during dense contemplative sessions.\n\n## Layout & Spacing\n\nThe layout is built around spacious, open single-column and modular card streams suited for portrait handheld usage. It prioritizes focus by presenting a limited number of elements on screen at any given time.\n\n### Grid & Form Factors\n- **Mobile (<640px):** Single-column layout with fluid full-width cards anchored by `1.25rem` outer canvas padding. Component stacks maintain `space-md` gaps.\n- **Tablet (640px\u20131024px):** Centered max-width canvas (600px for reflective sort flows, 768px for summary balance views) with `1.5rem` outer margins.\n- **Sorting Viewports:** Sorting columns or buckets utilize vertical flex stacks with `space-sm` or `space-md` separation to maintain clear tactile drop zones and distinct groupings.\n\n## Elevation & Depth\n\nVisual depth is achieved through layered warm surfaces paired with whisper-soft, colored ambient shadows rather than synthetic gray blurs.\n\n- **Flat / Ground Level:** Page background (`#FBF9F5`) with no shadow.\n- **Elevated Tiles & Cards:** Surface color `#F5F1EA` wrapped in a 1px border of `#E8E2D8`, elevated by a warm, diffuse ambient shadow: `box-shadow: 0 4px 16px -2px rgba(44, 40, 37, 0.04), 0 1px 4px 0 rgba(44, 40, 37, 0.02)`.\n- **Floating Controls & Active Drags:** While dragging or floating above other content, cards subtly lift: `box-shadow: 0 12px 28px -4px rgba(44, 40, 37, 0.08), 0 2px 8px 0 rgba(44, 40, 37, 0.03)`.\n- **Borders as Tone:** In place of strong contrast lines, borders act as quiet edge definitions using `#E8E2D8` to cleanly separate panels without fragmenting the canvas.\n\n## Shapes\n\nThe design system embraces a high-radius, organic shape language (`roundedness: 3`).\n\n- **Pill Geometry:** Interactive buttons, category filters, and selection pills utilize complete capsule geometry (`rounded-full`), reinforcing physical softness and comfort in the hand.\n- **Cards & Value Containers:** Larger surfaces utilize relaxed, generous border radii (`1.5rem` to `2rem` / `rounded-xl` to `rounded-2xl`), eliminating aggressive edges and providing an organic, pebble-like quality to draggable cards.\n- **Inset Wells & Modals:** Droppable sort regions adopt matching rounded corners to establish a natural visual container for nested items.\n\n## Components\n\n### Buttons\n- **Primary:** Full capsule (`rounded-full`) pill button with a `#2C2825` or `#7D6B58` background, `#FBF9F5` typography, and generous horizontal padding (`1.75rem`). No heavy drop shadows; tactile feedback relies on soft tonal lightening on press.\n- **Secondary / Gentle:** Subtle stone pill surface (`#F5F1EA`) with a 1px `#E8E2D8` border and `#2C2825` text.\n- **Ghost / Reflective:** Borderless with `#4A443F` text, emphasizing deliberate, low-urgency actions (e.g., \"Skip for now\", \"Pause reflection\").\n\n### Value Cards (Sorting Unit)\n- **Resting:** Background `#F5F1EA`, border 1px solid `#E8E2D8`, padding `space-lg`, radius `1.5rem`. Title set in `Newsreader` (`headline-md`) with an optional single-sentence descriptor below in `Plus Jakarta Sans` (`body-sm`, `#4A443F`).\n- **Dragging / Active:** Slight scale increase (1.02x) with ambient shadow lift and an accent border transition to `#C87D55`.\n\n### Chips & Sort Buckets\n- **Chips:** Capsule pills with `0.5rem` vertical and `1rem` horizontal padding. Selected states transition from background `#F5F1EA` to `#E8E2D8` with text shifting to `#2C2825`.\n- **Sort Buckets (Drop Zones):** Spacious containers framed in dashed or soft solid lines of `#E8E2D8` with background `#FBF9F5`. Labelled with serene, muted headers (e.g., *Always True for Me*, *Important to Me*, *Rarely Considered*).\n\n### Lists & Prompts\n- Framed in full-width soft-edged tiles or separated by subtle `#E8E2D8` hairline dividers. Touch targets remain large (`min-height: 52px`), accompanied by relaxed vertical spacing.\n\n### Checkboxes & Radio Buttons\n- Rounded indicators (circular radios, `6px` radius checkboxes) using `#E8E2D8` borders that fill with muted sage (`#6B8168`) or terracotta (`#C87D55`) when selected, accompanied by a soft white icon check.\n\n### Input Fields\n- Understated input panels with background `#F5F1EA`, bordered in `#E8E2D8`, rounding to `1rem`. Active focus shifts border tone smoothly to `#7D6B58` with no high-contrast glow rings.\n\n### Specialized Component: Contemplative Reflection Sheet\n- A bottom sheet modal featuring a soft drag handle, `2rem` top border radii, linen-stone background (`#F5F1EA`), and generous whitespace designed specifically for writing personal rationales during deep values prioritization.", + "colorVariant": "FIDELITY", + "overridePrimaryColor": "#7d6b58", + "overrideSecondaryColor": "#c87d55", + "overrideTertiaryColor": "#6b8168", + "overrideNeutralColor": "#f5f1ea", + "spacingScale": 2, + "typography": { + "label-lg": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "15px", + "fontWeight": "600", + "lineHeight": "20px", + "letterSpacing": "0.01em" + }, + "headline-lg": { + "fontFamily": "Newsreader", + "fontSize": "30px", + "fontWeight": "400", + "lineHeight": "38px", + "letterSpacing": "-0.01em" + }, + "label-md": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "13px", + "fontWeight": "500", + "lineHeight": "18px", + "letterSpacing": "0.02em" + }, + "body-md": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "16px", + "fontWeight": "400", + "lineHeight": "24px" + }, + "headline-xl": { + "fontFamily": "Newsreader", + "fontSize": "40px", + "fontWeight": "400", + "lineHeight": "48px", + "letterSpacing": "-0.02em" + }, + "headline-lg-mobile": { + "fontFamily": "Newsreader", + "fontSize": "26px", + "fontWeight": "400", + "lineHeight": "34px", + "letterSpacing": "0em" + }, + "headline-md": { + "fontFamily": "Newsreader", + "fontSize": "22px", + "fontWeight": "400", + "lineHeight": "30px" + }, + "body-lg": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "18px", + "fontWeight": "400", + "lineHeight": "28px" + }, + "body-sm": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "14px", + "fontWeight": "400", + "lineHeight": "20px" + }, + "headline-xl-mobile": { + "fontFamily": "Newsreader", + "fontSize": "32px", + "fontWeight": "400", + "lineHeight": "40px", + "letterSpacing": "-0.01em" + }, + "label-sm": { + "fontFamily": "Plus Jakarta Sans", + "fontSize": "11px", + "fontWeight": "600", + "lineHeight": "16px", + "letterSpacing": "0.04em" + } + }, + "spacing": { + "space-xs": "0.25rem", + "margin-mobile": "1.25rem", + "space-md": "1rem", + "space-lg": "1.5rem", + "margin": "1.5rem", + "gutter-mobile": "0.75rem", + "gutter": "1rem", + "space-xl": "2.5rem", + "space-sm": "0.5rem" + }, + "headlineFontFamily": "Newsreader", + "bodyFontFamily": "Plus Jakarta Sans", + "labelFontFamily": "Plus Jakarta Sans" + }, + "screenInstances": [ + { + "id": "07a9fc8b113c479db7ece5398a017a9e", + "sourceScreen": "projects/9343387512370733994/screens/07a9fc8b113c479db7ece5398a017a9e", + "x": 2506, + "y": 915, + "width": 390, + "height": 2124 + }, + { + "id": "12b14f518efb4476b2231b355342fb5d", + "sourceScreen": "projects/9343387512370733994/screens/12b14f518efb4476b2231b355342fb5d", + "x": 454, + "y": 2915, + "width": 390, + "height": 3434, + "hidden": true + }, + { + "id": "56fc5818737e435a8ecfe443599f2194", + "sourceScreen": "projects/9343387512370733994/screens/56fc5818737e435a8ecfe443599f2194", + "x": 1198, + "y": 2824, + "width": 390, + "height": 1383, + "hidden": true + }, + { + "id": "56fc5818737e435a8ecfe443599f2194-1789672128693", + "sourceScreen": "projects/9343387512370733994/screens/12809277486904866316", + "x": 3990, + "y": 936, + "width": 390, + "height": 1383 + }, + { + "id": "73272c6039864978bcec444c7df2973f", + "sourceScreen": "projects/9343387512370733994/screens/73272c6039864978bcec444c7df2973f", + "x": 3121, + "y": 978, + "width": 665, + "height": 2583 + }, + { + "id": "753eb21cb2754812961d396bb614563e", + "sourceScreen": "projects/9343387512370733994/screens/753eb21cb2754812961d396bb614563e", + "y": 928, + "width": 390, + "height": 1731, + "hidden": true + }, + { + "id": "7bb00b6022b14dd9a687b9a31ec6b1f5", + "sourceScreen": "projects/9343387512370733994/screens/7bb00b6022b14dd9a687b9a31ec6b1f5", + "x": 3622, + "y": 4505, + "width": 396, + "height": 1706, + "isResized": true + }, + { + "id": "8ca48b5fb47f46efb62882151cf3966d", + "sourceScreen": "projects/9343387512370733994/screens/8ca48b5fb47f46efb62882151cf3966d", + "x": 2948, + "y": 35, + "width": 395, + "height": 610 + }, + { + "id": "9b6c94164dea484f9a3bda995fac24fd", + "sourceScreen": "projects/9343387512370733994/screens/9b6c94164dea484f9a3bda995fac24fd", + "x": 1024, + "width": 512, + "height": 504 + }, + { + "id": "a646e40f534441db8c79e958d2a4443d", + "sourceScreen": "projects/9343387512370733994/screens/a646e40f534441db8c79e958d2a4443d", + "x": 2546, + "y": 4035, + "width": 390, + "height": 1836, + "hidden": true + }, + { + "id": "a646e40f534441db8c79e958d2a4443d-1789672538001", + "sourceScreen": "projects/9343387512370733994/screens/3064045350829608185", + "x": 3098, + "y": 4088, + "width": 460, + "height": 1704, + "isResized": true + }, + { + "id": "ae3467a3fe474e3eab1a2347b58853ef", + "sourceScreen": "projects/9343387512370733994/screens/ae3467a3fe474e3eab1a2347b58853ef", + "x": 1600, + "width": 390, + "height": 712, + "hidden": true + }, + { + "id": "ae3467a3fe474e3eab1a2347b58853ef-1789669940549", + "sourceScreen": "projects/9343387512370733994/screens/12479456381332509331", + "x": 2052, + "width": 390, + "height": 672, + "hidden": true + }, + { + "id": "assets_e82a9b9dabc94f3f883590193cadd6db", + "width": 960, + "height": 540, + "sourceAsset": "assets/e82a9b9dabc94f3f883590193cadd6db", + "type": "DESIGN_SYSTEM_INSTANCE" + }, + { + "id": "e3940f39a073450299cb3024914064c6", + "sourceScreen": "projects/9343387512370733994/screens/e3940f39a073450299cb3024914064c6", + "x": 2506, + "width": 390, + "height": 672 + }, + { + "id": "e3940f39a073450299cb3024914064c6-1789670090319", + "sourceScreen": "projects/9343387512370733994/screens/91919302947259240", + "x": 2068, + "width": 390, + "height": 672, + "hidden": true + } + ], + "metadata": { + "userRole": "OWNER" + } +} \ No newline at end of file diff --git a/stitch/screens/card-sorting.html b/stitch/screens/card-sorting.html new file mode 100644 index 0000000..4870ca2 --- /dev/null +++ b/stitch/screens/card-sorting.html @@ -0,0 +1,391 @@ +
+
+ +
+ +Stage 1 · Initial Sort +
+ +
+ +
+
+104 of 100 values sorted +100% +
+
+
+
+
+
+ +
+
+ +
+
+
+ +
+ + +
+ +

Compassion

+ +

Meeting human vulnerability, struggle, and limitation with open warmth and kindness.

+ + +
+
+
+ +
+ +
+ +layers + Assign to reflective pile + +Tap to sort +
+ +
+ + + + + + + + + + +
+ + +
+
+ + + \ No newline at end of file diff --git a/stitch/screens/card-sorting.json b/stitch/screens/card-sorting.json new file mode 100644 index 0000000..4461f24 --- /dev/null +++ b/stitch/screens/card-sorting.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/8ca48b5fb47f46efb62882151cf3966d", + "title": "Values Sort \u2014 Card Sorting (5 Piles)", + "screenshot": { + "name": "projects/9343387512370733994/files/15029646364846437108", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1UKPd2AvYz_Ucd2ae0AXKkL1mf0yGN6F1_AxDfBFGuduAa3Glzo-QZSGEM9bnNThdbJBwaLp6-YZKG96EL79UjeMqDwutbANo2j2Xxdxyo3S-P2kEfS5WsFqdk99nTzvphFypQtiFa5uF_CftoMwJRKKFm1D8Xo3YaGT07BEPrl09YGNSZR0wytLyEJUkl9Y2epmCJMJ_NiudNMLR-JxcsXqk5XndAVRz09mkUI3A8JitbLiv6Z3QlZDSU" + }, + "htmlCode": { + "name": "projects/9343387512370733994/files/10948046668312136526", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyNTNlZWY1YjEwNGU3NTljNGQwMzgyZWUzEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "1768", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/card-sorting.png b/stitch/screens/card-sorting.png new file mode 100644 index 0000000000000000000000000000000000000000..bb5682b4310bbbb0522ba30eb1acc6862f7f7ad8 GIT binary patch literal 75318 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 z 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 literal 0 HcmV?d00001 diff --git a/stitch/screens/important-cards.html b/stitch/screens/important-cards.html new file mode 100644 index 0000000..869ac0a --- /dev/null +++ b/stitch/screens/important-cards.html @@ -0,0 +1,467 @@ + + + + +
+ +
+
+
+Step 3 of 5 + +Reviewing Group +
+ +
+

+ Values Sort — Important Cards (Pile 3) +

+

+ 32 values considered meaningful, though secondary to your core anchors. +

+
+ + + +
+
+search + +
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + Presence + +

+ Equanimity +

+
+
+ + +
+
+

+ Maintaining inner balance and composure regardless of external turmoil or unexpected storms. +

+
+ +
+
+
+ + Growth + +

+ Curiosity +

+
+
+ + +
+
+

+ Approaching unknown frontiers with open wonder and eager inquiry rather than hasty assumptions. +

+
+ +
+
+
+ + Connection + +

+ Sincerity +

+
+
+ + +
+
+

+ Living and communicating without pretense, honoring what is genuine between ourselves and others. +

+
+ +
+
+
+ + Agency + +

+ Autonomy +

+
+
+ + +
+
+

+ The freedom to direct one’s own destiny, making choices grounded in authentic personal conviction. +

+
+ +
+
+
+ + Community + +

+ Hospitality +

+
+
+ + +
+
+

+ Extending warm physical and emotional sanctuary to neighbors, wanderers, and dear companions. +

+
+ +
+
+
+ + Growth + +

+ Craftsmanship +

+
+
+ + +
+
+

+ Devoting unhurried patience to shaping work with precision, care, and silent dedication. +

+
+
+ + + +
+
+ + +
+
+ +
+ + +
+check_circle +Value moved +
+
+
\ No newline at end of file diff --git a/stitch/screens/important-cards.json b/stitch/screens/important-cards.json new file mode 100644 index 0000000..5c5966e --- /dev/null +++ b/stitch/screens/important-cards.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/12809277486904866316", + "title": "Values Sort \u2014 Important Cards (Pile 3)", + "screenshot": { + "name": "projects/9343387512370733994/files/12809277486904866801", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1XQVoRrEK9mxF3gFjm9RD-lkFg-pwyvf_kJsLOREyZzFD3UWWWPbcivFX2aIvhiewCkv3Rw4SWGxq3AtN-TbfKPD2L4R0QKA3XPc_RImmva7z66yTUJo8bvozFBpwKdHXo5vPaxqB2-UyjVDLrfiCY75WYAkp6P0BF4W3xqoRy8mWUqe5ljCtjlIwbyo2GyR66wkPSOAeUqFl6s0jLycyB7MAaiBbBPOejz27uo2xYdbppL0Bzc7XVrpeE" + }, + "htmlCode": { + "name": "projects/9343387512370733994/files/12809277486904867286", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyODM5NjZmMWUwNGU3NThiMjE2MDFkYWQxEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "2766", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/important-cards.png b/stitch/screens/important-cards.png new file mode 100644 index 0000000000000000000000000000000000000000..8579622a4b3d7cea2b8cdb6f09b1a821a52fec0f GIT binary patch literal 47590 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 Z#AMwa>CIp&n6^M53NotFl~TsR{|8jHn0NpH literal 0 HcmV?d00001 diff --git a/stitch/screens/most-important.html b/stitch/screens/most-important.html new file mode 100644 index 0000000..d3a7700 --- /dev/null +++ b/stitch/screens/most-important.html @@ -0,0 +1,722 @@ + + + +
+ +
+ +
+
+
+ +
+
+

All Sorted Values

+100 Cards +
+

+ A bird’s-eye view of your 100 cards distributed across the 5 reflective piles. Review your intuition or gently rebalance. +

+ +
+
+ + + Distribution Profile + +8 Core Nominees +
+ +
+
+
+
+
+
+
+
+P5: 8 +P4: 18 +P3: 32 +P2: 24 +P1: 18 +
+
+
+ +
+
+search + + +
+
+ +
+ +
+ +
+
+
+5 +
+

Most Important

+
+
+8 cards +
+ +
+ +
+
+

Authenticity

+ +
+

+ Living in genuine alignment with inner truth and speaking without pretense or performance. +

+
+ +
+
+

Courage

+ +
+

+ Stepping directly into the unknown and acting in alignment with what is right, despite palpable fear. +

+
+ +
+
+

Compassion

+ +
+

+ Meeting suffering—in myself and others—with a gentle, unwavering posture of mercy and assistance. +

+
+ +
+
+

Freedom

+ +
+

+ Possessing agency over my time, movement, and life path without undue coercion or arbitrary constraints. +

+
+ +
+
+

Curiosity

+ +
+

+ Approaching life, people, and puzzles with wonder, humility, and an open thirst for understanding. +

+
+ +
+
+

Integrity

+ +
+

+ Upholding moral wholeness and consistency in character when nobody is watching. +

+
+ +
+
+

Connection

+ +
+

+ Fostering deep mutual bonds and empathy where souls are seen, understood, and cherished. +

+
+ +
+
+

Wisdom

+ +
+

+ Synthesizing deep experience and discernment into mindful, centered action. +

+
+
+
+ +
+
+
+4 +
+

Very Important

+

Strong priorities shaping everyday rhythms

+
+
+18 cards +
+
+
+ + + + + + + + + + + + + + + + + + + +
+
+Tap chip arrow to promote to Most Important +
+
+
+ +
+
+
+3 +
+

Important

+

Meaningful aspects kept in calm balance

+
+
+32 cards +
+
+
+Security +Order +Adventure +Discipline +Patience +Loyalty +Knowledge +Beauty +Playfulness +Solitude +Reliability +Honesty +Openness +Mastery +Intimacy +Balance +Presence +Acceptance +Clarity +Modesty +Vitality +Insight +Contribution +Depth +Cooperation +Resourcefulness +Adaptability +Spontaneity +Family +Community +
+
+
+ +
+
+
+2 +
+

Somewhat Important

+

Present, but rarely leading choices

+
+
+24 cards +
+
+
+Comfort +Tradition +Efficiency +Leisure +Predictability +Novelty +Ambition +Status +Precision +Competition +Thrift +Privacy +Recognition +Power +Popularity +Conformity +Charm +Intensity +Pleasure +Influence +Formality +Thrill +Reputation +Speed +
+
+
+ +
+
+
+1 +
+

Not Important

+

Consciously released from my life compass

+
+
+18 cards +
+
+
+Wealth +Fame +Authority +Luxury +Winning +Glamour +Perfection +Control +Hierarchy +Ritual +Dominance +Appearance +Acquisition +Strictness +Exclusivity +Superiority +Pride +Publicity +
+
+
+ + +
+ + +
+ + + +
+
+check_circle +Card moved +
+
+
\ No newline at end of file diff --git a/stitch/screens/most-important.json b/stitch/screens/most-important.json new file mode 100644 index 0000000..7602157 --- /dev/null +++ b/stitch/screens/most-important.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/73272c6039864978bcec444c7df2973f", + "title": "Values Sort \u2014 Most Important (with Demote Drawer)", + "screenshot": { + "name": "projects/9343387512370733994/screens/73272c6039864978bcec444c7df2973f/fileEntries/screenshot", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1Xhu39G6wcAy9suH2BL28jVCSboZ_ydBY69b4vlY9-gtnbu66RyRiHaRDF8MkiSVfcjYFtlIVfpFgyN856OBgA4qenmijh6Uii1vIm22lmUNWElTOI1GSSUyOF_NMNLN7N3HKNwLY6pc0PlrUBoB--DVbW6-RcnqfBG-CIAFWWzuOn0YEXUIbLzFLfecIwxJbbHEblBtC8m7q0RR140TUxcbtxtzHRX_km3es8xnlabSjh1DMxb3K1Efg" + }, + "htmlCode": { + "name": "projects/9343387512370733994/screens/73272c6039864978bcec444c7df2973f/fileEntries/html", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyNzZkYjg4ZjgwNWYxMzVmZTYyMDcyNzBkEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "6564", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/most-important.png b/stitch/screens/most-important.png new file mode 100644 index 0000000000000000000000000000000000000000..120e28f1e63595bd1e8409b8704c5f09a3067ecb GIT binary patch literal 24782 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 ds9K&2vq#zsS< +
+ +
+
+ +Values Sort Hub +
+ +
+ +
+
+spa + +
+

Your values landscape

+ +
+ +
stars

Your Core Values

The foundational principles selected as your highest inner compass:

1 Authenticity2 Courage3 Compassion4 Freedom5 Curiosity6 Integrity7 Connection8 Wisdom
+ +
+
+ + +
+ + + + + + +
+ +
+ +
+ +
+
+ + +
+
+ +
+
+ +
+
+
+hourglass_empty +
+
+

Reset Entire Practice?

+Clean slate contemplation +
+
+

+ This deliberate action will clear all 5 categorized piles, your prioritized 1–8 hierarchy, and stored reflection notes. You will begin this mindful exploration from the initial deck. +

+
+lightbulb + + Tip: You can pause here and revisit your values whenever you need clarity in daily choices without resetting. + +
+ +
+ + +
+
+
+
+
+ + \ No newline at end of file diff --git a/stitch/screens/practice-hub.json b/stitch/screens/practice-hub.json new file mode 100644 index 0000000..57f8633 --- /dev/null +++ b/stitch/screens/practice-hub.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/7247b606c08a44ef906836e5ab250fd1", + "title": "Values Sort \u2014 Practice Hub", + "screenshot": { + "name": "projects/9343387512370733994/files/7801972050289016175", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1UHEdAYHIX_yrZnosUKgBf2xJF0wQL3zTavsKvxg0OSr8wi6CA62NhoBaFMmJGpz7onY3fJBqEfn0FLm1DARm7R4FJ1Kvh-yLyufytn_LW9IJhT_HgxFUtYHE2lLfLUw0BK3O39haKwmhTXdWNkTAdlWoXmJZNRYACXJ6uXbfbXPvQsLtpT5LaQgBu30F_KmlrUqjUtsxxtzNzTEUF-GZhO8Hi-B5weq6pQ0aAppHrH13K3uxb0j6VwSiE" + }, + "htmlCode": { + "name": "projects/9343387512370733994/files/3785570347874661052", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmI0MDNhMzc1YWIwNWYxMjlkYjE3MDRmY2VkEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "3234", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/practice-hub.png b/stitch/screens/practice-hub.png new file mode 100644 index 0000000000000000000000000000000000000000..3d98e8ef8413edee736ee23c94c184f84df629ed GIT binary patch literal 5851 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 literal 0 HcmV?d00001 diff --git a/stitch/screens/rank-order.html b/stitch/screens/rank-order.html new file mode 100644 index 0000000..10509ee --- /dev/null +++ b/stitch/screens/rank-order.html @@ -0,0 +1,547 @@ + +
+ +
+
+
+ +Stage 3 of 4 · Prioritization +
+ +
+ +
+
+
+
+
+
+
+

Order Your Core Values

+

+ Drag or reorder your finalists. Let #1 represent your non-negotiable value.

+
+
+ + + +
+ +
+
+
+
1
+ +
starPrimary North Star
+
+ + +
+drag_indicator +
+
+
+
+

Authenticity

+

+ Living in honest alignment with who you are, without continuous performance or self-betrayal. +

+
+
+Pillar: Self-Alignment + +
+
+ + + +
+
+
+
2
+
+
+ + +
+drag_indicator +
+
+
+
+

Compassion

+

+ Meeting human frailty with gentleness, extending warmth before judgment. +

+
+
+Pillar: Relational + +
+
+ +
+
+
+
3
+
+
+ + +
+drag_indicator +
+
+
+
+

Freedom

+

+ Sovereignty over one’s calendar, bodily presence, and mental headspace. +

+
+
+Pillar: Independence + +
+
+ +
+
+
+
4
+
+
+ + +
+drag_indicator +
+
+
+
+

Curiosity

+

+ An open question kept alive without the desperate hurry to conclude. +

+
+
+Pillar: Growth + +
+
+ +
+
+
+
5
+
+
+ + +
+drag_indicator +
+
+
+
+

Integrity

+

+ Wholeness in private conduct; matching private conviction with public stance. +

+
+
+Pillar: Alignment + +
+
+
+
+
6
+Secondary Anchor +
+
+ + +
+drag_indicator +
+
+
+
+

Courage

+

+ Entering the uncertain room, speaking the tender truth despite physical trembling. +

+
+
+Pillar: Action + +
+
+ +
+
+
+
7
+
+
+ + +
+drag_indicator +
+
+
+
+

Connection

+

+ Deep, unhurried presence that allows another soul to feel seen and held. +

+
+
+Pillar: Relational + +
+
+ +
+
+
+
8
+
+
+ + +
+drag_indicator +
+
+
+
+

Creativity

+

+ The quiet joy of shaping raw experience into form, word, or tangible craft. +

+
+
+Pillar: Self-Expression + +
+
+
+ + + +
+
+psychology_alt +
+
+

Gentle Inquiry

+

+ Notice where inner resistance surfaces. Are you ranking what you truly value, or what you feel you should value for others? +

+
+
+ +
+
+

Stage Insight

+

+ "When values conflict under pressure, #1 determines your immediate direction." +

+
+
+ +
+
+ +
+ + +
+ + + + + + +
+check_circle +New hierarchy saved +
+
+
+ + \ No newline at end of file diff --git a/stitch/screens/rank-order.json b/stitch/screens/rank-order.json new file mode 100644 index 0000000..0a876c2 --- /dev/null +++ b/stitch/screens/rank-order.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/07a9fc8b113c479db7ece5398a017a9e", + "title": "Values Sort \u2014 Rank Order Top Values", + "screenshot": { + "name": "projects/9343387512370733994/files/1597732408047210864", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1WpFA576TA5wf1HnZIoIBm8m5-S0M9LlUvAz8ujVYmbkVydsAdUAmtOpQKsY9nixUIwZEd5bqrDTe6ITlJfFFRhDRxkehFVmgcdAZksW9L89pME6e2gTYuO-qqFQKwD-XAXg_PDunjOg8XZeYs5p1dIVenclfxkXwSQ4Y0IIDTHtIMONRE4S07sHY7skqnnL-f2vmbEBg3ah1WyjcLXIUFIL4AINmYK-vTMCxwwsQ_ev3qhq909m7CdoQ" + }, + "htmlCode": { + "name": "projects/9343387512370733994/files/15103438974169067770", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyY2VlNWY5MzgwMjNiZWU1MjMxMjVjMzFhEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "4408", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/rank-order.png b/stitch/screens/rank-order.png new file mode 100644 index 0000000000000000000000000000000000000000..7dbfc7f911f2f62354ce469b0fc78db435e2b389 GIT binary patch literal 2676 zcmex=Cx4wPY82hzz6|d4H zft2uLS$$DX*CsE>*%B1eaI{9_%!(x@Pv3LRi(Tb(wESAy7OpN2$BFTht1L6Qqx>2- zb$LyYSl=o;l~1bZd#itX)`YF=@8_Hi2=wGI(td2}uB({sdBH5uGl*IA!{SW~5BtS^ zSo!9yN7VKA+p3uGnWT4BF+29_%vD@6EwZ8?XYoZL*(Nzvq;1aLhru^*Ez!;Xe%m-i zB*=-U>&Mx^(;iWOf*0g0nzV#X`=NWPGcHvTOI}E8ELq9e^&{|Rz{BPG6(OJA28n6! z+ibcZ1Yy*r65c70FnF_~;PUi6T9suhxkc|s&RVbt98ejS8M>KPY^OA}9Fq3ca~W%C z@>*6OTE2NJ*n4R!G?uhTLYyu#mpN5rs)AuWm$jA*Bs4)LMa)`oNmG%{wI*%F()-IrR8KNQ+nw9n$hZJ4HW#8X#XRfkB zR5_k@#7uTiZ%x>`?$?nEQV5f_0OJKUG*55!h*30Sb~+YF0eP;$ba2!Pgob%X@dg`x}CiWQJ; zN3OC>M9Fqh;39*JG)_323DwrX0t%_<0hI-s*h;ar;L4LKB`aa; zK$RJ=uwR0$T0N-NNNY7G}qq8KyGK?Me^SOMmjC`1hlbJRItwI9Fl zCaj7DRe9GR!HWY}?TJMdqNYM51eBbP;&gar4Xk2;l>)pZ$D7lU>pXZA*Tbsx|2F~5 C3tPbe literal 0 HcmV?d00001 diff --git a/stitch/screens/reflect-top-values.html b/stitch/screens/reflect-top-values.html new file mode 100644 index 0000000..659ef70 --- /dev/null +++ b/stitch/screens/reflect-top-values.html @@ -0,0 +1,299 @@ + +
+ +
+
+ + Step 5 of 5 · Deep Reflection + + +spa + Unrushed Practice + +
+

Your Core Values

+ +
+ +
+
+Top 5 Core Anchors +3 of 4 answered +
+
+ + + + + +
+
+ +
+
+
+ +

+ Authenticity +

+
+ +
+

+ "Living in genuine alignment with inner truth and speaking without pretense or performance." +

+ +
+ +
+ +
+ +
+
+

+ To me, authenticity is the quiet permission to stop curating who I am for other people's approval. It means letting my outward actions and words match what is truly happening inside, even when that makes me feel vulnerable or imperfect. +

+
+
+ +
+
+
+ +
+ + +
+ +
+ +
+
+ + +
+
+ +
+
+
+ +
+ +
+
+ +
+ + 0 words + +
+
+
+ +
+
+
+
+ +
+
+
+explore +
+
+Your Life Compass is Taking Shape +14 of 20 total reflections recorded +
+
+ +
+ + + + +
+ + \ No newline at end of file diff --git a/stitch/screens/reflect-top-values.json b/stitch/screens/reflect-top-values.json new file mode 100644 index 0000000..93923dd --- /dev/null +++ b/stitch/screens/reflect-top-values.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/3064045350829608185", + "title": "Values Sort \u2014 Reflect on Top Values", + "screenshot": { + "name": "projects/9343387512370733994/files/3064045350829606144", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1Uwhwbp12i_K453L9y11FLMvbRC4yDVlY0fdRpaqI4rBUKKwEFBEzO2fbvVyKER5fnk5X11ceImXKtx6h37TpNJIYr6CZNuNhJc1LNKbOGiV_CO3ee7AVc0nOez48-19Q7vf8_H6Q1DlfjZj3B3v2X23in3GCgyxo5rAa-NsMkS9_G4oCvnWSIioTblp-viQRuJhyq3jIlEldpfZPkU5FQh7hr6lH9RMVXv2Pdy_sviQJK_4R2KOQJxAUc" + }, + "htmlCode": { + "name": "projects/9343387512370733994/files/3064045350829608199", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyOWJmZTJmY2UwOTY4YTAzNjNmMGQ1ODhmEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "3384", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/reflect-top-values.png b/stitch/screens/reflect-top-values.png new file mode 100644 index 0000000000000000000000000000000000000000..bc96c480797fe547d9ce13507f3da14f710f5ee3 GIT binary patch literal 4038 zcmb7H3rtg27`}Z!q>duhLW79a37t+WB2yz$2t`CeUO{mLr30DZE27CZMCq7gwW9by zK@zJ45p{w}jKM{~fi7rWL8G8^I+qdHH0op%6z%@g`{=!;=)5H4(A&c~=l{Rgv31%W zVD1aFQCf_}!Y~&6V79whA;w{|1p={HV1M{xAs-*1-@+00u}~lsq5-@?UlWQ%B7s06 z5ep?S7P2^8E}zF2^LYaFEr~?vco=^;K4y+=O_)^3#<0~KmK0-4SsW?L)`H1loA6+c zhlQ~@TzKQ_jNg#WQkaffqZJQB z4td5EMOak{Y2WS4dAUJ5`+CNaTB~=&yvCWC4P{y%bMJGVXQ}bBxcKX3;hU1N6A$%= zC#=yQ)J$Gm^fGU;cH9BguGSi9<-ZyaC5UtIwQs$0q z8oH{qNGq-i>X-lfbM*{eWp|3|HLo(^)$`2kn!PLTgdCcwj>@{W{8*3A;R}kbD?Mc* zWv=HPkuERt#zVcDYnIK=ex`nWC?@O5(rfiYPa4!=Hf`cRS|d$v<%P|^$D0|pDB5!nG4w&L)%!M@zE+`6ymJ;nL%R13Fx+L}qvoVQeiOfN8P&eYB1~s?(A9f{K zq?4#ftja^(mm2iyMMPt6FDNd!qd0w@mxkA<3u+{=*QhyhTjQv)U47lg+={CiX{LJd zmVD+>Wj>rb*stNDzsf_~6HxDQxqoMMt7p2$)|y3cKAd~D*CPLGR;i&eG;9CB*&u7% zw8y@&2j!LZnGLXC08*0^kfcQut}?{d~+o9iVqR zf!^VIY7Co}6j0l8<=p03W}lVQ+mm}F9yScn>qVirBhETUxha?euixagTM>Bu#)Q=@ zBG&AkRod35$r>|oHn7-1nIVhnm)w{3^&c^6<~PSH2Hn0|d81r?Yr_;-{??Az=POb* z@^d?@Eynniz|;W6WA9GIne!2h&OGO)i*g;5A@G1Gvyeua$k0cU&R@pY8pMSq4dT_@ z(-)P!&m!c7sceceC%cy+G^7CzR9s&k}+OL95M-U zfSw}C6yV|zlX0fjn!>{=6G$}14tzS0&H#`;sO}cFjN-+64=%LVr~}nV-!auS!AY|1 zDh+M|vMJrSA5J_FVt&<2X9gf@Hw3|~fPI8v1%i=vr? zszhA_hK~rXe$jpHc7p$p^_xR-bkj@r4E@kO<(#M&OOIw)^!bt^aBLti6#!*{_`3jv4r;nt+# z9vI#R44;H>Z=z(7##0yCz@PgEF1<(wLmMrHzt`+dCq&zV1k`1DjWU{m{vXlCxn?qI zKK_P|qkZ{$D}kefWKW%>3=r51a&HWSndJlm36?Suh;|!PADppHOo$+kT_~;yiknXy zlt2U1O@lgc!c@eS14;Q5N%g5nvJcpO4VUaAX@H_|97XB7+YdCyS+ld&v_0@*nv+qp zILWWEi7sU0?Ly|TVG@6&rcjP3YzF*s#{P}Wl<*0p3`0Rg&ZK-o*Z^&zP!DYx;hY*M zv1gc*Ud_`aZnI&y#ZaQsnVjI?is%9dEmzGJEMIf^H(B1|#0fjB37<{e@zgigAZ$_c zpeqdR40z4dUA5k9x@En$Z&-`@f+oC9E#2sE2Vmh!&rFCa1yoe=n*?g_>}z$Ww$U7> zh&&^($*IXWMeBuCQqsqzy>w2~Gr5LX2=zyOL( zNy^)5>FBG+u zV^0lKOYJi=sW|7-o1jFgVw6-~l;Sqr1vbnE^vZ6wsaF%RVOk<12>ukUcmVNJ8Zi_{ z34@)*1z6wXliXx@jsO&2?BJ)|S% zN#lzPy1<(FOl!jZ@EuvX2hzrU=d5fD^KZ4&^eUe1->XKZA1GY2!=kDiQ!QbGhW5V0e4MegDa1+9d{GlZy5--$++-RB1Y%KyH?}{V*pE zV}{Hm$GH5sk!A?K%3uf0=;-qzWcR=&-1dd!U5$*pv9`+J3C9>pwq*8kqn9 literal 0 HcmV?d00001 diff --git a/stitch/screens/reflection-journal.html b/stitch/screens/reflection-journal.html new file mode 100644 index 0000000..c3a4757 --- /dev/null +++ b/stitch/screens/reflection-journal.html @@ -0,0 +1,391 @@ + +
+ +
+
+ + Step 5 of 5 · Deep Reflection + + +spa + Unrushed Practice + +
+

Your Core Values

+
+ +
+
+Top 5 Core Anchors +3 of 4 answered +
+
+ + + + + +
+
+ +
+
+
+

+ Authenticity +

+
+
+

+ "Living in genuine alignment with inner truth and speaking without pretense or performance." +

+
+ +
+ +
+
+
+ +check + +
+
+Answered +· Prompt 1 +
+

+ What does this value mean to you? +

+
+
+open_in_full +
+
+
+

+ To me, authenticity is the quiet permission to stop curating who I am for other people's approval. It means letting my outward actions and words match what is truly happening inside, even when that makes me feel vulnerable or imperfect. +

+
+
+ +
+
+
+ +
+
+
+ +check + +
+
+Answered +· Prompt 2 +
+

+ Why did you choose this as important? +

+
+
+open_in_full +
+ +
+ +
+
+
+ +edit_note + +
+
+In Progress +· Prompt 3 +
+

+ How have you shown this value in your daily life? +

+
+
+open_in_full +
+
+
+

"Recently, during a project retrospective, I spoke honestly about feeling overwhelmed instead of nodding along like everything was fine..."

+
+
+ +mode_edit Tap to expand & journal + + +
+
+
+ +
+
+
+ +add + +
+
+Unanswered +· Prompt 4 +
+

+ In what ways could you be even more true to it? +

+
+
+edit_square +
+
+

Notice where you still mask, hold back, or seek quiet convenience over your core alignment.

+
+ +
+
+
+
+ +
+
+
+explore +
+
+Your Life Compass is Taking Shape +14 of 20 total reflections recorded +
+
+ +
+ + + +
+ +
+
+ +
+ +Prompt 3 of 4 +
+ +
+
+ +
+ +
+
+ + Reflecting on #1 Authenticity + + +
+

+ How have you shown this value in your daily life? +

+ + +
+ +
+ +
+ + 33 words · 214 characters + + +spa Mindful focus mode + +
+
+
+ +
+
+ + +
+
+
+ + +
+ + + \ No newline at end of file diff --git a/stitch/screens/reflection-journal.json b/stitch/screens/reflection-journal.json new file mode 100644 index 0000000..de141ee --- /dev/null +++ b/stitch/screens/reflection-journal.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/7bb00b6022b14dd9a687b9a31ec6b1f5", + "title": "Values Sort \u2014 Reflection (Full-Screen Journal Drawer)", + "screenshot": { + "name": "projects/9343387512370733994/files/15389870381633265971", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1UAeYCnBIII639-PoE0tFfV3LHW2yIsQ2XGm0L6YPETkrpzkMplK_QGvg-8F8PSLt_oJCS-3Uajl851y6H1IkywclVOp_OG34ANFKKEmKIyGFxXYg-XXlWWlanu_22zhpb_lhiO4auBOIFSxwwFc2NbU3b6qlsAIlBGONtInErxesAiJILt6j1yKKM1OkGJIrh4sWabbDoAfBNaJlu_hDywInGjs4j-d6SZOEvzgunjmwSjLStHmjuQoVk" + }, + "htmlCode": { + "name": "projects/9343387512370733994/files/2406486854586640137", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyYWE0ZDI3M2IwMjNiZWU1MjMxMjVjMzFhEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "3596", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/reflection-journal.png b/stitch/screens/reflection-journal.png new file mode 100644 index 0000000000000000000000000000000000000000..61da36fc2b0e8a646521e84ee2cf826322e36a9b GIT binary patch literal 4968 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 literal 0 HcmV?d00001 diff --git a/stitch/screens/welcome.html b/stitch/screens/welcome.html new file mode 100644 index 0000000..cff0349 --- /dev/null +++ b/stitch/screens/welcome.html @@ -0,0 +1,223 @@ + +
+ +
+
+Values Sort Emblem +VALUES SORT +
+
+ +
+ +
+
+ +
+Inquiry +

Curiosity

+

Seeking wonder, exploring questions without immediate answers.

+
+ +
+Belonging +

Connection

+

Nurturing deep kinship and seeing others as they truly are.

+
+ +
+
+Core Ground +spa +
+

Authenticity

+

Living in honest alignment with who you are, without performance.

+
+ + + +
+
+
+
+ +
+

+ Discover what matters most to you +

+

+ Through a gentle, guided card-sort practice, clarify your intrinsic values and illuminate the principles that guide your everyday decisions. +

+ +
+
+schedule +10–15 min +
+• +
+pace +Self-paced +
+• +
+lock +Private & reflective +
+
+
+ +
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/stitch/screens/welcome.json b/stitch/screens/welcome.json new file mode 100644 index 0000000..8e59298 --- /dev/null +++ b/stitch/screens/welcome.json @@ -0,0 +1,16 @@ +{ + "name": "projects/9343387512370733994/screens/e3940f39a073450299cb3024914064c6", + "title": "Values Sort \u2014 Welcome (with Guide Drawer)", + "screenshot": { + "name": "projects/9343387512370733994/files/13321085336226512739", + "downloadUrl": "https://lh3.googleusercontent.com/aida/AEtjO1XxoE8CbYmmotxXpSsZdC3wUE-E_xSas8nAxp_8GIUsaVeT2TjBeYVAwZM64nKp2KiGgcv4OGIq2noOJzxbWuzc-L2mitY9iU_fmiwGqgff0u7RpyjXlC0eRZlhvcRybK_E_dFQ_b8Q3GBOP06crg0MlaWtIPMS9WT-WIwmui7yJkqcEDsjlJlU8reI8HinfJtzvxK1gfOfEWbLDV5gPc7T_ypo6WR-fM3lZ35FSrkH4NQoX2e-d1-DlO0" + }, + "htmlCode": { + "name": "projects/9343387512370733994/files/24632818105687442", + "downloadUrl": "https://contribution.usercontent.google.com/download?c=CgthaWRhX2NvZGVmeBJ7Eh1hcHBfY29tcGFuaW9uX2dlbmVyYXRlZF9maWxlcxpaCiVodG1sXzAwMDY1YmIyNTQwYmQ5N2IwMjNiZTk5NjE2MDEzZDgzEgsSBxD_iY311x0YAZIBIwoKcHJvamVjdF9pZBIVQhM5MzQzMzg3NTEyMzcwNzMzOTk0&filename=&opi=89354086", + "mimeType": "text/html" + }, + "width": "780", + "height": "1768", + "deviceType": "MOBILE" +} \ No newline at end of file diff --git a/stitch/screens/welcome.png b/stitch/screens/welcome.png new file mode 100644 index 0000000000000000000000000000000000000000..e3f358b56894af41eda1a9537dbe6b927c83a419 GIT binary patch literal 35118 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 pumpApp(WidgetTester tester) async { + testWidgets('splash shows Values Sort then opens welcome', (tester) async { SharedPreferences.setMockInitialValues({}); final storage = StorageService(); await storage.init(); - await tester.pumpWidget( - MyApp( - storage: storage, - repository: ItemRepository(), - ), - ); - } - - testWidgets('splash shows the app name then opens Home', (tester) async { - await pumpApp(tester); + await tester.pumpWidget(MyApp(storage: storage)); expect(find.text(kAppName), findsWidgets); await tester.pump(kSplashDuration); - await tester.pump(const Duration(milliseconds: 450)); - await tester.pump(const Duration(milliseconds: 350)); + await tester.pump(const Duration(milliseconds: 500)); + await tester.pump(const Duration(milliseconds: 200)); - expect(find.text('Home'), findsWidgets); - expect(find.text('Featured items'), findsOneWidget); - expect(find.text('Search'), findsOneWidget); - expect(find.text('Profile'), findsOneWidget); - expect(find.text('Settings'), findsOneWidget); + expect(find.text('Begin Reflection'), findsOneWidget); + expect(find.textContaining('Discover what matters'), findsOneWidget); }); - testWidgets('tapping a list card opens the detail screen', (tester) async { - await pumpApp(tester); - await tester.pump(kSplashDuration); - await tester.pump(const Duration(milliseconds: 450)); - await tester.pump(const Duration(milliseconds: 350)); - - await tester.tap(find.text('Material 3 surfaces')); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 400)); - - expect(find.text('Details'), findsOneWidget); - expect(find.text('Back to list'), findsOneWidget); - }); - - test('Item.fromJson maps a JSONPlaceholder post', () { - final item = Item.fromJson({ - 'id': 3, - 'title': 'hello world', - 'body': 'First sentence. Second sentence.', + test('ValueCard and ValuePile helpers', () { + final card = ValueCard.fromJson({ + 'id': 'v1', + 'title': 'Courage', + 'description': 'Acting despite fear.', + 'domain': 'Agency', }); + expect(card.title, 'Courage'); + expect(ValuePile.mostImportant.rank, 5); + expect(ValuePile.notImportant.shortLabel, 'Not'); + }); - expect(item.id, 'remote-3'); - expect(item.title, 'Hello world'); - expect(item.subtitle, 'First sentence.'); - expect(item.category, ItemCategory.lifestyle); + testWidgets('sort progress persists across controller reloads', (tester) async { + SharedPreferences.setMockInitialValues({}); + final storage = StorageService(); + await storage.init(); + + const seed = [ + ValueCard( + id: 'v001', + title: 'Acceptance', + description: 'To be accepted as I am', + ), + ValueCard( + id: 'v002', + title: 'Accuracy', + description: 'To be accurate in my opinions and beliefs', + ), + ]; + + final first = ValuesSortController(storage: storage); + await first.load(seedDeck: seed); + first.beginPractice(); + final cardId = first.currentCard!.id; + first.assignCurrent(ValuePile.mostImportant); + await tester.pump(); + + expect(storage.sortSessionJson, isNotNull); + + first.dispose(); + + final second = ValuesSortController(storage: storage); + await second.load(seedDeck: seed); + expect(second.stage, SortStage.sorting); + expect(second.assignments[cardId], ValuePile.mostImportant); + expect(second.sortedCount, 1); + second.dispose(); }); }