Skip to content

Ekran — Statek i Garderoba

Przegląd

Statek to osobista strefa dziecka — hub z awatarem, todo listą, odznakami, XP i skrótami do garderoby i profilu. Garderoba to ekran personalizacji awatara z kategoriami ubrań i akcesoriów.

Routing (GoRouter)

dart
// Statek jest częścią ShellRoute (bottom nav)
GoRoute(path: '/spaceship', builder: (_, __) => SpaceshipScreen()),

// Garderoba jako sub-route
GoRoute(path: '/spaceship/wardrobe', builder: (_, __) => WardrobeScreen()),

Riverpod Providers

dart
// Profil użytkownika
final userProfileProvider = FutureProvider<UserProfile>((ref) {
  return ref.watch(userRepositoryProvider).getMe();
});

// Statystyki użytkownika (XP, level, streak)
final userStatsProvider = FutureProvider<UserStats>((ref) {
  return ref.watch(userRepositoryProvider).getStats();
});

// Todo lista (3 ostatnie na statek, pełna w profilu)
final todosProvider = FutureProvider<List<Todo>>((ref) {
  return ref.watch(todoRepositoryProvider).getTodos();
});

// Ostatnie 5 odznak
final recentBadgesProvider = FutureProvider<List<Badge>>((ref) {
  return ref.watch(userRepositoryProvider).getBadges();
});

// ── Garderoba ──

// Katalog przedmiotów awatara (pogrupowane wg kategorii)
final avatarItemsProvider = FutureProvider<AvatarItemCatalog>((ref) {
  return ref.watch(avatarRepositoryProvider).getItems();
});

// Aktualnie wybrane przedmioty (preview)
final avatarPreviewProvider = StateNotifierProvider<AvatarPreviewNotifier, AvatarConfig>((ref) {
  return AvatarPreviewNotifier(ref.watch(userProfileProvider).value?.avatar);
});

// Aktywna kategoria w garderobie
final wardrobeCategoryProvider = StateProvider<WardrobeCategory>((ref) {
  return WardrobeCategory.hats;
});

Statek (Spaceship Screen)

ASCII Wireframe

┌──────────────────────────────────┐
│  Mój Statek                 ⚙️  │
├──────────────────────────────────┤
│                                  │
│         ┌──────────────┐         │
│         │              │         │
│         │    👤        │         │
│         │   (awatar    │         │
│         │   dziecka)   │         │
│         │              │         │
│         └──────────────┘         │
│                                  │
│  Kacper              Poziom 5    │
│  ████████████░░░░ 1240/1500 XP   │
│                                  │
│  ┌──────────┐  ┌──────────┐      │
│  │ 👕       │  │ 👤       │      │
│  │Garderoba │  │ Profil   │      │
│  └──────────┘  └──────────┘      │
│                                  │
│  ── Zadania do zrobienia ──      │
│                                  │
│  ┌────────────────────────────┐  │
│  │ ○ Obejrzyj film o         │  │
│  │   dinozaurach              │  │
│  ├────────────────────────────┤  │
│  │ ○ Rozwiąż quiz            │  │
│  │   "Zwierzęta Polski"      │  │
│  ├────────────────────────────┤  │
│  │ ✅ Narysuj swoje           │  │
│  │   wymarzone zwierzę        │  │
│  └────────────────────────────┘  │
│  Zobacz wszystkie →              │
│                                  │
│  ── Moje odznaki ──             │
│                                  │
│  ┌────┐ ┌────┐ ┌────┐ ┌────┐   │
│  │ 🏅 │ │ 🎖️ │ │ 🥇 │ │ 🏆 │   │
│  └────┘ └────┘ └────┘ └────┘   │
│  +3 więcej →                     │
│                                  │
├──────────────────────────────────┤
│  🌍        🪐        🚀     👤  │
│ Globus    Kosmos    Statek  Profil│
└──────────────────────────────────┘

Komponenty — Statek

KomponentOpis
AvatarDisplayDuży awatar dziecka (center, animowany idle)
XpLevelBarPasek XP z numerem poziomu, imię dziecka
QuickLinkCardKarta szybkiego dostępu: Garderoba, Profil
TodoPreviewListLista 3 ostatnich todo (z checkboxami)
TodoItemPojedyncze todo: checkbox + tekst + opcjonalny deadline
BadgeShowcaseHoryzontalny rząd ostatnich odznak (max 5)
BadgeTileIkona odznaki (tappable → detail)
SectionHeaderNagłówek sekcji z linkiem "Zobacz wszystkie"

