improve login
This commit is contained in:
parent
bc8ced0fd2
commit
31794af1fd
|
@ -26,8 +26,8 @@
|
|||
</activity>
|
||||
|
||||
|
||||
|
||||
<activity android:name=".components.login.LoginWebViewActivity">
|
||||
<activity android:name=".components.login.LoginWebViewActivity"
|
||||
android:label="@string/title_login">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".components.settings.SettingsActivity"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package at.connyduck.pixelcat.components.login
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
|
@ -29,23 +30,30 @@ import androidx.activity.viewModels
|
|||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsCompat.Type.systemBars
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import at.connyduck.pixelcat.components.main.MainActivity
|
||||
import at.connyduck.pixelcat.R
|
||||
import at.connyduck.pixelcat.components.about.AboutActivity
|
||||
import at.connyduck.pixelcat.components.general.BaseActivity
|
||||
import at.connyduck.pixelcat.components.settings.SettingsActivity
|
||||
import at.connyduck.pixelcat.components.util.extension.visible
|
||||
import at.connyduck.pixelcat.dagger.ViewModelFactory
|
||||
import at.connyduck.pixelcat.databinding.ActivityLoginBinding
|
||||
import at.connyduck.pixelcat.util.viewBinding
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoginActivity : BaseActivity(), Observer<LoginModel> {
|
||||
@FlowPreview
|
||||
@ExperimentalCoroutinesApi
|
||||
class LoginActivity : BaseActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
|
||||
private val loginViewModel: LoginViewModel by viewModels { viewModelFactory }
|
||||
private val viewModel: LoginViewModel by viewModels { viewModelFactory }
|
||||
|
||||
private val binding by viewBinding(ActivityLoginBinding::inflate)
|
||||
|
||||
|
@ -54,7 +62,7 @@ class LoginActivity : BaseActivity(), Observer<LoginModel> {
|
|||
|
||||
setContentView(binding.root)
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.loginContainer) { _, insets ->
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||
val top = insets.getInsets(systemBars()).top
|
||||
val toolbarParams = binding.loginToolbar.layoutParams as ViewGroup.MarginLayoutParams
|
||||
toolbarParams.topMargin = top
|
||||
|
@ -67,10 +75,14 @@ class LoginActivity : BaseActivity(), Observer<LoginModel> {
|
|||
setDisplayShowTitleEnabled(false)
|
||||
}
|
||||
|
||||
loginViewModel.loginState.observe(this, this)
|
||||
lifecycleScope.launch {
|
||||
viewModel.observe().collect { loginModel ->
|
||||
onChanged(loginModel)
|
||||
}
|
||||
}
|
||||
|
||||
binding.loginButton.setOnClickListener {
|
||||
loginViewModel.startLogin(binding.loginInput.text.toString())
|
||||
viewModel.startLogin(binding.loginInput.text.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,13 +90,21 @@ class LoginActivity : BaseActivity(), Observer<LoginModel> {
|
|||
|
||||
val authCode = data?.getStringExtra(LoginWebViewActivity.RESULT_AUTHORIZATION_CODE)
|
||||
if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK && !authCode.isNullOrEmpty()) {
|
||||
loginViewModel.authCode(authCode)
|
||||
viewModel.authCode(authCode)
|
||||
return
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
if (!intent.hasExtra(LoginWebViewActivity.RESULT_AUTHORIZATION_CODE)) {
|
||||
viewModel.removeError()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.login, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
|
@ -105,7 +125,8 @@ class LoginActivity : BaseActivity(), Observer<LoginModel> {
|
|||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onChanged(loginModel: LoginModel?) {
|
||||
private fun onChanged(loginModel: LoginModel?) {
|
||||
|
||||
binding.loginInput.setText(loginModel?.input)
|
||||
|
||||
if (loginModel == null) {
|
||||
|
@ -113,23 +134,47 @@ class LoginActivity : BaseActivity(), Observer<LoginModel> {
|
|||
}
|
||||
|
||||
when (loginModel.state) {
|
||||
LoginState.NO_ERROR -> binding.loginInputLayout.error = null
|
||||
LoginState.AUTH_ERROR -> binding.loginInputLayout.error = "auth error"
|
||||
LoginState.INVALID_DOMAIN -> binding.loginInputLayout.error = "invalid domain"
|
||||
LoginState.NETWORK_ERROR -> binding.loginInputLayout.error = "network error"
|
||||
LoginState.NO_ERROR -> {
|
||||
binding.loginInputLayout.error = null
|
||||
setLoading(false)
|
||||
}
|
||||
LoginState.AUTH_ERROR -> {
|
||||
binding.loginInputLayout.error = "auth error"
|
||||
setLoading(false)
|
||||
}
|
||||
LoginState.INVALID_DOMAIN -> {
|
||||
binding.loginInputLayout.error = "invalid domain"
|
||||
setLoading(false)
|
||||
}
|
||||
LoginState.NETWORK_ERROR -> {
|
||||
binding.loginInputLayout.error = "network error"
|
||||
setLoading(false)
|
||||
}
|
||||
LoginState.LOADING -> {
|
||||
setLoading(true)
|
||||
}
|
||||
LoginState.SUCCESS -> {
|
||||
setLoading(true)
|
||||
startActivityForResult(LoginWebViewActivity.newIntent(loginModel.domain!!, loginModel.clientId!!, loginModel.clientSecret!!, this), REQUEST_CODE)
|
||||
}
|
||||
LoginState.SUCCESS_FINAL -> {
|
||||
startActivity(Intent(this, MainActivity::class.java)) // TODO dont create intent here
|
||||
setLoading(true)
|
||||
startActivity(MainActivity.newIntent(this))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLoading(loading: Boolean) {
|
||||
binding.loginLoading.visible = loading
|
||||
binding.loginImageView.visible = !loading
|
||||
binding.loginInputLayout.visible = !loading
|
||||
binding.loginButton.visible = !loading
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_CODE = 14
|
||||
|
||||
fun newIntent(context: Context) = Intent(context, LoginActivity::class.java)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,5 +32,11 @@ data class LoginModel(
|
|||
) : Parcelable
|
||||
|
||||
enum class LoginState { // TODO rename this stuff so it makes sense
|
||||
LOADING, NO_ERROR, NETWORK_ERROR, INVALID_DOMAIN, AUTH_ERROR, SUCCESS, SUCCESS_FINAL
|
||||
LOADING,
|
||||
NO_ERROR,
|
||||
NETWORK_ERROR,
|
||||
INVALID_DOMAIN,
|
||||
AUTH_ERROR,
|
||||
SUCCESS,
|
||||
SUCCESS_FINAL
|
||||
}
|
||||
|
|
|
@ -19,52 +19,54 @@
|
|||
|
||||
package at.connyduck.pixelcat.components.login
|
||||
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.connyduck.pixelcat.config.Config
|
||||
import at.connyduck.pixelcat.db.AccountManager
|
||||
import at.connyduck.pixelcat.db.entitity.AccountAuthData
|
||||
import at.connyduck.pixelcat.network.FediverseApi
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.HttpUrl
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
@FlowPreview
|
||||
@ExperimentalCoroutinesApi
|
||||
class LoginViewModel @Inject constructor(
|
||||
private val fediverseApi: FediverseApi,
|
||||
private val accountManager: AccountManager
|
||||
) : ViewModel() {
|
||||
|
||||
val loginState = MutableLiveData<LoginModel>().apply {
|
||||
value = LoginModel(state = LoginState.NO_ERROR)
|
||||
}
|
||||
private val loginState = ConflatedBroadcastChannel(LoginModel(state = LoginState.NO_ERROR))
|
||||
|
||||
fun observe() = loginState.asFlow()
|
||||
|
||||
@MainThread
|
||||
fun startLogin(input: String) {
|
||||
|
||||
val domainInput = canonicalizeDomain(input)
|
||||
|
||||
try {
|
||||
HttpUrl.Builder().host(domainInput).scheme("https").build()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
loginState.value = LoginModel(input, LoginState.INVALID_DOMAIN)
|
||||
return
|
||||
}
|
||||
|
||||
val exceptionMatch = Config.domainExceptions.any { exception ->
|
||||
domainInput.equals(exception, true) || domainInput.endsWith(".$exception", true)
|
||||
}
|
||||
|
||||
if (exceptionMatch) {
|
||||
loginState.value = LoginModel(input, LoginState.AUTH_ERROR)
|
||||
return
|
||||
}
|
||||
|
||||
loginState.value = LoginModel(input, LoginState.LOADING)
|
||||
|
||||
viewModelScope.launch {
|
||||
val domainInput = canonicalizeDomain(input)
|
||||
|
||||
try {
|
||||
HttpUrl.Builder().host(domainInput).scheme("https").build()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
loginState.send(LoginModel(input, LoginState.INVALID_DOMAIN))
|
||||
return@launch
|
||||
}
|
||||
|
||||
val exceptionMatch = Config.domainExceptions.any { exception ->
|
||||
domainInput.equals(exception, true) || domainInput.endsWith(".$exception", true)
|
||||
}
|
||||
|
||||
if (exceptionMatch) {
|
||||
loginState.send(LoginModel(input, LoginState.AUTH_ERROR))
|
||||
return@launch
|
||||
}
|
||||
|
||||
loginState.send(LoginModel(input, LoginState.LOADING))
|
||||
|
||||
fediverseApi.authenticateAppAsync(
|
||||
domain = domainInput,
|
||||
clientName = "Pixelcat",
|
||||
|
@ -73,19 +75,18 @@ class LoginViewModel @Inject constructor(
|
|||
scopes = Config.oAuthScopes
|
||||
).fold(
|
||||
{ appData ->
|
||||
loginState.postValue(LoginModel(input, LoginState.SUCCESS, domainInput, appData.clientId, appData.clientSecret))
|
||||
loginState.send(LoginModel(input, LoginState.SUCCESS, domainInput, appData.clientId, appData.clientSecret))
|
||||
},
|
||||
{
|
||||
loginState.postValue(LoginModel(input, LoginState.AUTH_ERROR))
|
||||
loginState.send(LoginModel(input, LoginState.AUTH_ERROR))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
fun authCode(authCode: String) {
|
||||
viewModelScope.launch {
|
||||
val loginModel = loginState.value!!
|
||||
val loginModel = loginState.value
|
||||
|
||||
fediverseApi.fetchOAuthToken(
|
||||
domain = loginModel.domain!!,
|
||||
|
@ -106,14 +107,21 @@ class LoginViewModel @Inject constructor(
|
|||
clientSecret = loginModel.clientSecret
|
||||
)
|
||||
accountManager.addAccount(loginModel.domain, authData)
|
||||
loginState.postValue(loginState.value?.copy(state = LoginState.SUCCESS_FINAL))
|
||||
loginState.send(loginState.value.copy(state = LoginState.SUCCESS_FINAL))
|
||||
},
|
||||
{
|
||||
loginState.send(loginState.value.copy(state = LoginState.AUTH_ERROR))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeError() {
|
||||
viewModelScope.launch {
|
||||
loginState.send(loginState.value.copy(state = LoginState.NO_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
private fun canonicalizeDomain(domain: String): String {
|
||||
// Strip any schemes out.
|
||||
var s = domain.replaceFirst("http://", "")
|
||||
|
|
|
@ -23,23 +23,35 @@ import android.app.Activity
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebView
|
||||
import at.connyduck.pixelcat.config.Config
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import at.connyduck.pixelcat.components.general.BaseActivity
|
||||
import at.connyduck.pixelcat.databinding.ActivityLoginWebViewBinding
|
||||
|
||||
class LoginWebViewActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityLoginWebViewBinding
|
||||
class LoginWebViewActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityLoginWebViewBinding.inflate(layoutInflater)
|
||||
val binding = ActivityLoginWebViewBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||
val top = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
|
||||
val toolbarParams = binding.loginToolbar.layoutParams as ViewGroup.MarginLayoutParams
|
||||
toolbarParams.topMargin = top
|
||||
WindowInsetsCompat.CONSUMED
|
||||
}
|
||||
|
||||
binding.loginToolbar.setNavigationOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
val domain = intent.getStringExtra(EXTRA_DOMAIN)!!
|
||||
val clientId = intent.getStringExtra(EXTRA_CLIENT_ID)!!
|
||||
val clientSecret = intent.getStringExtra(EXTRA_CLIENT_SECRET)!!
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package at.connyduck.pixelcat.components.main
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
|
@ -115,4 +116,8 @@ class MainActivity : BaseActivity() {
|
|||
startActivity(ComposeActivity.newIntent(this, returnValue?.firstOrNull()!!))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newIntent(context: Context) = Intent(context, MainActivity::class.java)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,5 +50,4 @@ class NotificationsViewModel @Inject constructor(
|
|||
).flow
|
||||
}
|
||||
.cachedIn(viewModelScope)
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package at.connyduck.pixelcat.components.splash
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import at.connyduck.pixelcat.components.login.LoginActivity
|
||||
|
@ -40,12 +39,9 @@ class SplashActivity : DaggerAppCompatActivity() {
|
|||
lifecycleScope.launch {
|
||||
|
||||
val intent = if (accountManager.activeAccount() != null) {
|
||||
Intent(
|
||||
this@SplashActivity,
|
||||
MainActivity::class.java
|
||||
) // TODO don't create intents here
|
||||
MainActivity.newIntent(this@SplashActivity)
|
||||
} else {
|
||||
Intent(this@SplashActivity, LoginActivity::class.java)
|
||||
LoginActivity.newIntent(this@SplashActivity)
|
||||
}
|
||||
startActivity(intent)
|
||||
finish()
|
||||
|
|
|
@ -28,5 +28,5 @@ object Config {
|
|||
const val oAuthRedirect = "$oAuthScheme://$oAuthHost"
|
||||
const val oAuthScopes = "read write follow"
|
||||
|
||||
val domainExceptions = arrayOf("gab.com", "gab.ai", "gabfed.com")
|
||||
val domainExceptions = arrayOf("gab.com", "gab.ai", "spinster.xyz")
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import at.connyduck.pixelcat.components.about.licenses.LicenseActivity
|
|||
import at.connyduck.pixelcat.components.compose.ComposeActivity
|
||||
import at.connyduck.pixelcat.components.timeline.detail.DetailActivity
|
||||
import at.connyduck.pixelcat.components.login.LoginActivity
|
||||
import at.connyduck.pixelcat.components.login.LoginWebViewActivity
|
||||
import at.connyduck.pixelcat.components.profile.ProfileActivity
|
||||
import at.connyduck.pixelcat.components.settings.SettingsActivity
|
||||
import at.connyduck.pixelcat.components.splash.SplashActivity
|
||||
|
@ -61,4 +62,7 @@ abstract class ActivityModule {
|
|||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesDetailActivity(): DetailActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesLoginWebViewActivity(): LoginWebViewActivity
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ fun Account.toEntity(accountId: Long) = TimelineAccountEntity(
|
|||
id = id,
|
||||
localUsername = localUsername,
|
||||
username = username,
|
||||
displayName = displayName,
|
||||
displayName = name,
|
||||
url = url,
|
||||
avatar = avatar
|
||||
)
|
||||
|
|
|
@ -19,14 +19,8 @@
|
|||
|
||||
package at.connyduck.pixelcat.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.text.Spanned
|
||||
import androidx.core.text.HtmlCompat
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import kotlinx.android.parcel.Parceler
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.util.Date
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
@ -55,38 +49,25 @@ data class Account(
|
|||
get() = if (displayName.isEmpty()) {
|
||||
localUsername
|
||||
} else displayName
|
||||
|
||||
fun isRemote(): Boolean = this.username != this.localUsername
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@Parcelize
|
||||
data class AccountSource(
|
||||
// val privacy: Status.Visibility,
|
||||
val privacy: Status.Visibility,
|
||||
val sensitive: Boolean,
|
||||
val note: String,
|
||||
val fields: List<StringField>?
|
||||
) : Parcelable
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@Parcelize
|
||||
data class Field(
|
||||
val name: String,
|
||||
// val value: @WriteWith<SpannedParceler>() Spanned,
|
||||
val value: String,
|
||||
@Json(name = "verified_at") val verifiedAt: Date?
|
||||
) : Parcelable
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@Parcelize
|
||||
data class StringField(
|
||||
val name: String,
|
||||
val value: String
|
||||
) : Parcelable
|
||||
|
||||
object SpannedParceler : Parceler<Spanned> {
|
||||
override fun create(parcel: Parcel): Spanned = HtmlCompat.fromHtml(parcel.readString() ?: "", HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH)
|
||||
|
||||
override fun Spanned.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(HtmlCompat.toHtml(this, HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="false" android:color="#6BFFFFFF"/>
|
||||
<item android:state_selected="true" android:color="#fff"/>
|
||||
</selector>
|
|
@ -1,7 +1,6 @@
|
|||
<?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"
|
||||
android:id="@+id/loginContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/pixelcat_gradient">
|
||||
|
@ -18,6 +17,7 @@
|
|||
android:id="@+id/loginToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ImageView
|
||||
|
@ -36,21 +36,27 @@
|
|||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/instance_input_hint"
|
||||
app:boxStrokeColor="@color/edit_text_color_white"
|
||||
app:boxStrokeErrorColor="@color/white"
|
||||
app:errorIconTint="@color/white"
|
||||
app:errorTextColor="@color/white"
|
||||
app:hintTextColor="@color/white"
|
||||
app:layout_constraintBottom_toTopOf="@id/loginButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:hint="@string/instance_input_hint"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginImageView">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/loginInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#fff"
|
||||
android:ems="10"
|
||||
android:inputType="textUri" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
android:inputType="textUri"
|
||||
android:textColor="@color/white"
|
||||
android:textCursorDrawable="@null" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/loginButton"
|
||||
|
@ -69,19 +75,19 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginInputLayout" />
|
||||
|
||||
<!--ProgressBar
|
||||
android:id="@+id/loading"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="64dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginBottom="64dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@+id/password"
|
||||
app:layout_constraintStart_toStartOf="@+id/password"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.3"/-->
|
||||
<ProgressBar
|
||||
android:id="@+id/loginLoading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="64dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginBottom="64dp"
|
||||
android:indeterminateTint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,15 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/pixelcat_gradient">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/loginToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:navigationIcon="@drawable/ic_arrow_back"
|
||||
app:title="@string/title_login"
|
||||
app:titleTextAppearance="@style/TextAppearanceToolbar"
|
||||
app:titleTextColor="#fff" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<WebView
|
||||
android:id="@+id/loginWebView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".components.login.LoginWebViewActivity">
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||
|
||||
<WebView android:id="@+id/loginWebView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -13,4 +13,12 @@
|
|||
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Fullscreen">
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
|
||||
<item name="android:navigationBarColor">@color/transparent</item>
|
||||
<item name="android:navigationBarDividerColor">@color/transparent</item>
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -87,4 +87,6 @@
|
|||
<string name="notification_favourited">%1$s liked your post</string>
|
||||
<string name="notification_followed">%1$s followed you</string>
|
||||
|
||||
<string name="title_login">Login</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
</style>
|
||||
|
||||
<style name="AppTheme.Fullscreen">
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearanceToolbar" parent="@style/TextAppearance.MaterialComponents.Headline6">
|
||||
|
|
Loading…
Reference in New Issue