# 📝 Code Integration Guide - AR Viewer & Favorit Panduan untuk mengintegrasikan fitur-fitur tambahan ke halaman Beranda. ## 🔍 Integrasi AR Viewer ### 1. Di destination_detail_page.dart Ganti tombol "Lihat AR" yang sekarang menampilkan SnackBar dengan navigasi ke AR viewer: ```dart // Current implementation (di beranda_screen.dart) ElevatedButton.icon( onPressed: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Model 3D: ${widget.destination.modelPath}', ), duration: const Duration(seconds: 2), ), ); }, // ... ) // Dapat diubah menjadi: ElevatedButton.icon( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ArViewerPage( modelPath: widget.destination.modelPath, destinationName: widget.destination.nama, ), ), ); }, // ... ) ``` ### 2. Buat file ArViewerPage Buat file baru: `lib/pages/ar_viewer_page.dart` ```dart import 'package:flutter/material.dart'; class ArViewerPage extends StatefulWidget { final String modelPath; final String destinationName; const ArViewerPage({ Key? key, required this.modelPath, required this.destinationName, }) : super(key: key); @override State createState() => _ArViewerPageState(); } class _ArViewerPageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.destinationName), centerTitle: true, ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.view_in_ar, size: 80, color: Colors.grey[400], ), const SizedBox(height: 16), Text( 'AR Viewer', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.grey[600], ), ), const SizedBox(height: 8), Text( 'Model: ${widget.modelPath}', style: TextStyle( fontSize: 12, color: Colors.grey[500], ), ), const SizedBox(height: 32), ElevatedButton( onPressed: () { // TODO: Implement actual AR viewer ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('AR Viewer akan segera hadir'), ), ); }, child: const Text('Buka AR Viewer'), ), ], ), ), ); } } ``` ## ❤️ Integrasi Favorit ### 1. Update destination_model.dart Tambahkan isFavorite property: ```dart class Destination { final int id; final String nama; // ... existing properties ... bool isFavorite; // Tambahan Destination({ required this.id, required this.nama, // ... existing parameters ... this.isFavorite = false, }); } ``` ### 2. Buat FavoriteProvider Buat file baru: `lib/providers/favorite_provider.dart` ```dart import 'package:flutter/material.dart'; import '../models/destination_model.dart'; class FavoriteProvider extends ChangeNotifier { final Set _favorites = {}; Set get favorites => _favorites; void toggleFavorite(Destination destination) { if (_favorites.contains(destination.id)) { _favorites.remove(destination.id); destination.isFavorite = false; } else { _favorites.add(destination.id); destination.isFavorite = true; } notifyListeners(); } bool isFavorite(int id) { return _favorites.contains(id); } } ``` ### 3. Update destination_card_widget.dart Tambahkan favorite button: ```dart // Di bagian bottom card Container( padding: const EdgeInsets.all(14), child: Column( children: [ // ... existing content ... Row( children: [ Expanded( child: ElevatedButton( // ... existing button ... ), ), const SizedBox(width: 8), Container( width: 48, height: 36, decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(12), border: Border.all( color: Colors.grey[300] ?? Colors.grey, ), ), child: Icon( widget.destination.isFavorite ? Icons.favorite : Icons.favorite_border, color: const Color(0xFFE28D42), ), ), ], ), ], ), ) ``` ## 🎯 Integrasi dengan Provider ### Update main.dart ```dart import 'package:provider/provider.dart'; import 'providers/favorite_provider.dart'; void main() { runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => FavoriteProvider()), ], child: const ExploreLumajangApp(), ), ); } ``` ## 🔖 Integrasi Favorit Page Buat file baru: `lib/pages/favorite_page.dart` ```dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/destination_data.dart'; import '../providers/favorite_provider.dart'; import '../widgets/destination_card_widget.dart'; import 'destination_detail_page.dart'; class FavoritePage extends StatelessWidget { const FavoritePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ SliverAppBar( expandedHeight: 100, floating: false, pinned: true, elevation: 0, backgroundColor: const Color(0xFF1F8F5F), flexibleSpace: FlexibleSpaceBar( background: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Color(0xFF1F8F5F), Color(0xFF2FA86B), ], ), ), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Padding( padding: EdgeInsets.fromLTRB(20, 0, 20, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Favorit Saya', style: TextStyle( color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold, ), ), ], ), ), ], ), ), ), ), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 20), sliver: Consumer( builder: (context, favoriteProvider, _) { final favorites = destinationList .where((d) => favoriteProvider.isFavorite(d.id)) .toList(); if (favorites.isEmpty) { return SliverToBoxAdapter( child: Center( child: Padding( padding: const EdgeInsets.symmetric(vertical: 100), child: Column( children: [ Icon( Icons.favorite_outline, size: 64, color: Colors.grey[300], ), const SizedBox(height: 16), Text( 'Belum ada favorit', style: TextStyle( fontSize: 16, color: Colors.grey[600], fontWeight: FontWeight.w500, ), ), ], ), ), ), ); } return SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 16, mainAxisSpacing: 20, childAspectRatio: 0.75, ), delegate: SliverChildBuilderDelegate( (context, index) { final destination = favorites[index]; return DestinationCardWidget( destination: destination, onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => DestinationDetailPage( destination: destination, ), ), ); }, ); }, childCount: favorites.length, ), ); }, ), ), ], ), ); } } ``` ## 👤 Integrasi Profile Page Buat file baru: `lib/pages/profile_page.dart` ```dart import 'package:flutter/material.dart'; class ProfilePage extends StatelessWidget { const ProfilePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ SliverAppBar( expandedHeight: 100, pinned: true, backgroundColor: const Color(0xFF1F8F5F), flexibleSpace: FlexibleSpaceBar( background: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Color(0xFF1F8F5F), Color(0xFF2FA86B), ], ), ), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Padding( padding: EdgeInsets.fromLTRB(20, 0, 20, 20), child: Text( 'Profil Saya', style: TextStyle( color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold, ), ), ), ], ), ), ), ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Profile info here CircleAvatar( radius: 50, backgroundColor: Colors.grey[300], child: const Icon( Icons.person, size: 50, color: Colors.grey, ), ), const SizedBox(height: 16), const Text( 'Wisatawan', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( 'wisatawan@example.com', style: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), const SizedBox(height: 32), // Add profile options here ], ), ), ), ], ), ); } } ``` ## 🔄 Update beranda_screen.dart ```dart import 'package:flutter/material.dart'; import '../pages/home_page.dart'; import '../pages/favorite_page.dart'; import '../pages/profile_page.dart'; class BerandaScreen extends StatefulWidget { const BerandaScreen({Key? key}) : super(key: key); static const routeName = '/beranda'; @override State createState() => _BerandaScreenState(); } class _BerandaScreenState extends State { int _selectedIndex = 0; final List _pages = [ const HomePage(), const FavoritePage(), const ProfilePage(), ]; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } @override Widget build(BuildContext context) { return Scaffold( body: _pages[_selectedIndex], bottomNavigationBar: NavigationBar( selectedIndex: _selectedIndex, onDestinationSelected: _onItemTapped, destinations: const [ NavigationDestination( icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Beranda', ), NavigationDestination( icon: Icon(Icons.favorite_outline), selectedIcon: Icon(Icons.favorite), label: 'Favorit', ), NavigationDestination( icon: Icon(Icons.person_outline), selectedIcon: Icon(Icons.person), label: 'Profil', ), ], ), ); } } ``` ## ✅ Checklist Integrasi - [ ] Update main.dart dengan Provider - [ ] Create FavoriteProvider - [ ] Create ArViewerPage - [ ] Create FavoritePage - [ ] Create ProfilePage - [ ] Update DestinationCardWidget dengan favorite button - [ ] Update destination_detail_page.dart untuk AR viewer - [ ] Test favorit functionality - [ ] Test AR viewer navigation - [ ] Test profile page ## 🚀 Testing Setelah integrasi: 1. Test favorit: - Buka halaman Beranda - Tap card untuk buka detail - Tap favorite button - Navigasi ke tab Favorit - Verify card muncul di favorite page 2. Test AR Viewer: - Buka halaman detail - Tap "Lihat AR" - Verify navigasi ke AR viewer page 3. Test Profile: - Navigasi ke tab Profil - Verify profile info muncul --- **Notes**: Code snippets ini adalah referensi. Sesuaikan dengan implementasi yang sudah ada di project Anda.