feat: Phase 3 — 26 medium-priority gaps implemented

P3-A/K  Profile: Eventify ID glassmorphic badge (tap-to-copy), DiceBear
        Notionists avatar via TierAvatarRing, district picker (14 pills)
        with 183-day cooldown lock, multipart photo upload to server
P3-B    Home: Top Events converted to PageView scroll-snap
        (viewportFraction 0.9 + PageScrollPhysics)
P3-C    Event detail: contributor widget (tier ring + name + navigation),
        related events horizontal row; added getEventsByCategory() to
        EventsService; added contributorId/Name/Tier fields to EventModel
P3-D    Kerala pincodes: 463-entry JSON (all 14 districts), registered as
        asset, async-loaded in SearchScreen replacing hardcoded 32 cities
P3-E    Checkout: promo code field + Apply/Remove button in Step 2,
        discountAmount subtracted from total, applyPromo()/resetPromo()
        methods in CheckoutProvider
P3-F/G  Gamification: reward cycle countdown + EP→RP progress bar (blue→
        amber) in contribute + profile screens; TierAvatarRing in podium
        and all leaderboard rows; GlassCard current-user stats card at
        top of leaderboard tab
P3-H    New ContributorProfileScreen: tier ring, stats, submission grid
        with status chips; getDashboardForUser() in GamificationService;
        wired from leaderboard row taps
P3-I    Achievements: 11 default badges (up from 6), 6 new icon map
        entries; progress % labels already confirmed present
P3-J    Reviews: CustomPainter circular arc rating ring (amber, 84px)
        replaces large rating number in ReviewSummary
P3-L    Share rank card: RepaintBoundary → PNG capture → Share.shareXFiles;
        share button wired in profile header and leaderboard tab
P3-M    SafeArea audit: home bottom nav, contribute/achievements scroll
        padding, profile CustomScrollView top inset

New files: tier_avatar_ring.dart, glass_card.dart,
  eventify_bottom_sheet.dart, contributor_profile_screen.dart,
  share_rank_card.dart, assets/data/kerala_pincodes.json
New dep:   path_provider ^2.1.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 17:17:36 +05:30
parent fe8af7cfe6
commit 632754415d
19 changed files with 2346 additions and 183 deletions

View File

@@ -50,7 +50,7 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
bool _loading = true;
// Hero carousel
final PageController _heroPageController = PageController(viewportFraction: 0.88);
final PageController _heroPageController = PageController(viewportFraction: 0.9);
late final ValueNotifier<int> _heroPageNotifier;
Timer? _autoScrollTimer;
@@ -453,10 +453,11 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
),
// Floating bottom navigation (always visible)
// bottom offset accounts for home indicator on iPhone/Android gesture bar
Positioned(
left: 16,
right: 16,
bottom: 16,
bottom: MediaQuery.of(context).padding.bottom + 16,
child: _buildFloatingBottomNav(),
),
],
@@ -1532,11 +1533,14 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
_selectedDateFilter.isNotEmpty ? 'No events for "$_selectedDateFilter"' : 'No events found',
style: const TextStyle(color: Color(0xFF9CA3AF)),
))
: ListView.separated(
scrollDirection: Axis.horizontal,
: PageView.builder(
controller: PageController(viewportFraction: 0.85),
physics: const PageScrollPhysics(),
itemCount: _allFilteredByDate.length,
separatorBuilder: (_, __) => const SizedBox(width: 12),
itemBuilder: (context, index) => _buildTopEventCard(_allFilteredByDate[index]),
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.only(right: 12),
child: _buildTopEventCard(_allFilteredByDate[index]),
),
),
),
const SizedBox(height: 24),