Unverified Commit dbfcde7e authored by Filipe de Lima Brito's avatar Filipe de Lima Brito Committed by GitHub

Merge pull request #1771 from RocketChat/fix/onboarding

[FIX] Fixes for Onboarding/Authentication
parents c9471b6a 71328567
...@@ -72,6 +72,7 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -72,6 +72,7 @@ class LoginOptionsPresenter @Inject constructor(
credentialToken = oauthToken credentialToken = oauthToken
credentialSecret = oauthSecret credentialSecret = oauthSecret
loginMethod = AuthenticationEvent.AuthenticationWithOauth loginMethod = AuthenticationEvent.AuthenticationWithOauth
setupConnectionInfo(currentServer)
doAuthentication(TYPE_LOGIN_OAUTH) doAuthentication(TYPE_LOGIN_OAUTH)
} }
...@@ -79,6 +80,7 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -79,6 +80,7 @@ class LoginOptionsPresenter @Inject constructor(
setupConnectionInfo(currentServer) setupConnectionInfo(currentServer)
credentialToken = casToken credentialToken = casToken
loginMethod = AuthenticationEvent.AuthenticationWithCas loginMethod = AuthenticationEvent.AuthenticationWithCas
setupConnectionInfo(currentServer)
doAuthentication(TYPE_LOGIN_CAS) doAuthentication(TYPE_LOGIN_CAS)
} }
...@@ -86,6 +88,7 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -86,6 +88,7 @@ class LoginOptionsPresenter @Inject constructor(
setupConnectionInfo(currentServer) setupConnectionInfo(currentServer)
credentialToken = samlToken credentialToken = samlToken
loginMethod = AuthenticationEvent.AuthenticationWithSaml loginMethod = AuthenticationEvent.AuthenticationWithSaml
setupConnectionInfo(currentServer)
doAuthentication(TYPE_LOGIN_SAML) doAuthentication(TYPE_LOGIN_SAML)
} }
......
...@@ -9,6 +9,7 @@ import android.view.View ...@@ -9,6 +9,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import chat.rocket.android.R import chat.rocket.android.R
...@@ -18,11 +19,7 @@ import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo ...@@ -18,11 +19,7 @@ import chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import chat.rocket.android.authentication.loginoptions.presentation.LoginOptionsPresenter import chat.rocket.android.authentication.loginoptions.presentation.LoginOptionsPresenter
import chat.rocket.android.authentication.loginoptions.presentation.LoginOptionsView import chat.rocket.android.authentication.loginoptions.presentation.LoginOptionsView
import chat.rocket.android.authentication.ui.AuthenticationActivity import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.util.extensions.clearLightStatusBar import chat.rocket.android.util.extensions.*
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.rotateBy
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_SECRET import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_SECRET
import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN import chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import chat.rocket.android.webview.oauth.ui.oauthWebViewIntent import chat.rocket.android.webview.oauth.ui.oauthWebViewIntent
...@@ -290,7 +287,6 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -290,7 +287,6 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
} }
} }
// OAuth Accounts. // OAuth Accounts.
override fun enableLoginByFacebook() = enableAccountButton(button_facebook) override fun enableLoginByFacebook() = enableAccountButton(button_facebook)
...@@ -337,8 +333,8 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -337,8 +333,8 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
buttonColor: Int buttonColor: Int
) { ) {
val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor) val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor)
accounts_container.addView(button)
setupButtonListener(button, customOauthUrl, state, REQUEST_CODE_FOR_OAUTH) setupButtonListener(button, customOauthUrl, state, REQUEST_CODE_FOR_OAUTH)
accounts_container.addView(button)
} }
// SAML account. // SAML account.
...@@ -350,8 +346,8 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -350,8 +346,8 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
buttonColor: Int buttonColor: Int
) { ) {
val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor) val button = getCustomServiceButton(serviceName, serviceNameColor, buttonColor)
accounts_container.addView(button)
setupButtonListener(button, samlUrl, samlToken, REQUEST_CODE_FOR_SAML) setupButtonListener(button, samlUrl, samlToken, REQUEST_CODE_FOR_SAML)
accounts_container.addView(button)
} }
override fun showAccountsView() { override fun showAccountsView() {
...@@ -487,7 +483,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -487,7 +483,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
val marginTop = resources.getDimensionPixelSize(R.dimen.button_account_margin_top) val marginTop = resources.getDimensionPixelSize(R.dimen.button_account_margin_top)
params.setMargins(0, marginTop, 0, 0) params.setMargins(0, marginTop, 0, 0)
val button = Button(context) val button = Button(
ContextThemeWrapper(context, R.style.Authentication_Button),
null,
R.style.Authentication_Button
)
button.layoutParams = params button.layoutParams = params
button.text = buttonText button.text = buttonText
button.setTextColor(buttonTextColor) button.setTextColor(buttonTextColor)
......
...@@ -124,166 +124,174 @@ abstract class CheckServerPresenter constructor( ...@@ -124,166 +124,174 @@ abstract class CheckServerPresenter constructor(
if (services.isNotEmpty()) { if (services.isNotEmpty()) {
state = OauthHelper.getState() state = OauthHelper.getState()
checkEnabledOauthAccounts(services, serverUrl)
checkEnabledCasAccounts(serverUrl)
checkEnabledCustomOauthAccounts(services, serverUrl)
checkEnabledSamlAccounts(services, serverUrl)
}
} catch (exception: RocketChatException) {
Timber.e(exception)
}
}
// OAuth accounts. private fun checkEnabledOauthAccounts(services: List<Map<String,Any>>, serverUrl: String) {
if (settings.isFacebookAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_FACEBOOK)?.let { serviceMap -> if (settings.isFacebookAuthenticationEnabled()) {
getOauthClientId(serviceMap)?.let { clientId -> getServiceMap(services, SERVICE_NAME_FACEBOOK)?.let { serviceMap ->
facebookOauthUrl = getOauthClientId(serviceMap)?.let { clientId ->
OauthHelper.getFacebookOauthUrl(clientId, serverUrl, state) facebookOauthUrl =
totalSocialAccountsEnabled++ OauthHelper.getFacebookOauthUrl(clientId, serverUrl, state)
} totalSocialAccountsEnabled++
}
} }
}
}
if (settings.isGithubAuthenticationEnabled()) { if (settings.isGithubAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GITHUB)?.let { serviceMap -> getServiceMap(services, SERVICE_NAME_GITHUB)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId -> getOauthClientId(serviceMap)?.let { clientId ->
githubOauthUrl = githubOauthUrl =
OauthHelper.getGithubOauthUrl(clientId, state) OauthHelper.getGithubOauthUrl(clientId, state)
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
}
}
} }
}
}
if (settings.isGoogleAuthenticationEnabled()) { if (settings.isGoogleAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GOOGLE)?.let { serviceMap -> getServiceMap(services, SERVICE_NAME_GOOGLE)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId -> getOauthClientId(serviceMap)?.let { clientId ->
googleOauthUrl = googleOauthUrl =
OauthHelper.getGoogleOauthUrl(clientId, serverUrl, state) OauthHelper.getGoogleOauthUrl(clientId, serverUrl, state)
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
}
}
} }
}
}
if (settings.isLinkedinAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_LINKEDIN)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId ->
linkedinOauthUrl =
OauthHelper.getLinkedinOauthUrl(clientId, serverUrl, state)
totalSocialAccountsEnabled++
}
}
}
if (settings.isLinkedinAuthenticationEnabled()) { if (settings.isGitlabAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_LINKEDIN)?.let { serviceMap -> getServiceMap(services, SERVICE_NAME_GILAB)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId -> getOauthClientId(serviceMap)?.let { clientId ->
linkedinOauthUrl = gitlabOauthUrl = if (settings.gitlabUrl() != null) {
OauthHelper.getLinkedinOauthUrl(clientId, serverUrl, state) OauthHelper.getGitlabOauthUrl(
totalSocialAccountsEnabled++ host = settings.gitlabUrl(),
} clientId = clientId,
serverUrl = serverUrl,
state = state
)
} else {
OauthHelper.getGitlabOauthUrl(
clientId = clientId,
serverUrl = serverUrl,
state = state
)
} }
totalSocialAccountsEnabled++
} }
}
}
if (settings.isGitlabAuthenticationEnabled()) { if (settings.isWordpressAuthenticationEnabled()) {
getServiceMap(services, SERVICE_NAME_GILAB)?.let { serviceMap -> getServiceMap(services, SERVICE_NAME_WORDPRESS)?.let { serviceMap ->
getOauthClientId(serviceMap)?.let { clientId -> getOauthClientId(serviceMap)?.let { clientId ->
gitlabOauthUrl = if (settings.gitlabUrl() != null) { wordpressOauthUrl =
OauthHelper.getGitlabOauthUrl( if (settings.wordpressUrl().isNullOrEmpty()) {
host = settings.gitlabUrl(), OauthHelper.getWordpressComOauthUrl(
clientId = clientId, clientId,
serverUrl = serverUrl, serverUrl,
state = state state
) )
} else { } else {
OauthHelper.getGitlabOauthUrl( OauthHelper.getWordpressCustomOauthUrl(
clientId = clientId, getCustomOauthHost(serviceMap)
serverUrl = serverUrl, ?: "https://public-api.wordpress.com",
state = state getCustomOauthAuthorizePath(serviceMap)
?: "/oauth/authorize",
clientId,
serverUrl,
SERVICE_NAME_WORDPRESS,
state,
getCustomOauthScope(serviceMap) ?: "openid"
) )
} }
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
}
}
} }
}
}
}
if (settings.isWordpressAuthenticationEnabled()) { private fun checkEnabledCasAccounts(serverUrl: String) {
getServiceMap(services, SERVICE_NAME_WORDPRESS)?.let { serviceMap -> if (settings.isCasAuthenticationEnabled()) {
getOauthClientId(serviceMap)?.let { clientId -> casToken = generateRandomString(17)
wordpressOauthUrl = casLoginUrl = settings.casLoginUrl().casUrl(serverUrl, casToken.toString())
if (settings.wordpressUrl().isNullOrEmpty()) { totalSocialAccountsEnabled++
OauthHelper.getWordpressComOauthUrl( }
clientId, }
serverUrl,
state
)
} else {
OauthHelper.getWordpressCustomOauthUrl(
getCustomOauthHost(serviceMap)
?: "https://public-api.wordpress.com",
getCustomOauthAuthorizePath(serviceMap)
?: "/oauth/authorize",
clientId,
serverUrl,
SERVICE_NAME_WORDPRESS,
state,
getCustomOauthScope(serviceMap) ?: "openid"
)
}
totalSocialAccountsEnabled++
}
}
}
// CAS account. private fun checkEnabledCustomOauthAccounts(services: List<Map<String,Any>>, serverUrl: String) {
if (settings.isCasAuthenticationEnabled()) { getCustomOauthServices(services).let {
casToken = generateRandomString(17) for (serviceMap in it) {
casLoginUrl = settings.casLoginUrl().casUrl(serverUrl, casToken.toString()) customOauthServiceName = getCustomOauthServiceName(serviceMap)
val host = getCustomOauthHost(serviceMap)
val authorizePath = getCustomOauthAuthorizePath(serviceMap)
val clientId = getOauthClientId(serviceMap)
val scope = getCustomOauthScope(serviceMap)
val serviceNameTextColor =
getServiceNameColorForCustomOauthOrSaml(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap)
if (customOauthServiceName != null &&
host != null &&
authorizePath != null &&
clientId != null &&
scope != null &&
serviceNameTextColor != null &&
serviceButtonColor != null
) {
customOauthUrl = OauthHelper.getCustomOauthUrl(
host,
authorizePath,
clientId,
serverUrl,
customOauthServiceName.toString(),
state,
scope
)
customOauthServiceNameTextColor = serviceNameTextColor
customOauthServiceButtonColor = serviceButtonColor
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
}
}
}
// Custom OAuth account. private fun checkEnabledSamlAccounts(services: List<Map<String,Any>>, serverUrl: String) {
getCustomOauthServices(services).let { getSamlServices(services).let {
for (serviceMap in it) { samlToken = generateRandomString(17)
customOauthServiceName = getCustomOauthServiceName(serviceMap) for (serviceMap in it) {
val host = getCustomOauthHost(serviceMap) val provider = getSamlProvider(serviceMap)
val authorizePath = getCustomOauthAuthorizePath(serviceMap) samlServiceName = getSamlServiceName(serviceMap)
val clientId = getOauthClientId(serviceMap) val serviceNameTextColor =
val scope = getCustomOauthScope(serviceMap) getServiceNameColorForCustomOauthOrSaml(serviceMap)
val serviceNameTextColor = val serviceButtonColor = getServiceButtonColor(serviceMap)
getServiceNameColorForCustomOauthOrSaml(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap) if (provider != null &&
if (customOauthServiceName != null && samlServiceName != null &&
host != null && serviceNameTextColor != null &&
authorizePath != null && serviceButtonColor != null
clientId != null && ) {
scope != null && samlUrl = serverUrl.samlUrl(provider, samlToken.toString())
serviceNameTextColor != null && samlServiceNameTextColor = serviceNameTextColor
serviceButtonColor != null samlServiceButtonColor = serviceButtonColor
) { totalSocialAccountsEnabled++
customOauthUrl = OauthHelper.getCustomOauthUrl(
host,
authorizePath,
clientId,
serverUrl,
customOauthServiceName.toString(),
state,
scope
)
customOauthServiceNameTextColor = serviceNameTextColor
customOauthServiceButtonColor = serviceButtonColor
totalSocialAccountsEnabled++
}
}
}
// SAML account.
getSamlServices(services).let {
samlToken = generateRandomString(17)
for (serviceMap in it) {
val provider = getSamlProvider(serviceMap)
samlServiceName = getSamlServiceName(serviceMap)
val serviceNameTextColor =
getServiceNameColorForCustomOauthOrSaml(serviceMap)
val serviceButtonColor = getServiceButtonColor(serviceMap)
if (provider != null &&
samlServiceName != null &&
serviceNameTextColor != null &&
serviceButtonColor != null
) {
samlUrl = serverUrl.samlUrl(provider, samlToken.toString())
samlServiceNameTextColor = serviceNameTextColor
samlServiceButtonColor = serviceButtonColor
totalSocialAccountsEnabled++
}
}
} }
} }
} catch (exception: RocketChatException) {
Timber.e(exception)
} }
} }
......
...@@ -12,18 +12,19 @@ ...@@ -12,18 +12,19 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:id="@+id/accounts_container" android:id="@+id/accounts_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" android:orientation="vertical"
android:visibility="gone" android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible"> tools:visibility="visible">
<Button <Button
android:id="@+id/button_facebook" android:id="@+id/button_facebook"
style="?borderlessButtonStyle" style="?borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:background="@drawable/rounded_border" android:background="@drawable/rounded_border"
android:clickable="false" android:clickable="false"
...@@ -36,15 +37,12 @@ ...@@ -36,15 +37,12 @@
android:textColor="@color/colorPrimary" android:textColor="@color/colorPrimary"
android:textSize="16sp" android:textSize="16sp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" /> tools:visibility="visible" />
<Button <Button
android:id="@+id/button_github" android:id="@+id/button_github"
style="?borderlessButtonStyle" style="?borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:background="@drawable/rounded_border" android:background="@drawable/rounded_border"
...@@ -58,15 +56,12 @@ ...@@ -58,15 +56,12 @@
android:textColor="@color/colorPrimary" android:textColor="@color/colorPrimary"
android:textSize="16sp" android:textSize="16sp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_facebook"
tools:visibility="visible" /> tools:visibility="visible" />
<Button <Button
android:id="@+id/button_google" android:id="@+id/button_google"
style="?borderlessButtonStyle" style="?borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:background="@drawable/rounded_border" android:background="@drawable/rounded_border"
...@@ -80,15 +75,12 @@ ...@@ -80,15 +75,12 @@
android:textColor="@color/colorPrimary" android:textColor="@color/colorPrimary"
android:textSize="16sp" android:textSize="16sp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_github"
tools:visibility="visible" /> tools:visibility="visible" />
<Button <Button
android:id="@+id/button_linkedin" android:id="@+id/button_linkedin"
style="?borderlessButtonStyle" style="?borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:background="@drawable/rounded_border" android:background="@drawable/rounded_border"
...@@ -102,15 +94,12 @@ ...@@ -102,15 +94,12 @@
android:textColor="@color/colorPrimary" android:textColor="@color/colorPrimary"
android:textSize="16sp" android:textSize="16sp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_google"
tools:visibility="visible" /> tools:visibility="visible" />
<Button <Button
android:id="@+id/button_gitlab" android:id="@+id/button_gitlab"
style="?borderlessButtonStyle" style="?borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:background="@drawable/rounded_border" android:background="@drawable/rounded_border"
...@@ -124,15 +113,12 @@ ...@@ -124,15 +113,12 @@
android:textColor="@color/colorPrimary" android:textColor="@color/colorPrimary"
android:textSize="16sp" android:textSize="16sp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_linkedin"
tools:visibility="visible" /> tools:visibility="visible" />
<Button <Button
android:id="@+id/button_wordpress" android:id="@+id/button_wordpress"
style="?borderlessButtonStyle" style="?borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:background="@drawable/rounded_border" android:background="@drawable/rounded_border"
...@@ -146,9 +132,6 @@ ...@@ -146,9 +132,6 @@
android:textColor="@color/colorPrimary" android:textColor="@color/colorPrimary"
android:textSize="16sp" android:textSize="16sp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_gitlab"
tools:visibility="visible" /> tools:visibility="visible" />
<Button <Button
...@@ -158,11 +141,8 @@ ...@@ -158,11 +141,8 @@
android:clickable="false" android:clickable="false"
android:text="@string/action_login_or_sign_up" android:text="@string/action_login_or_sign_up"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_wordpress"
tools:visibility="visible" /> tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/expand_more_accounts_container" android:id="@+id/expand_more_accounts_container"
......
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
</style> </style>
<style name="Authentication.Button" parent="Widget.AppCompat.Button.Borderless"> <style name="Authentication.Button" parent="Widget.AppCompat.Button.Borderless">
<item name="android:layout_width">0dp</item> <item name="android:layout_width">match_parent</item>
<item name="android:layout_height">48dp</item> <item name="android:layout_height">48dp</item>
<item name="android:foreground">?selectableItemBackground</item> <item name="android:foreground">?selectableItemBackground</item>
<item name="android:textSize">18sp</item> <item name="android:textSize">18sp</item>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment