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_오진우_2주차 과제_Step2 #57

Open
wants to merge 14 commits into
base: fivejinw
Choose a base branch
from
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
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
# android-map-keyword
# 2주차 - android-map-keyword
## step1 구현할 기능 목록

**UI 관련 기능**
- [x] 검색어를 입력할 수 있는 칸 구현
- [x] 검색 결과를 표시할 수 있는 칸 구현
- [x] 저장된 검색 결과를 표시할 수 있는 칸 구현

**DB 관련 기능**
- [x] 장소의 이름, 장소의 위치. 장소 카테고리를 저장할 수 있는 데이터베이스 구현

---------------------------
## step2 구현할 기능 목록


**검색 관련 기능**
- [x] 검색어를 입력하면 검색 결과 목록을 스크롤이 가능하도록 띄우는 기능
- [x] X를 누르면 입력한 검색어를 삭제하는 기능

**저장 관련 기능**
- [x] 검색 결과 목록중 하나를 클릭하면 저장하는 기능
- [x] 저장된 목록을 검색창 밑에서 가로 스크롤이 가능하도록 띄우는 기능
- [x] 저장된 목록중 X를 누르면 저장된 목록을 삭제하는 기능
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
android:theme="@style/Theme.Map"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name=".view.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
11 changes: 0 additions & 11 deletions app/src/main/java/campus/tech/kakao/map/MainActivity.kt

This file was deleted.

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

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.view.OnClickPlaceListener
import campus.tech.kakao.map.R
import campus.tech.kakao.map.model.Place

class PlaceViewAdapter(
val placeList: LiveData<MutableList<Place>>,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlaceViewAdapter 에서 LiveData 를 파라미터로 받고 있는데, 그런 사용은 지양해주시면 좋을 것 같아요! adapter 내에서 observe 하는 것도 없고, adapter 에서 필요한 것은 List 일 뿐이니까요!

val inflater: LayoutInflater,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inflater 를 굳이 parameter 를 통해서 받을 필요는 없습니다. onCreateViewHolder 의 parent: RecyclerView 의 context 를 사용하시면 됩니다 :)

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

