mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-16 02:05:06 +08:00
Merge pull request #2831 from vector-im/feature/bma/hs_version
Fetch homeserver type and version and display in a new setting screen and add info in rageshakes
This commit is contained in:
commit
e162ebdf91
@ -5,7 +5,7 @@ Features ✨:
|
||||
-
|
||||
|
||||
Improvements 🙌:
|
||||
-
|
||||
- Fetch homeserver type and version and display in a new setting screen and add info in rageshakes (#2831)
|
||||
|
||||
Bugfix 🐛:
|
||||
-
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.federation
|
||||
|
||||
interface FederationService {
|
||||
/**
|
||||
* Get information about the homeserver
|
||||
*/
|
||||
suspend fun getFederationVersion(): FederationVersion
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.federation
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/server_server/latest#get-matrix-federation-v1-version
|
||||
*/
|
||||
data class FederationVersion(
|
||||
/**
|
||||
* Arbitrary name that identify this implementation.
|
||||
*/
|
||||
val name: String?,
|
||||
/**
|
||||
* Version of this implementation. The version format depends on the implementation.
|
||||
*/
|
||||
val version: String?
|
||||
)
|
@ -21,6 +21,7 @@ import androidx.lifecycle.LiveData
|
||||
import okhttp3.OkHttpClient
|
||||
import org.matrix.android.sdk.api.auth.data.SessionParams
|
||||
import org.matrix.android.sdk.api.failure.GlobalError
|
||||
import org.matrix.android.sdk.api.federation.FederationService
|
||||
import org.matrix.android.sdk.api.pushrules.PushRuleService
|
||||
import org.matrix.android.sdk.api.session.account.AccountService
|
||||
import org.matrix.android.sdk.api.session.accountdata.AccountDataService
|
||||
@ -213,6 +214,11 @@ interface Session :
|
||||
*/
|
||||
fun searchService(): SearchService
|
||||
|
||||
/**
|
||||
* Returns the federation service associated with the session
|
||||
*/
|
||||
fun federationService(): FederationService
|
||||
|
||||
/**
|
||||
* Returns the third party service associated with the session
|
||||
*/
|
||||
|
@ -21,6 +21,11 @@ package org.matrix.android.sdk.api.session.homeserver
|
||||
*/
|
||||
interface HomeServerCapabilitiesService {
|
||||
|
||||
/**
|
||||
* Force a refresh of the stored data
|
||||
*/
|
||||
suspend fun refreshHomeServerCapabilities()
|
||||
|
||||
/**
|
||||
* Get the HomeServer capabilities
|
||||
*/
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.federation
|
||||
|
||||
import org.matrix.android.sdk.api.federation.FederationService
|
||||
import org.matrix.android.sdk.api.federation.FederationVersion
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultFederationService @Inject constructor(
|
||||
private val getFederationVersionTask: GetFederationVersionTask
|
||||
) : FederationService {
|
||||
override suspend fun getFederationVersion(): FederationVersion {
|
||||
return getFederationVersionTask.execute(Unit)
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.federation
|
||||
|
||||
import org.matrix.android.sdk.internal.network.NetworkConstants
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.GET
|
||||
|
||||
internal interface FederationAPI {
|
||||
@GET(NetworkConstants.URI_FEDERATION_PATH + "version")
|
||||
fun getVersion(): Call<FederationGetVersionResult>
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.federation
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/server_server/latest#get-matrix-federation-v1-version
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class FederationGetVersionResult(
|
||||
@Json(name = "server")
|
||||
val server: FederationGetVersionServer?
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class FederationGetVersionServer(
|
||||
/**
|
||||
* Arbitrary name that identify this implementation.
|
||||
*/
|
||||
@Json(name = "name")
|
||||
val name: String?,
|
||||
/**
|
||||
* Version of this implementation. The version format depends on the implementation.
|
||||
*/
|
||||
@Json(name = "version")
|
||||
val version: String?
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.federation
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Lazy
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import okhttp3.OkHttpClient
|
||||
import org.matrix.android.sdk.api.auth.data.SessionParams
|
||||
import org.matrix.android.sdk.api.federation.FederationService
|
||||
import org.matrix.android.sdk.internal.di.Unauthenticated
|
||||
import org.matrix.android.sdk.internal.network.RetrofitFactory
|
||||
|
||||
@Module
|
||||
internal abstract class FederationModule {
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesFederationAPI(@Unauthenticated okHttpClient: Lazy<OkHttpClient>,
|
||||
sessionParams: SessionParams,
|
||||
retrofitFactory: RetrofitFactory): FederationAPI {
|
||||
return retrofitFactory.create(okHttpClient, sessionParams.homeServerUrl).create(FederationAPI::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindFederationService(service: DefaultFederationService): FederationService
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetFederationVersionTask(task: DefaultGetFederationVersionTask): GetFederationVersionTask
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.federation
|
||||
|
||||
import org.matrix.android.sdk.api.federation.FederationVersion
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetFederationVersionTask : Task<Unit, FederationVersion>
|
||||
|
||||
internal class DefaultGetFederationVersionTask @Inject constructor(
|
||||
private val federationAPI: FederationAPI
|
||||
) : GetFederationVersionTask {
|
||||
|
||||
override suspend fun execute(params: Unit): FederationVersion {
|
||||
val result = executeRequest<FederationGetVersionResult>(null) {
|
||||
apiCall = federationAPI.getVersion()
|
||||
}
|
||||
|
||||
return FederationVersion(
|
||||
name = result.server?.name,
|
||||
version = result.server?.version
|
||||
)
|
||||
}
|
||||
}
|
@ -36,4 +36,7 @@ internal object NetworkConstants {
|
||||
|
||||
// Integration
|
||||
const val URI_INTEGRATION_MANAGER_PATH = "_matrix/integrations/v1/"
|
||||
|
||||
// Federation
|
||||
const val URI_FEDERATION_PATH = "_matrix/federation/v1/"
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import io.realm.RealmConfiguration
|
||||
import okhttp3.OkHttpClient
|
||||
import org.matrix.android.sdk.api.auth.data.SessionParams
|
||||
import org.matrix.android.sdk.api.failure.GlobalError
|
||||
import org.matrix.android.sdk.api.federation.FederationService
|
||||
import org.matrix.android.sdk.api.pushrules.PushRuleService
|
||||
import org.matrix.android.sdk.api.session.InitialSyncProgressService
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
@ -88,6 +89,7 @@ internal class DefaultSession @Inject constructor(
|
||||
private val groupService: Lazy<GroupService>,
|
||||
private val userService: Lazy<UserService>,
|
||||
private val filterService: Lazy<FilterService>,
|
||||
private val federationService: Lazy<FederationService>,
|
||||
private val cacheService: Lazy<CacheService>,
|
||||
private val signOutService: Lazy<SignOutService>,
|
||||
private val pushRuleService: Lazy<PushRuleService>,
|
||||
@ -260,6 +262,8 @@ internal class DefaultSession @Inject constructor(
|
||||
|
||||
override fun searchService(): SearchService = searchService.get()
|
||||
|
||||
override fun federationService(): FederationService = federationService.get()
|
||||
|
||||
override fun thirdPartyService(): ThirdPartyService = thirdPartyService.get()
|
||||
|
||||
override fun getOkHttpClient(): OkHttpClient {
|
||||
|
@ -27,6 +27,7 @@ import org.matrix.android.sdk.internal.crypto.SendGossipWorker
|
||||
import org.matrix.android.sdk.internal.crypto.crosssigning.UpdateTrustWorker
|
||||
import org.matrix.android.sdk.internal.crypto.verification.SendVerificationMessageWorker
|
||||
import org.matrix.android.sdk.internal.di.MatrixComponent
|
||||
import org.matrix.android.sdk.internal.federation.FederationModule
|
||||
import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker
|
||||
import org.matrix.android.sdk.internal.session.account.AccountModule
|
||||
import org.matrix.android.sdk.internal.session.cache.CacheModule
|
||||
@ -87,6 +88,7 @@ import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
|
||||
AccountDataModule::class,
|
||||
ProfileModule::class,
|
||||
AccountModule::class,
|
||||
FederationModule::class,
|
||||
CallModule::class,
|
||||
SearchModule::class,
|
||||
ThirdPartyModule::class
|
||||
|
@ -17,16 +17,23 @@
|
||||
package org.matrix.android.sdk.internal.session.homeserver
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService
|
||||
import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper
|
||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
|
||||
import org.matrix.android.sdk.internal.database.query.get
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import io.realm.Realm
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultHomeServerCapabilitiesService @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : HomeServerCapabilitiesService {
|
||||
internal class DefaultHomeServerCapabilitiesService @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask
|
||||
) : HomeServerCapabilitiesService {
|
||||
|
||||
override suspend fun refreshHomeServerCapabilities() {
|
||||
getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = true))
|
||||
}
|
||||
|
||||
override fun getHomeServerCapabilities(): HomeServerCapabilities {
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
|
@ -38,7 +38,11 @@ import timber.log.Timber
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetHomeServerCapabilitiesTask : Task<Unit, Unit>
|
||||
internal interface GetHomeServerCapabilitiesTask : Task<GetHomeServerCapabilitiesTask.Params, Unit> {
|
||||
data class Params(
|
||||
val forceRefresh: Boolean
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||
private val capabilitiesAPI: CapabilitiesAPI,
|
||||
@ -52,13 +56,15 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||
private val userId: String
|
||||
) : GetHomeServerCapabilitiesTask {
|
||||
|
||||
override suspend fun execute(params: Unit) {
|
||||
var doRequest = false
|
||||
override suspend fun execute(params: GetHomeServerCapabilitiesTask.Params) {
|
||||
var doRequest = params.forceRefresh
|
||||
if (!doRequest) {
|
||||
monarchy.awaitTransaction { realm ->
|
||||
val homeServerCapabilitiesEntity = HomeServerCapabilitiesEntity.getOrCreate(realm)
|
||||
|
||||
doRequest = homeServerCapabilitiesEntity.lastUpdatedTimestamp + MIN_DELAY_BETWEEN_TWO_REQUEST_MILLIS < Date().time
|
||||
}
|
||||
}
|
||||
|
||||
if (!doRequest) {
|
||||
return
|
||||
@ -123,7 +129,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
|
||||
}
|
||||
|
||||
companion object {
|
||||
// 8 hours like on Riot Web
|
||||
// 8 hours like on Element Web
|
||||
private const val MIN_DELAY_BETWEEN_TWO_REQUEST_MILLIS = 8 * 60 * 60 * 1000
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ internal class DefaultSyncTask @Inject constructor(
|
||||
initialSyncProgressService.startTask(R.string.initial_sync_start_importing_account, 100)
|
||||
}
|
||||
// Maybe refresh the home server capabilities data we know
|
||||
getHomeServerCapabilitiesTask.execute(Unit)
|
||||
getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false))
|
||||
|
||||
val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT)
|
||||
|
||||
|
@ -48,7 +48,8 @@ print("Get information from " + baseUrl)
|
||||
items = [
|
||||
# [Title, URL, True for GET request and False for POST request]
|
||||
["Well-known", baseUrl + ".well-known/matrix/client", True]
|
||||
, ["Version", baseUrl + "_matrix/client/versions", True]
|
||||
, ["API version", baseUrl + "_matrix/client/versions", True]
|
||||
, ["Homeserver version", baseUrl + "_matrix/federation/v1/version", True]
|
||||
, ["Login flow", baseUrl + "_matrix/client/r0/login", True]
|
||||
, ["Registration flow", baseUrl + "_matrix/client/r0/register", False]
|
||||
# Useless , ["Username availability", baseUrl + "_matrix/client/r0/register/available?username=benoit", True]
|
||||
|
@ -23,7 +23,6 @@ import androidx.test.espresso.Espresso.pressBack
|
||||
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
|
||||
import androidx.test.espresso.action.ViewActions.longClick
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
@ -145,7 +144,7 @@ class UiAllScreensSanityTest {
|
||||
}
|
||||
|
||||
private fun ignoreVerification() {
|
||||
Thread.sleep(6000)
|
||||
sleep(6000)
|
||||
val activity = EspressoHelper.getCurrentActivity()!!
|
||||
|
||||
val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)
|
||||
@ -155,7 +154,7 @@ class UiAllScreensSanityTest {
|
||||
|
||||
assertDisplayed(R.id.bottomSheetFragmentContainer)
|
||||
|
||||
onView(ViewMatchers.isRoot()).perform(SleepViewAction.sleep(2000))
|
||||
onView(isRoot()).perform(SleepViewAction.sleep(2000))
|
||||
|
||||
clickOn(R.string.skip)
|
||||
assertDisplayed(R.string.are_you_sure)
|
||||
@ -206,12 +205,12 @@ class UiAllScreensSanityTest {
|
||||
// Test quick reaction
|
||||
longClickOnMessage()
|
||||
// Add quick reaction
|
||||
clickOn("👍")
|
||||
clickOn("\uD83D\uDC4D️") // 👍
|
||||
|
||||
sleep(1000)
|
||||
|
||||
// Open reactions
|
||||
longClickOn("👍")
|
||||
longClickOn("\uD83D\uDC4D️") // 👍
|
||||
pressBack()
|
||||
|
||||
// Test add reaction
|
||||
@ -226,6 +225,8 @@ class UiAllScreensSanityTest {
|
||||
clickOn(R.string.edit)
|
||||
// TODO Cancel action
|
||||
writeTo(R.id.composerEditText, "Hello universe!")
|
||||
// Wait a bit for the keyboard layout to update
|
||||
sleep(30)
|
||||
clickOn(R.id.sendButton)
|
||||
// Open edit history
|
||||
longClickOnMessage("Hello universe! (edited)")
|
||||
@ -277,13 +278,18 @@ class UiAllScreensSanityTest {
|
||||
|
||||
assertDisplayed(R.id.roomProfileAvatarView)
|
||||
|
||||
// Room addresses
|
||||
// Leave
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 13)
|
||||
clickDialogNegativeButton()
|
||||
|
||||
// Advanced
|
||||
// Room addresses
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 15)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_alias_published_alias_title)))
|
||||
pressBack()
|
||||
|
||||
// Room permissions
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 15)
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 17)
|
||||
onView(isRoot()).perform(waitForView(withText(R.string.room_permissions_title)))
|
||||
clickOn(R.string.room_permissions_change_room_avatar)
|
||||
clickDialogNegativeButton()
|
||||
@ -292,10 +298,6 @@ class UiAllScreensSanityTest {
|
||||
clickOn(R.string.hide_advanced)
|
||||
pressBack()
|
||||
|
||||
// Leave
|
||||
clickListItem(R.id.matrixProfileRecyclerView, 17)
|
||||
clickDialogNegativeButton()
|
||||
|
||||
// Menu share
|
||||
// clickMenu(R.id.roomProfileShareAction)
|
||||
// pressBack()
|
||||
@ -483,6 +485,9 @@ class UiAllScreensSanityTest {
|
||||
clickOn(R.string.add_identity_server)
|
||||
pressBack()
|
||||
pressBack()
|
||||
// Home server
|
||||
clickOnPreference(R.string.settings_home_server)
|
||||
pressBack()
|
||||
// Identity server
|
||||
clickOnPreference(R.string.settings_identity_server)
|
||||
pressBack()
|
||||
|
@ -109,6 +109,7 @@ import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailFragmen
|
||||
import im.vector.app.features.settings.devtools.IncomingKeyRequestListFragment
|
||||
import im.vector.app.features.settings.devtools.KeyRequestsFragment
|
||||
import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment
|
||||
import im.vector.app.features.settings.homeserver.HomeserverSettingsFragment
|
||||
import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
|
||||
import im.vector.app.features.settings.locale.LocalePickerFragment
|
||||
import im.vector.app.features.settings.push.PushGatewaysFragment
|
||||
@ -284,6 +285,11 @@ interface FragmentModule {
|
||||
@FragmentKey(VectorSettingsLabsFragment::class)
|
||||
fun bindVectorSettingsLabsFragment(fragment: VectorSettingsLabsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(HomeserverSettingsFragment::class)
|
||||
fun bindHomeserverSettingsFragment(fragment: HomeserverSettingsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsPinFragment::class)
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.app.features.discovery
|
||||
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_settings_centered_image)
|
||||
abstract class SettingsCenteredImageItem : EpoxyModelWithHolder<SettingsCenteredImageItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
@DrawableRes
|
||||
var drawableRes: Int = 0
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.image.setImageResource(drawableRes)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val image by bind<ImageView>(R.id.itemSettingsImage)
|
||||
}
|
||||
}
|
@ -21,12 +21,15 @@ import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.databinding.ActivityBugReportBinding
|
||||
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Form to send a bug report
|
||||
@ -39,6 +42,10 @@ class BugReportActivity : VectorBaseActivity<ActivityBugReportBinding>() {
|
||||
|
||||
override fun getBinding() = ActivityBugReportBinding.inflate(layoutInflater)
|
||||
|
||||
@Inject lateinit var bugReportViewModelFactory: BugReportViewModel.Factory
|
||||
|
||||
private val viewModel: BugReportViewModel by viewModel()
|
||||
|
||||
private var forSuggestion: Boolean = false
|
||||
|
||||
override fun initUiAndData() {
|
||||
@ -114,7 +121,7 @@ class BugReportActivity : VectorBaseActivity<ActivityBugReportBinding>() {
|
||||
/**
|
||||
* Send the bug report
|
||||
*/
|
||||
private fun sendBugReport() {
|
||||
private fun sendBugReport() = withState(viewModel) { state ->
|
||||
views.bugReportScrollview.alpha = 0.3f
|
||||
views.bugReportMaskView.isVisible = true
|
||||
|
||||
@ -133,6 +140,7 @@ class BugReportActivity : VectorBaseActivity<ActivityBugReportBinding>() {
|
||||
views.bugReportButtonIncludeKeyShareHistory.isChecked,
|
||||
views.bugReportButtonIncludeScreenshot.isChecked,
|
||||
views.bugReportEditText.text.toString(),
|
||||
state.serverVersion,
|
||||
object : BugReporter.IMXBugReportListener {
|
||||
override fun onUploadFailed(reason: String?) {
|
||||
try {
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.rageshake
|
||||
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
|
||||
data class BugReportState(
|
||||
val serverVersion: String = ""
|
||||
) : MvRxState
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.rageshake
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.platform.EmptyAction
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
|
||||
class BugReportViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: BugReportState,
|
||||
val activeSessionHolder: ActiveSessionHolder
|
||||
) : VectorViewModel<BugReportState, EmptyAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(initialState: BugReportState): BugReportViewModel
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<BugReportViewModel, BugReportState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: BugReportState): BugReportViewModel? {
|
||||
val activity: BugReportActivity = (viewModelContext as ActivityViewModelContext).activity()
|
||||
return activity.bugReportViewModelFactory.create(state)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
fetchHomeserverVersion()
|
||||
}
|
||||
|
||||
private fun fetchHomeserverVersion() {
|
||||
viewModelScope.launch {
|
||||
val version = tryOrNull {
|
||||
activeSessionHolder.getSafeActiveSession()
|
||||
?.federationService()
|
||||
?.getFederationVersion()
|
||||
?.let { "${it.name} - ${it.version}" }
|
||||
} ?: "undefined"
|
||||
|
||||
setState {
|
||||
copy(
|
||||
serverVersion = version
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: EmptyAction) {
|
||||
// No op
|
||||
}
|
||||
}
|
@ -165,6 +165,7 @@ class BugReporter @Inject constructor(
|
||||
withKeyRequestHistory: Boolean,
|
||||
withScreenshot: Boolean,
|
||||
theBugDescription: String,
|
||||
serverVersion: String,
|
||||
listener: IMXBugReportListener?) {
|
||||
// enumerate files to delete
|
||||
val mBugReportFiles: MutableList<File> = ArrayList()
|
||||
@ -273,6 +274,7 @@ class BugReporter @Inject constructor(
|
||||
.addFormDataPart("app_language", VectorLocale.applicationLocale.toString())
|
||||
.addFormDataPart("default_app_language", systemLocaleProvider.getSystemLocale().toString())
|
||||
.addFormDataPart("theme", ThemeUtils.getApplicationTheme(context))
|
||||
.addFormDataPart("server_version", serverVersion)
|
||||
|
||||
val buildNumber = context.getString(R.string.build_number)
|
||||
if (buildNumber.isNotEmpty() && buildNumber != "0") {
|
||||
|
@ -57,6 +57,7 @@ class RoomProfileController @Inject constructor(
|
||||
fun onRoomAliasesClicked()
|
||||
fun onRoomPermissionsClicked()
|
||||
fun onRoomIdClicked()
|
||||
fun onRoomDevToolsClicked()
|
||||
fun onUrlInTopicLongClicked(url: String)
|
||||
}
|
||||
|
||||
@ -193,7 +194,7 @@ class RoomProfileController @Inject constructor(
|
||||
title = stringProvider.getString(R.string.room_settings_permissions_title),
|
||||
subtitle = stringProvider.getString(R.string.room_settings_permissions_subtitle),
|
||||
dividerColor = dividerColor,
|
||||
divider = true,
|
||||
divider = false,
|
||||
editable = true,
|
||||
action = { callback?.onRoomPermissionsClicked() }
|
||||
)
|
||||
@ -204,10 +205,29 @@ class RoomProfileController @Inject constructor(
|
||||
title = stringProvider.getString(R.string.room_settings_room_internal_id),
|
||||
subtitle = roomSummary.roomId,
|
||||
dividerColor = dividerColor,
|
||||
divider = false,
|
||||
divider = true,
|
||||
editable = false,
|
||||
action = { callback?.onRoomIdClicked() }
|
||||
)
|
||||
data.roomCreateContent()?.roomVersion?.let {
|
||||
buildProfileAction(
|
||||
id = "roomVersion",
|
||||
title = stringProvider.getString(R.string.room_settings_room_version_title),
|
||||
subtitle = it,
|
||||
dividerColor = dividerColor,
|
||||
divider = true,
|
||||
editable = false
|
||||
)
|
||||
}
|
||||
buildProfileAction(
|
||||
id = "devTools",
|
||||
title = stringProvider.getString(R.string.dev_tools_menu_name),
|
||||
subtitle = roomSummary.roomId,
|
||||
dividerColor = dividerColor,
|
||||
divider = false,
|
||||
editable = true,
|
||||
action = { callback?.onRoomDevToolsClicked() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,6 +295,10 @@ class RoomProfileFragment @Inject constructor(
|
||||
copyToClipboard(requireContext(), roomProfileArgs.roomId)
|
||||
}
|
||||
|
||||
override fun onRoomDevToolsClicked() {
|
||||
navigator.openDevTools(requireContext(), roomProfileArgs.roomId)
|
||||
}
|
||||
|
||||
override fun onUrlInTopicLongClicked(url: String) {
|
||||
copyToClipboard(requireContext(), url, true)
|
||||
}
|
||||
|
@ -33,13 +33,17 @@ import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.state.isPublic
|
||||
import org.matrix.android.sdk.rx.RxRoom
|
||||
import org.matrix.android.sdk.rx.mapOptional
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import org.matrix.android.sdk.rx.unwrap
|
||||
|
||||
@ -69,10 +73,20 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||
init {
|
||||
val rxRoom = room.rx()
|
||||
observeRoomSummary(rxRoom)
|
||||
observeRoomCreateContent(rxRoom)
|
||||
observeBannedRoomMembers(rxRoom)
|
||||
observePermissions()
|
||||
}
|
||||
|
||||
private fun observeRoomCreateContent(rxRoom: RxRoom) {
|
||||
rxRoom.liveStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.NoCondition)
|
||||
.mapOptional { it.content.toModel<RoomCreateContent>() }
|
||||
.unwrap()
|
||||
.execute {
|
||||
copy(roomCreateContent = it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummary(rxRoom: RxRoom) {
|
||||
rxRoom.liveRoomSummary()
|
||||
.unwrap()
|
||||
|
@ -22,10 +22,12 @@ import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
|
||||
data class RoomProfileViewState(
|
||||
val roomId: String,
|
||||
val roomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val roomCreateContent: Async<RoomCreateContent> = Uninitialized,
|
||||
val bannedMembership: Async<List<RoomMemberSummary>> = Uninitialized,
|
||||
val actionPermissions: ActionPermissions = ActionPermissions(),
|
||||
val isLoading: Boolean = false
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.settings.homeserver
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.federation.FederationVersion
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
|
||||
data class HomeServerSettingsViewState(
|
||||
val baseUrl: String = "",
|
||||
val homeServerCapabilities: HomeServerCapabilities = HomeServerCapabilities(),
|
||||
val federationVersion: Async<FederationVersion> = Uninitialized
|
||||
) : MvRxState
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.settings.homeserver
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class HomeserverSettingsAction : VectorViewModelAction {
|
||||
object Refresh : HomeserverSettingsAction()
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.settings.homeserver
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.errorWithRetryItem
|
||||
import im.vector.app.core.epoxy.loadingItem
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.discovery.settingsCenteredImageItem
|
||||
import im.vector.app.features.discovery.settingsInfoItem
|
||||
import im.vector.app.features.discovery.settingsSectionTitleItem
|
||||
import org.matrix.android.sdk.api.federation.FederationVersion
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
import javax.inject.Inject
|
||||
|
||||
class HomeserverSettingsController @Inject constructor(
|
||||
private val stringProvider: StringProvider,
|
||||
private val errorFormatter: ErrorFormatter
|
||||
) : TypedEpoxyController<HomeServerSettingsViewState>() {
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
interface Callback {
|
||||
fun retry()
|
||||
}
|
||||
|
||||
override fun buildModels(data: HomeServerSettingsViewState?) {
|
||||
data ?: return
|
||||
|
||||
buildHeader(data)
|
||||
when (val federationVersion = data.federationVersion) {
|
||||
is Loading,
|
||||
is Uninitialized ->
|
||||
loadingItem {
|
||||
id("loading")
|
||||
}
|
||||
is Fail ->
|
||||
errorWithRetryItem {
|
||||
id("error")
|
||||
text(errorFormatter.toHumanReadable(federationVersion.error))
|
||||
listener { callback?.retry() }
|
||||
}
|
||||
is Success ->
|
||||
buildFederationVersion(federationVersion())
|
||||
}
|
||||
buildCapabilities(data)
|
||||
}
|
||||
|
||||
private fun buildHeader(state: HomeServerSettingsViewState) {
|
||||
settingsCenteredImageItem {
|
||||
id("icon")
|
||||
drawableRes(R.drawable.ic_layers)
|
||||
}
|
||||
settingsSectionTitleItem {
|
||||
id("urlTitle")
|
||||
titleResId(R.string.hs_url)
|
||||
}
|
||||
settingsInfoItem {
|
||||
id("urlValue")
|
||||
helperText(state.baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildFederationVersion(federationVersion: FederationVersion) {
|
||||
settingsSectionTitleItem {
|
||||
id("nameTitle")
|
||||
titleResId(R.string.settings_server_name)
|
||||
}
|
||||
settingsInfoItem {
|
||||
id("nameValue")
|
||||
helperText(federationVersion.name)
|
||||
}
|
||||
settingsSectionTitleItem {
|
||||
id("versionTitle")
|
||||
titleResId(R.string.settings_server_version)
|
||||
}
|
||||
settingsInfoItem {
|
||||
id("versionValue")
|
||||
helperText(federationVersion.version)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildCapabilities(data: HomeServerSettingsViewState) {
|
||||
settingsSectionTitleItem {
|
||||
id("uploadTitle")
|
||||
titleResId(R.string.settings_server_upload_size_title)
|
||||
}
|
||||
|
||||
val limit = data.homeServerCapabilities.maxUploadFileSize
|
||||
|
||||
settingsInfoItem {
|
||||
id("uploadValue")
|
||||
if (limit == HomeServerCapabilities.MAX_UPLOAD_FILE_SIZE_UNKNOWN) {
|
||||
helperTextResId(R.string.settings_server_upload_size_unknown)
|
||||
} else {
|
||||
helperText(stringProvider.getString(R.string.settings_server_upload_size_content, "${limit / 1048576L} MB"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.settings.homeserver
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Display some information about the homeserver
|
||||
*/
|
||||
class HomeserverSettingsFragment @Inject constructor(
|
||||
val homeserverSettingsViewModelFactory: HomeserverSettingsViewModel.Factory,
|
||||
private val homeserverSettingsController: HomeserverSettingsController
|
||||
) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
|
||||
HomeserverSettingsController.Callback {
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding {
|
||||
return FragmentGenericRecyclerBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
private val viewModel: HomeserverSettingsViewModel by fragmentViewModel()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
homeserverSettingsController.callback = this
|
||||
views.genericRecyclerView.configureWith(homeserverSettingsController)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
homeserverSettingsController.callback = null
|
||||
views.genericRecyclerView.cleanup()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.settings_home_server)
|
||||
}
|
||||
|
||||
override fun retry() {
|
||||
viewModel.handle(HomeserverSettingsAction.Refresh)
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
homeserverSettingsController.setData(state)
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.settings.homeserver
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
|
||||
class HomeserverSettingsViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: HomeServerSettingsViewState,
|
||||
private val session: Session
|
||||
) : VectorViewModel<HomeServerSettingsViewState, HomeserverSettingsAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(initialState: HomeServerSettingsViewState): HomeserverSettingsViewModel
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<HomeserverSettingsViewModel, HomeServerSettingsViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: HomeServerSettingsViewState): HomeserverSettingsViewModel? {
|
||||
val fragment: HomeserverSettingsFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
||||
return fragment.homeserverSettingsViewModelFactory.create(state)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
setState {
|
||||
copy(
|
||||
baseUrl = session.sessionParams.homeServerUrl,
|
||||
homeServerCapabilities = session.getHomeServerCapabilities()
|
||||
)
|
||||
}
|
||||
fetchHomeserverVersion()
|
||||
refreshHomeServerCapabilities()
|
||||
}
|
||||
|
||||
private fun refreshHomeServerCapabilities() {
|
||||
viewModelScope.launch {
|
||||
runCatching {
|
||||
session.refreshHomeServerCapabilities()
|
||||
}
|
||||
|
||||
setState {
|
||||
copy(
|
||||
homeServerCapabilities = session.getHomeServerCapabilities()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchHomeserverVersion() {
|
||||
setState {
|
||||
copy(
|
||||
federationVersion = Loading()
|
||||
)
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val federationVersion = session.federationService().getFederationVersion()
|
||||
setState {
|
||||
copy(
|
||||
federationVersion = Success(federationVersion)
|
||||
)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
setState {
|
||||
copy(
|
||||
federationVersion = Fail(failure)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: HomeserverSettingsAction) {
|
||||
when (action) {
|
||||
HomeserverSettingsAction.Refresh -> fetchHomeserverVersion()
|
||||
}
|
||||
}
|
||||
}
|
27
vector/src/main/res/drawable/ic_layers.xml
Normal file
27
vector/src/main/res/drawable/ic_layers.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M12,2L2,7L12,12L22,7L12,2Z"
|
||||
android:strokeWidth="2"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M2,17L12,22L22,17"
|
||||
android:strokeWidth="2"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M2,12L12,17L22,12"
|
||||
android:strokeWidth="2"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
11
vector/src/main/res/layout/item_settings_centered_image.xml
Normal file
11
vector/src/main/res/layout/item_settings_centered_image.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageView 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:id="@+id/itemSettingsImage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:layout_margin="16dp"
|
||||
android:importantForAccessibility="no"
|
||||
app:tint="@color/riotx_accent"
|
||||
tools:src="@drawable/ic_layers" />
|
@ -1117,6 +1117,7 @@
|
||||
<!-- advanced -->
|
||||
<string name="room_settings_category_advanced_title">Advanced</string>
|
||||
<string name="room_settings_room_internal_id">This room’s internal ID</string>
|
||||
<string name="room_settings_room_version_title">Room version</string>
|
||||
<string name="room_settings_addresses_pref_title">Addresses</string>
|
||||
<string name="room_settings_labs_pref_title">Labs</string>
|
||||
<string name="room_settings_labs_warning_message">These are experimental features that may break in unexpected ways. Use with caution.</string>
|
||||
@ -2336,6 +2337,12 @@
|
||||
<string name="settings_active_sessions_manage">Manage Sessions</string>
|
||||
<string name="settings_active_sessions_signout_device">Sign out of this session</string>
|
||||
|
||||
<string name="settings_server_name">Server name</string>
|
||||
<string name="settings_server_version">Server version</string>
|
||||
<string name="settings_server_upload_size_title">Server file upload limit</string>
|
||||
<string name="settings_server_upload_size_content">Your homeserver accepts attachments (files, media, etc.) with a size up to %s.</string>
|
||||
<string name="settings_server_upload_size_unknown">The limit is unknown.</string>
|
||||
|
||||
<string name="settings_failed_to_get_crypto_device_info">No cryptographic information available</string>
|
||||
|
||||
<string name="settings_active_sessions_verified_device_desc">This session is trusted for secure messaging because you verified it:</string>
|
||||
|
@ -81,6 +81,7 @@
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
android:key="SETTINGS_HOME_SERVER_PREFERENCE_KEY"
|
||||
android:title="@string/settings_home_server"
|
||||
app:fragment="im.vector.app.features.settings.homeserver.HomeserverSettingsFragment"
|
||||
tools:summary="https://homeserver.org" />
|
||||
|
||||
<im.vector.app.core.preference.VectorPreference
|
||||
|
Loading…
Reference in New Issue
Block a user