From 14e97aca313c816a8ee89eb2ee23a92b6ed30ae7 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Sun, 21 Jan 2024 15:37:59 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EC=97=91=EC=85=80=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/susu/data/data/di/RepositoryModule.kt | 7 ++++ .../data/repository/ExcelRepositoryImpl.kt | 29 +++++++++++++++++ .../com/susu/data/remote/di/ExcelModule.kt | 21 ++++++++++++ .../susu/domain/repository/ExcelRepository.kt | 5 +++ .../usecase/mypage/DownloadExcelUseCase.kt | 13 ++++++++ .../feature/mypage/main/MyPageViewModel.kt | 8 ++++- .../susu/feature/navigator/MainActivity.kt | 32 +++++++++++++++++++ 7 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt create mode 100644 data/src/main/java/com/susu/data/remote/di/ExcelModule.kt create mode 100644 domain/src/main/java/com/susu/domain/repository/ExcelRepository.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/mypage/DownloadExcelUseCase.kt diff --git a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt index 4f9ed96f..9eaffd4a 100644 --- a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt +++ b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt @@ -1,6 +1,7 @@ package com.susu.data.data.di import com.susu.data.data.repository.CategoryConfigRepositoryImpl +import com.susu.data.data.repository.ExcelRepositoryImpl import com.susu.data.data.repository.LedgerRecentSearchRepositoryImpl import com.susu.data.data.repository.LedgerRepositoryImpl import com.susu.data.data.repository.LoginRepositoryImpl @@ -9,6 +10,7 @@ import com.susu.data.data.repository.TermRepositoryImpl import com.susu.data.data.repository.TokenRepositoryImpl import com.susu.data.data.repository.UserRepositoryImpl import com.susu.domain.repository.CategoryConfigRepository +import com.susu.domain.repository.ExcelRepository import com.susu.domain.repository.LedgerRecentSearchRepository import com.susu.domain.repository.LedgerRepository import com.susu.domain.repository.LoginRepository @@ -64,4 +66,9 @@ abstract class RepositoryModule { abstract fun bindUserRepository( userRepositoryImpl: UserRepositoryImpl, ): UserRepository + + @Binds + abstract fun bindExcelRepository( + excelRepositoryImpl: ExcelRepositoryImpl, + ): ExcelRepository } diff --git a/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt new file mode 100644 index 00000000..cb614722 --- /dev/null +++ b/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt @@ -0,0 +1,29 @@ +package com.susu.data.data.repository + +import android.app.DownloadManager +import android.os.Environment +import androidx.core.net.toUri +import com.susu.domain.repository.ExcelRepository +import com.susu.domain.repository.TokenRepository +import kotlinx.coroutines.flow.firstOrNull +import javax.inject.Inject + +class ExcelRepositoryImpl @Inject constructor( + private val downloadManager: DownloadManager, + private val tokenRepository: TokenRepository, +) : ExcelRepository { + override suspend fun downloadEnvelopExcel(): Long { + val token = tokenRepository.getAccessToken().firstOrNull() ?: return -1L + val url = "https://api.oksusu.site/api/v1/excel/all-envelopes" + + val request = DownloadManager.Request(url.toUri()) + .setMimeType("application/vnd.ms-excel") + .setAllowedOverMetered(true) + .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) + .setTitle("수수") + .addRequestHeader("X-SUSU-AUTH-TOKEN", token) + .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "수수_기록.xlsx") + + return downloadManager.enqueue(request) + } +} diff --git a/data/src/main/java/com/susu/data/remote/di/ExcelModule.kt b/data/src/main/java/com/susu/data/remote/di/ExcelModule.kt new file mode 100644 index 00000000..3fbddb11 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/di/ExcelModule.kt @@ -0,0 +1,21 @@ +package com.susu.data.remote.di + +import android.app.DownloadManager +import android.content.Context +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object ExcelModule { + + @Provides + @Singleton + fun providesDownloadManager(@ApplicationContext context: Context): DownloadManager { + return context.getSystemService(DownloadManager::class.java) + } +} diff --git a/domain/src/main/java/com/susu/domain/repository/ExcelRepository.kt b/domain/src/main/java/com/susu/domain/repository/ExcelRepository.kt new file mode 100644 index 00000000..f6093033 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/repository/ExcelRepository.kt @@ -0,0 +1,5 @@ +package com.susu.domain.repository + +interface ExcelRepository { + suspend fun downloadEnvelopExcel(): Long +} diff --git a/domain/src/main/java/com/susu/domain/usecase/mypage/DownloadExcelUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/mypage/DownloadExcelUseCase.kt new file mode 100644 index 00000000..81f47590 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/mypage/DownloadExcelUseCase.kt @@ -0,0 +1,13 @@ +package com.susu.domain.usecase.mypage + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.ExcelRepository +import javax.inject.Inject + +class DownloadExcelUseCase @Inject constructor( + private val excelRepository: ExcelRepository, +) { + suspend operator fun invoke() = runCatchingIgnoreCancelled { + excelRepository.downloadEnvelopExcel() + } +} diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageViewModel.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageViewModel.kt index a09deb9d..10096a3f 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageViewModel.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageViewModel.kt @@ -5,6 +5,7 @@ import com.kakao.sdk.auth.TokenManagerProvider import com.kakao.sdk.user.UserApiClient import com.susu.core.model.exception.UserNotFoundException import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.mypage.DownloadExcelUseCase import com.susu.domain.usecase.mypage.GetUserUseCase import com.susu.domain.usecase.mypage.LogoutUseCase import com.susu.domain.usecase.mypage.WithdrawUseCase @@ -17,6 +18,7 @@ class MyPageViewModel @Inject constructor( private val logoutUseCase: LogoutUseCase, private val withdrawUseCase: WithdrawUseCase, private val getUserUseCase: GetUserUseCase, + private val downloadExcelUseCase: DownloadExcelUseCase, ) : BaseViewModel(MyPageState()) { init { @@ -72,6 +74,10 @@ class MyPageViewModel @Inject constructor( } fun export() { - postSideEffect(MyPageEffect.ShowExportSuccessSnackbar) + viewModelScope.launch { + downloadExcelUseCase().onFailure { + postSideEffect(MyPageEffect.HandleException(it, ::export)) + } + } } } diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt index 8eb4e5ee..45747887 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt @@ -1,5 +1,10 @@ package com.susu.feature.navigator +import android.app.DownloadManager +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -11,9 +16,11 @@ import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.ui.Modifier +import androidx.core.content.ContextCompat import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.SnackbarToken import com.susu.feature.loginsignup.social.KakaoLoginHelper import dagger.hilt.android.AndroidEntryPoint @@ -24,6 +31,8 @@ class MainActivity : ComponentActivity() { private val uiState get() = viewModel.uiState.value + private lateinit var broadcastReceiver: BroadcastReceiver + override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() super.onCreate(savedInstanceState) @@ -45,6 +54,24 @@ class MainActivity : ComponentActivity() { WindowCompat.setDecorFitsSystemWindows(window, false) + broadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent?) { + if (intent?.action == "android.intent.action.DOWNLOAD_COMPLETE") { + val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1L) + if (id != -1L) { + viewModel.onShowSnackbar(SnackbarToken(message = context.getString(com.susu.feature.mypage.R.string.snackbar_success_export))) + } + } + } + } + + ContextCompat.registerReceiver( + this, + broadcastReceiver, + IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), + ContextCompat.RECEIVER_EXPORTED, + ) + setContent { SusuTheme { MainScreen( @@ -60,4 +87,9 @@ class MainActivity : ComponentActivity() { } } } + + override fun onDestroy() { + super.onDestroy() + unregisterReceiver(broadcastReceiver) + } } From c085915b0b4fdb4292b2c9dc433e05f82230eea5 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Sun, 21 Jan 2024 17:07:34 +0900 Subject: [PATCH 2/4] =?UTF-8?q?chore:=20=ED=95=98=EB=93=9C=EC=BD=94?= =?UTF-8?q?=EB=94=A9=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/src/main/java/com/susu/core/ui/Consts.kt | 2 ++ .../data/data/repository/ExcelRepositoryImpl.kt | 17 ++++++++++++----- .../com/susu/feature/navigator/MainActivity.kt | 3 ++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 5242f62e..3df5e883 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -18,6 +18,8 @@ val alignList const val USER_NAME_MAX_LENGTH = 10 val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") +const val INTENT_ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE" + enum class SnsProviders( val path: String, @StringRes val nameId: Int, diff --git a/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt index cb614722..c4b6042c 100644 --- a/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt @@ -14,16 +14,23 @@ class ExcelRepositoryImpl @Inject constructor( ) : ExcelRepository { override suspend fun downloadEnvelopExcel(): Long { val token = tokenRepository.getAccessToken().firstOrNull() ?: return -1L - val url = "https://api.oksusu.site/api/v1/excel/all-envelopes" val request = DownloadManager.Request(url.toUri()) - .setMimeType("application/vnd.ms-excel") + .setMimeType(mimeType) .setAllowedOverMetered(true) .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) - .setTitle("수수") - .addRequestHeader("X-SUSU-AUTH-TOKEN", token) - .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "수수_기록.xlsx") + .setTitle(downloaderName) + .addRequestHeader(headerTokenName, token) + .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName) return downloadManager.enqueue(request) } + + companion object { + private const val url = "https://api.oksusu.site/api/v1/excel/all-envelopes" + private const val mimeType = "application/vnd.ms-excel" + private const val downloaderName = "수수" + private const val headerTokenName = "X-SUSU-AUTH-TOKEN" + private const val fileName = "수수_기록.xlsx" + } } diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt index 45747887..6e002707 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt @@ -20,6 +20,7 @@ import androidx.core.content.ContextCompat import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.INTENT_ACTION_DOWNLOAD_COMPLETE import com.susu.core.ui.SnackbarToken import com.susu.feature.loginsignup.social.KakaoLoginHelper import dagger.hilt.android.AndroidEntryPoint @@ -56,7 +57,7 @@ class MainActivity : ComponentActivity() { broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent?) { - if (intent?.action == "android.intent.action.DOWNLOAD_COMPLETE") { + if (intent?.action == INTENT_ACTION_DOWNLOAD_COMPLETE) { val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1L) if (id != -1L) { viewModel.onShowSnackbar(SnackbarToken(message = context.getString(com.susu.feature.mypage.R.string.snackbar_success_export))) From 163ccc7d5064e2c7431e19c113cb873a022e1b45 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Sun, 21 Jan 2024 17:08:02 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=EC=97=91=EC=85=80=EB=A1=9C=20?= =?UTF-8?q?=EB=82=B4=EB=B3=B4=EB=82=B4=EA=B8=B0=20dialog=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=EC=97=90=20=EA=B2=BD=EB=A1=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt | 3 ++- feature/mypage/src/main/res/values/strings.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt index 1309c005..da34cbd4 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/main/MyPageDefaultScreen.kt @@ -1,5 +1,6 @@ package com.susu.feature.mypage.main +import android.os.Environment import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -78,7 +79,7 @@ fun MyPageDefaultRoute( onShowDialog( DialogToken( title = context.getString(com.susu.feature.mypage.R.string.dialog_export_title), - text = context.getString(com.susu.feature.mypage.R.string.dialog_export_detail), + text = context.getString(com.susu.feature.mypage.R.string.dialog_export_detail, Environment.DIRECTORY_DOWNLOADS), dismissText = context.getString(R.string.word_cancel), confirmText = context.getString(com.susu.feature.mypage.R.string.dialog_export_confirm), onConfirmRequest = viewModel::export, diff --git a/feature/mypage/src/main/res/values/strings.xml b/feature/mypage/src/main/res/values/strings.xml index 5e848ebc..ffc84c9c 100644 --- a/feature/mypage/src/main/res/values/strings.xml +++ b/feature/mypage/src/main/res/values/strings.xml @@ -3,7 +3,7 @@ 로그아웃 할까요? 로그아웃 엑셀로 내보낼까요? - 모든 기록을 엑셀로 저장해요. 파일은 (경로)에서 확인할 수 있어요. + 모든 기록을 엑셀로 저장해요. 파일은 %s에서 확인할 수 있어요. 내보내기 정말 탈퇴하시겠어요? 계정 정보와 모든 기록이 삭제되며 다시 복구할 수 없어요 From d86f0d7f93a2b1e35d5cd3cdb4837fbcf6a329d4 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Sun, 21 Jan 2024 18:33:16 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=EC=97=91=EC=85=80=20=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=EB=A1=9C=EB=93=9C=20=EC=8B=9C=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EC=9D=84=20=EB=95=8C=20Exception=EC=9D=84?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=EC=8B=9C=ED=82=A4=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/data/data/repository/ExcelRepositoryImpl.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt index c4b6042c..4a3fce19 100644 --- a/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt +++ b/data/src/main/java/com/susu/data/data/repository/ExcelRepositoryImpl.kt @@ -3,6 +3,7 @@ package com.susu.data.data.repository import android.app.DownloadManager import android.os.Environment import androidx.core.net.toUri +import com.susu.core.model.exception.UnknownException import com.susu.domain.repository.ExcelRepository import com.susu.domain.repository.TokenRepository import kotlinx.coroutines.flow.firstOrNull @@ -13,7 +14,7 @@ class ExcelRepositoryImpl @Inject constructor( private val tokenRepository: TokenRepository, ) : ExcelRepository { override suspend fun downloadEnvelopExcel(): Long { - val token = tokenRepository.getAccessToken().firstOrNull() ?: return -1L + val token = tokenRepository.getAccessToken().firstOrNull() ?: throw UnknownException() val request = DownloadManager.Request(url.toUri()) .setMimeType(mimeType)