Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

전남대 Android_장수민_3주차 과제(0단계) #28

Merged
merged 1 commit into from
Jul 10, 2024
Merged
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
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