fix(이미지 선택): 이미지 선택 및 크롭 로직 수정

This commit is contained in:
2025-09-18 00:17:20 +09:00
parent 02155065f7
commit d22907c7d5
16 changed files with 397 additions and 571 deletions

View File

@@ -3,15 +3,14 @@ package kr.co.vividnext.sodalive.live.room
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.Service
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Rect
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.CountDownTimer
@@ -37,6 +36,7 @@ import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -46,7 +46,6 @@ import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.github.dhaval2404.imagepicker.ImagePicker
import com.google.gson.Gson
import com.orhanobut.logger.Logger
import io.agora.rtc2.ClientRoleOptions
@@ -67,8 +66,8 @@ import kr.co.vividnext.sodalive.agora.Agora
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.ImagePickerCropper
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.RealPathUtil
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.SodaLiveService
import kr.co.vividnext.sodalive.databinding.ActivityLiveRoomBinding
@@ -117,6 +116,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
private lateinit var speakerListAdapter: LiveRoomProfileListAdapter
private lateinit var loadingDialog: LoadingDialog
private lateinit var cropper: ImagePickerCropper
private lateinit var imm: InputMethodManager
private val handler = Handler(Looper.getMainLooper())
@@ -235,20 +236,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
}
}
private val imageResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val resultCode = result.resultCode
val data = result.data
if (resultCode == RESULT_OK) {
// Image Uri will not be null for RESULT_OK
val fileUri = data?.data!!
roomInfoEditDialog.setCoverImageUri(fileUri)
} else if (resultCode == ImagePicker.RESULT_ERROR) {
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
}
}
private val rouletteConfigResult = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
@@ -280,9 +267,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
super.onCreate(savedInstanceState)
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
viewModel.getRealPathFromURI = {
RealPathUtil.getRealPath(applicationContext, it)
}
this.roomId = intent.getLongExtra(Constants.EXTRA_ROOM_ID, 0)
if (roomId <= 0) {
@@ -321,27 +305,34 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
bindData()
loadingDialog = LoadingDialog(this, layoutInflater)
cropper = ImagePickerCropper(
caller = this,
context = this,
excludeGif = true,
config = ImagePickerCropper.Config(
aspectX = 2f, aspectY = 3.8f,
maxWidth = 1080, maxHeight = 2052,
compressFormat = Bitmap.CompressFormat.JPEG,
compressQuality = 90
),
onSuccess = { file, uri ->
roomInfoEditDialog.setCoverImageUri(file)
},
onError = { e ->
Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show()
}
)
imm = getSystemService(
Service.INPUT_METHOD_SERVICE
INPUT_METHOD_SERVICE
) as InputMethodManager
roomDialog = LiveRoomDialog(this, layoutInflater)
roomInfoEditDialog = LiveRoomInfoEditDialog(
activity = this,
layoutInflater = layoutInflater,
onClickImagePicker = {
ImagePicker.with(this)
.crop()
.galleryOnly()
.galleryMimeTypes( // Exclude gif images
mimeTypes = arrayOf(
"image/png",
"image/jpg",
"image/jpeg"
)
)
.createIntent { imageResult.launch(it) }
}
onClickImagePicker = { cropper.launch() }
)
roomProfileDialog = LiveRoomProfileDialog(
layoutInflater = layoutInflater,
@@ -559,6 +550,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
}
override fun onDestroy() {
cropper.cleanup()
hideKeyboard {
viewModel.quitRoom(roomId) {
SodaLiveService.stopService(this)
@@ -960,7 +952,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
)
roomInfoEditDialog.setCoverImageUrl(response.coverImageUrl)
roomInfoEditDialog.setMenuPreset(it)
roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageUri, isActivateMenu, menuId, menu, isAdult, isEntryMessageEnabled ->
roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageFile, isActivateMenu, menuId, menu, isAdult, isEntryMessageEnabled ->
if (isEntryMessageEnabled != null) {
this.isEntryMessageEnabled = isEntryMessageEnabled
}
@@ -969,12 +961,13 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
response.roomId,
newTitle,
newContent,
newCoverImageUri,
newCoverImageFile,
isActivateMenu,
menuId,
menu,
isAdult,
onSuccess = {
cropper.cleanup()
Toast.makeText(
applicationContext,
"라이브 정보가 수정되었습니다.",
@@ -1280,7 +1273,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val clickableSpan = object : ClickableSpan() {
override fun onClick(widget: View) {
val url = spannable.subSequence(start, end).toString()
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
startActivity(Intent(Intent.ACTION_VIEW, url.toUri()))
}
}
spannable.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

View File

@@ -1,6 +1,5 @@
package kr.co.vividnext.sodalive.live.room
import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
@@ -99,8 +98,6 @@ class LiveRoomViewModel(
val isSignatureOn: LiveData<Boolean>
get() = _isSignatureOn
lateinit var getRealPathFromURI: (Uri) -> String?
private val blockedMemberIdList: MutableList<Long> = mutableListOf()
val mutex = Mutex()
@@ -430,7 +427,7 @@ class LiveRoomViewModel(
roomId: Long,
newTitle: String,
newContent: String,
newCoverImageUri: Uri? = null,
newCoverImageFile: File? = null,
isActivateMenu: Boolean?,
menuId: Long,
menu: String,
@@ -462,7 +459,7 @@ class LiveRoomViewModel(
request.notice == null &&
menu == roomInfoResponse.menuPan &&
request.isAdult == null &&
newCoverImageUri == null &&
newCoverImageFile == null &&
request.isActiveMenuPan == null
) {
return
@@ -480,8 +477,8 @@ class LiveRoomViewModel(
null
}
val coverImage = if (newCoverImageUri != null) {
val file = File(getRealPathFromURI(newCoverImageUri))
val coverImage = if (newCoverImageFile != null) {
val file = newCoverImageFile
MultipartBody.Part.createFormData(
"coverImage",
file.name,

View File

@@ -131,6 +131,7 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
cropper = ImagePickerCropper(
caller = this,
context = this,
excludeGif = true,
config = ImagePickerCropper.Config(
aspectX = 2f, aspectY = 3.8f,
maxWidth = 1080, maxHeight = 2052,

View File

@@ -2,8 +2,6 @@ package kr.co.vividnext.sodalive.live.room.update
import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -15,15 +13,18 @@ import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toDrawable
import androidx.lifecycle.MutableLiveData
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 kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.DialogLiveRoomInfoUpdateBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
import kr.co.vividnext.sodalive.live.room.menu.GetMenuPresetResponse
import java.io.File
@SuppressLint("ClickableViewAccessibility")
class LiveRoomInfoEditDialog(
@@ -35,7 +36,7 @@ class LiveRoomInfoEditDialog(
private val dialogView = DialogLiveRoomInfoUpdateBinding.inflate(layoutInflater)
private var coverImageUrl: String? = null
private var coverImageUri: Uri? = null
private var coverImageFile: File? = null
private var menuId = 0L
private val menuList = mutableListOf<GetMenuPresetResponse>()
@@ -58,7 +59,7 @@ class LiveRoomInfoEditDialog(
alertDialog = dialogBuilder.create()
alertDialog.setCancelable(false)
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
alertDialog.window?.setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
dialogView.ivPhotoPicker.setOnClickListener { onClickImagePicker() }
dialogView.ivClose.setOnClickListener { alertDialog.dismiss() }
@@ -185,22 +186,34 @@ class LiveRoomInfoEditDialog(
isEntryMessageEnabledLiveData.value = isEntryMessageEnabled
}
fun setCoverImageUri(coverImageUri: Uri) {
this.coverImageUri = coverImageUri
dialogView.ivCover.load(coverImageUri) {
crossfade(true)
placeholder(R.drawable.ic_place_holder)
transformations(RoundedCornersTransformation(13.3f.dpToPx()))
}
fun setCoverImageUri(file: File) {
this.coverImageFile = file
Glide.with(activity)
.load(file)
.placeholder(R.drawable.ic_place_holder)
.apply(
RequestOptions().transform(
RoundedCorners(
13.3f.dpToPx().toInt()
)
)
)
.into(dialogView.ivCover)
}
fun setCoverImageUrl(coverImageUrl: String) {
this.coverImageUrl = coverImageUrl
dialogView.ivCover.load(coverImageUrl) {
crossfade(true)
placeholder(R.drawable.ic_place_holder)
transformations(RoundedCornersTransformation(13.3f.dpToPx()))
}
Glide.with(activity)
.load(coverImageUrl)
.placeholder(R.drawable.ic_place_holder)
.apply(
RequestOptions().transform(
RoundedCorners(
13.3f.dpToPx().toInt()
)
)
)
.into(dialogView.ivCover)
}
fun setMenuPreset(menuList: List<GetMenuPresetResponse>) {
@@ -223,7 +236,7 @@ class LiveRoomInfoEditDialog(
}
fun setConfirmAction(
confirmAction: (String, String, Uri?, Boolean?, Long, String, Boolean?, Boolean?) -> Unit
confirmAction: (String, String, File?, Boolean?, Long, String, Boolean?, Boolean?) -> Unit
) {
dialogView.tvConfirm.setOnClickListener {
alertDialog.dismiss()
@@ -235,7 +248,7 @@ class LiveRoomInfoEditDialog(
confirmAction(
newTitle,
newContent,
coverImageUri,
coverImageFile,
if (isActivateMenu != null) {
isActivateMenu
} else if (
@@ -262,7 +275,7 @@ class LiveRoomInfoEditDialog(
null
}
)
coverImageUri = null
coverImageFile = null
coverImageUrl = null
}
}
@@ -291,7 +304,7 @@ class LiveRoomInfoEditDialog(
)
)
if (menuList.size > 0) {
if (menuList.isNotEmpty()) {
dialogView.llSelectMenu2.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
dialogView.tvSelectMenu2.setTextColor(
ContextCompat.getColor(