-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Initial commit * feat: step0 (#17) * 충남대Android_전영주_4주차 과제_Step1 (피드백 반영) (#37) * feat: step0 * docs: 1단계 기능 목록 작성 * feat(ui): create BottomSheet layout * feat: 마커 기능&바텀 시트 추가 * feat: 에러 화면 추가 * feat: 마지막 위치를 저장 및 앱 실행 시 포커스 * feat: 피드백 반영 * 충남대 Android_전영주 4주차 Step2 (#83) * feat: step0 * docs: 1단계 기능 목록 작성 * feat(ui): create BottomSheet layout * feat: 마커 기능&바텀 시트 추가 * feat: 에러 화면 추가 * feat: 마지막 위치를 저장 및 앱 실행 시 포커스 * feat: 피드백 반영 * feat: step2 UI테스트 코드 추가 * step0: 4주차 코드 가져오기 --------- Co-authored-by: MyStoryG <[email protected]>
- Loading branch information
Showing
50 changed files
with
1,571 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
app/src/androidTest/java/campus/tech/kakao/map/MapActivityTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package campus.tech.kakao.map | ||
|
||
import android.content.Context | ||
import android.content.Intent | ||
import androidx.test.core.app.ApplicationProvider | ||
import androidx.test.core.app.launchActivity | ||
import androidx.test.espresso.Espresso.onView | ||
import androidx.test.espresso.action.ViewActions.click | ||
import androidx.test.espresso.assertion.ViewAssertions.matches | ||
import androidx.test.espresso.intent.Intents | ||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent | ||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed | ||
import androidx.test.espresso.matcher.ViewMatchers.withHint | ||
import androidx.test.espresso.matcher.ViewMatchers.withId | ||
import androidx.test.espresso.matcher.ViewMatchers.withText | ||
import androidx.test.ext.junit.rules.ActivityScenarioRule | ||
import campus.tech.kakao.map.domain.model.PlaceVO | ||
import campus.tech.kakao.map.presentation.MapActivity | ||
import campus.tech.kakao.map.presentation.PlaceActivity | ||
import org.hamcrest.CoreMatchers.not | ||
import org.junit.Rule | ||
import org.junit.Test | ||
|
||
class MapActivityTest { | ||
@get:Rule | ||
val activityRule = ActivityScenarioRule(MapActivity::class.java) | ||
|
||
|
||
@Test | ||
fun 검색필드가_표시되는지_확인_테스트() { | ||
onView(withId(R.id.searchBox)).check(matches(isDisplayed())) | ||
} | ||
|
||
@Test | ||
fun 검색필드의_힌트텍스트_확인_테스트() { | ||
onView(withId(R.id.searchTextView)).check(matches(withHint("검색어를 입력해 주세요"))) | ||
} | ||
|
||
@Test | ||
fun 맵뷰가_표시되는지_확인_테스트() { | ||
onView(withId(R.id.mapView)).check(matches(isDisplayed())) | ||
} | ||
|
||
@Test | ||
fun 검색필드를_누르면_액티비티_전환되는지_확인_테스트() { | ||
Intents.init() | ||
onView(withId(R.id.searchBox)).perform(click()) | ||
Intents.intended(hasComponent(PlaceActivity::class.java.name)) | ||
Intents.release() | ||
} | ||
|
||
|
||
@Test | ||
fun 인텐트가_있을때_바텀시트가_표시되는지_확인() { | ||
val place = PlaceVO("가짜 장소", "가짜 주소", "카페", 37.5665, 126.9780) | ||
val intent = | ||
Intent(ApplicationProvider.getApplicationContext(), MapActivity::class.java).apply { | ||
putExtra("place", place) | ||
} | ||
|
||
launchActivity<MapActivity>(intent) | ||
onView(withId(R.id.bottomSheet)).check(matches(isDisplayed())) | ||
} | ||
|
||
@Test | ||
fun 바텀시트에_표시된_텍스트가_인텐트로_보낸것과_일치하는지_확인() { | ||
val place = PlaceVO("가짜 장소", "가짜 주소", "카페", 37.5665, 126.9780) | ||
val intent = | ||
Intent(ApplicationProvider.getApplicationContext(), MapActivity::class.java).apply { | ||
putExtra("place", place) | ||
} | ||
launchActivity<MapActivity>(intent) | ||
|
||
onView(withId(R.id.nameTextaView)).check(matches(withText("가짜 장소"))) | ||
onView(withId(R.id.addressTextView)).check(matches(withText("가짜 주소"))) | ||
} | ||
|
||
@Test | ||
fun 인텐트와_마지막장소가_없다면_디폴트맵_표시하는지_확인_테스트() { | ||
|
||
// 마지막 장소 초기화 | ||
val context = ApplicationProvider.getApplicationContext<Context>() | ||
val sharedPreferences = context.getSharedPreferences("kakao_map", Context.MODE_PRIVATE) | ||
sharedPreferences.edit().clear().apply() | ||
|
||
launchActivity<MapActivity>() | ||
|
||
onView(withId(R.id.mapView)).check(matches(isDisplayed())) | ||
onView(withId(R.id.bottomSheet)).check(matches(not(isDisplayed()))) | ||
|
||
|
||
} | ||
|
||
|
||
} |
124 changes: 124 additions & 0 deletions
124
app/src/androidTest/java/campus/tech/kakao/map/PlaceActivityTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package campus.tech.kakao.map | ||
|
||
|
||
import android.content.pm.ActivityInfo | ||
import androidx.test.espresso.Espresso | ||
import androidx.test.espresso.Espresso.onView | ||
import androidx.test.espresso.action.ViewActions.* | ||
import androidx.test.espresso.assertion.ViewAssertions.matches | ||
import androidx.test.espresso.intent.Intents | ||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent | ||
import androidx.test.espresso.matcher.ViewMatchers.* | ||
import androidx.test.ext.junit.rules.ActivityScenarioRule | ||
import androidx.test.espresso.contrib.RecyclerViewActions | ||
import campus.tech.kakao.map.presentation.MapActivity | ||
import campus.tech.kakao.map.presentation.PlaceActivity | ||
import campus.tech.kakao.map.presentation.PlaceAdapter | ||
import campus.tech.kakao.map.presentation.SearchHistoryAdapter | ||
import org.hamcrest.CoreMatchers.not | ||
import org.junit.Rule | ||
import org.junit.Test | ||
|
||
class PlaceActivityTest { | ||
@get:Rule | ||
val activityRule = ActivityScenarioRule(PlaceActivity::class.java) | ||
|
||
@Test | ||
fun 검색박스에_텍스트_입력_시_검색_결과가_표시되는지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
Thread.sleep(3000) | ||
onView(withId(R.id.placeRecyclerView)).check(matches(isDisplayed())) | ||
} | ||
|
||
@Test | ||
fun 검색_아이템_클릭_시_히스토리에_잘_저장되는지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
Thread.sleep(2000) | ||
onView(withId(R.id.placeRecyclerView)).perform( | ||
RecyclerViewActions.actionOnItemAtPosition<PlaceAdapter.PlaceViewHolder>(0, click()) | ||
) | ||
Espresso.pressBack() | ||
onView(withId(R.id.historyRecyclerView)).check(matches(hasDescendant(withText("N")))) | ||
} | ||
|
||
@Test | ||
fun 검색_결과_클릭_시_지도_액티비티로_넘어가는지_테스트() { | ||
Intents.init() | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
Thread.sleep(1000) | ||
onView(withId(R.id.placeRecyclerView)).perform( | ||
RecyclerViewActions.actionOnItemAtPosition<PlaceAdapter.PlaceViewHolder>(0, click()) | ||
) | ||
Intents.intended(hasComponent(MapActivity::class.java.name)) | ||
|
||
Intents.release() | ||
} | ||
|
||
@Test | ||
fun 검색_히스토리_항목_클릭_시_검색_결과_표시되는지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("Z")) | ||
Thread.sleep(3000) | ||
onView(withId(R.id.placeRecyclerView)).perform( | ||
RecyclerViewActions.actionOnItemAtPosition<PlaceAdapter.PlaceViewHolder>(0, click()) | ||
) | ||
Espresso.pressBack() | ||
onView(withId(R.id.historyRecyclerView)).perform( | ||
RecyclerViewActions.actionOnItemAtPosition<SearchHistoryAdapter.HistoryViewHolder>( | ||
0, | ||
click() | ||
) | ||
) | ||
Thread.sleep(3000) | ||
onView(withId(R.id.placeRecyclerView)).check(matches(isDisplayed())) | ||
} | ||
|
||
@Test | ||
fun 검색_히스토리에서_삭제_시_히스토리에서_제거되는지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
Thread.sleep(1000) | ||
onView(withId(R.id.historyRecyclerView)).perform( | ||
RecyclerViewActions.actionOnItemAtPosition<SearchHistoryAdapter.HistoryViewHolder>( | ||
0, | ||
click() | ||
) | ||
) | ||
Thread.sleep(1000) | ||
onView(withId(R.id.historyRecyclerView)).check(matches(not(hasDescendant(withText("N"))))) | ||
} | ||
|
||
@Test | ||
fun 검색박스에서_텍스트_지우면_검색_결과가_사라지고_빈_메시지_표시되는지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
onView(withId(R.id.cancelButton)).perform(click()) | ||
Thread.sleep(2000) | ||
onView(withId(R.id.emptyMessage)).check(matches(isDisplayed())) | ||
onView(withId(R.id.placeRecyclerView)).check(matches(not(isDisplayed()))) | ||
} | ||
|
||
@Test | ||
fun 검색박스에서_x_버튼누르면_텍스트_지워지는지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
onView(withId(R.id.cancelButton)).perform(click()) | ||
onView(withId(R.id.searchEditText)).check(matches(withText(""))) | ||
} | ||
|
||
@Test | ||
fun 기기_회전_후에_검색_히스토리가_유지되는지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
activityRule.scenario.onActivity { | ||
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE | ||
} | ||
onView(withId(R.id.historyRecyclerView)).check(matches(hasDescendant(withText("N")))) | ||
} | ||
|
||
@Test | ||
fun 검색_결과가_스크롤_가능한지_테스트() { | ||
onView(withId(R.id.searchEditText)).perform(typeText("N")) | ||
Thread.sleep(3000) | ||
onView(withId(R.id.placeRecyclerView)).perform( | ||
RecyclerViewActions.scrollToPosition<PlaceAdapter.PlaceViewHolder>(10) | ||
) | ||
onView(withId(R.id.placeRecyclerView)).check(matches(isDisplayed())) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,18 @@ | ||
package campus.tech.kakao.map | ||
|
||
import android.content.Intent | ||
import android.os.Bundle | ||
import androidx.appcompat.app.AppCompatActivity | ||
import campus.tech.kakao.map.presentation.MapActivity | ||
import campus.tech.kakao.map.presentation.PlaceActivity | ||
|
||
|
||
class MainActivity : AppCompatActivity() { | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
setContentView(R.layout.activity_main) | ||
intent = Intent(this, MapActivity::class.java) | ||
startActivity(intent) | ||
finish() | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
app/src/main/java/campus/tech/kakao/map/data/PreferenceHelper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package campus.tech.kakao.map.data | ||
|
||
import android.content.Context | ||
import android.content.SharedPreferences | ||
import campus.tech.kakao.map.domain.model.PlaceVO | ||
import com.google.gson.Gson | ||
import com.google.gson.reflect.TypeToken | ||
|
||
|
||
object PreferenceHelper { | ||
private const val PREF_NAME = "kakao_map" | ||
private const val PREF_KEY_SEARCH_QUERY = "search_query" | ||
private const val PREF_KEY_LAST_PLACE = "last_place" | ||
|
||
fun defaultPrefs(context: Context): SharedPreferences = | ||
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) | ||
|
||
fun getSearchHistory(context: Context): List<String> { | ||
val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) | ||
val jsonSearchHistory = prefs.getString(PREF_KEY_SEARCH_QUERY, null) | ||
|
||
return if (jsonSearchHistory != null) { | ||
val type = object : TypeToken<List<String>>() {}.type | ||
Gson().fromJson(jsonSearchHistory, type) | ||
} else { | ||
emptyList() | ||
} | ||
} | ||
|
||
fun removeSearchQuery(context: Context, query: String) { | ||
val searchHistory = getSearchHistory(context).toMutableList() | ||
searchHistory.remove(query) | ||
val jsonSearchHistory = Gson().toJson(searchHistory) | ||
defaultPrefs(context).edit().putString(PREF_KEY_SEARCH_QUERY, jsonSearchHistory).apply() | ||
} | ||
|
||
fun saveSearchQuery(context: Context, query: String) { | ||
val searchHistory = getSearchHistory(context).toMutableList() | ||
searchHistory.remove(query) | ||
searchHistory.add(0, query) | ||
val jsonSearchHistory = Gson().toJson(searchHistory) | ||
|
||
defaultPrefs(context).edit().putString(PREF_KEY_SEARCH_QUERY, jsonSearchHistory).apply() | ||
} | ||
|
||
fun saveLastPlace(context: Context, place: PlaceVO) { | ||
val jsonLastPlace = Gson().toJson(place) | ||
defaultPrefs(context).edit().putString(PREF_KEY_LAST_PLACE, jsonLastPlace).apply() | ||
} | ||
|
||
fun getLastPlace(context: Context): PlaceVO? { | ||
val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) | ||
val jsonLastPlace = prefs.getString(PREF_KEY_LAST_PLACE, null) | ||
|
||
return if (jsonLastPlace != null) { | ||
Gson().fromJson(jsonLastPlace, PlaceVO::class.java) | ||
} else { | ||
null | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
app/src/main/java/campus/tech/kakao/map/data/model/DocumentEntity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package campus.tech.kakao.map.data.model | ||
|
||
import com.google.gson.annotations.SerializedName | ||
|
||
data class DocumentEntity( | ||
val id: String, | ||
@SerializedName("place_name") | ||
val placeName: String, | ||
@SerializedName("category_name") | ||
val categoryName: String, | ||
@SerializedName("category_group_code") | ||
val categoryGroupCode: String?, | ||
@SerializedName("category_group_name") | ||
val categoryGroupName: String, | ||
val phone: String?, | ||
@SerializedName("address_name") | ||
val addressName: String, | ||
@SerializedName("road_address_name") | ||
val roadAddressName: String?, | ||
val x: String, | ||
val y: String, | ||
@SerializedName("place_url") | ||
val placeUrl: String, | ||
val distance: String? | ||
) |
Oops, something went wrong.