Skip to content

Commit

Permalink
2주차 과제 옮김 (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
sumintnals authored Jul 10, 2024
1 parent bbf77e9 commit f7ac3aa
Show file tree
Hide file tree
Showing 41 changed files with 702 additions and 179 deletions.
8 changes: 7 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("kotlin-kapt")
}

android {
Expand Down Expand Up @@ -40,6 +41,11 @@ android {
}

dependencies {
kapt("com.android.databinding:compiler:3.1.4")
implementation("androidx.fragment:fragment-ktx:1.8.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.3")
implementation("com.google.code.gson:gson:2.11.0")

implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
Expand All @@ -49,7 +55,7 @@ dependencies {
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")
// implementation("com.kakao.maps.open:android:2.9.5")
implementation("androidx.activity:activity:1.8.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name="campus.tech.kakao.map.MapApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand Down
Binary file added app/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/Constans.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package campus.tech.kakao.map

object Constants {
const val SEARCH_HISTORY_KEY = "searchHistory"
const val PREFERENCE_NAME = "preference_name"
}
54 changes: 54 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/DBHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package campus.tech.kakao.map

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DBHelper (context: Context): SQLiteOpenHelper(context, "place.db", null, 1) {
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(
"CREATE TABLE IF NOT EXISTS ${PlaceContract.TABLE_NAME} ("+
"${PlaceContract.TABLE_COLUMN_NAME} VARCHAR(30) NOT NULL,"+
"${PlaceContract.TABLE_COLUMN_ADDRESS} VARCHAR(50) NOT NULL,"+
"${PlaceContract.TABLE_COLUMN_CATEGORY} VARCHAR(30) NOT NULL"+
");"
)
insertDummyData(db)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
db?.execSQL("DROP TABLE IF EXISTS ${PlaceContract.TABLE_NAME}")
onCreate(db)
}

fun insert(db: SQLiteDatabase, place: Place) {
val sql = " INSERT INTO " +
"${PlaceContract.TABLE_NAME}("+
"${PlaceContract.TABLE_COLUMN_NAME}, ${PlaceContract.TABLE_COLUMN_ADDRESS}, ${PlaceContract.TABLE_COLUMN_CATEGORY})"+
" VALUES(${place.name}, ${place.address}, ${place.category});"

db.execSQL(sql)
}

fun select(db: SQLiteDatabase, name:String, address: String, category: String) : String? {
return null
}

private fun insertDummyData(db: SQLiteDatabase?) {
db?.let {
val categories = listOf("카페", "약국", "식당")
val baseAddress = "서울 성동구 성수동"

categories.forEach { category ->
for (i in 1..15) {
val name = "$category $i"
val address = "$baseAddress $i"
val sql = "INSERT INTO ${PlaceContract.TABLE_NAME} (" +
"${PlaceContract.TABLE_COLUMN_NAME}, ${PlaceContract.TABLE_COLUMN_ADDRESS}, ${PlaceContract.TABLE_COLUMN_CATEGORY}) " +
"VALUES ('$name', '$address', '$category');"
it.execSQL(sql)
}
}
}
}
}
109 changes: 108 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,118 @@
package campus.tech.kakao.map

import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import campus.tech.kakao.map.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels {
ViewModelFactory(applicationContext)
}

private val placeAdapter: PlaceAdapter by lazy {
PlaceAdapter(placeList,
LayoutInflater.from(this@MainActivity),
object :
PlaceAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
val item = placeAdapter.getItem(position)
val searchHistory = SearchHistory(item.name)
viewModel.saveSearchHistory(searchHistory)
Log.d("실행", "저장")
}
}
)
}

private val historyAdapter: HistoryAdapter by lazy {
HistoryAdapter(
viewModel.searchHistoryList.value ?: emptyList(),
LayoutInflater.from(this@MainActivity),
object : HistoryAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
val item = viewModel.searchHistoryList.value?.get(position)
if (item != null) {
mainBinding.search.setText(item.searchHistory)
Log.d("실행", "검색창")
}
}
override fun onXMarkClick(position: Int) {
viewModel.deleteSearchHistory(position)
Log.d("실행", "삭제")
}
}
)
}

private lateinit var mainBinding: ActivityMainBinding


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

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

if (placeList.isNullOrEmpty()) {
mainBinding.emptyMainText.visibility = View.VISIBLE
} else {
mainBinding.emptyMainText.visibility = View.GONE
}

setupRecyclerViews(mainBinding)
setupSearchEditText(mainBinding)
observeViewModel(mainBinding)

mainBinding.xmark.setOnClickListener {
mainBinding.search.setText("")
}
}

private fun setupRecyclerViews(mainBinding: ActivityMainBinding) {
mainBinding.placeResult.apply {
layoutManager = LinearLayoutManager(this@MainActivity, LinearLayoutManager.VERTICAL, false)
adapter = placeAdapter
}

mainBinding.searchHistory.apply {
layoutManager = LinearLayoutManager(this@MainActivity, LinearLayoutManager.HORIZONTAL, false)
adapter = historyAdapter
}
}

