From 75af5f92bd38fb0e377a34ffe14baa7515eb0ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EC=A7=84?= Date: Thu, 10 Oct 2024 12:08:18 +0900 Subject: [PATCH] release/2.1.1 (#227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update release_tag.yml * Update bug_report.md * Production to develop (#213) * release 1.1.15 * Release/2.0.0 (#209) * [Refactor/#165] 문의하기 리팩토링 (#189) * refactor: inquire * add: todo * [Chore] migrate build.gradle.kts & lib.version.toml (#194) * chore: migrate build.gradle.kts & lib.version.toml * chore: toml use kebab-case * [Fix/#141] remote config ENUM값 있는걸로 교체 (#193) * fix: as Restaurant 타입 캐스팅 안되는 중 * fix: conflict * ds * chore: add gitignore ".DS_Store" * [Fix/#139] 리뷰 수정시 정보가 안넘어가던 현상 고치기 (#192) * release 1.1.15 * fix: 리뷰 수정하기 정보 안넘어가던거 성공 * fix: 맛 별점이 양 별점으로 잘못 들어가는거 수정 * fix: endpoint "s" * [chore/#195] change new color scheme (#196) * chore: change new color scheme * chore: naming * chore: naming lower * chore: missing "1" * chore: change missing color * [Redesign] change home design (#198) * redesign: calendar * redesign: item_cafeteria_section.xml * fix: top 여백을 fragment에서 item으로 변경 * feat: 장소 바인딩 * chore: indicator width min * add: ic good, bad * Revert "add: ic good, bad" This reverts commit f115b5feb91ab756a059780298cf0cbcc847492d. * Revert "chore: indicator width min" This reverts commit afc2f16d13c85d0d2aa666f6ec5c258a9c7a311e. * [Feat] 현재 시간에 따른 아침/점심/저녁 구분 (#201) * feat: TabLayout 시간대 설정 * feat: TabLayout 시간대 설정 * [Redesign/#203] my page 리디자인 적용 (#204) * redesign: 마이페이지 UI 변경 * redesign: 닉네임 변경 디자인 변경 * redesign: 닉네임 변경 디자인 변경 * delete: 안쓰는 drawable 삭제 * add: 정말 탈퇴하시겠습니까? 뷰 * feat: 닉네임 설정 로직 3개 완료 * feat: 정말 탈퇴하시겠습니까? * feat: 만든 사람들 * [Redesign/#200] review보기 리디자인 적용 (#202) * resign: 액션바 색상 변경 * add: 리사이클러뷰 메뉴 아이템 생성 * chore: 프로그래스 바 간격 맞추기 * chore: 맛&양 -> 굿&배드 * feat: 카드뷰로 사진 테두리 구현 * feat: 카드뷰로 사진 둥근테두리 구현 * feat: 간격 값 조정 * chore: gitignore 수정 * fix: 사진 있을 때만 imageView&CardView 보이게 * delete: ds_store * fix: missing files * chore: 바 추가 * chore: 리뷰 없을 때 간격 조정 * chore: 시간 대 조정 * [Redesign/#199] Info 리디자인 적용 + bottomSheet로 변경 (#205) * redesign: info bottomsheet로 변경 * feat: 식당 운영정보 실제 정보로 바인딩 * [Redesign] menus (#208) * refactor: material menus로 신고/수정/삭제 분리 * fix: 삭제 안되는거 수정 dialog import 수정, context를 this로 수정 * fix: 리뷰 삭제 후 리스트 재로딩 * [Redesign/#206] report 리디자인 적용 +문의하기 웹뷰처리 (#207) * add: shape, selector 파일 * delete: 문의하기 카카오채널로 변경 * refactor: 신고하기 flow로 리팩토링 * chore: 로고 변경 * chore: 메뉴이름 임시 바인딩 * chore: 굿배드 주석처리 * chore: 리뷰 작성 임시 처리 * fix: 리뷰 사진 안보이는거 해결 * fix: 메뉴이름 Text style * fix: 식당 사진 똑같게 들어가던거 수정 * chore: 체크박스 색상 변경 * fix: 텍스트 비정상적으로 작은거 해결 * chore: tablayout indicator 수정 * fix: NPE 뜨는 부분 주석처리 * fix: 사진이 없는데 자리 차지 하던거 고침 * fix: 아이콘 없대서 다시 되돌림 * Create qa_apk (#218) * Rename qa_apk to qa_apk.yml * feat: colored on today was not selected (#219) * Update README.md * Update README.md * [Feat] Notification (#216) * feat: test notify 성공 * add: notify 작업 파일 스테이징 * feat: workManager로 구현 * chore: modify workManager * modify: change workManager to AlarmManager it working on api 28, but not working on api 33 * chore: notify on 11 am * feat: save notification statue in datastore * modify: change mypage design * chore: modify layout * chore: modify code * chore: modify code * delete: work manager * chore: change alarm logo file to vector * chore: move code loading app version * chore: change padding * chore: separate setting alarm code at UI * chore: at 11 * [Redesign/login] 로그인 화면 리디자인 적용 (#222) * chore: delete firebase version * chore: delete default splash (android 12) * chore: set new splash * redesign: login activity * chore: delete unused logo files * chore: dark mode * [Refactor/remote config] 리모트 컨피그 관련 로직 수정 + info 버튼 터치 영역 확대 (#224) * chore: change small size logo file * delete: infoviewmodelfactory 제거 * chore: modify default config * chore: modify real location data * chore: more larger touch area(cafetria info btn) * [Refactor/#167] Hilt를 통해 ApplicationContext 주입하기 (#226) * add: appContext to di * chore: clean code * release/2.1.1 --- app/build.gradle.kts | 6 +- app/src/main/AndroidManifest.xml | 13 +-- .../FirebaseRemoteConfigRepository.kt | 40 ++++---- .../data/usecase/GetAccessTokenUseCase.kt | 8 +- .../data/usecase/GetRefreshTokenUseCase.kt | 7 +- .../data/usecase/GetUserEmailUseCase.kt | 7 +- .../data/usecase/GetUserNameUseCase.kt | 7 +- .../android/data/usecase/LogoutUseCase.kt | 6 +- .../data/usecase/SetAccessTokenUseCase.kt | 10 +- .../data/usecase/SetRefreshTokenUseCase.kt | 10 +- .../data/usecase/SetUserEmailUseCase.kt | 10 +- .../data/usecase/SetUserNameUseCase.kt | 6 +- .../java/com/eatssu/android/di/AppModule.kt | 8 ++ .../android/di/network/TokenInterceptor.kt | 17 ++-- .../eatssu/android/ui/info/InfoActivity.kt | 69 ------------- .../ui/info/InfoBottomSheetFragment.kt | 91 ++++-------------- .../eatssu/android/ui/info/InfoViewModel.kt | 83 +++++----------- .../android/ui/info/InfoViewModelFactory.kt | 18 ---- .../eatssu/android/ui/login/LoginViewModel.kt | 6 +- .../eatssu/android/ui/main/MainViewModel.kt | 10 +- .../android/ui/main/menu/MenuAdapter.kt | 3 +- .../android/ui/main/menu/MenuFragment.kt | 31 ++---- app/src/main/res/drawable/img_logo_512.png | Bin 0 -> 8232 bytes .../res/layout/item_cafeteria_section.xml | 9 ++ .../main/res/xml/firebase_remote_config.xml | 13 +-- 25 files changed, 158 insertions(+), 330 deletions(-) delete mode 100644 app/src/main/java/com/eatssu/android/ui/info/InfoActivity.kt delete mode 100644 app/src/main/java/com/eatssu/android/ui/info/InfoViewModelFactory.kt create mode 100644 app/src/main/res/drawable/img_logo_512.png diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1e39c1e5..90b98000 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,9 +21,9 @@ android { applicationId = "com.eatssu.android" minSdk = 23 targetSdk = 34 - versionCode = 1 - versionName = "2.1.0" - + versionCode = 21 + versionName = "2.1.1" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 50bbb7fb..ce54b951 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,11 +32,11 @@ android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" - android:icon="@drawable/img_logo1_44" + android:icon="@drawable/img_logo_512" android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config" android:requestLegacyExternalStorage="true" - android:roundIcon="@drawable/img_logo1_44" + android:roundIcon="@drawable/img_logo_512" android:supportsRtl="true" android:theme="@style/Theme.EatSSUAndroid" android:usesCleartextTraffic="true" @@ -151,14 +151,7 @@ android:name="android.app.lib_name" android:value="" /> - - - + diff --git a/app/src/main/java/com/eatssu/android/data/repository/FirebaseRemoteConfigRepository.kt b/app/src/main/java/com/eatssu/android/data/repository/FirebaseRemoteConfigRepository.kt index e18d3373..87e2bb18 100644 --- a/app/src/main/java/com/eatssu/android/data/repository/FirebaseRemoteConfigRepository.kt +++ b/app/src/main/java/com/eatssu/android/data/repository/FirebaseRemoteConfigRepository.kt @@ -2,11 +2,9 @@ package com.eatssu.android.data.repository import com.eatssu.android.R import com.eatssu.android.data.enums.Restaurant -import com.eatssu.android.data.model.AndroidMessage import com.eatssu.android.data.model.RestaurantInfo import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings -import com.google.gson.Gson import org.json.JSONArray import timber.log.Timber @@ -41,25 +39,25 @@ class FirebaseRemoteConfigRepository { } } - fun getAndroidMessage(): AndroidMessage { - - // Gson을 사용하여 JSON 문자열을 DTO로 파싱 - val serverStatus: AndroidMessage = Gson().fromJson(instance.getString("android_message"), AndroidMessage::class.java) - - // 파싱된 결과 확인 - println("Dialog: ${serverStatus.dialog}") - println("Message: ${serverStatus.message}") - - return serverStatus - } - - fun getForceUpdate(): Boolean { - return instance.getBoolean("force_update") - } - - fun getAppVersion(): String { - return instance.getString("app_version") - } +// fun getAndroidMessage(): AndroidMessage { +// +// // Gson을 사용하여 JSON 문자열을 DTO로 파싱 +// val serverStatus: AndroidMessage = Gson().fromJson(instance.getString("android_message"), AndroidMessage::class.java) +// +// // 파싱된 결과 확인 +// println("Dialog: ${serverStatus.dialog}") +// println("Message: ${serverStatus.message}") +// +// return serverStatus +// } + +// fun getForceUpdate(): Boolean { +// return instance.getBoolean("force_update") +// } +// +// fun getAppVersion(): String { +// return instance.getString("app_version") +// } fun getVersionCode(): Long { return instance.getLong("android_version_code") diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetAccessTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/GetAccessTokenUseCase.kt index 87975038..f54de06b 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetAccessTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/GetAccessTokenUseCase.kt @@ -1,14 +1,14 @@ package com.eatssu.android.data.usecase -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class GetAccessTokenUseCase @Inject constructor( -// private val preferencesRepository: PreferencesRepository, + @ApplicationContext private val context: Context ) { suspend operator fun invoke(): String { - - return MySharedPreferences.getAccessToken(App.appContext) + return MySharedPreferences.getAccessToken(context) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetRefreshTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/GetRefreshTokenUseCase.kt index aa69fbc0..635780b8 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetRefreshTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/GetRefreshTokenUseCase.kt @@ -1,14 +1,15 @@ package com.eatssu.android.data.usecase -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class GetRefreshTokenUseCase @Inject constructor( + @ApplicationContext private val context: Context // private val preferencesRepository: PreferencesRepository, ) { suspend operator fun invoke(): String { - - return MySharedPreferences.getRefreshToken(App.appContext) + return MySharedPreferences.getRefreshToken(context) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetUserEmailUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/GetUserEmailUseCase.kt index 1ccdf66c..5bbabb1c 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetUserEmailUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/GetUserEmailUseCase.kt @@ -1,14 +1,15 @@ package com.eatssu.android.data.usecase -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class GetUserEmailUseCase @Inject constructor( -// private val preferencesRepository: PreferencesRepository, + @ApplicationContext private val context: Context ) { suspend operator fun invoke(): String { - return MySharedPreferences.getUserEmail(App.appContext) + return MySharedPreferences.getUserEmail(context) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/GetUserNameUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/GetUserNameUseCase.kt index 5d204fdf..e85a49d9 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/GetUserNameUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/GetUserNameUseCase.kt @@ -1,14 +1,15 @@ package com.eatssu.android.data.usecase -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class GetUserNameUseCase @Inject constructor( // private val preferencesRepository: PreferencesRepository, + @ApplicationContext private val context: Context ) { suspend operator fun invoke(): String { - - return MySharedPreferences.getUserName(App.appContext) + return MySharedPreferences.getUserName(context) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/LogoutUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/LogoutUseCase.kt index 4afc03de..7d1e5b7f 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/LogoutUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/LogoutUseCase.kt @@ -1,14 +1,16 @@ package com.eatssu.android.data.usecase -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class LogoutUseCase @Inject constructor( + @ApplicationContext private val context: Context ) { suspend operator fun invoke() { - MySharedPreferences.clearUser(App.appContext) + MySharedPreferences.clearUser(context) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetAccessTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/SetAccessTokenUseCase.kt index 0474445d..2c5e06b4 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetAccessTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/SetAccessTokenUseCase.kt @@ -1,17 +1,15 @@ package com.eatssu.android.data.usecase -import android.util.Log -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class SetAccessTokenUseCase @Inject constructor( // private val preferencesRepository: PreferencesRepository, + @ApplicationContext private val context: Context ) { suspend operator fun invoke(accessToken: String) { - MySharedPreferences.setAccessToken(App.appContext, accessToken) - - Log.d("SetAccessTokenUseCase", accessToken) - + MySharedPreferences.setAccessToken(context, accessToken) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetRefreshTokenUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/SetRefreshTokenUseCase.kt index 0674ff1b..d8863c33 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetRefreshTokenUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/SetRefreshTokenUseCase.kt @@ -1,17 +1,15 @@ package com.eatssu.android.data.usecase -import android.util.Log -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class SetRefreshTokenUseCase @Inject constructor( // private val preferencesRepository: PreferencesRepository, + @ApplicationContext private val context: Context ) { suspend operator fun invoke(refreshToken: String) { - MySharedPreferences.setRefreshToken(App.appContext, refreshToken) - - Log.d("SetRefreshTokenUseCase", refreshToken) - + MySharedPreferences.setRefreshToken(context, refreshToken) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetUserEmailUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/SetUserEmailUseCase.kt index ca88a2bc..2e27b2ae 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetUserEmailUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/SetUserEmailUseCase.kt @@ -1,16 +1,14 @@ package com.eatssu.android.data.usecase -import android.util.Log -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject class SetUserEmailUseCase @Inject constructor( + @ApplicationContext private val context: Context ) { suspend operator fun invoke(email: String) { - MySharedPreferences.setUserEmail(App.appContext, email) - - Log.d("SetUserEmailUseCase", email) - + MySharedPreferences.setUserEmail(context, email) } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/data/usecase/SetUserNameUseCase.kt b/app/src/main/java/com/eatssu/android/data/usecase/SetUserNameUseCase.kt index b2b62c88..18e80ca7 100644 --- a/app/src/main/java/com/eatssu/android/data/usecase/SetUserNameUseCase.kt +++ b/app/src/main/java/com/eatssu/android/data/usecase/SetUserNameUseCase.kt @@ -1,18 +1,20 @@ package com.eatssu.android.data.usecase -import com.eatssu.android.App +import android.content.Context import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.request.ChangeNicknameRequest import com.eatssu.android.data.repository.UserRepository import com.eatssu.android.util.MySharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.Flow import javax.inject.Inject class SetUserNameUseCase @Inject constructor( private val userRepository: UserRepository, + @ApplicationContext private val context: Context ) { suspend operator fun invoke(name: String): Flow> { - MySharedPreferences.setUserName(App.appContext, name) + MySharedPreferences.setUserName(context, name) //Todo 이게 최선일까? 로컬에 이름 Set과 리모트의 이름 change를 usecase를 따로 만들어야하나? return userRepository.updateUserName(ChangeNicknameRequest(name)) diff --git a/app/src/main/java/com/eatssu/android/di/AppModule.kt b/app/src/main/java/com/eatssu/android/di/AppModule.kt index 5b4f9e17..62988858 100644 --- a/app/src/main/java/com/eatssu/android/di/AppModule.kt +++ b/app/src/main/java/com/eatssu/android/di/AppModule.kt @@ -2,6 +2,7 @@ package com.eatssu.android.di import android.app.Application import android.content.Context +import com.eatssu.android.data.repository.FirebaseRemoteConfigRepository import com.eatssu.android.data.repository.PreferencesRepository import dagger.Module import dagger.Provides @@ -25,4 +26,11 @@ object AppModule { fun providePreferencesRepository(@ApplicationContext context: Context): PreferencesRepository { return PreferencesRepository(context) } + + @Provides + @Singleton + fun provideFirebaseRemoteConfigRepository(): FirebaseRemoteConfigRepository { + return FirebaseRemoteConfigRepository() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt b/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt index 034072a6..d1583cc6 100644 --- a/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt +++ b/app/src/main/java/com/eatssu/android/di/network/TokenInterceptor.kt @@ -1,12 +1,11 @@ package com.eatssu.android.di.network +import android.content.Context import android.content.Intent import android.os.Handler import android.os.Looper -import android.util.Log import android.widget.Toast -import com.eatssu.android.App import com.eatssu.android.BuildConfig.BASE_URL import com.eatssu.android.base.BaseResponse import com.eatssu.android.data.dto.response.TokenResponse @@ -18,6 +17,7 @@ import com.eatssu.android.data.usecase.SetRefreshTokenUseCase import com.eatssu.android.ui.login.LoginActivity import com.google.gson.Gson import com.google.gson.reflect.TypeToken +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.Request @@ -33,6 +33,7 @@ class TokenInterceptor @Inject constructor( private val setAccessTokenUseCase: SetAccessTokenUseCase, private val setRefreshTokenUseCase: SetRefreshTokenUseCase, private val logoutUseCase: LogoutUseCase, + @ApplicationContext private val context: Context ) : Interceptor { companion object { @@ -68,7 +69,7 @@ class TokenInterceptor @Inject constructor( val response = chain.proceed(request) if (response.code == 401) { - Log.d(TAG, "토큰 퉤퉤") + Timber.d("토큰 퉤퉤") response.close() try { @@ -78,13 +79,13 @@ class TokenInterceptor @Inject constructor( .addHeader(HEADER_AUTHORIZATION, "Bearer $refreshToken") .build() - Log.d(TAG, "재발급 중") + Timber.d("재발급 중") val refreshTokenResponse = chain.proceed(refreshTokenRequest) - Log.d(TAG, "refreshTokenResponse : $refreshTokenResponse") + Timber.d("refreshTokenResponse : $refreshTokenResponse") if (refreshTokenResponse.isSuccessful) { - Log.d(TAG, "재발급 성공") + Timber.d("재발급 성공") val responseToken = parseRefreshTokenResponse(refreshTokenResponse) @@ -110,7 +111,6 @@ class TokenInterceptor @Inject constructor( Timber.e("재발급에서의 401") Handler(Looper.getMainLooper()).post { - val context = App.appContext Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show() val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) @@ -123,7 +123,6 @@ class TokenInterceptor @Inject constructor( Timber.e("재발급 실패 $e") Handler(Looper.getMainLooper()).post { - val context = App.appContext Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show() val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) @@ -137,7 +136,6 @@ class TokenInterceptor @Inject constructor( Timber.e("404 + 다른 유저!") Handler(Looper.getMainLooper()).post { - val context = App.appContext Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show() val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) @@ -150,7 +148,6 @@ class TokenInterceptor @Inject constructor( Timber.e("500 + 다른 유저") Handler(Looper.getMainLooper()).post { - val context = App.appContext Toast.makeText(context, "토큰이 만료되어 로그아웃 됩니다.", Toast.LENGTH_SHORT).show() val intent = Intent(context, LoginActivity::class.java) // 로그인 화면으로 이동 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) diff --git a/app/src/main/java/com/eatssu/android/ui/info/InfoActivity.kt b/app/src/main/java/com/eatssu/android/ui/info/InfoActivity.kt deleted file mode 100644 index de5c06d4..00000000 --- a/app/src/main/java/com/eatssu/android/ui/info/InfoActivity.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.eatssu.android.ui.info - -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.ViewModelProvider -import com.eatssu.android.R -import com.eatssu.android.data.enums.Restaurant -import com.eatssu.android.data.repository.FirebaseRemoteConfigRepository -import com.eatssu.android.databinding.ActivityInfoBinding - -class InfoActivity : AppCompatActivity() { - - private lateinit var binding: ActivityInfoBinding - - private lateinit var infoViewModel: InfoViewModel - private lateinit var restaurantType: Restaurant - private lateinit var firebaseRemoteConfigRepository: FirebaseRemoteConfigRepository - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityInfoBinding.inflate(layoutInflater) - setContentView(binding.root) - window.setBackgroundDrawableResource(R.drawable.shape_round_corners_dialog) - - - firebaseRemoteConfigRepository = FirebaseRemoteConfigRepository() - infoViewModel = ViewModelProvider(this, InfoViewModelFactory(firebaseRemoteConfigRepository))[InfoViewModel::class.java] - - restaurantType = intent.getSerializableExtra("restaurantType") as Restaurant - binding.tvName.text = restaurantType.displayName - - infoViewModel.infoList.observe(this) { - - when (restaurantType) { - Restaurant.DODAM -> { - binding.tvLocation.text = infoViewModel.dodamEtc.value - binding.tvTime.text = infoViewModel.dodamTime.value - binding.tvEtc.text = infoViewModel.dodamEtc.value - } - - Restaurant.HAKSIK -> { - binding.tvLocation.text = infoViewModel.dodamLocation.value - binding.tvTime.text = infoViewModel.haksikTime.value - binding.tvEtc.text = infoViewModel.haksikEtc.value - } - - Restaurant.FOOD_COURT -> { - binding.tvLocation.text = infoViewModel.foodLocation.value - binding.tvTime.text = infoViewModel.foodTime.value - binding.tvEtc.text = infoViewModel.foodEtc.value - } - - Restaurant.SNACK_CORNER -> { - binding.tvLocation.text = infoViewModel.snackLocation.value - binding.tvTime.text = infoViewModel.snackTime.value - binding.tvEtc.text = infoViewModel.snackEtc.value - } - - Restaurant.DORMITORY -> { - binding.tvLocation.text = infoViewModel.dormitoryLocation.value - binding.tvTime.text = infoViewModel.dormitoryTime.value - binding.tvEtc.text = infoViewModel.dormitoryEtc.value - } - - else -> {} - } - } - } -} diff --git a/app/src/main/java/com/eatssu/android/ui/info/InfoBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/ui/info/InfoBottomSheetFragment.kt index bf583f48..9de27f41 100644 --- a/app/src/main/java/com/eatssu/android/ui/info/InfoBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/ui/info/InfoBottomSheetFragment.kt @@ -1,117 +1,66 @@ package com.eatssu.android.ui.info import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.lifecycle.ViewModelProvider +import androidx.fragment.app.activityViewModels import com.bumptech.glide.Glide import com.eatssu.android.data.enums.Restaurant -import com.eatssu.android.data.repository.FirebaseRemoteConfigRepository import com.eatssu.android.databinding.FragmentBottomsheetInfoBinding import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import timber.log.Timber class InfoBottomSheetFragment : BottomSheetDialogFragment() { private var _binding: FragmentBottomsheetInfoBinding? = null private val binding get() = _binding!! - private lateinit var infoViewModel: InfoViewModel - private lateinit var firebaseRemoteConfigRepository: FirebaseRemoteConfigRepository - + private val infoViewModel: InfoViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { _binding = FragmentBottomsheetInfoBinding.inflate(inflater, container, false) - - firebaseRemoteConfigRepository = FirebaseRemoteConfigRepository() - infoViewModel = ViewModelProvider( - this, - InfoViewModelFactory(firebaseRemoteConfigRepository) - )[InfoViewModel::class.java] - return binding.root } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - // 전달된 데이터 받기 + // Retrieve passed data val name = arguments?.getString("name") val restaurantType = enumValues().find { it.name == name } ?: Restaurant.HAKSIK - Log.d("InfoBottomSheetFragment", "onViewCreated: $name $restaurantType") + Timber.d("onViewCreated: $name $restaurantType") binding.tvName.text = restaurantType.displayName - //TODO 방법 개선 - infoViewModel.infoList.observe(this) { + // Collect the infoList Flow + CoroutineScope(Dispatchers.Main).launch { + infoViewModel.infoList.collect { restaurantInfoList -> + val restaurantInfo = infoViewModel.getRestaurantInfo(restaurantType) - when (restaurantType) { - Restaurant.DODAM -> { - binding.tvLocation.text = infoViewModel.dodamLocation.value - binding.tvTime.text = infoViewModel.dodamTime.value - binding.tvEtc.text = infoViewModel.dodamEtc.value + restaurantInfo?.let { + binding.tvLocation.text = it.location + binding.tvTime.text = it.time + binding.tvEtc.text = it.etc - Glide.with(this) - .load(infoViewModel.dodamPhotoUrl.value) + Glide.with(this@InfoBottomSheetFragment) + .load(it.photoUrl) .into(binding.ivCafeteriaPhoto) } - - Restaurant.HAKSIK -> { - binding.tvLocation.text = infoViewModel.haksikLocation.value - binding.tvTime.text = infoViewModel.haksikTime.value - binding.tvEtc.text = infoViewModel.haksikEtc.value - - Glide.with(this) - .load(infoViewModel.haksikPhotoUrl.value) - .into(binding.ivCafeteriaPhoto) - } - - Restaurant.FOOD_COURT -> { - binding.tvLocation.text = infoViewModel.foodLocation.value - binding.tvTime.text = infoViewModel.foodTime.value - binding.tvEtc.text = infoViewModel.foodEtc.value - - Glide.with(this) - .load(infoViewModel.foodPhotoUrl.value) - .into(binding.ivCafeteriaPhoto) - } - - Restaurant.SNACK_CORNER -> { - binding.tvLocation.text = infoViewModel.snackLocation.value - binding.tvTime.text = infoViewModel.snackTime.value - binding.tvEtc.text = infoViewModel.snackEtc.value - - Glide.with(this) - .load(infoViewModel.snackPhotoUrl.value) - .into(binding.ivCafeteriaPhoto) - } - - Restaurant.DORMITORY -> { - binding.tvLocation.text = infoViewModel.dormitoryLocation.value - binding.tvTime.text = infoViewModel.dormitoryTime.value - binding.tvEtc.text = infoViewModel.dormitoryEtc.value - - Glide.with(this) - .load(infoViewModel.dormitoryPhotoUrl.value) - .into(binding.ivCafeteriaPhoto) - } - - else -> {} } } } companion object { - // newInstance 메서드를 통해 데이터를 전달하는 방법 fun newInstance(data: String): InfoBottomSheetFragment { val fragment = InfoBottomSheetFragment() - val args = Bundle() - args.putString("name", data) + val args = Bundle().apply { putString("name", data) } fragment.arguments = args return fragment } diff --git a/app/src/main/java/com/eatssu/android/ui/info/InfoViewModel.kt b/app/src/main/java/com/eatssu/android/ui/info/InfoViewModel.kt index 84598b55..b9f1f130 100644 --- a/app/src/main/java/com/eatssu/android/ui/info/InfoViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/info/InfoViewModel.kt @@ -1,73 +1,40 @@ package com.eatssu.android.ui.info import android.util.Log -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.eatssu.android.data.enums.Restaurant import com.eatssu.android.data.model.RestaurantInfo import com.eatssu.android.data.repository.FirebaseRemoteConfigRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject -class InfoViewModel(firebaseRemoteConfigRepository: FirebaseRemoteConfigRepository): ViewModel() { +@HiltViewModel +class InfoViewModel @Inject constructor( + private val firebaseRemoteConfigRepository: FirebaseRemoteConfigRepository +) : ViewModel() { - val infoList: MutableLiveData> = MutableLiveData() + // StateFlow to hold restaurant info list + private val _infoList = MutableStateFlow>(emptyList()) + val infoList: StateFlow> = _infoList.asStateFlow() - val dodamLocation = MutableLiveData() - val dodamPhotoUrl = MutableLiveData() - val dodamTime = MutableLiveData() - val dodamEtc = MutableLiveData() - - val foodLocation = MutableLiveData() - val foodPhotoUrl = MutableLiveData() - val foodTime = MutableLiveData() - val foodEtc = MutableLiveData() - - val dormitoryLocation = MutableLiveData() - val dormitoryPhotoUrl = MutableLiveData() - val dormitoryTime = MutableLiveData() - val dormitoryEtc = MutableLiveData() - - val snackLocation = MutableLiveData() - val snackPhotoUrl = MutableLiveData() - val snackTime = MutableLiveData() - val snackEtc = MutableLiveData() - - val haksikLocation = MutableLiveData() - val haksikPhotoUrl = MutableLiveData() - val haksikTime = MutableLiveData() - val haksikEtc = MutableLiveData() + // Map to hold restaurant info + private val restaurantInfoMap: MutableMap = mutableMapOf() init { - infoList.value = firebaseRemoteConfigRepository.getCafeteriaInfo() - Log.d("InfoViewModel",infoList.value.toString()) - val dodam = infoList.value!!.find { it.enum == Restaurant.DODAM } - dodamPhotoUrl.value = dodam?.photoUrl ?: "" - dodamTime.value = dodam?.time ?: "" - dodamLocation.value = dodam?.location ?: "" - dodamEtc.value = dodam?.etc ?: "" - - val food = infoList.value!!.find { it.enum == Restaurant.FOOD_COURT } - foodPhotoUrl.value = food?.photoUrl ?: "" - foodTime.value = food?.time ?: "" - foodLocation.value = food?.location ?: "" - foodEtc.value = food?.etc ?: "" - - val dormitory = infoList.value!!.find { it.enum == Restaurant.DORMITORY } - dormitoryPhotoUrl.value = dormitory?.photoUrl ?: "" - dormitoryTime.value = dormitory?.time ?: "" - dormitoryLocation.value = dormitory?.location ?: "" - dormitoryEtc.value = dormitory?.etc ?: "" - - val snack = infoList.value!!.find { it.enum == Restaurant.SNACK_CORNER } - snackPhotoUrl.value = snack?.photoUrl ?: "" - snackTime.value = snack?.time ?: "" - snackLocation.value = snack?.location ?: "" - snackEtc.value = snack?.etc ?: "" + // Load cafeteria info from repository and update the StateFlow + _infoList.value = firebaseRemoteConfigRepository.getCafeteriaInfo() + Log.d("InfoViewModel", _infoList.value.toString()) + _infoList.value.forEach { restaurantInfo -> + restaurantInfoMap[restaurantInfo.enum] = restaurantInfo + } + } - val haksik = infoList.value!!.find { it.enum == Restaurant.HAKSIK } - haksikPhotoUrl.value = haksik?.photoUrl ?: "" - haksikTime.value = haksik?.time ?: "" - haksikLocation.value = haksik?.location ?: "" - haksikEtc.value = haksik?.etc ?: "" + // Helper function to get restaurant details + fun getRestaurantInfo(restaurant: Restaurant): RestaurantInfo? { + return restaurantInfoMap[restaurant] } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/eatssu/android/ui/info/InfoViewModelFactory.kt b/app/src/main/java/com/eatssu/android/ui/info/InfoViewModelFactory.kt deleted file mode 100644 index 1b982232..00000000 --- a/app/src/main/java/com/eatssu/android/ui/info/InfoViewModelFactory.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.eatssu.android.ui.info - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.eatssu.android.data.repository.FirebaseRemoteConfigRepository - -class InfoViewModelFactory(private val repository: FirebaseRemoteConfigRepository) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(InfoViewModel::class.java)) { - @Suppress("UNCHECKED_CAST") - return InfoViewModel(repository) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} - diff --git a/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt b/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt index 8366b4be..435399ec 100644 --- a/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/login/LoginViewModel.kt @@ -1,8 +1,8 @@ package com.eatssu.android.ui.login +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.App import com.eatssu.android.R import com.eatssu.android.data.dto.request.LoginWithKakaoRequest import com.eatssu.android.data.usecase.LoginUseCase @@ -10,6 +10,7 @@ import com.eatssu.android.data.usecase.SetAccessTokenUseCase import com.eatssu.android.data.usecase.SetRefreshTokenUseCase import com.eatssu.android.data.usecase.SetUserEmailUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -28,6 +29,7 @@ class LoginViewModel @Inject constructor( private val setAccessTokenUseCase: SetAccessTokenUseCase, private val setRefreshTokenUseCase: SetRefreshTokenUseCase, private val setUserEmailUseCase: SetUserEmailUseCase, + @ApplicationContext private val context: Context ) : ViewModel() { private val _uiState: MutableStateFlow = MutableStateFlow(LoginState()) @@ -46,7 +48,7 @@ class LoginViewModel @Inject constructor( _uiState.update { it.copy( loading = false, error = false, - toastMessage = App.appContext.getString(R.string.login_done) + toastMessage = context.getString(R.string.login_done) ) //Todo 로그인과 회원가입에 따른 토스트 메시지 구분하기 } diff --git a/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt b/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt index 16571d76..07acdaad 100644 --- a/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt +++ b/app/src/main/java/com/eatssu/android/ui/main/MainViewModel.kt @@ -1,11 +1,12 @@ package com.eatssu.android.ui.main +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eatssu.android.App import com.eatssu.android.R import com.eatssu.android.data.usecase.GetUserInfoUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -21,6 +22,7 @@ import javax.inject.Inject @HiltViewModel class MainViewModel @Inject constructor( private val getUserInfoUseCase: GetUserInfoUseCase, + @ApplicationContext private val context: Context ) : ViewModel() { private val _uiState: MutableStateFlow = MutableStateFlow(MainState()) @@ -40,7 +42,7 @@ class MainViewModel @Inject constructor( _uiState.update { it.copy( error = true, - toastMessage = App.appContext.getString(R.string.not_found) + toastMessage = context.getString(R.string.not_found) ) } Timber.e(e.toString()) @@ -51,7 +53,7 @@ class MainViewModel @Inject constructor( _uiState.update { it.copy( isNicknameNull = true, - toastMessage = App.appContext.getString(R.string.set_nickname) + toastMessage = context.getString(R.string.set_nickname) ) } } else { @@ -59,7 +61,7 @@ class MainViewModel @Inject constructor( it.copy( isNicknameNull = false, toastMessage = String.format( - App.appContext.getString(R.string.hello_user), + context.getString(R.string.hello_user), this.nickname ) ) diff --git a/app/src/main/java/com/eatssu/android/ui/main/menu/MenuAdapter.kt b/app/src/main/java/com/eatssu/android/ui/main/menu/MenuAdapter.kt index da7f67e6..a7e0c34a 100644 --- a/app/src/main/java/com/eatssu/android/ui/main/menu/MenuAdapter.kt +++ b/app/src/main/java/com/eatssu/android/ui/main/menu/MenuAdapter.kt @@ -27,8 +27,7 @@ class MenuAdapter( sectionModel: Section ) { - - binding.btnInfo.setOnClickListener { + binding.llCafeteriaInfo.setOnClickListener { val modalBottomSheet = InfoBottomSheetFragment.newInstance(sectionModel.cafeteria.name) diff --git a/app/src/main/java/com/eatssu/android/ui/main/menu/MenuFragment.kt b/app/src/main/java/com/eatssu/android/ui/main/menu/MenuFragment.kt index 9a96b5df..09686888 100644 --- a/app/src/main/java/com/eatssu/android/ui/main/menu/MenuFragment.kt +++ b/app/src/main/java/com/eatssu/android/ui/main/menu/MenuFragment.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.RequiresApi import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager @@ -17,12 +18,10 @@ import com.eatssu.android.data.enums.MenuType import com.eatssu.android.data.enums.Restaurant import com.eatssu.android.data.enums.Time import com.eatssu.android.data.model.Section -import com.eatssu.android.data.repository.FirebaseRemoteConfigRepository import com.eatssu.android.data.service.MealService import com.eatssu.android.data.service.MenuService import com.eatssu.android.databinding.FragmentMenuBinding import com.eatssu.android.ui.info.InfoViewModel -import com.eatssu.android.ui.info.InfoViewModelFactory import com.eatssu.android.ui.main.calendar.CalendarViewModel import com.eatssu.android.util.RetrofitImpl import java.time.DayOfWeek @@ -51,9 +50,9 @@ class MenuFragment : Fragment() { private val totalMenuList = ArrayList
() - private lateinit var infoViewModel: InfoViewModel private lateinit var restaurantType: Restaurant - private lateinit var firebaseRemoteConfigRepository: FirebaseRemoteConfigRepository + + private val infoViewModel: InfoViewModel by activityViewModels() companion object { @@ -75,13 +74,6 @@ class MenuFragment : Fragment() { savedInstanceState: Bundle?, ): View { _binding = FragmentMenuBinding.inflate(inflater, container, false) - - firebaseRemoteConfigRepository = FirebaseRemoteConfigRepository() - infoViewModel = ViewModelProvider( - this, - InfoViewModelFactory(firebaseRemoteConfigRepository) - )[InfoViewModel::class.java] - return binding.root } @@ -92,11 +84,6 @@ class MenuFragment : Fragment() { observeViewModel() } - override fun onResume() { - super.onResume() - - } - @RequiresApi(Build.VERSION_CODES.O) fun observeViewModel() { menuService = RetrofitImpl.retrofit.create(MenuService::class.java) @@ -145,7 +132,8 @@ class MenuFragment : Fragment() { MenuType.FIXED, Restaurant.FOOD_COURT, result.mapFixedMenuResponseToMenu(), - infoViewModel.foodLocation.value.toString() + infoViewModel.getRestaurantInfo(Restaurant.FOOD_COURT)?.location + ?: "" ) ) } @@ -163,7 +151,8 @@ class MenuFragment : Fragment() { MenuType.FIXED, Restaurant.SNACK_CORNER, result.mapFixedMenuResponseToMenu(), - infoViewModel.snackLocation.value.toString() + infoViewModel.getRestaurantInfo(Restaurant.SNACK_CORNER)?.location + ?: "" ) ) } @@ -198,7 +187,7 @@ class MenuFragment : Fragment() { MenuType.VARIABLE, Restaurant.HAKSIK, result.mapTodayMenuResponseToMenu(), - infoViewModel.haksikLocation.value.toString() + infoViewModel.getRestaurantInfo(Restaurant.HAKSIK)?.location ?: "" ) ) @@ -217,7 +206,7 @@ class MenuFragment : Fragment() { MenuType.VARIABLE, Restaurant.DODAM, result.mapTodayMenuResponseToMenu(), - infoViewModel.dodamLocation.value.toString() + infoViewModel.getRestaurantInfo(Restaurant.DODAM)?.location ?: "" ) ) } @@ -234,7 +223,7 @@ class MenuFragment : Fragment() { MenuType.VARIABLE, Restaurant.DORMITORY, result.mapTodayMenuResponseToMenu(), - infoViewModel.dormitoryLocation.value.toString() + infoViewModel.getRestaurantInfo(Restaurant.DORMITORY)?.location ?: "" ) ) } diff --git a/app/src/main/res/drawable/img_logo_512.png b/app/src/main/res/drawable/img_logo_512.png new file mode 100644 index 0000000000000000000000000000000000000000..e70b51706395b707aa758d9bfdace4bb2673184d GIT binary patch literal 8232 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 + + + + + diff --git a/app/src/main/res/xml/firebase_remote_config.xml b/app/src/main/res/xml/firebase_remote_config.xml index 148997e5..af102769 100644 --- a/app/src/main/res/xml/firebase_remote_config.xml +++ b/app/src/main/res/xml/firebase_remote_config.xml @@ -18,6 +18,7 @@ cafeteria_information + [ { "enum": "DODAM", "name": "도담 식당", @@ -25,17 +26,16 @@ "time": "11:20~14:00(점심)\n17:00~18:30(저녁)", "etc": "2개 코너 운영\n대면 배식,웰빙코너\n토요일 11:30~13:30", "image": - "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/04f266a1-0649-430c-af8f-29e83e87472120240823074119%E1%84%83%E1%85%A9%E1%84%83%E1%85%A1%E1%86%B7%E1%84%89%E1%85%B5%E1%86%A8%E1%84%83%E1%85%A1%E1%86%BC.jpeg" + "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/298437cb-45b1-48cf-bace-ea84e8f23e1820240926041857%E1%84%83%E1%85%A9%E1%84%83%E1%85%A1%E1%86%B7IMG_8268%20%E1%84%8F%E1%85%B3%E1%84%80%E1%85%A6.jpeg" }, { "enum": "HAKSIK", "name": "학생 식당", "location": "학생회관 3층", - "time": "08:10~09:20(천원의 아침밥, 100개 한정, - 24.03.11~06.14)\n11:20~14:00\n(점심)\n14:00~17:00(공간 개방)", + "time": "08:10~09:20(천원의 아침밥, 100개 한정)\n11:20~14:00\n(점심)\n14:00~17:00(공간 개방)", "etc": "3개 코너 운영\n뚝배기찌개, 덮밥, 양식", "image": - "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/f0fbf458-5f7e-49bb-97e7-c663c4ec8cc820240823074519%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%A2%E1%86%BC%E1%84%89%E1%85%B5%E1%86%A8%E1%84%83%E1%85%A1%E1%86%BC.jpeg" + "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/fa802164-621d-4b6d-b44e-e9de4bab225520240926041948%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%A2%E1%86%BC%20IMG_0394%20%E1%84%8F%E1%85%B3%E1%84%80%E1%85%A6.jpeg" }, { "enum": "SNACK_CORNER", @@ -53,7 +53,7 @@ "time": "휴무", "etc": "준비 중", "image": - "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/2f8a9ae2-c2f9-4f20-bafe-28e0a9e414e320240823074451%E1%84%91%E1%85%AE%E1%84%83%E1%85%B3%E1%84%8F%E1%85%A9%E1%84%90%E1%85%B3.jpeg" + "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/09b487f5-e431-4ab2-a339-76e472ea8d8320240926041925%E1%84%91%E1%85%AE%E1%84%8F%E1%85%A9IMG_0396%20%E1%84%8F%E1%85%B3%E1%84%80%E1%85%A6.jpeg" }, { "enum": "DORMITORY", @@ -62,8 +62,9 @@ "time": "08:00~09:30\n11:00~14:00\n17:00~18:30", "etc": "주말 조식은 운영되지 않습니다.", "image": - "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/2f8a9ae2-c2f9-4f20-bafe-28e0a9e414e320240823074451%E1%84%91%E1%85%AE%E1%84%83%E1%85%B3%E1%84%8F%E1%85%A9%E1%84%90%E1%85%B3.jpeg" + "https://eatssu-prod-bucket.s3.ap-northeast-2.amazonaws.com/reviewImg/364077d5-f09b-4e9c-b5e4-e1e08d098f1820240926041231%E1%84%80%E1%85%B5%E1%84%89%E1%85%AE%E1%86%A8%E1%84%89%E1%85%A1IMG_2480%20%E1%84%8F%E1%85%B3%E1%84%80%E1%85%A6.jpeg" } + ]