프로필 수정 페이지 추가
This commit is contained in:
parent
9adadaf572
commit
be7c7d0682
|
@ -101,6 +101,9 @@
|
|||
<activity android:name=".live.reservation.all.LiveReservationAllActivity" />
|
||||
<activity android:name=".mypage.service_center.ServiceCenterActivity" />
|
||||
<activity android:name=".onboarding.OnBoardingActivity" />
|
||||
<activity android:name=".mypage.profile.ProfileUpdateActivity" />
|
||||
<activity android:name=".mypage.profile.nickname.NicknameUpdateActivity" />
|
||||
<activity android:name=".mypage.profile.password.ModifyPasswordActivity" />
|
||||
|
||||
<activity
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||
|
|
|
@ -55,6 +55,11 @@ import kr.co.vividnext.sodalive.mypage.can.CanRepository
|
|||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.profile.nickname.NicknameUpdateViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagApi
|
||||
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagRepository
|
||||
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.service_center.FaqApi
|
||||
import kr.co.vividnext.sodalive.mypage.service_center.FaqRepository
|
||||
import kr.co.vividnext.sodalive.mypage.service_center.ServiceCenterViewModel
|
||||
|
@ -134,6 +139,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
single { ApiBuilder().build(get(), NoticeApi::class.java) }
|
||||
single { ApiBuilder().build(get(), AudioContentApi::class.java) }
|
||||
single { ApiBuilder().build(get(), FaqApi::class.java) }
|
||||
single { ApiBuilder().build(get(), MemberTagApi::class.java) }
|
||||
}
|
||||
|
||||
private val viewModelModule = module {
|
||||
|
@ -179,6 +185,9 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { AudioContentCommentReplyViewModel(get()) }
|
||||
viewModel { FollowingCreatorViewModel(get()) }
|
||||
viewModel { ServiceCenterViewModel(get()) }
|
||||
viewModel { ProfileUpdateViewModel(get()) }
|
||||
viewModel { NicknameUpdateViewModel(get()) }
|
||||
viewModel { MemberTagViewModel(get()) }
|
||||
}
|
||||
|
||||
private val repositoryModule = module {
|
||||
|
@ -199,6 +208,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
factory { PlaybackTrackingRepository(get()) }
|
||||
factory { FollowingCreatorRepository(get(), get()) }
|
||||
factory { FaqRepository(get()) }
|
||||
factory { MemberTagRepository(get()) }
|
||||
}
|
||||
|
||||
private val moduleList = listOf(
|
||||
|
|
|
@ -19,12 +19,13 @@ import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
|||
import kr.co.vividnext.sodalive.databinding.FragmentMyBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kr.co.vividnext.sodalive.live.reservation_status.LiveReservationStatusActivity
|
||||
import kr.co.vividnext.sodalive.mypage.auth.Auth
|
||||
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
|
||||
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusActivity
|
||||
import kr.co.vividnext.sodalive.live.reservation_status.LiveReservationStatusActivity
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateActivity
|
||||
import kr.co.vividnext.sodalive.mypage.service_center.ServiceCenterActivity
|
||||
import kr.co.vividnext.sodalive.settings.SettingsActivity
|
||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||
|
@ -59,7 +60,14 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||
)
|
||||
}
|
||||
|
||||
binding.ivEdit.setOnClickListener {}
|
||||
binding.ivEdit.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(
|
||||
requireActivity(),
|
||||
ProfileUpdateActivity::class.java
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
binding.llTotalCan.setOnClickListener {
|
||||
startActivity(
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kr.co.vividnext.sodalive.user.Gender
|
||||
|
||||
data class ProfileResponse(
|
||||
@SerializedName("userId") val userId: Long,
|
||||
@SerializedName("email") val email: String,
|
||||
@SerializedName("nickname") val nickname: String,
|
||||
@SerializedName("gender") val gender: Gender,
|
||||
@SerializedName("profileUrl") val profileUrl: String,
|
||||
@SerializedName("chargeCoin") val chargeCoin: Int,
|
||||
@SerializedName("rewardCoin") val rewardCoin: Int,
|
||||
@SerializedName("youtubeUrl") val youtubeUrl: String?,
|
||||
@SerializedName("instagramUrl") val instagramUrl: String?,
|
||||
@SerializedName("blogUrl") val blogUrl: String?,
|
||||
@SerializedName("websiteUrl") val websiteUrl: String?,
|
||||
@SerializedName("introduce") val introduce: String,
|
||||
@SerializedName("tags") val tags: List<String>
|
||||
)
|
|
@ -0,0 +1,277 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile
|
||||
|
||||
import android.content.Intent
|
||||
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.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.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
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.mypage.profile.nickname.NicknameUpdateActivity
|
||||
import kr.co.vividnext.sodalive.mypage.profile.password.ModifyPasswordActivity
|
||||
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagFragment
|
||||
import kr.co.vividnext.sodalive.user.Gender
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ProfileUpdateActivity : BaseActivity<ActivityProfileUpdateBinding>(
|
||||
ActivityProfileUpdateBinding::inflate
|
||||
) {
|
||||
|
||||
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) {
|
||||
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 {
|
||||
isChecked -> {
|
||||
viewModel.addTag(tag)
|
||||
return@MemberTagFragment true
|
||||
}
|
||||
|
||||
!isChecked -> {
|
||||
viewModel.removeTag(tag)
|
||||
return@MemberTagFragment true
|
||||
}
|
||||
|
||||
else -> {
|
||||
return@MemberTagFragment false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel.getRealPathFromURI = {
|
||||
RealPathUtil.getRealPath(applicationContext, it)
|
||||
}
|
||||
|
||||
bindData()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
viewModel.getUserInfo()
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
compositeDisposable.add(
|
||||
binding.etBlog.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.blogUrl = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etWebsite.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.websiteUrl = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etYoutube.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.youtubeUrl = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etInstagram.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.instagramUrl = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
viewModel.genderLiveData.observe(this) {
|
||||
binding.tvMale.isSelected = false
|
||||
binding.tvFemale.isSelected = false
|
||||
binding.tvNone.isSelected = false
|
||||
|
||||
when (it) {
|
||||
Gender.MALE -> binding.tvMale.isSelected = true
|
||||
Gender.FEMALE -> binding.tvFemale.isSelected = true
|
||||
Gender.NONE -> binding.tvNone.isSelected = true
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.userInfoLiveData.observe(this) {
|
||||
binding.ivProfile.load(it.profileUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.tvEmail.text = it.email
|
||||
binding.tvNickname.text = it.nickname
|
||||
it.youtubeUrl?.let { url -> binding.etYoutube.setText(url) }
|
||||
it.instagramUrl?.let { url -> binding.etInstagram.setText(url) }
|
||||
it.websiteUrl?.let { url -> binding.etWebsite.setText(url) }
|
||||
it.blogUrl?.let { url -> binding.etBlog.setText(url) }
|
||||
binding.etIntroduce.setText(it.introduce)
|
||||
|
||||
SharedPreferenceManager.nickname = it.nickname
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
it?.let {
|
||||
Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(this) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.selectedTagLiveData.observe(this) {
|
||||
binding.llSelectTags.removeAllViews()
|
||||
binding.llSelectTags.visibility = if (it.isNotEmpty()) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
for (index in it.indices) {
|
||||
val tag = it[index]
|
||||
val itemView = ItemLiveTagSelectedBinding.inflate(layoutInflater)
|
||||
itemView.tvTag.text = tag
|
||||
itemView.ivRemove.setOnClickListener {
|
||||
viewModel.removeTag(tag)
|
||||
}
|
||||
binding.llSelectTags.addView(itemView.root)
|
||||
|
||||
if (index > 0) {
|
||||
val layoutParams = itemView.root.layoutParams as LinearLayout.LayoutParams
|
||||
layoutParams.marginStart = 10.dpToPx().toInt()
|
||||
itemView.root.layoutParams = layoutParams
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
binding.toolbar.tvBack.text = "프로필 수정"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etIntroduce.textChanges()
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.introduce = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
binding.tvMale.setOnClickListener {
|
||||
viewModel.changeGender(Gender.MALE)
|
||||
}
|
||||
|
||||
binding.tvFemale.setOnClickListener {
|
||||
viewModel.changeGender(Gender.FEMALE)
|
||||
}
|
||||
|
||||
binding.tvNone.setOnClickListener {
|
||||
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.tvSelectTag.setOnClickListener {
|
||||
if (tagFragment.isAdded) return@setOnClickListener
|
||||
|
||||
tagFragment.show(supportFragmentManager, tagFragment.tag)
|
||||
}
|
||||
|
||||
binding.tvModifyPassword.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(
|
||||
applicationContext,
|
||||
ModifyPasswordActivity::class.java
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
binding.tvSave.setOnClickListener {
|
||||
viewModel.updateProfile {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
binding.tvChangeNickname.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(
|
||||
applicationContext,
|
||||
NicknameUpdateActivity::class.java
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kr.co.vividnext.sodalive.user.Gender
|
||||
|
||||
data class ProfileUpdateRequest(
|
||||
@SerializedName("email") val email: String,
|
||||
@SerializedName("password") val password: String? = null,
|
||||
@SerializedName("modifyPassword") val modifyPassword: String? = null,
|
||||
@SerializedName("nickname") val nickname: String? = null,
|
||||
@SerializedName("gender") val gender: Gender? = null,
|
||||
@SerializedName("insertTags") val insertTags: List<String>? = null,
|
||||
@SerializedName("removeTags") val removeTags: List<String>? = null,
|
||||
@SerializedName("introduce") val introduce: String? = null,
|
||||
@SerializedName("youtubeUrl") val youtubeUrl: String? = null,
|
||||
@SerializedName("instagramUrl") val instagramUrl: String? = null,
|
||||
@SerializedName("websiteUrl") val websiteUrl: String? = null,
|
||||
@SerializedName("blogUrl") val blogUrl: String? = null,
|
||||
@SerializedName("container") val container: String = "aos"
|
||||
)
|
|
@ -0,0 +1,290 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.user.Gender
|
||||
import kr.co.vividnext.sodalive.user.UserRepository
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import java.io.File
|
||||
|
||||
class ProfileUpdateViewModel(private val repository: UserRepository) : BaseViewModel() {
|
||||
|
||||
var youtubeUrl = ""
|
||||
var instagramUrl = ""
|
||||
var websiteUrl = ""
|
||||
var blogUrl = ""
|
||||
var introduce = ""
|
||||
|
||||
var currentPassword = ""
|
||||
var newPassword = ""
|
||||
var newPasswordConfirm = ""
|
||||
|
||||
val tags = mutableSetOf<String>()
|
||||
private val insertTags = mutableListOf<String>()
|
||||
private val removeTags = mutableListOf<String>()
|
||||
|
||||
private lateinit var profileResponse: ProfileResponse
|
||||
|
||||
private val _userInfoLiveData = MutableLiveData<ProfileResponse>()
|
||||
val userInfoLiveData: LiveData<ProfileResponse>
|
||||
get() = _userInfoLiveData
|
||||
|
||||
private val _genderLiveData = MutableLiveData<Gender>()
|
||||
val genderLiveData: LiveData<Gender>
|
||||
get() = _genderLiveData
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private val _selectedTagLiveData = MutableLiveData<List<String>>()
|
||||
val selectedTagLiveData: LiveData<List<String>>
|
||||
get() = _selectedTagLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||
|
||||
fun getUserInfo() {
|
||||
compositeDisposable.add(
|
||||
repository.getProfile("Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
profileResponse = it.data
|
||||
tags.addAll(profileResponse.tags)
|
||||
_selectedTagLiveData.postValue(profileResponse.tags)
|
||||
_genderLiveData.postValue(profileResponse.gender)
|
||||
_userInfoLiveData.postValue(profileResponse)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun changeGender(gender: Gender) {
|
||||
_genderLiveData.postValue(gender)
|
||||
}
|
||||
|
||||
fun updateProfileImage(uri: Uri, onSuccess: (String) -> Unit) {
|
||||
val file = File(getRealPathFromURI(uri))
|
||||
val image = MultipartBody.Part.createFormData(
|
||||
"image",
|
||||
file.name,
|
||||
file.asRequestBody("image/*".toMediaType())
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.updateProfileImage(image, "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
onSuccess(it.data)
|
||||
_toastLiveData.postValue("프로필 이미지가 변경되었습니다.")
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun updateProfile(onSuccess: () -> Unit) {
|
||||
if (
|
||||
profileResponse.youtubeUrl != youtubeUrl ||
|
||||
profileResponse.instagramUrl != instagramUrl ||
|
||||
profileResponse.blogUrl != blogUrl ||
|
||||
profileResponse.websiteUrl != websiteUrl ||
|
||||
profileResponse.gender != _genderLiveData.value ||
|
||||
insertTags.isNotEmpty() ||
|
||||
removeTags.isNotEmpty() ||
|
||||
profileResponse.introduce != introduce
|
||||
) {
|
||||
val request = ProfileUpdateRequest(
|
||||
email = profileResponse.email,
|
||||
nickname = null,
|
||||
youtubeUrl = if (profileResponse.youtubeUrl != youtubeUrl) {
|
||||
youtubeUrl
|
||||
} else {
|
||||
null
|
||||
},
|
||||
instagramUrl = if (profileResponse.instagramUrl != instagramUrl) {
|
||||
instagramUrl
|
||||
} else {
|
||||
null
|
||||
},
|
||||
blogUrl = if (profileResponse.blogUrl != blogUrl) {
|
||||
blogUrl
|
||||
} else {
|
||||
null
|
||||
},
|
||||
websiteUrl = if (profileResponse.websiteUrl != websiteUrl) {
|
||||
websiteUrl
|
||||
} else {
|
||||
null
|
||||
},
|
||||
gender = if (profileResponse.gender != _genderLiveData.value) {
|
||||
_genderLiveData.value
|
||||
} else {
|
||||
null
|
||||
},
|
||||
introduce = if (profileResponse.introduce != introduce) {
|
||||
introduce
|
||||
} else {
|
||||
null
|
||||
},
|
||||
insertTags = insertTags.ifEmpty { null },
|
||||
removeTags = removeTags.ifEmpty { null }
|
||||
)
|
||||
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.updateProfile(request, "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success) {
|
||||
_toastLiveData.postValue(
|
||||
"프로필이 변경되었습니다."
|
||||
)
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
} else run {
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePassword(onSuccess: () -> Unit) {
|
||||
val email = SharedPreferenceManager.email
|
||||
|
||||
if (currentPassword.isBlank()) {
|
||||
_toastLiveData.postValue("현재 비밀번호를 입력하세요")
|
||||
return
|
||||
}
|
||||
|
||||
if (newPassword.isBlank()) {
|
||||
_toastLiveData.postValue("변경할 비밀번호를 입력하세요")
|
||||
return
|
||||
}
|
||||
|
||||
if (newPasswordConfirm != newPassword) {
|
||||
_toastLiveData.postValue("비밀번호가 일치하지 않습니다.")
|
||||
return
|
||||
}
|
||||
|
||||
val request = ProfileUpdateRequest(
|
||||
email = email,
|
||||
password = currentPassword,
|
||||
modifyPassword = newPassword
|
||||
)
|
||||
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.updateProfile(request, "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success) {
|
||||
_toastLiveData.postValue(
|
||||
"비밀번호가 변경되었습니다."
|
||||
)
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun removeTag(tag: String) {
|
||||
tags.remove(tag)
|
||||
if (insertTags.contains(tag)) {
|
||||
insertTags.remove(tag)
|
||||
} else {
|
||||
removeTags.add(tag)
|
||||
}
|
||||
_selectedTagLiveData.postValue(tags.toList())
|
||||
}
|
||||
|
||||
fun addTag(tag: String) {
|
||||
tags.add(tag)
|
||||
if (removeTags.contains(tag)) {
|
||||
removeTags.remove(tag)
|
||||
} else {
|
||||
insertTags.add(tag)
|
||||
}
|
||||
_selectedTagLiveData.postValue(tags.toList())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.nickname
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class GetChangeNicknamePriceResponse(@SerializedName("price") val price: Int)
|
|
@ -0,0 +1,83 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.nickname
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityNicknameUpdateBinding
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class NicknameUpdateActivity : BaseActivity<ActivityNicknameUpdateBinding>(
|
||||
ActivityNicknameUpdateBinding::inflate
|
||||
) {
|
||||
|
||||
private val viewModel: NicknameUpdateViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
bindData()
|
||||
viewModel.getChangeNicknamePrice()
|
||||
|
||||
binding.etNickname.setText(SharedPreferenceManager.nickname)
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
binding.toolbar.tvBack.text = "닉네임 변경"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
|
||||
binding.tvCheckNickname.setOnClickListener {
|
||||
viewModel.checkNickname()
|
||||
}
|
||||
|
||||
binding.tvChangeNickname.setOnClickListener {
|
||||
viewModel.changeNickname { finish() }
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindData() {
|
||||
compositeDisposable.add(
|
||||
binding.etNickname.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.isCheckedNickname = false
|
||||
viewModel.nickname = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
it?.let {
|
||||
Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(this) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.priceLiveData.observe(this) {
|
||||
if (it > 0) {
|
||||
binding.tvChangeNickname.text = "${it}코인으로 닉네임 변경하기"
|
||||
} else {
|
||||
binding.tvChangeNickname.text = "닉네임 변경하기"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.nickname
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateRequest
|
||||
import kr.co.vividnext.sodalive.user.UserRepository
|
||||
|
||||
class NicknameUpdateViewModel(private val repository: UserRepository) : BaseViewModel() {
|
||||
var nickname = ""
|
||||
|
||||
private val _priceLiveData = MutableLiveData(0)
|
||||
val priceLiveData: LiveData<Int>
|
||||
get() = _priceLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
var isCheckedNickname = false
|
||||
|
||||
fun getChangeNicknamePrice() {
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.getChangeNicknamePrice(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
if (it.success && it.data != null) {
|
||||
_priceLiveData.value = it.data.price
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun checkNickname() {
|
||||
if (nickname.isNotBlank()) {
|
||||
_isLoading.value = true
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.checkNickname(nickname)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
if (it.success) {
|
||||
isCheckedNickname = true
|
||||
_toastLiveData.postValue("사용가능한 닉네임 입니다.")
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
} else {
|
||||
_toastLiveData.postValue("닉네임을 입력하세요.")
|
||||
}
|
||||
}
|
||||
|
||||
fun changeNickname(onSuccess: () -> Unit) {
|
||||
if (isCheckedNickname) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
repository.changeNickname(
|
||||
request = ProfileUpdateRequest(
|
||||
email = SharedPreferenceManager.email,
|
||||
nickname = nickname
|
||||
),
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
if (it.success) {
|
||||
_toastLiveData.postValue("닉네임이 변경되었습니다.")
|
||||
SharedPreferenceManager.nickname = nickname
|
||||
onSuccess()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
} else {
|
||||
_toastLiveData.postValue("닉네임 중복체크를 해주세요.")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.password
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import com.jakewharton.rxbinding4.widget.textChanges
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityModifyPasswordBinding
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ModifyPasswordActivity : BaseActivity<ActivityModifyPasswordBinding>(
|
||||
ActivityModifyPasswordBinding::inflate
|
||||
) {
|
||||
|
||||
private val viewModel: ProfileUpdateViewModel by inject()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
bindData()
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
compositeDisposable.add(
|
||||
binding.etCurrentPassword.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.currentPassword = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etNewPassword.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.newPassword = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etNewPasswordConfirm.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
viewModel.newPasswordConfirm = it.toString()
|
||||
}
|
||||
)
|
||||
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
it?.let {
|
||||
Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
binding.toolbar.tvBack.text = "비밀번호 변경"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
binding.tvModifyPassword.setOnClickListener {
|
||||
viewModel.updatePassword { finish() }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.tag
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemLiveTagBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
|
||||
class MemberTagAdapter(
|
||||
private val selectedTags: Set<String>,
|
||||
private val onItemClick: (String, Boolean) -> Boolean
|
||||
) : RecyclerView.Adapter<MemberTagAdapter.ViewHolder>() {
|
||||
inner class ViewHolder(
|
||||
private val binding: ItemLiveTagBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
private var isChecked = false
|
||||
|
||||
fun bind(item: MemberTagResponse) {
|
||||
if (selectedTags.contains(item.tag)) {
|
||||
binding.ivTagChecked.visibility = View.VISIBLE
|
||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_9970ff)
|
||||
isChecked = true
|
||||
} else {
|
||||
binding.ivTagChecked.visibility = View.GONE
|
||||
binding.ivTag.background = null
|
||||
isChecked = false
|
||||
}
|
||||
|
||||
binding.ivTag.load(item.image) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
transformations(RoundedCornersTransformation(30f.dpToPx()))
|
||||
}
|
||||
binding.tvTag.text = item.tag
|
||||
|
||||
binding.root.setOnClickListener {
|
||||
isChecked = !isChecked
|
||||
|
||||
if (onItemClick(item.tag, isChecked)) {
|
||||
if (isChecked) {
|
||||
binding.ivTagChecked.visibility = View.VISIBLE
|
||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_9970ff)
|
||||
} else {
|
||||
binding.ivTagChecked.visibility = View.GONE
|
||||
binding.ivTag.background = null
|
||||
}
|
||||
} else {
|
||||
isChecked = !isChecked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val items = mutableSetOf<MemberTagResponse>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(
|
||||
ItemLiveTagBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(items.toList()[position])
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.tag
|
||||
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
|
||||
interface MemberTagApi {
|
||||
@GET("/member/tag")
|
||||
fun getTags(
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<MemberTagResponse>>>
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.tag
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class MemberTagFragment(
|
||||
private val selectedTags: Set<String>,
|
||||
private val onItemClick: (String, Boolean) -> Boolean
|
||||
) : BottomSheetDialogFragment() {
|
||||
private val viewModel: MemberTagViewModel by inject()
|
||||
|
||||
private lateinit var adapter: MemberTagAdapter
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
|
||||
dialog.setOnShowListener {
|
||||
val d = it as BottomSheetDialog
|
||||
val bottomSheet = d.findViewById<FrameLayout>(
|
||||
com.google.android.material.R.id.design_bottom_sheet
|
||||
)
|
||||
if (bottomSheet != null) {
|
||||
BottomSheetBehavior.from(bottomSheet).state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View = inflater.inflate(R.layout.fragment_creator_tag, container, false)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
view.findViewById<ImageView>(R.id.iv_close).setOnClickListener {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
|
||||
view.findViewById<TextView>(R.id.tv_select).setOnClickListener {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
|
||||
setupAdapter(view)
|
||||
bindData()
|
||||
|
||||
viewModel.getTags()
|
||||
}
|
||||
|
||||
private fun setupAdapter(view: View) {
|
||||
val recyclerView = view.findViewById<RecyclerView>(R.id.rv_tags)
|
||||
adapter = MemberTagAdapter(selectedTags) { tag, isChecked ->
|
||||
return@MemberTagAdapter onItemClick(tag, isChecked)
|
||||
}
|
||||
|
||||
recyclerView.setHasFixedSize(true)
|
||||
recyclerView.layoutManager = GridLayoutManager(requireContext(), 4)
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
|
||||
outRect.top = 13.3f.dpToPx().toInt()
|
||||
outRect.bottom = 13.3f.dpToPx().toInt()
|
||||
outRect.left = 13.3f.dpToPx().toInt()
|
||||
outRect.right = 13.3f.dpToPx().toInt()
|
||||
}
|
||||
})
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun bindData() {
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
|
||||
viewModel.tagLiveData.observe(viewLifecycleOwner) {
|
||||
adapter.items.addAll(it)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(resources.displayMetrics.widthPixels)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.tag
|
||||
|
||||
class MemberTagRepository(private val api: MemberTagApi) {
|
||||
fun getTags(token: String) = api.getTags(authHeader = token)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.tag
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class MemberTagResponse(
|
||||
@SerializedName("id") val id: Long,
|
||||
@SerializedName("tag") val tag: String,
|
||||
@SerializedName("image") val image: String
|
||||
)
|
|
@ -0,0 +1,53 @@
|
|||
package kr.co.vividnext.sodalive.mypage.profile.tag
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
|
||||
class MemberTagViewModel(private val repository: MemberTagRepository) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private val _tagLiveData = MutableLiveData<List<MemberTagResponse>>()
|
||||
val tagLiveData: LiveData<List<MemberTagResponse>>
|
||||
get() = _tagLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
fun getTags() {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
repository.getTags("Bearer ${SharedPreferenceManager.token}")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
_tagLiveData.postValue(it.data!!)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -6,6 +6,9 @@ import kr.co.vividnext.sodalive.explorer.profile.MemberBlockRequest
|
|||
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
|
||||
import kr.co.vividnext.sodalive.main.PushTokenUpdateRequest
|
||||
import kr.co.vividnext.sodalive.mypage.MyPageResponse
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileResponse
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateRequest
|
||||
import kr.co.vividnext.sodalive.mypage.profile.nickname.GetChangeNicknamePriceResponse
|
||||
import kr.co.vividnext.sodalive.settings.notification.GetMemberInfoResponse
|
||||
import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingRequest
|
||||
import kr.co.vividnext.sodalive.settings.signout.SignOutRequest
|
||||
|
@ -101,4 +104,37 @@ interface UserApi {
|
|||
|
||||
@POST("/member/logout/all")
|
||||
fun logoutAll(@Header("Authorization") authHeader: String): Single<ApiResponse<Any>>
|
||||
|
||||
@GET("/member/change/nickname/price")
|
||||
fun getChangeNicknamePrice(
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetChangeNicknamePriceResponse>>
|
||||
|
||||
@GET("/member/check/nickname")
|
||||
fun checkNickname(@Query("nickname") nickname: String): Single<ApiResponse<Any>>
|
||||
|
||||
@PUT("/member/change/nickname")
|
||||
fun changeNickname(
|
||||
@Body request: ProfileUpdateRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@GET("/member")
|
||||
fun getMyProfile(
|
||||
@Query("container") container: String = "aos",
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<ProfileResponse>>
|
||||
|
||||
@PUT("/member")
|
||||
fun updateProfile(
|
||||
@Body request: ProfileUpdateRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<ProfileResponse>>
|
||||
|
||||
@Multipart
|
||||
@POST("/member/image")
|
||||
fun updateProfileImage(
|
||||
@Part multipartFile: MultipartBody.Part,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<String>>
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import kr.co.vividnext.sodalive.explorer.profile.MemberBlockRequest
|
|||
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
|
||||
import kr.co.vividnext.sodalive.main.PushTokenUpdateRequest
|
||||
import kr.co.vividnext.sodalive.mypage.MyPageResponse
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileResponse
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateRequest
|
||||
import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingRequest
|
||||
import kr.co.vividnext.sodalive.user.find_password.ForgotPasswordRequest
|
||||
import kr.co.vividnext.sodalive.user.login.LoginRequest
|
||||
|
@ -79,4 +81,31 @@ class UserRepository(private val userApi: UserApi) {
|
|||
|
||||
fun logout(token: String) = userApi.logout(authHeader = token)
|
||||
fun logoutAllDevice(token: String) = userApi.logoutAll(authHeader = token)
|
||||
|
||||
fun getChangeNicknamePrice(token: String) = userApi.getChangeNicknamePrice(authHeader = token)
|
||||
|
||||
fun checkNickname(nickname: String) = userApi.checkNickname(nickname)
|
||||
|
||||
fun changeNickname(
|
||||
request: ProfileUpdateRequest,
|
||||
token: String
|
||||
) = userApi.changeNickname(request = request, authHeader = token)
|
||||
|
||||
fun updateProfileImage(
|
||||
multipartFile: MultipartBody.Part,
|
||||
token: String
|
||||
): Single<ApiResponse<String>> {
|
||||
return userApi.updateProfileImage(multipartFile, authHeader = token)
|
||||
}
|
||||
|
||||
fun updateProfile(
|
||||
request: ProfileUpdateRequest,
|
||||
token: String
|
||||
): Single<ApiResponse<ProfileResponse>> {
|
||||
return userApi.updateProfile(request, authHeader = token)
|
||||
}
|
||||
|
||||
fun getProfile(token: String): Single<ApiResponse<ProfileResponse>> {
|
||||
return userApi.getMyProfile(authHeader = token)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="30dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_9970ff" />
|
||||
<corners android:radius="8dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/detail_toolbar" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/fl_modify_password"
|
||||
android:layout_below="@+id/toolbar">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="40dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:gravity="center"
|
||||
android:lineSpacingExtra="6.7sp"
|
||||
android:text="안전한 비밀번호로 내 내 정보를 보호하세요"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="13.3sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="26.7dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="현재 비밀번호"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_current_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:hint="현재 비밀번호를 입력해주세요."
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebPassword"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="26.7dp"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="신규 비밀번호"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_new_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:hint="신규 비밀번호를 입력해주세요(영문, 숫자 포함 8자 이상)"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebPassword"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="26.7dp"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="신규 비밀번호 확인"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_new_password_confirm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:hint="신규 비밀번호를 재입력해주세요"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebPassword"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="26.7dp"
|
||||
android:layout_marginTop="13.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="* 영문, 숫자 포함 8자 이상"
|
||||
android:textColor="@color/color_dd4500"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_modify_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@drawable/bg_top_round_corner_16_7_222222">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_modify_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="13.3dp"
|
||||
android:layout_marginVertical="13.7dp"
|
||||
android:background="@drawable/bg_round_corner_10_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="16dp"
|
||||
android:text="비밀번호 변경하기"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18.3sp" />
|
||||
|
||||
</FrameLayout>
|
||||
</RelativeLayout>
|
|
@ -0,0 +1,111 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/detail_toolbar" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/toolbar">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="닉네임 변경으로 인해 피해를 입는 사용자가 지속적으로 발생하여 닉네임 변경을 부득이하게 유료로 전환합니다."
|
||||
android:textColor="@color/color_eeeeee" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="최초 1회에 한해서 무료로 변경이 가능하고, 그 이후부터는 유료로 전환됩니다."
|
||||
android:textColor="@color/color_dd4500" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="닉네임 (최대 12자)"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_nickname"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:hint="닉네임"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebEditText"
|
||||
android:maxLength="12"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_check_nickname"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginTop="21.3dp"
|
||||
android:background="@drawable/bg_round_corner_8_transparent_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="13.3dp"
|
||||
android:text="중복확인"
|
||||
android:textColor="@color/color_eeeeee" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:background="@drawable/bg_top_round_corner_16_7_222222"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="13.7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_change_nickname"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_round_corner_10_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="16dp"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18.3sp"
|
||||
tools:text="1000코인으로 닉네임 변경하기" />
|
||||
|
||||
</FrameLayout>
|
||||
</RelativeLayout>
|
|
@ -0,0 +1,532 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/detail_toolbar" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/fl_save"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="85dp"
|
||||
android:layout_height="85dp"
|
||||
android:layout_marginTop="13.3dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_profile"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@null"
|
||||
tools:src="@drawable/ic_launcher_background" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_photo_picker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="@drawable/bg_round_corner_33_3_9970ff"
|
||||
android:contentDescription="@null"
|
||||
android:padding="10dp"
|
||||
android:src="@drawable/ic_camera" />
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="13.3dp"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:background="@drawable/bg_round_corner_6_7_222222"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="이메일"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:layout_marginTop="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="tkdekatk121212@gmail.com"
|
||||
android:textColor="@color/color_777777"
|
||||
android:textSize="13.3sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/color_b3909090" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="비밀번호"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="6.7dp"
|
||||
android:layout_toStartOf="@+id/tv_modify_password"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:gravity="center_vertical"
|
||||
android:text="********"
|
||||
android:textColor="@color/color_777777"
|
||||
android:textSize="13.3sp" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignBottom="@+id/tv_modify_password"
|
||||
android:layout_toStartOf="@+id/tv_modify_password"
|
||||
android:background="@color/color_b3909090" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_modify_password"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginStart="13.3dp"
|
||||
android:background="@drawable/bg_round_corner_8_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:paddingHorizontal="22.7dp"
|
||||
android:paddingVertical="13.3dp"
|
||||
android:text="비밀번호 변경"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13.3sp" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="13.3dp"
|
||||
android:layout_marginTop="13.3dp"
|
||||
android:background="@drawable/bg_round_corner_6_7_222222"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="0dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="닉네임"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_nickname"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="6.7dp"
|
||||
android:layout_toStartOf="@+id/tv_change_nickname"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="13.3sp"
|
||||
tools:text="닉네임" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignBottom="@+id/tv_change_nickname"
|
||||
android:layout_toStartOf="@+id/tv_change_nickname"
|
||||
android:background="@color/color_b3909090" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_change_nickname"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginStart="13.3dp"
|
||||
android:background="@drawable/bg_round_corner_8_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:paddingHorizontal="22.7dp"
|
||||
android:paddingVertical="13.3dp"
|
||||
android:text="닉네임 변경"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13.3sp" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16.7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="성별"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:paddingVertical="13.3dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_female"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:button="@null"
|
||||
android:drawablePadding="13.3dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="여자"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="13.3sp"
|
||||
app:drawableStartCompat="@drawable/ic_radio_button_select" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_male"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:button="@null"
|
||||
android:drawablePadding="13.3dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="남자"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="13.3sp"
|
||||
app:drawableStartCompat="@drawable/ic_radio_button_select" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_none"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:button="@null"
|
||||
android:drawablePadding="13.3dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="공개 안 함"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="13.3sp"
|
||||
app:drawableStartCompat="@drawable/ic_radio_button_select" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="13.3dp"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:layout_marginBottom="13.3dp"
|
||||
android:background="@drawable/bg_round_corner_6_7_222222"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="인스타그램"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_instagram"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:hint="인스타그램 URL"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebEditText"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="18dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="유튜브 채널"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_youtube"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:hint="유튜브 채널 URL"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebEditText"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="18dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="웹사이트"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_website"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:hint="웹사이트 URL"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebEditText"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="18dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="6.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="블로그"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_blog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/edittext_underline"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:hint="블로그 URL"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textWebEditText"
|
||||
android:paddingHorizontal="6.7dp"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
android:theme="@style/EditTextStyle"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="13.3dp"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:background="@drawable/bg_round_corner_6_7_222222"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="20dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="관심사"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="16.7sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_select_tag"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="13.3dp"
|
||||
android:background="@drawable/bg_round_corner_24_3_339970ff_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="13.7dp"
|
||||
android:text="관심사 선택"
|
||||
android:textColor="@color/color_9970ff"
|
||||
android:textSize="16.7sp" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_select_tags"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="13.3dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone" />
|
||||
</HorizontalScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="13.3dp"
|
||||
android:layout_marginVertical="40dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:lineSpacingExtra="5sp"
|
||||
android:text="소개글"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="16.7sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_introduce"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="13.3dp"
|
||||
android:background="@drawable/bg_round_corner_6_7_222222"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:gravity="top"
|
||||
android:hint="소개글을 입력하세요"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textMultiLine"
|
||||
android:minHeight="200dp"
|
||||
android:padding="20dp"
|
||||
android:textColor="@color/color_bbbbbb"
|
||||
android:textColorHint="@color/color_777777"
|
||||
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||
android:textSize="13.3sp"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_save"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_top_round_corner_16_7_222222"
|
||||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="13.7dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_round_corner_10_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="16dp"
|
||||
android:text="저장하기"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18.3sp" />
|
||||
|
||||
</FrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/color_222222"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="26.7dp"
|
||||
android:layout_marginTop="26.7dp"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="관심사 선택"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18.3sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:contentDescription="@null"
|
||||
android:padding="29dp"
|
||||
android:src="@drawable/ic_close_white" />
|
||||
</RelativeLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_tags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_select"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="13.3dp"
|
||||
android:background="@drawable/bg_round_corner_10_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="16dp"
|
||||
android:text="선택하기"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18.3sp" />
|
||||
|
||||
</LinearLayout>
|
Loading…
Reference in New Issue