Firebase 추가
Crashlytics 추가 RemoteConfig 이용한 강제 업데이트 로직 추가
This commit is contained in:
parent
edbaceba0b
commit
fd8c4e726d
|
@ -20,7 +20,8 @@ bin/
|
||||||
gen/
|
gen/
|
||||||
out/
|
out/
|
||||||
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||||
release/
|
/release/
|
||||||
|
/debug/
|
||||||
|
|
||||||
# Gradle files
|
# Gradle files
|
||||||
.gradle/
|
.gradle/
|
||||||
|
@ -302,7 +303,7 @@ fabric.properties
|
||||||
### AndroidStudio Patch ###
|
### AndroidStudio Patch ###
|
||||||
|
|
||||||
!/gradle/wrapper/gradle-wrapper.jar
|
!/gradle/wrapper/gradle-wrapper.jar
|
||||||
app/debug/*
|
app/debug/
|
||||||
app/release/*
|
app/release/
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/macos,android,androidstudio,visualstudiocode,git,kotlin,java
|
# End of https://www.toptal.com/developers/gitignore/api/macos,android,androidstudio,visualstudiocode,git,kotlin,java
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'org.jetbrains.kotlin.android'
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
id 'com.google.gms.google-services'
|
||||||
id 'com.google.android.gms.oss-licenses-plugin'
|
id 'com.google.android.gms.oss-licenses-plugin'
|
||||||
|
|
||||||
id 'kotlin-kapt'
|
id 'kotlin-kapt'
|
||||||
|
@ -8,6 +9,7 @@ plugins {
|
||||||
id 'org.jlleitschuh.gradle.ktlint'
|
id 'org.jlleitschuh.gradle.ktlint'
|
||||||
|
|
||||||
id 'io.objectbox'
|
id 'io.objectbox'
|
||||||
|
id("com.google.firebase.crashlytics")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -115,4 +117,12 @@ dependencies {
|
||||||
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
||||||
|
|
||||||
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1'
|
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1'
|
||||||
|
|
||||||
|
// Firebase
|
||||||
|
implementation platform('com.google.firebase:firebase-bom:32.2.0')
|
||||||
|
implementation 'com.google.firebase:firebase-dynamic-links-ktx'
|
||||||
|
implementation 'com.google.firebase:firebase-crashlytics-ktx'
|
||||||
|
implementation 'com.google.firebase:firebase-analytics-ktx'
|
||||||
|
implementation 'com.google.firebase:firebase-messaging-ktx'
|
||||||
|
implementation 'com.google.firebase:firebase-config-ktx'
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "758414412471",
|
||||||
|
"project_id": "sodalive-test",
|
||||||
|
"storage_bucket": "sodalive-test.appspot.com"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:758414412471:android:dcea9dff87fa125c7a5b32",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "kr.co.vividnext.sodalive.debug"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "758414412471-g35socquiplhaamhfl4e6bsta5blabi7.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyAeNDVDY_r5afz97L1NPvQC6oFy5lPXHNI"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": [
|
||||||
|
{
|
||||||
|
"client_id": "758414412471-g35socquiplhaamhfl4e6bsta5blabi7.apps.googleusercontent.com",
|
||||||
|
"client_type": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package kr.co.vividnext.sodalive.base
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import kr.co.vividnext.sodalive.databinding.DialogSodaBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
open class SodaDialog(
|
||||||
|
activity: Activity,
|
||||||
|
layoutInflater: LayoutInflater,
|
||||||
|
title: String,
|
||||||
|
desc: String,
|
||||||
|
confirmButtonTitle: String,
|
||||||
|
confirmButtonClick: () -> Unit,
|
||||||
|
cancelButtonTitle: String = "",
|
||||||
|
cancelButtonClick: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val alertDialog: AlertDialog
|
||||||
|
|
||||||
|
val dialogView = DialogSodaBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
init {
|
||||||
|
val dialogBuilder = AlertDialog.Builder(activity)
|
||||||
|
dialogBuilder.setView(dialogView.root)
|
||||||
|
|
||||||
|
alertDialog = dialogBuilder.create()
|
||||||
|
alertDialog.setCancelable(false)
|
||||||
|
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
|
||||||
|
dialogView.tvTitle.text = title
|
||||||
|
dialogView.tvDesc.text = desc
|
||||||
|
|
||||||
|
dialogView.tvCancel.text = cancelButtonTitle
|
||||||
|
dialogView.tvCancel.setOnClickListener {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
cancelButtonClick?.let { it() }
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvConfirm.text = confirmButtonTitle
|
||||||
|
dialogView.tvConfirm.setOnClickListener {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
confirmButtonClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvCancel.visibility = if (cancelButtonTitle.isNotBlank()) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvConfirm.visibility = if (confirmButtonTitle.isNotBlank()) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show(width: Int) {
|
||||||
|
alertDialog.show()
|
||||||
|
|
||||||
|
val lp = WindowManager.LayoutParams()
|
||||||
|
lp.copyFrom(alertDialog.window?.attributes)
|
||||||
|
lp.width = width - (26.7f.dpToPx()).toInt()
|
||||||
|
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
|
alertDialog.window?.attributes = lp
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,4 +12,8 @@ object Constants {
|
||||||
|
|
||||||
const val EXTRA_DATA = "extra_data"
|
const val EXTRA_DATA = "extra_data"
|
||||||
const val EXTRA_TERMS = "extra_terms"
|
const val EXTRA_TERMS = "extra_terms"
|
||||||
|
const val EXTRA_USER_ID = "extra_user_id"
|
||||||
|
const val EXTRA_ROOM_ID = "extra_room_id"
|
||||||
|
|
||||||
|
const val EXTRA_AUDIO_CONTENT_ID = "extra_audio_content_id"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,21 @@ package kr.co.vividnext.sodalive.splash
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import com.google.firebase.dynamiclinks.PendingDynamicLinkData
|
||||||
|
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
|
||||||
|
import com.google.firebase.ktx.Firebase
|
||||||
|
import com.google.firebase.remoteconfig.ktx.get
|
||||||
|
import com.google.firebase.remoteconfig.ktx.remoteConfig
|
||||||
|
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
|
||||||
|
import kr.co.vividnext.sodalive.BuildConfig
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
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.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivitySplashBinding
|
import kr.co.vividnext.sodalive.databinding.ActivitySplashBinding
|
||||||
import kr.co.vividnext.sodalive.main.MainActivity
|
import kr.co.vividnext.sodalive.main.MainActivity
|
||||||
|
@ -15,21 +26,163 @@ import kr.co.vividnext.sodalive.user.login.LoginActivity
|
||||||
class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding::inflate) {
|
class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding::inflate) {
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
private val remoteConfig = Firebase.remoteConfig
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
if (SharedPreferenceManager.token.isBlank()) {
|
setupRemoteConfig()
|
||||||
showLoginActivity()
|
fetchAndroidLatestVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupRemoteConfig() {
|
||||||
|
val configSettings = remoteConfigSettings {
|
||||||
|
minimumFetchIntervalInSeconds = 300
|
||||||
|
}
|
||||||
|
remoteConfig.setConfigSettingsAsync(configSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchAndroidLatestVersion() {
|
||||||
|
remoteConfig.fetchAndActivate()
|
||||||
|
.addOnCompleteListener(this) { task ->
|
||||||
|
if (task.isSuccessful) {
|
||||||
|
handler.post {
|
||||||
|
checkAppVersion(remoteConfig["android_latest_version"].asString())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
checkFirebaseDynamicLink()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkAppVersion(latestVersion: String) {
|
||||||
|
val versions = BuildConfig.VERSION_NAME.split(".")
|
||||||
|
val latestVersions = latestVersion.split(".")
|
||||||
|
|
||||||
|
if (latestVersions.isNotEmpty() && latestVersions.size == versions.size) {
|
||||||
|
val latestMajor = latestVersions[0].toInt()
|
||||||
|
val latestMinor = latestVersions[1].toInt()
|
||||||
|
val latestPatch = latestVersions[2].toInt()
|
||||||
|
|
||||||
|
val major = versions[0].toInt()
|
||||||
|
val minor = versions[1].toInt()
|
||||||
|
val patch = versions[2].toInt()
|
||||||
|
|
||||||
|
if (latestMajor > major || (latestMajor == major && latestMinor > minor)) {
|
||||||
|
showUpdateDialog(isEssential = true)
|
||||||
|
} else if (latestMajor == major && latestMinor == minor && latestPatch > patch) {
|
||||||
|
showUpdateDialog(isEssential = false)
|
||||||
|
} else {
|
||||||
|
checkFirebaseDynamicLink()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
showMainActivity()
|
checkFirebaseDynamicLink()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showMainActivity() {
|
private fun showUpdateDialog(isEssential: Boolean = false) {
|
||||||
|
val desc = if (isEssential) {
|
||||||
|
"필수 업데이트가 있습니다.\n업데이트 후 사용가능합니다."
|
||||||
|
} else {
|
||||||
|
"최신 업데이트가 있습니다.\n업데이트 하시겠습니까?"
|
||||||
|
}
|
||||||
|
|
||||||
|
val cancelButtonClick = if (!isEssential) {
|
||||||
|
{ checkFirebaseDynamicLink() }
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
SodaDialog(
|
||||||
|
activity = this,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = "업데이트",
|
||||||
|
desc = desc,
|
||||||
|
confirmButtonTitle = "업데이트",
|
||||||
|
confirmButtonClick = {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("market://details?id=${BuildConfig.APPLICATION_ID}")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
finish()
|
||||||
|
},
|
||||||
|
cancelButtonTitle = if (isEssential) {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
"다음에"
|
||||||
|
},
|
||||||
|
cancelButtonClick = cancelButtonClick
|
||||||
|
).show(screenWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkFirebaseDynamicLink() {
|
||||||
|
Firebase.dynamicLinks
|
||||||
|
.getDynamicLink(intent)
|
||||||
|
.addOnSuccessListener(this) { getDynamicLinkSuccess(it) }
|
||||||
|
.addOnFailureListener(this) { getDynamicLinkFailure() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDynamicLinkSuccess(pendingDynamicLinkData: PendingDynamicLinkData?) {
|
||||||
|
var deepLink: Uri? = null
|
||||||
|
if (pendingDynamicLinkData != null) {
|
||||||
|
deepLink = pendingDynamicLinkData.link
|
||||||
|
}
|
||||||
|
|
||||||
|
val extras = if (deepLink != null) {
|
||||||
|
val roomIdString = deepLink.getQueryParameter("room_id")
|
||||||
|
val channelIdString = deepLink.getQueryParameter("channel_id")
|
||||||
|
val audioContentIdString = deepLink.getQueryParameter("audio_content_id")
|
||||||
|
|
||||||
|
if (roomIdString != null) {
|
||||||
|
bundleOf(
|
||||||
|
Constants.EXTRA_ROOM_ID to roomIdString.toLong()
|
||||||
|
)
|
||||||
|
} else if (channelIdString != null) {
|
||||||
|
bundleOf(
|
||||||
|
Constants.EXTRA_USER_ID to channelIdString.toLong()
|
||||||
|
)
|
||||||
|
} else if (audioContentIdString != null) {
|
||||||
|
bundleOf(
|
||||||
|
Constants.EXTRA_AUDIO_CONTENT_ID to audioContentIdString.toLong()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else if (intent.extras != null) {
|
||||||
|
intent.extras
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
startNextActivity(extras = extras)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDynamicLinkFailure() {
|
||||||
|
val extras = intent.getBundleExtra(Constants.EXTRA_DATA)
|
||||||
|
?: if (intent.extras != null) {
|
||||||
|
intent.extras
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
startNextActivity(extras = extras)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startNextActivity(extras: Bundle? = null) {
|
||||||
|
if (SharedPreferenceManager.token.isBlank()) {
|
||||||
|
showLoginActivity(extras)
|
||||||
|
} else {
|
||||||
|
showMainActivity(extras)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showMainActivity(extras: Bundle?) {
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent(applicationContext, MainActivity::class.java).apply {
|
Intent(applicationContext, MainActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_DATA, extras)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
}
|
}
|
||||||
|
@ -38,10 +191,11 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showLoginActivity() {
|
private fun showLoginActivity(extras: Bundle?) {
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent(applicationContext, LoginActivity::class.java).apply {
|
Intent(applicationContext, LoginActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_DATA, extras)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_339970ff" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_9970ff" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?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="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@drawable/bg_round_corner_10_222222">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="40dp"
|
||||||
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="@color/color_bbbbbb"
|
||||||
|
android:textSize="18.3sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="작성글 등록" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_desc"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:fontFamily="@font/gmarket_sans_medium"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="@color/color_bbbbbb"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tv_title"
|
||||||
|
tools:text="작성한 글을 등록하시겠습니까?" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16.7dp"
|
||||||
|
android:layout_marginTop="45dp"
|
||||||
|
android:layout_marginBottom="16.7dp"
|
||||||
|
android:gravity="center"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tv_desc">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_cancel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="13.3dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_round_corner_10_339970ff_9970ff"
|
||||||
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingVertical="16dp"
|
||||||
|
android:textColor="@color/color_9970ff"
|
||||||
|
android:textSize="18.3sp"
|
||||||
|
tools:text="취소" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_confirm"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
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="확인" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -16,4 +16,5 @@
|
||||||
|
|
||||||
<color name="color_b3909090">#B3909090</color>
|
<color name="color_b3909090">#B3909090</color>
|
||||||
<color name="color_88909090">#88909090</color>
|
<color name="color_88909090">#88909090</color>
|
||||||
|
<color name="color_339970ff">#339970FF</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -22,6 +22,8 @@ plugins {
|
||||||
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
|
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
|
||||||
|
|
||||||
id "org.jlleitschuh.gradle.ktlint" version "11.2.0"
|
id "org.jlleitschuh.gradle.ktlint" version "11.2.0"
|
||||||
|
id 'com.google.gms.google-services' version '4.3.15' apply false
|
||||||
|
id("com.google.firebase.crashlytics") version "2.9.7" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
task clean(type: Delete) {
|
||||||
|
|
Loading…
Reference in New Issue