Skip to content

Commit

Permalink
강원대 Android_윤채원 4주차 과제 Step0 (kakao-tech-campus-2nd-step2#7)
Browse files Browse the repository at this point in the history
* Initial commit

* 강원대 Android_윤채원 3주차 과제 Step0 (kakao-tech-campus-2nd-step2#17)

* Initial commit

* style: Make MainActivity.xml

* feat: make Place.kt and PlaceDBHelper.kt

* feat: add checkPlaceExist of PlaceDBHelper

* feat: modify DB files

* docs: write readme.md

* docs: modify readme.md

* feat: consolidate MVVM pattern

* docs: write readme.md

* style: searchHistory and places cardviews

* style: modify recyclerviews

* feat: implement viewmodel and livedata

* style: modify placemodule

* feat: implement searchHistory

* feat: add search history animation

* feat: implementing search history click

* style: move xml ui string to strings.xml

* check

* delete useless variable

* modify code according to feedback

* move search history methods to repository

* modify README.md

* docs: write readme.md

---------

Co-authored-by: MyStoryG <[email protected]>

* 강원대 Android_윤채원 3주차 과제 Step1 (kakao-tech-campus-2nd-step2#43)

* Initial commit

* style: Make MainActivity.xml

* feat: make Place.kt and PlaceDBHelper.kt

* feat: add checkPlaceExist of PlaceDBHelper

* feat: modify DB files

* docs: write readme.md

* docs: modify readme.md

* feat: consolidate MVVM pattern

* docs: write readme.md

* style: searchHistory and places cardviews

* style: modify recyclerviews

* feat: implement viewmodel and livedata

* style: modify placemodule

* feat: implement searchHistory

* feat: add search history animation

* feat: implementing search history click

* style: move xml ui string to strings.xml

* check

* delete useless variable

* modify code according to feedback

* move search history methods to repository

* modify README.md

* docs: write readme.md

* feat: make DTO and retrofitservice interface

* feat: implement api search

* style: long place name shortening

* refactor: move search api method to repository

---------

Co-authored-by: MyStoryG <[email protected]>

* 강원대 Android_윤채원 3주차 과제 Step2 (kakao-tech-campus-2nd-step2#89)

* Initial commit

* style: Make MainActivity.xml

* feat: make Place.kt and PlaceDBHelper.kt

* feat: add checkPlaceExist of PlaceDBHelper

* feat: modify DB files

* docs: write readme.md

* docs: modify readme.md

* feat: consolidate MVVM pattern

* docs: write readme.md

* style: searchHistory and places cardviews

* style: modify recyclerviews

* feat: implement viewmodel and livedata

* style: modify placemodule

* feat: implement searchHistory

* feat: add search history animation

* feat: implementing search history click

* style: move xml ui string to strings.xml

* check

* delete useless variable

* modify code according to feedback

* move search history methods to repository

* modify README.md

* docs: write readme.md

* feat: make DTO and retrofitservice interface

* feat: implement api search

* style: long place name shortening

* refactor: move search api method to repository

* feat: generate map view methods

* docs: write readme.md

* feat: add mapview

* style: make search window of map activity

* feat: clicking search window to go search activity

* refactor: modify code according to first feedback

* refactor: move history methods to viewmodel

---------

Co-authored-by: MyStoryG <[email protected]>

* fix: merge rest things

* refactor: move places mutable livedata to viewmodel

---------

Co-authored-by: MyStoryG <[email protected]>
  • Loading branch information
settle54 and MyStoryG authored Jul 15, 2024
1 parent 8b097b3 commit e5245dc
Show file tree
Hide file tree
Showing 30 changed files with 1,032 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# android-map-location

31 changes: 28 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
Expand All @@ -15,6 +17,16 @@ android {
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

resValue("string", "kakao_api_key", getApiKey("KAKAO_API_KEY"))
buildConfigField("String", "KAKAO_REST_API_KEY", getApiKey("KAKAO_REST_API_KEY"))

ndk {
abiFilters.add("arm64-v8a")
abiFilters.add("armeabi-v7a")
abiFilters.add("x86")
abiFilters.add("x86_64")
}
}

buildTypes {
Expand All @@ -27,25 +39,32 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "17"
jvmTarget = "1.8"
}

buildFeatures {
viewBinding = true
dataBinding = true
buildConfig = true
}
}

fun getApiKey(key: String): String = gradleLocalProperties(rootDir, providers).getProperty(key)

dependencies {
val lifecycle_version = "2.8.3"
val activity_version = "1.9.0"

implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.datastore:datastore-preferences:1.0.0")
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation("com.kakao.maps.open:android:2.9.5")
Expand All @@ -60,4 +79,10 @@ dependencies {
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test:rules:1.5.0")
androidTestImplementation("androidx.test.espresso:espresso-intents:3.5.1")


implementation ("com.kakao.sdk:v2-all:2.20.3")
implementation ("androidx.activity:activity-ktx:$activity_version")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version")
}
11 changes: 11 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,26 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

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

<application
android:name=".MyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Map"
tools:targetApi="31">

<meta-data android:name="com.kakao.sdk.AppKey" android:value="@string/kakao_api_key"/>

<activity
android:name=".SearchActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
Expand All @@ -24,3 +34,4 @@
</application>

</manifest>

49 changes: 48 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,58 @@
package campus.tech.kakao.map

import android.content.Intent
import android.os.Bundle
import android.util.Log
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.MapLifeCycleCallback
import java.lang.Exception


class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var kakaoMap: KakaoMap

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

binding.mapView.start(object : MapLifeCycleCallback() {
override fun onMapDestroy() {
Log.d("KakaoMap", "카카오맵 종료")
}

override fun onMapError(e: Exception?) {
Log.e("KakaoMap", "카카오맵 인증실패", e)
}
}, object : KakaoMapReadyCallback() {
override fun onMapReady(p0: KakaoMap) {
Log.d("KakaoMap", "카카오맵 실행")
kakaoMap = p0
}
})

binding.searchInput.setOnClickListener {
val intent = Intent(this, SearchActivity::class.java)
startActivity(intent)
}

binding.searchButton.setOnClickListener {
val intent = Intent(this, SearchActivity::class.java)
startActivity(intent)
}
}

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

override fun onPause() {
super.onPause()
binding.mapView.pause()
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/MyApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package campus.tech.kakao.map

import android.app.Application
import com.kakao.vectormap.KakaoMapSdk

class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
val nativeKey = getString(R.string.kakao_api_key)
KakaoMapSdk.init(this, nativeKey)
}
}
50 changes: 50 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/PlacesAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package campus.tech.kakao.map

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.model.Place
import campus.tech.kakao.map.databinding.PlaceModuleBinding

class PlacesAdapter(
private val onClick: (Int) -> Unit
) : RecyclerView.Adapter<PlacesAdapter.ViewHolder>() {

private var localList: List<Place> = emptyList()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = PlaceModuleBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(localList[position])
}

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

fun updateList(newList: List<Place>) {
localList = newList
}

fun getItemName(position: Int): String {
return localList[position].name
}

inner class ViewHolder(private val binding: PlaceModuleBinding): RecyclerView.ViewHolder(binding.root) {

init {
binding.root.setOnClickListener {
onClick(bindingAdapterPosition)
}
}

fun bind(place: Place) {
binding.data = place
}

}

}
115 changes: 115 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package campus.tech.kakao.map

import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import campus.tech.kakao.map.model.RecentSearchWord
import campus.tech.kakao.map.databinding.ActivitySearchBinding
import campus.tech.kakao.map.viewModel.MapRepository
import campus.tech.kakao.map.viewModel.PlacesViewModel
import campus.tech.kakao.map.viewModel.PlacesViewModelFactory

class SearchActivity : AppCompatActivity() {
private lateinit var binding: ActivitySearchBinding
private lateinit var viewModel: PlacesViewModel
private lateinit var placesAdapter: PlacesAdapter

private lateinit var searchHistoryList: List<RecentSearchWord>
private lateinit var searchHistoryAdapter: SearchHistoryAdapter

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

val repository = MapRepository(this)
val viewModelFactory = PlacesViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(PlacesViewModel::class.java)

searchHistoryList = viewModel.getSearchHistory()
setUpSearchHistoryAdapter()
setUpPlacesAdapter()
setUpViewModelObservers()

binding.searchInput.addTextChangedListener { text ->
viewModel.searchPlaces(text.toString())
}

binding.deleteInput.setOnClickListener {
binding.searchInput.text.clear()
}

updateSearchHistoryVisibility()
}

private fun setUpSearchHistoryAdapter() {
searchHistoryAdapter = SearchHistoryAdapter(
searchHistoryList,
onDeleteClick = { position: Int ->
delSearch(position)
updateSearchHistoryVisibility()
},
onTextClick = { position: Int ->
val itemName = searchHistoryAdapter.getItemName(position)
binding.searchInput.setText(itemName)
})
binding.searchHistory.adapter = searchHistoryAdapter
}

private fun setUpPlacesAdapter() {
placesAdapter = PlacesAdapter { position: Int ->
val itemName = placesAdapter.getItemName(position)
insertSearch(itemName)
binding.searchHistory.visibility = View.VISIBLE
}
binding.placesRView.adapter = placesAdapter
binding.placesRView.layoutManager = LinearLayoutManager(this)
}

private fun setUpViewModelObservers() {
viewModel.places.observe(this, Observer { places ->
placesAdapter.updateList(places)
placesAdapter.notifyDataSetChanged()
binding.textView.visibility =
if (placesAdapter.itemCount <= 0) View.VISIBLE else View.GONE
})

viewModel.searchHistoryData.observe(this, Observer { searchHistoryData ->
searchHistoryList = searchHistoryData
})
}

private fun updateSearchHistoryVisibility() {
binding.searchHistory.isVisible = searchHistoryList.isNotEmpty()
}

private fun searchHistoryContains(itemName: String): Int {
return searchHistoryList.indexOfFirst { it.word == itemName }
}

private fun moveSearchToLast(foundIdx: Int, itemName: String) {
viewModel.moveSearchToLast(foundIdx, itemName)
searchHistoryAdapter.notifyItemMoved(foundIdx, searchHistoryList.size - 1)
}

private fun insertSearch(search: String) {
val foundIdx = searchHistoryContains(search)
if (foundIdx != -1) {
moveSearchToLast(foundIdx, search)
} else {
viewModel.addSearch(search)
searchHistoryAdapter.notifyItemInserted(searchHistoryList.size)
}
}

private fun delSearch(position: Int) {
viewModel.delSearch(position)
searchHistoryAdapter.notifyItemRemoved(position)
}
}
46 changes: 46 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/SearchHistoryAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package campus.tech.kakao.map

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.model.RecentSearchWord
import campus.tech.kakao.map.databinding.SearchHistoryModuleBinding

class SearchHistoryAdapter(
private var searchHistory: List<RecentSearchWord>,
private val onDeleteClick: (Int) -> Unit,
private val onTextClick: (Int) -> Unit
) : RecyclerView.Adapter<SearchHistoryAdapter.ViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = SearchHistoryModuleBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}

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

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(searchHistory[position])
}

fun getItemName(position: Int): String {
return searchHistory[position].word
}

inner class ViewHolder(private val binding: SearchHistoryModuleBinding) :
RecyclerView.ViewHolder(binding.root) {
init {
binding.deleteHistory.setOnClickListener {
onDeleteClick(bindingAdapterPosition)
}
binding.seachRecord.setOnClickListener {
onTextClick(bindingAdapterPosition)
}
}
fun bind(rsw : RecentSearchWord) {
binding.data = rsw
}
}
}
Loading

0 comments on commit e5245dc

Please sign in to comment.