From 1be855a387cde8e6df6347489954ba7f3e761a3a Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Wed, 11 Nov 2020 18:25:21 +0900 Subject: [PATCH 01/24] feature : base code setting --- app/build.gradle | 28 +++++++++++++ .../siba/searchmvvmpractice/MainActivity.kt | 28 ++++++++++++- .../adapter/TabLayoutAdapter.kt | 13 ++++++ .../presentation/SearchFragment.kt | 29 +++++++++++++ .../presentation/SearchUserFragment.kt | 28 +++++++++++++ .../searchmvvmpractice/vm/MainViewModel.kt | 7 ++++ app/src/main/res/layout/activity_main.xml | 42 ++++++++++++------- app/src/main/res/layout/fragment_search.xml | 22 ++++++++++ .../main/res/layout/fragment_search_user.xml | 23 ++++++++++ app/src/main/res/values/strings.xml | 2 + build.gradle | 9 ++++ 11 files changed, 216 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt create mode 100644 app/src/main/res/layout/fragment_search.xml create mode 100644 app/src/main/res/layout/fragment_search_user.xml diff --git a/app/build.gradle b/app/build.gradle index 9f9e574..ac6f666 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,6 +30,12 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures{ + dataBinding = true + } + kotlinOptions{ + jvmTarget = "1.8" + } } dependencies { @@ -39,7 +45,29 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + + // retrofit + implementation 'com.google.code.gson:gson:2.8.5' + implementation 'com.squareup.retrofit2:retrofit:2.6.0' + implementation 'com.squareup.retrofit2:converter-gson:2.6.0' + + // coroutine + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.0' + + // liveData + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' + + // viewModel + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$version_lifecycle" + + // ktx + implementation "androidx.core:core-ktx:1.3.2" + implementation "androidx.fragment:fragment-ktx:1.2.5" + implementation "androidx.activity:activity-ktx:1.1.0" + + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt index c5fd61e..4db3c1a 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt @@ -2,10 +2,36 @@ package com.siba.searchmvvmpractice import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.activity.viewModels +import androidx.databinding.DataBindingUtil +import com.siba.searchmvvmpractice.adapter.TabLayoutAdapter +import com.siba.searchmvvmpractice.databinding.ActivityMainBinding +import com.siba.searchmvvmpractice.presentation.SearchFragment +import com.siba.searchmvvmpractice.presentation.SearchUserFragment +import com.siba.searchmvvmpractice.vm.MainViewModel class MainActivity : AppCompatActivity() { + + private lateinit var binding : ActivityMainBinding + private lateinit var tabAdapter : TabLayoutAdapter + + private val viewModel : MainViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + binding = DataBindingUtil.setContentView(this,R.layout.activity_main) + tabAdapter = TabLayoutAdapter(supportFragmentManager) + tabAdapter.fragments = listOf( + SearchFragment(), + SearchUserFragment() + ) + binding.searchResult.apply { + adapter = tabAdapter + } + binding.searchTab.apply { + setupWithViewPager(binding.searchResult) + getTabAt(0)?.text = "첫 번쨰" + getTabAt(1)?.text = "두 번쨰" + } } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt new file mode 100644 index 0000000..d0a2aae --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt @@ -0,0 +1,13 @@ +package com.siba.searchmvvmpractice.adapter + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter + +class TabLayoutAdapter(fm : FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + + var fragments = listOf() + override fun getCount(): Int = fragments.size + + override fun getItem(position: Int): Fragment = fragments[position] +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt new file mode 100644 index 0000000..ab1cbe4 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt @@ -0,0 +1,29 @@ +package com.siba.searchmvvmpractice.presentation + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.activityViewModels +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.databinding.FragmentSearchBinding +import com.siba.searchmvvmpractice.vm.MainViewModel + +class SearchFragment : Fragment() { + + private lateinit var binding : FragmentSearchBinding + + private val viewModel : MainViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search,container,false) + + return binding.root + } +} diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt new file mode 100644 index 0000000..1d0e177 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt @@ -0,0 +1,28 @@ +package com.siba.searchmvvmpractice.presentation + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.activityViewModels +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding +import com.siba.searchmvvmpractice.vm.MainViewModel + +class SearchUserFragment : Fragment() { + + private lateinit var binding : FragmentSearchUserBinding + + private val viewModel : MainViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_user,container,false) + return binding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt new file mode 100644 index 0000000..3400570 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt @@ -0,0 +1,7 @@ +package com.siba.searchmvvmpractice.vm + +import androidx.lifecycle.ViewModel + +class MainViewModel : ViewModel(){ + +} \ 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 4fc2444..3b7f651 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,18 +1,32 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + - \ No newline at end of file + + + + + + + diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml new file mode 100644 index 0000000..c5c1a77 --- /dev/null +++ b/app/src/main/res/layout/fragment_search.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_search_user.xml b/app/src/main/res/layout/fragment_search_user.xml new file mode 100644 index 0000000..9ffec63 --- /dev/null +++ b/app/src/main/res/layout/fragment_search_user.xml @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 101c85f..235d3d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ SearchMVVMPractice + + Hello blank fragment \ No newline at end of file diff --git a/build.gradle b/build.gradle index 24d1382..461df9b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,15 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext.kotlin_version = "1.4.10" + ext{ + version_kotlin = "1.3.72" + version_core = "1.3.1" + version_constraint_layout = "2.0.0-rc1" + version_lifecycle_extensions = "2.2.0" + version_material = "1.2.0" + version_navigation = "2.3.0" + version_lifecycle = "2.2.0" + } repositories { google() jcenter() From 74815edec6bc424d163eaf29dc916b13f1c21a60 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Wed, 11 Nov 2020 21:50:39 +0900 Subject: [PATCH 02/24] TODO : How to handle Path value in repos :) --- .../siba/searchmvvmpractice/MainActivity.kt | 20 ++++++++-- .../searchmvvmpractice/api/RetrofitBuilder.kt | 18 +++++++++ .../searchmvvmpractice/api/RetrofitHelper.kt | 5 +++ .../searchmvvmpractice/api/RetrofitService.kt | 14 +++++++ .../searchmvvmpractice/data/GithubUserData.kt | 38 +++++++++++++++++++ .../repo/GithubUserRepository.kt | 8 ++++ .../searchmvvmpractice/vm/MainViewModel.kt | 10 +++++ app/src/main/res/layout/activity_main.xml | 9 ++++- app/src/main/res/layout/fragment_search.xml | 6 +-- 9 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitBuilder.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt diff --git a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt index 4db3c1a..16918fc 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt @@ -20,18 +20,30 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this,R.layout.activity_main) + setAdapter() + setViewpager() + setTab() + } + + fun setAdapter(){ tabAdapter = TabLayoutAdapter(supportFragmentManager) tabAdapter.fragments = listOf( - SearchFragment(), - SearchUserFragment() + SearchFragment(), + SearchUserFragment() ) + } + + fun setViewpager(){ binding.searchResult.apply { adapter = tabAdapter } + } + + fun setTab(){ binding.searchTab.apply { setupWithViewPager(binding.searchResult) - getTabAt(0)?.text = "첫 번쨰" - getTabAt(1)?.text = "두 번쨰" + getTabAt(0)?.text = "첫 번째" + getTabAt(1)?.text = "두 번째" } } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitBuilder.kt b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitBuilder.kt new file mode 100644 index 0000000..7ae8ed5 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitBuilder.kt @@ -0,0 +1,18 @@ +package com.siba.searchmvvmpractice.api + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +object RetrofitBuilder { + + private val URL = "https://api.github.com" + + private fun getRetrofit() : Retrofit { + return Retrofit.Builder() + .baseUrl(URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + } + + val retrofitService : RetrofitService = getRetrofit().create(RetrofitService::class.java) +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt new file mode 100644 index 0000000..06f00d5 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt @@ -0,0 +1,5 @@ +package com.siba.searchmvvmpractice.api + +class RetrofitHelper(private val retrofitService: RetrofitService , private val user : String) { + suspend fun getGithubUser() = retrofitService.getUser(user) +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt new file mode 100644 index 0000000..56408a5 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt @@ -0,0 +1,14 @@ +package com.siba.searchmvvmpractice.api + +import com.siba.searchmvvmpractice.data.GithubUserData +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface RetrofitService { + // https://api.github.com/search/SSong-develop + @GET("search/users/{user}") + suspend fun getUser( + @Path("user") user : String + ) : GithubUserData +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt b/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt new file mode 100644 index 0000000..6030e83 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt @@ -0,0 +1,38 @@ +package com.siba.searchmvvmpractice.data + +class GithubUserData( + var login : String, + var id : String, + var node_id : String, + val avatar_url : String, + val gravatar_id : String, + val url : String, + val html_url : String, + val followers_url : String, + val following_url : String, + val gists_url : String, + val starred_url : String, + val subscriptions_url : String, + val organizations_url : String, + val repos_url : String, + val events_url : String, + val received_events_url : String, + val type : String, + val site_admin : Boolean, + val name : String, + val company : String, + val blog : String, + val location : String, + val email : String, + val hireable : String, + val bio : String, + val twitter_username : String, + val public_repos : Int, + val public_gists : Int, + val followers : Int, + val following : Int, + val created_at : String, + val updated_at : String +) { + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt new file mode 100644 index 0000000..c9115c8 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt @@ -0,0 +1,8 @@ +package com.siba.searchmvvmpractice.repo + +import com.siba.searchmvvmpractice.api.RetrofitHelper + +class GithubUserRepository(private val retrofitHelper: RetrofitHelper) { + + suspend fun getGithubUser() = retrofitHelper.getGithubUser() +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt index 3400570..18a6a63 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt @@ -1,7 +1,17 @@ package com.siba.searchmvvmpractice.vm +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class MainViewModel : ViewModel(){ + private val _userName = MutableLiveData() + val userName : MutableLiveData + get() = _userName + + // TODO : How to handle Path Value in repository + fun getName() : LiveData{ + return userName + } } \ 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 3b7f651..e2b58b6 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,7 +3,14 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> - + + + + From 56934c211587a3ec8312066f8be3bc0537f0fe68 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 13 Nov 2020 01:55:04 +0900 Subject: [PATCH 03/24] feature #1 : UserSearch done :) --- app/src/main/AndroidManifest.xml | 2 ++ .../siba/searchmvvmpractice/MainActivity.kt | 25 +++++++++++++++++ .../searchmvvmpractice/api/RetrofitService.kt | 5 ++-- .../presentation/SearchUserFragment.kt | 17 ++++++++++- .../searchmvvmpractice/vm/MainViewModel.kt | 24 ++++++++++++++-- app/src/main/res/layout/fragment_search.xml | 5 ++++ .../main/res/layout/fragment_search_user.xml | 28 +++++++++++++++++-- 7 files changed, 98 insertions(+), 8 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e9c8904..e3bbe8f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + () val userName : MutableLiveData get() = _userName + private val _githubUser = MutableLiveData() + val githubUser : MutableLiveData + get() = _githubUser + + + // TODO : How to handle Path Value in repository - fun getName() : LiveData{ - return userName + fun searchUser() = viewModelScope.launch { + val repo = GithubUserRepository(RetrofitHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) + _githubUser.value = repo.getGithubUser() } - } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index c896400..071ee8b 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -2,6 +2,11 @@ + + + + + + + + + + From 0416b558283782c6b97b72362a9c09a12c9c2f7b Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 13 Nov 2020 02:02:06 +0900 Subject: [PATCH 04/24] TODO #1 --- .../main/java/com/siba/searchmvvmpractice/MainActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt index 53cd0db..f59146d 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt @@ -20,6 +20,10 @@ class MainActivity : AppCompatActivity() { private val viewModel : MainViewModel by viewModels() + // 기능이 다른 것이니까 viewModel도 하나 더 만들어야지 + // TODO : New Branch & New ViewModel + // TODO : MainViewModel name Refactor + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this,R.layout.activity_main) @@ -31,6 +35,7 @@ class MainActivity : AppCompatActivity() { setTab() } + // TODO : Listener divide fun setSearchView(){ binding.searchView.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { From d33aadc27b8c467affdc3ad285a8585f82802917 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 13 Nov 2020 19:40:05 +0900 Subject: [PATCH 05/24] feature #2 : get All User from Github done :) --- app/build.gradle | 5 +-- app/src/main/AndroidManifest.xml | 1 + .../siba/searchmvvmpractice/MainActivity.kt | 19 +++++----- .../searchmvvmpractice/adapter/UserAdapter.kt | 23 ++++++++++++ .../api/GithubUserSearchHelper.kt | 5 +++ .../searchmvvmpractice/api/RetrofitService.kt | 6 ++++ .../data/GithubAllUserData.kt | 5 +++ .../searchmvvmpractice/data/GithubUserData.kt | 2 ++ .../searchmvvmpractice/data/RetrofitData.kt | 28 +++++++++++++++ .../presentation/SearchFragment.kt | 4 +-- .../presentation/SearchUserFragment.kt | 14 ++++---- .../repo/GithubAllUserRepository.kt | 7 ++++ .../util/CustomBindingAdapter.kt | 25 +++++++++++++ .../vm/SearchUserRepoViewModel.kt | 12 +++++++ ...ainViewModel.kt => SearchUserViewModel.kt} | 17 +++++++-- app/src/main/res/layout/activity_main.xml | 4 +-- app/src/main/res/layout/fragment_search.xml | 2 +- .../main/res/layout/fragment_search_user.xml | 35 +++---------------- build.gradle | 2 +- 19 files changed, 160 insertions(+), 56 deletions(-) create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/data/RetrofitData.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt rename app/src/main/java/com/siba/searchmvvmpractice/vm/{MainViewModel.kt => SearchUserViewModel.kt} (60%) diff --git a/app/build.gradle b/app/build.gradle index ac6f666..4f5397c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ plugins { id 'com.android.application' id 'kotlin-android' + id 'kotlin-kapt' } android { @@ -30,8 +31,8 @@ android { kotlinOptions { jvmTarget = '1.8' } - buildFeatures{ - dataBinding = true + dataBinding{ + enabled = true } kotlinOptions{ jvmTarget = "1.8" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e3bbe8f..cb8994f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + () { + class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { + TODO("Not yet implemented") + } + + override fun onBindViewHolder(holder: UserViewHolder, position: Int) { + TODO("Not yet implemented") + } + + override fun getItemCount(): Int { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt b/app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt new file mode 100644 index 0000000..aabd929 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt @@ -0,0 +1,5 @@ +package com.siba.searchmvvmpractice.api + +class GithubUserSearchHelper(private val retrofitService: RetrofitService , private val userName : String) { + suspend fun getGithubAllUser() = retrofitService.getAllUser(userName) +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt index 2a1e704..2af2a50 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt @@ -1,6 +1,7 @@ package com.siba.searchmvvmpractice.api import com.siba.searchmvvmpractice.data.GithubUserData +import com.siba.searchmvvmpractice.data.RetrofitData import okhttp3.Response import retrofit2.Call import retrofit2.http.GET @@ -12,4 +13,9 @@ interface RetrofitService { suspend fun getUser( @Path("user") user : String ) : GithubUserData + + @GET("search/users") + suspend fun getAllUser( + @Query("q") user : String + ) : RetrofitData } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt b/app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt new file mode 100644 index 0000000..6e16393 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt @@ -0,0 +1,5 @@ +package com.siba.searchmvvmpractice.data + +class GithubAllUserData { + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt b/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt index 6030e83..b4e3e0e 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt @@ -1,5 +1,7 @@ package com.siba.searchmvvmpractice.data +import com.google.gson.annotations.SerializedName + class GithubUserData( var login : String, var id : String, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/data/RetrofitData.kt b/app/src/main/java/com/siba/searchmvvmpractice/data/RetrofitData.kt new file mode 100644 index 0000000..435f56c --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/data/RetrofitData.kt @@ -0,0 +1,28 @@ +package com.siba.searchmvvmpractice.data + +data class RetrofitData( + val total_count : Int, + val incomplete_results : Boolean, + val items : List +) +data class Items ( + val login : String, + val id : Int, + val node_id : String, + val avatar_url : String, + val gravatar_id : String, + val url : String, + val html_url : String, + val followers_url : String, + val following_url : String, + val gists_url : String, + val starred_url : String, + val subscriptions_url : String, + val organizations_url : String, + val repos_url : String, + val events_url : String, + val received_events_url : String, + val type : String, + val site_admin : Boolean, + val score : Double +) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt index ab1cbe4..036296c 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt @@ -9,13 +9,13 @@ import androidx.databinding.DataBindingUtil import androidx.fragment.app.activityViewModels import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.FragmentSearchBinding -import com.siba.searchmvvmpractice.vm.MainViewModel +import com.siba.searchmvvmpractice.vm.SearchUserViewModel class SearchFragment : Fragment() { private lateinit var binding : FragmentSearchBinding - private val viewModel : MainViewModel by activityViewModels() + private val viewModel : SearchUserViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt index 31ebef6..6e7574d 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt @@ -1,6 +1,7 @@ package com.siba.searchmvvmpractice.presentation import android.os.Bundle +import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View @@ -10,13 +11,13 @@ import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding -import com.siba.searchmvvmpractice.vm.MainViewModel +import com.siba.searchmvvmpractice.vm.SearchUserViewModel class SearchUserFragment : Fragment() { private lateinit var binding : FragmentSearchUserBinding - private val viewModel : MainViewModel by activityViewModels() + private val viewModel : SearchUserViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -24,7 +25,6 @@ class SearchUserFragment : Fragment() { ): View? { binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_user,container,false) binding.viewModel = viewModel - setObserver() return binding.root } @@ -35,9 +35,11 @@ class SearchUserFragment : Fragment() { fun setObserver(){ binding.viewModel?.githubUser?.observe(viewLifecycleOwner, Observer { - binding.userName.text = it.name - binding.follower.text = it.followers.toString() - binding.following.text = it.following.toString() + // TODO : 어떻게하면 한번에 모든 값을 보여줄 수 있을까 + // One Person Call + }) + binding.viewModel?.githubAllUser?.observe(viewLifecycleOwner, Observer { + Log.i("userFragment",it.items[2].toString()) }) } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt new file mode 100644 index 0000000..8c1cac1 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt @@ -0,0 +1,7 @@ +package com.siba.searchmvvmpractice.repo + +import com.siba.searchmvvmpractice.api.GithubUserSearchHelper + +class GithubAllUserRepository(private val githubUserSearchHelper: GithubUserSearchHelper) { + suspend fun getGithubAllUser() = githubUserSearchHelper.getGithubAllUser() +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt new file mode 100644 index 0000000..777274f --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt @@ -0,0 +1,25 @@ +package com.siba.searchmvvmpractice.util + +import android.widget.SearchView +import androidx.databinding.BindingAdapter +import com.siba.searchmvvmpractice.vm.SearchUserViewModel + +object CustomBindingAdapter { + + @BindingAdapter("setOnQueryTextListener") + @JvmStatic + fun setOnQueryTextListener(searchView: SearchView , searchKey : String) { + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ + override fun onQueryTextSubmit(p0: String?): Boolean { + p0?.let {keyWord -> + + } + return false + } + + override fun onQueryTextChange(p0: String?): Boolean { + return false + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt new file mode 100644 index 0000000..c06a803 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt @@ -0,0 +1,12 @@ +package com.siba.searchmvvmpractice.vm + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class SearchUserRepoViewModel : ViewModel() { + val focus = false + + private val _userName = MutableLiveData() + val userName : MutableLiveData + get() = _userName +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt similarity index 60% rename from app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt rename to app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt index 9c101ad..7642e4c 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/vm/MainViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt @@ -5,10 +5,13 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.siba.searchmvvmpractice.api.GithubUserSearchHelper import com.siba.searchmvvmpractice.api.RetrofitBuilder import com.siba.searchmvvmpractice.api.RetrofitHelper import com.siba.searchmvvmpractice.api.RetrofitService import com.siba.searchmvvmpractice.data.GithubUserData +import com.siba.searchmvvmpractice.data.RetrofitData +import com.siba.searchmvvmpractice.repo.GithubAllUserRepository import com.siba.searchmvvmpractice.repo.GithubUserRepository import kotlinx.coroutines.launch import retrofit2.Call @@ -16,7 +19,7 @@ import retrofit2.Callback import retrofit2.Response import retrofit2.Retrofit -class MainViewModel : ViewModel(){ +class SearchUserViewModel : ViewModel(){ private val _userName = MutableLiveData() val userName : MutableLiveData get() = _userName @@ -25,11 +28,21 @@ class MainViewModel : ViewModel(){ val githubUser : MutableLiveData get() = _githubUser + private val _githubAllUser = MutableLiveData() + val githubAllUser : MutableLiveData + get() = _githubAllUser + // Repository ViewModel에서 생성 // TODO : How to handle Path Value in repository - fun searchUser() = viewModelScope.launch { + // TODO : Error Exception 처리하기 + fun searchUser() = viewModelScope.launch { val repo = GithubUserRepository(RetrofitHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) _githubUser.value = repo.getGithubUser() } + + fun searchAllUser() = viewModelScope.launch { + val repo = GithubAllUserRepository(GithubUserSearchHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) + _githubAllUser.value = repo.getGithubAllUser() + } } \ 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 e2b58b6..b3dc30f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,7 @@ + type="com.siba.searchmvvmpractice.vm.SearchUserViewModel" /> @@ -21,7 +21,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent"/> + type="com.siba.searchmvvmpractice.vm.SearchUserViewModel" /> + type="com.siba.searchmvvmpractice.vm.SearchUserViewModel" /> - - - - - - + diff --git a/build.gradle b/build.gradle index 461df9b..af2762b 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ buildscript { jcenter() } dependencies { - classpath "com.android.tools.build:gradle:4.1.0" + classpath 'com.android.tools.build:gradle:4.1.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong From 82cf42a0cc3746d2c8a4c02934107772cd0f934e Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 13 Nov 2020 20:42:48 +0900 Subject: [PATCH 06/24] TODO : TODO Something --- .../searchmvvmpractice/adapter/UserAdapter.kt | 31 +++++++++++------ .../presentation/SearchUserFragment.kt | 13 +++++++ app/src/main/res/layout/user_item.xml | 34 +++++++++++++++++++ 3 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 app/src/main/res/layout/user_item.xml diff --git a/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt index 70e9ffb..d274e63 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt @@ -1,23 +1,34 @@ package com.siba.searchmvvmpractice.adapter +import android.service.autofill.UserData +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding import androidx.recyclerview.widget.RecyclerView +import com.siba.searchmvvmpractice.BR +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.data.Items +import com.siba.searchmvvmpractice.databinding.UserItemBinding -class UserAdapter : RecyclerView.Adapter() { - class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { +class UserAdapter : RecyclerView.Adapter.UserViewHolder>() { + var data = mutableListOf() - } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder = + UserViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.user_item,parent,false)) - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { - TODO("Not yet implemented") + override fun onBindViewHolder(holder: UserViewHolder, position: Int) { + holder.bind(data[position]) } - override fun onBindViewHolder(holder: UserViewHolder, position: Int) { - TODO("Not yet implemented") - } + override fun getItemCount(): Int = data.size + + inner class UserViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ + val binding : B = DataBindingUtil.bind(itemView)!! - override fun getItemCount(): Int { - TODO("Not yet implemented") + fun bind(item : Items){ + binding.setVariable(BR.ItemData,item) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt index 6e7574d..2fb76aa 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt @@ -9,8 +9,11 @@ import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.adapter.UserAdapter import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding +import com.siba.searchmvvmpractice.databinding.UserItemBinding import com.siba.searchmvvmpractice.vm.SearchUserViewModel class SearchUserFragment : Fragment() { @@ -18,6 +21,7 @@ class SearchUserFragment : Fragment() { private lateinit var binding : FragmentSearchUserBinding private val viewModel : SearchUserViewModel by activityViewModels() + private lateinit var userAdapter : UserAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -30,7 +34,16 @@ class SearchUserFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding.lifecycleOwner = viewLifecycleOwner + userAdapter = UserAdapter() setObserver() + setAdapter() + } + + private fun setAdapter() { + binding.userRecyclerView.apply { + layoutManager = LinearLayoutManager(requireContext()) + adapter = userAdapter + } } fun setObserver(){ diff --git a/app/src/main/res/layout/user_item.xml b/app/src/main/res/layout/user_item.xml new file mode 100644 index 0000000..0a31f7c --- /dev/null +++ b/app/src/main/res/layout/user_item.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + From 6d9ff1307db7746136c7a19738bac676efd0a597 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Sat, 14 Nov 2020 12:29:14 +0900 Subject: [PATCH 07/24] feature#2 : get All User done :) --- .../searchmvvmpractice/presentation/SearchUserFragment.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt index 2fb76aa..1c9caa0 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt @@ -12,6 +12,7 @@ import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.adapter.UserAdapter +import com.siba.searchmvvmpractice.data.Items import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding import com.siba.searchmvvmpractice.databinding.UserItemBinding import com.siba.searchmvvmpractice.vm.SearchUserViewModel @@ -52,7 +53,8 @@ class SearchUserFragment : Fragment() { // One Person Call }) binding.viewModel?.githubAllUser?.observe(viewLifecycleOwner, Observer { - Log.i("userFragment",it.items[2].toString()) + userAdapter.data = it.items as MutableList + userAdapter.notifyDataSetChanged() }) } } \ No newline at end of file From cc44c50537261fc847d0a951f5d48b7929fb330a Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Sat, 14 Nov 2020 17:08:23 +0900 Subject: [PATCH 08/24] feature#3 : second Search done :) --- app/build.gradle | 2 - .../siba/searchmvvmpractice/MainActivity.kt | 33 ++++++----- .../searchmvvmpractice/adapter/UserAdapter.kt | 18 +++++- .../data/GithubAllUserData.kt | 5 -- .../presentation/SearchAllUserFragment.kt | 55 +++++++++++++++++++ .../presentation/SearchFragment.kt | 29 ---------- .../presentation/SearchUserFragment.kt | 31 +++-------- .../util/CustomBindingAdapter.kt | 25 --------- .../vm/SearchOneUserViewModel.kt | 27 +++++++++ .../vm/SearchUserRepoViewModel.kt | 12 ---- .../vm/SearchUserViewModel.kt | 12 ---- app/src/main/res/layout/activity_main.xml | 6 +- ...earch.xml => fragment_search_all_user.xml} | 17 ++---- .../main/res/layout/fragment_search_user.xml | 16 ++++-- 14 files changed, 143 insertions(+), 145 deletions(-) delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchAllUserFragment.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt rename app/src/main/res/layout/{fragment_search.xml => fragment_search_all_user.xml} (52%) diff --git a/app/build.gradle b/app/build.gradle index 4f5397c..4e1be6b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -69,6 +69,4 @@ dependencies { implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.fragment:fragment-ktx:1.2.5" implementation "androidx.activity:activity-ktx:1.1.0" - - } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt index 050f406..085ce08 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt @@ -5,11 +5,11 @@ import android.os.Bundle import androidx.activity.viewModels import androidx.databinding.DataBindingUtil import androidx.lifecycle.Observer -import com.google.android.material.tabs.TabLayout import com.siba.searchmvvmpractice.adapter.TabLayoutAdapter import com.siba.searchmvvmpractice.databinding.ActivityMainBinding -import com.siba.searchmvvmpractice.presentation.SearchFragment import com.siba.searchmvvmpractice.presentation.SearchUserFragment +import com.siba.searchmvvmpractice.presentation.SearchAllUserFragment +import com.siba.searchmvvmpractice.vm.SearchOneUserViewModel import com.siba.searchmvvmpractice.vm.SearchUserViewModel class MainActivity : AppCompatActivity() { @@ -18,15 +18,13 @@ class MainActivity : AppCompatActivity() { private lateinit var tabAdapter : TabLayoutAdapter private val viewModel : SearchUserViewModel by viewModels() - - // 기능이 다른 것이니까 viewModel도 하나 더 만들어야지 - // TODO : New Branch & New ViewModel - // TODO : MainViewModel name Refactor - + private val ViewModel : SearchOneUserViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this,R.layout.activity_main) - binding.viewModel = viewModel + binding.searchAllViewModel = viewModel + binding.searchOneViewModel = ViewModel setSearchView() setObserver() setAdapter() @@ -37,7 +35,12 @@ class MainActivity : AppCompatActivity() { fun setSearchView(){ binding.searchView.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { - binding.viewModel?.userName?.value = query!! + if(binding.searchTab.selectedTabPosition == 0){ + binding.searchAllViewModel?.userName?.value = query!! + } + if(binding.searchTab.selectedTabPosition == 1){ + binding.searchOneViewModel?.userName?.value = query!! + } return false } @@ -48,17 +51,19 @@ class MainActivity : AppCompatActivity() { } fun setObserver(){ - binding.viewModel?.userName?.observe(this, Observer { - binding.viewModel?.searchUser() - binding.viewModel?.searchAllUser() + binding.searchAllViewModel?.userName?.observe(this, Observer { + binding.searchAllViewModel?.searchAllUser() + }) + binding.searchOneViewModel?.userName?.observe(this , Observer{ + binding.searchOneViewModel?.searchUser() }) } fun setAdapter(){ tabAdapter = TabLayoutAdapter(supportFragmentManager) tabAdapter.fragments = listOf( - SearchUserFragment(), - SearchFragment() + SearchAllUserFragment(), + SearchUserFragment() ) } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt index d274e63..72ed336 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt @@ -12,9 +12,18 @@ import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.data.Items import com.siba.searchmvvmpractice.databinding.UserItemBinding +// TODO : 코드 이해 , 내 코드가 아님 아직 class UserAdapter : RecyclerView.Adapter.UserViewHolder>() { var data = mutableListOf() + // 이 어댑터는 recyclerView item에 Databinding을 적용한 형태이다 + // 이 예시에서는 user_item.xml파일에 DataBinding을 적용한 형태이기 때문에 + // 제네릭은 UserItemBinding으로 생성되어 이를 사용해 어댑터를 적용한 것이다. + + // onCreateViewHolder function + // 반환형은 ViewHolder를 반환하는데 , 어떤형태로 가공이 된 ViewHolder인지를 알아야 한다. + // 가공의 형태는 ViewHolder(inflate,container,attachroot)를 통해 viewHolder에 user_item이 inflate + // 이후 가공된 viewHolder를 반환함으로써 item이 inflate하도록 한다. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder = UserViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.user_item,parent,false)) @@ -24,10 +33,15 @@ class UserAdapter : RecyclerView.Adapter.Use override fun getItemCount(): Int = data.size + // UserViewHolder 클래스 + // inner class로 구현하였는데 이 클래스를 좀 자세히 보자 + // 첫번째로 제네릭으로 들어가는 UserItemBinding을 통해 ViewDataBinding를 받아준다. + // 예시 어댑터에서는 UserItemBinding에 관한 ViewDataBinding을 제네릭으로 받음으로 데이터바인딩을 사용할 수 있도록합니다. + // - Base Class 할때 기억을 되살리시면 될거 같아요 inner class UserViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ - val binding : B = DataBindingUtil.bind(itemView)!! + val binding : B = DataBindingUtil.bind(itemView)!! // DataBindingUtil를 bind해줌으로 데이터바인딩된 xml를 연결해준다 - fun bind(item : Items){ + fun bind(item : Items){ // 이 바인드는 onBindViewHolder function에서 사용할 bind function , 위에꺼랑 다름 binding.setVariable(BR.ItemData,item) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt b/app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt deleted file mode 100644 index 6e16393..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubAllUserData.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.siba.searchmvvmpractice.data - -class GithubAllUserData { - -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchAllUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchAllUserFragment.kt new file mode 100644 index 0000000..5a3f039 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchAllUserFragment.kt @@ -0,0 +1,55 @@ +package com.siba.searchmvvmpractice.presentation + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.adapter.UserAdapter +import com.siba.searchmvvmpractice.data.Items +import com.siba.searchmvvmpractice.databinding.FragmentSearchAllUserBinding +import com.siba.searchmvvmpractice.databinding.UserItemBinding +import com.siba.searchmvvmpractice.vm.SearchUserViewModel + +class SearchAllUserFragment : Fragment() { + // TODO : Rename it ViewModel name is not match + private lateinit var binding : FragmentSearchAllUserBinding + + private val viewModel : SearchUserViewModel by activityViewModels() + private lateinit var userAdapter : UserAdapter + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_all_user,container,false) + binding.viewModel = viewModel + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + binding.lifecycleOwner = viewLifecycleOwner + userAdapter = UserAdapter() + setObserver() + setAdapter() + } + + private fun setAdapter() { + binding.userRecyclerView.apply { + layoutManager = LinearLayoutManager(requireContext()) + adapter = userAdapter + } + } + + fun setObserver(){ + binding.viewModel?.githubAllUser?.observe(viewLifecycleOwner, Observer { + userAdapter.data = it.items as MutableList + userAdapter.notifyDataSetChanged() + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt deleted file mode 100644 index 036296c..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchFragment.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.siba.searchmvvmpractice.presentation - -import android.os.Bundle -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.databinding.DataBindingUtil -import androidx.fragment.app.activityViewModels -import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.databinding.FragmentSearchBinding -import com.siba.searchmvvmpractice.vm.SearchUserViewModel - -class SearchFragment : Fragment() { - - private lateinit var binding : FragmentSearchBinding - - private val viewModel : SearchUserViewModel by activityViewModels() - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // Inflate the layout for this fragment - binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search,container,false) - - return binding.root - } -} diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt index 1c9caa0..cacd117 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt @@ -1,7 +1,6 @@ package com.siba.searchmvvmpractice.presentation import android.os.Bundle -import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View @@ -9,52 +8,36 @@ import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.adapter.UserAdapter -import com.siba.searchmvvmpractice.data.Items import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding -import com.siba.searchmvvmpractice.databinding.UserItemBinding +import com.siba.searchmvvmpractice.vm.SearchOneUserViewModel import com.siba.searchmvvmpractice.vm.SearchUserViewModel class SearchUserFragment : Fragment() { private lateinit var binding : FragmentSearchUserBinding - private val viewModel : SearchUserViewModel by activityViewModels() - private lateinit var userAdapter : UserAdapter + private val viewModel : SearchOneUserViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { + // Inflate the layout for this fragment binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_user,container,false) binding.viewModel = viewModel + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding.lifecycleOwner = viewLifecycleOwner - userAdapter = UserAdapter() setObserver() - setAdapter() - } - - private fun setAdapter() { - binding.userRecyclerView.apply { - layoutManager = LinearLayoutManager(requireContext()) - adapter = userAdapter - } } - fun setObserver(){ + private fun setObserver() { binding.viewModel?.githubUser?.observe(viewLifecycleOwner, Observer { - // TODO : 어떻게하면 한번에 모든 값을 보여줄 수 있을까 - // One Person Call - }) - binding.viewModel?.githubAllUser?.observe(viewLifecycleOwner, Observer { - userAdapter.data = it.items as MutableList - userAdapter.notifyDataSetChanged() + binding.oneUserText.text = "${it.name} , ${it.company} , ${it.email} , ${it.followers} , ${it.following}" }) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt deleted file mode 100644 index 777274f..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/util/CustomBindingAdapter.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.siba.searchmvvmpractice.util - -import android.widget.SearchView -import androidx.databinding.BindingAdapter -import com.siba.searchmvvmpractice.vm.SearchUserViewModel - -object CustomBindingAdapter { - - @BindingAdapter("setOnQueryTextListener") - @JvmStatic - fun setOnQueryTextListener(searchView: SearchView , searchKey : String) { - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ - override fun onQueryTextSubmit(p0: String?): Boolean { - p0?.let {keyWord -> - - } - return false - } - - override fun onQueryTextChange(p0: String?): Boolean { - return false - } - }) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt new file mode 100644 index 0000000..7055318 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt @@ -0,0 +1,27 @@ +package com.siba.searchmvvmpractice.vm + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.siba.searchmvvmpractice.api.RetrofitBuilder +import com.siba.searchmvvmpractice.api.RetrofitHelper +import com.siba.searchmvvmpractice.data.GithubUserData +import com.siba.searchmvvmpractice.repo.GithubUserRepository +import kotlinx.coroutines.launch + +class SearchOneUserViewModel : ViewModel() { + + private val _userName = MutableLiveData() + val userName : MutableLiveData + get() = _userName + + private val _githubUser = MutableLiveData() + val githubUser : MutableLiveData + get() = _githubUser + + // TODO : ERROR Exception Handle + fun searchUser() = viewModelScope.launch { + val repo = GithubUserRepository(RetrofitHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) + _githubUser.value = repo.getGithubUser() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt deleted file mode 100644 index c06a803..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserRepoViewModel.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.siba.searchmvvmpractice.vm - -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class SearchUserRepoViewModel : ViewModel() { - val focus = false - - private val _userName = MutableLiveData() - val userName : MutableLiveData - get() = _userName -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt index 7642e4c..fae7a2c 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt @@ -24,23 +24,11 @@ class SearchUserViewModel : ViewModel(){ val userName : MutableLiveData get() = _userName - private val _githubUser = MutableLiveData() - val githubUser : MutableLiveData - get() = _githubUser - private val _githubAllUser = MutableLiveData() val githubAllUser : MutableLiveData get() = _githubAllUser - // Repository ViewModel에서 생성 - - // TODO : How to handle Path Value in repository // TODO : Error Exception 처리하기 - fun searchUser() = viewModelScope.launch { - val repo = GithubUserRepository(RetrofitHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) - _githubUser.value = repo.getGithubUser() - } - fun searchAllUser() = viewModelScope.launch { val repo = GithubAllUserRepository(GithubUserSearchHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) _githubAllUser.value = repo.getGithubAllUser() diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b3dc30f..ef9dcc3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,11 +5,11 @@ xmlns:tools="http://schemas.android.com/tools"> + name="searchOneViewModel" + type="com.siba.searchmvvmpractice.vm.SearchOneUserViewModel" /> + tools:context=".presentation.SearchAllUserFragment"> - + diff --git a/app/src/main/res/layout/fragment_search_user.xml b/app/src/main/res/layout/fragment_search_user.xml index 3b561c3..6f1eb78 100644 --- a/app/src/main/res/layout/fragment_search_user.xml +++ b/app/src/main/res/layout/fragment_search_user.xml @@ -5,18 +5,22 @@ + type="com.siba.searchmvvmpractice.vm.SearchOneUserViewModel" /> - + From 2e109e7192092976239856c3ec41088e602cdd07 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Mon, 16 Nov 2020 22:15:17 +0900 Subject: [PATCH 09/24] [UPDATE] : Regroup Package --- README.md | 7 ++ app/build.gradle | 8 +- app/src/main/AndroidManifest.xml | 2 +- .../siba/searchmvvmpractice/MainActivity.kt | 83 ------------------- .../adapter/TabLayoutAdapter.kt | 13 --- .../searchmvvmpractice/adapter/UserAdapter.kt | 48 ----------- .../api/GithubUserSearchHelper.kt | 5 -- .../searchmvvmpractice/api/RetrofitHelper.kt | 5 -- .../{data => model}/GithubUserData.kt | 4 +- .../{data => model}/RetrofitData.kt | 2 +- .../presentation/SearchUserFragment.kt | 43 ---------- .../{api => remote}/RetrofitService.kt | 11 ++- .../{ => remote}/api/RetrofitBuilder.kt | 5 +- .../repo/GithubAllUserRepository.kt | 7 -- .../repo/GithubUserRepository.kt | 8 -- .../repository/MainRepository.kt | 9 ++ .../ui/adapter/UserAdapter.kt | 31 +++++++ .../ui/adapter/ViewPagerAdapter.kt | 20 +++++ .../presentation/activity/SearchActivity.kt | 53 ++++++++++++ .../fragment/SearchRepoFragment.kt | 32 +++++++ .../fragment/SearchUserFragment.kt} | 26 +++--- .../ui/viewmodel/SearchViewModel.kt | 30 +++++++ .../vm/SearchOneUserViewModel.kt | 27 ------ .../vm/SearchUserViewModel.kt | 36 -------- .../main/res/drawable/ic_recent_keyword.xml | 5 ++ ...{activity_main.xml => activity_search.xml} | 21 ++--- .../res/layout/fragment_search_all_user.xml | 22 ----- .../main/res/layout/fragment_search_repo.xml | 26 ++++++ .../main/res/layout/fragment_search_user.xml | 18 ++-- .../main/res/layout/recent_keyword_item.xml | 39 +++++++++ app/src/main/res/layout/user_item.xml | 18 ++-- build.gradle | 1 + 32 files changed, 311 insertions(+), 354 deletions(-) create mode 100644 README.md delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt rename app/src/main/java/com/siba/searchmvvmpractice/{data => model}/GithubUserData.kt (91%) rename app/src/main/java/com/siba/searchmvvmpractice/{data => model}/RetrofitData.kt (94%) delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt rename app/src/main/java/com/siba/searchmvvmpractice/{api => remote}/RetrofitService.kt (58%) rename app/src/main/java/com/siba/searchmvvmpractice/{ => remote}/api/RetrofitBuilder.kt (81%) delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt rename app/src/main/java/com/siba/searchmvvmpractice/{presentation/SearchAllUserFragment.kt => ui/presentation/fragment/SearchUserFragment.kt} (63%) create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt create mode 100644 app/src/main/res/drawable/ic_recent_keyword.xml rename app/src/main/res/layout/{activity_main.xml => activity_search.xml} (62%) delete mode 100644 app/src/main/res/layout/fragment_search_all_user.xml create mode 100644 app/src/main/res/layout/fragment_search_repo.xml create mode 100644 app/src/main/res/layout/recent_keyword_item.xml diff --git a/README.md b/README.md new file mode 100644 index 0000000..aadc7aa --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Search My Profile in Github + +## branch + +### hunki - like develop + +### feature_hunki : using to make feat \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 4e1be6b..c64e4ed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,7 +40,6 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' @@ -69,4 +68,11 @@ dependencies { implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.fragment:fragment-ktx:1.2.5" implementation "androidx.activity:activity-ktx:1.1.0" + + // Room database + implementation "androidx.room:room-runtime:$version_room" + kapt "androidx.room:room-compiler:$version_room" + + // Kotlin Extensions and Coroutines support for Room + implementation "androidx.room:room-ktx:$version_room" } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cb8994f..5b175a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.SearchMVVMPractice"> - + diff --git a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt deleted file mode 100644 index 085ce08..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/MainActivity.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.siba.searchmvvmpractice - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import androidx.activity.viewModels -import androidx.databinding.DataBindingUtil -import androidx.lifecycle.Observer -import com.siba.searchmvvmpractice.adapter.TabLayoutAdapter -import com.siba.searchmvvmpractice.databinding.ActivityMainBinding -import com.siba.searchmvvmpractice.presentation.SearchUserFragment -import com.siba.searchmvvmpractice.presentation.SearchAllUserFragment -import com.siba.searchmvvmpractice.vm.SearchOneUserViewModel -import com.siba.searchmvvmpractice.vm.SearchUserViewModel - -class MainActivity : AppCompatActivity() { - - private lateinit var binding : ActivityMainBinding - private lateinit var tabAdapter : TabLayoutAdapter - - private val viewModel : SearchUserViewModel by viewModels() - private val ViewModel : SearchOneUserViewModel by viewModels() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = DataBindingUtil.setContentView(this,R.layout.activity_main) - binding.searchAllViewModel = viewModel - binding.searchOneViewModel = ViewModel - setSearchView() - setObserver() - setAdapter() - setViewpager() - setTab() - } - - fun setSearchView(){ - binding.searchView.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener{ - override fun onQueryTextSubmit(query: String?): Boolean { - if(binding.searchTab.selectedTabPosition == 0){ - binding.searchAllViewModel?.userName?.value = query!! - } - if(binding.searchTab.selectedTabPosition == 1){ - binding.searchOneViewModel?.userName?.value = query!! - } - return false - } - - override fun onQueryTextChange(newText: String?): Boolean { - return false - } - }) - } - - fun setObserver(){ - binding.searchAllViewModel?.userName?.observe(this, Observer { - binding.searchAllViewModel?.searchAllUser() - }) - binding.searchOneViewModel?.userName?.observe(this , Observer{ - binding.searchOneViewModel?.searchUser() - }) - } - - fun setAdapter(){ - tabAdapter = TabLayoutAdapter(supportFragmentManager) - tabAdapter.fragments = listOf( - SearchAllUserFragment(), - SearchUserFragment() - ) - } - - fun setViewpager(){ - binding.searchResult.apply { - adapter = tabAdapter - } - } - - fun setTab(){ - binding.searchTab.apply { - setupWithViewPager(binding.searchResult) - getTabAt(0)?.text = "유저 검색" - getTabAt(1)?.text = "레포지토리 검색" - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt deleted file mode 100644 index d0a2aae..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/adapter/TabLayoutAdapter.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.siba.searchmvvmpractice.adapter - -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentStatePagerAdapter - -class TabLayoutAdapter(fm : FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - - var fragments = listOf() - override fun getCount(): Int = fragments.size - - override fun getItem(position: Int): Fragment = fragments[position] -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt deleted file mode 100644 index 72ed336..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/adapter/UserAdapter.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.siba.searchmvvmpractice.adapter - -import android.service.autofill.UserData -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.databinding.DataBindingUtil -import androidx.databinding.ViewDataBinding -import androidx.recyclerview.widget.RecyclerView -import com.siba.searchmvvmpractice.BR -import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.data.Items -import com.siba.searchmvvmpractice.databinding.UserItemBinding - -// TODO : 코드 이해 , 내 코드가 아님 아직 -class UserAdapter : RecyclerView.Adapter.UserViewHolder>() { - var data = mutableListOf() - - // 이 어댑터는 recyclerView item에 Databinding을 적용한 형태이다 - // 이 예시에서는 user_item.xml파일에 DataBinding을 적용한 형태이기 때문에 - // 제네릭은 UserItemBinding으로 생성되어 이를 사용해 어댑터를 적용한 것이다. - - // onCreateViewHolder function - // 반환형은 ViewHolder를 반환하는데 , 어떤형태로 가공이 된 ViewHolder인지를 알아야 한다. - // 가공의 형태는 ViewHolder(inflate,container,attachroot)를 통해 viewHolder에 user_item이 inflate - // 이후 가공된 viewHolder를 반환함으로써 item이 inflate하도록 한다. - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder = - UserViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.user_item,parent,false)) - - override fun onBindViewHolder(holder: UserViewHolder, position: Int) { - holder.bind(data[position]) - } - - override fun getItemCount(): Int = data.size - - // UserViewHolder 클래스 - // inner class로 구현하였는데 이 클래스를 좀 자세히 보자 - // 첫번째로 제네릭으로 들어가는 UserItemBinding을 통해 ViewDataBinding를 받아준다. - // 예시 어댑터에서는 UserItemBinding에 관한 ViewDataBinding을 제네릭으로 받음으로 데이터바인딩을 사용할 수 있도록합니다. - // - Base Class 할때 기억을 되살리시면 될거 같아요 - inner class UserViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ - val binding : B = DataBindingUtil.bind(itemView)!! // DataBindingUtil를 bind해줌으로 데이터바인딩된 xml를 연결해준다 - - fun bind(item : Items){ // 이 바인드는 onBindViewHolder function에서 사용할 bind function , 위에꺼랑 다름 - binding.setVariable(BR.ItemData,item) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt b/app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt deleted file mode 100644 index aabd929..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/api/GithubUserSearchHelper.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.siba.searchmvvmpractice.api - -class GithubUserSearchHelper(private val retrofitService: RetrofitService , private val userName : String) { - suspend fun getGithubAllUser() = retrofitService.getAllUser(userName) -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt b/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt deleted file mode 100644 index 06f00d5..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitHelper.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.siba.searchmvvmpractice.api - -class RetrofitHelper(private val retrofitService: RetrofitService , private val user : String) { - suspend fun getGithubUser() = retrofitService.getUser(user) -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt b/app/src/main/java/com/siba/searchmvvmpractice/model/GithubUserData.kt similarity index 91% rename from app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt rename to app/src/main/java/com/siba/searchmvvmpractice/model/GithubUserData.kt index b4e3e0e..5befdc5 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/data/GithubUserData.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/model/GithubUserData.kt @@ -1,6 +1,4 @@ -package com.siba.searchmvvmpractice.data - -import com.google.gson.annotations.SerializedName +package com.siba.searchmvvmpractice.model class GithubUserData( var login : String, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/data/RetrofitData.kt b/app/src/main/java/com/siba/searchmvvmpractice/model/RetrofitData.kt similarity index 94% rename from app/src/main/java/com/siba/searchmvvmpractice/data/RetrofitData.kt rename to app/src/main/java/com/siba/searchmvvmpractice/model/RetrofitData.kt index 435f56c..c84d36d 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/data/RetrofitData.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/model/RetrofitData.kt @@ -1,4 +1,4 @@ -package com.siba.searchmvvmpractice.data +package com.siba.searchmvvmpractice.model data class RetrofitData( val total_count : Int, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt deleted file mode 100644 index cacd117..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchUserFragment.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.siba.searchmvvmpractice.presentation - -import android.os.Bundle -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.databinding.DataBindingUtil -import androidx.fragment.app.activityViewModels -import androidx.lifecycle.Observer -import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding -import com.siba.searchmvvmpractice.vm.SearchOneUserViewModel -import com.siba.searchmvvmpractice.vm.SearchUserViewModel - -class SearchUserFragment : Fragment() { - - private lateinit var binding : FragmentSearchUserBinding - - private val viewModel : SearchOneUserViewModel by activityViewModels() - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // Inflate the layout for this fragment - binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_user,container,false) - binding.viewModel = viewModel - - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - binding.lifecycleOwner = viewLifecycleOwner - setObserver() - } - - private fun setObserver() { - binding.viewModel?.githubUser?.observe(viewLifecycleOwner, Observer { - binding.oneUserText.text = "${it.name} , ${it.company} , ${it.email} , ${it.followers} , ${it.following}" - }) - } -} diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt similarity index 58% rename from app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt rename to app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt index 2af2a50..3af54fd 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt @@ -1,9 +1,7 @@ -package com.siba.searchmvvmpractice.api +package com.siba.searchmvvmpractice.remote -import com.siba.searchmvvmpractice.data.GithubUserData -import com.siba.searchmvvmpractice.data.RetrofitData -import okhttp3.Response -import retrofit2.Call +import com.siba.searchmvvmpractice.model.GithubUserData +import com.siba.searchmvvmpractice.model.RetrofitData import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query @@ -15,7 +13,8 @@ interface RetrofitService { ) : GithubUserData @GET("search/users") - suspend fun getAllUser( + suspend fun getUsers( @Query("q") user : String ) : RetrofitData + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitBuilder.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt similarity index 81% rename from app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitBuilder.kt rename to app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt index 7ae8ed5..8b444ce 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/api/RetrofitBuilder.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt @@ -1,10 +1,10 @@ -package com.siba.searchmvvmpractice.api +package com.siba.searchmvvmpractice.remote.api +import com.siba.searchmvvmpractice.remote.RetrofitService import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory object RetrofitBuilder { - private val URL = "https://api.github.com" private fun getRetrofit() : Retrofit { @@ -15,4 +15,5 @@ object RetrofitBuilder { } val retrofitService : RetrofitService = getRetrofit().create(RetrofitService::class.java) + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt deleted file mode 100644 index 8c1cac1..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubAllUserRepository.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.siba.searchmvvmpractice.repo - -import com.siba.searchmvvmpractice.api.GithubUserSearchHelper - -class GithubAllUserRepository(private val githubUserSearchHelper: GithubUserSearchHelper) { - suspend fun getGithubAllUser() = githubUserSearchHelper.getGithubAllUser() -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt deleted file mode 100644 index c9115c8..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/repo/GithubUserRepository.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.siba.searchmvvmpractice.repo - -import com.siba.searchmvvmpractice.api.RetrofitHelper - -class GithubUserRepository(private val retrofitHelper: RetrofitHelper) { - - suspend fun getGithubUser() = retrofitHelper.getGithubUser() -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt new file mode 100644 index 0000000..3335efa --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt @@ -0,0 +1,9 @@ +package com.siba.searchmvvmpractice.repository + +import com.siba.searchmvvmpractice.remote.api.RetrofitBuilder + +// TODO : Make Offline cache +class MainRepository() { + suspend fun fetchUser(userName : String) = RetrofitBuilder.retrofitService.getUsers(userName) + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt new file mode 100644 index 0000000..3c4db43 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt @@ -0,0 +1,31 @@ +package com.siba.searchmvvmpractice.ui.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.RecyclerView +import com.siba.searchmvvmpractice.BR +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.model.Items +import com.siba.searchmvvmpractice.databinding.UserItemBinding + +class UserAdapter : RecyclerView.Adapter.UserViewHolder>() { + var data = mutableListOf() + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder = + UserViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.user_item,parent,false)) + + override fun onBindViewHolder(holder: UserViewHolder, position: Int) { + holder.bind(data[position]) + } + + override fun getItemCount(): Int = data.size + + inner class UserViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ + val binding : B = DataBindingUtil.bind(itemView)!! + fun bind(item : Items){ + binding.setVariable(BR.ItemData,item) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt new file mode 100644 index 0000000..a31a969 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt @@ -0,0 +1,20 @@ +package com.siba.searchmvvmpractice.ui.adapter + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import com.siba.searchmvvmpractice.ui.presentation.fragment.SearchUserFragment +import com.siba.searchmvvmpractice.ui.presentation.fragment.SearchRepoFragment + +class ViewPagerAdapter(fm : FragmentManager) : + FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + override fun getCount(): Int = 2 + + override fun getItem(position: Int): Fragment { + return when(position){ + 0 -> SearchUserFragment() + else -> SearchRepoFragment() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt new file mode 100644 index 0000000..e63ca93 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -0,0 +1,53 @@ +package com.siba.searchmvvmpractice.ui.presentation.activity + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import androidx.activity.viewModels +import androidx.appcompat.widget.SearchView +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.FragmentManager +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.ui.adapter.ViewPagerAdapter +import com.siba.searchmvvmpractice.databinding.ActivitySearchBinding +import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel + +class SearchActivity : AppCompatActivity() { + + private lateinit var binding : ActivitySearchBinding + private val viewModel : SearchViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView(this, R.layout.activity_search) + binding.searchViewModel = viewModel + binding.lifecycleOwner = this + + setAdapter(supportFragmentManager) + setSearchView(binding.searchviewMain) + } + + fun setSearchView(searchView: SearchView){ + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ + override fun onQueryTextSubmit(query: String?): Boolean { + viewModel.userName.value = query!! + viewModel.searchUser() + return false + } + + override fun onQueryTextChange(newText: String?): Boolean { + return false + } + }) + } + + fun setAdapter(fm : FragmentManager){ + binding.viewpagerMain.apply { + adapter = ViewPagerAdapter(fm) + } + binding.tabMain.apply { + setupWithViewPager(binding.viewpagerMain) + getTabAt(0)?.text = "모든유저검색" + getTabAt(1)?.text = "특정유저검색" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt new file mode 100644 index 0000000..ad0d6cc --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -0,0 +1,32 @@ +package com.siba.searchmvvmpractice.ui.presentation.fragment + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.activityViewModels +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.databinding.FragmentSearchRepoBinding +import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel + +class SearchRepoFragment : Fragment() { + private lateinit var binding : FragmentSearchRepoBinding + + private val viewModel : SearchViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_repo,container,false) + binding.viewModel = viewModel + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + binding.lifecycleOwner = viewLifecycleOwner + } + +} diff --git a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchAllUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt similarity index 63% rename from app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchAllUserFragment.kt rename to app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt index 5a3f039..e4b28b1 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/presentation/SearchAllUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt @@ -1,4 +1,4 @@ -package com.siba.searchmvvmpractice.presentation +package com.siba.searchmvvmpractice.ui.presentation.fragment import android.os.Bundle import androidx.fragment.app.Fragment @@ -7,27 +7,26 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.fragment.app.activityViewModels -import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.adapter.UserAdapter -import com.siba.searchmvvmpractice.data.Items -import com.siba.searchmvvmpractice.databinding.FragmentSearchAllUserBinding +import com.siba.searchmvvmpractice.ui.adapter.UserAdapter +import com.siba.searchmvvmpractice.model.Items +import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding import com.siba.searchmvvmpractice.databinding.UserItemBinding -import com.siba.searchmvvmpractice.vm.SearchUserViewModel +import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel -class SearchAllUserFragment : Fragment() { - // TODO : Rename it ViewModel name is not match - private lateinit var binding : FragmentSearchAllUserBinding +class SearchUserFragment : Fragment() { + private lateinit var binding : FragmentSearchUserBinding - private val viewModel : SearchUserViewModel by activityViewModels() + private val viewModel : SearchViewModel by activityViewModels() private lateinit var userAdapter : UserAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_all_user,container,false) + binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_user,container,false) binding.viewModel = viewModel return binding.root } @@ -43,13 +42,14 @@ class SearchAllUserFragment : Fragment() { binding.userRecyclerView.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = userAdapter + addItemDecoration(DividerItemDecoration(requireContext(),LinearLayoutManager.VERTICAL)) } } fun setObserver(){ - binding.viewModel?.githubAllUser?.observe(viewLifecycleOwner, Observer { + viewModel.githubUser.observe(viewLifecycleOwner){ userAdapter.data = it.items as MutableList userAdapter.notifyDataSetChanged() - }) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt new file mode 100644 index 0000000..afe9cf8 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -0,0 +1,30 @@ +package com.siba.searchmvvmpractice.ui.viewmodel + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.siba.searchmvvmpractice.model.GithubUserData +import com.siba.searchmvvmpractice.model.RetrofitData +import com.siba.searchmvvmpractice.repository.MainRepository +import kotlinx.coroutines.launch + +class SearchViewModel : ViewModel(){ + private val _userName = MutableLiveData() + val userName : MutableLiveData + get() = _userName + + private val _githubUser = MutableLiveData() + val githubUser : MutableLiveData + get() = _githubUser + + private val _githubRepo = MutableLiveData() + val githubRepo : MutableLiveData + get() = _githubRepo + + val repository = MainRepository() + + fun searchUser() = viewModelScope.launch { + githubUser.value = repository.fetchUser(userName.value.toString()) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt deleted file mode 100644 index 7055318..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchOneUserViewModel.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.siba.searchmvvmpractice.vm - -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.siba.searchmvvmpractice.api.RetrofitBuilder -import com.siba.searchmvvmpractice.api.RetrofitHelper -import com.siba.searchmvvmpractice.data.GithubUserData -import com.siba.searchmvvmpractice.repo.GithubUserRepository -import kotlinx.coroutines.launch - -class SearchOneUserViewModel : ViewModel() { - - private val _userName = MutableLiveData() - val userName : MutableLiveData - get() = _userName - - private val _githubUser = MutableLiveData() - val githubUser : MutableLiveData - get() = _githubUser - - // TODO : ERROR Exception Handle - fun searchUser() = viewModelScope.launch { - val repo = GithubUserRepository(RetrofitHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) - _githubUser.value = repo.getGithubUser() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt deleted file mode 100644 index fae7a2c..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/vm/SearchUserViewModel.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.siba.searchmvvmpractice.vm - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.siba.searchmvvmpractice.api.GithubUserSearchHelper -import com.siba.searchmvvmpractice.api.RetrofitBuilder -import com.siba.searchmvvmpractice.api.RetrofitHelper -import com.siba.searchmvvmpractice.api.RetrofitService -import com.siba.searchmvvmpractice.data.GithubUserData -import com.siba.searchmvvmpractice.data.RetrofitData -import com.siba.searchmvvmpractice.repo.GithubAllUserRepository -import com.siba.searchmvvmpractice.repo.GithubUserRepository -import kotlinx.coroutines.launch -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import retrofit2.Retrofit - -class SearchUserViewModel : ViewModel(){ - private val _userName = MutableLiveData() - val userName : MutableLiveData - get() = _userName - - private val _githubAllUser = MutableLiveData() - val githubAllUser : MutableLiveData - get() = _githubAllUser - - // TODO : Error Exception 처리하기 - fun searchAllUser() = viewModelScope.launch { - val repo = GithubAllUserRepository(GithubUserSearchHelper(RetrofitBuilder.retrofitService,_userName.value.toString())) - _githubAllUser.value = repo.getGithubAllUser() - } -} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_recent_keyword.xml b/app/src/main/res/drawable/ic_recent_keyword.xml new file mode 100644 index 0000000..2b4ff02 --- /dev/null +++ b/app/src/main/res/drawable/ic_recent_keyword.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_search.xml similarity index 62% rename from app/src/main/res/layout/activity_main.xml rename to app/src/main/res/layout/activity_search.xml index ef9dcc3..fc11838 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -5,35 +5,32 @@ xmlns:tools="http://schemas.android.com/tools"> - + name="searchViewModel" + type="com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel" /> + tools:context=".ui.presentation.activity.SearchActivity"> + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@+id/searchview_main" /> + app:layout_constraintTop_toBottomOf="@id/tab_main" /> diff --git a/app/src/main/res/layout/fragment_search_all_user.xml b/app/src/main/res/layout/fragment_search_all_user.xml deleted file mode 100644 index 0582b55..0000000 --- a/app/src/main/res/layout/fragment_search_all_user.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_search_repo.xml b/app/src/main/res/layout/fragment_search_repo.xml new file mode 100644 index 0000000..745ada4 --- /dev/null +++ b/app/src/main/res/layout/fragment_search_repo.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_search_user.xml b/app/src/main/res/layout/fragment_search_user.xml index 6f1eb78..889ace0 100644 --- a/app/src/main/res/layout/fragment_search_user.xml +++ b/app/src/main/res/layout/fragment_search_user.xml @@ -5,22 +5,18 @@ + type="com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel" /> + tools:context=".ui.presentation.fragment.SearchUserFragment"> - + diff --git a/app/src/main/res/layout/recent_keyword_item.xml b/app/src/main/res/layout/recent_keyword_item.xml new file mode 100644 index 0000000..a0f66fd --- /dev/null +++ b/app/src/main/res/layout/recent_keyword_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/user_item.xml b/app/src/main/res/layout/user_item.xml index 0a31f7c..09187ac 100644 --- a/app/src/main/res/layout/user_item.xml +++ b/app/src/main/res/layout/user_item.xml @@ -5,30 +5,34 @@ + type="com.siba.searchmvvmpractice.model.Items" /> + + app:layout_constraintTop_toTopOf="parent" /> + + app:layout_constraintTop_toBottomOf="@+id/login" /> diff --git a/build.gradle b/build.gradle index af2762b..73280a7 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ buildscript { version_material = "1.2.0" version_navigation = "2.3.0" version_lifecycle = "2.2.0" + version_room = "2.2.5" } repositories { google() From 8b9c5f30349ed34688799b3675b4f1d38a7ef396 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Tue, 17 Nov 2020 17:12:29 +0900 Subject: [PATCH 10/24] [FEATURE] : Room create ;) --- app/src/main/AndroidManifest.xml | 1 - .../local/dao/SearchTermDao.kt | 20 ++++++++++ .../local/database/SearchTermDatabase.kt | 34 ++++++++++++++++ .../local/entity/RecentSearchTerm.kt | 12 ++++++ .../repository/MainRepository.kt | 9 ----- .../repository/SearchRepository.kt | 25 ++++++++++++ .../ui/base/SearchViewModelFactory.kt | 17 ++++++++ .../presentation/activity/SearchActivity.kt | 29 ++++++++++---- .../fragment/SearchRepoFragment.kt | 2 +- .../ui/viewmodel/SearchViewModel.kt | 13 +++++-- .../searchmvvmpractice/utils/Injection.kt | 26 +++++++++++++ .../main/res/layout/recent_keyword_item.xml | 39 ------------------- 12 files changed, 167 insertions(+), 60 deletions(-) create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/utils/Injection.kt delete mode 100644 app/src/main/res/layout/recent_keyword_item.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5b175a4..0f089cf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,7 +6,6 @@ > +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt new file mode 100644 index 0000000..68750e2 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt @@ -0,0 +1,34 @@ +package com.siba.searchmvvmpractice.local.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import com.siba.searchmvvmpractice.local.dao.SearchTermDao +import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm + +@Database(entities = [RecentSearchTerm::class],version = 1) +abstract class SearchTermDatabase : RoomDatabase(){ + abstract val searchTermDao : SearchTermDao + + companion object{ + @Volatile + private var INSTANCE : SearchTermDatabase? = null + + fun getInstance(context : Context) : SearchTermDatabase{ + synchronized(this){ + var instance = INSTANCE + + if(instance == null){ + instance = Room.databaseBuilder( + context.applicationContext, + SearchTermDatabase::class.java, + "search_keyword_history_database" + ).build() + INSTANCE = instance + } + return instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt new file mode 100644 index 0000000..41d6331 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt @@ -0,0 +1,12 @@ +package com.siba.searchmvvmpractice.local.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "recent_search_term_table") +data class RecentSearchTerm( + @PrimaryKey(autoGenerate = true) + val id : Int, + val keyword : String +) { +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt deleted file mode 100644 index 3335efa..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/MainRepository.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.siba.searchmvvmpractice.repository - -import com.siba.searchmvvmpractice.remote.api.RetrofitBuilder - -// TODO : Make Offline cache -class MainRepository() { - suspend fun fetchUser(userName : String) = RetrofitBuilder.retrofitService.getUsers(userName) - -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt new file mode 100644 index 0000000..1232bc6 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -0,0 +1,25 @@ +package com.siba.searchmvvmpractice.repository + +import android.util.Log +import com.siba.searchmvvmpractice.local.dao.SearchTermDao +import com.siba.searchmvvmpractice.local.database.SearchTermDatabase +import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm +import com.siba.searchmvvmpractice.remote.RetrofitService +import com.siba.searchmvvmpractice.remote.api.RetrofitBuilder +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class SearchRepository( + private val retrofitService: RetrofitService, + private val searchTermDao: SearchTermDao +) { + suspend fun fetchUser(userName : String) = retrofitService.getUsers(userName) + + suspend fun insertKeyword(recentSearchTerm: RecentSearchTerm){ + searchTermDao.insertKeyword(recentSearchTerm) + } + + suspend fun getAllKeyword(){ + searchTermDao.getAllKeyword() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt new file mode 100644 index 0000000..30310da --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt @@ -0,0 +1,17 @@ +package com.siba.searchmvvmpractice.ui.base + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.siba.searchmvvmpractice.repository.SearchRepository +import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel +import java.lang.IllegalArgumentException + +class SearchViewModelFactory(private val repository: SearchRepository) : ViewModelProvider.NewInstanceFactory() { + override fun create(modelClass: Class): T { + if(modelClass.isAssignableFrom(SearchViewModel::class.java)){ + return SearchViewModel(repository) as T + } + throw IllegalArgumentException("Unknown class name") + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index e63ca93..cd7de6f 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -2,35 +2,50 @@ package com.siba.searchmvvmpractice.ui.presentation.activity import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import androidx.activity.viewModels import androidx.appcompat.widget.SearchView import androidx.databinding.DataBindingUtil import androidx.fragment.app.FragmentManager +import androidx.lifecycle.ViewModelProvider import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.ui.adapter.ViewPagerAdapter import com.siba.searchmvvmpractice.databinding.ActivitySearchBinding +import com.siba.searchmvvmpractice.local.database.SearchTermDatabase import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel +import com.siba.searchmvvmpractice.utils.Injection class SearchActivity : AppCompatActivity() { private lateinit var binding : ActivitySearchBinding - private val viewModel : SearchViewModel by viewModels() + private lateinit var viewModel : SearchViewModel + private lateinit var mDatabase : SearchTermDatabase override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_search) + initViews() + initViewModel() + setViewPagerAdapter(supportFragmentManager) + setSearchView(binding.searchviewMain) binding.searchViewModel = viewModel binding.lifecycleOwner = this - setAdapter(supportFragmentManager) - setSearchView(binding.searchviewMain) } + private fun initViewModel() { + viewModel = ViewModelProvider(this,Injection.provideSearchViewModelFactory(this)).get(SearchViewModel::class.java) + } + + private fun initViews() { + mDatabase = SearchTermDatabase.getInstance(this) + } + + fun setSearchView(searchView: SearchView){ searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { viewModel.userName.value = query!! viewModel.searchUser() + viewModel.saveSearchTerm() return false } @@ -40,14 +55,14 @@ class SearchActivity : AppCompatActivity() { }) } - fun setAdapter(fm : FragmentManager){ + fun setViewPagerAdapter(fm : FragmentManager){ binding.viewpagerMain.apply { adapter = ViewPagerAdapter(fm) } binding.tabMain.apply { setupWithViewPager(binding.viewpagerMain) - getTabAt(0)?.text = "모든유저검색" - getTabAt(1)?.text = "특정유저검색" + getTabAt(0)?.text = "User" + getTabAt(1)?.text = "Repository" } } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index ad0d6cc..5040c31 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -28,5 +28,5 @@ class SearchRepoFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding.lifecycleOwner = viewLifecycleOwner } - + } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index afe9cf8..8a31a06 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -3,12 +3,16 @@ package com.siba.searchmvvmpractice.ui.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.model.GithubUserData import com.siba.searchmvvmpractice.model.RetrofitData -import com.siba.searchmvvmpractice.repository.MainRepository +import com.siba.searchmvvmpractice.repository.SearchRepository import kotlinx.coroutines.launch -class SearchViewModel : ViewModel(){ +class SearchViewModel( + private val repository: SearchRepository +) : ViewModel(){ + private val _userName = MutableLiveData() val userName : MutableLiveData get() = _userName @@ -21,10 +25,13 @@ class SearchViewModel : ViewModel(){ val githubRepo : MutableLiveData get() = _githubRepo - val repository = MainRepository() fun searchUser() = viewModelScope.launch { githubUser.value = repository.fetchUser(userName.value.toString()) } + fun saveSearchTerm() = viewModelScope.launch{ + repository.insertKeyword(RecentSearchTerm(0,userName.value.toString())) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/utils/Injection.kt b/app/src/main/java/com/siba/searchmvvmpractice/utils/Injection.kt new file mode 100644 index 0000000..a1222c0 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/utils/Injection.kt @@ -0,0 +1,26 @@ +package com.siba.searchmvvmpractice.utils + +import android.content.Context +import androidx.lifecycle.ViewModelProvider +import com.siba.searchmvvmpractice.local.database.SearchTermDatabase +import com.siba.searchmvvmpractice.remote.RetrofitService +import com.siba.searchmvvmpractice.remote.api.RetrofitBuilder +import com.siba.searchmvvmpractice.repository.SearchRepository +import com.siba.searchmvvmpractice.ui.base.SearchViewModelFactory + +object Injection { + + fun provideRetrofitService() : RetrofitService{ + return RetrofitBuilder.retrofitService + } + + fun provideMainRepository(context : Context) : SearchRepository{ + val database = SearchTermDatabase.getInstance(context) + return SearchRepository(provideRetrofitService(),database.searchTermDao) + } + + fun provideSearchViewModelFactory(context : Context) : ViewModelProvider.Factory{ + return SearchViewModelFactory(provideMainRepository(context)) + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/recent_keyword_item.xml b/app/src/main/res/layout/recent_keyword_item.xml deleted file mode 100644 index a0f66fd..0000000 --- a/app/src/main/res/layout/recent_keyword_item.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file From fe5da29b340f7436fdad94469c0c0e559e3ccb0c Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Tue, 17 Nov 2020 18:10:06 +0900 Subject: [PATCH 11/24] [FEATURE] : Search Repo done :) --- .../searchmvvmpractice/model/ReposData.kt | 12 ++++++ .../remote/RetrofitService.kt | 6 +++ .../repository/SearchRepository.kt | 2 + .../ui/adapter/RepoAdapter.kt | 32 +++++++++++++++ .../ui/adapter/UserAdapter.kt | 2 +- .../presentation/activity/SearchActivity.kt | 2 + .../fragment/SearchRepoFragment.kt | 29 +++++++++++++- .../fragment/SearchUserFragment.kt | 2 +- .../ui/viewmodel/SearchViewModel.kt | 10 ++++- .../main/res/layout/fragment_search_repo.xml | 12 ++---- .../main/res/layout/fragment_search_user.xml | 2 +- app/src/main/res/layout/repo_item.xml | 39 +++++++++++++++++++ app/src/main/res/layout/user_item.xml | 6 +-- 13 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/model/ReposData.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt create mode 100644 app/src/main/res/layout/repo_item.xml diff --git a/app/src/main/java/com/siba/searchmvvmpractice/model/ReposData.kt b/app/src/main/java/com/siba/searchmvvmpractice/model/ReposData.kt new file mode 100644 index 0000000..c2e7c5f --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/model/ReposData.kt @@ -0,0 +1,12 @@ +package com.siba.searchmvvmpractice.model + +data class ReposData ( + val total_count : Int, + val incomplete_results : Boolean, + val items : List +) + +data class ReposItems ( + val full_name : String, + val html_url : String +) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt index 3af54fd..ceb1767 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt @@ -1,6 +1,7 @@ package com.siba.searchmvvmpractice.remote import com.siba.searchmvvmpractice.model.GithubUserData +import com.siba.searchmvvmpractice.model.ReposData import com.siba.searchmvvmpractice.model.RetrofitData import retrofit2.http.GET import retrofit2.http.Path @@ -17,4 +18,9 @@ interface RetrofitService { @Query("q") user : String ) : RetrofitData + @GET("search/repositories") + suspend fun getRepos( + @Query("q") repoName : String + ) : ReposData + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt index 1232bc6..f631e79 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -15,6 +15,8 @@ class SearchRepository( ) { suspend fun fetchUser(userName : String) = retrofitService.getUsers(userName) + suspend fun fetchRepo(repoName : String) = retrofitService.getRepos(repoName) + suspend fun insertKeyword(recentSearchTerm: RecentSearchTerm){ searchTermDao.insertKeyword(recentSearchTerm) } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt new file mode 100644 index 0000000..51b2e41 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt @@ -0,0 +1,32 @@ +package com.siba.searchmvvmpractice.ui.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.databinding.library.baseAdapters.BR +import androidx.recyclerview.widget.RecyclerView +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.databinding.RepoItemBinding +import com.siba.searchmvvmpractice.model.Items +import com.siba.searchmvvmpractice.model.ReposItems + +class RepoAdapter : RecyclerView.Adapter.RepoViewHolder>() { + var data = mutableListOf() + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RepoViewHolder = + RepoViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.repo_item,parent,false)) + + override fun onBindViewHolder(holder: RepoViewHolder, position: Int) { + holder.bind(data[position]) + } + + override fun getItemCount(): Int = data.size + + inner class RepoViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { + val binding : B = DataBindingUtil.bind(itemView)!! + fun bind(reposItem : ReposItems){ + binding.setVariable(BR.repoItem,reposItem) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt index 3c4db43..53cdbcf 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt @@ -24,7 +24,7 @@ class UserAdapter : RecyclerView.Adapter.Use inner class UserViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ val binding : B = DataBindingUtil.bind(itemView)!! fun bind(item : Items){ - binding.setVariable(BR.ItemData,item) + binding.setVariable(BR.userItem,item) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index cd7de6f..1ec0a6f 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -26,6 +26,7 @@ class SearchActivity : AppCompatActivity() { initViewModel() setViewPagerAdapter(supportFragmentManager) setSearchView(binding.searchviewMain) + binding.searchViewModel = viewModel binding.lifecycleOwner = this @@ -45,6 +46,7 @@ class SearchActivity : AppCompatActivity() { override fun onQueryTextSubmit(query: String?): Boolean { viewModel.userName.value = query!! viewModel.searchUser() + viewModel.searchRepo() viewModel.saveSearchTerm() return false } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index 5040c31..1429caa 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -7,14 +7,21 @@ import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.FragmentSearchRepoBinding +import com.siba.searchmvvmpractice.databinding.RepoItemBinding +import com.siba.searchmvvmpractice.model.Items +import com.siba.searchmvvmpractice.model.ReposItems +import com.siba.searchmvvmpractice.ui.adapter.RepoAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel class SearchRepoFragment : Fragment() { private lateinit var binding : FragmentSearchRepoBinding private val viewModel : SearchViewModel by activityViewModels() + private lateinit var repoAdapter : RepoAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -27,6 +34,26 @@ class SearchRepoFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding.lifecycleOwner = viewLifecycleOwner + repoAdapter = RepoAdapter() + setAdapter() + setObserver() } - + + private fun setObserver() { + viewModel.githubRepo.observe(viewLifecycleOwner){ + repoAdapter.data = it.items as MutableList + repoAdapter.notifyDataSetChanged() + } + } + + private fun setAdapter() { + binding.searchRepoRecyclerview.apply { + layoutManager = LinearLayoutManager(requireContext()) + adapter = repoAdapter + addItemDecoration(DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)) + } + } + + + } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt index e4b28b1..d7e7bb2 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt @@ -39,7 +39,7 @@ class SearchUserFragment : Fragment() { } private fun setAdapter() { - binding.userRecyclerView.apply { + binding.searchUserRecyclerview.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = userAdapter addItemDecoration(DividerItemDecoration(requireContext(),LinearLayoutManager.VERTICAL)) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index 8a31a06..5d1f409 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.model.GithubUserData +import com.siba.searchmvvmpractice.model.ReposData import com.siba.searchmvvmpractice.model.RetrofitData import com.siba.searchmvvmpractice.repository.SearchRepository import kotlinx.coroutines.launch @@ -21,15 +22,20 @@ class SearchViewModel( val githubUser : MutableLiveData get() = _githubUser - private val _githubRepo = MutableLiveData() - val githubRepo : MutableLiveData + private val _githubRepo = MutableLiveData() + val githubRepo : MutableLiveData get() = _githubRepo + var tabPosition : Int = 0 fun searchUser() = viewModelScope.launch { githubUser.value = repository.fetchUser(userName.value.toString()) } + fun searchRepo() = viewModelScope.launch { + githubRepo.value = repository.fetchRepo(userName.value.toString()) + } + fun saveSearchTerm() = viewModelScope.launch{ repository.insertKeyword(RecentSearchTerm(0,userName.value.toString())) } diff --git a/app/src/main/res/layout/fragment_search_repo.xml b/app/src/main/res/layout/fragment_search_repo.xml index 745ada4..146adf1 100644 --- a/app/src/main/res/layout/fragment_search_repo.xml +++ b/app/src/main/res/layout/fragment_search_repo.xml @@ -14,13 +14,9 @@ android:layout_height="match_parent" tools:context=".ui.presentation.fragment.SearchRepoFragment"> - + diff --git a/app/src/main/res/layout/fragment_search_user.xml b/app/src/main/res/layout/fragment_search_user.xml index 889ace0..7eb972e 100644 --- a/app/src/main/res/layout/fragment_search_user.xml +++ b/app/src/main/res/layout/fragment_search_user.xml @@ -15,7 +15,7 @@ tools:context=".ui.presentation.fragment.SearchUserFragment"> diff --git a/app/src/main/res/layout/repo_item.xml b/app/src/main/res/layout/repo_item.xml new file mode 100644 index 0000000..723d3cc --- /dev/null +++ b/app/src/main/res/layout/repo_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/user_item.xml b/app/src/main/res/layout/user_item.xml index 09187ac..7895ebc 100644 --- a/app/src/main/res/layout/user_item.xml +++ b/app/src/main/res/layout/user_item.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> @@ -18,7 +18,7 @@ android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginTop="16dp" - android:text="@{ItemData.login}" + android:text="@{userItem.login}" android:textSize="12sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -29,7 +29,7 @@ android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="16dp" - android:text="@{ItemData.url}" + android:text="@{userItem.url}" android:textSize="12sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="@+id/login" From 75b9cb1c0e003027266ada5968835bbf98f7559b Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Wed, 18 Nov 2020 00:26:34 +0900 Subject: [PATCH 12/24] [TODO] UPDATE :) --- .../local/entity/RecentSearchTerm.kt | 4 +- .../model/SearchTermData.kt | 5 +++ .../repository/SearchRepository.kt | 6 +-- .../ui/adapter/RepoAdapter.kt | 2 +- .../ui/adapter/SearchTermAdapter.kt | 32 ++++++++++++++++ .../presentation/activity/SearchActivity.kt | 27 +++++++++++-- .../fragment/SearchRepoFragment.kt | 2 - .../ui/viewmodel/SearchViewModel.kt | 8 ++-- app/src/main/res/layout/activity_search.xml | 7 +++- app/src/main/res/layout/search_term_item.xml | 38 +++++++++++++++++++ 10 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt create mode 100644 app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt create mode 100644 app/src/main/res/layout/search_term_item.xml diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt index 41d6331..dc5cedc 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt @@ -2,11 +2,11 @@ package com.siba.searchmvvmpractice.local.entity import androidx.room.Entity import androidx.room.PrimaryKey +import com.siba.searchmvvmpractice.model.SearchTermData @Entity(tableName = "recent_search_term_table") data class RecentSearchTerm( @PrimaryKey(autoGenerate = true) val id : Int, val keyword : String -) { -} \ No newline at end of file +) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt b/app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt new file mode 100644 index 0000000..a401736 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt @@ -0,0 +1,5 @@ +package com.siba.searchmvvmpractice.model + +data class SearchTermData( + val searchTerm : String +) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt index f631e79..4d6d4c5 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -1,9 +1,12 @@ package com.siba.searchmvvmpractice.repository import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import com.siba.searchmvvmpractice.local.dao.SearchTermDao import com.siba.searchmvvmpractice.local.database.SearchTermDatabase import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm +import com.siba.searchmvvmpractice.model.SearchTermData import com.siba.searchmvvmpractice.remote.RetrofitService import com.siba.searchmvvmpractice.remote.api.RetrofitBuilder import kotlinx.coroutines.Dispatchers @@ -21,7 +24,4 @@ class SearchRepository( searchTermDao.insertKeyword(recentSearchTerm) } - suspend fun getAllKeyword(){ - searchTermDao.getAllKeyword() - } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt index 51b2e41..02c4442 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt @@ -4,8 +4,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil -import androidx.databinding.library.baseAdapters.BR import androidx.recyclerview.widget.RecyclerView +import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.RepoItemBinding import com.siba.searchmvvmpractice.model.Items diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt new file mode 100644 index 0000000..8314928 --- /dev/null +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt @@ -0,0 +1,32 @@ +package com.siba.searchmvvmpractice.ui.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.RecyclerView +import com.siba.searchmvvmpractice.BR +import com.siba.searchmvvmpractice.R +import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding +import com.siba.searchmvvmpractice.model.ReposItems +import com.siba.searchmvvmpractice.model.SearchTermData + +class SearchTermAdapter : RecyclerView.Adapter.SearchTermViewHolder>() { + var data = mutableListOf() + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchTermViewHolder = + SearchTermViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.search_term_item,parent,false)) + + override fun onBindViewHolder(holder: SearchTermViewHolder, position: Int) { + holder.bind(data[position]) + } + + override fun getItemCount(): Int = data.size + + inner class SearchTermViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { + val binding : B = DataBindingUtil.bind(itemView)!! + fun bind(searchTermData: SearchTermData){ + binding.setVariable(BR.searchTerm,searchTermData) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index 1ec0a6f..3aed13a 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -5,11 +5,18 @@ import android.os.Bundle import androidx.appcompat.widget.SearchView import androidx.databinding.DataBindingUtil import androidx.fragment.app.FragmentManager +import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.ui.adapter.ViewPagerAdapter import com.siba.searchmvvmpractice.databinding.ActivitySearchBinding +import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding import com.siba.searchmvvmpractice.local.database.SearchTermDatabase +import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm +import com.siba.searchmvvmpractice.model.SearchTermData +import com.siba.searchmvvmpractice.ui.adapter.SearchTermAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel import com.siba.searchmvvmpractice.utils.Injection @@ -18,29 +25,40 @@ class SearchActivity : AppCompatActivity() { private lateinit var binding : ActivitySearchBinding private lateinit var viewModel : SearchViewModel private lateinit var mDatabase : SearchTermDatabase - + + private lateinit var searchTermAdapter : SearchTermAdapter + + // TODO : 검색어 recyclerview dataclass 변경 , Database entity와 동일하게 생성 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_search) - initViews() initViewModel() + initViews() setViewPagerAdapter(supportFragmentManager) setSearchView(binding.searchviewMain) - + setSearchTermRecyclerView() binding.searchViewModel = viewModel binding.lifecycleOwner = this } + private fun setSearchTermRecyclerView() { + binding.searchTermRecyclerviewMain.apply { + adapter = searchTermAdapter + layoutManager = LinearLayoutManager(this@SearchActivity) + addItemDecoration(DividerItemDecoration(this@SearchActivity, LinearLayoutManager.VERTICAL)) + } + } + private fun initViewModel() { viewModel = ViewModelProvider(this,Injection.provideSearchViewModelFactory(this)).get(SearchViewModel::class.java) } private fun initViews() { mDatabase = SearchTermDatabase.getInstance(this) + searchTermAdapter = SearchTermAdapter() } - fun setSearchView(searchView: SearchView){ searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ override fun onQueryTextSubmit(query: String?): Boolean { @@ -67,4 +85,5 @@ class SearchActivity : AppCompatActivity() { getTabAt(1)?.text = "Repository" } } + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index 1429caa..01c89fd 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -54,6 +54,4 @@ class SearchRepoFragment : Fragment() { } } - - } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index 5d1f409..c1efc48 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -1,12 +1,12 @@ package com.siba.searchmvvmpractice.ui.viewmodel -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import android.view.animation.Transformation +import androidx.lifecycle.* import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.model.GithubUserData import com.siba.searchmvvmpractice.model.ReposData import com.siba.searchmvvmpractice.model.RetrofitData +import com.siba.searchmvvmpractice.model.SearchTermData import com.siba.searchmvvmpractice.repository.SearchRepository import kotlinx.coroutines.launch @@ -26,8 +26,6 @@ class SearchViewModel( val githubRepo : MutableLiveData get() = _githubRepo - var tabPosition : Int = 0 - fun searchUser() = viewModelScope.launch { githubUser.value = repository.fetchUser(userName.value.toString()) } diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index fc11838..093a73f 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -20,11 +20,16 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + app:layout_constraintTop_toBottomOf="@+id/search_term_recyclerview_main" /> + + + + + + + + + + + + + + \ No newline at end of file From 08127fc53ff8a37a0d254f178fc6dd34e4294140 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Thu, 19 Nov 2020 18:50:01 +0900 Subject: [PATCH 13/24] [FEATURE] RecentSearchTerm Done :) --- .../local/dao/SearchTermDao.kt | 9 ++---- .../local/database/SearchTermDatabase.kt | 2 +- .../local/entity/RecentSearchTerm.kt | 3 +- .../repository/SearchRepository.kt | 4 ++- .../ui/adapter/SearchTermAdapter.kt | 13 +++++++-- .../presentation/activity/SearchActivity.kt | 29 +++++++++---------- .../ui/viewmodel/SearchViewModel.kt | 18 ++++++++---- app/src/main/res/drawable/ic_delete.xml | 5 ++++ app/src/main/res/layout/activity_search.xml | 5 +++- app/src/main/res/layout/search_term_item.xml | 13 +++++++-- 10 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 app/src/main/res/drawable/ic_delete.xml diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt index c8459e7..5c4856b 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt @@ -1,19 +1,16 @@ package com.siba.searchmvvmpractice.local.dao import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.Query +import androidx.room.* import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm @Dao interface SearchTermDao { - @Insert + @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertKeyword(recentSearchTerm: RecentSearchTerm) @Query("DELETE FROM recent_search_term_table") - suspend fun clear() + fun clear() @Query("SELECT * FROM recent_search_term_table") fun getAllKeyword() : LiveData> diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt index 68750e2..4dae89e 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt @@ -23,7 +23,7 @@ abstract class SearchTermDatabase : RoomDatabase(){ instance = Room.databaseBuilder( context.applicationContext, SearchTermDatabase::class.java, - "search_keyword_history_database" + "search_keyword_history_database2" ).build() INSTANCE = instance } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt index dc5cedc..eef5e16 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt @@ -5,8 +5,9 @@ import androidx.room.PrimaryKey import com.siba.searchmvvmpractice.model.SearchTermData @Entity(tableName = "recent_search_term_table") + data class RecentSearchTerm( @PrimaryKey(autoGenerate = true) - val id : Int, + val searchTermId : Int = 0, val keyword : String ) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt index 4d6d4c5..cea816b 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -3,6 +3,7 @@ package com.siba.searchmvvmpractice.repository import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations +import androidx.room.withTransaction import com.siba.searchmvvmpractice.local.dao.SearchTermDao import com.siba.searchmvvmpractice.local.database.SearchTermDatabase import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm @@ -20,8 +21,9 @@ class SearchRepository( suspend fun fetchRepo(repoName : String) = retrofitService.getRepos(repoName) - suspend fun insertKeyword(recentSearchTerm: RecentSearchTerm){ + suspend fun insert(recentSearchTerm: RecentSearchTerm){ searchTermDao.insertKeyword(recentSearchTerm) } + fun getAll() = searchTermDao.getAllKeyword() } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt index 8314928..9399376 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt @@ -4,15 +4,17 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil +import androidx.lifecycle.LiveData import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding +import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.model.ReposItems import com.siba.searchmvvmpractice.model.SearchTermData class SearchTermAdapter : RecyclerView.Adapter.SearchTermViewHolder>() { - var data = mutableListOf() + var data = emptyList() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchTermViewHolder = SearchTermViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.search_term_item,parent,false)) @@ -22,10 +24,15 @@ class SearchTermAdapter : RecyclerView.Adapter){ + this.data = recentSearchTerm + notifyDataSetChanged() + } + inner class SearchTermViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { val binding : B = DataBindingUtil.bind(itemView)!! - fun bind(searchTermData: SearchTermData){ - binding.setVariable(BR.searchTerm,searchTermData) + fun bind(recentSearchTerm: RecentSearchTerm){ + binding.setVariable(BR.searchTerm,recentSearchTerm) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index 3aed13a..35e0585 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -1,11 +1,13 @@ package com.siba.searchmvvmpractice.ui.presentation.activity +import android.opengl.Visibility import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.view.View import androidx.appcompat.widget.SearchView +import androidx.core.view.isVisible import androidx.databinding.DataBindingUtil import androidx.fragment.app.FragmentManager -import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -13,22 +15,17 @@ import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.ui.adapter.ViewPagerAdapter import com.siba.searchmvvmpractice.databinding.ActivitySearchBinding import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding -import com.siba.searchmvvmpractice.local.database.SearchTermDatabase -import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm -import com.siba.searchmvvmpractice.model.SearchTermData import com.siba.searchmvvmpractice.ui.adapter.SearchTermAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel import com.siba.searchmvvmpractice.utils.Injection class SearchActivity : AppCompatActivity() { - private lateinit var binding : ActivitySearchBinding - private lateinit var viewModel : SearchViewModel - private lateinit var mDatabase : SearchTermDatabase + private lateinit var binding: ActivitySearchBinding + private lateinit var viewModel: SearchViewModel - private lateinit var searchTermAdapter : SearchTermAdapter + private lateinit var searchTermAdapter: SearchTermAdapter - // TODO : 검색어 recyclerview dataclass 변경 , Database entity와 동일하게 생성 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_search) @@ -37,7 +34,6 @@ class SearchActivity : AppCompatActivity() { setViewPagerAdapter(supportFragmentManager) setSearchView(binding.searchviewMain) setSearchTermRecyclerView() - binding.searchViewModel = viewModel binding.lifecycleOwner = this } @@ -51,16 +47,19 @@ class SearchActivity : AppCompatActivity() { } private fun initViewModel() { - viewModel = ViewModelProvider(this,Injection.provideSearchViewModelFactory(this)).get(SearchViewModel::class.java) + viewModel = ViewModelProvider(this, Injection.provideSearchViewModelFactory(this)).get(SearchViewModel::class.java) } private fun initViews() { - mDatabase = SearchTermDatabase.getInstance(this) searchTermAdapter = SearchTermAdapter() + viewModel.allSearch.observe(this){ + searchTermAdapter.setData(it) + } + searchTermAdapter.notifyDataSetChanged() } - fun setSearchView(searchView: SearchView){ - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ + fun setSearchView(searchView: SearchView) { + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { viewModel.userName.value = query!! viewModel.searchUser() @@ -75,7 +74,7 @@ class SearchActivity : AppCompatActivity() { }) } - fun setViewPagerAdapter(fm : FragmentManager){ + fun setViewPagerAdapter(fm: FragmentManager) { binding.viewpagerMain.apply { adapter = ViewPagerAdapter(fm) } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index c1efc48..004d7a3 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -1,5 +1,6 @@ package com.siba.searchmvvmpractice.ui.viewmodel +import android.util.Log import android.view.animation.Transformation import androidx.lifecycle.* import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm @@ -8,24 +9,28 @@ import com.siba.searchmvvmpractice.model.ReposData import com.siba.searchmvvmpractice.model.RetrofitData import com.siba.searchmvvmpractice.model.SearchTermData import com.siba.searchmvvmpractice.repository.SearchRepository +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class SearchViewModel( private val repository: SearchRepository -) : ViewModel(){ +) : ViewModel() { private val _userName = MutableLiveData() - val userName : MutableLiveData + val userName: MutableLiveData get() = _userName private val _githubUser = MutableLiveData() - val githubUser : MutableLiveData + val githubUser: MutableLiveData get() = _githubUser private val _githubRepo = MutableLiveData() - val githubRepo : MutableLiveData + val githubRepo: MutableLiveData get() = _githubRepo + var allSearch : LiveData> = repository.getAll() + fun searchUser() = viewModelScope.launch { githubUser.value = repository.fetchUser(userName.value.toString()) } @@ -34,8 +39,9 @@ class SearchViewModel( githubRepo.value = repository.fetchRepo(userName.value.toString()) } - fun saveSearchTerm() = viewModelScope.launch{ - repository.insertKeyword(RecentSearchTerm(0,userName.value.toString())) + fun saveSearchTerm() = viewModelScope.launch(Dispatchers.IO) { + val recentSearchTerm = RecentSearchTerm(keyword = userName.value.toString()) + repository.insert(recentSearchTerm) } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..44be649 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 093a73f..07b011a 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -11,6 +11,7 @@ + type="com.siba.searchmvvmpractice.local.entity.RecentSearchTerm" /> + + \ No newline at end of file From 3440b9fe9782d195ee77d9a221821c609018564c Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Thu, 19 Nov 2020 18:53:09 +0900 Subject: [PATCH 14/24] =?UTF-8?q?[FEATURE]=20=EA=B0=81=EA=B0=80=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=EA=B8=B0=EB=8A=A5=20done=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/presentation/activity/SearchActivity.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index 35e0585..6512ddb 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -62,8 +62,7 @@ class SearchActivity : AppCompatActivity() { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { viewModel.userName.value = query!! - viewModel.searchUser() - viewModel.searchRepo() + search() viewModel.saveSearchTerm() return false } @@ -85,4 +84,10 @@ class SearchActivity : AppCompatActivity() { } } + fun search(){ + if(binding.tabMain.selectedTabPosition == 0) + viewModel.searchUser() + else + viewModel.searchRepo() + } } \ No newline at end of file From 97cef74602baadd0c64504049d213ec5b2b4f243 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Thu, 19 Nov 2020 18:59:49 +0900 Subject: [PATCH 15/24] [REFACT] Package Refactor --- .../{utils => injection}/Injection.kt | 2 +- .../local/entity/RecentSearchTerm.kt | 1 - .../model/GithubUserData.kt | 38 ------------------- .../model/SearchTermData.kt | 5 --- .../remote/RetrofitService.kt | 6 +-- .../{ => remote}/model/ReposData.kt | 2 +- .../{ => remote}/model/RetrofitData.kt | 2 +- .../repository/SearchRepository.kt | 9 ----- .../ui/adapter/RepoAdapter.kt | 3 +- .../ui/adapter/SearchTermAdapter.kt | 3 -- .../ui/adapter/UserAdapter.kt | 2 +- .../presentation/activity/SearchActivity.kt | 23 ++++++----- .../fragment/SearchRepoFragment.kt | 3 +- .../fragment/SearchUserFragment.kt | 2 +- .../ui/viewmodel/SearchViewModel.kt | 9 +---- 15 files changed, 23 insertions(+), 87 deletions(-) rename app/src/main/java/com/siba/searchmvvmpractice/{utils => injection}/Injection.kt (95%) delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/model/GithubUserData.kt delete mode 100644 app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt rename app/src/main/java/com/siba/searchmvvmpractice/{ => remote}/model/ReposData.kt (82%) rename app/src/main/java/com/siba/searchmvvmpractice/{ => remote}/model/RetrofitData.kt (94%) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/utils/Injection.kt b/app/src/main/java/com/siba/searchmvvmpractice/injection/Injection.kt similarity index 95% rename from app/src/main/java/com/siba/searchmvvmpractice/utils/Injection.kt rename to app/src/main/java/com/siba/searchmvvmpractice/injection/Injection.kt index a1222c0..f19d059 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/utils/Injection.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/injection/Injection.kt @@ -1,4 +1,4 @@ -package com.siba.searchmvvmpractice.utils +package com.siba.searchmvvmpractice.injection import android.content.Context import androidx.lifecycle.ViewModelProvider diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt index eef5e16..09d3935 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt @@ -2,7 +2,6 @@ package com.siba.searchmvvmpractice.local.entity import androidx.room.Entity import androidx.room.PrimaryKey -import com.siba.searchmvvmpractice.model.SearchTermData @Entity(tableName = "recent_search_term_table") diff --git a/app/src/main/java/com/siba/searchmvvmpractice/model/GithubUserData.kt b/app/src/main/java/com/siba/searchmvvmpractice/model/GithubUserData.kt deleted file mode 100644 index 5befdc5..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/model/GithubUserData.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.siba.searchmvvmpractice.model - -class GithubUserData( - var login : String, - var id : String, - var node_id : String, - val avatar_url : String, - val gravatar_id : String, - val url : String, - val html_url : String, - val followers_url : String, - val following_url : String, - val gists_url : String, - val starred_url : String, - val subscriptions_url : String, - val organizations_url : String, - val repos_url : String, - val events_url : String, - val received_events_url : String, - val type : String, - val site_admin : Boolean, - val name : String, - val company : String, - val blog : String, - val location : String, - val email : String, - val hireable : String, - val bio : String, - val twitter_username : String, - val public_repos : Int, - val public_gists : Int, - val followers : Int, - val following : Int, - val created_at : String, - val updated_at : String -) { - -} \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt b/app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt deleted file mode 100644 index a401736..0000000 --- a/app/src/main/java/com/siba/searchmvvmpractice/model/SearchTermData.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.siba.searchmvvmpractice.model - -data class SearchTermData( - val searchTerm : String -) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt index ceb1767..0e65819 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt @@ -1,8 +1,8 @@ package com.siba.searchmvvmpractice.remote -import com.siba.searchmvvmpractice.model.GithubUserData -import com.siba.searchmvvmpractice.model.ReposData -import com.siba.searchmvvmpractice.model.RetrofitData +import com.siba.searchmvvmpractice.remote.model.GithubUserData +import com.siba.searchmvvmpractice.remote.model.ReposData +import com.siba.searchmvvmpractice.remote.model.RetrofitData import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query diff --git a/app/src/main/java/com/siba/searchmvvmpractice/model/ReposData.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/ReposData.kt similarity index 82% rename from app/src/main/java/com/siba/searchmvvmpractice/model/ReposData.kt rename to app/src/main/java/com/siba/searchmvvmpractice/remote/model/ReposData.kt index c2e7c5f..1a859cb 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/model/ReposData.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/ReposData.kt @@ -1,4 +1,4 @@ -package com.siba.searchmvvmpractice.model +package com.siba.searchmvvmpractice.remote.model data class ReposData ( val total_count : Int, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/model/RetrofitData.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/RetrofitData.kt similarity index 94% rename from app/src/main/java/com/siba/searchmvvmpractice/model/RetrofitData.kt rename to app/src/main/java/com/siba/searchmvvmpractice/remote/model/RetrofitData.kt index c84d36d..2e14c71 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/model/RetrofitData.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/RetrofitData.kt @@ -1,4 +1,4 @@ -package com.siba.searchmvvmpractice.model +package com.siba.searchmvvmpractice.remote.model data class RetrofitData( val total_count : Int, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt index cea816b..fc919f1 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -1,17 +1,8 @@ package com.siba.searchmvvmpractice.repository -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations -import androidx.room.withTransaction import com.siba.searchmvvmpractice.local.dao.SearchTermDao -import com.siba.searchmvvmpractice.local.database.SearchTermDatabase import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm -import com.siba.searchmvvmpractice.model.SearchTermData import com.siba.searchmvvmpractice.remote.RetrofitService -import com.siba.searchmvvmpractice.remote.api.RetrofitBuilder -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext class SearchRepository( private val retrofitService: RetrofitService, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt index 02c4442..8c8125e 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt @@ -8,8 +8,7 @@ import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.RepoItemBinding -import com.siba.searchmvvmpractice.model.Items -import com.siba.searchmvvmpractice.model.ReposItems +import com.siba.searchmvvmpractice.remote.model.ReposItems class RepoAdapter : RecyclerView.Adapter.RepoViewHolder>() { var data = mutableListOf() diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt index 9399376..54a3cdc 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt @@ -4,14 +4,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil -import androidx.lifecycle.LiveData import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm -import com.siba.searchmvvmpractice.model.ReposItems -import com.siba.searchmvvmpractice.model.SearchTermData class SearchTermAdapter : RecyclerView.Adapter.SearchTermViewHolder>() { var data = emptyList() diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt index 53cdbcf..411cd38 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt @@ -7,7 +7,7 @@ import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.model.Items +import com.siba.searchmvvmpractice.remote.model.Items import com.siba.searchmvvmpractice.databinding.UserItemBinding class UserAdapter : RecyclerView.Adapter.UserViewHolder>() { diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index 6512ddb..06b8e6b 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -1,11 +1,8 @@ package com.siba.searchmvvmpractice.ui.presentation.activity -import android.opengl.Visibility import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.view.View import androidx.appcompat.widget.SearchView -import androidx.core.view.isVisible import androidx.databinding.DataBindingUtil import androidx.fragment.app.FragmentManager import androidx.lifecycle.ViewModelProvider @@ -17,7 +14,7 @@ import com.siba.searchmvvmpractice.databinding.ActivitySearchBinding import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding import com.siba.searchmvvmpractice.ui.adapter.SearchTermAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel -import com.siba.searchmvvmpractice.utils.Injection +import com.siba.searchmvvmpractice.injection.Injection class SearchActivity : AppCompatActivity() { @@ -38,14 +35,6 @@ class SearchActivity : AppCompatActivity() { } - private fun setSearchTermRecyclerView() { - binding.searchTermRecyclerviewMain.apply { - adapter = searchTermAdapter - layoutManager = LinearLayoutManager(this@SearchActivity) - addItemDecoration(DividerItemDecoration(this@SearchActivity, LinearLayoutManager.VERTICAL)) - } - } - private fun initViewModel() { viewModel = ViewModelProvider(this, Injection.provideSearchViewModelFactory(this)).get(SearchViewModel::class.java) } @@ -58,6 +47,15 @@ class SearchActivity : AppCompatActivity() { searchTermAdapter.notifyDataSetChanged() } + private fun setSearchTermRecyclerView() { + binding.searchTermRecyclerviewMain.apply { + adapter = searchTermAdapter + layoutManager = LinearLayoutManager(this@SearchActivity) + addItemDecoration(DividerItemDecoration(this@SearchActivity, LinearLayoutManager.VERTICAL)) + } + } + + fun setSearchView(searchView: SearchView) { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { @@ -90,4 +88,5 @@ class SearchActivity : AppCompatActivity() { else viewModel.searchRepo() } + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index 01c89fd..29bdd2a 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -12,8 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.FragmentSearchRepoBinding import com.siba.searchmvvmpractice.databinding.RepoItemBinding -import com.siba.searchmvvmpractice.model.Items -import com.siba.searchmvvmpractice.model.ReposItems +import com.siba.searchmvvmpractice.remote.model.ReposItems import com.siba.searchmvvmpractice.ui.adapter.RepoAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt index d7e7bb2..fdbf42d 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt @@ -11,7 +11,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.ui.adapter.UserAdapter -import com.siba.searchmvvmpractice.model.Items +import com.siba.searchmvvmpractice.remote.model.Items import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding import com.siba.searchmvvmpractice.databinding.UserItemBinding import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index 004d7a3..c7470b2 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -1,17 +1,12 @@ package com.siba.searchmvvmpractice.ui.viewmodel -import android.util.Log -import android.view.animation.Transformation import androidx.lifecycle.* import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm -import com.siba.searchmvvmpractice.model.GithubUserData -import com.siba.searchmvvmpractice.model.ReposData -import com.siba.searchmvvmpractice.model.RetrofitData -import com.siba.searchmvvmpractice.model.SearchTermData +import com.siba.searchmvvmpractice.remote.model.ReposData +import com.siba.searchmvvmpractice.remote.model.RetrofitData import com.siba.searchmvvmpractice.repository.SearchRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext class SearchViewModel( private val repository: SearchRepository From 207b6cc40a488a2bb3382febd0c6cfa942011f24 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Thu, 19 Nov 2020 19:08:07 +0900 Subject: [PATCH 16/24] [REFACT] delete not using api --- .../com/siba/searchmvvmpractice/remote/RetrofitService.kt | 6 ------ .../ui/presentation/activity/SearchActivity.kt | 4 +++- app/src/main/res/layout/repo_item.xml | 2 +- app/src/main/res/layout/user_item.xml | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt index 0e65819..9c77245 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt @@ -1,6 +1,5 @@ package com.siba.searchmvvmpractice.remote -import com.siba.searchmvvmpractice.remote.model.GithubUserData import com.siba.searchmvvmpractice.remote.model.ReposData import com.siba.searchmvvmpractice.remote.model.RetrofitData import retrofit2.http.GET @@ -8,11 +7,6 @@ import retrofit2.http.Path import retrofit2.http.Query interface RetrofitService { - @GET("users/{user}") - suspend fun getUser( - @Path("user") user : String - ) : GithubUserData - @GET("search/users") suspend fun getUsers( @Query("q") user : String diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index 06b8e6b..8a3075f 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -23,6 +23,9 @@ class SearchActivity : AppCompatActivity() { private lateinit var searchTermAdapter: SearchTermAdapter + // TODO : 1. 최근검색어가 2개씩 저장되는 issue 처리 + // TODO : 2. OFFLINE 캐싱 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_search) @@ -55,7 +58,6 @@ class SearchActivity : AppCompatActivity() { } } - fun setSearchView(searchView: SearchView) { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { diff --git a/app/src/main/res/layout/repo_item.xml b/app/src/main/res/layout/repo_item.xml index 723d3cc..017b497 100644 --- a/app/src/main/res/layout/repo_item.xml +++ b/app/src/main/res/layout/repo_item.xml @@ -6,7 +6,7 @@ + type="com.siba.searchmvvmpractice.remote.model.ReposItems" /> + type="com.siba.searchmvvmpractice.remote.model.Items" /> Date: Fri, 20 Nov 2020 00:53:21 +0900 Subject: [PATCH 17/24] [ERROR] Can't Retrofit --- .../searchmvvmpractice/remote/RetrofitService.kt | 8 ++++---- .../remote/model/{RetrofitData.kt => UserCatalog.kt} | 6 +++--- .../model/{ReposData.kt => UserRepositoryCatalog.kt} | 7 +++---- .../searchmvvmpractice/ui/adapter/RepoAdapter.kt | 8 ++++---- .../searchmvvmpractice/ui/adapter/UserAdapter.kt | 8 ++++---- .../ui/presentation/fragment/SearchRepoFragment.kt | 4 ++-- .../ui/presentation/fragment/SearchUserFragment.kt | 8 +++++--- .../ui/viewmodel/SearchViewModel.kt | 12 ++++++------ app/src/main/res/layout/repo_item.xml | 8 ++++---- app/src/main/res/layout/user_item.xml | 8 ++++---- 10 files changed, 39 insertions(+), 38 deletions(-) rename app/src/main/java/com/siba/searchmvvmpractice/remote/model/{RetrofitData.kt => UserCatalog.kt} (90%) rename app/src/main/java/com/siba/searchmvvmpractice/remote/model/{ReposData.kt => UserRepositoryCatalog.kt} (62%) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt index 9c77245..104f02d 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt @@ -1,7 +1,7 @@ package com.siba.searchmvvmpractice.remote -import com.siba.searchmvvmpractice.remote.model.ReposData -import com.siba.searchmvvmpractice.remote.model.RetrofitData +import com.siba.searchmvvmpractice.remote.model.UserCatalog +import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query @@ -10,11 +10,11 @@ interface RetrofitService { @GET("search/users") suspend fun getUsers( @Query("q") user : String - ) : RetrofitData + ) : UserCatalog @GET("search/repositories") suspend fun getRepos( @Query("q") repoName : String - ) : ReposData + ) : UserRepositoryCatalog } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/RetrofitData.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt similarity index 90% rename from app/src/main/java/com/siba/searchmvvmpractice/remote/model/RetrofitData.kt rename to app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt index 2e14c71..c39de54 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/RetrofitData.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt @@ -1,11 +1,11 @@ package com.siba.searchmvvmpractice.remote.model -data class RetrofitData( +data class UserCatalog( val total_count : Int, val incomplete_results : Boolean, - val items : List + val users : List ) -data class Items ( +data class Users ( val login : String, val id : Int, val node_id : String, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/ReposData.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt similarity index 62% rename from app/src/main/java/com/siba/searchmvvmpractice/remote/model/ReposData.kt rename to app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt index 1a859cb..8031ed6 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/ReposData.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt @@ -1,12 +1,11 @@ package com.siba.searchmvvmpractice.remote.model -data class ReposData ( +data class UserRepositoryCatalog ( val total_count : Int, val incomplete_results : Boolean, - val items : List + val userRepository : List ) - -data class ReposItems ( +data class UserRepository ( val full_name : String, val html_url : String ) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt index 8c8125e..c7f8891 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt @@ -8,10 +8,10 @@ import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.RepoItemBinding -import com.siba.searchmvvmpractice.remote.model.ReposItems +import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog class RepoAdapter : RecyclerView.Adapter.RepoViewHolder>() { - var data = mutableListOf() + var data = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RepoViewHolder = RepoViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.repo_item,parent,false)) @@ -23,8 +23,8 @@ class RepoAdapter : RecyclerView.Adapter.Rep inner class RepoViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { val binding : B = DataBindingUtil.bind(itemView)!! - fun bind(reposItem : ReposItems){ - binding.setVariable(BR.repoItem,reposItem) + fun bind(userRepositoryCatalog : UserRepositoryCatalog){ + binding.setVariable(BR.userRepository,userRepositoryCatalog) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt index 411cd38..9f3b728 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt @@ -7,11 +7,11 @@ import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.remote.model.Items +import com.siba.searchmvvmpractice.remote.model.Users import com.siba.searchmvvmpractice.databinding.UserItemBinding class UserAdapter : RecyclerView.Adapter.UserViewHolder>() { - var data = mutableListOf() + var data = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder = UserViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.user_item,parent,false)) @@ -23,8 +23,8 @@ class UserAdapter : RecyclerView.Adapter.Use inner class UserViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ val binding : B = DataBindingUtil.bind(itemView)!! - fun bind(item : Items){ - binding.setVariable(BR.userItem,item) + fun bind(users : Users){ + binding.setVariable(BR.users,users) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index 29bdd2a..9e0f3f7 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -12,7 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.FragmentSearchRepoBinding import com.siba.searchmvvmpractice.databinding.RepoItemBinding -import com.siba.searchmvvmpractice.remote.model.ReposItems +import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import com.siba.searchmvvmpractice.ui.adapter.RepoAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel @@ -40,7 +40,7 @@ class SearchRepoFragment : Fragment() { private fun setObserver() { viewModel.githubRepo.observe(viewLifecycleOwner){ - repoAdapter.data = it.items as MutableList + repoAdapter.data = it.userRepository as MutableList repoAdapter.notifyDataSetChanged() } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt index fdbf42d..d1d8006 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt @@ -1,6 +1,7 @@ package com.siba.searchmvvmpractice.ui.presentation.fragment import android.os.Bundle +import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View @@ -11,9 +12,9 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.ui.adapter.UserAdapter -import com.siba.searchmvvmpractice.remote.model.Items import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding import com.siba.searchmvvmpractice.databinding.UserItemBinding +import com.siba.searchmvvmpractice.remote.model.Users import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel class SearchUserFragment : Fragment() { @@ -48,8 +49,9 @@ class SearchUserFragment : Fragment() { fun setObserver(){ viewModel.githubUser.observe(viewLifecycleOwner){ - userAdapter.data = it.items as MutableList - userAdapter.notifyDataSetChanged() + Log.i("SearchUserFragment",it.users.toString()) +/* userAdapter.data = it.users as MutableList + userAdapter.notifyDataSetChanged()*/ } } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index c7470b2..af5b7a3 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -2,8 +2,8 @@ package com.siba.searchmvvmpractice.ui.viewmodel import androidx.lifecycle.* import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm -import com.siba.searchmvvmpractice.remote.model.ReposData -import com.siba.searchmvvmpractice.remote.model.RetrofitData +import com.siba.searchmvvmpractice.remote.model.UserCatalog +import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import com.siba.searchmvvmpractice.repository.SearchRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -16,12 +16,12 @@ class SearchViewModel( val userName: MutableLiveData get() = _userName - private val _githubUser = MutableLiveData() - val githubUser: MutableLiveData + private val _githubUser = MutableLiveData() + val githubUser: MutableLiveData get() = _githubUser - private val _githubRepo = MutableLiveData() - val githubRepo: MutableLiveData + private val _githubRepo = MutableLiveData() + val githubRepo: MutableLiveData get() = _githubRepo var allSearch : LiveData> = repository.getAll() diff --git a/app/src/main/res/layout/repo_item.xml b/app/src/main/res/layout/repo_item.xml index 017b497..1668741 100644 --- a/app/src/main/res/layout/repo_item.xml +++ b/app/src/main/res/layout/repo_item.xml @@ -5,8 +5,8 @@ + name="userRepository" + type="com.siba.searchmvvmpractice.remote.model.UserRepository" /> @@ -29,7 +29,7 @@ android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="16dp" - android:text="@{repoItem.html_url}" + android:text="@{userRepository.html_url}" android:textSize="12sp" android:inputType="textUri" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/layout/user_item.xml b/app/src/main/res/layout/user_item.xml index f9225d9..bcf9207 100644 --- a/app/src/main/res/layout/user_item.xml +++ b/app/src/main/res/layout/user_item.xml @@ -4,8 +4,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + name="users" + type="com.siba.searchmvvmpractice.remote.model.Users" /> @@ -29,7 +29,7 @@ android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="16dp" - android:text="@{userItem.url}" + android:text="@{users.url}" android:textSize="12sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="@+id/login" From 5e0a31bdf31c4718de774daff307cc1f4cbfae20 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 20 Nov 2020 01:39:52 +0900 Subject: [PATCH 18/24] :( --- .../com/siba/searchmvvmpractice/remote/RetrofitService.kt | 5 ++--- .../siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt | 2 +- .../siba/searchmvvmpractice/repository/SearchRepository.kt | 6 ++++-- .../ui/presentation/fragment/SearchRepoFragment.kt | 1 + .../ui/presentation/fragment/SearchUserFragment.kt | 5 ++--- .../siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt | 5 +++-- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt index 104f02d..07c9f03 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt @@ -13,8 +13,7 @@ interface RetrofitService { ) : UserCatalog @GET("search/repositories") - suspend fun getRepos( - @Query("q") repoName : String + suspend fun getRepositories( + @Query("q") repositoryName : String ) : UserRepositoryCatalog - } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt index 8b444ce..f6ae631 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt @@ -5,7 +5,7 @@ import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory object RetrofitBuilder { - private val URL = "https://api.github.com" + private const val URL = "https://api.github.com" private fun getRetrofit() : Retrofit { return Retrofit.Builder() diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt index fc919f1..23380f8 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -3,14 +3,16 @@ package com.siba.searchmvvmpractice.repository import com.siba.searchmvvmpractice.local.dao.SearchTermDao import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.remote.RetrofitService +import com.siba.searchmvvmpractice.remote.model.UserCatalog +import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog class SearchRepository( private val retrofitService: RetrofitService, private val searchTermDao: SearchTermDao ) { - suspend fun fetchUser(userName : String) = retrofitService.getUsers(userName) + suspend fun fetchUser(userName : String) : UserCatalog = retrofitService.getUsers(userName) - suspend fun fetchRepo(repoName : String) = retrofitService.getRepos(repoName) + suspend fun fetchRepo(repositoryName : String) : UserRepositoryCatalog = retrofitService.getRepositories(repositoryName) suspend fun insert(recentSearchTerm: RecentSearchTerm){ searchTermDao.insertKeyword(recentSearchTerm) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index 9e0f3f7..38a2474 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -12,6 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.FragmentSearchRepoBinding import com.siba.searchmvvmpractice.databinding.RepoItemBinding +import com.siba.searchmvvmpractice.remote.model.UserRepository import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import com.siba.searchmvvmpractice.ui.adapter.RepoAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt index d1d8006..8512077 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt @@ -49,9 +49,8 @@ class SearchUserFragment : Fragment() { fun setObserver(){ viewModel.githubUser.observe(viewLifecycleOwner){ - Log.i("SearchUserFragment",it.users.toString()) -/* userAdapter.data = it.users as MutableList - userAdapter.notifyDataSetChanged()*/ + userAdapter.data = it.users as MutableList + userAdapter.notifyDataSetChanged() } } } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index af5b7a3..b2743f6 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -1,5 +1,6 @@ package com.siba.searchmvvmpractice.ui.viewmodel +import android.util.Log import androidx.lifecycle.* import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.remote.model.UserCatalog @@ -27,11 +28,11 @@ class SearchViewModel( var allSearch : LiveData> = repository.getAll() fun searchUser() = viewModelScope.launch { - githubUser.value = repository.fetchUser(userName.value.toString()) + _githubUser.value = repository.fetchUser(userName.value.toString()) } fun searchRepo() = viewModelScope.launch { - githubRepo.value = repository.fetchRepo(userName.value.toString()) + _githubRepo.value = repository.fetchRepo(userName.value.toString()) } fun saveSearchTerm() = viewModelScope.launch(Dispatchers.IO) { From 63d7b1189340a7ee3207c023fa347976cfc48fc1 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 20 Nov 2020 02:00:48 +0900 Subject: [PATCH 19/24] [FIX] Data class rename done :) --- .../com/siba/searchmvvmpractice/remote/model/UserCatalog.kt | 3 +++ .../searchmvvmpractice/remote/model/UserRepositoryCatalog.kt | 3 +++ .../com/siba/searchmvvmpractice/repository/SearchRepository.kt | 1 + 3 files changed, 7 insertions(+) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt index c39de54..08ea4de 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt @@ -1,8 +1,11 @@ package com.siba.searchmvvmpractice.remote.model +import com.google.gson.annotations.SerializedName + data class UserCatalog( val total_count : Int, val incomplete_results : Boolean, + @SerializedName("items") val users : List ) data class Users ( diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt index 8031ed6..bcc6681 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt @@ -1,8 +1,11 @@ package com.siba.searchmvvmpractice.remote.model +import com.google.gson.annotations.SerializedName + data class UserRepositoryCatalog ( val total_count : Int, val incomplete_results : Boolean, + @SerializedName("items") val userRepository : List ) data class UserRepository ( diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt index 23380f8..1a9e0cf 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -5,6 +5,7 @@ import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.remote.RetrofitService import com.siba.searchmvvmpractice.remote.model.UserCatalog import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog +import com.siba.searchmvvmpractice.remote.model.Users class SearchRepository( private val retrofitService: RetrofitService, From d12855860a90afdc439890c26ebfe28c86df588a Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 20 Nov 2020 17:13:04 +0900 Subject: [PATCH 20/24] [FIX] Repo Search Error Fix :) --- .../remote/model/UserCatalog.kt | 21 +++++++++++++++++++ .../ui/adapter/RepoAdapter.kt | 7 ++++--- .../fragment/SearchRepoFragment.kt | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt index 08ea4de..e5f32db 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt @@ -3,29 +3,50 @@ package com.siba.searchmvvmpractice.remote.model import com.google.gson.annotations.SerializedName data class UserCatalog( + @SerializedName("total_count") val total_count : Int, + @SerializedName("incomplete_results") val incomplete_results : Boolean, @SerializedName("items") val users : List ) data class Users ( + @SerializedName("login") val login : String, + @SerializedName("id") val id : Int, + @SerializedName("node_id") val node_id : String, + @SerializedName("avatar_url") val avatar_url : String, + @SerializedName("gravatar_id") val gravatar_id : String, + @SerializedName("url") val url : String, + @SerializedName("html_url") val html_url : String, + @SerializedName("followers_url") val followers_url : String, + @SerializedName("following_url") val following_url : String, + @SerializedName("gists_url") val gists_url : String, + @SerializedName("starred_url") val starred_url : String, + @SerializedName("subscriptions_url") val subscriptions_url : String, + @SerializedName("organizations_url") val organizations_url : String, + @SerializedName("repos_url") val repos_url : String, + @SerializedName("events_url") val events_url : String, + @SerializedName("received_events_url") val received_events_url : String, + @SerializedName("type") val type : String, + @SerializedName("site_admin") val site_admin : Boolean, + @SerializedName("score") val score : Double ) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt index c7f8891..22095cb 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt @@ -8,10 +8,11 @@ import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.RepoItemBinding +import com.siba.searchmvvmpractice.remote.model.UserRepository import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog class RepoAdapter : RecyclerView.Adapter.RepoViewHolder>() { - var data = mutableListOf() + var data = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RepoViewHolder = RepoViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.repo_item,parent,false)) @@ -23,8 +24,8 @@ class RepoAdapter : RecyclerView.Adapter.Rep inner class RepoViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { val binding : B = DataBindingUtil.bind(itemView)!! - fun bind(userRepositoryCatalog : UserRepositoryCatalog){ - binding.setVariable(BR.userRepository,userRepositoryCatalog) + fun bind(userRepository : UserRepository){ + binding.setVariable(BR.userRepository,userRepository) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index 38a2474..0039d0b 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -41,7 +41,7 @@ class SearchRepoFragment : Fragment() { private fun setObserver() { viewModel.githubRepo.observe(viewLifecycleOwner){ - repoAdapter.data = it.userRepository as MutableList + repoAdapter.data = it.userRepository as MutableList repoAdapter.notifyDataSetChanged() } } From d5d77f610eb77e7c340a4e618094a80c86243b4f Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 20 Nov 2020 17:45:42 +0900 Subject: [PATCH 21/24] =?UTF-8?q?[TODO]=20Todo=20issue=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=A0=81=EC=96=B4=EB=86=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../remote/model/UserRepositoryCatalog.kt | 4 ++++ .../presentation/activity/SearchActivity.kt | 3 ++- .../fragment/SearchUserFragment.kt | 1 + .../ui/viewmodel/SearchViewModel.kt | 20 +++++++++++++++++-- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt index bcc6681..0a04528 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt @@ -3,12 +3,16 @@ package com.siba.searchmvvmpractice.remote.model import com.google.gson.annotations.SerializedName data class UserRepositoryCatalog ( + @SerializedName("total_count") val total_count : Int, + @SerializedName("incomplete_results") val incomplete_results : Boolean, @SerializedName("items") val userRepository : List ) data class UserRepository ( + @SerializedName("full_name") val full_name : String, + @SerializedName("html_url") val html_url : String ) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index 8a3075f..97ba16f 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -24,7 +24,8 @@ class SearchActivity : AppCompatActivity() { private lateinit var searchTermAdapter: SearchTermAdapter // TODO : 1. 최근검색어가 2개씩 저장되는 issue 처리 - // TODO : 2. OFFLINE 캐싱 + // TODO : 2. 서버에서 데이터가져오는걸 실패할 경우 앱이 죽지 말고 있어야함 , 에러처리 주체도 생각해봐야 할 듯 + // TODO : 3. OFFLINE 캐싱 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt index 8512077..13210de 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt @@ -53,4 +53,5 @@ class SearchUserFragment : Fragment() { userAdapter.notifyDataSetChanged() } } + } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index b2743f6..8793901 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -8,6 +8,8 @@ import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import com.siba.searchmvvmpractice.repository.SearchRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.lang.Exception +import java.lang.NullPointerException class SearchViewModel( private val repository: SearchRepository @@ -28,11 +30,25 @@ class SearchViewModel( var allSearch : LiveData> = repository.getAll() fun searchUser() = viewModelScope.launch { - _githubUser.value = repository.fetchUser(userName.value.toString()) + try { + _githubUser.value = repository.fetchUser(userName.value.toString()) + } catch (e : NullPointerException){ + e.printStackTrace() + } catch (e : InterruptedException){ + e.printStackTrace() + } } fun searchRepo() = viewModelScope.launch { - _githubRepo.value = repository.fetchRepo(userName.value.toString()) + try{ + _githubRepo.value = repository.fetchRepo(userName.value.toString()) + } catch (e : NullPointerException){ + // retry? or offline Caching + e.printStackTrace() + } catch (e : InterruptedException){ + // 쓰레드가 중단되었을 경우 + e.printStackTrace() + } } fun saveSearchTerm() = viewModelScope.launch(Dispatchers.IO) { From f79a554333cee34af59326a8f44148e754307ef3 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Fri, 20 Nov 2020 18:22:42 +0900 Subject: [PATCH 22/24] [UPDATE] Update --- .../com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index 8793901..0a084fc 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -43,10 +43,8 @@ class SearchViewModel( try{ _githubRepo.value = repository.fetchRepo(userName.value.toString()) } catch (e : NullPointerException){ - // retry? or offline Caching e.printStackTrace() } catch (e : InterruptedException){ - // 쓰레드가 중단되었을 경우 e.printStackTrace() } } From 130d577b94da612584966a98d71a3098f789a9c4 Mon Sep 17 00:00:00 2001 From: SSong-develop Date: Sat, 21 Nov 2020 20:54:46 +0900 Subject: [PATCH 23/24] Optimized Package --- .../searchmvvmpractice/injection/Injection.kt | 8 +- .../local/dao/SearchTermDao.kt | 7 +- .../local/database/SearchTermDatabase.kt | 16 ++-- .../local/entity/RecentSearchTerm.kt | 6 +- .../remote/RetrofitService.kt | 9 +- .../remote/api/RetrofitBuilder.kt | 4 +- .../remote/model/UserCatalog.kt | 91 ++++++++++--------- .../remote/model/UserRepositoryCatalog.kt | 15 +-- .../repository/SearchRepository.kt | 11 +-- .../ui/adapter/RepoAdapter.kt | 16 ++-- .../ui/adapter/SearchTermAdapter.kt | 20 ++-- .../ui/adapter/UserAdapter.kt | 17 ++-- .../ui/adapter/ViewPagerAdapter.kt | 8 +- .../ui/base/SearchViewModelFactory.kt | 6 +- .../presentation/activity/SearchActivity.kt | 28 ++++-- .../fragment/SearchRepoFragment.kt | 13 ++- .../fragment/SearchUserFragment.kt | 19 ++-- .../ui/viewmodel/SearchViewModel.kt | 20 ++-- app/src/main/res/layout/user_item.xml | 2 +- 19 files changed, 167 insertions(+), 149 deletions(-) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/injection/Injection.kt b/app/src/main/java/com/siba/searchmvvmpractice/injection/Injection.kt index f19d059..a30e49b 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/injection/Injection.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/injection/Injection.kt @@ -10,16 +10,16 @@ import com.siba.searchmvvmpractice.ui.base.SearchViewModelFactory object Injection { - fun provideRetrofitService() : RetrofitService{ + private fun provideRetrofitService(): RetrofitService { return RetrofitBuilder.retrofitService } - fun provideMainRepository(context : Context) : SearchRepository{ + private fun provideMainRepository(context: Context): SearchRepository { val database = SearchTermDatabase.getInstance(context) - return SearchRepository(provideRetrofitService(),database.searchTermDao) + return SearchRepository(provideRetrofitService(), database.searchTermDao) } - fun provideSearchViewModelFactory(context : Context) : ViewModelProvider.Factory{ + fun provideSearchViewModelFactory(context: Context): ViewModelProvider.Factory { return SearchViewModelFactory(provideMainRepository(context)) } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt index 5c4856b..0e86ef1 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/dao/SearchTermDao.kt @@ -1,7 +1,10 @@ package com.siba.searchmvvmpractice.local.dao import androidx.lifecycle.LiveData -import androidx.room.* +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm @Dao @@ -13,5 +16,5 @@ interface SearchTermDao { fun clear() @Query("SELECT * FROM recent_search_term_table") - fun getAllKeyword() : LiveData> + fun getAllKeyword(): LiveData> } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt index 4dae89e..f7db529 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/database/SearchTermDatabase.kt @@ -7,19 +7,19 @@ import androidx.room.RoomDatabase import com.siba.searchmvvmpractice.local.dao.SearchTermDao import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm -@Database(entities = [RecentSearchTerm::class],version = 1) -abstract class SearchTermDatabase : RoomDatabase(){ - abstract val searchTermDao : SearchTermDao +@Database(entities = [RecentSearchTerm::class], version = 1) +abstract class SearchTermDatabase : RoomDatabase() { + abstract val searchTermDao: SearchTermDao - companion object{ + companion object { @Volatile - private var INSTANCE : SearchTermDatabase? = null + private var INSTANCE: SearchTermDatabase? = null - fun getInstance(context : Context) : SearchTermDatabase{ - synchronized(this){ + fun getInstance(context: Context): SearchTermDatabase { + synchronized(this) { var instance = INSTANCE - if(instance == null){ + if (instance == null) { instance = Room.databaseBuilder( context.applicationContext, SearchTermDatabase::class.java, diff --git a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt index 09d3935..5adb0b7 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/local/entity/RecentSearchTerm.kt @@ -6,7 +6,7 @@ import androidx.room.PrimaryKey @Entity(tableName = "recent_search_term_table") data class RecentSearchTerm( - @PrimaryKey(autoGenerate = true) - val searchTermId : Int = 0, - val keyword : String + @PrimaryKey(autoGenerate = true) + val searchTermId: Int = 0, + val keyword: String ) diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt index 07c9f03..7e34253 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/RetrofitService.kt @@ -3,17 +3,16 @@ package com.siba.searchmvvmpractice.remote import com.siba.searchmvvmpractice.remote.model.UserCatalog import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import retrofit2.http.GET -import retrofit2.http.Path import retrofit2.http.Query interface RetrofitService { @GET("search/users") suspend fun getUsers( - @Query("q") user : String - ) : UserCatalog + @Query("q") user: String + ): UserCatalog @GET("search/repositories") suspend fun getRepositories( - @Query("q") repositoryName : String - ) : UserRepositoryCatalog + @Query("q") repositoryName: String + ): UserRepositoryCatalog } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt index f6ae631..f038053 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/api/RetrofitBuilder.kt @@ -7,13 +7,13 @@ import retrofit2.converter.gson.GsonConverterFactory object RetrofitBuilder { private const val URL = "https://api.github.com" - private fun getRetrofit() : Retrofit { + private fun getRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl(URL) .addConverterFactory(GsonConverterFactory.create()) .build() } - val retrofitService : RetrofitService = getRetrofit().create(RetrofitService::class.java) + val retrofitService: RetrofitService = getRetrofit().create(RetrofitService::class.java) } \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt index e5f32db..d984d5a 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserCatalog.kt @@ -3,50 +3,51 @@ package com.siba.searchmvvmpractice.remote.model import com.google.gson.annotations.SerializedName data class UserCatalog( - @SerializedName("total_count") - val total_count : Int, - @SerializedName("incomplete_results") - val incomplete_results : Boolean, - @SerializedName("items") - val users : List + @SerializedName("total_count") + val total_count: Int, + @SerializedName("incomplete_results") + val incomplete_results: Boolean, + @SerializedName("items") + val users: List ) -data class Users ( - @SerializedName("login") - val login : String, - @SerializedName("id") - val id : Int, - @SerializedName("node_id") - val node_id : String, - @SerializedName("avatar_url") - val avatar_url : String, - @SerializedName("gravatar_id") - val gravatar_id : String, - @SerializedName("url") - val url : String, - @SerializedName("html_url") - val html_url : String, - @SerializedName("followers_url") - val followers_url : String, - @SerializedName("following_url") - val following_url : String, - @SerializedName("gists_url") - val gists_url : String, - @SerializedName("starred_url") - val starred_url : String, - @SerializedName("subscriptions_url") - val subscriptions_url : String, - @SerializedName("organizations_url") - val organizations_url : String, - @SerializedName("repos_url") - val repos_url : String, - @SerializedName("events_url") - val events_url : String, - @SerializedName("received_events_url") - val received_events_url : String, - @SerializedName("type") - val type : String, - @SerializedName("site_admin") - val site_admin : Boolean, - @SerializedName("score") - val score : Double + +data class Users( + @SerializedName("login") + val login: String, + @SerializedName("id") + val id: Int, + @SerializedName("node_id") + val node_id: String, + @SerializedName("avatar_url") + val avatar_url: String, + @SerializedName("gravatar_id") + val gravatar_id: String, + @SerializedName("url") + val url: String, + @SerializedName("html_url") + val html_url: String, + @SerializedName("followers_url") + val followers_url: String, + @SerializedName("following_url") + val following_url: String, + @SerializedName("gists_url") + val gists_url: String, + @SerializedName("starred_url") + val starred_url: String, + @SerializedName("subscriptions_url") + val subscriptions_url: String, + @SerializedName("organizations_url") + val organizations_url: String, + @SerializedName("repos_url") + val repos_url: String, + @SerializedName("events_url") + val events_url: String, + @SerializedName("received_events_url") + val received_events_url: String, + @SerializedName("type") + val type: String, + @SerializedName("site_admin") + val site_admin: Boolean, + @SerializedName("score") + val score: Double ) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt index 0a04528..8114b8e 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/remote/model/UserRepositoryCatalog.kt @@ -2,17 +2,18 @@ package com.siba.searchmvvmpractice.remote.model import com.google.gson.annotations.SerializedName -data class UserRepositoryCatalog ( +data class UserRepositoryCatalog( @SerializedName("total_count") - val total_count : Int, + val total_count: Int, @SerializedName("incomplete_results") - val incomplete_results : Boolean, + val incomplete_results: Boolean, @SerializedName("items") - val userRepository : List + val userRepository: List ) -data class UserRepository ( + +data class UserRepository( @SerializedName("full_name") - val full_name : String, + val full_name: String, @SerializedName("html_url") - val html_url : String + val html_url: String ) \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt index 1a9e0cf..0185cc6 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/repository/SearchRepository.kt @@ -5,17 +5,16 @@ import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.remote.RetrofitService import com.siba.searchmvvmpractice.remote.model.UserCatalog import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog -import com.siba.searchmvvmpractice.remote.model.Users class SearchRepository( - private val retrofitService: RetrofitService, - private val searchTermDao: SearchTermDao + private val retrofitService: RetrofitService, + private val searchTermDao: SearchTermDao ) { - suspend fun fetchUser(userName : String) : UserCatalog = retrofitService.getUsers(userName) + suspend fun fetchUser(userName: String): UserCatalog = retrofitService.getUsers(userName) - suspend fun fetchRepo(repositoryName : String) : UserRepositoryCatalog = retrofitService.getRepositories(repositoryName) + suspend fun fetchRepo(repositoryName: String): UserRepositoryCatalog = retrofitService.getRepositories(repositoryName) - suspend fun insert(recentSearchTerm: RecentSearchTerm){ + suspend fun insert(recentSearchTerm: RecentSearchTerm) { searchTermDao.insertKeyword(recentSearchTerm) } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt index 22095cb..07c765d 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/RepoAdapter.kt @@ -9,12 +9,13 @@ import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.RepoItemBinding import com.siba.searchmvvmpractice.remote.model.UserRepository -import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog class RepoAdapter : RecyclerView.Adapter.RepoViewHolder>() { - var data = mutableListOf() + var data = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RepoViewHolder = - RepoViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.repo_item,parent,false)) + RepoViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.repo_item, parent, false) + ) override fun onBindViewHolder(holder: RepoViewHolder, position: Int) { holder.bind(data[position]) @@ -22,10 +23,11 @@ class RepoAdapter : RecyclerView.Adapter.Rep override fun getItemCount(): Int = data.size - inner class RepoViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { - val binding : B = DataBindingUtil.bind(itemView)!! - fun bind(userRepository : UserRepository){ - binding.setVariable(BR.userRepository,userRepository) + inner class RepoViewHolder(itemView: View) : + RecyclerView.ViewHolder(itemView) { + private val binding: B = DataBindingUtil.bind(itemView)!! + fun bind(userRepository: UserRepository) { + binding.setVariable(BR.userRepository, userRepository) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt index 54a3cdc..78bcc1b 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/SearchTermAdapter.kt @@ -10,10 +10,13 @@ import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm -class SearchTermAdapter : RecyclerView.Adapter.SearchTermViewHolder>() { - var data = emptyList() +class SearchTermAdapter : + RecyclerView.Adapter.SearchTermViewHolder>() { + var data = emptyList() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchTermViewHolder = - SearchTermViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.search_term_item,parent,false)) + SearchTermViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.search_term_item, parent, false) + ) override fun onBindViewHolder(holder: SearchTermViewHolder, position: Int) { holder.bind(data[position]) @@ -21,15 +24,16 @@ class SearchTermAdapter : RecyclerView.Adapter){ + internal fun setData(recentSearchTerm: List) { this.data = recentSearchTerm notifyDataSetChanged() } - inner class SearchTermViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) { - val binding : B = DataBindingUtil.bind(itemView)!! - fun bind(recentSearchTerm: RecentSearchTerm){ - binding.setVariable(BR.searchTerm,recentSearchTerm) + inner class SearchTermViewHolder(itemView: View) : + RecyclerView.ViewHolder(itemView) { + private val binding: B = DataBindingUtil.bind(itemView)!! + fun bind(recentSearchTerm: RecentSearchTerm) { + binding.setVariable(BR.searchTerm, recentSearchTerm) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt index 9f3b728..71296a2 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/UserAdapter.kt @@ -7,13 +7,15 @@ import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import com.siba.searchmvvmpractice.BR import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.remote.model.Users import com.siba.searchmvvmpractice.databinding.UserItemBinding +import com.siba.searchmvvmpractice.remote.model.Users class UserAdapter : RecyclerView.Adapter.UserViewHolder>() { - var data = mutableListOf() + var data = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder = - UserViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.user_item,parent,false)) + UserViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.user_item, parent, false) + ) override fun onBindViewHolder(holder: UserViewHolder, position: Int) { holder.bind(data[position]) @@ -21,10 +23,11 @@ class UserAdapter : RecyclerView.Adapter.Use override fun getItemCount(): Int = data.size - inner class UserViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){ - val binding : B = DataBindingUtil.bind(itemView)!! - fun bind(users : Users){ - binding.setVariable(BR.users,users) + inner class UserViewHolder(itemView: View) : + RecyclerView.ViewHolder(itemView) { + private val binding: B = DataBindingUtil.bind(itemView)!! + fun bind(users: Users) { + binding.setVariable(BR.users, users) } } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt index a31a969..f629580 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/adapter/ViewPagerAdapter.kt @@ -3,15 +3,15 @@ package com.siba.searchmvvmpractice.ui.adapter import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter -import com.siba.searchmvvmpractice.ui.presentation.fragment.SearchUserFragment import com.siba.searchmvvmpractice.ui.presentation.fragment.SearchRepoFragment +import com.siba.searchmvvmpractice.ui.presentation.fragment.SearchUserFragment -class ViewPagerAdapter(fm : FragmentManager) : - FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { +class ViewPagerAdapter(fm: FragmentManager) : + FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { override fun getCount(): Int = 2 override fun getItem(position: Int): Fragment { - return when(position){ + return when (position) { 0 -> SearchUserFragment() else -> SearchRepoFragment() } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt index 30310da..fb811e8 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt @@ -4,11 +4,11 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.siba.searchmvvmpractice.repository.SearchRepository import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel -import java.lang.IllegalArgumentException -class SearchViewModelFactory(private val repository: SearchRepository) : ViewModelProvider.NewInstanceFactory() { +class SearchViewModelFactory(private val repository: SearchRepository) : + ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { - if(modelClass.isAssignableFrom(SearchViewModel::class.java)){ + if (modelClass.isAssignableFrom(SearchViewModel::class.java)) { return SearchViewModel(repository) as T } throw IllegalArgumentException("Unknown class name") diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt index 97ba16f..4f77377 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/activity/SearchActivity.kt @@ -1,7 +1,7 @@ package com.siba.searchmvvmpractice.ui.presentation.activity -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView import androidx.databinding.DataBindingUtil import androidx.fragment.app.FragmentManager @@ -9,12 +9,12 @@ import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.ui.adapter.ViewPagerAdapter import com.siba.searchmvvmpractice.databinding.ActivitySearchBinding import com.siba.searchmvvmpractice.databinding.SearchTermItemBinding +import com.siba.searchmvvmpractice.injection.Injection import com.siba.searchmvvmpractice.ui.adapter.SearchTermAdapter +import com.siba.searchmvvmpractice.ui.adapter.ViewPagerAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel -import com.siba.searchmvvmpractice.injection.Injection class SearchActivity : AppCompatActivity() { @@ -26,6 +26,7 @@ class SearchActivity : AppCompatActivity() { // TODO : 1. 최근검색어가 2개씩 저장되는 issue 처리 // TODO : 2. 서버에서 데이터가져오는걸 실패할 경우 앱이 죽지 말고 있어야함 , 에러처리 주체도 생각해봐야 할 듯 // TODO : 3. OFFLINE 캐싱 + // TODO : 4. base Factory rename to factory override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -40,12 +41,14 @@ class SearchActivity : AppCompatActivity() { } private fun initViewModel() { - viewModel = ViewModelProvider(this, Injection.provideSearchViewModelFactory(this)).get(SearchViewModel::class.java) + viewModel = ViewModelProvider(this, Injection.provideSearchViewModelFactory(this)).get( + SearchViewModel::class.java + ) } private fun initViews() { searchTermAdapter = SearchTermAdapter() - viewModel.allSearch.observe(this){ + viewModel.allSearch.observe(this) { searchTermAdapter.setData(it) } searchTermAdapter.notifyDataSetChanged() @@ -55,11 +58,16 @@ class SearchActivity : AppCompatActivity() { binding.searchTermRecyclerviewMain.apply { adapter = searchTermAdapter layoutManager = LinearLayoutManager(this@SearchActivity) - addItemDecoration(DividerItemDecoration(this@SearchActivity, LinearLayoutManager.VERTICAL)) + addItemDecoration( + DividerItemDecoration( + this@SearchActivity, + LinearLayoutManager.VERTICAL + ) + ) } } - fun setSearchView(searchView: SearchView) { + private fun setSearchView(searchView: SearchView) { searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { viewModel.userName.value = query!! @@ -74,7 +82,7 @@ class SearchActivity : AppCompatActivity() { }) } - fun setViewPagerAdapter(fm: FragmentManager) { + private fun setViewPagerAdapter(fm: FragmentManager) { binding.viewpagerMain.apply { adapter = ViewPagerAdapter(fm) } @@ -85,8 +93,8 @@ class SearchActivity : AppCompatActivity() { } } - fun search(){ - if(binding.tabMain.selectedTabPosition == 0) + private fun search() { + if (binding.tabMain.selectedTabPosition == 0) viewModel.searchUser() else viewModel.searchRepo() diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt index 0039d0b..3b5cd21 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchRepoFragment.kt @@ -1,11 +1,11 @@ package com.siba.searchmvvmpractice.ui.presentation.fragment import android.os.Bundle -import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -13,21 +13,20 @@ import com.siba.searchmvvmpractice.R import com.siba.searchmvvmpractice.databinding.FragmentSearchRepoBinding import com.siba.searchmvvmpractice.databinding.RepoItemBinding import com.siba.searchmvvmpractice.remote.model.UserRepository -import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import com.siba.searchmvvmpractice.ui.adapter.RepoAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel class SearchRepoFragment : Fragment() { - private lateinit var binding : FragmentSearchRepoBinding + private lateinit var binding: FragmentSearchRepoBinding - private val viewModel : SearchViewModel by activityViewModels() - private lateinit var repoAdapter : RepoAdapter + private val viewModel: SearchViewModel by activityViewModels() + private lateinit var repoAdapter: RepoAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_repo,container,false) + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search_repo, container, false) binding.viewModel = viewModel return binding.root } @@ -40,7 +39,7 @@ class SearchRepoFragment : Fragment() { } private fun setObserver() { - viewModel.githubRepo.observe(viewLifecycleOwner){ + viewModel.githubRepo.observe(viewLifecycleOwner) { repoAdapter.data = it.userRepository as MutableList repoAdapter.notifyDataSetChanged() } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt index 13210de..05b781c 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/presentation/fragment/SearchUserFragment.kt @@ -1,33 +1,32 @@ package com.siba.searchmvvmpractice.ui.presentation.fragment import android.os.Bundle -import android.util.Log -import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.siba.searchmvvmpractice.R -import com.siba.searchmvvmpractice.ui.adapter.UserAdapter import com.siba.searchmvvmpractice.databinding.FragmentSearchUserBinding import com.siba.searchmvvmpractice.databinding.UserItemBinding import com.siba.searchmvvmpractice.remote.model.Users +import com.siba.searchmvvmpractice.ui.adapter.UserAdapter import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel class SearchUserFragment : Fragment() { - private lateinit var binding : FragmentSearchUserBinding + private lateinit var binding: FragmentSearchUserBinding - private val viewModel : SearchViewModel by activityViewModels() - private lateinit var userAdapter : UserAdapter + private val viewModel: SearchViewModel by activityViewModels() + private lateinit var userAdapter: UserAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - binding = DataBindingUtil.inflate(inflater,R.layout.fragment_search_user,container,false) + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search_user, container, false) binding.viewModel = viewModel return binding.root } @@ -43,12 +42,12 @@ class SearchUserFragment : Fragment() { binding.searchUserRecyclerview.apply { layoutManager = LinearLayoutManager(requireContext()) adapter = userAdapter - addItemDecoration(DividerItemDecoration(requireContext(),LinearLayoutManager.VERTICAL)) + addItemDecoration(DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)) } } - fun setObserver(){ - viewModel.githubUser.observe(viewLifecycleOwner){ + fun setObserver() { + viewModel.githubUser.observe(viewLifecycleOwner) { userAdapter.data = it.users as MutableList userAdapter.notifyDataSetChanged() } diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt index 0a084fc..e6abab4 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/viewmodel/SearchViewModel.kt @@ -1,15 +1,15 @@ package com.siba.searchmvvmpractice.ui.viewmodel -import android.util.Log -import androidx.lifecycle.* +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.siba.searchmvvmpractice.local.entity.RecentSearchTerm import com.siba.searchmvvmpractice.remote.model.UserCatalog import com.siba.searchmvvmpractice.remote.model.UserRepositoryCatalog import com.siba.searchmvvmpractice.repository.SearchRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import java.lang.Exception -import java.lang.NullPointerException class SearchViewModel( private val repository: SearchRepository @@ -27,24 +27,24 @@ class SearchViewModel( val githubRepo: MutableLiveData get() = _githubRepo - var allSearch : LiveData> = repository.getAll() + var allSearch: LiveData> = repository.getAll() fun searchUser() = viewModelScope.launch { try { _githubUser.value = repository.fetchUser(userName.value.toString()) - } catch (e : NullPointerException){ + } catch (e: NullPointerException) { e.printStackTrace() - } catch (e : InterruptedException){ + } catch (e: InterruptedException) { e.printStackTrace() } } fun searchRepo() = viewModelScope.launch { - try{ + try { _githubRepo.value = repository.fetchRepo(userName.value.toString()) - } catch (e : NullPointerException){ + } catch (e: NullPointerException) { e.printStackTrace() - } catch (e : InterruptedException){ + } catch (e: InterruptedException) { e.printStackTrace() } } diff --git a/app/src/main/res/layout/user_item.xml b/app/src/main/res/layout/user_item.xml index bcf9207..76ea547 100644 --- a/app/src/main/res/layout/user_item.xml +++ b/app/src/main/res/layout/user_item.xml @@ -9,7 +9,7 @@ Date: Mon, 23 Nov 2020 15:52:41 +0900 Subject: [PATCH 24/24] update advice --- .idea/codeStyles/Project.xml | 139 ++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 + .../ui/base/SearchViewModelFactory.kt | 9 +- app/src/main/res/layout/repo_item.xml | 13 +- app/src/main/res/layout/search_term_item.xml | 6 +- app/src/main/res/layout/user_item.xml | 10 +- 6 files changed, 165 insertions(+), 17 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..3c7772a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt b/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt index fb811e8..86b698f 100644 --- a/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt +++ b/app/src/main/java/com/siba/searchmvvmpractice/ui/base/SearchViewModelFactory.kt @@ -5,13 +5,18 @@ import androidx.lifecycle.ViewModelProvider import com.siba.searchmvvmpractice.repository.SearchRepository import com.siba.searchmvvmpractice.ui.viewmodel.SearchViewModel +@Suppress("UNCHECKED_CAST") class SearchViewModelFactory(private val repository: SearchRepository) : ViewModelProvider.NewInstanceFactory() { override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(SearchViewModel::class.java)) { + /* if (modelClass.isAssignableFrom(SearchViewModel::class.java)) { return SearchViewModel(repository) as T } - throw IllegalArgumentException("Unknown class name") + throw IllegalArgumentException("Unknown class name")*/ + + // SearchViewModel(repository) as T에서 T는 ViewModel 로 타입이 일치한다. 하지만 에러가 나타나 suppress 해주었다. + require(modelClass.isAssignableFrom(SearchViewModel::class.java)){"Unknown class name"} + return SearchViewModel(repository) as T } } \ No newline at end of file diff --git a/app/src/main/res/layout/repo_item.xml b/app/src/main/res/layout/repo_item.xml index 1668741..2328454 100644 --- a/app/src/main/res/layout/repo_item.xml +++ b/app/src/main/res/layout/repo_item.xml @@ -13,10 +13,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> + app:layout_constraintStart_toStartOf="@+id/repository_name" + app:layout_constraintTop_toBottomOf="@+id/repository_name" /> \ No newline at end of file diff --git a/app/src/main/res/layout/search_term_item.xml b/app/src/main/res/layout/search_term_item.xml index 761c78c..c60a510 100644 --- a/app/src/main/res/layout/search_term_item.xml +++ b/app/src/main/res/layout/search_term_item.xml @@ -18,7 +18,7 @@ android:layout_height="wrap_content" android:src="@drawable/ic_recent_keyword" android:layout_marginTop="8dp" - android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" android:layout_marginBottom="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -29,7 +29,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{searchTerm.keyword}" - android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" app:layout_constraintLeft_toRightOf="@+id/ic_item" app:layout_constraintTop_toTopOf="@+id/ic_item" app:layout_constraintBottom_toBottomOf="@+id/ic_item" /> @@ -39,7 +39,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_delete" - android:layout_marginRight="16dp" + android:layout_marginEnd="16dp" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@+id/ic_item"/> diff --git a/app/src/main/res/layout/user_item.xml b/app/src/main/res/layout/user_item.xml index 76ea547..791727b 100644 --- a/app/src/main/res/layout/user_item.xml +++ b/app/src/main/res/layout/user_item.xml @@ -13,10 +13,10 @@ android:layout_height="wrap_content"> + app:layout_constraintStart_toStartOf="@+id/user_id" + app:layout_constraintTop_toBottomOf="@+id/user_id" />