Skip to content

Commit

Permalink
충남대 Android_김선규 4주차 Step0 (kakao-tech-campus-2nd-step2#10)
Browse files Browse the repository at this point in the history
* Initial commit

* Merge : android-map-keyword into android-map-search (kakao-tech-campus-2nd-step2#8)

* 충남대 Android_김선규 3주차 과제 Step1 (kakao-tech-campus-2nd-step2#47)

* docs: add step1 requirements

* chore: set for using android api

* style: rename id in layout

* feat: remove storeInfo for using api

* feat: add connecting api for searching

* style: rename variable name proper

* 충남대 Android_김선규 3주차 과제 Step2 (kakao-tech-campus-2nd-step2#85)

* style: function rename and split

* feat: Change function to fit coroutine

* docs: add step2 requirements

* style: move from main to sub file

* chore: set it up to work in the right environment

* feat: display kakao map, when app is started

---------

Co-authored-by: MyStoryG <[email protected]>
  • Loading branch information
kimseongyu and MyStoryG committed Jul 29, 2024
1 parent 3d3c1b2 commit d8043f6
Show file tree
Hide file tree
Showing 14 changed files with 464 additions and 1 deletion.
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.Map"
tools:targetApi="31">
<activity
android:name=".SearchWindowActivity"
android:exported="false" />
<activity
android:name=".view.kakaomap.KakaoMapActivity"
android:exported="false" />
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/KakaoSearchKeywordAPI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package campus.tech.kakao.map

import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query

interface KakaoSearchKeywordAPI {
@GET("/v2/local/search/keyword.json")
suspend fun getSearchKeyWord(
@Header("Authorization") key: String,
@Query("query") keyword: String
): SearchResults
}
53 changes: 52 additions & 1 deletion app/src/main/java/campus/tech/kakao/map/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,62 @@
package campus.tech.kakao.map

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import campus.tech.kakao.map.databinding.ActivityMainBinding
import com.kakao.vectormap.KakaoMap
import com.kakao.vectormap.KakaoMapReadyCallback
import com.kakao.vectormap.KakaoMapSdk
import com.kakao.vectormap.MapLifeCycleCallback
import com.kakao.vectormap.MapView
import java.lang.Exception

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding
lateinit var mapView: MapView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

gotoSearchWindowBtnListener()
displayKakaoMap()
}

override fun onResume() {
super.onResume()
mapView.resume()
}

override fun onPause() {
super.onPause()
mapView.pause()
}

fun gotoSearchWindowBtnListener(){
binding.gotoSearchWindow.setOnClickListener {
val intent = Intent(this, SearchWindowActivity::class.java)
startActivity(intent)
}
}

fun displayKakaoMap(){
KakaoMapSdk.init(this, BuildConfig.KAKAO_API_KEY)
mapView = binding.mapView
mapView.start(object: MapLifeCycleCallback() {
override fun onMapDestroy() {

}

override fun onMapError(p0: Exception?) {

}
}, object: KakaoMapReadyCallback() {
override fun onMapReady(kakaoMap: KakaoMap) {

}
})
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package campus.tech.kakao.map

import android.content.ContentValues
import android.content.Context

class SavedSearchKeywordRepository(context: Context) {

private val dbHelper = StoreInfoDBHelper(context)

fun saveSearchKeyword(searchKeyword: SearchKeyword) {
val db = dbHelper.writableDatabase
val values = ContentValues().apply {
put(SearchKeywordEntry.SEARCH_KEYWORD, searchKeyword.searchKeyword)
}
db.insert(SearchKeywordEntry.TABLE_NAME, null, values)
db.close()
}

fun getSavedSearchKeywords(): List<SearchKeyword> {
val db = dbHelper.readableDatabase

val projection = arrayOf(
SearchKeywordEntry.SEARCH_KEYWORD
)

val cursor = db.query(
SearchKeywordEntry.TABLE_NAME,
projection,
null,
null,
null,
null,
null
)

val savedSearchKeywords = mutableListOf<SearchKeyword>()
with(cursor) {
while (moveToNext()) {
val searchWord = getString(getColumnIndexOrThrow(SearchKeywordEntry.SEARCH_KEYWORD))

val savedSearchWord = SearchKeyword(searchWord)
savedSearchKeywords.add(savedSearchWord)
}
}
cursor.close()
db.close()
return savedSearchKeywords
}

fun delSavedSearchKeyword(searchKeyword: SearchKeyword) {
val db = dbHelper.writableDatabase
val selection = "${SearchKeywordEntry.SEARCH_KEYWORD} = ?"
val selectionArgs = arrayOf(searchKeyword.searchKeyword)
db.delete(SearchKeywordEntry.TABLE_NAME, selection, selectionArgs)
db.close()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package campus.tech.kakao.map

import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.databinding.SavedSearchKeywordItemBinding

class SavedSearchKeywordsAdapter(
private val savedSearchKeywords: List<SearchKeyword>,
private val layoutInflater: LayoutInflater,
private val delSavedSearchKeyword: (SearchKeyword) -> Unit
) :
RecyclerView.Adapter<SavedSearchKeywordsAdapter.ViewHolder>() {
inner class ViewHolder(binding: SavedSearchKeywordItemBinding) :
RecyclerView.ViewHolder(binding.root) {
val savedSearchKeyword: TextView = binding.SavedSearchKeyword

init {
binding.delSavedSearchKeyword.setOnClickListener {
val searchKeyword = SearchKeyword(savedSearchKeyword.text.toString())
delSavedSearchKeyword(searchKeyword)
}
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = SavedSearchKeywordItemBinding.inflate(layoutInflater, parent, false)
return ViewHolder(view)
}

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

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = savedSearchKeywords[position]
holder.savedSearchKeyword.text = item.searchKeyword
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchKeyword.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package campus.tech.kakao.map

import android.provider.BaseColumns

data class SearchKeyword(
val searchKeyword: String
)

object SearchKeywordEntry : BaseColumns {
const val TABLE_NAME = "search_keyword"
const val SEARCH_KEYWORD = "search_keyword"
}
29 changes: 29 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package campus.tech.kakao.map

import kotlinx.coroutines.coroutineScope
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class SearchRepository {
companion object {
const val BASE_URL = "https://dapi.kakao.com"
const val API_KEY = "KakaoAK ${BuildConfig.KAKAO_REST_API_KEY}"
}

private val retrofitKakaoSearchKeyword = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(KakaoSearchKeywordAPI::class.java)

suspend fun Search(searchKeyword: SearchKeyword): List<Place> {
if (searchKeyword.searchKeyword == "")
return emptyList()

return coroutineScope {
retrofitKakaoSearchKeyword
.getSearchKeyWord(API_KEY, searchKeyword.searchKeyword)
.places
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchResults.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package campus.tech.kakao.map

import com.google.gson.annotations.SerializedName

data class SearchResults(
@SerializedName("documents")
val places: List<Place>
)

data class Place(
val place_name: String,
val category_name: String,
val address_name: String
)
45 changes: 45 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchResultsAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package campus.tech.kakao.map

import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.databinding.SearchResultItemBinding


class SearchResultsAdapter(
private val searchResults: List<Place>,
private val layoutInflater: LayoutInflater,
private val saveStoreName: (SearchKeyword) -> Unit
) :
RecyclerView.Adapter<SearchResultsAdapter.ViewHolder>() {
inner class ViewHolder(binding: SearchResultItemBinding) :
RecyclerView.ViewHolder(binding.root) {
val placeName: TextView = binding.placeName
val addressName: TextView = binding.addressName
val categoryName: TextView = binding.categoryName

init {
binding.root.setOnClickListener {
val searchKeyword = SearchKeyword(placeName.text.toString())
saveStoreName(searchKeyword)
}
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = SearchResultItemBinding.inflate(layoutInflater, parent, false)
return ViewHolder(view)
}

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

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = searchResults[position]
holder.placeName.text = item.place_name
holder.addressName.text = item.address_name
holder.categoryName.text = item.category_name
}
}
42 changes: 42 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package campus.tech.kakao.map

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class SearchViewModel(
private val searchRepository: SearchRepository,
private val savedSearchKeywordRepository: SavedSearchKeywordRepository
) : ViewModel() {

private val _searchResults = MutableStateFlow<List<Place>>(emptyList())
val searchResults: StateFlow<List<Place>> get() = _searchResults
private val _savedSearchKeywords = MutableStateFlow<List<SearchKeyword>>(emptyList())
val savedSearchKeywords: StateFlow<List<SearchKeyword>> get() = _savedSearchKeywords

init {
getSavedSearchKeywords()
}

fun getSearchResults(searchKeyword: SearchKeyword) {
viewModelScope.launch{
_searchResults.value = searchRepository.Search(searchKeyword)
}
}

fun saveSearchKeyword(searchKeyword: SearchKeyword) {
savedSearchKeywordRepository.saveSearchKeyword(searchKeyword)
getSavedSearchKeywords()
}

fun getSavedSearchKeywords() {
_savedSearchKeywords.value = savedSearchKeywordRepository.getSavedSearchKeywords()
}

fun delSavedSearchKeyword(searchKeyword: SearchKeyword) {
savedSearchKeywordRepository.delSavedSearchKeyword(searchKeyword)
getSavedSearchKeywords()
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchViewModelFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package campus.tech.kakao.map

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class SearchViewModelFactory(
private val searchRepository: SearchRepository,
private val savedSearchKeywordRepository: SavedSearchKeywordRepository
) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SearchViewModel(searchRepository, savedSearchKeywordRepository) as T
}
}
Loading

0 comments on commit d8043f6

Please sign in to comment.