Logika — Statek

  1. Przy wejściu → równoległe pobranie: profil, stats, todos, badges
  2. Awatar wyświetlony z aktualnym ubraniem
  3. Todo lista — checkbox toggle → PATCH /app/todos/:id
  4. "Garderoba" → nawigacja do /spaceship/wardrobe
  5. "Profil" → nawigacja do /profile
  6. "Zobacz wszystkie" (todo) → nawigacja do pełnej listy todo
  7. Tap na odznakę → bottom sheet ze szczegółami odznaki

Endpointy — Statek

MetodaEndpointOpis
GET/app/users/meProfil użytkownika
GET/app/users/me/statsStatystyki (XP, level, streak)
GET/app/todosLista zadań do zrobienia
GET/app/users/me/badgesZdobyte odznaki
PATCH/app/todos/:idZmień status todo

User Profile Response:

json
{
  "data": {
    "id": "child-1",
    "display_name": "Kacper",
    "avatar": {
      "face": "smile_01",
      "hair": "curly_brown",
      "hat": "cap_red",
      "top": "tshirt_blue",
      "bottom": "jeans_dark",
      "shoes": "sneakers_white",
      "accessories": ["backpack_green"]
    },
    "avatar_url": "https://..."
  }
}

Stats Response:

json
{
  "data": {
    "level": 5,
    "xp": 1240,
    "xp_to_next_level": 1500,
    "tasks_completed": 42,
    "worlds_visited": 3,
    "days_streak": 7,
    "badges_count": 12
  }
}

Todos Response:

json
{
  "data": [
    {
      "id": "todo-1",
      "text": "Obejrzyj film o dinozaurach",
      "status": "pending",
      "source": "parent",
      "task_id": "task-v1",
      "due_date": null
    },
    {
      "id": "todo-2",
      "text": "Rozwiąż quiz \"Zwierzęta Polski\"",
      "status": "pending",
      "source": "system",
      "task_id": "task-q1",
      "due_date": "2026-03-15"
    },
    {
      "id": "todo-3",
      "text": "Narysuj swoje wymarzone zwierzę",
      "status": "completed",
      "source": "parent",
      "task_id": "task-c1",
      "due_date": null
    }
  ]
}

Badges Response:

json
{
  "data": [
    {
      "id": "badge-dino",
      "name": "Odkrywca Dinozaurów",
      "description": "Ukończ wszystkie zadania o dinozaurach",
      "icon_url": "https://...",
      "earned_at": "2026-03-05T14:30:00Z"
    }
  ]
}

Garderoba (Wardrobe Screen)

ASCII Wireframe

┌──────────────────────────────────┐
│  ← Garderoba             Zapisz │
├──────────────────────────────────┤
│                                  │
│         ┌──────────────┐         │
│         │              │         │
│         │    👤        │         │
│         │  (podgląd    │         │
│         │   awatara    │         │
│         │   na żywo)   │         │
│         │              │         │
│         └──────────────┘         │
│                                  │
├──────────────────────────────────┤
│  [🎩][💇][😊][👕][👖][👟][💎]   │
│  czap włos twarz góra dół buty  │
│                          dodat.  │
├──────────────────────────────────┤
│                                  │
│  ┌────┐ ┌────┐ ┌────┐ ┌────┐   │
│  │ 🎩 │ │ 🧢 │ │ 🎓 │ │ 👑 │   │
│  │    │ │    │ │    │ │ 🔒 │   │
│  └────┘ └────┘ └────┘ └────┘   │
│  ┌────┐ ┌────┐ ┌────┐ ┌────┐   │
│  │ 🤠 │ │ 🪖 │ │ ⛑️ │ │ 🎀 │   │
│  │ 🔒 │ │ 🔒 │ │    │ │    │   │
│  └────┘ └────┘ └────┘ └────┘   │
│  ┌────┐ ┌────┐ ┌────┐ ┌────┐   │
│  │ 🧢 │ │ 🎩 │ │ 🪄 │ │ ❌ │   │
│  │    │ │ 🔒 │ │ 🔒 │ │brak│   │
│  └────┘ └────┘ └────┘ └────┘   │
│                                  │
└──────────────────────────────────┘

Po wybraniu zablokowanego przedmiotu

┌────────────────────────────────┐
│                                │
│  🔒 Korona Królewska           │
│                                │
│  Żeby odblokować ten           │
│  przedmiot, zdobądź            │
│  odznakę "Król Wiedzy".        │
│                                │
│  Postęp: ██████░░░░ 60%       │
│                                │
│  [ OK ]                        │
│                                │
└────────────────────────────────┘

