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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}

android {
Expand All @@ -16,6 +17,11 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildFeatures {
dataBinding true
viewBinding true
}

buildTypes {
release {
minifyEnabled false
Expand All @@ -40,4 +46,20 @@ dependencies {
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'androidx.activity:activity-ktx:1.1.0'
implementation 'androidx.fragment:fragment-ktx:1.2.5'

// Lifecycle
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"

// Retrofit
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation "com.squareup.retrofit2:adapter-rxjava2:2.5.0"

//Glide
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}
10 changes: 7 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="place.pic.android.plus">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
Expand All @@ -10,14 +12,16 @@
android:supportsRtl="true"
android:theme="@style/Theme.AssignmentMVVM">
<activity
android:name=".MainActivity"
android:exported="true">
android:name=".detail.DetailUserActivity"
android:exported="false" />
<activity
android:name=".search.SearchUserActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
49 changes: 49 additions & 0 deletions app/src/main/java/place/pic/android/plus/BindingAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package place.pic.android.plus

import android.widget.ImageView
import androidx.databinding.BindingAdapter
import com.bumptech.glide.Glide

object BindingAdapter {
@BindingAdapter("setImageUrl")
@JvmStatic
fun loadImage(imageView: ImageView, url: String) {
Glide.with(imageView.context)
.load(url)
.circleCrop()
.into(imageView)
}

@BindingAdapter("setButtonChange")
@JvmStatic
fun setButtonChange(button: ImageView, compass: Boolean) {
when (compass) {
true -> button.setBackgroundResource(R.drawable.ic_baseline_clear_24)
else -> button.setBackgroundResource(R.drawable.ic_baseline_search_24)
}
}

/*
@BindingAdapter("TextChangeWatcher")
@JvmStatic
fun onEditTextWatcher(): TextWatcher {
return object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {
}
}
}

@BindingAdapter("bindRecyclerView")
@JvmStatic
fun bindRecyclerView(recyclerView: RecyclerView, searchUserData: MutableList<SearchUserData>?)
{
if (recyclerView.adapter != null) {
with(recyclerView.adapter as SearchUserAdapter) {
submitList(searchUserData)
}
}
}
*/
}
11 changes: 0 additions & 11 deletions app/src/main/java/place/pic/android/plus/MainActivity.kt

This file was deleted.

43 changes: 43 additions & 0 deletions app/src/main/java/place/pic/android/plus/SingleLiveEvent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package place.pic.android.plus

import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean

open class SingleLiveEvent<T> : MutableLiveData<T>() {

private val mPending = AtomicBoolean(false)

override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}

super.observe(
owner,
Observer { t ->
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t)
}
}
)
}

@MainThread
override fun setValue(t: T?) {
mPending.set(true)
super.setValue(t)
}

@MainThread
fun call() {
value = null
}

companion object {
private val TAG = "SingleLiveEvent"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package place.pic.android.plus.data.remote

import place.pic.android.plus.data.remote.response.ResponseUserSearch
import retrofit2.http.GET
import retrofit2.http.Query

interface GithubService {
@GET("/search/users")
suspend fun userList(
@Query("q") param: String?
): ResponseUserSearch
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package place.pic.android.plus.data.remote

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitBuilder {
private const val baseUrl = "https://api.github.com"

private var retrofit = Retrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()

var service: GithubService = retrofit.create(GithubService::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package place.pic.android.plus.data.remote.response

import java.io.Serializable

data class ResponseUserSearch(
val total_count: Int,
val incomplete_results: Boolean,
val items: List<SearchUserData>
) : Serializable

data class SearchUserData(
val login: String,
val avatar_url: String,
val html_url: String
) : Serializable
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package place.pic.android.plus.detail

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import place.pic.android.plus.data.remote.response.SearchUserData
import place.pic.android.plus.databinding.ActivityDetailUserBinding

class DetailUserActivity : AppCompatActivity() {
private lateinit var binding: ActivityDetailUserBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailUserBinding.inflate(layoutInflater)
setContentView(binding.root)
setBindingUserData()
}

private fun setBindingUserData() {
val user = intent.getSerializableExtra("user") as SearchUserData

with(binding) {
tvUser.text = user.login

Glide.with(this@DetailUserActivity)
.load(user.avatar_url)
.circleCrop()
.into(imgUser)

btnUser.setOnClickListener {
val webIntent =
Intent(Intent.ACTION_VIEW, Uri.parse(user.html_url))
startActivity(webIntent)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package place.pic.android.plus.search

import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import place.pic.android.plus.R
import place.pic.android.plus.data.remote.response.SearchUserData
import place.pic.android.plus.databinding.ActivitySearchUserBinding
import place.pic.android.plus.detail.DetailUserActivity
import place.pic.android.plus.search.adapter.SearchUserAdapter
import place.pic.android.plus.search.viewmodel.SearchUserViewModel

class SearchUserActivity : AppCompatActivity() {
private lateinit var binding: ActivitySearchUserBinding
private val searchUserViewModel: SearchUserViewModel by viewModels()
private lateinit var searchUserAdapter: SearchUserAdapter
private val userList = mutableListOf<SearchUserData>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_search_user)
searchUserAdapter = SearchUserAdapter()
binding.searchUserActivity = searchUserViewModel
binding.lifecycleOwner = this
binding.rvUserSearch.adapter = searchUserAdapter

searchUser()
changeButton()
deleteText()
gotoDetail()
}

private fun searchUser() {
searchUserViewModel.recyclerListData.observe(this) {
searchUserAdapter.submitList(it)
}

binding.etUserSearch.setOnEditorActionListener(object : TextView.OnEditorActionListener {
override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
lifecycleScope.launch {
searchUserViewModel.requestUserData(binding.etUserSearch.text.toString())
}
return true
}
return false
}
})
}

// livedata 쓰기
private fun changeButton() {
binding.etUserSearch.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
binding.btnUserSearch.visibility = View.VISIBLE
binding.btnUserSearchDelete.visibility = View.INVISIBLE
}

override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}

override fun afterTextChanged(p0: Editable?) {
binding.btnUserSearch.visibility = View.INVISIBLE
binding.btnUserSearchDelete.visibility = View.VISIBLE
}
})
}

// Btn 바인딩으로빼기
private fun deleteText() {
binding.btnUserSearchDelete.setOnClickListener {
binding.etUserSearch.text.clear()
}
}

// 여기 바꿔야함요 ㅎㅎ
private fun gotoDetail() {
searchUserAdapter.itemClick = object : SearchUserAdapter.ItemClick {
override fun onClick(view: View, position: Int) {
val intent = Intent(this@SearchUserActivity, DetailUserActivity::class.java)

intent.putExtra("user", userList[position])
startActivity(intent)
}
}
}
}
Loading