Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/300 인앱 웹뷰 환경에서 공연 등록하기 #307

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,9 @@ internal class AuthDataSource @Inject constructor(
setUserProperty("nickname", user.nickname)
}
}

/**
* @return [accessToken, refreshToken]
*/
fun getTokens(): Flow<Pair<String, String>> = data.map { it.accessToken to it.refreshToken }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.nexters.boolti.data.datasource.TokenDataSource
import com.nexters.boolti.data.datasource.UserDataSource
import com.nexters.boolti.data.network.response.LoginResponse
import com.nexters.boolti.domain.model.LoginUserState
import com.nexters.boolti.domain.model.TokenPair
import com.nexters.boolti.domain.model.User
import com.nexters.boolti.domain.repository.AuthRepository
import com.nexters.boolti.domain.request.EditProfileRequest
Expand Down Expand Up @@ -70,4 +71,8 @@ internal class AuthRepositoryImpl @Inject constructor(
runCatching { userDateSource.edit(editProfileRequest) }
.onSuccess { authDataSource.updateUser(it) }
.mapCatching {}

override fun getTokens(): Flow<TokenPair> = authDataSource.getTokens().map {
TokenPair(it.first, it.second)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.nexters.boolti.domain.model

data class TokenPair(
val accessToken: String,
val refreshToken: String,
) {
val isLoggedIn: Boolean = accessToken.isNotBlank() && refreshToken.isNotBlank()
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.nexters.boolti.domain.repository

import com.nexters.boolti.domain.model.LoginUserState
import com.nexters.boolti.domain.model.TokenPair
import com.nexters.boolti.domain.model.User
import com.nexters.boolti.domain.request.EditProfileRequest
import com.nexters.boolti.domain.request.LoginRequest
Expand Down Expand Up @@ -28,4 +29,6 @@ interface AuthRepository {
val cachedUser: Flow<User?>

suspend fun editProfile(editProfileRequest: EditProfileRequest): Result<Unit>

fun getTokens(): Flow<TokenPair>
}
3 changes: 2 additions & 1 deletion presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,21 @@ android {
consumerProguardFiles("consumer-rules.pro")
buildConfigField("String", "PACKAGE_NAME", "\"${libs.versions.packageName.get()}\"")
buildConfigField("String", "VERSION_NAME", "\"${libs.versions.versionName.get()}\"")
buildConfigField("String", "DEV_SUBDOMAIN", getLocalProperty("DEV_SUBDOMAIN"))
}

buildTypes {
debug {
buildConfigField("String", "TOSS_CLIENT_KEY", getLocalProperty("DEV_TOSS_CLIENT_KEY"))
buildConfigField("String", "TOSS_SECRET_KEY", getLocalProperty("DEV_TOSS_SECRET_KEY"))
buildConfigField("String", "DOMAIN", getLocalProperty("DEV_DOMAIN"))
}
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")

buildConfigField("String", "TOSS_CLIENT_KEY", getLocalProperty("PROD_TOSS_CLIENT_KEY"))
buildConfigField("String", "TOSS_SECRET_KEY", getLocalProperty("PROD_TOSS_SECRET_KEY"))
buildConfigField("String", "DOMAIN", getLocalProperty("PROD_DOMAIN"))
}
}
compileOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import com.nexters.boolti.presentation.screen.showdetail.ShowImagesScreen
import com.nexters.boolti.presentation.screen.signout.SignoutScreen
import com.nexters.boolti.presentation.screen.ticket.detail.TicketDetailScreen
import com.nexters.boolti.presentation.screen.ticketing.TicketingScreen
import com.nexters.boolti.presentation.screen.showregistration.addShowRegistration
import com.nexters.boolti.presentation.theme.BooltiTheme
import com.nexters.boolti.presentation.util.SnackbarController
import com.nexters.boolti.presentation.util.rememberNavControllerWithLog
Expand Down Expand Up @@ -252,6 +253,8 @@ fun MainNavigation(modifier: Modifier, onClickQrScan: (showId: String, showName:
popBackStack = navController::popBackStack,
)
}

addShowRegistration()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ sealed class MainDestination(val route: String) {
fun createRoute(link: Link): String =
"profileLinkEdit?id=${link.id}&title=${link.name}&url=${link.url}"
}

data object ShowRegistration : MainDestination(route = "webView")
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ fun sendMessage(
dateText: String,
buttonText: String
) {
val subDomain = if (BuildConfig.DEBUG) BuildConfig.DEV_SUBDOMAIN else ""
val giftUrl = "https://${subDomain}boolti.in/gift/$giftUuid"
val domain = BuildConfig.DOMAIN
val giftUrl = "https://${domain}/gift/$giftUuid"

val defaultFeed = FeedTemplate(
content = Content(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fun NavGraphBuilder.HomeScreen(
navigateToReservations = { navigateTo(MainDestination.Reservations.route) },
navigateToProfile = { navigateTo(MainDestination.Profile.createRoute()) },
navigateToBusiness = { navigateTo(MainDestination.Business.route) },
navigateToShowRegistration = { navigateTo(MainDestination.ShowRegistration.route) },
requireLogin = { navigateTo(MainDestination.Login.route) },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ fun HomeScreen(
navigateToReservations: () -> Unit,
navigateToProfile: () -> Unit,
navigateToBusiness: () -> Unit,
navigateToShowRegistration: () -> Unit,
requireLogin: () -> Unit,
modifier: Modifier,
viewModel: HomeViewModel = hiltViewModel(),
Expand Down Expand Up @@ -134,6 +135,7 @@ fun HomeScreen(
modifier = modifier.padding(innerPadding),
onClickShowItem = onClickShowItem,
navigateToBusiness = navigateToBusiness,
navigateToShowRegistration = navigateToShowRegistration,
)
}
composable(
Expand Down Expand Up @@ -168,6 +170,7 @@ fun HomeScreen(
onClickAccountSetting = onClickAccountSetting,
navigateToReservations = navigateToReservations,
navigateToProfile = navigateToProfile,
navigateToShowRegistration = navigateToShowRegistration,
onClickQrScan = onClickQrScan,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fun MyScreen(
onClickAccountSetting: () -> Unit,
navigateToReservations: () -> Unit,
navigateToProfile: () -> Unit,
navigateToShowRegistration: () -> Unit,
onClickQrScan: () -> Unit,
) {
val user by viewModel.user.collectAsStateWithLifecycle()
Expand All @@ -75,10 +76,7 @@ fun MyScreen(
onClickHeaderButton = if (user != null) navigateToProfile else requireLogin,
onClickAccountSetting = if (user != null) onClickAccountSetting else requireLogin,
onClickReservations = if (user != null) navigateToReservations else requireLogin,
onClickRegisterShow = {
val url = if (user != null) "https://boolti.in/home" else "https://boolti.in/login"
uriHandler.openUri(url)
},
onClickRegisterShow = navigateToShowRegistration,
onClickQrScan = if (user != null) onClickQrScan else requireLogin,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
Expand All @@ -74,6 +73,7 @@ import com.nexters.boolti.presentation.theme.point4
fun ShowScreen(
navigateToBusiness: () -> Unit,
onClickShowItem: (showId: String) -> Unit,
navigateToShowRegistration: () -> Unit,
modifier: Modifier = Modifier,
viewModel: ShowViewModel = hiltViewModel()
) {
Expand Down Expand Up @@ -144,7 +144,8 @@ fun ShowScreen(
span = { GridItemSpan(2) },
) {
Banner(
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth(),
navigateToShowRegistration = navigateToShowRegistration,
)
}

Expand Down Expand Up @@ -274,14 +275,13 @@ fun SearchBar(

@Composable
private fun Banner(
navigateToShowRegistration: () -> Unit,
modifier: Modifier = Modifier,
) {
val uriHandler = LocalUriHandler.current

Box(
modifier = modifier
.clickable {
uriHandler.openUri("https://boolti.in/login")
navigateToShowRegistration()
},
) {
Image(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.nexters.boolti.presentation.screen.showregistration

import androidx.compose.ui.Modifier
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.nexters.boolti.presentation.screen.MainDestination

fun NavGraphBuilder.addShowRegistration(
modifier: Modifier = Modifier,
) {
composable(
route = MainDestination.ShowRegistration.route,
) {
ShowRegistrationScreen(
modifier = modifier,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.nexters.boolti.presentation.screen.showregistration

import android.annotation.SuppressLint
import android.net.Uri
import android.view.ViewGroup
import android.webkit.CookieManager
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebStorage
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.hilt.navigation.compose.hiltViewModel
import com.nexters.boolti.presentation.BuildConfig
import com.nexters.boolti.presentation.util.BtWebChromeClient
import timber.log.Timber

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun ShowRegistrationScreen(
modifier: Modifier = Modifier,
viewModel: ShowRegistrationViewModel = hiltViewModel(),
) {
var filePathCallback: ValueCallback<Array<Uri>>? = null
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { uris ->
Timber.d("선택한 파일 uri 목록 : $uris")
filePathCallback?.onReceiveValue(uris.toTypedArray())
}
val domain = BuildConfig.DOMAIN
val url = "https://${domain}/show/add"

LaunchedEffect(Unit) {
CookieManager.getInstance().removeAllCookies(null)
WebStorage.getInstance().deleteAllData()

viewModel.tokens.collect { tokens ->
if (tokens == null || !tokens.isLoggedIn) return@collect

with(CookieManager.getInstance()) {
setCookie(url, "x-access-token=${tokens.accessToken}")
setCookie(url, "x-refresh-token=${tokens.refreshToken}")
flush()
}
}
}

AndroidView(
modifier = modifier,
factory = { context ->
WebView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)

webViewClient = WebViewClient()
webChromeClient = BtWebChromeClient(launchActivity = {
launcher.launch(arrayOf("image/*"))
}) { callback ->
filePathCallback = callback
}

settings.javaScriptEnabled = true
settings.domStorageEnabled = true

loadUrl(url)

Timber.d("내가 만든 쿠키 : ${CookieManager.getInstance().getCookie(url)}")
}
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.nexters.boolti.presentation.screen.showregistration

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.nexters.boolti.domain.repository.AuthRepository
import com.nexters.boolti.presentation.extension.stateInUi
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class ShowRegistrationViewModel @Inject constructor(
val authRepository: AuthRepository,
) : ViewModel() {
val tokens = authRepository.getTokens()
.stateInUi(viewModelScope, null)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.nexters.boolti.presentation.util

import android.net.Uri
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebView

class BtWebChromeClient(
private val launchActivity: () -> Unit,
private val setFilePathCallback: (ValueCallback<Array<Uri>>) -> Unit,
) : WebChromeClient() {
override fun onShowFileChooser(
webView: WebView,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams
): Boolean {
if (filePathCallback == null) return false
setFilePathCallback(filePathCallback)

launchActivity()

return true
}
}
Loading