show rules on the login screen (#2746)
* show rules on the login screen * fix code formatting * fix code formatting * fix tests
This commit is contained in:
parent
3fb1173d3f
commit
8e9b356074
10 changed files with 152 additions and 8 deletions
|
@ -216,7 +216,7 @@ class LoginActivity : BaseActivity(), Injectable {
|
|||
.addQueryParameter("response_type", "code")
|
||||
.addQueryParameter("scope", OAUTH_SCOPES)
|
||||
.build()
|
||||
doWebViewAuth.launch(LoginData(url.toString().toUri(), oauthRedirectUri.toUri()))
|
||||
doWebViewAuth.launch(LoginData(domain, url.toString().toUri(), oauthRedirectUri.toUri()))
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
/* Copyright 2022 Tusky Contributors
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.components.login
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
|
@ -16,16 +31,23 @@ import android.webkit.WebStorage
|
|||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.keylesspalace.tusky.BaseActivity
|
||||
import com.keylesspalace.tusky.BuildConfig
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ActivityLoginWebviewBinding
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.parcelableExtra
|
||||
import com.keylesspalace.tusky.util.viewBinding
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Contract for starting [LoginWebViewActivity]. */
|
||||
class OauthLogin : ActivityResultContract<LoginData, LoginResult>() {
|
||||
|
@ -62,6 +84,7 @@ class OauthLogin : ActivityResultContract<LoginData, LoginResult>() {
|
|||
|
||||
@Parcelize
|
||||
data class LoginData(
|
||||
val domain: String,
|
||||
val url: Uri,
|
||||
val oauthRedirectUrl: Uri,
|
||||
) : Parcelable
|
||||
|
@ -81,6 +104,11 @@ sealed class LoginResult : Parcelable {
|
|||
class LoginWebViewActivity : BaseActivity(), Injectable {
|
||||
private val binding by viewBinding(ActivityLoginWebviewBinding::inflate)
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
|
||||
private val viewModel: LoginWebViewViewModel by viewModels { viewModelFactory }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
@ -162,6 +190,25 @@ class LoginWebViewActivity : BaseActivity(), Injectable {
|
|||
} else {
|
||||
webView.restoreState(savedInstanceState)
|
||||
}
|
||||
|
||||
binding.loginRules.text = getString(R.string.instance_rule_info, data.domain)
|
||||
|
||||
viewModel.init(data.domain)
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.instanceRules.collect { instanceRules ->
|
||||
binding.loginRules.visible(instanceRules.isNotEmpty())
|
||||
binding.loginRules.setOnClickListener {
|
||||
AlertDialog.Builder(this@LoginWebViewActivity)
|
||||
.setTitle(getString(R.string.instance_rule_title, data.domain))
|
||||
.setMessage(
|
||||
instanceRules.joinToString(separator = "\n\n") { "• $it" }
|
||||
)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* Copyright 2022 Tusky Contributors
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.components.login
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import at.connyduck.calladapter.networkresult.fold
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoginWebViewViewModel @Inject constructor(
|
||||
private val api: MastodonApi
|
||||
) : ViewModel() {
|
||||
|
||||
val instanceRules: MutableStateFlow<List<String>> = MutableStateFlow(emptyList())
|
||||
|
||||
private var domain: String? = null
|
||||
|
||||
fun init(domain: String) {
|
||||
if (this.domain == null) {
|
||||
this.domain = domain
|
||||
viewModelScope.launch {
|
||||
api.getInstance(domain).fold({ instance ->
|
||||
instanceRules.value = instance.rules?.map { rule -> rule.text }.orEmpty()
|
||||
}, { throwable ->
|
||||
Log.w("LoginWebViewViewModel", "failed to load instance info", throwable)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import com.keylesspalace.tusky.components.announcements.AnnouncementsViewModel
|
|||
import com.keylesspalace.tusky.components.compose.ComposeViewModel
|
||||
import com.keylesspalace.tusky.components.conversation.ConversationsViewModel
|
||||
import com.keylesspalace.tusky.components.drafts.DraftsViewModel
|
||||
import com.keylesspalace.tusky.components.login.LoginWebViewViewModel
|
||||
import com.keylesspalace.tusky.components.report.ReportViewModel
|
||||
import com.keylesspalace.tusky.components.scheduled.ScheduledStatusViewModel
|
||||
import com.keylesspalace.tusky.components.search.SearchViewModel
|
||||
|
@ -119,5 +120,11 @@ abstract class ViewModelModule {
|
|||
@IntoMap
|
||||
@ViewModelKey(AccountMediaViewModel::class)
|
||||
internal abstract fun accountMediaViewModel(viewModel: AccountMediaViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(LoginWebViewViewModel::class)
|
||||
internal abstract fun loginWebViewViewModel(viewModel: LoginWebViewViewModel): ViewModel
|
||||
|
||||
// Add more ViewModels here
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ data class Instance(
|
|||
val configuration: InstanceConfiguration?,
|
||||
@SerializedName("max_media_attachments") val maxMediaAttachments: Int?,
|
||||
val pleroma: PleromaConfiguration?,
|
||||
@SerializedName("upload_limit") val uploadLimit: Int?
|
||||
@SerializedName("upload_limit") val uploadLimit: Int?,
|
||||
val rules: List<InstanceRules>?
|
||||
) {
|
||||
override fun hashCode(): Int {
|
||||
return uri.hashCode()
|
||||
|
@ -90,3 +91,8 @@ data class PleromaFieldLimits(
|
|||
@SerializedName("name_length") val nameLength: Int?,
|
||||
@SerializedName("value_length") val valueLength: Int?
|
||||
)
|
||||
|
||||
data class InstanceRules(
|
||||
val id: String,
|
||||
val text: String
|
||||
)
|
||||
|
|
|
@ -79,7 +79,7 @@ interface MastodonApi {
|
|||
suspend fun getCustomEmojis(): NetworkResult<List<Emoji>>
|
||||
|
||||
@GET("api/v1/instance")
|
||||
suspend fun getInstance(): NetworkResult<Instance>
|
||||
suspend fun getInstance(@Header(DOMAIN_HEADER) domain: String? = null): NetworkResult<Instance>
|
||||
|
||||
@GET("api/v1/filters")
|
||||
fun getFilters(): Single<List<Filter>>
|
||||
|
|
11
app/src/main/res/drawable/info_24dp.xml
Normal file
11
app/src/main/res/drawable/info_24dp.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorPrimary">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M22.65,34H25.65V22H22.65ZM24,18.3Q24.7,18.3 25.175,17.85Q25.65,17.4 25.65,16.7Q25.65,16 25.175,15.5Q24.7,15 24,15Q23.3,15 22.825,15.5Q22.35,16 22.35,16.7Q22.35,17.4 22.825,17.85Q23.3,18.3 24,18.3ZM24,44Q19.9,44 16.25,42.425Q12.6,40.85 9.875,38.125Q7.15,35.4 5.575,31.75Q4,28.1 4,23.95Q4,19.85 5.575,16.2Q7.15,12.55 9.875,9.85Q12.6,7.15 16.25,5.575Q19.9,4 24.05,4Q28.15,4 31.8,5.575Q35.45,7.15 38.15,9.85Q40.85,12.55 42.425,16.2Q44,19.85 44,24Q44,28.1 42.425,31.75Q40.85,35.4 38.15,38.125Q35.45,40.85 31.8,42.425Q28.15,44 24,44ZM24.05,41Q31.1,41 36.05,36.025Q41,31.05 41,23.95Q41,16.9 36.05,11.95Q31.1,7 24,7Q16.95,7 11.975,11.95Q7,16.9 7,24Q7,31.05 11.975,36.025Q16.95,41 24.05,41ZM24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Q24,24 24,24Z"/>
|
||||
</vector>
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">
|
||||
|
||||
|
@ -19,12 +20,33 @@
|
|||
android:id="@+id/loginProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center" />
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<WebView
|
||||
android:id="@+id/loginWebView"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||
android:orientation="vertical"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/loginWebView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginRules"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/colorBackground"
|
||||
android:drawablePadding="8dp"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="12dp"
|
||||
app:drawableStartCompat="@drawable/info_24dp"
|
||||
tools:text="By logging in you agree to the rules of instance.example" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -670,4 +670,7 @@
|
|||
|
||||
<string name="delete_scheduled_post_warning">Delete this scheduled post?</string>
|
||||
|
||||
<string name="instance_rule_info">By logging in you agree to the rules of %s.</string>
|
||||
<string name="instance_rule_title">%s rules</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -480,7 +480,8 @@ class ComposeActivityTest {
|
|||
configuration = configuration,
|
||||
maxMediaAttachments = null,
|
||||
pleroma = null,
|
||||
uploadLimit = null
|
||||
uploadLimit = null,
|
||||
rules = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue