fix(이미지 선택): 이미지 선택 및 크롭 로직 수정
This commit is contained in:
@@ -148,7 +148,6 @@ dependencies {
|
||||
// permission
|
||||
implementation "io.github.ParkSangGwon:tedpermission-normal:3.3.0"
|
||||
|
||||
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
||||
implementation 'com.github.yalantis:ucrop:2.2.11'
|
||||
implementation 'com.github.zhpanvip:bannerviewpager:3.5.7'
|
||||
|
||||
|
||||
@@ -2,16 +2,18 @@ package kr.co.vividnext.sodalive.audio_content.modify
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Bitmap
|
||||
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 androidx.core.view.setPadding
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.gun0912.tedpermission.PermissionListener
|
||||
import com.gun0912.tedpermission.normal.TedPermission
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
@@ -20,6 +22,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
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.databinding.ActivityAudioContentModifyBinding
|
||||
@@ -33,36 +36,7 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||
private val viewModel: AudioContentModifyViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
||||
private val imageResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
val data = result.data
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
val fileUri = data?.data
|
||||
|
||||
if (fileUri != null) {
|
||||
binding.ivCover.setPadding(0)
|
||||
binding.ivCover.background = null
|
||||
binding.ivCover.load(fileUri) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
transformations(RoundedCornersTransformation(13.3f.dpToPx()))
|
||||
}
|
||||
viewModel.coverImageUri = fileUri
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
private lateinit var cropper: ImagePickerCropper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -82,24 +56,50 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||
viewModel.getAudioContentDetail(audioContentId = audioContentId) { finish() }
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
cropper.cleanup()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
|
||||
cropper = ImagePickerCropper(
|
||||
caller = this,
|
||||
context = this,
|
||||
excludeGif = true,
|
||||
isEnabledFreeStyleCrop = true,
|
||||
config = ImagePickerCropper.Config(
|
||||
aspectX = 1f, aspectY = 1f,
|
||||
compressFormat = Bitmap.CompressFormat.JPEG,
|
||||
compressQuality = 90
|
||||
),
|
||||
onSuccess = { file, uri ->
|
||||
binding.ivCover.setPadding(0)
|
||||
binding.ivCover.background = null
|
||||
Glide.with(this)
|
||||
.load(uri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
13.3f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivCover)
|
||||
|
||||
viewModel.coverImageFile = file
|
||||
},
|
||||
onError = { e ->
|
||||
Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
)
|
||||
|
||||
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 { cropper.launch() }
|
||||
|
||||
binding.llAvailablePoint.setOnClickListener { viewModel.setAvailablePoint(true) }
|
||||
binding.llNotAvailablePoint.setOnClickListener { viewModel.setAvailablePoint(false) }
|
||||
@@ -239,8 +239,8 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||
viewModel.setAdult(true)
|
||||
}
|
||||
|
||||
viewModel.isAdultLiveData.observe(this) {
|
||||
if (it) {
|
||||
viewModel.isAdultLiveData.observe(this) { isAdult ->
|
||||
if (isAdult) {
|
||||
binding.ivAgeAll.visibility = View.GONE
|
||||
binding.llAgeAll.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_6_7_13181b
|
||||
|
||||
@@ -68,7 +68,7 @@ class AudioContentModifyViewModel(
|
||||
var title: String? = null
|
||||
var detail: String? = null
|
||||
var tags: String? = null
|
||||
var coverImageUri: Uri? = null
|
||||
var coverImageFile: File? = null
|
||||
var isPointAvailable: Boolean? = null
|
||||
|
||||
fun setAdult(isAdult: Boolean) {
|
||||
@@ -154,8 +154,8 @@ class AudioContentModifyViewModel(
|
||||
|
||||
val requestJson = Gson().toJson(request)
|
||||
|
||||
val coverImage = if (coverImageUri != null) {
|
||||
val file = File(getRealPathFromURI(coverImageUri!!))
|
||||
val coverImage = if (coverImageFile != null) {
|
||||
val file = coverImageFile!!
|
||||
MultipartBody.Part.createFormData(
|
||||
"coverImage",
|
||||
file.name,
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.annotation.SuppressLint
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -15,8 +16,9 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.gun0912.tedpermission.PermissionListener
|
||||
import com.gun0912.tedpermission.normal.TedPermission
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
@@ -26,6 +28,7 @@ import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.PurchaseOption
|
||||
import kr.co.vividnext.sodalive.audio_content.upload.theme.AudioContentThemeFragment
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
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
|
||||
@@ -48,6 +51,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
private val viewModel: AudioContentUploadViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var cropper: ImagePickerCropper
|
||||
|
||||
private val themeFragment: AudioContentThemeFragment by lazy {
|
||||
AudioContentThemeFragment(
|
||||
@@ -66,35 +70,6 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
)
|
||||
}
|
||||
|
||||
private val imageResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
val data = result.data
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
val fileUri = data?.data
|
||||
|
||||
if (fileUri != null) {
|
||||
binding.ivCover.background = null
|
||||
binding.ivCover.load(fileUri) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(RoundedCornersTransformation(13.3f.dpToPx()))
|
||||
}
|
||||
viewModel.coverImageUri = fileUri
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private val selectAudioActivityResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
@@ -113,18 +88,29 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
} else {
|
||||
binding.tvSelectContent.text = "파일 선택"
|
||||
viewModel.contentUri = null
|
||||
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(
|
||||
this,
|
||||
"파일 선택을 실패했습니다.\n다시 시도해 주세요.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
private val datePickerDialogListener =
|
||||
DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
|
||||
viewModel.releaseDate = String.format("%d-%02d-%02d", year, monthOfYear + 1, dayOfMonth)
|
||||
viewModel.releaseDate = String.format(
|
||||
Locale.getDefault(),
|
||||
"%d-%02d-%02d",
|
||||
year,
|
||||
monthOfYear + 1,
|
||||
dayOfMonth
|
||||
)
|
||||
viewModel.setReservationDate(
|
||||
String.format(
|
||||
Locale.getDefault(),
|
||||
"%d.%02d.%02d",
|
||||
year,
|
||||
monthOfYear + 1,
|
||||
@@ -135,7 +121,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
|
||||
private val timePickerDialogListener =
|
||||
TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute ->
|
||||
val timeString = String.format("%02d:%02d", hourOfDay, minute)
|
||||
val timeString = String.format(Locale.getDefault(), "%02d:%02d", hourOfDay, minute)
|
||||
viewModel.releaseTime = timeString
|
||||
viewModel.setReservationTime(timeString.convertDateFormat("HH:mm", "a hh:mm"))
|
||||
}
|
||||
@@ -151,9 +137,45 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
bindData()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
cropper.cleanup()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
|
||||
cropper = ImagePickerCropper(
|
||||
caller = this,
|
||||
context = this,
|
||||
excludeGif = true,
|
||||
isEnabledFreeStyleCrop = true,
|
||||
config = ImagePickerCropper.Config(
|
||||
aspectX = 1f, aspectY = 1f,
|
||||
compressFormat = Bitmap.CompressFormat.JPEG,
|
||||
compressQuality = 90
|
||||
),
|
||||
onSuccess = { file, uri ->
|
||||
binding.ivCover.background = null
|
||||
Glide.with(this)
|
||||
.load(uri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
13.3f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivCover)
|
||||
|
||||
viewModel.coverImageFile = file
|
||||
},
|
||||
onError = { e ->
|
||||
Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
)
|
||||
|
||||
binding.tvServiceDate.text = if (SharedPreferenceManager.userId == 17958L) {
|
||||
"※ 이용기간 : 대여(5일) | 소장(이용 기간 1년)"
|
||||
} else {
|
||||
@@ -167,19 +189,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
themeFragment.show(supportFragmentManager, themeFragment.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 { cropper.launch() }
|
||||
|
||||
binding.tvSelectContent.setOnClickListener {
|
||||
val intent = Intent().apply {
|
||||
@@ -359,7 +369,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
.subscribe {
|
||||
val price = it.toString().toIntOrNull()
|
||||
if (price != null) {
|
||||
viewModel.price = price.toInt()
|
||||
viewModel.price = price
|
||||
} else {
|
||||
viewModel.price = 0
|
||||
if (it.isNotBlank()) {
|
||||
@@ -377,7 +387,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||
.subscribe {
|
||||
val limited = it.toString().toIntOrNull()
|
||||
if (limited != null) {
|
||||
viewModel.limited = limited.toInt()
|
||||
viewModel.limited = limited
|
||||
} else {
|
||||
viewModel.limited = 0
|
||||
if (it.isNotBlank()) {
|
||||
|
||||
@@ -89,7 +89,7 @@ class AudioContentUploadViewModel(
|
||||
var releaseDate = ""
|
||||
var releaseTime = ""
|
||||
var theme: GetAudioContentThemeResponse? = null
|
||||
var coverImageUri: Uri? = null
|
||||
var coverImageFile: File? = null
|
||||
var contentUri: Uri? = null
|
||||
var previewStartTime: String? = null
|
||||
var previewEndTime: String? = null
|
||||
@@ -203,8 +203,8 @@ class AudioContentUploadViewModel(
|
||||
|
||||
val requestJson = Gson().toJson(request)
|
||||
|
||||
val coverImage = if (coverImageUri != null) {
|
||||
val file = File(getRealPathFromURI(coverImageUri!!))
|
||||
val coverImage = if (coverImageFile != null) {
|
||||
val file = coverImageFile!!
|
||||
MultipartBody.Part.createFormData(
|
||||
"coverImage",
|
||||
file.name,
|
||||
@@ -323,7 +323,7 @@ class AudioContentUploadViewModel(
|
||||
return false
|
||||
}
|
||||
|
||||
if (coverImageUri == null) {
|
||||
if (coverImageFile == null) {
|
||||
_toastLiveData.postValue("커버이미지를 선택해 주세요.")
|
||||
return false
|
||||
}
|
||||
@@ -413,7 +413,7 @@ class AudioContentUploadViewModel(
|
||||
|
||||
// Check if the time difference is greater than 30 seconds (30000 milliseconds)
|
||||
return date2.time - date1.time
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
// Handle invalid time formats or parsing errors
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import androidx.activity.result.ActivityResultCaller
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.PickVisualMediaRequest
|
||||
@@ -13,6 +14,7 @@ import com.yalantis.ucrop.UCrop
|
||||
import com.yalantis.ucrop.UCropActivity
|
||||
import kr.co.vividnext.sodalive.BuildConfig
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
/**
|
||||
* 단일 이미지 선택(13+ Photo Picker / 12- GetContent) → uCrop(기본 9:20) → [File, Uri] 반환
|
||||
@@ -20,8 +22,10 @@ import java.io.File
|
||||
* - 결과 파일은 cacheDir에 임시 생성 → 업로드 후 cleanup() 호출로 삭제
|
||||
*/
|
||||
class ImagePickerCropper(
|
||||
private val caller: ActivityResultCaller,
|
||||
caller: ActivityResultCaller,
|
||||
private val context: Context,
|
||||
private val excludeGif: Boolean = false,
|
||||
private val isEnabledFreeStyleCrop: Boolean = false,
|
||||
private val config: Config = Config(),
|
||||
private val onSuccess: (file: File, uri: Uri) -> Unit,
|
||||
private val onError: (Throwable) -> Unit = { it.printStackTrace() }
|
||||
@@ -41,15 +45,21 @@ class ImagePickerCropper(
|
||||
// 13+ : 시스템 Photo Picker
|
||||
private val pickPhoto: ActivityResultLauncher<PickVisualMediaRequest> =
|
||||
caller.registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
|
||||
if (uri == null) onError(CancellationException("User cancelled picking."))
|
||||
else startCrop(uri)
|
||||
if (uri == null) onError(CancellationException("이미지 선택을 취소했습니다."))
|
||||
else handlePickedUri(uri)
|
||||
}
|
||||
|
||||
// 12- : SAF GetContent
|
||||
private val pickContent: ActivityResultLauncher<String> =
|
||||
caller.registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
if (uri == null) onError(CancellationException("User cancelled picking."))
|
||||
else startCrop(uri)
|
||||
if (uri == null) onError(CancellationException("이미지 선택을 취소했습니다."))
|
||||
else handlePickedUri(uri)
|
||||
}
|
||||
|
||||
private val openDocument =
|
||||
caller.registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
|
||||
if (uri == null) onError(CancellationException("이미지 선택을 취소했습니다."))
|
||||
else handlePickedUri(uri)
|
||||
}
|
||||
|
||||
// uCrop 결과 수신
|
||||
@@ -62,38 +72,98 @@ class ImagePickerCropper(
|
||||
if (out != null && file != null && file.exists()) {
|
||||
onSuccess(file, out)
|
||||
} else {
|
||||
onError(IllegalStateException("Crop finished but no output file/uri"))
|
||||
onError(IllegalStateException("이미지 크롭을 실패했습니다.\n다시 시도해 주세요"))
|
||||
}
|
||||
}
|
||||
|
||||
UCrop.RESULT_ERROR -> onError(
|
||||
UCrop.getError(result.data!!) ?: RuntimeException("Crop error")
|
||||
UCrop.getError(result.data!!)
|
||||
?: RuntimeException("이미지 크롭을 실패했습니다.\n다시 시도해 주세요")
|
||||
)
|
||||
|
||||
else -> onError(CancellationException("User cancelled cropping."))
|
||||
else -> onError(CancellationException("이미지 크롭을 취소했습니다."))
|
||||
}
|
||||
}
|
||||
|
||||
/** 외부에서 호출: 선택 → 크롭 시작 */
|
||||
fun launch() {
|
||||
if (ActivityResultContracts.PickVisualMedia.isPhotoPickerAvailable(context)) {
|
||||
pickPhoto.launch(
|
||||
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
|
||||
)
|
||||
if (excludeGif) {
|
||||
openDocument.launch(arrayOf("image/png", "image/jpg", "image/jpeg"))
|
||||
} else {
|
||||
pickContent.launch("image/*")
|
||||
if (ActivityResultContracts.PickVisualMedia.isPhotoPickerAvailable(context)) {
|
||||
pickPhoto.launch(
|
||||
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
|
||||
)
|
||||
} else {
|
||||
pickContent.launch("image/*")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 마지막 크롭 결과 파일 (있으면) */
|
||||
fun getCroppedFile(): File? = lastCroppedFile?.takeIf { it.exists() }
|
||||
|
||||
/** 임시 파일 삭제 */
|
||||
fun cleanup() {
|
||||
lastCroppedFile?.let { if (it.exists()) it.delete() }
|
||||
lastCroppedFile = null
|
||||
}
|
||||
|
||||
private fun handlePickedUri(source: Uri) {
|
||||
if (isGifUri(source)) {
|
||||
// 1) 캐시에 gif 그대로 복사
|
||||
val gifFile = copyUriToCacheAsGif(source)
|
||||
lastCroppedFile = gifFile
|
||||
val fileUri = FileProvider.getUriForFile(
|
||||
context, "${BuildConfig.APPLICATION_ID}.fileprovider", gifFile
|
||||
)
|
||||
// 2) 바로 반환 (크롭 생략)
|
||||
onSuccess(gifFile, fileUri)
|
||||
} else {
|
||||
// 기존 그대로: uCrop 9:20 실행
|
||||
startCrop(source)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isGifUri(uri: Uri): Boolean {
|
||||
// 1순위: MIME type
|
||||
val mime = context.contentResolver.getType(uri)
|
||||
if (mime?.equals("image/gif", ignoreCase = true) == true) return true
|
||||
|
||||
// 2순위: 파일명 확장자
|
||||
val name = getDisplayName(uri)?.lowercase()
|
||||
return name?.endsWith(".gif") == true
|
||||
}
|
||||
|
||||
private fun getDisplayName(uri: Uri): String? {
|
||||
return context.contentResolver.query(
|
||||
uri,
|
||||
arrayOf(OpenableColumns.DISPLAY_NAME),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
?.use { c ->
|
||||
val idx = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||
if (idx >= 0 && c.moveToFirst()) c.getString(idx) else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyUriToCacheAsGif(uri: Uri): File {
|
||||
val base = if (config.useExternalCache) context.externalCacheDir ?: context.cacheDir
|
||||
else context.cacheDir
|
||||
|
||||
// 원본 이름 유지 시도, 실패하면 타임스탬프
|
||||
val name = getDisplayName(uri)?.takeIf { it.endsWith(".gif", true) }
|
||||
?: "picked_${System.currentTimeMillis()}.gif"
|
||||
|
||||
val outFile = File(base, name)
|
||||
context.contentResolver.openInputStream(uri).use { input ->
|
||||
requireNotNull(input) { "Cannot open input stream for $uri" }
|
||||
FileOutputStream(outFile).use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
return outFile
|
||||
}
|
||||
|
||||
private fun startCrop(source: Uri) {
|
||||
val destFile = createTempCropFile()
|
||||
lastCroppedFile = destFile
|
||||
@@ -110,8 +180,8 @@ class ImagePickerCropper(
|
||||
setCompressionQuality(config.compressQuality)
|
||||
|
||||
// 제스처/컨트롤 (필요시 조절)
|
||||
setFreeStyleCropEnabled(false)
|
||||
setHideBottomControls(false)
|
||||
setFreeStyleCropEnabled(isEnabledFreeStyleCrop)
|
||||
setHideBottomControls(true)
|
||||
setAllowedGestures(
|
||||
UCropActivity.SCALE, // Aspect 줄이진 못하지만 확대/축소
|
||||
UCropActivity.ROTATE, // 회전
|
||||
|
||||
@@ -2,35 +2,29 @@ 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.graphics.Bitmap
|
||||
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 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
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
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.databinding.ActivityCreatorCommunityModifyBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.io.File
|
||||
|
||||
class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModifyBinding>(
|
||||
ActivityCreatorCommunityModifyBinding::inflate
|
||||
@@ -39,142 +33,11 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
|
||||
private val viewModel: CreatorCommunityModifyViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var croppedTempFile: File
|
||||
|
||||
private val imageCropResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
val data = result.data
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
val fileUri = UCrop.getOutput(data!!)
|
||||
|
||||
if (fileUri != null) {
|
||||
handleCroppedImage(fileUri)
|
||||
} else {
|
||||
showWrongImageFile()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
val cropError = UCrop.getError(data!!)
|
||||
cropError?.printStackTrace()
|
||||
Toast.makeText(
|
||||
this,
|
||||
cropError?.message,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
private lateinit var cropper: ImagePickerCropper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
checkPermissions()
|
||||
|
||||
viewModel.getRealPathFromURI = {
|
||||
RealPathUtil.getRealPath(applicationContext, it)
|
||||
}
|
||||
|
||||
bindData()
|
||||
|
||||
val postId = intent.getLongExtra(Constants.EXTRA_COMMUNITY_POST_ID, 0)
|
||||
@@ -193,31 +56,47 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
deleteCroppedTempFile()
|
||||
|
||||
cropper.cleanup()
|
||||
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)
|
||||
|
||||
cropper = ImagePickerCropper(
|
||||
caller = this,
|
||||
context = this,
|
||||
isEnabledFreeStyleCrop = true,
|
||||
config = ImagePickerCropper.Config(
|
||||
aspectX = 1f, aspectY = 1f,
|
||||
compressFormat = Bitmap.CompressFormat.JPEG,
|
||||
compressQuality = 90
|
||||
),
|
||||
onSuccess = { file, uri ->
|
||||
binding.ivContent.background = null
|
||||
Glide.with(this)
|
||||
.load(uri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
16f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivContent)
|
||||
|
||||
viewModel.imageFile = file
|
||||
},
|
||||
onError = { e ->
|
||||
Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
)
|
||||
|
||||
binding.toolbar.tvBack.text = "게시글 등록"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
binding.ivPhotoPicker.setOnClickListener { launchImagePicker() }
|
||||
binding.ivPhotoPicker.setOnClickListener { cropper.launch() }
|
||||
|
||||
if (SharedPreferenceManager.isAuth) {
|
||||
binding.llSetAdult.visibility = View.VISIBLE
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.google.gson.Gson
|
||||
@@ -46,11 +45,9 @@ class CreatorCommunityModifyViewModel(
|
||||
val isAvailableCommentLiveData: LiveData<Boolean>
|
||||
get() = _isAvailableCommentLiveData
|
||||
|
||||
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||
|
||||
var postId = 0L
|
||||
var content = ""
|
||||
var imageUri: Uri? = null
|
||||
var imageFile: File? = null
|
||||
private var communityPost: GetCommunityPostListResponse? = null
|
||||
|
||||
fun setAdult(isAdult: Boolean) {
|
||||
@@ -134,8 +131,8 @@ class CreatorCommunityModifyViewModel(
|
||||
|
||||
val requestJson = Gson().toJson(request)
|
||||
|
||||
val postImage = if (imageUri != null) {
|
||||
val file = File(getRealPathFromURI(imageUri!!))
|
||||
val postImage = if (imageFile != null) {
|
||||
val file = imageFile!!
|
||||
MultipartBody.Part.createFormData(
|
||||
"postImage",
|
||||
file.name,
|
||||
|
||||
@@ -2,29 +2,24 @@ 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.graphics.Bitmap
|
||||
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 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
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
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.databinding.ActivityCreatorCommunityWriteBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
@@ -38,154 +33,18 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
private val viewModel: CreatorCommunityWriteViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var croppedTempFile: File
|
||||
|
||||
private val imageCropResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
val resultCode = result.resultCode
|
||||
val data = result.data
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
val fileUri = UCrop.getOutput(data!!)
|
||||
|
||||
if (fileUri != null) {
|
||||
handleCroppedImage(fileUri)
|
||||
} else {
|
||||
showWrongImageFile()
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
val cropError = UCrop.getError(data!!)
|
||||
cropError?.printStackTrace()
|
||||
Toast.makeText(
|
||||
this,
|
||||
cropError?.message,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
private lateinit var cropper: ImagePickerCropper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
checkPermissions()
|
||||
|
||||
viewModel.getRealPathFromURI = {
|
||||
RealPathUtil.getRealPath(applicationContext, it)
|
||||
}
|
||||
|
||||
bindData()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
cropper.cleanup()
|
||||
deleteAudioFile()
|
||||
|
||||
deleteCroppedTempFile()
|
||||
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
@@ -195,22 +54,39 @@ 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)
|
||||
|
||||
cropper = ImagePickerCropper(
|
||||
caller = this,
|
||||
context = this,
|
||||
isEnabledFreeStyleCrop = true,
|
||||
config = ImagePickerCropper.Config(
|
||||
aspectX = 1f, aspectY = 1f,
|
||||
compressFormat = Bitmap.CompressFormat.JPEG,
|
||||
compressQuality = 90
|
||||
),
|
||||
onSuccess = { file, uri ->
|
||||
binding.ivContent.background = null
|
||||
Glide.with(this)
|
||||
.load(uri)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
RoundedCorners(
|
||||
16f.dpToPx().toInt()
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(binding.ivContent)
|
||||
|
||||
viewModel.setImageFile(file)
|
||||
},
|
||||
onError = { e ->
|
||||
Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
)
|
||||
|
||||
binding.toolbar.tvBack.text = "게시글 등록"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
@@ -220,7 +96,7 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
fragment.show(supportFragmentManager, fragment.tag)
|
||||
}
|
||||
|
||||
binding.ivPhotoPicker.setOnClickListener { launchImagePicker() }
|
||||
binding.ivPhotoPicker.setOnClickListener { cropper.launch() }
|
||||
|
||||
if (SharedPreferenceManager.isAuth) {
|
||||
binding.llSetAdult.visibility = View.VISIBLE
|
||||
@@ -278,7 +154,7 @@ class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWrite
|
||||
.subscribe {
|
||||
val price = it.toString().toIntOrNull()
|
||||
if (price != null) {
|
||||
viewModel.price = price.toInt()
|
||||
viewModel.price = price
|
||||
} else {
|
||||
viewModel.price = 0
|
||||
if (it.isNotBlank()) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.write
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.google.gson.Gson
|
||||
@@ -45,12 +44,10 @@ class CreatorCommunityWriteViewModel(
|
||||
val isShowPriceUiLiveData: LiveData<Boolean>
|
||||
get() = _isShowPriceUiLiveData
|
||||
|
||||
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||
|
||||
var price = 0
|
||||
var content = ""
|
||||
var audioFile: File? = null
|
||||
private var imageUri: Uri? = null
|
||||
private var imageFile: File? = null
|
||||
|
||||
fun setAdult(isAdult: Boolean) {
|
||||
_isAdultLiveData.postValue(isAdult)
|
||||
@@ -64,8 +61,8 @@ class CreatorCommunityWriteViewModel(
|
||||
_isPriceFreeLiveData.postValue(isPriceFree)
|
||||
}
|
||||
|
||||
fun setImageUri(uri: Uri) {
|
||||
this.imageUri = uri
|
||||
fun setImageFile(file: File) {
|
||||
this.imageFile = file
|
||||
_isShowPriceUiLiveData.postValue(true)
|
||||
}
|
||||
|
||||
@@ -82,8 +79,8 @@ class CreatorCommunityWriteViewModel(
|
||||
|
||||
val requestJson = Gson().toJson(request)
|
||||
|
||||
val postImage = if (imageUri != null) {
|
||||
val file = File(getRealPathFromURI(imageUri!!))
|
||||
val postImage = if (imageFile != null) {
|
||||
val file = imageFile!!
|
||||
MultipartBody.Part.createFormData(
|
||||
"postImage",
|
||||
file.name,
|
||||
@@ -188,12 +185,12 @@ class CreatorCommunityWriteViewModel(
|
||||
return false
|
||||
}
|
||||
|
||||
if (imageUri == null) {
|
||||
if (imageFile == null) {
|
||||
_toastLiveData.postValue("유료 게시글 등록을 위해서는 이미지가 필요합니다.")
|
||||
return false
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
_toastLiveData.postValue("가격은 숫자만 입력 가능 합니다.")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
package kr.co.vividnext.sodalive.mypage.profile
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.CircleCrop
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
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.databinding.ActivityProfileUpdateBinding
|
||||
import kr.co.vividnext.sodalive.databinding.ItemLiveTagSelectedBinding
|
||||
@@ -33,27 +35,6 @@ class ProfileUpdateActivity : BaseActivity<ActivityProfileUpdateBinding>(
|
||||
|
||||
private val viewModel: ProfileUpdateViewModel by inject()
|
||||
|
||||
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!!
|
||||
binding.ivProfile.background = null
|
||||
viewModel.updateProfileImage(fileUri) {
|
||||
SharedPreferenceManager.profileImage = it
|
||||
binding.ivProfile.load(it) {
|
||||
crossfade(true)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
}
|
||||
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private val tagFragment: MemberTagFragment by lazy {
|
||||
MemberTagFragment(viewModel.tags) { tag, isChecked ->
|
||||
when {
|
||||
@@ -76,22 +57,23 @@ class ProfileUpdateActivity : BaseActivity<ActivityProfileUpdateBinding>(
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
||||
private lateinit var cropper: ImagePickerCropper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel.getRealPathFromURI = {
|
||||
RealPathUtil.getRealPath(applicationContext, it)
|
||||
}
|
||||
|
||||
bindData()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
viewModel.getUserInfo()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
cropper.cleanup()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
compositeDisposable.add(
|
||||
binding.etBlog.textChanges().skip(1)
|
||||
@@ -220,6 +202,34 @@ class ProfileUpdateActivity : BaseActivity<ActivityProfileUpdateBinding>(
|
||||
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
|
||||
cropper = ImagePickerCropper(
|
||||
caller = this,
|
||||
context = this,
|
||||
isEnabledFreeStyleCrop = false,
|
||||
config = ImagePickerCropper.Config(
|
||||
aspectX = 1f, aspectY = 1f,
|
||||
compressFormat = Bitmap.CompressFormat.JPEG,
|
||||
compressQuality = 90
|
||||
),
|
||||
onSuccess = { file, _ ->
|
||||
binding.ivProfile.background = null
|
||||
viewModel.updateProfileImage(file) {
|
||||
SharedPreferenceManager.profileImage = it
|
||||
Glide.with(this)
|
||||
.load(it)
|
||||
.placeholder(R.drawable.ic_place_holder)
|
||||
.apply(
|
||||
RequestOptions()
|
||||
.transform(CircleCrop())
|
||||
)
|
||||
.into(binding.ivProfile)
|
||||
}
|
||||
},
|
||||
onError = { e ->
|
||||
Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etIntroduce.textChanges()
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
@@ -241,19 +251,7 @@ class ProfileUpdateActivity : BaseActivity<ActivityProfileUpdateBinding>(
|
||||
viewModel.changeGender(Gender.NONE)
|
||||
}
|
||||
|
||||
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 { cropper.launch() }
|
||||
|
||||
binding.tvSelectTag.setOnClickListener {
|
||||
if (tagFragment.isAdded) return@setOnClickListener
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package kr.co.vividnext.sodalive.mypage.profile
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
@@ -53,8 +52,6 @@ class ProfileUpdateViewModel(private val repository: UserRepository) : BaseViewM
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||
|
||||
fun getUserInfo() {
|
||||
compositeDisposable.add(
|
||||
repository.getProfile("Bearer ${SharedPreferenceManager.token}")
|
||||
@@ -90,8 +87,7 @@ class ProfileUpdateViewModel(private val repository: UserRepository) : BaseViewM
|
||||
_genderLiveData.postValue(gender)
|
||||
}
|
||||
|
||||
fun updateProfileImage(uri: Uri, onSuccess: (String) -> Unit) {
|
||||
val file = File(getRealPathFromURI(uri))
|
||||
fun updateProfileImage(file: File, onSuccess: (String) -> Unit) {
|
||||
val image = MultipartBody.Part.createFormData(
|
||||
"image",
|
||||
file.name,
|
||||
|
||||
Reference in New Issue
Block a user