MIF_E31231623/INTEGRATION_GUIDE.md

15 KiB

📝 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:

// 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

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<ArViewerPage> createState() => _ArViewerPageState();
}

class _ArViewerPageState extends State<ArViewerPage> {
  @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:

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

import 'package:flutter/material.dart';
import '../models/destination_model.dart';

class FavoriteProvider extends ChangeNotifier {
  final Set<int> _favorites = {};
  
  Set<int> 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:

// 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

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

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<FavoriteProvider>(
              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

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

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<BerandaScreen> createState() => _BerandaScreenState();
}

class _BerandaScreenState extends State<BerandaScreen> {
  int _selectedIndex = 0;

  final List<Widget> _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.