From 8111f669b8d8fab64d1938978de1bb8db88f1efd Mon Sep 17 00:00:00 2001 From: ii2001 Date: Thu, 1 Aug 2024 15:52:46 +0900 Subject: [PATCH] :recycle: ktFormating --- .../DefaultMakingRecipeRemoteDataSource.kt | 8 +- .../MakingRecipeRemoteDataSource.kt | 6 +- .../data/remote/api/MakingRecipeService.kt | 7 +- .../makingrecipe/MakingRecipeRepository.kt | 6 +- .../android/presentation/MainActivity.kt | 8 +- .../presentation/core/util/FileUtils.kt | 5 +- .../making/RecipeMakingFragment.kt | 135 ++++++++++-------- .../making/RecipeMakingViewModel.kt | 6 +- .../making/RecipeMakingViewModelFactory.kt | 2 +- .../listener/RecipeMakingEventListener.kt | 1 + .../app/src/main/res/navigation/nav_graph.xml | 2 +- .../presenter/RecipeMakingViewModelTest.kt | 92 ++++++------ 12 files changed, 159 insertions(+), 119 deletions(-) diff --git a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeRemoteDataSource.kt b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeRemoteDataSource.kt index 0b120648..646b5563 100644 --- a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeRemoteDataSource.kt +++ b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeRemoteDataSource.kt @@ -6,9 +6,8 @@ import okhttp3.RequestBody.Companion.asRequestBody import java.io.File class DefaultMakingRecipeRemoteDataSource( - private val makingRecipeService: MakingRecipeService + private val makingRecipeService: MakingRecipeService, ) : MakingRecipeRemoteDataSource { - override suspend fun fetchImageUri(keyName: String): String { val response = makingRecipeService.fetchImageUri(keyName) if (response.isSuccessful) { @@ -18,7 +17,10 @@ class DefaultMakingRecipeRemoteDataSource( } } - override suspend fun uploadImageToS3(presignedUrl: String, file: File) { + override suspend fun uploadImageToS3( + presignedUrl: String, + file: File, + ) { val requestFile = file.asRequestBody("image/jpeg".toMediaTypeOrNull()) val response = makingRecipeService.uploadImageToS3(presignedUrl, requestFile) if (!response.isSuccessful) { diff --git a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeRemoteDataSource.kt b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeRemoteDataSource.kt index 72e0d5c8..620357c5 100644 --- a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeRemoteDataSource.kt +++ b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeRemoteDataSource.kt @@ -4,5 +4,9 @@ import java.io.File interface MakingRecipeRemoteDataSource { suspend fun fetchImageUri(keyName: String): String - suspend fun uploadImageToS3(presignedUrl: String, file: File) + + suspend fun uploadImageToS3( + presignedUrl: String, + file: File, + ) } diff --git a/android/app/src/main/java/net/pengcook/android/data/remote/api/MakingRecipeService.kt b/android/app/src/main/java/net/pengcook/android/data/remote/api/MakingRecipeService.kt index c0a07efc..da020dba 100644 --- a/android/app/src/main/java/net/pengcook/android/data/remote/api/MakingRecipeService.kt +++ b/android/app/src/main/java/net/pengcook/android/data/remote/api/MakingRecipeService.kt @@ -9,19 +9,18 @@ import retrofit2.http.Query import retrofit2.http.Url interface MakingRecipeService { - @GET("/image") suspend fun fetchImageUri( - @Query("keyName") keyName: String + @Query("keyName") keyName: String, ): Response @PUT suspend fun uploadImageToS3( @Url url: String, - @Body image: RequestBody + @Body image: RequestBody, ): Response } data class PresignedUrlResponse( - val url: String + val url: String, ) diff --git a/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/MakingRecipeRepository.kt b/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/MakingRecipeRepository.kt index 33a5d4b0..e3bd6c82 100644 --- a/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/MakingRecipeRepository.kt +++ b/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/MakingRecipeRepository.kt @@ -4,12 +4,14 @@ import net.pengcook.android.data.datasource.makingrecipe.MakingRecipeRemoteDataS import java.io.File class MakingRecipeRepository(private val remoteDataSource: MakingRecipeRemoteDataSource) { - suspend fun fetchImageUri(keyName: String): String { return remoteDataSource.fetchImageUri(keyName) } - suspend fun uploadImageToS3(presignedUrl: String, file: File) { + suspend fun uploadImageToS3( + presignedUrl: String, + file: File, + ) { remoteDataSource.uploadImageToS3(presignedUrl, file) } } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/MainActivity.kt b/android/app/src/main/java/net/pengcook/android/presentation/MainActivity.kt index 180573c3..a967b12e 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/MainActivity.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/MainActivity.kt @@ -10,6 +10,9 @@ import net.pengcook.android.R class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + + // Security.insertProviderAt(Conscrypt.newProvider(), 1) + setContentView(R.layout.activity_main) val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment @@ -21,7 +24,10 @@ class MainActivity : AppCompatActivity() { navController.addOnDestinationChangedListener { _, destination, _ -> when (destination.id) { - R.id.homeFragment, R.id.searchFragment, R.id.profileFragment, R.id.categoryFragment -> bottomNav.visibility = View.VISIBLE + R.id.homeFragment, R.id.searchFragment, R.id.profileFragment, R.id.categoryFragment -> + bottomNav.visibility = + View.VISIBLE + else -> bottomNav.visibility = View.GONE } } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/core/util/FileUtils.kt b/android/app/src/main/java/net/pengcook/android/presentation/core/util/FileUtils.kt index 03e6b499..994eb7be 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/core/util/FileUtils.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/core/util/FileUtils.kt @@ -6,7 +6,10 @@ import android.net.Uri import android.provider.MediaStore object FileUtils { - fun getPathFromUri(context: Context, uri: Uri): String? { + fun getPathFromUri( + context: Context, + uri: Uri, + ): String? { val projection = arrayOf(MediaStore.Images.Media.DATA) val cursor: Cursor? = context.contentResolver.query(uri, projection, null, null, null) cursor?.use { diff --git a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt index 0b634096..2f6860d3 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt @@ -26,7 +26,7 @@ import retrofit2.converter.gson.GsonConverterFactory import java.io.File import java.io.IOException import java.text.SimpleDateFormat -import java.util.* +import java.util.Date class RecipeMakingFragment : Fragment() { private var _binding: FragmentRecipeMakingBinding? = null @@ -34,10 +34,11 @@ class RecipeMakingFragment : Fragment() { get() = _binding!! private val viewModel: RecipeMakingViewModel by viewModels { - val retrofit = Retrofit.Builder() - .baseUrl(BuildConfig.BASE_URL) - .addConverterFactory(GsonConverterFactory.create()) - .build() + val retrofit = + Retrofit.Builder() + .baseUrl(BuildConfig.BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() val makingRecipeService = retrofit.create(MakingRecipeService::class.java) val remoteDataSource = DefaultMakingRecipeRemoteDataSource(makingRecipeService) @@ -50,46 +51,49 @@ class RecipeMakingFragment : Fragment() { private val permissionArray = arrayOf( - Manifest.permission.CAMERA + Manifest.permission.CAMERA, ) - private val requestPermissionLauncher = registerForActivityResult( - ActivityResultContracts.RequestPermission() - ) { isGranted: Boolean -> - if (isGranted) { - Toast.makeText(requireContext(), "카메라 권한이 허용되어 있습니다.", Toast.LENGTH_SHORT).show() - showImageSourceDialog() - } else { - Toast.makeText(requireContext(), "카메라 권한이 필요합니다.", Toast.LENGTH_SHORT).show() + private val requestPermissionLauncher = + registerForActivityResult( + ActivityResultContracts.RequestPermission(), + ) { isGranted: Boolean -> + if (isGranted) { + Toast.makeText(requireContext(), "카메라 권한이 허용되어 있습니다.", Toast.LENGTH_SHORT).show() + showImageSourceDialog() + } else { + Toast.makeText(requireContext(), "카메라 권한이 필요합니다.", Toast.LENGTH_SHORT).show() + } } - } - private val getContentLauncher = registerForActivityResult( - ActivityResultContracts.GetContent() - ) { uri: Uri? -> - uri?.let { - photoUri = it - currentPhotoPath = FileUtils.getPathFromUri(requireContext(), it) - if (currentPhotoPath != null) { - viewModel.fetchImageUri(File(currentPhotoPath!!).name) - } else { + private val getContentLauncher = + registerForActivityResult( + ActivityResultContracts.GetContent(), + ) { uri: Uri? -> + uri?.let { + photoUri = it + currentPhotoPath = FileUtils.getPathFromUri(requireContext(), it) + if (currentPhotoPath != null) { + viewModel.fetchImageUri(File(currentPhotoPath!!).name) + } else { + Toast.makeText(requireContext(), "이미지 선택에 실패했습니다.", Toast.LENGTH_SHORT).show() + } + } ?: run { Toast.makeText(requireContext(), "이미지 선택에 실패했습니다.", Toast.LENGTH_SHORT).show() } - } ?: run { - Toast.makeText(requireContext(), "이미지 선택에 실패했습니다.", Toast.LENGTH_SHORT).show() } - } // 사진 촬영 ActivityResultLauncher - private val takePictureLauncher = registerForActivityResult( - ActivityResultContracts.TakePicture() - ) { success -> - if (success) { - viewModel.fetchImageUri(File(currentPhotoPath!!).name) - } else { - Toast.makeText(requireContext(), "사진을 찍는데 실패했습니다.", Toast.LENGTH_SHORT).show() + private val takePictureLauncher = + registerForActivityResult( + ActivityResultContracts.TakePicture(), + ) { success -> + if (success) { + viewModel.fetchImageUri(File(currentPhotoPath!!).name) + } else { + Toast.makeText(requireContext(), "사진을 찍는데 실패했습니다.", Toast.LENGTH_SHORT).show() + } } - } override fun onCreateView( inflater: LayoutInflater, @@ -115,36 +119,46 @@ class RecipeMakingFragment : Fragment() { } // Observer to handle the pre-signed URL response - viewModel.imageUri.observe(viewLifecycleOwner, Observer { uri -> - if (uri != null) { - uploadImageToS3(uri) - } - }) + viewModel.imageUri.observe( + viewLifecycleOwner, + Observer { uri -> + if (uri != null) { + uploadImageToS3(uri) + } + }, + ) // Observer to handle the upload success - viewModel.uploadSuccess.observe(viewLifecycleOwner, Observer { success -> - if (success == true) { - Toast.makeText(requireContext(), "이미지 업로드 성공!", Toast.LENGTH_SHORT).show() - } else if (success == false) { - Toast.makeText(requireContext(), "이미지 업로드 실패!", Toast.LENGTH_SHORT).show() - } - }) + viewModel.uploadSuccess.observe( + viewLifecycleOwner, + Observer { success -> + if (success == true) { + Toast.makeText(requireContext(), "이미지 업로드 성공!", Toast.LENGTH_SHORT).show() + } else if (success == false) { + Toast.makeText(requireContext(), "이미지 업로드 실패!", Toast.LENGTH_SHORT).show() + } + }, + ) // Observer to handle upload error - viewModel.uploadError.observe(viewLifecycleOwner, Observer { errorMessage -> - if (errorMessage != null) { - Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show() - } - }) + viewModel.uploadError.observe( + viewLifecycleOwner, + Observer { errorMessage -> + if (errorMessage != null) { + Toast.makeText(requireContext(), errorMessage, Toast.LENGTH_SHORT).show() + } + }, + ) } private fun onAddImageClicked() { if (permissionArray.all { ContextCompat.checkSelfPermission( requireContext(), - it + it, ) == PackageManager.PERMISSION_GRANTED - }) { + } + ) { showImageSourceDialog() } else { requestPermissionLauncher.launch(Manifest.permission.CAMERA) @@ -166,11 +180,12 @@ class RecipeMakingFragment : Fragment() { private fun takePicture() { val photoFile: File = createImageFile() - photoUri = FileProvider.getUriForFile( - requireContext(), - "net.pengcook.android.fileprovider", - photoFile - ) + photoUri = + FileProvider.getUriForFile( + requireContext(), + "net.pengcook.android.fileprovider", + photoFile, + ) takePictureLauncher.launch(photoUri) } @@ -185,7 +200,7 @@ class RecipeMakingFragment : Fragment() { return File.createTempFile( "JPEG_${timeStamp}_", ".jpg", - storageDir + storageDir, ).apply { currentPhotoPath = absolutePath } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt index 29ec0198..41087709 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt @@ -55,7 +55,10 @@ class RecipeMakingViewModel(private val makingRecipeRepository: MakingRecipeRepo } // Function to upload image to S3 - fun uploadImageToS3(presignedUrl: String, file: File) { + fun uploadImageToS3( + presignedUrl: String, + file: File, + ) { viewModelScope.launch { try { makingRecipeRepository.uploadImageToS3(presignedUrl, file) @@ -71,5 +74,6 @@ class RecipeMakingViewModel(private val makingRecipeRepository: MakingRecipeRepo sealed interface MakingEvent { data object NavigateToMakingStep : MakingEvent + data object AddImage : MakingEvent } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModelFactory.kt b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModelFactory.kt index ff038a55..0cfd055b 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModelFactory.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModelFactory.kt @@ -10,7 +10,7 @@ class RecipeMakingViewModelFactory(private val makingRecipeRepository: MakingRec override fun create(modelClass: Class): T { if (modelClass.isAssignableFrom(RecipeMakingViewModel::class.java)) { return RecipeMakingViewModel( - makingRecipeRepository = makingRecipeRepository + makingRecipeRepository = makingRecipeRepository, ) as T } else { throw IllegalArgumentException() diff --git a/android/app/src/main/java/net/pengcook/android/presentation/making/listener/RecipeMakingEventListener.kt b/android/app/src/main/java/net/pengcook/android/presentation/making/listener/RecipeMakingEventListener.kt index 608ce1a4..39f2e290 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/making/listener/RecipeMakingEventListener.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/making/listener/RecipeMakingEventListener.kt @@ -2,5 +2,6 @@ package net.pengcook.android.presentation.making.listener interface RecipeMakingEventListener { fun onNavigateToMakingStep() + fun onAddImage() } diff --git a/android/app/src/main/res/navigation/nav_graph.xml b/android/app/src/main/res/navigation/nav_graph.xml index 030b18b6..7e5ad3c8 100644 --- a/android/app/src/main/res/navigation/nav_graph.xml +++ b/android/app/src/main/res/navigation/nav_graph.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" - app:startDestination="@id/recipeMakingFragment"> + app:startDestination="@id/homeFragment">