Komponenty — Garderoba

KomponentOpis
AvatarPreviewPodgląd awatara na żywo (aktualizuje się przy wyborze)
CategoryTabBarZakładki kategorii (ikony): czapki, włosy, twarz, góra, dół, buty, dodatki
ItemGridSiatka przedmiotów (GridView, 4 kolumny)
ItemTileKafelek przedmiotu: ikona/miniatura + stan (odblokowany / zablokowany)
ItemTile.unlockedJasny kafelek, tappable, zaznaczony = ramka brand-primary
ItemTile.lockedPrzyciemniony kafelek z ikoną kłódki
ItemTile.noneKafelek "brak" (❌) — zdjęcie przedmiotu z tej kategorii
LockedItemDialogDialog z informacją jak odblokować przedmiot
SaveButtonPrzycisk "Zapisz" w app bar (aktywny gdy zmieniony)

Logika — Garderoba

  1. Przy wejściu → pobranie katalogu przedmiotów (GET /app/avatar/items)
  2. Podgląd awatara inicjalizowany z aktualnego profilu
  3. Tap na kategorię → zmiana wyświetlanej siatki przedmiotów
  4. Tap na odblokowany przedmiot → aktualizacja podglądu awatara (live preview)
  5. Tap na zablokowany przedmiot → LockedItemDialog
  6. Tap na "brak" → usunięcie przedmiotu z kategorii (np. zdejmij czapkę)
  7. "Zapisz" → PATCH /app/avatar → powrót do statku

Kategorie przedmiotów

KategoriaKluczIkona
Czapkihats🎩
Włosyhair💇
Twarzface😊
Góratops👕
Dółbottoms👖
Butyshoes👟
Dodatkiaccessories💎

Endpointy — Garderoba

MetodaEndpointOpis
GET/app/avatar/itemsKatalog przedmiotów awatara
PATCH/app/avatarZmień wygląd awatara

Avatar Items Response:

json
{
  "data": {
    "categories": [
      {
        "key": "hats",
        "label": "Czapki",
        "items": [
          {
            "id": "hat-cap-red",
            "name": "Czerwona czapka",
            "thumbnail_url": "https://...",
            "unlocked": true,
            "equipped": true
          },
          {
            "id": "hat-crown",
            "name": "Korona Królewska",
            "thumbnail_url": "https://...",
            "unlocked": false,
            "unlock_condition": {
              "type": "badge",
              "badge_id": "badge-king",
              "badge_name": "Król Wiedzy",
              "progress_percent": 60
            }
          }
        ]
      },
      {
        "key": "hair",
        "label": "Włosy",
        "items": [
          {
            "id": "hair-curly-brown",
            "name": "Kręcone brązowe",
            "thumbnail_url": "https://...",
            "unlocked": true,
            "equipped": true
          }
        ]
      }
    ]
  }
}

PATCH Avatar Request:

json
{
  "hat": "hat-cap-red",
  "hair": "hair-curly-brown",
  "face": "smile_01",
  "top": "tshirt_blue",
  "bottom": "jeans_dark",
  "shoes": "sneakers_white",
  "accessories": ["backpack_green", "glasses_round"]
}

PATCH Avatar Response:

json
{
  "data": {
    "avatar_url": "https://...",
    "updated": true
  }
}

Stany Ekranu

Statek

StanWidok
ŁadowanieSkeleton awatara + skeleton sekcji
DanePełny layout z awatarem, todo, odznakami
BłądErrorView z przyciskiem retry

Garderoba

StanWidok
ŁadowanieSkeleton preview + skeleton grid
DanePodgląd awatara + siatka przedmiotów
ZapisywanieSaveButton z loading spinner
Błąd zapisuSnackbar z komunikatem + przycisk retry
Bez zmianSaveButton disabled (szary)

Uwagi Techniczne

  • Awatar renderowany jako kompozycja warstw (Stack z PNG): tło → twarz → włosy → ubranie → czapka → dodatki
  • Live preview: każda zmiana natychmiast aktualizuje Stack (bez requestu do API)
  • Zapis tylko przy "Zapisz" (nie automatyczny)
  • Cache przedmiotów awatara — katalog rzadko się zmienia
  • Todo toggle: PATCH /app/todos/:id z body { "status": "completed" } — optimistic update
  • Sekcja odznak: tap → bottom sheet z nazwą, opisem, datą zdobycia

Lumos Islands v2 - Dokumentacja Projektowa