Skip to content

Commit

Permalink
upload files
Browse files Browse the repository at this point in the history
  • Loading branch information
elmahsieh authored May 16, 2024
1 parent 8478ec6 commit d4a2155
Show file tree
Hide file tree
Showing 44 changed files with 1,938 additions and 0 deletions.
10 changes: 10 additions & 0 deletions animationSettings/AppPreferences.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ehsieh2.letswatchtv.animationSettings

import android.content.Context

object AppPreferences {
fun isAnimationEnabled(context: Context): Boolean {
val prefs = context.getSharedPreferences("AppSettingsPrefs", Context.MODE_PRIVATE)
return prefs.getBoolean("AnimationEnabled", true)
}
}
59 changes: 59 additions & 0 deletions apiFragments/PopularMoviesFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.ehsieh2.letswatchtv.apiFragments

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.ehsieh2.letswatchtv.MoviesAdapter
import com.ehsieh2.letswatchtv.MoviesViewModel
import com.ehsieh2.letswatchtv.databinding.FragmentPopularMoviesBinding
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController

class PopularMoviesFragment : Fragment() {

private lateinit var binding: FragmentPopularMoviesBinding
private val viewModel: MoviesViewModel by activityViewModels()
private lateinit var moviesAdapter: MoviesAdapter

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentPopularMoviesBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
observeViewModel()
viewModel.fetchTopRatedMovies()
}

private fun setupRecyclerView() {
moviesAdapter = MoviesAdapter { movie ->
// Define the onClick action
Toast.makeText(context, "Clicked: ${movie.title}", Toast.LENGTH_LONG).show()
// Navigate to the movie details fragment and pass movie id as argument
val action = PopularMoviesFragmentDirections.actionPopularMoviesFragmentToMovieDetailsFragment(movie.id)
findNavController().navigate(action)
}

binding.recyclerViewPopular.apply {
layoutManager = LinearLayoutManager(context)
adapter = moviesAdapter
}
}

private fun observeViewModel() {
viewModel.popularMovies.observe(viewLifecycleOwner) { movies ->
(binding.recyclerViewPopular.adapter as MoviesAdapter).submitList(movies)
binding.progressBar.visibility = View.GONE
}

viewModel.errorMessage.observe(viewLifecycleOwner) { error ->
Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
}
}
}
26 changes: 26 additions & 0 deletions apiFragments/PopularMoviesFragmentDirections.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.ehsieh2.letswatchtv.apiFragments

import android.os.Bundle
import androidx.navigation.NavDirections
import com.ehsieh2.letswatchtv.R

class PopularMoviesFragmentDirections {
companion object {
fun actionPopularMoviesFragmentToMovieDetailsFragment(movieId: Int): NavDirections {
return ActionPopularMoviesFragmentToMovieDetailsFragment(movieId)
}

private class ActionPopularMoviesFragmentToMovieDetailsFragment(private val movieId: Int) :
NavDirections {
override fun getArguments(): Bundle {
val result = Bundle()
result.putInt("movieId", movieId)
return result
}

override fun getActionId(): Int {
return R.id.action_popularMoviesFragment_to_movieDetailsFragment
}
}
}
}
59 changes: 59 additions & 0 deletions apiFragments/UpcomingMoviesFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.ehsieh2.letswatchtv.apiFragments

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.ehsieh2.letswatchtv.MoviesAdapter
import com.ehsieh2.letswatchtv.MoviesViewModel
import com.ehsieh2.letswatchtv.databinding.FragmentUpcomingMoviesBinding
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController

class UpcomingMoviesFragment : Fragment() {

private lateinit var binding: FragmentUpcomingMoviesBinding
private val viewModel: MoviesViewModel by activityViewModels()
private lateinit var moviesAdapter: MoviesAdapter

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentUpcomingMoviesBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
observeViewModel()
viewModel.fetchUpcomingMovies()
}

private fun setupRecyclerView() {
moviesAdapter = MoviesAdapter { movie ->
// Define the onClick action
Toast.makeText(context, "Clicked: ${movie.title}", Toast.LENGTH_LONG).show()
// Navigate to the movie details fragment and pass movie id as argument
val action = UpcomingMoviesFragmentDirection.actionUpcomingMoviesFragmentToMovieDetailsFragment(movie.id)
findNavController().navigate(action)
}

binding.recyclerViewUpcoming.apply {
layoutManager = LinearLayoutManager(context)
adapter = moviesAdapter
}
}

private fun observeViewModel() {
viewModel.upcomingMovies.observe(viewLifecycleOwner) { movies ->
(binding.recyclerViewUpcoming.adapter as MoviesAdapter).submitList(movies)
binding.progressBar.visibility = View.GONE
}

viewModel.errorMessage.observe(viewLifecycleOwner) { error ->
Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
}
}
}
26 changes: 26 additions & 0 deletions apiFragments/UpcomingMoviesFragmentDirection.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.ehsieh2.letswatchtv.apiFragments

import android.os.Bundle
import androidx.navigation.NavDirections
import com.ehsieh2.letswatchtv.R

class UpcomingMoviesFragmentDirection {
companion object {
fun actionUpcomingMoviesFragmentToMovieDetailsFragment(movieId: Int): NavDirections {
return ActionUpcomingMoviesFragmentToMovieDetailsFragment(movieId)
}

private class ActionUpcomingMoviesFragmentToMovieDetailsFragment(private val movieId: Int) :
NavDirections {
override fun getArguments(): Bundle {
val result = Bundle()
result.putInt("movieId", movieId)
return result
}

override fun getActionId(): Int {
return R.id.action_upcomingMoviesFragment_to_movieDetailsFragment
}
}
}
}
24 changes: 24 additions & 0 deletions dataHandler/Api.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.ehsieh2.letswatchtv.dataHandler

