Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MVVM2">
<activity
android:name=".ui.history.HistoryActivity"
android:exported="true" />
<activity
android:name=".ui.moive.MovieActivity"
android:exported="true" />
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/com/example/mvvm2/App.kt
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 접근 방식은 좋지 못해요 전역에서 사용하는건데 safe하지 않습니다!
잘 생각해보면 DI로 ViewModel init할때 넣으면 좋을 것 같네요

}
}
35 changes: 35 additions & 0 deletions app/src/main/java/com/example/mvvm2/data/repository/Repository.kt
Original file line number Diff line number Diff line change
@@ -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<MovieResponse>
fun getHistory(): ArrayList<String>?
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<MovieResponse> {
return remoteDataSource.getMovieList(query)
}

override fun getHistory(): ArrayList<String>? {
return localDataSource.getHistory()
}

override fun setHistory(title: String) {
return localDataSource.setHistory(title)
}
}
Original file line number Diff line number Diff line change
@@ -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<String>?
fun setHistory(title:String)
}

class LocalDataSourceImpl():LocalDataSource{
override fun getHistory(): ArrayList<String>? {
return pref.getHistory()
}

override fun setHistory(title: String) {
pref.setHistory(title)
}
}
Original file line number Diff line number Diff line change
@@ -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<String>? {
val history = pref.getString(HISTORY, null)
return Gson().fromJson(history, object : TypeToken<ArrayList<String>>() {}.type)
}

fun setHistory(h: String) {
var history: ArrayList<String>? = if (getHistory().isNullOrEmpty()) arrayListOf() else getHistory()
history!!.add(h)
history = history.distinct() as ArrayList<String>

if (history.size == 6) {
history.removeAt(0)
}
pref.edit().putString(HISTORY, Gson().toJson(history)).apply()
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<MovieResponse>
}

class RemoteDataSourceImpl() : RemoteDataSource {

override fun getMovieList(query: String): Call<MovieResponse> {
return BaseRetrofit.retrofit.create(MovieRetrofit::class.java).getMovieList(query)
}
}
42 changes: 42 additions & 0 deletions app/src/main/java/com/example/mvvm2/ui/history/HistoryActivity.kt
Original file line number Diff line number Diff line change
@@ -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)
}

}
}
Original file line number Diff line number Diff line change
@@ -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<HistoryRecyclerAdapter.ViewHolder>() {

private val histories:ArrayList<String> = 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<String>) {
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
}
}

}
15 changes: 15 additions & 0 deletions app/src/main/java/com/example/mvvm2/ui/history/HistoryViewModel.kt
Original file line number Diff line number Diff line change
@@ -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<ArrayList<String>?> = MutableLiveData()

fun getHistory () {
historyList.value = repository.getHistory()
}
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/example/mvvm2/ui/main/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,6 +27,12 @@ class MainActivity : AppCompatActivity() {
ViewModelProvider.NewInstanceFactory()
)[MainViewModel::class.java]


if (intent.getStringExtra("title") != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스코프 함수를 써서 해보세요!

vm.query = intent.getStringExtra("title").toString()
vm.getMoveList()
}

// binding
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.vm = vm
Expand All @@ -36,5 +43,11 @@ class MainActivity : AppCompatActivity() {
}
startActivity(movieIntent)
}

//History button clickListener
binding.mainHistoryBtn.setOnClickListener{
val historyIntent = Intent(this, HistoryActivity::class.java)
startActivity(historyIntent)
}
}
}
21 changes: 21 additions & 0 deletions app/src/main/java/com/example/mvvm2/ui/main/MainBindingAdapter.kt
Original file line number Diff line number Diff line change
@@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

view 다음에 들어오는 데이터는 nullable하게 받아줘야 합니다!

if (empty) {
textView.visibility = View.VISIBLE
}
else {
textView.visibility = View.GONE
}
Comment on lines +18 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삼항 연산을 쓰는게 더 깔끔할거같아요

}

@BindingAdapter("bind_movie_list")
fun setMovie(recyclerView: RecyclerView, movies:ArrayList<Movie>?){
Expand All @@ -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<String>?) {
if (histories != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 스코프함수!

(recyclerView.adapter as HistoryRecyclerAdapter).setItem(histories)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<MainRecyclerAdapter.ViewHolder>() {
var movies:ArrayList<Movie> = arrayListOf()
class MainRecyclerAdapter(val movieClickListener: (Movie) -> Unit) :
RecyclerView.Adapter<MainRecyclerAdapter.ViewHolder>() {

var movies: ArrayList<Movie> = arrayListOf()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemMainBinding.inflate(LayoutInflater.from(parent.context), parent, false)
Expand All @@ -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]) }
Comment on lines 22 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

binding 내부로 click listener를 넣어서 사용하는게 더 깔끔해보여요!

}

override fun getItemCount(): Int {
return movies.size
}

fun setItem(movies : ArrayList<Movie>) {
fun setItem(movies: ArrayList<Movie>) {
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
}

}

}
Loading