Skip to content
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
2 changes: 2 additions & 0 deletions .github/workflows/debug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@ jobs:
DEV_BASE_URL: ${{ secrets.DEV_BASE_URL }}
PROD_BASE_URL: ${{ secrets.PROD_BASE_URL }}
KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
KAKAO_REST_API_KEY: ${{ secrets.KAKAO_REST_API_KEY }}
NAVER_MAPS_CLIENT_ID: ${{ secrets.NAVER_MAPS_CLIENT_ID }}
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
run: |
echo DEV_BASE_URL=\"$DEV_BASE_URL\" >> local.properties
echo PROD_BASE_URL=\"$PROD_BASE_URL\" >> local.properties
echo KAKAO_NATIVE_APP_KEY=$KAKAO_NATIVE_APP_KEY >> local.properties
echo KAKAO_REST_API_KEY=$KAKAO_REST_API_KEY >> local.properties
echo NAVER_MAPS_CLIENT_ID=$NAVER_MAPS_CLIENT_ID >> local.properties
echo POSTHOG_API_KEY=$POSTHOG_API_KEY >> local.properties
echo POSTHOG_HOST=$POSTHOG_HOST >> local.properties
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ jobs:
DEV_BASE_URL: ${{ secrets.DEV_BASE_URL }}
PROD_BASE_URL: ${{ secrets.PROD_BASE_URL }}
KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
KAKAO_REST_API_KEY: ${{ secrets.KAKAO_REST_API_KEY }}
NAVER_MAPS_CLIENT_ID: ${{ secrets.NAVER_MAPS_CLIENT_ID }}
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
Expand All @@ -123,6 +124,7 @@ jobs:
DEV_BASE_URL: ${{ secrets.DEV_BASE_URL }}
PROD_BASE_URL: ${{ secrets.PROD_BASE_URL }}
KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }}
KAKAO_REST_API_KEY: ${{ secrets.KAKAO_REST_API_KEY }}
NAVER_MAPS_CLIENT_ID: ${{ secrets.NAVER_MAPS_CLIENT_ID }}
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
POSTHOG_HOST: ${{ secrets.POSTHOG_HOST }}
Expand Down
6 changes: 6 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ android {
buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"$kakaoKey\"")
manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = kakaoKey

val kakaoRestApiKey: String = p.getProperty("KAKAO_REST_API_KEY") ?: ""
buildConfigField("String", "KAKAO_REST_API_KEY", "\"$kakaoRestApiKey\"")

val naverMapsClientID: String = p.getProperty("NAVER_MAPS_CLIENT_ID")
buildConfigField("String", "NAVER_MAPS_CLIENT_ID", "\"$naverMapsClientID\"")
manifestPlaceholders["NAVER_MAPS_CLIENT_ID"] = naverMapsClientID
Expand Down Expand Up @@ -122,6 +125,9 @@ android {
buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"$kakaoKey\"")
manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = kakaoKey

val kakaoRestApiKey: String = p.getProperty("KAKAO_REST_API_KEY") ?: ""
buildConfigField("String", "KAKAO_REST_API_KEY", "\"$kakaoRestApiKey\"")

val naverMapsClientID: String = p.getProperty("NAVER_MAPS_CLIENT_ID")
buildConfigField("String", "NAVER_MAPS_CLIENT_ID", "\"$naverMapsClientID\"")
manifestPlaceholders["NAVER_MAPS_CLIENT_ID"] = naverMapsClientID
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
<package android:name="com.nhn.android.nmap" />
<package android:name="net.daum.android.map" />
</queries>

<uses-permission android:name="android.permission.INTERNET" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.eatssu.android.data.remote.dto.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class KakaoLocalSearchResponse(
@SerialName("documents")
val documents: List<Document> = emptyList(),
) {
@Serializable
data class Document(
@SerialName("id")
val id: String = "",
@SerialName("place_name")
val placeName: String = "",
@SerialName("distance")
val distance: String = "",
) {
fun distanceInMeters(): Int = distance.toIntOrNull() ?: Int.MAX_VALUE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ data class PartnershipResponse(
val latitude: Double? = null,
@SerialName("restaurantType")
val restaurantType: StoreType? = null,
@SerialName("naverMapUrl")
val naverMapUrl: String? = null,
@SerialName("kakaoMapUrl")
val kakaoMapUrl: String? = null,
@SerialName("partnershipInfos")
val partnershipInfos: List<PartnershipInfo> = emptyList()
){
) {
@Serializable
data class PartnershipInfo(
@SerialName("id")
Expand Down Expand Up @@ -50,6 +54,8 @@ fun PartnershipResponse.toDomain(): Partnership =
longitude = longitude ?: 126.95661313346206,
latitude = latitude ?: 37.49517278813046,
restaurantType = restaurantType ?: StoreType.RESTAURANT,
naverMapUrl = naverMapUrl?.trim()?.takeIf(String::isNotEmpty),
kakaoMapUrl = kakaoMapUrl?.trim()?.takeIf(String::isNotEmpty),
partnershipInfos = partnershipInfos.map {
Partnership.PartnershipInfo(
id = it.id ?: -1,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.eatssu.android.data.remote.service

import com.eatssu.android.data.remote.dto.response.KakaoLocalSearchResponse
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query

interface KakaoLocalService {
@GET("v2/local/search/keyword.json")
suspend fun searchPlaces(
@Header("Authorization") authorization: String,
@Query("query") query: String,
@Query("x") longitude: Double,
@Query("y") latitude: Double,
@Query("radius") radius: Int = 300,
@Query("size") size: Int = 5,
@Query("sort") sort: String = "distance",
): Response<KakaoLocalSearchResponse>
}
27 changes: 27 additions & 0 deletions app/src/main/java/com/eatssu/android/di/KakaoLocalModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.eatssu.android.di

import javax.inject.Singleton
import com.eatssu.android.data.remote.service.KakaoLocalService
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import retrofit2.Retrofit

@Module
@InstallIn(SingletonComponent::class)
object KakaoLocalModule {
@Provides
@Singleton
fun provideKakaoLocalService(json: Json): KakaoLocalService =
Retrofit.Builder()
.baseUrl("https://dapi.kakao.com/")
.client(OkHttpClient.Builder().build())
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
.create(KakaoLocalService::class.java)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ data class Partnership(
val longitude: Double,
val latitude: Double,
val restaurantType: StoreType,
val partnershipInfos: List<PartnershipInfo>
val partnershipInfos: List<PartnershipInfo>,
val naverMapUrl: String? = null,
val kakaoMapUrl: String? = null,
) {
data class PartnershipInfo(
val id: Int,
Expand All @@ -22,4 +24,4 @@ data class Partnership(
val endDate: String,
val periodType: PeriodType,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ data class PartnershipRestaurant(
val departmentName: String,
val partnershipLikeCount: Int,
val likedByUser: Boolean,
val naverMapUrl: String? = null,
val kakaoMapUrl: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class GetPartnershipDetailUseCase @Inject constructor() {
collegeName = info.collegeName,
departmentName = info.departmentName,
partnershipLikeCount = info.likeCount,
likedByUser = info.isLiked
likedByUser = info.isLiked,
naverMapUrl = matched.naverMapUrl,
kakaoMapUrl = matched.kakaoMapUrl,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.eatssu.android.presentation.map

import com.eatssu.android.BuildConfig
import com.eatssu.android.data.remote.dto.response.KakaoLocalSearchResponse
import com.eatssu.android.data.remote.service.KakaoLocalService
import com.eatssu.android.domain.model.PartnershipRestaurant
import timber.log.Timber
import javax.inject.Inject

class KakaoLocalPlaceResolver @Inject constructor(
private val kakaoLocalService: KakaoLocalService,
) {
internal suspend fun resolve(
restaurant: PartnershipRestaurant,
preferredPlaceId: String?,
): ResolvedMapPlace? {
val restApiKey = BuildConfig.KAKAO_REST_API_KEY.trim()
if (restApiKey.isEmpty()) return null

val response = runCatching {
kakaoLocalService.searchPlaces(
authorization = "KakaoAK $restApiKey",
query = restaurant.storeName,
longitude = restaurant.longitude,
latitude = restaurant.latitude,
)
}.onFailure { throwable ->
Timber.w(throwable, "Failed to resolve Kakao local place")
}.getOrNull() ?: return null

if (!response.isSuccessful) {
Timber.w("Kakao local place search failed: %s", response.code())
return null
}

val matched = selectBestKakaoPlace(
documents = response.body()?.documents.orEmpty(),
preferredPlaceId = preferredPlaceId,
) ?: return null

return ResolvedMapPlace(
id = matched.id,
name = matched.placeName,
)
}
}

internal fun selectBestKakaoPlace(
documents: List<KakaoLocalSearchResponse.Document>,
preferredPlaceId: String?,
): KakaoLocalSearchResponse.Document? {
val matched = documents.firstOrNull { document -> document.id == preferredPlaceId }
?: documents.minByOrNull(KakaoLocalSearchResponse.Document::distanceInMeters)
?: return null

return matched.takeIf { document ->
document.distanceInMeters() <= MAX_MATCH_DISTANCE_METERS
}
}

private const val MAX_MATCH_DISTANCE_METERS = 300
Loading
Loading