val listener: OnClickPlaceListener
) : RecyclerView.Adapter<PlaceViewAdapter.PlaceViewHolder>() {

inner class PlaceViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 또한 inner class 가 아닌 형태로 처리하는 것으로 고려해주시면 좋을 것 같아요! ViewHolder 에서 adapter 를 접근하는 것이 올바른 형태는 아니에요!

val name = itemView.findViewById<TextView>(R.id.place_name)
val location = itemView.findViewById<TextView>(R.id.place_location)
val category = itemView.findViewById<TextView>(R.id.place_category)

init {
itemView.setOnClickListener {
val position = absoluteAdapterPosition
Log.d("testt", "콜백함수 호출")
placeList.value?.get(position)?.let { listener.savePlace(it) }
}
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlaceViewHolder {
val view = inflater.inflate(R.layout.place_item, parent, false)
Log.d("testt", "검색 결과 뷰 생성")
return PlaceViewHolder(view)
}

override fun onBindViewHolder(holder: PlaceViewHolder, position: Int) {
holder.name.text = placeList.value?.get(position)?.name ?: ""
holder.location.text = placeList.value?.get(position)?.location ?: ""
holder.category.text = placeList.value?.get(position)?.category ?: ""
}

override fun getItemCount(): Int {
return placeList.value?.size ?: 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package campus.tech.kakao.map.adapter

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.view.OnClickSavedPlaceListener
import campus.tech.kakao.map.R
import campus.tech.kakao.map.model.SavedPlace

class SavedPlaceViewAdapter(
val savedPlaceList: LiveData<MutableList<SavedPlace>>,
val inflater: LayoutInflater,
val listener: OnClickSavedPlaceListener
) : RecyclerView.Adapter<SavedPlaceViewAdapter.SavedPlaceViewHolder>() {

inner class SavedPlaceViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val name = itemView.findViewById<TextView>(R.id.saved_place_name)
val deleteButton = itemView.findViewById<ImageView>(R.id.button_saved_delete)

init {
deleteButton.setOnClickListener {
val position = absoluteAdapterPosition
Log.d("testt", "삭제 콜백함수 호출")
savedPlaceList.value?.get(position)?.let { listener.deleteSavedPlace(it, position) }
}
}

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SavedPlaceViewHolder {
val view = inflater.inflate(R.layout.saved_place_item, parent, false)
Log.d("testt", "저장된 장소를 띄우는 뷰 홀더 생성")
return SavedPlaceViewHolder(view)
}

override fun onBindViewHolder(holder: SavedPlaceViewHolder, position: Int) {
holder.name.text = savedPlaceList.value?.get(position)?.name ?: ""
}

override fun getItemCount(): Int {
return savedPlaceList.value?.size ?: 0
}
}
17 changes: 17 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/db/PlaceContract.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package campus.tech.kakao.map.db

import android.provider.BaseColumns

object PlaceContract{
object PlaceEntry : BaseColumns {
const val TABLE_NAME = "PLACE"
const val COLUMN_NAME = "NAME"
const val COLUMN_LOCATION = "LOCATION"
const val COLUMN_CATEGORY = "CATEGORY"
}

object SavedPlaceEntry : BaseColumns{
const val TABLE_NAME = "SAVED_PLACE"
const val COLUMN_NAME = "SAVED_NAME"
}
}
Comment on lines +5 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

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

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.util.Log


class PlaceDBHelper(context: Context) : SQLiteOpenHelper(context, "place.db", null, 2) {
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(
"CREATE TABLE " +
"${PlaceContract.PlaceEntry.TABLE_NAME}( " +
" ${PlaceContract.PlaceEntry.COLUMN_NAME} varchar(60) not null ," +
" ${PlaceContract.PlaceEntry.COLUMN_LOCATION} varchar(255) not null, " +
" ${PlaceContract.PlaceEntry.COLUMN_CATEGORY} varchar(30) );"
)

db?.execSQL(
"CREATE TABLE " +
"${PlaceContract.SavedPlaceEntry.TABLE_NAME}( " +
" ${PlaceContract.SavedPlaceEntry.COLUMN_NAME} varchar(60) not null);"
)
}

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

fun insertDummyData() {
val name = "카페"
val category = "카페"
val location = "서울 농기구 고길동"
for (i in 1..10) {
insertPlaceData(name + i, location + i, category)
}
readPlaceData()
}

fun insertPlaceData(name: String, location: String, category: String) {
val db = this.writableDatabase
val values = ContentValues().apply {
put(PlaceContract.PlaceEntry.COLUMN_NAME, name)
put(PlaceContract.PlaceEntry.COLUMN_LOCATION, location)
put(PlaceContract.PlaceEntry.COLUMN_CATEGORY, category)
}
db.insert(PlaceContract.PlaceEntry.TABLE_NAME, null, values)
}

fun insertSavedPlaceData(name: String) {
val db = this.writableDatabase
val values = ContentValues().apply {
put(PlaceContract.SavedPlaceEntry.COLUMN_NAME, name)
}
db.insert(PlaceContract.SavedPlaceEntry.TABLE_NAME, null, values)
}

fun readPlaceData(): Cursor {
val rDb = this.readableDatabase
return rDb.rawQuery("SELECT * FROM ${PlaceContract.PlaceEntry.TABLE_NAME};", null)
}

fun readPlaceDataWithSamedCategory(category: String): Cursor {
val rDb = this.readableDatabase
return rDb.rawQuery(
"SELECT * FROM ${PlaceContract.PlaceEntry.TABLE_NAME} WHERE ${PlaceContract.PlaceEntry.COLUMN_CATEGORY} = '${category}';",
null
)
}

fun readSavedPlaceData(): Cursor {
val rDb = this.readableDatabase
return rDb.rawQuery("SELECT * FROM ${PlaceContract.SavedPlaceEntry.TABLE_NAME};", null)
}

fun readSavedPlaceDataWithSamedName(name: String): Cursor {
val rDb = this.readableDatabase
return rDb.rawQuery(
"SELECT * FROM ${PlaceContract.SavedPlaceEntry.TABLE_NAME} WHERE ${PlaceContract.SavedPlaceEntry.COLUMN_NAME} = '${name}';",
null
)
}

fun deleteSavedPlace(name: String) {
val db = this.writableDatabase
db.delete(PlaceContract.SavedPlaceEntry.TABLE_NAME, "${PlaceContract.SavedPlaceEntry.COLUMN_NAME} = ?", arrayOf(name))
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/model/Place.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package campus.tech.kakao.map.model

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

data class SavedPlace(
val name: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package campus.tech.kakao.map.repository

import android.util.Log
import campus.tech.kakao.map.db.PlaceContract
import campus.tech.kakao.map.db.PlaceDBHelper
import campus.tech.kakao.map.model.Place

class PlaceRepository (val dbHelper: PlaceDBHelper){
fun getAllPlace() : MutableList<Place>{
val cursor = dbHelper.readPlaceData()
val placeList = mutableListOf<Place>()

while (cursor.moveToNext()) {
val place = Place(
cursor.getString(
cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_NAME)
),
cursor.getString(
cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_LOCATION)
),
cursor.getString(
cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_CATEGORY)
)
)
Log.d("readData", "이름 = ${place.name}, 위치 = ${place.location}, 분류 = ${place.category}")
placeList.add(place)
}

cursor.close()
return placeList
}

fun writePlace(place: Place){
dbHelper.insertPlaceData(place.name, place.location, place.category)
}

fun getPlaceWithCategory(category : String): MutableList<Place>{
val cursor = dbHelper.readPlaceDataWithSamedCategory(category)
val placeList = mutableListOf<Place>()

while (cursor.moveToNext()) {
val place = Place(
cursor.getString(
cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_NAME)
),
cursor.getString(
cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_LOCATION)
),
cursor.getString(
cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_CATEGORY)
)
)
Log.d("readData", "이름 = ${place.name}, 위치 = ${place.location}, 분류 = ${place.category}")
placeList.add(place)
}


cursor.close()
return placeList
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package campus.tech.kakao.map.repository

import android.util.Log
import campus.tech.kakao.map.db.PlaceContract
import campus.tech.kakao.map.db.PlaceDBHelper
import campus.tech.kakao.map.model.Place
import campus.tech.kakao.map.model.SavedPlace

class SavedPlaceRepository (val dbHelper: PlaceDBHelper){
fun getAllSavedPlace() : MutableList<SavedPlace>{
val cursor = dbHelper.readSavedPlaceData()
val placeList = mutableListOf<SavedPlace>()

while (cursor.moveToNext()) {
val place = SavedPlace(
cursor.getString(
cursor.getColumnIndexOrThrow(PlaceContract.SavedPlaceEntry.COLUMN_NAME)
)
)
Log.d("readData", "이름 = ${place.name}")
placeList.add(place)
}

cursor.close()
return placeList
}

fun writePlace(place: Place){
val cursor = dbHelper.readSavedPlaceDataWithSamedName(place.name)
if (cursor.moveToFirst()) {
Log.d("testt", "데이터 중복")
// 입력의 시간순대로 정렬되기 떄문에 레코드 삭제후 다시 집어넣기
dbHelper.deleteSavedPlace(place.name)
dbHelper.insertSavedPlaceData(place.name)
} else {
dbHelper.insertSavedPlaceData(place.name)
}
}

fun deleteSavedPlace(savedPlace: SavedPlace){
dbHelper.deleteSavedPlace(savedPlace.name)
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/view/ClickListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package campus.tech.kakao.map.view

import campus.tech.kakao.map.model.Place
import campus.tech.kakao.map.model.SavedPlace

interface OnClickPlaceListener {
fun savePlace(place: Place)
}

interface OnClickSavedPlaceListener {
fun deleteSavedPlace(savedPlace: SavedPlace, position: Int)
}
Loading