feat: 커뮤니티 글쓰기/수정
- 이미지 gif 등록 기능 추가
This commit is contained in:
@@ -2,18 +2,24 @@ package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
import com.gun0912.tedpermission.PermissionListener
|
||||
import com.gun0912.tedpermission.normal.TedPermission
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
@@ -26,6 +32,7 @@ import kr.co.vividnext.sodalive.databinding.ActivityCreatorCommunityModifyBindin
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.io.File
|
||||
|
||||
class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModifyBinding>(
|
||||
ActivityCreatorCommunityModifyBinding::inflate
|
||||
@@ -34,8 +41,9 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
|
||||
private val viewModel: CreatorCommunityModifyViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var croppedTempFile: File
|
||||
|
||||
private val imageResult = registerForActivityResult(
|
||||
private val imageCropResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
@@ -45,25 +53,116 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
|
||||
val fileUri = data?.data
|
||||
|
||||
if (fileUri != null) {
|
||||
binding.ivContent.background = null
|
||||
binding.ivContent.load(fileUri) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(RoundedCornersTransformation(8f.dpToPx()))
|
||||
}
|
||||
viewModel.imageUri = fileUri
|
||||
handleCroppedImage(fileUri)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
showWrongImageFile()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||
showImagePickerError(data = data)
|
||||
}
|
||||
}
|
||||
|
||||
private val imageSelectResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
val data = result.data
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
val fileUri = data?.data
|
||||
|
||||
if (fileUri != null) {
|
||||
val mime = contentResolver.getType(fileUri)
|
||||
|
||||
if (mime.equals("image/gif", ignoreCase = true)) {
|
||||
handleGifImage(fileUri)
|
||||
} else {
|
||||
launchCrop(fileUri)
|
||||
}
|
||||
} else {
|
||||
showWrongImageFile()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
showImagePickerError(data = data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchImagePicker() {
|
||||
ImagePicker.with(this)
|
||||
.galleryOnly()
|
||||
.createIntent { imageSelectResult.launch(it) }
|
||||
}
|
||||
|
||||
private fun launchCrop(fileUri: Uri) {
|
||||
croppedTempFile = File.createTempFile("cropped_", ".jpg", cacheDir)
|
||||
|
||||
val destinationUri = Uri.fromFile(croppedTempFile)
|
||||
|
||||
val options = UCrop.Options().apply {
|
||||
setFreeStyleCropEnabled(true)
|
||||
setToolbarTitle("이미지 자르기")
|
||||
}
|
||||
|
||||
val uCrop = UCrop.of(fileUri, destinationUri)
|
||||
.withOptions(options)
|
||||
.withMaxResultSize(1080, 1080)
|
||||
|
||||
imageCropResult.launch(uCrop.getIntent(this))
|
||||
}
|
||||
|
||||
private fun handleGifImage(fileUri: Uri) {
|
||||
binding.ivContent.background = null
|
||||
|
||||
Glide.with(this)
|
||||
.asGif()
|
||||
.load(fileUri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
8f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivContent)
|
||||
|
||||
viewModel.imageUri = fileUri
|
||||
}
|
||||
|
||||
private fun handleCroppedImage(fileUri: Uri) {
|
||||
binding.ivContent.background = null
|
||||
|
||||
Glide.with(this)
|
||||
.load(fileUri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
8f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivContent)
|
||||
|
||||
viewModel.imageUri = fileUri
|
||||
}
|
||||
|
||||
private fun showWrongImageFile() {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
private fun showImagePickerError(data: Intent?) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
ImagePicker.getError(data),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
checkPermissions()
|
||||
@@ -89,25 +188,32 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
deleteCroppedTempFile()
|
||||
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun deleteCroppedTempFile() {
|
||||
try {
|
||||
if (::croppedTempFile.isInitialized && croppedTempFile.exists()) {
|
||||
val deleted = croppedTempFile.delete()
|
||||
if (!deleted) {
|
||||
Logger.w("임시 파일 삭제 실패: ${croppedTempFile.absolutePath}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
|
||||
binding.toolbar.tvBack.text = "게시글 등록"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
binding.ivPhotoPicker.setOnClickListener {
|
||||
ImagePicker.with(this)
|
||||
.crop()
|
||||
.galleryOnly()
|
||||
.galleryMimeTypes( // Exclude gif images
|
||||
mimeTypes = arrayOf(
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"image/jpeg"
|
||||
)
|
||||
)
|
||||
.createIntent { imageResult.launch(it) }
|
||||
}
|
||||
binding.ivPhotoPicker.setOnClickListener { launchImagePicker() }
|
||||
|
||||
if (SharedPreferenceManager.isAuth) {
|
||||
binding.llSetAdult.visibility = View.VISIBLE
|
||||
@@ -174,11 +280,17 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
|
||||
viewModel.imageUrlLiveData.observe(this) {
|
||||
if (!it.isNullOrBlank()) {
|
||||
binding.ivContent.background = null
|
||||
binding.ivContent.loadUrl(it) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(RoundedCornersTransformation(8f.dpToPx()))
|
||||
}
|
||||
Glide.with(this)
|
||||
.load(it)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
8f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivContent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,23 @@ package kr.co.vividnext.sodalive.explorer.profile.creator_community.write
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
import com.gun0912.tedpermission.PermissionListener
|
||||
import com.gun0912.tedpermission.normal.TedPermission
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
@@ -33,8 +38,9 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
private val viewModel: CreatorCommunityWriteViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var croppedTempFile: File
|
||||
|
||||
private val imageResult = registerForActivityResult(
|
||||
private val imageCropResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
@@ -44,30 +50,120 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
val fileUri = data?.data
|
||||
|
||||
if (fileUri != null) {
|
||||
binding.ivContent.background = null
|
||||
binding.ivContent.load(fileUri) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(RoundedCornersTransformation(8f.dpToPx()))
|
||||
}
|
||||
|
||||
viewModel.setImageUri(fileUri)
|
||||
|
||||
binding.llRecordAudio.visibility = View.VISIBLE
|
||||
handleCroppedImage(fileUri)
|
||||
} else {
|
||||
binding.llRecordAudio.visibility = View.GONE
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
showWrongImageFile()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
binding.llRecordAudio.visibility = View.GONE
|
||||
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||
showImagePickerError(data = data)
|
||||
}
|
||||
}
|
||||
|
||||
private val imageSelectResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
val data = result.data
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
val fileUri = data?.data
|
||||
|
||||
if (fileUri != null) {
|
||||
val mime = contentResolver.getType(fileUri)
|
||||
|
||||
if (mime.equals("image/gif", ignoreCase = true)) {
|
||||
handleGifImage(fileUri)
|
||||
} else {
|
||||
launchCrop(fileUri)
|
||||
}
|
||||
} else {
|
||||
showWrongImageFile()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
showImagePickerError(data = data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchImagePicker() {
|
||||
ImagePicker.with(this)
|
||||
.galleryOnly()
|
||||
.createIntent { imageSelectResult.launch(it) }
|
||||
}
|
||||
|
||||
private fun launchCrop(fileUri: Uri) {
|
||||
croppedTempFile = File.createTempFile("cropped_", ".jpg", cacheDir)
|
||||
|
||||
val destinationUri = Uri.fromFile(croppedTempFile)
|
||||
|
||||
val options = UCrop.Options().apply {
|
||||
setFreeStyleCropEnabled(true)
|
||||
setToolbarTitle("이미지 자르기")
|
||||
}
|
||||
|
||||
val uCrop = UCrop.of(fileUri, destinationUri)
|
||||
.withOptions(options)
|
||||
.withMaxResultSize(1080, 1080)
|
||||
|
||||
imageCropResult.launch(uCrop.getIntent(this))
|
||||
}
|
||||
|
||||
private fun handleGifImage(fileUri: Uri) {
|
||||
binding.llRecordAudio.visibility = View.VISIBLE
|
||||
binding.ivContent.background = null
|
||||
|
||||
Glide.with(this)
|
||||
.asGif()
|
||||
.load(fileUri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
8f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivContent)
|
||||
|
||||
viewModel.setImageUri(fileUri)
|
||||
}
|
||||
|
||||
private fun handleCroppedImage(fileUri: Uri) {
|
||||
binding.llRecordAudio.visibility = View.VISIBLE
|
||||
binding.ivContent.background = null
|
||||
|
||||
Glide.with(this)
|
||||
.load(fileUri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
8f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivContent)
|
||||
|
||||
viewModel.setImageUri(fileUri)
|
||||
}
|
||||
|
||||
private fun showWrongImageFile() {
|
||||
binding.llRecordAudio.visibility = View.GONE
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
private fun showImagePickerError(data: Intent?) {
|
||||
binding.llRecordAudio.visibility = View.GONE
|
||||
Toast.makeText(
|
||||
this,
|
||||
ImagePicker.getError(data),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
checkPermissions()
|
||||
@@ -81,6 +177,9 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
|
||||
override fun onDestroy() {
|
||||
deleteAudioFile()
|
||||
|
||||
deleteCroppedTempFile()
|
||||
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
@@ -90,6 +189,19 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteCroppedTempFile() {
|
||||
try {
|
||||
if (::croppedTempFile.isInitialized && croppedTempFile.exists()) {
|
||||
val deleted = croppedTempFile.delete()
|
||||
if (!deleted) {
|
||||
Logger.w("임시 파일 삭제 실패: ${croppedTempFile.absolutePath}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
|
||||
@@ -102,19 +214,7 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
fragment.show(supportFragmentManager, fragment.tag)
|
||||
}
|
||||
|
||||
binding.ivPhotoPicker.setOnClickListener {
|
||||
ImagePicker.with(this)
|
||||
.crop()
|
||||
.galleryOnly()
|
||||
.galleryMimeTypes( // Exclude gif images
|
||||
mimeTypes = arrayOf(
|
||||
"image/png",
|
||||
"image/jpg",
|
||||
"image/jpeg"
|
||||
)
|
||||
)
|
||||
.createIntent { imageResult.launch(it) }
|
||||
}
|
||||
binding.ivPhotoPicker.setOnClickListener { launchImagePicker() }
|
||||
|
||||
if (SharedPreferenceManager.isAuth) {
|
||||
binding.llSetAdult.visibility = View.VISIBLE
|
||||
|
||||
Reference in New Issue
Block a user