UAS - MovFlix
Nama : Christoforus Indra Bagus Pratama
NRP : 5025231124
Mata Kuliah : Pemrograman Perangkat Bergerak
Tanggal : 14 Juni 2026
Pertemuan : 16 - Final Project
Proyek : MovFlix - Aplikasi Katalog Film Android
Kode : Github
Presentasi : Link Canva
Video : Link Youtube
Daftar Isi
1. Deskripsi Aplikasi
MovFlix adalah aplikasi katalog film (movie catalogue) Android yang menampilkan daftar film, detail film, serta pemutaran trailer. Seluruh data film diambil secara real-time dari TMDB (The Movie Database) API. Aplikasi dibangun sepenuhnya menggunakan Jetpack Compose, framework UI declarative modern dari Android, untuk menghadirkan antarmuka yang responsif dan mulus.
Pengguna dapat menjelajahi film berdasarkan kategori (Trending, Now Playing, Popular, Top Rated), mencari film dengan filter genre, melihat detail lengkap sebuah film, dan menonton trailer langsung di dalam aplikasi melalui YouTube embed. MovFlix juga dilengkapi sistem autentikasi lokal (login, register, dan guest) serta fitur watchlist yang tersimpan terpisah per akun pengguna.
Bahasa Antarmuka: antarmuka utama menggunakan istilah Inggris yang umum (Home, Search, Watch Trailer) dengan beberapa bagian berbahasa Indonesia. Minimum SDK: aplikasi kompatibel dengan Android 7.0 (API Level 24) ke atas. Arsitektur: menggunakan pola MVVM dengan tema gelap (dark theme) sinematik.
2. Fitur-Fitur Utama Aplikasi
2.1 Autentikasi Lokal (Login, Register, Guest)
Fitur: Pengguna dapat membuat akun (register), masuk (login) dengan email & password, atau memilih Masuk sebagai Guest tanpa akun.
Implementasi: Data akun disimpan lokal di Room Database. Password tidak disimpan dalam bentuk teks asli, melainkan di-hash dengan SHA-256 + salt. Status login (session) disimpan menggunakan SharedPreferences sehingga pengguna tetap login setelah aplikasi ditutup.
2.2 Navigasi Swipe Berbasis Pager
Fitur: Tiga menu utama — Home, Search, dan Profile — dapat dipindah dengan mengusap layar (swipe) maupun menekan bottom navigation bar. Keduanya tersinkron dua arah.
Implementasi: Menggunakan HorizontalPager yang dipasangkan dengan
NavigationBar melalui PagerState.
2.3 Beranda Kategori dengan Hero Slider
Fitur: Halaman Home menampilkan hero slider film trending yang berganti otomatis, lalu baris kategori Now Playing, Popular, dan Top Rated yang dapat di-scroll horizontal.
Collapsing Top Bar: Header akan tersembunyi saat layar di-scroll ke bawah dan muncul kembali saat di-scroll ke atas (enter-always scroll behavior). Saat menunggu data, ditampilkan shimmer skeleton.
2.4 Pencarian dengan Filter Genre
Fitur: Pencarian film secara debounced (tanpa menekan tombol submit) dan filter berdasarkan genre chips. Hasil ditampilkan dalam grid, lengkap dengan empty state yang jelas.
2.5 Detail Film dan Pemutar Trailer
Fitur: Halaman detail menampilkan backdrop, poster, rating, durasi, genre, sinopsis, dan tombol Watch Trailer.
Pemutar Trailer: Trailer dari TMDB (berupa YouTube video id) diputar full-screen landscape di dalam aplikasi menggunakan WebView yang memuat iframe embed YouTube. Pendekatan iframe statis dipilih karena lebih andal dibanding membuka URL embed langsung.
2.6 Watchlist Per-Akun
Fitur: Pengguna dapat menyimpan film ke watchlist. Watchlist terikat ke akun — setiap akun memiliki daftar sendiri, dan akan muncul kembali saat login dengan akun yang sama.
Batasan Guest: Akun guest tidak bisa menyimpan watchlist. Saat guest menekan tombol simpan, muncul dialog peringatan untuk login atau membatalkan. Penghapusan watchlist dilengkapi undo via Snackbar.
2.7 Halaman Profile
Fitur: Menampilkan nama dan email pengguna beserta daftar watchlist miliknya. Untuk guest, ditampilkan ajakan untuk login.
3. Arsitektur Aplikasi
MovFlix menggunakan arsitektur MVVM (Model-View-ViewModel) yang direkomendasikan Google. Arsitektur ini memisahkan logika bisnis dari antarmuka, sehingga kode lebih terstruktur, testable, dan mudah dirawat. Lapisan data menerapkan prinsip Single Source of Truth melalui Repository.
UI Layer (Presentation)
Jetpack Compose, Material 3, Navigation, HorizontalPager, Coil
▼
ViewModel Layer (State Management)
ViewModel, StateFlow, collectAsState
▼
Repository Layer (Data Abstraction)
MovieRepository, AuthRepository, ServiceLocator (DI)
▼
Data Layer
Remote: Retrofit + OkHttp (TMDB API) | Local: Room (SQLite), SharedPreferences
3.1 Penjelasan Setiap Layer
| Layer | Deskripsi | Tanggung Jawab |
|---|---|---|
| UI Layer | Lapisan presentasi berbasis Jetpack Compose & Material 3 untuk UI deklaratif yang modern. | Menampilkan data, menangkap input, navigasi antar layar |
| ViewModel | Mengelola state UI dengan StateFlow dan menjembatani UI dengan Repository. | Mengelola state, menangani event UI, menyediakan data ke UI |
| Repository | Abstraksi sumber data. Menggabungkan data remote (TMDB) dan local (Room) menjadi satu sumber. | Menyediakan data, logika bisnis (watchlist per-akun, kandidat trailer) |
| Data Layer | Retrofit untuk REST API TMDB; Room untuk database lokal; SharedPreferences untuk session. | Network request, akses & penyimpanan database |
3.2 Dependency Injection
Aplikasi memakai DI manual sederhana melalui object ServiceLocator yang membuat instance singleton dari Retrofit, Room database, serta Repository. Pendekatan ini ringan dan cukup untuk lingkup proyek tanpa overhead Hilt/Dagger.
4. Struktur File dan Folder Proyek
Berikut struktur direktori utama proyek MovFlix beserta fungsi tiap bagiannya:
Struktur Proyek (ringkas)
FP-PPB/
└── app/src/main/
├── kotlin/com/example/moviecatalogue/
│ ├── MainActivity.kt Entry point + setup navigation
│ ├── MovieCatalogueApp.kt Application class
│ ├── SplashScreen.kt Splash screen (logo)
│ ├── data/
│ │ ├── auth/ PasswordHasher, SessionManager
│ │ ├── local/ Room: MovieDao, UserDao,
│ │ │ MovieDatabase, MovieEntity, UserEntity
│ │ ├── remote/ ApiService (TMDB), Dtos
│ │ └── repository/ MovieRepositoryImpl, AuthRepositoryImpl
│ ├── di/
│ │ └── ServiceLocator.kt Dependency Injection
│ ├── domain/ Model + interface (Movie, UserSession,
│ │ MovieRepository, AuthRepository)
│ └── ui/
│ ├── components/ MovieCard, MovieSlider,
│ │ YouTubeTrailerPlayer
│ ├── navigation/ Navigation.kt (NavHost + Pager)
│ ├── screens/
│ │ ├── home/ HomeScreen, HomeViewModel
│ │ ├── search/ SearchScreen, SearchViewModel
│ │ ├── detail/ DetailScreen, DetailViewModel
│ │ ├── profile/ ProfileScreen, ProfileViewModel
│ │ └── auth/ LoginScreen, RegisterScreen, AuthViewModel
│ └── theme/ Color, Theme, Typography
├── res/ Drawable, values
└── AndroidManifest.xml4.1 Penjelasan Folder Utama
data/remote/
ApiService.kt mendefinisikan endpoint TMDB (trending, now playing, popular, top rated, search, detail, videos, genres) dengan Retrofit. Dtos.kt berisi Data Transfer Object untuk parsing JSON respons API.
data/local/
Implementasi Room: MovieDao & UserDao (operasi CRUD), MovieDatabase (kelas database), MovieEntity (watchlist, ber-key gabungan id+userId) dan UserEntity (akun pengguna).
data/auth/
PasswordHasher.kt melakukan hashing password (SHA-256 + salt). SessionManager.kt menyimpan & mengekspos session pengguna sebagai
StateFlow melalui SharedPreferences.
data/repository/ & domain/
MovieRepositoryImpl & AuthRepositoryImpl mengimplementasikan interface di domain/. Repository film menggabungkan API dan Room serta menyaring watchlist sesuai user aktif.
ui/navigation/
Navigation.kt berisi
AppNavigation (NavHost: Splash, Login, Register, Main, Detail) dan MainScreen (HorizontalPager + bottom navigation).
ui/screens/ & ui/components/
Tiap fitur memiliki Screen (Composable) dan ViewModel-nya. Komponen yang dipakai berulang seperti MovieCard, MovieSlider, dan YouTubeTrailerPlayer berada di components/.
5. Penjelasan Detil Kode MainActivity.kt
MainActivity.kt adalah single activity yang menjadi entry point aplikasi. Tugasnya menyiapkan dependency, mengaktifkan tema, dan menampilkan graph navigasi. Berikut penjelasan tiap bagiannya.
5.1 Class MainActivity dan onCreate()
MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Mengaktifkan tampilan edge-to-edge (immersive)
enableEdgeToEdge()
// Dependency Injection via ServiceLocator
val repository = ServiceLocator.provideRepository(applicationContext)
val authRepository = ServiceLocator.provideAuthRepository(applicationContext)
setContent {
FinalProjectTheme {
Surface(modifier = Modifier.fillMaxSize()) {
AppNavigation(
repository = repository,
authRepository = authRepository
)
}
}
}
}
}
Penjelasan:
- ComponentActivity: base activity yang mendukung Jetpack Compose.
- enableEdgeToEdge(): membuat konten menggambar hingga di belakang status bar & navigation bar untuk tampilan modern.
- ServiceLocator.provideRepository / provideAuthRepository: mengambil instance singleton Repository film dan Repository autentikasi (Dependency Injection manual).
- setContent { }: mendefinisikan seluruh UI Compose untuk activity ini.
- FinalProjectTheme: membungkus aplikasi dengan tema gelap (Material 3) sekaligus mengatur warna system bar.
- AppNavigation(...): memasang graph navigasi dengan kedua repository sebagai dependency.
5.2 AppNavigation — Graph Navigasi
Navigation.kt (ringkas)
@Composable
fun AppNavigation(repository: MovieRepository, authRepository: AuthRepository) {
val navController = rememberNavController()
val session by authRepository.session.collectAsState()
val isGuest = session?.isGuest == true
NavHost(navController, startDestination = Screen.Splash.route) {
composable(Screen.Splash.route) {
SplashScreen(onTimeout = {
// Sudah login -> Main, belum -> Login
val target = if (session != null) Screen.Main.route else Screen.Login.route
navController.navigate(target) { popUpTo(Screen.Splash.route) { inclusive = true } }
})
}
composable(Screen.Login.route) { /* LoginScreen */ }
composable(Screen.Register.route) { /* RegisterScreen */ }
composable(Screen.Main.route) { /* MainScreen (pager) */ }
composable(Screen.Detail.route) { /* DetailScreen */ }
}
}
Penjelasan:
NavHost mendaftarkan seluruh rute. State session diamati sebagai StateFlow sehingga UI bereaksi otomatis saat login/logout. Splash menentukan tujuan awal: Main jika sudah ada sesi, atau Login jika belum.
5.3 MainScreen — Pager + Bottom Navigation
Navigation.kt (ringkas)
@Composable
fun MainScreen(/* repository, authRepository, isGuest, callbacks */) {
val pagerState = rememberPagerState(pageCount = { bottomNavItems.size })
val scope = rememberCoroutineScope()
Scaffold(
bottomBar = {
NavigationBar {
bottomNavItems.forEachIndexed { index, item ->
NavigationBarItem(
selected = pagerState.currentPage == index,
onClick = { scope.launch { pagerState.animateScrollToPage(index) } },
icon = { /* Home / Search / Profile */ },
label = { Text(item.label) }
)
}
}
}
) { padding ->
HorizontalPager(state = pagerState, modifier = Modifier.padding(padding)) { page ->
when (page) {
0 -> HomeScreen(...)
1 -> SearchScreen(...)
2 -> ProfileScreen(...)
}
}
}
}
Penjelasan:
HorizontalPager menampung tiga halaman yang bisa digeser (swipe). NavigationBar dan pager dihubungkan lewat pagerState.currentPage dan animateScrollToPage(), sehingga menekan menu dan menggeser layar saling sinkron.
5.4 SplashScreen
SplashScreen.kt (ringkas)
@Composable
fun SplashScreen(onTimeout: () -> Unit) {
LaunchedEffect(Unit) {
delay(2000) // tampilkan logo 2 detik
onTimeout()
}
Surface(modifier = Modifier.fillMaxSize(), color = Color.Black) {
Box(contentAlignment = Alignment.Center) {
Image(painter = painterResource(R.drawable.movflix_logo), contentDescription = "MovFlix Logo")
}
}
}
Penjelasan:
LaunchedEffect menjalankan delay 2 detik untuk menampilkan logo, lalu memanggil onTimeout() yang memutuskan navigasi berikutnya (Login atau Main).
6. Alur Eksekusi Aplikasi
Berikut alur lengkap dari peluncuran hingga aplikasi siap digunakan:
1. Aplikasi Diluncurkan: Android memanggil
MainActivity.onCreate().2. Setup & DI:
enableEdgeToEdge() dijalankan, lalu ServiceLocator menyediakan MovieRepository dan AuthRepository (singleton).3. UI Dipasang:
setContent memasang FinalProjectTheme dan AppNavigation.4. Splash Screen: Logo MovFlix ditampilkan selama 2 detik.
5. Pengecekan Session: Setelah delay, aplikasi memeriksa session. Jika sudah login → Main; jika belum → Login.
6. Autentikasi: Pengguna login, register, atau memilih guest. Saat berhasil, session disimpan dan navigasi menuju Main.
7. Main Screen:
HorizontalPager + bottom navigation dirender, halaman Home tampil pertama.8. Pemuatan Data: Setiap ViewModel memanggil Repository untuk mengambil data film dari TMDB API (atau watchlist dari Room), lalu meng-update
StateFlow.9. UI Recompose: Perubahan state otomatis memicu recompose sehingga daftar film tampil. Aplikasi siap untuk interaksi.
7. Interaksi User dan Event Flow
MovFlix menggunakan event-driven architecture: interaksi di UI memanggil callback yang terhubung ke method ViewModel, yang lalu memperbarui state dan/atau database. Berikut alur tiap interaksi utama (disertai panduan manual penggunaan).
Register / Login
Cara pakai: Pada layar Login, isi email & password lalu tekan Masuk, atau tekan Daftar untuk membuat akun baru.
Flow: Input user →
Flow: Input user →
AuthViewModel.login()/register() → validasi → AuthRepository cek/simpan ke Room (password di-hash) → session disimpan → navigasi ke Main.
Masuk sebagai Guest
Cara pakai: Tekan Masuk sebagai Guest di layar Login.
Flow:
Flow:
AuthViewModel.loginAsGuest() → session guest disimpan → masuk ke Main. Tombol akun pada Home berubah menjadi Masuk.
Menjelajah & Mencari Film
Cara pakai: Geser antar tab atau scroll kategori di Home; buka tab Search dan ketik judul, pilih genre untuk memfilter.
Flow: ViewModel memanggil
Flow: ViewModel memanggil
MovieRepository → Retrofit request ke TMDB → respons dipetakan ke domain model → StateFlow update → grid film recompose.
Membuka Detail & Menonton Trailer
Cara pakai: Tekan poster film untuk membuka detail, lalu tekan Watch Trailer.
Flow:
Flow:
DetailViewModel mengambil detail + daftar video dari TMDB → trailer (YouTube id) diputar full-screen di YouTubeTrailerPlayer (WebView iframe).
Menyimpan ke Watchlist
Cara pakai: Pada detail, tekan tombol Watchlist untuk menyimpan/menghapus.
Flow (user login):
Flow (guest): Muncul dialog "Login diperlukan" dengan pilihan Login atau Batal.
Flow (user login):
DetailViewModel.toggleWatchlist() → MovieRepository.addToWatchlist() menyimpan ke Room dengan userId aktif → ikon berubah menjadi Saved.Flow (guest): Muncul dialog "Login diperlukan" dengan pilihan Login atau Batal.
8. Teknologi dan Dependencies
MovFlix dibangun dengan berbagai library modern dari ekosistem Android:
| Teknologi | Versi | Kegunaan |
|---|---|---|
| Jetpack Compose | BOM 2024.09.00 | UI declarative framework berbasis Kotlin |
| Material 3 | Latest | Design system & komponen siap pakai (Scaffold, TopAppBar, dll) |
| Navigation Compose | 2.8.3 | Navigasi antar layar (NavHost, routes) |
| HorizontalPager | (Compose Foundation) | Navigasi swipe antar tab |
| Retrofit | 2.11.0 | HTTP client untuk REST API TMDB |
| OkHttp | 4.12.0 | Networking & interceptor (Authorization header) |
| Gson | (converter 2.11.0) | Parsing JSON respons API |
| Room | 2.6.1 | Database lokal (watchlist & akun) |
| KSP | 2.0.21-1.0.27 | Annotation processor untuk Room |
| Coil | 2.7.0 | Memuat gambar poster/backdrop |
| ViewModel + StateFlow | Lifecycle 2.8.6 | State management reaktif |
| Coroutines | 1.8.1 | Pemrograman asynchronous |
| WebView | (Android SDK) | Memutar trailer via YouTube iframe embed |
| SharedPreferences | (Android SDK) | Menyimpan session login |
Sumber data: seluruh informasi film berasal dari TMDB API (
https://api.themoviedb.org/3/). Min SDK 24, Target/Compile SDK 35, ditulis dalam Kotlin.
9. Kesimpulan
MovFlix menunjukkan penerapan teknologi Android modern untuk membangun aplikasi katalog film yang lengkap dan rapi. Dengan arsitektur MVVM, Jetpack Compose untuk UI, Retrofit untuk konsumsi TMDB API, dan Room untuk penyimpanan lokal, aplikasi memiliki fondasi yang kuat dan mudah dikembangkan.
Fitur seperti autentikasi lokal, watchlist per-akun, pencarian dengan filter, pemutaran trailer, dan navigasi swipe membuat aplikasi terasa modern dan ramah pengguna. Pemisahan tanggung jawab antar layer yang jelas memastikan kode mudah dirawat, diuji, dan diperluas dengan fitur baru di masa depan.

Komentar
Posting Komentar