changes / android

MPC Android — Demo Changelog

Changelog build demo APK. Nama file: mpc-android-demo-v{MAJOR}.{MINOR}.apk → disalin ke /Users/glen/Downloads/.

Versi aktif berikutnya: v1.21 (current demo v1.20). Dalam satu chat/agent yang sama, jangan naikkan versi — update bullet di section versi aktif saja lalu rebuild.

Indeks semua app: mpc-dev/docs/versions/README.md.


v1.20 — 2026-08-20

  • OTP verify (register): tombol "Verify & Continue" pakai morph bouncing ball sama Login; sukses → splash "Let's Start!" lalu Home.
  • Reset password via OTP: morph saat loading, lalu ke Login (tanpa splash Let's Start).
  • Resend / error fade saat busy; tombol disabled sampai 4 digit terisi.

v1.19 — 2026-08-15

  • Login Sign In: tombol morph rounded-rect → circle bouncing (bola) saat loading; sukses splash primary full-screen + "Let's Start!" 1 detik lalu masuk Home.
  • Secondary actions (Google / Register / or) disembunyikan selama loading/splash; gagal login morph kembali + error.
  • Setelah API sukses, tunggu minimal 1 full bounce (~1s) baru splash — API tetap langsung.
  • Bounce diganti hop fisik: naik ~40dp lalu turun (bukan pulse/kedutan); squash hanya saat land.
  • Secondary actions fade opacity (ruang layout tetap) supaya tombol Sign In tidak loncat saat loading.
  • Bounce dihaluskan: satu kurva keyframe naik–turun (gravitasi); squash impact-based — cepat sesaat menyentuh tanah (~70ms) lalu recover cepat, stretch tipis saat terbang.
  • Lingkaran loading 40dp; tinggi tombol idle tetap 56dp; lompatan bola 96dp, siklus cepat ~0.76s, squash impact tipis (0.88) dan singkat ~30ms (bola padel, bukan balon).
  • Log Out: spinner + "Logging out…" saat proses revoke token (sebelumnya diam tanpa indikator), klik ganda dicegah.
  • Login/Register: ikon mata di field password sekarang berfungsi toggle show/hide password.
  • Login gagal: bola tetap bounce minimal 1 siklus dulu; pesan error manusiawi ("That email and password don't match…", "We couldn't find an account…", koneksi, generic) — bukan HTTP 401 mentah.
  • Bottom navbar redesign: warna unselected diganti dari abu-abu netral (mismatch) jadi primary teal dengan alpha 42% (tetap satu keluarga warna dengan tema); indikator pill Material3 dihapus, ripple sekarang membungkus seluruh tab (icon + label) bukan cuma icon.
  • Bottom navbar: ripple diubah jadi radius tetap (36dp) supaya bentuknya lingkaran bersih, bukan persegi panjang yang mengisi seluruh lebar tab.
  • Home (Android only): status bar icon jadi putih (light content) selama tab Home aktif, karena header hero Home fullscreen/gelap sampai ke bawah status bar; tab History/Profile & layar lain tetap ikutan tema (ikon gelap di palette Elegant).
  • Lock orientasi ke portrait (android:screenOrientation="portrait" di MainActivity) — tidak bisa diputar landscape.
  • Home welcome: saat pertama kali muncul (setelah login / buka app), sapaan lalu kartu upcoming, judul Quick Actions, lalu keempat menu muncul satu-satu, lalu sisa halaman fade masuk — tidak diulang saat pindah tab; di-reset setelah logout.
  • Home header: kartu "Upcoming Match" di header diganti carousel gambar Promo (looping, auto-advance ~4.5s, swipeable, dot indicator) — hanya promo dengan image_url yang tampil, diurutkan display_order; header lebih ringkas jika tidak ada promo bergambar.
  • "Upcoming Match" dipindah jadi kartu tersendiri di atas "Quick Actions"; tombol "Play Live" diganti "Play" dan hanya muncul selama jam main (antara jam mulai–selesai booking berjalan), dicek ulang tiap 30 detik.
  • Section "Promotions" (banner teks/emoji) di bagian bawah Home dihapus — sudah tercover carousel gambar di header.
  • Kartu "Upcoming Match" di body Home disembunyikan sementara (flag SHOW_UPCOMING_MATCH_CARD = false, mudah dinyalakan lagi) — carousel promo di header tetap tampil.
  • Pull-to-refresh (Material3 PullToRefreshBox) ditambahkan di Home (refetch home content + upcoming booking) dan Time Slot Booking (refetch daftar court + availability slot berjalan, tanpa reset pilihan tanggal/durasi/court yang sedang aktif).
  • Promo carousel: tinggi diubah dari fixed 128dp jadi rasio 16:9 (fillMaxWidth().aspectRatio(16f/9f)) — mengikuti cek langsung ke project mtix_lumiere (cinema chain) yang memakai formula tinggi banner (lebar layar - 32) / 3.6 + 96; 16:9 dipilih karena hasilnya nyaris identik pada lebar device umum sekaligus cocok dengan aspek rasio gambar promo yang baru (tidak perlu crop agresif). Header Home yang menampung carousel ikut menyesuaikan tinggi secara dinamis (bukan konstanta 228dp tetap).
  • Nama promo + badge diskon ("20% OFF" / "Rp75.000 OFF") sekarang digambar native di atas foto (scrim gradient bawah) berdasarkan data live Promo.name/type/value — bukan dibakar ke file gambar. Jadi admin bisa ganti judul/harga promo tanpa perlu generate ulang gambar; dot indicator dipindah ke pojok kanan-atas biar tidak numpuk sama teks.
  • Regenerate 5 foto promo (real photography, tanpa teks/watermark) di rasio 16:9 — 3 Court (morning action, weekend, off-peak solo) + 2 F&B (cafe spread, match-day combo); replace file lama yang aspect ratio-nya kependekan (1.5:1) sehingga ke-crop parah di carousel lama.
  • Promo carousel dikecilkan lagi: tinggi dikurangi 24dp dari hasil rasio 16:9 (bukan bikin gambar baru — foto lama tetap dipakai, ContentScale.Crop yang menangani sisa crop di bagian bawah foto). Tinggi dihitung sekali di HomeScreen lalu diteruskan sebagai height eksplisit ke PromoCarousel (bukan lagi Modifier.aspectRatio mandiri), jadi header ikut menyusut pas sama besar.

v1.18 — 2026-08-15

  • Push FCM: Firebase Messaging, channel mpc_main, permission POST_NOTIFICATIONS, register/revoke POST/DELETE /device-tokens saat login/logout.
  • Deep link mpc://notifications / mpc://history dari tap notifikasi.
  • Ganti google-services.json placeholder dengan file Firebase project nyata sebelum production (lihat mpc-dev/docs/push-notifications-setup.md).
  • iOS push ditunda (APNs / Apple Developer) — jejak mpc-dev/docs/ios-changes/032-push-notifications.md + mpc-dev/docs/tasks.md.
  • Fix: rebuild APK dengan Firebase mpclub-a3b1e (APK sebelumnya masih placeholder sehingga FCM token gagal); PushRegistrar tunggu session JWT + log error register.
  • Fix: retry FCM token (hingga 5×) untuk error transient SERVICE_NOT_AVAILABLE di MIUI.
  • UI Notifications: hapus swipe-delete merah (background merah terlihat saat buka); kartu tenang, unread dot primer, loading/empty elegan, ikon per kategori.
  • Tanggal notifikasi hari ini: relatif (Just now / 10 minutes ago / 1 hour ago); ticker 30 detik supaya label tidak stuck saat halaman tetap terbuka.

v1.17 — 2026-08-13

  • Menu Resto di Home Quick Actions → landing Resto baru (route resto): daftar space (Room privat & Dining area) dari GET /spaces urut display_order — foto (placeholder elegan bila kosong), label tipe, "Up to N guests", "Minimum spend Rp X" untuk Room; link sekunder "Order food & drinks" ke F&B existing.
  • Flow reservasi space (route resto-reserve/{spaceId}): pilih tanggal (hari ini ke depan), stepper guests 1..max_party_pax (note "For larger groups, please contact us" di batas atas), grid slot 30-menit dari GET /spaces/:id/availability (durasi fixed, mis. "90-minute seating"; slot penuh/lewat disabled), dialog konfirmasi (space, tanggal, jam, guests + note minimum spend settled via F&B) → POST /spaces/reservations → success state dengan kode reservasi.
  • History: filter segmented Courts / Resto; tab Resto dari GET /spaces/reservations/me — card space, tanggal, jam, guests, badge status (Confirmed/Seated/Completed/Cancelled/No-show), minimum spend; Cancel (dialog konfirmasi) hanya untuk Confirmed + belum mulai + bukan CourtBundle (POST /spaces/reservations/:id/cancel, error BE ditampilkan sopan).
  • Court Detail: callout "Includes Private VIP Room — {nama}" (+ "Minimum spend Rp X applies, settled through F&B") di atas perk chips saat bundled_space terisi; model Court + bundledSpace (DTO + mapper).
  • Data layer: SpaceDto/SpaceAvailabilityDto/SpaceReservationDto/CreateSpaceReservationBody + model RestoSpace/SpaceSlot/SpaceReservation/BundledSpace; repository getSpaces/getSpaceAvailability/createSpaceReservation/getMySpaceReservations/cancelSpaceReservation; spaces di-cache di RuntimeCatalog (ikut refreshCatalog).
  • Quick Action card: label satu baris (12sp) agar 4 kartu sejajar rapi.
  • Court Detail: copy callout VIP room disesuaikan bundling best-effort — "Included when the room is available for your slot" (court tetap bisa dibook saat Room penuh, tanpa room).
  • Resto landing: hapus link sekunder "Order food & drinks" — order F&B hanya ditawarkan setelah reservasi space berhasil (tombol "Order food & drinks" di success state reservasi).
  • Dialog konfirmasi reservasi diganti bottom sheet (foto space, nama, tipe, tanggal/jam/guests/durasi, note minimum spend) — bukan AlertDialog lawas.
  • Flow reservasi dirombak berurutan: pilih tanggal di landing Resto (date strip dipindah dari reserve screen, dibawa via resto-reserve/{spaceId}?date=) → pilih ruangan+pax → pilih jam saja di reserve screen; landing tambah section "Your reservations" (quiet reminder reservasi upcoming + link "See all" ke History) via MainTabState/goHistory().
  • Pre-order F&B terikat ke reservasi: tombol "Order food & drinks" di success state membuka katalog F&B mode pre-order (food-drinks?reservationId=) — CheckoutState dimulai bersih + tag spaceReservationId, checkout langsung ke Payment (tanpa alur cart court booking); schema baru transactions.space_reservation_id (migration 021) + POST /orders terima space_reservation_id + GET /spaces/reservations/me sertakan orders[].
  • History tab Resto: card reservasi menampilkan pesanan F&B yang terikat (ReservationOrdersSummary — item, qty, status, total) di bawah detail reservasi, bukan entri terpisah.
  • Copy "No minimum spend" (bukan diam saja) di kartu space, ringkasan reserve screen, bottom sheet konfirmasi, success state, dan History saat space/reservasi tidak punya minimum spend.
  • Fitur Tip di booking history: order dengan status Completed menampilkan section Tip di bawah Payment Summary (BookingDetailScreen) — belum pernah tip → CTA "Give a Tip"; sudah pernah → kartu "Thank you" dengan nominal (1x per order). TipScreen baru (route tip/{transactionId}): chip Rp 5rb/10rb/20rb/30rb/50rb (single-select) atau input manual (min Rp 5.000, tanpa batas atas) → POST /orders/:id/tip → lanjut ke PaymentScreen lewat flow existing-invoice (sama seperti reschedule fee).
  • PaymentScreen: title & label invoice existing digeneralisasi jadi dinamis dari nama item transaksi (existingTx.items.firstOrNull()?.name), bukan hardcode "Pay Reschedule Fee" — otomatis "Pay Tip" untuk flow tip tanpa mengubah perilaku reschedule.
  • OrderSummaryScreen: saat transaksi bertipe Tip, hero copy jadi "Thank You!" + pesan apresiasi, tombol jadi "Back to My Bookings" (goHistory()) — berlaku juga untuk reschedule fee (deteksi via transactionType != "Mixed"), selain itu tetap "Booking Confirmed!" / "Back to Home".
  • Data layer: TransactionDto.tipAmount + CreateTipRequest, BookingHistoryItem.tipAmount (di-map dari transaksi saat getBookingHistory()), MpcApi.createOrderTip (POST orders/{id}/tip), MpcRepository.createOrderTip.

v1.16 — 2026-08-11

  • API-only: hapus Developer Mode / dummy data source; catalog selalu dari mpc-be.
  • Matchplay sync: DTO + MpcApi (detail, join, participants, generate, update game, leaderboard).
  • Create Match → create + add guests + generate session dari API; skor game sync ke BE.
  • Community players dari GET /users/players; Home open matches / top players tanpa fallback dummy.
  • Google Sign-In: tampilkan "belum tersedia" (tolak mock token).
  • Fix decode: join/leave/participants/generate/update game response = MatchDetail (bukan participant/game tunggal).
  • FnB Pick-up time: fetch GET /settings/fnb-pickup; picker di Order Summary saat ada booking + FnB; kirim fnb_pickup_time di checkout.
  • Court Detail showcase: screen baru immersive (hero gallery full-bleed edge-to-edge + nama court di atas foto, tombol back/share/favorite melayang, perk chips, About, Specifications, CTA "Book This Court"); favorite pakai API favorites target_type=Court; share via Android share sheet; Home court card → detail; Time Slot preselect mode By court via time-slot?courtId=; model Court + description/gallery/specs/perks.
  • Home court card: hapus tombol "Book Court" — seluruh card tappable (PressableScale) → Court Detail; gambar card pakai foto pertama gallery (konsisten dengan hero detail); seed gallery diganti foto lapangan padel asli (Pexels, hero = foto court kosong per court).
  • FnB pick-up time tampil di Order Complete (section Food & Beverages) dan Booking Details (mapping fnb_pickup_time dari transaksi); history memisahkan item FnB dari Rent via nama produk katalog; Payment Summary di Order Complete kini lengkap (subtotal per kategori + breakdown PPN/PB1/service) juga saat memakai angka server.

v1.15 — 2026-08-10

  • Create Match: POST /matches saat Generate Session (tetap buka local session).
  • Notifications: load + mark-read dari API (bukan dummy).
  • Favorites: sync Player ke BE (hydrate / toggleRemote).
  • Booking court picker (By time + By court): kartu teks saja, tanpa gambar.
  • Court picker: daftar vertikal full-width (tanpa scroll samping); harga hanya /hr.
  • Hapus label "Find by" & "Choose your court"; slot expanded = satu kotak (waktu + court).
  • Bottom bar: Book + total Court rental; animasi expand/collapse slot; court cards grid 2 kolom.
  • Label Select Court; section By court muncul/hilang dengan animasi.
  • Animasi Select Court / expand slot: tanpa move-from-top (hindari nembus); auto-scroll ke slot yang di-expand.

v1.14 — 2026-08-10

  • Parse inventory ProShop (legacy Merch); Pro Shop catalog tanpa group Rent.
  • Booking labels: Rent (amenities) vs Pro Shop (jual); dummy rental items di amenities.

v1.13 — 2026-08-09

  • Time Slot: hilangkan badge "Available"; section "Select time"; status hanya Passed / Full / Sold / split.
  • Segmented By time / By court di atas Select Date; By court pakai courtAvailabilityFor (tanpa split).
  • By court: kartu court samakan dengan By time (gambar + harga), bukan chip teks saja.

v1.12 — 2026-08-09

  • Time Slot API mode: selalu re-fetch GET /courts sebelum availability (hindari court soft-deleted di cache → selalu Sold / urutan salah).
  • Dummy courts: Court 1–3, displayOrder 1–3, Court 3 = VIP.

v1.11 — 2026-08-07

  • Time Slot: court yang sudah sold tetap ditampilkan (greyed-out + label "Sold"), tidak disembunyikan.
  • Urutan court tetap display_order admin (posisi konsisten antar jam).
  • Baris jam "Available" jika ≥1 court free; "Full" jika semua sold. Split plan hanya pakai court yang available.

v1.10 — baseline

  • Versi demo terakhir sebelum changelog formal di mpc-dev/docs/changes/android.md.