diff --git a/.idea/misc.xml b/.idea/misc.xml index 3d451ac..942c66b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,8 +3,10 @@ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4b5cf57..688ba38 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,12 +5,16 @@ + diff --git a/app/src/main/java/com/example/mvvm2/App.kt b/app/src/main/java/com/example/mvvm2/App.kt new file mode 100644 index 0000000..ae76b94 --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/App.kt @@ -0,0 +1,16 @@ +package com.example.mvvm2 + +import android.app.Application +import android.content.SharedPreferences +import com.example.mvvm2.data.repository.local.SharedPreference + +class App: Application() { + override fun onCreate() { + super.onCreate() + instance = this + } + + companion object { + lateinit var instance: App + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/data/repository/Repository.kt b/app/src/main/java/com/example/mvvm2/data/repository/Repository.kt new file mode 100644 index 0000000..bbc8d99 --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/data/repository/Repository.kt @@ -0,0 +1,35 @@ +package com.example.mvvm2.data.repository + +import com.example.mvvm2.data.model.MovieResponse +import com.example.mvvm2.data.repository.local.LocalDataSource +import com.example.mvvm2.data.repository.local.LocalDataSourceImpl +import com.example.mvvm2.data.repository.remote.RemoteDataSourceImpl +import retrofit2.Call + +interface Repository { + val remoteDataSource: RemoteDataSourceImpl + val localDataSource: LocalDataSourceImpl + + fun getMovieList(query: String): Call + fun getHistory(): ArrayList? + fun setHistory(title:String) +} + +class RepositoryImpl() : Repository { + override val remoteDataSource: RemoteDataSourceImpl + get() = RemoteDataSourceImpl() + override val localDataSource: LocalDataSourceImpl + get() = LocalDataSourceImpl() + + override fun getMovieList(query: String): Call { + return remoteDataSource.getMovieList(query) + } + + override fun getHistory(): ArrayList? { + return localDataSource.getHistory() + } + + override fun setHistory(title: String) { + return localDataSource.setHistory(title) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/data/repository/local/LocalDataSource.kt b/app/src/main/java/com/example/mvvm2/data/repository/local/LocalDataSource.kt new file mode 100644 index 0000000..8d4d723 --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/data/repository/local/LocalDataSource.kt @@ -0,0 +1,21 @@ +package com.example.mvvm2.data.repository.local + +import com.example.mvvm2.App + +interface LocalDataSource { + val pref: SharedPreference + get() = SharedPreference(App.instance.applicationContext) + + fun getHistory(): ArrayList? + fun setHistory(title:String) +} + +class LocalDataSourceImpl():LocalDataSource{ + override fun getHistory(): ArrayList? { + return pref.getHistory() + } + + override fun setHistory(title: String) { + pref.setHistory(title) + } +} diff --git a/app/src/main/java/com/example/mvvm2/data/repository/local/SharedPreference.kt b/app/src/main/java/com/example/mvvm2/data/repository/local/SharedPreference.kt new file mode 100644 index 0000000..58355dc --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/data/repository/local/SharedPreference.kt @@ -0,0 +1,32 @@ +package com.example.mvvm2.data.repository.local + +import android.content.Context +import android.content.SharedPreferences +import android.util.Log +import com.example.mvvm2.App +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken + +class SharedPreference(context: Context) { + private val PREF_NAME = "PREF" + private val PREF_MODE = Context.MODE_PRIVATE + private var pref: SharedPreferences = context.getSharedPreferences(PREF_NAME, PREF_MODE) + + + private val HISTORY = "HISTORY" + fun getHistory(): ArrayList? { + val history = pref.getString(HISTORY, null) + return Gson().fromJson(history, object : TypeToken>() {}.type) + } + + fun setHistory(h: String) { + var history: ArrayList? = if (getHistory().isNullOrEmpty()) arrayListOf() else getHistory() + history!!.add(h) + history = history.distinct() as ArrayList + + if (history.size == 6) { + history.removeAt(0) + } + pref.edit().putString(HISTORY, Gson().toJson(history)).apply() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/data/repository/BaseRetrofit.kt b/app/src/main/java/com/example/mvvm2/data/repository/remote/BaseRetrofit.kt similarity index 86% rename from app/src/main/java/com/example/mvvm2/data/repository/BaseRetrofit.kt rename to app/src/main/java/com/example/mvvm2/data/repository/remote/BaseRetrofit.kt index ff5fb24..2541979 100644 --- a/app/src/main/java/com/example/mvvm2/data/repository/BaseRetrofit.kt +++ b/app/src/main/java/com/example/mvvm2/data/repository/remote/BaseRetrofit.kt @@ -1,4 +1,4 @@ -package com.example.mvvm2.data.repository +package com.example.mvvm2.data.repository.remote import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory diff --git a/app/src/main/java/com/example/mvvm2/data/repository/MovieRetrofit.kt b/app/src/main/java/com/example/mvvm2/data/repository/remote/MovieRetrofit.kt similarity index 90% rename from app/src/main/java/com/example/mvvm2/data/repository/MovieRetrofit.kt rename to app/src/main/java/com/example/mvvm2/data/repository/remote/MovieRetrofit.kt index 4baa503..1f03a3f 100644 --- a/app/src/main/java/com/example/mvvm2/data/repository/MovieRetrofit.kt +++ b/app/src/main/java/com/example/mvvm2/data/repository/remote/MovieRetrofit.kt @@ -1,4 +1,4 @@ -package com.example.mvvm2.data.repository +package com.example.mvvm2.data.repository.remote import com.example.mvvm2.data.model.MovieResponse import retrofit2.Call diff --git a/app/src/main/java/com/example/mvvm2/data/repository/remote/RemoteDataSource.kt b/app/src/main/java/com/example/mvvm2/data/repository/remote/RemoteDataSource.kt new file mode 100644 index 0000000..98f3ad3 --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/data/repository/remote/RemoteDataSource.kt @@ -0,0 +1,15 @@ +package com.example.mvvm2.data.repository.remote + +import com.example.mvvm2.data.model.MovieResponse +import retrofit2.Call + +interface RemoteDataSource { + fun getMovieList(query: String):Call +} + +class RemoteDataSourceImpl() : RemoteDataSource { + + override fun getMovieList(query: String): Call { + return BaseRetrofit.retrofit.create(MovieRetrofit::class.java).getMovieList(query) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/ui/history/HistoryActivity.kt b/app/src/main/java/com/example/mvvm2/ui/history/HistoryActivity.kt new file mode 100644 index 0000000..52f8b47 --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/ui/history/HistoryActivity.kt @@ -0,0 +1,42 @@ +package com.example.mvvm2.ui.history + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.ViewModelProvider +import com.example.mvvm2.R +import com.example.mvvm2.databinding.ActivityHistoryBinding +import com.example.mvvm2.databinding.ActivityMainBinding +import com.example.mvvm2.ui.main.MainActivity +import com.example.mvvm2.ui.main.MainRecyclerAdapter +import com.example.mvvm2.ui.main.MainViewModel +import com.example.mvvm2.ui.moive.MovieActivity + +class HistoryActivity : AppCompatActivity() { + private lateinit var vm:HistoryViewModel + private lateinit var binding: ActivityHistoryBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + //viewmodel + vm = ViewModelProvider( + this, + ViewModelProvider.NewInstanceFactory() + )[HistoryViewModel::class.java] + vm.getHistory() + + //binding + binding = DataBindingUtil.setContentView(this, R.layout.activity_history) + binding.vm = vm + binding.lifecycleOwner = this + binding.historyRecycler.adapter = HistoryRecyclerAdapter(){ + val mainIntent = Intent(this, MainActivity::class.java).apply { + putExtra("title", it) + } + startActivity(mainIntent) + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/ui/history/HistoryRecyclerAdapter.kt b/app/src/main/java/com/example/mvvm2/ui/history/HistoryRecyclerAdapter.kt new file mode 100644 index 0000000..062d5af --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/ui/history/HistoryRecyclerAdapter.kt @@ -0,0 +1,40 @@ +package com.example.mvvm2.ui.history + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.mvvm2.databinding.ItemHistoryBinding + +class HistoryRecyclerAdapter(val historyClickListener: (String) -> Unit) : + RecyclerView.Adapter() { + + private val histories:ArrayList = arrayListOf() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryRecyclerAdapter.ViewHolder { + val binding = ItemHistoryBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: HistoryRecyclerAdapter.ViewHolder, position: Int) { + holder.bind(histories[position]) + holder.itemView.setOnClickListener { historyClickListener(histories[position])} + } + + override fun getItemCount(): Int = histories.size + + @SuppressLint("NotifyDataSetChanged") + fun setItem(histories: ArrayList) { + this.histories.clear() + this.histories.addAll(histories) + notifyDataSetChanged() + } + + class ViewHolder(private val binding:ItemHistoryBinding):RecyclerView.ViewHolder(binding.root){ + fun bind(history:String) { + binding.history = history + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/ui/history/HistoryViewModel.kt b/app/src/main/java/com/example/mvvm2/ui/history/HistoryViewModel.kt new file mode 100644 index 0000000..a7687e4 --- /dev/null +++ b/app/src/main/java/com/example/mvvm2/ui/history/HistoryViewModel.kt @@ -0,0 +1,15 @@ +package com.example.mvvm2.ui.history + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.example.mvvm2.data.repository.RepositoryImpl + +class HistoryViewModel:ViewModel() { + val repository:RepositoryImpl = RepositoryImpl() + + val historyList: MutableLiveData?> = MutableLiveData() + + fun getHistory () { + historyList.value = repository.getHistory() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/ui/main/MainActivity.kt b/app/src/main/java/com/example/mvvm2/ui/main/MainActivity.kt index 19499c7..b46c6ec 100644 --- a/app/src/main/java/com/example/mvvm2/ui/main/MainActivity.kt +++ b/app/src/main/java/com/example/mvvm2/ui/main/MainActivity.kt @@ -7,6 +7,7 @@ import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider import com.example.mvvm2.R import com.example.mvvm2.databinding.ActivityMainBinding +import com.example.mvvm2.ui.history.HistoryActivity import com.example.mvvm2.ui.moive.MovieActivity import javax.security.auth.callback.Callback import kotlin.math.log @@ -26,6 +27,12 @@ class MainActivity : AppCompatActivity() { ViewModelProvider.NewInstanceFactory() )[MainViewModel::class.java] + + if (intent.getStringExtra("title") != null) { + vm.query = intent.getStringExtra("title").toString() + vm.getMoveList() + } + // binding binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.vm = vm @@ -36,5 +43,11 @@ class MainActivity : AppCompatActivity() { } startActivity(movieIntent) } + + //History button clickListener + binding.mainHistoryBtn.setOnClickListener{ + val historyIntent = Intent(this, HistoryActivity::class.java) + startActivity(historyIntent) + } } } diff --git a/app/src/main/java/com/example/mvvm2/ui/main/MainBindingAdapter.kt b/app/src/main/java/com/example/mvvm2/ui/main/MainBindingAdapter.kt index 533d1b2..fc50925 100644 --- a/app/src/main/java/com/example/mvvm2/ui/main/MainBindingAdapter.kt +++ b/app/src/main/java/com/example/mvvm2/ui/main/MainBindingAdapter.kt @@ -1,13 +1,27 @@ package com.example.mvvm2.ui.main import android.util.Log +import android.view.View import android.widget.ImageView +import android.widget.TextView import androidx.databinding.BindingAdapter import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.example.mvvm2.R import com.example.mvvm2.data.model.Movie +import com.example.mvvm2.ui.history.HistoryRecyclerAdapter +import org.w3c.dom.Text + +@BindingAdapter("bind_visible_if") +fun setVisibility(textView:TextView, empty:Boolean) { + if (empty) { + textView.visibility = View.VISIBLE + } + else { + textView.visibility = View.GONE + } +} @BindingAdapter("bind_movie_list") fun setMovie(recyclerView: RecyclerView, movies:ArrayList?){ @@ -23,4 +37,11 @@ fun setImage(imageView: ImageView, url:String) { .load(url) .error(R.drawable.ic_launcher_foreground) .into(imageView) +} + +@BindingAdapter("bind_history_list") +fun setHistory(recyclerView: RecyclerView, histories: ArrayList?) { + if (histories != null) { + (recyclerView.adapter as HistoryRecyclerAdapter).setItem(histories) + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/mvvm2/ui/main/MainRecyclerAdapter.kt b/app/src/main/java/com/example/mvvm2/ui/main/MainRecyclerAdapter.kt index 4009d60..6aa3c41 100644 --- a/app/src/main/java/com/example/mvvm2/ui/main/MainRecyclerAdapter.kt +++ b/app/src/main/java/com/example/mvvm2/ui/main/MainRecyclerAdapter.kt @@ -8,8 +8,10 @@ import com.example.mvvm2.data.model.Movie import com.example.mvvm2.databinding.ItemMainBinding import com.example.mvvm2.ui.moive.MovieActivity -class MainRecyclerAdapter ( val movieClickListener: (Movie)->Unit) : RecyclerView.Adapter() { - var movies:ArrayList = arrayListOf() +class MainRecyclerAdapter(val movieClickListener: (Movie) -> Unit) : + RecyclerView.Adapter() { + + var movies: ArrayList = arrayListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = ItemMainBinding.inflate(LayoutInflater.from(parent.context), parent, false) @@ -18,24 +20,23 @@ class MainRecyclerAdapter ( val movieClickListener: (Movie)->Unit) : RecyclerVie override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.bind(movies[position]) - holder.itemView.setOnClickListener{movieClickListener(movies[position])} + holder.itemView.setOnClickListener { movieClickListener(movies[position]) } } override fun getItemCount(): Int { return movies.size } - fun setItem(movies : ArrayList) { + fun setItem(movies: ArrayList) { this.movies.clear() this.movies.addAll(movies) notifyDataSetChanged() } - class ViewHolder(private val binding: ItemMainBinding) :RecyclerView.ViewHolder(binding.root) { - fun bind (movie:Movie) { + class ViewHolder(private val binding: ItemMainBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(movie: Movie) { binding.movie = movie } - } } diff --git a/app/src/main/java/com/example/mvvm2/ui/main/MainViewModel.kt b/app/src/main/java/com/example/mvvm2/ui/main/MainViewModel.kt index c67f559..6c80127 100644 --- a/app/src/main/java/com/example/mvvm2/ui/main/MainViewModel.kt +++ b/app/src/main/java/com/example/mvvm2/ui/main/MainViewModel.kt @@ -1,33 +1,43 @@ package com.example.mvvm2.ui.main +import android.content.Intent import android.util.Log +import android.widget.Toast import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import com.example.mvvm2.App import com.example.mvvm2.data.model.Movie import com.example.mvvm2.data.model.MovieResponse -import com.example.mvvm2.data.repository.BaseRetrofit -import com.example.mvvm2.data.repository.MovieRetrofit +import com.example.mvvm2.data.repository.Repository +import com.example.mvvm2.data.repository.RepositoryImpl +import com.example.mvvm2.data.repository.remote.BaseRetrofit +import com.example.mvvm2.data.repository.remote.MovieRetrofit +import com.example.mvvm2.ui.history.HistoryActivity import retrofit2.Call import retrofit2.Response class MainViewModel :ViewModel() { - var query:String = "Harry potter" + var query:String = "" + var empty:MutableLiveData = MutableLiveData(false) val movieList: MutableLiveData> = MutableLiveData() + val repository: RepositoryImpl = RepositoryImpl() fun getMoveList () { - val api = BaseRetrofit.retrofit.create(MovieRetrofit::class.java).getMovieList(query) - - api.enqueue(object : retrofit2.Callback { + if (query.isNotEmpty()) { + repository.setHistory(query) + } + repository.getMovieList(query).enqueue(object : retrofit2.Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful){ movieList.value = response.body()!!.items + empty.value = movieList.value!!.size == 0 } } override fun onFailure(call: Call, t: Throwable) { + Toast.makeText(App.instance.applicationContext, "검색 도중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show() } } ) - } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml new file mode 100644 index 0000000..b91ad33 --- /dev/null +++ b/app/src/main/res/layout/activity_history.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4e09659..eba5a08 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -27,11 +27,22 @@