private fun setupSearchEditText(mainBinding: ActivityMainBinding) {
val searchEditText = mainBinding.search

searchEditText.addTextChangedListener(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?) {
val searchText = searchEditText.text.toString()
viewModel.getSearchResult(searchText)
}
})
}

private fun observeViewModel(mainBinding: ActivityMainBinding) {
viewModel.searchHistoryList.observe(this@MainActivity, Observer {
historyAdapter.setData(it)
})
viewModel.getSearchHistoryList()

viewModel.placeList.observe(this@MainActivity, Observer {
placeAdapter.setData(it)
mainBinding.emptyMainText.visibility = if (it.isNullOrEmpty()) View.VISIBLE else View.GONE
})
}
}
78 changes: 78 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/MainViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package campus.tech.kakao.map

import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class MainViewModel(context: Context) : ViewModel() {
private val dbHelper: DBHelper = DBHelper(context)
private val db = dbHelper.writableDatabase
private val preferenceManager = MapApplication.prefs

private var _placeList = MutableLiveData<List<Place>>()
private val _searchHistoryList = MutableLiveData<List<SearchHistory>>()

init {
_searchHistoryList.value = getSearchHistory()
}

val searchHistoryList: LiveData<List<SearchHistory>>
get() = _searchHistoryList

val placeList: LiveData<List<Place>>
get() = _placeList

fun insertPlace(place: Place) {
dbHelper.insert(db, place)
}

override fun onCleared() {
super.onCleared()
if (db.isOpen) db.close()
}

fun getSearchResult(searchText: String) {
if (searchText.isEmpty()) {
_placeList.postValue(emptyList())
} else {
val rDb = dbHelper.readableDatabase
val places = mutableListOf<Place>()
val query = "SELECT * FROM ${PlaceContract.TABLE_NAME} WHERE ${PlaceContract.TABLE_COLUMN_NAME} LIKE ?"
val cursor = rDb.rawQuery(query, arrayOf("%$searchText%"))

if (cursor != null) {
if (cursor.moveToFirst()) {
do {
val name = cursor.getString(cursor.getColumnIndexOrThrow(PlaceContract.TABLE_COLUMN_NAME))
val address = cursor.getString(cursor.getColumnIndexOrThrow(PlaceContract.TABLE_COLUMN_ADDRESS))
val category = cursor.getString(cursor.getColumnIndexOrThrow(PlaceContract.TABLE_COLUMN_CATEGORY))
val place = Place(name, address, category)
places.add(place)
} while (cursor.moveToNext())
}
cursor.close()
}
_placeList.postValue(places)
}
}

fun getSearchHistoryList() {
_searchHistoryList.value = getSearchHistory()
}

private fun getSearchHistory(): ArrayList<SearchHistory> {
return preferenceManager.getArrayList(Constants.SEARCH_HISTORY_KEY)
}

fun saveSearchHistory(searchHistory: SearchHistory) {
val currentList = getSearchHistory()
preferenceManager.savePreference(Constants.SEARCH_HISTORY_KEY, searchHistory, currentList)
getSearchHistoryList()
}

fun deleteSearchHistory(position: Int) {
preferenceManager.deleteArrayListItem(Constants.SEARCH_HISTORY_KEY, position)
getSearchHistoryList()
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/MapApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package campus.tech.kakao.map

import android.app.Application
import android.content.SharedPreferences

class MapApplication: Application() {
companion object {
lateinit var prefs: PreferenceManager
}

override fun onCreate() {
prefs = PreferenceManager(applicationContext)
super.onCreate()
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/Place.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package campus.tech.kakao.map

data class Place (
val name: String,
val address: String,
val category: String,
)
61 changes: 61 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/PlaceAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package campus.tech.kakao.map

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.BaseAdapter
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.RecyclerView

class PlaceAdapter(var items: List<Place>, val inflater: LayoutInflater, var itemClickListener: OnItemClickListener): RecyclerView.Adapter<PlaceAdapter.PlaceViewHolder>() {

interface OnItemClickListener {
fun onItemClick(position: Int) {}
}

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): PlaceAdapter.PlaceViewHolder {
val view = inflater.inflate(R.layout.place_item, parent, false)
return PlaceViewHolder(view)
}

override fun onBindViewHolder(holder: PlaceAdapter.PlaceViewHolder, position: Int) {
holder.name.text = items[position].name
holder.address.text = items[position].address
holder.category.text = items[position].category
}

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

fun setData(searchResults: List<Place>) {
items = searchResults
notifyDataSetChanged()
}

fun getItem(position: Int): Place {
return items[position]
}

inner class PlaceViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val name: TextView
val address: TextView
val category: TextView

init {
name = itemView.findViewById<TextView>(R.id.place)
address = itemView.findViewById<TextView>(R.id.address)
category = itemView.findViewById<TextView>(R.id.category)

itemView.setOnClickListener {
itemClickListener.onItemClick(absoluteAdapterPosition)
}
}
}
}
Loading

0 comments on commit f7ac3aa

Please sign in to comment.