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 김민혁 5주차 STEP1 #89

Open
wants to merge 72 commits into
base: kyleidea1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
04c907f
Initial commit
MyStoryG Jun 15, 2024
8b097b3
Initial commit
MyStoryG Jun 15, 2024
9f4d9a7
docs: add project overview of STEP1 to README
kyleidea1 Jul 1, 2024
b2b33de
feat(view): Add activity_search.xml view for SearchView
kyleidea1 Jul 1, 2024
8eac791
feat(view): Add SearchMainActivity.kt
kyleidea1 Jul 1, 2024
a21a7c2
feat(view): Add DBHelper.kt which is local storage of places.
kyleidea1 Jul 2, 2024
f5e9623
feat: Added 9 data into Place.db
kyleidea1 Jul 2, 2024
b3a1339
docs: Modified README.md
kyleidea1 Jul 2, 2024
deb1a3c
feat: Create STEP1 branch and move existing work to it
kyleidea1 Jul 2, 2024
d3adda3
docs: Modified README.md for STEP2
kyleidea1 Jul 2, 2024
b959286
feat(db): add SearchHistoryDBHelper and initial place data
kyleidea1 Jul 5, 2024
a03fdc7
refactor(db): extract Place data class to separate file
kyleidea1 Jul 5, 2024
84ad89b
feat(ui): add SearchHistoryRecyclerViewAdapter for displaying search …
kyleidea1 Jul 5, 2024
496dd1d
fix(SearchActivity): Fix filtering logic to correctly filter search r…
kyleidea1 Jul 5, 2024
a62f21e
refactor: Split DBHelper into PlaceDBHelper and SearchHistoryDBHelper
kyleidea1 Jul 5, 2024
b043982
Refactor XML layout to fix visibility bug in SearchActivity
kyleidea1 Jul 5, 2024
7c26fd4
Add: Extracted Korean strings into string resources and updated decla…
kyleidea1 Jul 5, 2024
e404119
Add: Extracted Korean strings into string resources and updated decla…
kyleidea1 Jul 5, 2024
61d5adc
Refactor: Changed variable names to enhance consistency
kyleidea1 Jul 5, 2024
62e3846
docs: Modified README.md
kyleidea1 Jul 5, 2024
bbf77e9
Initial commit
MyStoryG Jul 7, 2024
9dd9533
Added missing files
kyleidea1 Jul 8, 2024
f62e568
chore(project): import code from android-map-keyword project
kyleidea1 Jul 9, 2024
811b9bc
docs: Added README.md of android-search-STEP1
kyleidea1 Jul 9, 2024
7499b1c
임시저장
kyleidea1 Jul 9, 2024
f898541
임시저장
kyleidea1 Jul 9, 2024
bb225cd
feat: Add Kakao Local API dependencies to Gradle files
kyleidea1 Jul 9, 2024
a5f25d9
feat(dto): Add DTO classes for Kakao API response
kyleidea1 Jul 10, 2024
cf5667f
feat(network): Implement KakaoLocalApi interface for API communication
kyleidea1 Jul 10, 2024
0d7f0e6
feat(repository): Create KakaoRepository for data retrieval from Kaka…
kyleidea1 Jul 10, 2024
81059af
feat: Added KyleMaps application class with Retrofit instance
kyleidea1 Jul 10, 2024
ec020cd
feat: added application icon image resources
kyleidea1 Jul 10, 2024
e4f5aa3
feat: added retrofit instance into KyleMaps.kt
kyleidea1 Jul 10, 2024
bebe6de
feat: remove activity_main_search
kyleidea1 Jul 12, 2024
e4839e6
remove: PlaceDBHelper.kt
kyleidea1 Jul 12, 2024
d7d4f93
feat: Added dto package and its elements
kyleidea1 Jul 12, 2024
70486ba
chore: added dependencies to use Kakao APIs
kyleidea1 Jul 12, 2024
a0be820
feat: Added KakaoRepository.kt
kyleidea1 Jul 12, 2024
cde3ac6
feat: Added KyleMaps.kt
kyleidea1 Jul 12, 2024
4f8a9f6
feat: Added drawable resources
kyleidea1 Jul 12, 2024
43a339a
feat: Added MapActivity and its layout
kyleidea1 Jul 12, 2024
2fb4d24
feat: Modified activity_search.xml and DBHelpers
kyleidea1 Jul 12, 2024
6b912fa
docs: updated README.md
kyleidea1 Jul 12, 2024
7bcbe37
commit before fixing bug
kyleidea1 Jul 16, 2024
a5a9a26
finished STEP0
kyleidea1 Jul 16, 2024
2c28c03
docs: updated README.md
kyleidea1 Jul 16, 2024
7260c3e
temporal save point
kyleidea1 Jul 17, 2024
0f1c076
feat: updated result recycler view's item click event
kyleidea1 Jul 17, 2024
b9ec7b4
부산대 Android_김민혁_4주차 과제_0단계 (#40)
kyleidea1 Jul 17, 2024
2a4502e
feat: added marker when selected an item of result recycler view
kyleidea1 Jul 17, 2024
f002a98
feat: implemented function that remembering last place's position whe…
kyleidea1 Jul 17, 2024
a30c46c
feat: added activity appears when error occurs
kyleidea1 Jul 18, 2024
807dc2d
feat: added bottom sheet dialog and its components
kyleidea1 Jul 18, 2024
34cf47c
style: get rid of paddings of bottomsheet layout
kyleidea1 Jul 18, 2024
4594193
Merge branch 'kyleidea1' into STEP1
kyleidea1 Jul 18, 2024
7c5707f
fix: fixed bug that MapActivities doesn't destory
kyleidea1 Jul 18, 2024
873df85
Merge remote-tracking branch 'origin/STEP1' into STEP1
kyleidea1 Jul 18, 2024
32ef74e
docs: updated README.md for android-location-STEP2
kyleidea1 Jul 18, 2024
2ded205
Feat: added UITest for MapActivity and SearchActivity
kyleidea1 Jul 19, 2024
68a947f
Feat: added UnitTest for MapActivity
kyleidea1 Jul 19, 2024
b06d783
modified trivial
kyleidea1 Jul 19, 2024
30e1b68
modified trivial
kyleidea1 Jul 19, 2024
15d1975
fix: fixed bug that Intent doesn't work
kyleidea1 Jul 22, 2024
dcf47d6
Merge remote-tracking branch 'location/STEP2'
kyleidea1 Jul 22, 2024
5e05b95
feat: finished STEP0
kyleidea1 Jul 22, 2024
92b279a
feat: added SearchHistory data class
kyleidea1 Jul 26, 2024
fcc536d
feat: added DataBase.kt and SearchHistoryDao.kt
kyleidea1 Jul 26, 2024
283d481
remove: Removed files supposed not to be used
kyleidea1 Jul 26, 2024
4da4f92
feat: Start to use Hilt
kyleidea1 Jul 26, 2024
847494d
feat: Added Appmodule.kt
kyleidea1 Jul 26, 2024
34d4b63
feat: Modified SearchHistoryRecyclerViewAdapter.kt
kyleidea1 Jul 26, 2024
ce24c63
docs: Updated README.md
kyleidea1 Jul 26, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ google-services.json

# Android Profiling
*.hprof

/keyStore
/app/release
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
# android-map-refactoring
# android-map-refactoring STEP1

## 개요

`android-map-refactoring STEP1`에서는 `android-map-search`에서 SQLite를 이용해 구현했던 로컬 데이터베이스를 Room 라이브러리로 대체합니다.
또한, `Hilt`를 이용해 의존성 주입 패턴을 적용합니다.
8 changes: 7 additions & 1 deletion 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 @@ -17,8 +19,9 @@ android {
targetSdk = 34
versionCode = 1
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"))
}

buildTypes {
Expand All @@ -39,6 +42,7 @@ android {
}

buildFeatures {
viewBinding = true
dataBinding = true
buildConfig = true
}
Expand Down Expand Up @@ -78,3 +82,5 @@ dependencies {
androidTestImplementation("com.google.dagger:hilt-android-testing:2.48.1")
kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.48.1")
}

fun getApiKey(key: String): String = gradleLocalProperties(rootDir, providers).getProperty(key)
34 changes: 34 additions & 0 deletions app/src/androidTest/java/campus/tech/kakao/map/MapActivityTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package campus.tech.kakao.map

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.*
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class MapActivityTest {

@get:Rule
val activityScenarioRule = ActivityScenarioRule(MapActivity::class.java)

@Before
fun setUp() {
}

@Test
fun testFirstScreen() {
onView(withId(R.id.search_button)).check(ViewAssertions.matches(isDisplayed()))
}
@Test
fun testSearchButtonClick() {
onView(withId(R.id.search_button)).perform(click())
Thread.sleep(1000)
onView(withId(R.id.search_edit_text)).check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package campus.tech.kakao.map

import android.content.Context
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.assertEquals

@RunWith(AndroidJUnit4::class)
class MapActivityUnitTest {

@get:Rule
val activityScenarioRule = ActivityScenarioRule(MapActivity::class.java)

private lateinit var sharedPreferences: SharedPreferences

@Before
fun setUp() {
val context = ApplicationProvider.getApplicationContext<Context>()
sharedPreferences = context.getSharedPreferences("lastLatLng", AppCompatActivity.MODE_PRIVATE)
sharedPreferences.edit().clear().apply()
}

@Test
fun testSaveLatLng() {
val latitude = "35.231627"
val longitude = "129.084020"

activityScenarioRule.scenario.onActivity { activity ->
activity.saveLatLng(latitude, longitude)

val savedLat = sharedPreferences.getString("lastLat", null)
val savedLng = sharedPreferences.getString("lastLng", null)

assertEquals(latitude, savedLat)
assertEquals(longitude, savedLng)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package campus.tech.kakao.map

import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.matcher.BoundedMatcher
import org.hamcrest.Description
import org.hamcrest.Matcher

class ResultRecyclerViewMatcher {
fun atPosition(position: Int, itemMatcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
return itemMatcher.matches(viewHolder?.itemView)
}

override fun describeTo(description: Description) {
description.appendText("has item at position $position: ")
itemMatcher.describeTo(description)
}
}
}

fun hasTextInViewWithId(viewId: Int, text: String): Matcher<View> {
return object : BoundedMatcher<View, View>(View::class.java) {
override fun matchesSafely(view: View): Boolean {
val textView = view.findViewById<TextView>(viewId)
return textView?.text.toString() == text
}

override fun describeTo(description: Description) {
description.appendText("has text '$text' in view with id $viewId")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package campus.tech.kakao.map

import android.annotation.SuppressLint
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.*
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.filters.MediumTest
import org.hamcrest.CoreMatchers.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(androidx.test.ext.junit.runners.AndroidJUnit4::class)
@MediumTest
class SearchActivityTest {

@get:Rule
val activityScenarioRule = ActivityScenarioRule(SearchActivity::class.java)

@Before
fun setup() {
activityScenarioRule.scenario.onActivity { activity ->
(activity.application as KyleMaps).isTestMode = true
}
}

@Test
fun testSearchFunctionality() {
onView(withId(R.id.no_results))
.check(matches(isDisplayed()))
}

@Test
fun testViewVisibility() {
onView(withId(R.id.search_edit_text)).perform(typeText("Hello"))
Thread.sleep(1000)
onView(withId(R.id.no_results)).check(matches(not(isDisplayed())))
onView(withId(R.id.recycler_view)).check(matches(isDisplayed()))
}

@Test
fun testResultRecyclerViewItem() {
val resultRecyclerViewMatcher = ResultRecyclerViewMatcher()
onView(withId(R.id.search_edit_text)).perform(typeText("DDDD"))
Thread.sleep(1000)
onView(withId(R.id.recycler_view))
.check(matches(resultRecyclerViewMatcher.atPosition(
0,
resultRecyclerViewMatcher.hasTextInViewWithId(R.id.place_name, "DDDD")
)))
onView(withId(R.id.recycler_view))
.check(matches(resultRecyclerViewMatcher.atPosition(
0,
resultRecyclerViewMatcher.hasTextInViewWithId(R.id.place_category, "음식점")
)))
onView(withId(R.id.recycler_view))
.check(matches(resultRecyclerViewMatcher.atPosition(
0,
resultRecyclerViewMatcher.hasTextInViewWithId(R.id.place_address, "경남 창원시 성산구 용호동 17-1")
)))
}

// @SuppressLint("CheckResult")
// @Test
// fun testSearchHistoryRecyclerViewItem() {
// val searchHistoryRecyclerViewMatcher = SearchHistoryRecyclerViewMatcher()
// var itemCount = 0
// activityScenarioRule.scenario.onActivity { activity ->
// val recyclerView: RecyclerView = activity.findViewById(R.id.horizontal_recycler_view)
// itemCount = recyclerView.adapter?.itemCount ?: 0
// }
// onView(withId(R.id.search_edit_text)).perform(typeText("DDDD"))
// Thread.sleep(1000)
//
// onView(withId(R.id.recycler_view))
// .perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click()))
// Thread.sleep(1000)
//
// onView(withId(R.id.horizontal_recycler_view))
// .check(matches(searchHistoryRecyclerViewMatcher.atPosition(
// itemCount-1,
// searchHistoryRecyclerViewMatcher.hasTextInViewWithId(R.id.search_history_item, "DDDD")
// )))
// }
// 로그도 잘 찍히고 아무 문제 없어보이는데 왜 안 되는 지 도무지 모르겠는 테스트 코드 !

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

import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import junit.framework.TestCase.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SearchActivityUnitTest {

@get:Rule
val activityScenarioRule = ActivityScenarioRule(SearchActivity::class.java)

@Before
fun setUp() {}

// @Test
// fun testSearchPlacesWithResults() {
// activityScenarioRule.scenario.onActivity { activity ->
// activity.searchPlaces("DDDD")
//
// val recyclerViewAdapter = activity.findViewById<RecyclerView>(R.id.recycler_view).adapter as ResultRecyclerViewAdapter
// assertEquals(1, recyclerViewAdapter.itemCount)
// }
// }
// 도저히 왜 안 되는 지 모르겠는 코드 2..
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package campus.tech.kakao.map

import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.matcher.BoundedMatcher
import org.hamcrest.Description
import org.hamcrest.Matcher

class SearchHistoryRecyclerViewMatcher {
fun atPosition(position: Int, itemMatcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
return itemMatcher.matches(viewHolder?.itemView)
}

override fun describeTo(description: Description) {
description.appendText("has item at position $position: ")
itemMatcher.describeTo(description)
}
}
}

fun hasTextInViewWithId(viewId: Int, text: String): Matcher<View> {
return object : BoundedMatcher<View, View>(View::class.java) {
override fun matchesSafely(view: View): Boolean {
val textView = view.findViewById<TextView>(viewId)
return textView?.text.toString() == text
}

override fun describeTo(description: Description) {
description.appendText("has text '$text' in view with id $viewId")
}
}
}
}
13 changes: 10 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,32 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

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

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

<activity
android:name=".MainActivity"
android:name=".MapActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".AuthenticationErrorActivity" />
<activity android:name=".SearchActivity" />

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package campus.tech.kakao.map

import android.os.Bundle
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.appcompat.app.AppCompatActivity

class AuthenticationErrorActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_authentication_error)

val retryIcon: ImageView = findViewById(R.id.retry_icon)
val loadingIndicator: ProgressBar = findViewById(R.id.loading_indicator)

retryIcon.setOnClickListener {
loadingIndicator.visibility = ProgressBar.VISIBLE
}
}
}
Loading