import com.ehsieh2.letswatchtv.Movie
import com.ehsieh2.letswatchtv.MoviesResponse
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query

interface Api {

@GET("movie/popular")
fun getPopularMovies(@Query("api_key") apiKey: String, @Query("page") page: Int): Call<MoviesResponse>

@GET("movie/upcoming")
fun getUpcomingMovies(@Query("api_key") apiKey: String, @Query("page") page: Int): Call<MoviesResponse>

@GET("movie/top_rated")
fun getTopRatedMovies(@Query("api_key") apiKey: String, @Query("page") page: Int): Call<MoviesResponse>

@GET("movie/{id}")
fun getMovieDetails(@Path("id") movieId: Int): Call<Movie>

}
12 changes: 12 additions & 0 deletions dataHandler/AssetJsonReader.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ehsieh2.letswatchtv.dataHandler

import android.content.Context
import com.ehsieh2.letswatchtv.MoviesResponse
import com.google.gson.Gson

object AssetJsonReader {
fun getMoviesFromJson(context: Context, fileName: String): MoviesResponse {
val jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() }
return Gson().fromJson(jsonString, MoviesResponse::class.java)
}
}
44 changes: 44 additions & 0 deletions dataHandler/RetrofitClient.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.ehsieh2.letswatchtv.dataHandler

import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory


object RetrofitClient {
private const val BASE_URL = "https://api.themoviedb.org/3/"
private const val API_KEY = "f30a516df866e8e39ffc019d1fcace2f" // Ensure this is securely managed

private val okHttpClient = OkHttpClient.Builder()
.addInterceptor(ApiKeyInterceptor(API_KEY))
.build()

val instance: Api by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(Api::class.java) // Make sure Api is your interface
}
}

class ApiKeyInterceptor(private val apiKey: String) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val originalHttpUrl = originalRequest.url // Ensure to use the method call

val newHttpUrl = originalHttpUrl.newBuilder()
.addQueryParameter("api_key", apiKey)
.build()

val newRequest = originalRequest.newBuilder()
.url(newHttpUrl)
.build()

return chain.proceed(newRequest)
}
}

86 changes: 86 additions & 0 deletions dataHandler/moviesRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.ehsieh2.letswatchtv.dataHandler

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.ehsieh2.letswatchtv.Movie
import com.ehsieh2.letswatchtv.MoviesResponse
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MoviesRepository {
private val apiKey = "f30a516df866e8e39ffc019d1fcace2f"

fun fetchUpcomingMovies(onSuccess: (List<Movie>) -> Unit, onFailure: (String) -> Unit) {
RetrofitClient.instance.getUpcomingMovies(apiKey, 1).enqueue(object : Callback<MoviesResponse> {
override fun onFailure(call: Call<MoviesResponse>, t: Throwable) {
onFailure("Network error: ${t.message ?: "Unknown error"}")
}

override fun onResponse(call: Call<MoviesResponse>, response: Response<MoviesResponse>) {
if (response.isSuccessful) {
response.body()?.results?.let(onSuccess) ?: onFailure("No upcoming movies found")
} else {
onFailure("Error fetching upcoming movies: ${response.errorBody()?.string() ?: "Unknown error"}")
}
}
})
}

fun fetchTopRatedMovies(page: Int, onSuccess: (List<Movie>) -> Unit, onFailure: (String) -> Unit) {
RetrofitClient.instance.getTopRatedMovies(apiKey, page).enqueue(object : Callback<MoviesResponse> {
override fun onResponse(call: Call<MoviesResponse>, response: Response<MoviesResponse>) {
if (response.isSuccessful) {
response.body()?.results?.let(onSuccess) ?: onFailure("No top rated movies found")
} else {
onFailure("Error fetching top rated movies: ${response.errorBody()?.string() ?: "Unknown error"}")
}
}

override fun onFailure(call: Call<MoviesResponse>, t: Throwable) {
onFailure("Network error: ${t.message ?: "Unknown error"}")
}
})
}

fun fetchPopularMovies(onSuccess: (List<Movie>) -> Unit, onFailure: (String) -> Unit) {
RetrofitClient.instance.getPopularMovies(apiKey, 1).enqueue(object : Callback<MoviesResponse> {
override fun onResponse(call: Call<MoviesResponse>, response: Response<MoviesResponse>) {
if (response.isSuccessful) {
response.body()?.results?.let {
if (it.isNotEmpty()) {
onSuccess(it)
} else {
onFailure("No movies found.")
}
} ?: onFailure("No movies found.")
} else {
onFailure("Error fetching movies: ${response.errorBody()?.string() ?: "Unknown error"}")
}
}

override fun onFailure(call: Call<MoviesResponse>, t: Throwable) {
onFailure("Network error: ${t.message ?: "Unknown error"}")
}
})
}

fun getMovieDetails(movieId: Int): LiveData<Movie?> {
val movieDetailsLiveData = MutableLiveData<Movie?>()
val request = RetrofitClient.instance.getMovieDetails(movieId)
request.enqueue(object : Callback<Movie> {
override fun onFailure(call: Call<Movie>, t: Throwable) {
movieDetailsLiveData.postValue(null)
}

override fun onResponse(call: Call<Movie>, response: Response<Movie>) {
if (response.isSuccessful) {
movieDetailsLiveData.postValue(response.body())
} else {
movieDetailsLiveData.postValue(null)
}
}
})
return movieDetailsLiveData
}
}
Loading

0 comments on commit d4a2155

Please sign in to comment.