Merge branch 'develop' into feature/bma/posthog

This commit is contained in:
Benoit Marty 2021-12-13 23:18:14 +01:00
commit a40e60ba8f
270 changed files with 2044 additions and 853 deletions

View File

@ -34,7 +34,7 @@ jobs:
with: with:
headers: '{"GraphQL-Features": "projects_next_graphql"}' headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: | query: |
mutation add_to_project($projectid:String!,$contentid:String!) { mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem { projectNextItem {
id id
@ -47,45 +47,30 @@ jobs:
PROJECT_ID: "PN_kwDOAM0swc0sUA" PROJECT_ID: "PN_kwDOAM0swc0sUA"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
spaces_issues_to_old_board: # delight_issues_to_board:
name: Spaces issues to old Delight project board # name: Spaces issues to new Delight project board
runs-on: ubuntu-latest # runs-on: ubuntu-latest
if: > # if: >
contains(github.event.issue.labels.*.name, 'A-Spaces') || # contains(github.event.issue.labels.*.name, 'A-Spaces') ||
contains(github.event.issue.labels.*.name, 'A-Space-Settings') || # contains(github.event.issue.labels.*.name, 'A-Space-Settings') ||
contains(github.event.issue.labels.*.name, 'A-Subspaces') # contains(github.event.issue.labels.*.name, 'A-Subspaces')
steps: # steps:
- uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338 # - uses: octokit/graphql-action@v2.x
with: # with:
action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}" # headers: '{"GraphQL-Features": "projects_next_graphql"}'
project-url: "https://github.com/orgs/vector-im/projects/6" # query: |
column-name: "📥 Inbox" # mutation add_to_project($projectid:ID!,$contentid:ID!) {
label-name: "A-Spaces" # addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
# projectNextItem {
spaces_issues_to_new_board: # id
name: Spaces issues to new Delight project board # }
runs-on: ubuntu-latest # }
if: > # }
contains(github.event.issue.labels.*.name, 'A-Spaces') || # projectid: ${{ env.PROJECT_ID }}
contains(github.event.issue.labels.*.name, 'A-Space-Settings') || # contentid: ${{ github.event.issue.node_id }}
contains(github.event.issue.labels.*.name, 'A-Subspaces') # env:
steps: # PROJECT_ID: "PN_kwDOAM0swc1HvQ"
- uses: octokit/graphql-action@v2.x # GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:String!,$contentid:String!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
id
}
}
}
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc1HvQ"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_voice-message_issues: move_voice-message_issues:
name: A-Voice Messages to voice message board name: A-Voice Messages to voice message board
@ -97,7 +82,7 @@ jobs:
with: with:
headers: '{"GraphQL-Features": "projects_next_graphql"}' headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: | query: |
mutation add_to_project($projectid:String!,$contentid:String!) { mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem { projectNextItem {
id id
@ -120,7 +105,7 @@ jobs:
with: with:
headers: '{"GraphQL-Features": "projects_next_graphql"}' headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: | query: |
mutation add_to_project($projectid:String!,$contentid:String!) { mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem { projectNextItem {
id id
@ -132,3 +117,26 @@ jobs:
env: env:
PROJECT_ID: "PN_kwDOAM0swc0rRA" PROJECT_ID: "PN_kwDOAM0swc0rRA"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
move_message_bubbles_issues:
name: A-Message-Bubbles to Message bubbles board
runs-on: ubuntu-latest
if: >
contains(github.event.issue.labels.*.name, 'A-Message-Bubbles')
steps:
- uses: octokit/graphql-action@v2.x
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
query: |
mutation add_to_project($projectid:ID!,$contentid:ID!) {
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
projectNextItem {
id
}
}
}
projectid: ${{ env.PROJECT_ID }}
contentid: ${{ github.event.issue.node_id }}
env:
PROJECT_ID: "PN_kwDOAM0swc3m-g"
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}

View File

@ -1,12 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
apply from: 'dependencies.gradle' apply from: 'dependencies.gradle'
apply from: 'dependencies_groups.gradle'
repositories { repositories {
google() google()
jcenter()
maven { maven {
url "https://plugins.gradle.org/m2/" url "https://plugins.gradle.org/m2/"
} }
@ -37,45 +36,50 @@ allprojects {
apply plugin: "org.jlleitschuh.gradle.ktlint" apply plugin: "org.jlleitschuh.gradle.ktlint"
repositories { repositories {
// For olm library. This has to be declared first, to ensure that Olm library is not downloaded from another repo // For olm library.
maven {
url 'https://gitlab.matrix.org/api/v4/projects/27/packages/maven'
content {
groups.olm.regex.each { includeGroupByRegex it }
groups.olm.group.each { includeGroup it }
}
}
maven { maven {
url 'https://jitpack.io' url 'https://jitpack.io'
content { content {
// Use this repo only for olm library groups.jitpack.regex.each { includeGroupByRegex it }
includeGroupByRegex "org\\.matrix\\.gitlab\\.matrix-org" groups.jitpack.group.each { includeGroup it }
// And also for FilePicker
includeGroupByRegex "com\\.github\\.jaiselrahman"
// And monarchy
includeGroupByRegex "com\\.github\\.Zhuinden"
// And ucrop
includeGroupByRegex "com\\.github\\.yalantis"
// JsonViewer
includeGroupByRegex 'com\\.github\\.BillCarsonFr'
// PhotoView
includeGroupByRegex 'com\\.github\\.chrisbanes'
// PFLockScreen-Android
includeGroupByRegex 'com\\.github\\.vector-im'
// DraggableView
includeGroupByRegex 'com\\.github\\.hyuwah'
// Chat effects
includeGroupByRegex 'com\\.github\\.jetradarmobile'
includeGroupByRegex 'nl\\.dionsegijn'
// Voice RecordView
includeGroupByRegex 'com\\.github\\.Armen101'
} }
} }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
// Jitsi repo // Jitsi repo
maven { maven {
url "https://github.com/vector-im/jitsi_libre_maven/raw/main/android-sdk-3.10.0" url "https://github.com/vector-im/jitsi_libre_maven/raw/main/android-sdk-3.10.0"
// Note: to test Jitsi release you can use a local file like this: // Note: to test Jitsi release you can use a local file like this:
// url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-3.10.0" // url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-3.10.0"
content {
groups.jitsi.regex.each { includeGroupByRegex it }
groups.jitsi.group.each { includeGroup it }
}
}
google {
content {
groups.google.regex.each { includeGroupByRegex it }
groups.google.group.each { includeGroup it }
}
}
mavenCentral {
content {
groups.mavenCentral.regex.each { includeGroupByRegex it }
groups.mavenCentral.group.each { includeGroup it }
}
}
//noinspection JcenterRepositoryObsolete
jcenter {
content {
groups.jcenter.regex.each { includeGroupByRegex it }
groups.jcenter.group.each { includeGroup it }
}
} }
google()
mavenCentral()
jcenter()
} }
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {

1
changelog.d/4278.feature Normal file
View File

@ -0,0 +1 @@
Updates URL previews to match latest designs

1
changelog.d/4592.bugfix Normal file
View File

@ -0,0 +1 @@
Fix empty Dev Tools screen issue.

1
changelog.d/4638.feature Normal file
View File

@ -0,0 +1 @@
Add a help section in the settings.

1
changelog.d/4647.misc Normal file
View File

@ -0,0 +1 @@
Upgrade OLM to v3.2.7 and get it from our maven repository.

1
changelog.d/4650.misc Normal file
View File

@ -0,0 +1 @@
Cleanup id ref. Use type views instead

1
changelog.d/4660.feature Normal file
View File

@ -0,0 +1 @@
Create a legal screen in the setting to group all the different policies.

1
changelog.d/4666.misc Normal file
View File

@ -0,0 +1 @@
Add automation to move message bubbles issues to message bubbles board.

1
changelog.d/4670.misc Normal file
View File

@ -0,0 +1 @@
Add explicit dependency location, regarding the several maven repository. Also update some libraries (flexbox and alerter), and do some cleanup.

1
changelog.d/4671.misc Normal file
View File

@ -0,0 +1 @@
Fix graphql warning in issue workflow automation

View File

@ -7,7 +7,7 @@ ext.versions = [
'targetCompat' : JavaVersion.VERSION_11, 'targetCompat' : JavaVersion.VERSION_11,
] ]
def gradle = "7.0.3" def gradle = "7.0.4"
// Ref: https://kotlinlang.org/releases.html // Ref: https://kotlinlang.org/releases.html
def kotlin = "1.5.31" def kotlin = "1.5.31"
def kotlinCoroutines = "1.5.2" def kotlinCoroutines = "1.5.2"
@ -19,7 +19,7 @@ def moshi = "1.12.0"
def lifecycle = "2.4.0" def lifecycle = "2.4.0"
def flowBinding = "1.2.0" def flowBinding = "1.2.0"
def epoxy = "4.6.2" def epoxy = "4.6.2"
def mavericks = "2.4.0" def mavericks = "2.5.0"
def glide = "4.12.0" def glide = "4.12.0"
def bigImageViewer = "1.8.1" def bigImageViewer = "1.8.1"
def jjwt = "0.11.2" def jjwt = "0.11.2"

200
dependencies_groups.gradle Normal file
View File

@ -0,0 +1,200 @@
ext.groups = [
jitpack : [
regex: [
],
group: [
'com.github.Armen101',
'com.github.BillCarsonFr',
'com.github.chrisbanes',
'com.github.hyuwah',
'com.github.jetradarmobile',
'com.github.tapadoo',
'com.github.vector-im',
'com.github.yalantis',
'com.github.Zhuinden',
]
],
olm : [
regex: [
],
group: [
'org.matrix.android',
]
],
jitsi : [
regex: [
],
group: [
'com.facebook.react',
'org.jitsi.react',
'org.webkit',
]
],
google : [
regex: [
'androidx\\..*',
'com\\.android\\.tools\\..*',
'com\\.google\\.android\\..*',
],
group: [
'com.google.firebase',
'com.android',
'com.android.tools',
]
],
mavenCentral: [
regex: [
],
group: [
'com.adevinta.android',
'com.airbnb.android',
'com.almworks.sqlite4java',
'com.arthenica',
'com.atlassian.commonmark',
'com.atlassian.pom',
'com.beust',
'com.davemorrissey.labs',
'com.dropbox.core',
'com.facebook.fresco',
'com.facebook.infer.annotation',
'com.facebook.soloader',
'com.facebook.stetho',
'com.fasterxml',
'com.fasterxml.jackson',
'com.fasterxml.jackson.core',
'com.gabrielittner.threetenbp',
'com.getkeepsafe.relinker',
'com.github.bumptech.glide',
'com.github.filippudak',
'com.github.filippudak.progresspieview',
'com.github.javaparser',
'com.github.piasy',
'com.github.shyiko.klob',
'com.google',
'com.google.auto.service',
'com.google.auto.value',
'com.google.code.findbugs',
'com.google.code.gson',
'com.google.dagger',
'com.google.devtools.ksp',
'com.google.errorprone',
'com.google.googlejavaformat',
'com.google.guava',
'com.google.j2objc',
'com.google.jimfs',
'com.google.protobuf',
'com.google.zxing',
'com.googlecode.htmlcompressor',
'com.googlecode.json-simple',
'com.googlecode.libphonenumber',
'com.ibm.icu',
'com.jakewharton.android.repackaged',
'com.jakewharton.timber',
'com.linkedin.dexmaker',
'com.nulab-inc',
'com.otaliastudios.opengl',
'com.parse.bolts',
'com.pinterest',
'com.pinterest.ktlint',
'com.squareup',
'com.squareup.duktape',
'com.squareup.moshi',
'com.squareup.okhttp3',
'com.squareup.okio',
'com.squareup.retrofit2',
'com.sun.activation',
'com.sun.istack',
'com.sun.xml.bind',
'com.sun.xml.bind.mvn',
'com.sun.xml.fastinfoset',
'com.thoughtworks.qdox',
'com.vanniktech',
'commons-cli',
'commons-codec',
'commons-io',
'commons-logging',
'info.picocli',
'io.arrow-kt',
'io.github.detekt.sarif4k',
'io.github.reactivecircus.flowbinding',
'io.jsonwebtoken',
'io.kindedj',
'io.mockk',
'io.noties.markwon',
'io.reactivex.rxjava2',
'io.realm',
'it.unimi.dsi',
'jakarta.activation',
'jakarta.xml.bind',
'javax.annotation',
'javax.inject',
'jline',
'jp.wasabeef',
'junit',
'me.leolin',
'me.saket',
'net.bytebuddy',
'net.java',
'net.java.dev.jna',
'net.lachlanmckee',
'net.ltgt.gradle.incap',
'net.sf.jopt-simple',
'net.sf.kxml',
'nl.dionsegijn',
'org.amshove.kluent',
'org.apache',
'org.apache.ant',
'org.apache.commons',
'org.apache.httpcomponents',
'org.apache.sanselan',
'org.bouncycastle',
'org.checkerframework',
'org.codehaus',
'org.codehaus.groovy',
'org.codehaus.mojo',
'org.eclipse.ee4j',
'org.ec4j.core',
'org.glassfish.jaxb',
'org.hamcrest',
'org.jetbrains',
'org.jetbrains.intellij.deps',
'org.jetbrains.kotlin',
'org.jetbrains.kotlinx',
'org.jsoup',
'org.junit',
'org.junit.jupiter',
'org.junit.platform',
'org.jvnet.staxex',
'org.mockito',
'org.mongodb',
'org.objenesis',
'org.opentest4j',
'org.ow2',
'org.ow2.asm',
'org.ow2.asm',
'org.reactivestreams',
'org.robolectric',
'org.slf4j',
'org.sonatype.oss',
'org.testng',
'org.threeten',
'xerces',
'xml-apis',
]
],
jcenter : [
regex: [
],
group: [
'com.amulyakhare',
'com.otaliastudios',
'com.yqritc',
// https://github.com/cmelchior/realmfieldnameshelper/issues/42
'dk.ilios',
'im.dlg',
'me.dm7.barcodescanner',
'me.gujun.android',
]
]
]

View File

@ -39,4 +39,7 @@
<!-- Navigation Drawer --> <!-- Navigation Drawer -->
<dimen name="navigation_drawer_max_width">320dp</dimen> <dimen name="navigation_drawer_max_width">320dp</dimen>
<!-- Preview Url -->
<dimen name="preview_url_view_corner_radius">8dp</dimen>
</resources> </resources>

View File

@ -9,7 +9,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath "io.realm:realm-gradle-plugin:10.8.1" classpath "io.realm:realm-gradle-plugin:10.9.0"
} }
} }
@ -140,8 +140,8 @@ dependencies {
implementation libs.arrow.core implementation libs.arrow.core
implementation libs.arrow.instances implementation libs.arrow.instances
// olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm // olm lib is now hosted by maven at https://gitlab.matrix.org/api/v4/projects/27/packages/maven
implementation 'org.matrix.gitlab.matrix-org:olm:3.2.4' implementation 'org.matrix.android:olm:3.2.7'
// DI // DI
implementation libs.dagger.dagger implementation libs.dagger.dagger
@ -158,7 +158,7 @@ dependencies {
implementation libs.apache.commonsImaging implementation libs.apache.commonsImaging
// Phone number https://github.com/google/libphonenumber // Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.38' implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.39'
testImplementation libs.tests.junit testImplementation libs.tests.junit
testImplementation 'org.robolectric:robolectric:4.7.3' testImplementation 'org.robolectric:robolectric:4.7.3'

View File

@ -16,6 +16,8 @@
package org.matrix.android.sdk.api.session.terms package org.matrix.android.sdk.api.session.terms
import org.matrix.android.sdk.internal.session.terms.TermsResponse
interface TermsService { interface TermsService {
enum class ServiceType { enum class ServiceType {
IntegrationManager, IntegrationManager,
@ -28,4 +30,10 @@ interface TermsService {
baseUrl: String, baseUrl: String,
agreedUrls: List<String>, agreedUrls: List<String>,
token: String?) token: String?)
/**
* Get the homeserver terms, from the register API.
* Will be updated once https://github.com/matrix-org/matrix-doc/pull/3012 will be implemented.
*/
suspend fun getHomeserverTerms(baseUrl: String): TermsResponse
} }

View File

@ -18,10 +18,13 @@ package org.matrix.android.sdk.internal.session.terms
import dagger.Lazy import dagger.Lazy
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.terms.GetTermsResponse import org.matrix.android.sdk.api.session.terms.GetTermsResponse
import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
import org.matrix.android.sdk.internal.network.NetworkConstants import org.matrix.android.sdk.internal.network.NetworkConstants
import org.matrix.android.sdk.internal.network.RetrofitFactory import org.matrix.android.sdk.internal.network.RetrofitFactory
@ -55,6 +58,27 @@ internal class DefaultTermsService @Inject constructor(
return GetTermsResponse(termsResponse, getAlreadyAcceptedTermUrlsFromAccountData()) return GetTermsResponse(termsResponse, getAlreadyAcceptedTermUrlsFromAccountData())
} }
/**
* We use a trick here to get the homeserver T&C, we use the register API
*/
override suspend fun getHomeserverTerms(baseUrl: String): TermsResponse {
return try {
executeRequest(null) {
termsAPI.register(baseUrl + NetworkConstants.URI_API_PREFIX_PATH_R0 + "register")
}
// Return empty result if it succeed, but it should never happen
TermsResponse()
} catch (throwable: Throwable) {
@Suppress("UNCHECKED_CAST")
TermsResponse(
policies = (throwable.toRegistrationFlowResponse()
?.params
?.get(LoginFlowTypes.TERMS) as? JsonDict)
?.get("policies") as? JsonDict
)
}
}
override suspend fun agreeToTerms(serviceType: TermsService.ServiceType, override suspend fun agreeToTerms(serviceType: TermsService.ServiceType,
baseUrl: String, baseUrl: String,
agreedUrls: List<String>, agreedUrls: List<String>,

View File

@ -16,6 +16,8 @@
package org.matrix.android.sdk.internal.session.terms package org.matrix.android.sdk.internal.session.terms
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.api.util.emptyJsonDict
import org.matrix.android.sdk.internal.network.HttpHeaders import org.matrix.android.sdk.internal.network.HttpHeaders
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
@ -37,4 +39,12 @@ internal interface TermsAPI {
suspend fun agreeToTerms(@Url url: String, suspend fun agreeToTerms(@Url url: String,
@Body params: AcceptTermsBody, @Body params: AcceptTermsBody,
@Header(HttpHeaders.Authorization) token: String) @Header(HttpHeaders.Authorization) token: String)
/**
* API to retrieve the terms for a homeserver. The API /terms does not exist yet, so retrieve the terms from the login flow.
* We do not care about the result (Credentials)
*/
@POST
suspend fun register(@Url url: String,
@Body body: JsonDict = emptyJsonDict)
} }

View File

@ -35,9 +35,9 @@ class ${activityClass} : VectorBaseActivity(), ToolbarConfigurable {
<#if createFragmentArgs> <#if createFragmentArgs>
val fragmentArgs: ${fragmentArgsClass} = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS) val fragmentArgs: ${fragmentArgsClass} = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS)
?: return ?: return
addFragment(R.id.simpleFragmentContainer, ${fragmentClass}::class.java, fragmentArgs) addFragment(views.simpleFragmentContainer.id, ${fragmentClass}::class.java, fragmentArgs)
<#else> <#else>
addFragment(R.id.simpleFragmentContainer, ${fragmentClass}::class.java) addFragment(views.simpleFragmentContainer.id, ${fragmentClass}::class.java)
</#if> </#if>
} }
} }

View File

@ -141,7 +141,6 @@ android {
resValue "string", "build_number", "\"${buildNumber}\"" resValue "string", "build_number", "\"${buildNumber}\""
buildConfigField "im.vector.app.features.VectorFeatures.LoginVersion", "LOGIN_VERSION", "im.vector.app.features.VectorFeatures.LoginVersion.V1" buildConfigField "im.vector.app.features.VectorFeatures.LoginVersion", "LOGIN_VERSION", "im.vector.app.features.VectorFeatures.LoginVersion.V1"
buildConfigField "im.vector.app.features.VectorFeatures.NotificationSettingsVersion", "NOTIFICATION_SETTINGS_VERSION", "im.vector.app.features.VectorFeatures.NotificationSettingsVersion.V2"
buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping" buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping"
@ -317,11 +316,6 @@ android {
} }
} }
configurations {
// videocache includes a sl4j logger which causes mockk to attempt to call the static android Log
testImplementation.exclude group: 'org.slf4j', module: 'slf4j-android'
}
dependencies { dependencies {
implementation project(":matrix-sdk-android") implementation project(":matrix-sdk-android")
@ -365,7 +359,7 @@ dependencies {
implementation 'com.facebook.stetho:stetho:1.6.0' implementation 'com.facebook.stetho:stetho:1.6.0'
// Phone number https://github.com/google/libphonenumber // Phone number https://github.com/google/libphonenumber
implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.38' implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.39'
// FlowBinding // FlowBinding
implementation libs.github.flowBinding implementation libs.github.flowBinding
@ -398,7 +392,7 @@ dependencies {
implementation libs.markwon.html implementation libs.markwon.html
implementation 'com.googlecode.htmlcompressor:htmlcompressor:1.5.2' implementation 'com.googlecode.htmlcompressor:htmlcompressor:1.5.2'
implementation 'me.saket:better-link-movement-method:2.2.0' implementation 'me.saket:better-link-movement-method:2.2.0'
implementation 'com.google.android:flexbox:2.0.1' implementation 'com.google.android.flexbox:flexbox:3.0.0'
implementation libs.androidx.autoFill implementation libs.androidx.autoFill
implementation 'jp.wasabeef:glide-transformations:4.3.0' implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation 'com.github.vector-im:PFLockScreen-Android:1.0.0-beta12' implementation 'com.github.vector-im:PFLockScreen-Android:1.0.0-beta12'
@ -415,7 +409,7 @@ dependencies {
implementation 'com.arthenica:ffmpeg-kit-audio:4.5.LTS' implementation 'com.arthenica:ffmpeg-kit-audio:4.5.LTS'
// Alerter // Alerter
implementation 'com.tapadoo.android:alerter:7.0.1' implementation 'com.github.tapadoo:alerter:7.2.4'
implementation 'com.otaliastudios:autocomplete:1.1.0' implementation 'com.otaliastudios:autocomplete:1.1.0'
@ -433,7 +427,6 @@ dependencies {
implementation libs.github.glide implementation libs.github.glide
kapt libs.github.glideCompiler kapt libs.github.glideCompiler
implementation 'com.danikula:videocache:2.7.1'
implementation 'com.github.yalantis:ucrop:2.2.7' implementation 'com.github.yalantis:ucrop:2.2.7'
// Badge for compatibility // Badge for compatibility

View File

@ -18,20 +18,12 @@ package im.vector.app.ui.robot.settings
import androidx.test.espresso.Espresso.pressBack import androidx.test.espresso.Espresso.pressBack
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import im.vector.app.BuildConfig
import im.vector.app.R import im.vector.app.R
import im.vector.app.espresso.tools.clickOnPreference import im.vector.app.espresso.tools.clickOnPreference
import im.vector.app.features.VectorFeatures
class SettingsNotificationsRobot { class SettingsNotificationsRobot {
fun crawl() { fun crawl() {
when (BuildConfig.NOTIFICATION_SETTINGS_VERSION!!) {
VectorFeatures.NotificationSettingsVersion.V1 -> {
clickOn(R.string.settings_notification_advanced)
pressBack()
}
VectorFeatures.NotificationSettingsVersion.V2 -> {
clickOn(R.string.settings_notification_default) clickOn(R.string.settings_notification_default)
pressBack() pressBack()
clickOn(R.string.settings_notification_mentions_and_keywords) clickOn(R.string.settings_notification_mentions_and_keywords)
@ -39,8 +31,6 @@ class SettingsNotificationsRobot {
pressBack() pressBack()
clickOn(R.string.settings_notification_other) clickOn(R.string.settings_notification_other)
pressBack() pressBack()
}
}
/* /*
clickOn(R.string.settings_noisy_notifications_preferences) clickOn(R.string.settings_noisy_notifications_preferences)

View File

@ -8,6 +8,7 @@
<activity android:name=".features.debug.analytics.DebugAnalyticsActivity" /> <activity android:name=".features.debug.analytics.DebugAnalyticsActivity" />
<activity android:name=".features.debug.settings.DebugPrivateSettingsActivity" /> <activity android:name=".features.debug.settings.DebugPrivateSettingsActivity" />
<activity android:name=".features.debug.sas.DebugSasEmojiActivity" /> <activity android:name=".features.debug.sas.DebugSasEmojiActivity" />
<activity android:name=".features.debug.features.DebugFeaturesSettingsActivity" />
</application> </application>
</manifest> </manifest>

View File

@ -35,6 +35,7 @@ import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.core.utils.toast import im.vector.app.core.utils.toast
import im.vector.app.databinding.ActivityDebugMenuBinding import im.vector.app.databinding.ActivityDebugMenuBinding
import im.vector.app.features.debug.analytics.DebugAnalyticsActivity import im.vector.app.features.debug.analytics.DebugAnalyticsActivity
import im.vector.app.features.debug.features.DebugFeaturesSettingsActivity
import im.vector.app.features.debug.sas.DebugSasEmojiActivity import im.vector.app.features.debug.sas.DebugSasEmojiActivity
import im.vector.app.features.debug.settings.DebugPrivateSettingsActivity import im.vector.app.features.debug.settings.DebugPrivateSettingsActivity
import im.vector.app.features.qrcode.QrCodeScannerActivity import im.vector.app.features.qrcode.QrCodeScannerActivity
@ -77,6 +78,7 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
} }
private fun setupViews() { private fun setupViews() {
views.debugFeatures.setOnClickListener { startActivity(Intent(this, DebugFeaturesSettingsActivity::class.java)) }
views.debugPrivateSetting.setOnClickListener { openPrivateSettings() } views.debugPrivateSetting.setOnClickListener { openPrivateSettings() }
views.debugAnalytics.setOnClickListener { views.debugAnalytics.setOnClickListener {
startActivity(Intent(this, DebugAnalyticsActivity::class.java)) startActivity(Intent(this, DebugAnalyticsActivity::class.java))

View File

@ -0,0 +1,48 @@
/*
* 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.debug.di
import android.content.Context
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import im.vector.app.features.DefaultVectorFeatures
import im.vector.app.features.VectorFeatures
import im.vector.app.features.debug.features.DebugVectorFeatures
@InstallIn(SingletonComponent::class)
@Module
interface FeaturesModule {
@Binds
fun bindFeatures(debugFeatures: DebugVectorFeatures): VectorFeatures
companion object {
@Provides
fun providesDefaultVectorFeatures(): DefaultVectorFeatures {
return DefaultVectorFeatures()
}
@Provides
fun providesDebugVectorFeatures(context: Context, defaultVectorFeatures: DefaultVectorFeatures): DebugVectorFeatures {
return DebugVectorFeatures(context, defaultVectorFeatures)
}
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.debug.features
import android.os.Bundle
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.cleanup
import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import javax.inject.Inject
@AndroidEntryPoint
class DebugFeaturesSettingsActivity : VectorBaseActivity<FragmentGenericRecyclerBinding>() {
@Inject lateinit var debugFeatures: DebugVectorFeatures
@Inject lateinit var debugFeaturesStateFactory: DebugFeaturesStateFactory
@Inject lateinit var controller: FeaturesController
override fun getBinding() = FragmentGenericRecyclerBinding.inflate(layoutInflater)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
controller.listener = object : EnumFeatureItem.Listener {
override fun <T : Enum<T>> onOptionSelected(option: T?, feature: Feature.EnumFeature<T>) {
debugFeatures.overrideEnum(option, feature.type)
}
}
views.genericRecyclerView.configureWith(controller)
controller.setData(debugFeaturesStateFactory.create())
}
override fun onDestroy() {
controller.listener = null
views.genericRecyclerView.cleanup()
super.onDestroy()
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.debug.features
import im.vector.app.features.DefaultVectorFeatures
import javax.inject.Inject
class DebugFeaturesStateFactory @Inject constructor(
private val debugFeatures: DebugVectorFeatures,
private val defaultFeatures: DefaultVectorFeatures
) {
fun create(): FeaturesState {
return FeaturesState(listOf(
createEnumFeature(
label = "Login version",
selection = debugFeatures.loginVersion(),
default = defaultFeatures.loginVersion()
)
))
}
private inline fun <reified T : Enum<T>> createEnumFeature(label: String, selection: T, default: T): Feature {
return Feature.EnumFeature(
label = label,
selection = selection.takeIf { debugFeatures.hasEnumOverride(T::class) },
default = default,
options = enumValues<T>().toList(),
type = T::class
)
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.debug.features
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.MutablePreferences
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import im.vector.app.features.DefaultVectorFeatures
import im.vector.app.features.VectorFeatures
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import kotlin.reflect.KClass
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "debug_features")
class DebugVectorFeatures(
context: Context,
private val vectorFeatures: DefaultVectorFeatures
) : VectorFeatures {
private val dataStore = context.dataStore
override fun loginVersion(): VectorFeatures.LoginVersion {
return readPreferences().getEnum<VectorFeatures.LoginVersion>() ?: vectorFeatures.loginVersion()
}
fun <T : Enum<T>> hasEnumOverride(type: KClass<T>) = readPreferences().containsEnum(type)
fun <T : Enum<T>> overrideEnum(value: T?, type: KClass<T>) {
if (value == null) {
updatePreferences { it.removeEnum(type) }
} else {
updatePreferences { it.putEnum(value, type) }
}
}
private fun readPreferences() = runBlocking { dataStore.data.first() }
private fun updatePreferences(block: (MutablePreferences) -> Unit) = runBlocking {
dataStore.edit { block(it) }
}
}
private fun <T : Enum<T>> MutablePreferences.removeEnum(type: KClass<T>) {
remove(enumPreferencesKey(type))
}
private fun <T : Enum<T>> Preferences.containsEnum(type: KClass<T>) = contains(enumPreferencesKey(type))
private fun <T : Enum<T>> MutablePreferences.putEnum(value: T, type: KClass<T>) {
this[enumPreferencesKey(type)] = value.name
}
private inline fun <reified T : Enum<T>> Preferences.getEnum(): T? {
return get(enumPreferencesKey<T>())?.let { enumValueOf<T>(it) }
}
private inline fun <reified T : Enum<T>> enumPreferencesKey() = enumPreferencesKey(T::class)
private fun <T : Enum<T>> enumPreferencesKey(type: KClass<T>) = stringPreferencesKey("enum-${type.simpleName}")

View File

@ -0,0 +1,79 @@
/*
* Copyright 2019 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.debug.features
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
@EpoxyModelClass(layout = im.vector.app.R.layout.item_feature)
abstract class EnumFeatureItem : VectorEpoxyModel<EnumFeatureItem.Holder>() {
@EpoxyAttribute
lateinit var feature: Feature.EnumFeature<*>
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
var listener: Listener? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.label.text = feature.label
holder.optionsSpinner.apply {
val arrayAdapter = ArrayAdapter<String>(context, android.R.layout.simple_spinner_dropdown_item)
arrayAdapter.add("DEFAULT - ${feature.default.name}")
arrayAdapter.addAll(feature.options.map { it.name })
adapter = arrayAdapter
feature.selection?.let {
setSelection(feature.options.indexOf(it) + 1, false)
}
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (position) {
0 -> listener?.onOptionSelected(option = null, feature)
else -> feature.onOptionSelected(position - 1)
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// do nothing
}
}
}
}
private fun <T : Enum<T>> Feature.EnumFeature<T>.onOptionSelected(selection: Int) {
listener?.onOptionSelected(options[selection], this)
}
class Holder : VectorEpoxyHolder() {
val label by bind<TextView>(im.vector.app.R.id.feature_label)
val optionsSpinner by bind<Spinner>(im.vector.app.R.id.feature_options)
}
interface Listener {
fun <T : Enum<T>> onOptionSelected(option: T?, feature: Feature.EnumFeature<T>)
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2019 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.debug.features
import com.airbnb.epoxy.TypedEpoxyController
import javax.inject.Inject
import kotlin.reflect.KClass
data class FeaturesState(
val features: List<Feature>
)
sealed interface Feature {
data class EnumFeature<T : Enum<T>>(
val label: String,
val selection: T?,
val default: T,
val options: List<T>,
val type: KClass<T>
) : Feature
}
class FeaturesController @Inject constructor() : TypedEpoxyController<FeaturesState>() {
var listener: EnumFeatureItem.Listener? = null
override fun buildModels(data: FeaturesState?) {
if (data == null) return
data.features.forEachIndexed { index, feature ->
when (feature) {
is Feature.EnumFeature<*> -> enumFeatureItem {
id(index)
feature(feature)
listener(this@FeaturesController.listener)
}
}
}
}
}

View File

@ -17,7 +17,6 @@
package im.vector.app.features.debug.settings package im.vector.app.features.debug.settings
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.databinding.ActivitySimpleBinding
@ -30,7 +29,7 @@ class DebugPrivateSettingsActivity : VectorBaseActivity<ActivitySimpleBinding>()
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment( addFragment(
R.id.simpleFragmentContainer, views.simpleFragmentContainer,
DebugPrivateSettingsFragment::class.java DebugPrivateSettingsFragment::class.java
) )
} }

View File

@ -20,6 +20,12 @@
android:padding="@dimen/layout_horizontal_margin" android:padding="@dimen/layout_horizontal_margin"
android:showDividers="middle"> android:showDividers="middle">
<Button
android:id="@+id/debug_features"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Features" />
<Button <Button
android:id="@+id/debug_private_setting" android:id="@+id/debug_private_setting"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/feature_label"
style="@style/Widget.Vector.TextView.Subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:gravity="center"
android:textColor="?vctr_content_primary"
tools:text="Login version" />
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/feature_options"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>

View File

@ -8,7 +8,8 @@
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal"
tools:viewBindingIgnore="true">
<TextView <TextView
android:id="@+id/sas_emoji_index" android:id="@+id/sas_emoji_index"

View File

@ -342,11 +342,6 @@ SOFTWARE.
<br/> <br/>
Copyright 2012 Square, Inc. Copyright 2012 Square, Inc.
</li> </li>
<li>
<b>videocache</b>
<br/>
Copyright 2014-2017 Alexey Danilov
</li>
<li> <li>
<b>ShortcutBadger</b> <b>ShortcutBadger</b>
<br/> <br/>

View File

@ -134,6 +134,7 @@ import im.vector.app.features.settings.devtools.KeyRequestsFragment
import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment
import im.vector.app.features.settings.homeserver.HomeserverSettingsFragment import im.vector.app.features.settings.homeserver.HomeserverSettingsFragment
import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
import im.vector.app.features.settings.legals.LegalsFragment
import im.vector.app.features.settings.locale.LocalePickerFragment import im.vector.app.features.settings.locale.LocalePickerFragment
import im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment import im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment
import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment
@ -705,6 +706,11 @@ interface FragmentModule {
@FragmentKey(DiscoverySettingsFragment::class) @FragmentKey(DiscoverySettingsFragment::class)
fun bindDiscoverySettingsFragment(fragment: DiscoverySettingsFragment): Fragment fun bindDiscoverySettingsFragment(fragment: DiscoverySettingsFragment): Fragment
@Binds
@IntoMap
@FragmentKey(LegalsFragment::class)
fun bindLegalsFragment(fragment: LegalsFragment): Fragment
@Binds @Binds
@IntoMap @IntoMap
@FragmentKey(ReviewTermsFragment::class) @FragmentKey(ReviewTermsFragment::class)

View File

@ -87,6 +87,7 @@ import im.vector.app.features.settings.devtools.KeyRequestListViewModel
import im.vector.app.features.settings.devtools.KeyRequestViewModel import im.vector.app.features.settings.devtools.KeyRequestViewModel
import im.vector.app.features.settings.homeserver.HomeserverSettingsViewModel import im.vector.app.features.settings.homeserver.HomeserverSettingsViewModel
import im.vector.app.features.settings.ignored.IgnoredUsersViewModel import im.vector.app.features.settings.ignored.IgnoredUsersViewModel
import im.vector.app.features.settings.legals.LegalsViewModel
import im.vector.app.features.settings.locale.LocalePickerViewModel import im.vector.app.features.settings.locale.LocalePickerViewModel
import im.vector.app.features.settings.push.PushGatewaysViewModel import im.vector.app.features.settings.push.PushGatewaysViewModel
import im.vector.app.features.settings.threepids.ThreePidsSettingsViewModel import im.vector.app.features.settings.threepids.ThreePidsSettingsViewModel
@ -516,6 +517,11 @@ interface MavericksViewModelModule {
@MavericksViewModelKey(DiscoverySettingsViewModel::class) @MavericksViewModelKey(DiscoverySettingsViewModel::class)
fun discoverySettingsViewModelFactory(factory: DiscoverySettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> fun discoverySettingsViewModelFactory(factory: DiscoverySettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
@Binds
@IntoMap
@MavericksViewModelKey(LegalsViewModel::class)
fun legalsViewModelFactory(factory: LegalsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
@Binds @Binds
@IntoMap @IntoMap
@MavericksViewModelKey(RoomDetailViewModel::class) @MavericksViewModelKey(RoomDetailViewModel::class)

View File

@ -31,8 +31,6 @@ import im.vector.app.core.error.DefaultErrorFormatter
import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.time.Clock import im.vector.app.core.time.Clock
import im.vector.app.core.time.DefaultClock import im.vector.app.core.time.DefaultClock
import im.vector.app.features.DefaultVectorFeatures
import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.VectorAnalytics import im.vector.app.features.analytics.VectorAnalytics
import im.vector.app.features.analytics.impl.DefaultVectorAnalytics import im.vector.app.features.analytics.impl.DefaultVectorAnalytics
import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.AutoAcceptInvites
@ -140,9 +138,4 @@ object VectorStaticModule {
fun providesCoroutineDispatchers(): CoroutineDispatchers { fun providesCoroutineDispatchers(): CoroutineDispatchers {
return CoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.Default) return CoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.Default)
} }
@Provides
fun providesFeatures(): VectorFeatures {
return DefaultVectorFeatures()
}
} }

View File

@ -19,6 +19,7 @@ package im.vector.app.core.extensions
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Parcelable import android.os.Parcelable
import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
@ -33,57 +34,56 @@ fun ComponentActivity.registerStartForActivityResult(onResult: (ActivityResult)
} }
fun AppCompatActivity.addFragment( fun AppCompatActivity.addFragment(
frameId: Int, container: ViewGroup,
fragment: Fragment, fragment: Fragment,
allowStateLoss: Boolean = false allowStateLoss: Boolean = false) {
) { supportFragmentManager.commitTransaction(allowStateLoss) { add(container.id, fragment) }
supportFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
} }
fun <T : Fragment> AppCompatActivity.addFragment( fun <T : Fragment> AppCompatActivity.addFragment(
frameId: Int, container: ViewGroup,
fragmentClass: Class<T>, fragmentClass: Class<T>,
params: Parcelable? = null, params: Parcelable? = null,
tag: String? = null, tag: String? = null,
allowStateLoss: Boolean = false allowStateLoss: Boolean = false) {
) {
supportFragmentManager.commitTransaction(allowStateLoss) { supportFragmentManager.commitTransaction(allowStateLoss) {
add(frameId, fragmentClass, params.toMvRxBundle(), tag) add(container.id, fragmentClass, params.toMvRxBundle(), tag)
} }
} }
fun AppCompatActivity.replaceFragment( fun AppCompatActivity.replaceFragment(
frameId: Int, container: ViewGroup,
fragment: Fragment, fragment: Fragment,
tag: String? = null, tag: String? = null,
allowStateLoss: Boolean = false allowStateLoss: Boolean = false) {
) { supportFragmentManager.commitTransaction(allowStateLoss) {
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment, tag) } replace(container.id, fragment, tag)
}
} }
fun <T : Fragment> AppCompatActivity.replaceFragment( fun <T : Fragment> AppCompatActivity.replaceFragment(
frameId: Int, container: ViewGroup,
fragmentClass: Class<T>, fragmentClass: Class<T>,
params: Parcelable? = null, params: Parcelable? = null,
tag: String? = null, tag: String? = null,
allowStateLoss: Boolean = false allowStateLoss: Boolean = false) {
) {
supportFragmentManager.commitTransaction(allowStateLoss) { supportFragmentManager.commitTransaction(allowStateLoss) {
replace(frameId, fragmentClass, params.toMvRxBundle(), tag) replace(container.id, fragmentClass, params.toMvRxBundle(), tag)
} }
} }
fun AppCompatActivity.addFragmentToBackstack( fun AppCompatActivity.addFragmentToBackstack(
frameId: Int, container: ViewGroup,
fragment: Fragment, fragment: Fragment,
tag: String? = null, tag: String? = null,
allowStateLoss: Boolean = false allowStateLoss: Boolean = false) {
) { supportFragmentManager.commitTransaction(allowStateLoss) {
supportFragmentManager.commitTransaction(allowStateLoss) { replace(frameId, fragment).addToBackStack(tag) } replace(container.id, fragment).addToBackStack(tag)
}
} }
fun <T : Fragment> AppCompatActivity.addFragmentToBackstack( fun <T : Fragment> AppCompatActivity.addFragmentToBackstack(
frameId: Int, container: ViewGroup,
fragmentClass: Class<T>, fragmentClass: Class<T>,
params: Parcelable? = null, params: Parcelable? = null,
tag: String? = null, tag: String? = null,
@ -91,7 +91,7 @@ fun <T : Fragment> AppCompatActivity.addFragmentToBackstack(
option: ((FragmentTransaction) -> Unit)? = null) { option: ((FragmentTransaction) -> Unit)? = null) {
supportFragmentManager.commitTransaction(allowStateLoss) { supportFragmentManager.commitTransaction(allowStateLoss) {
option?.invoke(this) option?.invoke(this)
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) replace(container.id, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
} }
} }

View File

@ -20,7 +20,7 @@ import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.util.AttributeSet import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.view.isVisible import androidx.core.view.isInvisible
import im.vector.app.R import im.vector.app.R
import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
@ -38,28 +38,28 @@ class SendStateImageView @JvmOverloads constructor(
} }
fun render(sendState: SendStateDecoration) { fun render(sendState: SendStateDecoration) {
isVisible = when (sendState) { isInvisible = when (sendState) {
SendStateDecoration.SENDING_NON_MEDIA -> { SendStateDecoration.SENDING_NON_MEDIA -> {
setImageResource(R.drawable.ic_sending_message) setImageResource(R.drawable.ic_sending_message)
imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary)) imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary))
contentDescription = context.getString(R.string.event_status_a11y_sending) contentDescription = context.getString(R.string.event_status_a11y_sending)
true false
} }
SendStateDecoration.SENT -> { SendStateDecoration.SENT -> {
setImageResource(R.drawable.ic_message_sent) setImageResource(R.drawable.ic_message_sent)
imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary)) imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary))
contentDescription = context.getString(R.string.event_status_a11y_sent) contentDescription = context.getString(R.string.event_status_a11y_sent)
true false
} }
SendStateDecoration.FAILED -> { SendStateDecoration.FAILED -> {
setImageResource(R.drawable.ic_sending_message_failed) setImageResource(R.drawable.ic_sending_message_failed)
imageTintList = null imageTintList = null
contentDescription = context.getString(R.string.event_status_a11y_failed) contentDescription = context.getString(R.string.event_status_a11y_failed)
true false
} }
SendStateDecoration.SENDING_MEDIA, SendStateDecoration.SENDING_MEDIA,
SendStateDecoration.NONE -> { SendStateDecoration.NONE -> {
false true
} }
} }
} }

View File

@ -23,7 +23,7 @@ import android.webkit.WebViewClient
import android.widget.TextView import android.widget.TextView
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R import im.vector.app.R
import im.vector.app.features.discovery.IdentityServerWithTerms import im.vector.app.features.discovery.ServerAndPolicies
import me.gujun.android.span.link import me.gujun.android.span.link
import me.gujun.android.span.span import me.gujun.android.span.span
@ -45,7 +45,7 @@ fun Context.displayInWebView(url: String) {
.show() .show()
} }
fun Context.showIdentityServerConsentDialog(identityServerWithTerms: IdentityServerWithTerms?, fun Context.showIdentityServerConsentDialog(identityServerWithTerms: ServerAndPolicies?,
consentCallBack: (() -> Unit)) { consentCallBack: (() -> Unit)) {
// Build the message // Build the message
val content = span { val content = span {

View File

@ -21,7 +21,6 @@ import im.vector.app.BuildConfig
interface VectorFeatures { interface VectorFeatures {
fun loginVersion(): LoginVersion fun loginVersion(): LoginVersion
fun notificationSettingsVersion(): NotificationSettingsVersion
enum class LoginVersion { enum class LoginVersion {
V1, V1,
@ -36,5 +35,4 @@ interface VectorFeatures {
class DefaultVectorFeatures : VectorFeatures { class DefaultVectorFeatures : VectorFeatures {
override fun loginVersion(): VectorFeatures.LoginVersion = BuildConfig.LOGIN_VERSION override fun loginVersion(): VectorFeatures.LoginVersion = BuildConfig.LOGIN_VERSION
override fun notificationSettingsVersion(): VectorFeatures.NotificationSettingsVersion = BuildConfig.NOTIFICATION_SETTINGS_VERSION
} }

View File

@ -21,7 +21,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
@ -61,7 +60,7 @@ class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(),
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
val fragmentArgs: AttachmentsPreviewArgs = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS) ?: return val fragmentArgs: AttachmentsPreviewArgs = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS) ?: return
addFragment(R.id.simpleFragmentContainer, AttachmentsPreviewFragment::class.java, fragmentArgs) addFragment(views.simpleFragmentContainer, AttachmentsPreviewFragment::class.java, fragmentArgs)
} }
} }

View File

@ -79,7 +79,7 @@ class ReAuthActivity : SimpleFragmentActivity() {
// so we assume that after the user close the tab we return success and let caller retry the UIA flow :/ // so we assume that after the user close the tab we return success and let caller retry the UIA flow :/
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment( addFragment(
R.id.container, views.container,
PromptFragment::class.java PromptFragment::class.java
) )
} }

View File

@ -17,9 +17,9 @@
package im.vector.app.features.contactsbook package im.vector.app.features.contactsbook
import im.vector.app.core.platform.VectorViewEvents import im.vector.app.core.platform.VectorViewEvents
import im.vector.app.features.discovery.IdentityServerWithTerms import im.vector.app.features.discovery.ServerAndPolicies
sealed class ContactsBookViewEvents : VectorViewEvents { sealed class ContactsBookViewEvents : VectorViewEvents {
data class Failure(val throwable: Throwable) : ContactsBookViewEvents() data class Failure(val throwable: Throwable) : ContactsBookViewEvents()
data class OnPoliciesRetrieved(val identityServerWithTerms: IdentityServerWithTerms?) : ContactsBookViewEvents() data class OnPoliciesRetrieved(val identityServerWithTerms: ServerAndPolicies?) : ContactsBookViewEvents()
} }

View File

@ -80,7 +80,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment( addFragment(
R.id.container, views.container,
UserListFragment::class.java, UserListFragment::class.java,
UserListFragmentArgs( UserListFragmentArgs(
title = getString(R.string.fab_menu_create_chat), title = getString(R.string.fab_menu_create_chat),
@ -95,20 +95,20 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
private fun openAddByQrCode() { private fun openAddByQrCode() {
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, permissionCameraLauncher)) { if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, permissionCameraLauncher)) {
addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) addFragment(views.container, CreateDirectRoomByQrCodeFragment::class.java)
} }
} }
private fun openPhoneBook() { private fun openPhoneBook() {
// Check permission first // Check permission first
if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, this, permissionReadContactLauncher)) { if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, this, permissionReadContactLauncher)) {
addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) addFragmentToBackstack(views.container, ContactsBookFragment::class.java)
} }
} }
private val permissionReadContactLauncher = registerForPermissionsResult { allGranted, deniedPermanently -> private val permissionReadContactLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
if (allGranted) { if (allGranted) {
doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } doOnPostResume { addFragmentToBackstack(views.container, ContactsBookFragment::class.java) }
} else if (deniedPermanently) { } else if (deniedPermanently) {
onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact) onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact)
} }
@ -116,7 +116,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
private val permissionCameraLauncher = registerForPermissionsResult { allGranted, deniedPermanently -> private val permissionCameraLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
if (allGranted) { if (allGranted) {
addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) addFragment(views.container, CreateDirectRoomByQrCodeFragment::class.java)
} else if (deniedPermanently) { } else if (deniedPermanently) {
onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code) onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code)
} }

View File

@ -64,9 +64,9 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
val isBackupCreatedFromPassphrase = val isBackupCreatedFromPassphrase =
viewModel.keyVersionResult.value?.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null viewModel.keyVersionResult.value?.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
if (isBackupCreatedFromPassphrase) { if (isBackupCreatedFromPassphrase) {
replaceFragment(R.id.container, KeysBackupRestoreFromPassphraseFragment::class.java) replaceFragment(views.container, KeysBackupRestoreFromPassphraseFragment::class.java)
} else { } else {
replaceFragment(R.id.container, KeysBackupRestoreFromKeyFragment::class.java) replaceFragment(views.container, KeysBackupRestoreFromKeyFragment::class.java)
} }
} }
} }
@ -91,13 +91,13 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
viewModel.navigateEvent.observeEvent(this) { uxStateEvent -> viewModel.navigateEvent.observeEvent(this) { uxStateEvent ->
when (uxStateEvent) { when (uxStateEvent) {
KeysBackupRestoreSharedViewModel.NAVIGATE_TO_RECOVER_WITH_KEY -> { KeysBackupRestoreSharedViewModel.NAVIGATE_TO_RECOVER_WITH_KEY -> {
addFragmentToBackstack(R.id.container, KeysBackupRestoreFromKeyFragment::class.java, allowStateLoss = true) addFragmentToBackstack(views.container, KeysBackupRestoreFromKeyFragment::class.java, allowStateLoss = true)
} }
KeysBackupRestoreSharedViewModel.NAVIGATE_TO_SUCCESS -> { KeysBackupRestoreSharedViewModel.NAVIGATE_TO_SUCCESS -> {
viewModel.keyVersionResult.value?.version?.let { viewModel.keyVersionResult.value?.version?.let {
KeysBackupBanner.onRecoverDoneForVersion(this, it) KeysBackupBanner.onRecoverDoneForVersion(this, it)
} }
replaceFragment(R.id.container, KeysBackupRestoreSuccessFragment::class.java, allowStateLoss = true) replaceFragment(views.container, KeysBackupRestoreSuccessFragment::class.java, allowStateLoss = true)
} }
KeysBackupRestoreSharedViewModel.NAVIGATE_TO_4S -> { KeysBackupRestoreSharedViewModel.NAVIGATE_TO_4S -> {
launch4SActivity() launch4SActivity()

View File

@ -44,7 +44,7 @@ class KeysBackupManageActivity : SimpleFragmentActivity() {
override fun initUiAndData() { override fun initUiAndData() {
super.initUiAndData() super.initUiAndData()
if (supportFragmentManager.fragments.isEmpty()) { if (supportFragmentManager.fragments.isEmpty()) {
replaceFragment(R.id.container, KeysBackupSettingsFragment::class.java) replaceFragment(views.container, KeysBackupSettingsFragment::class.java)
viewModel.handle(KeyBackupSettingsAction.Init) viewModel.handle(KeyBackupSettingsAction.Init)
} }

View File

@ -54,7 +54,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
override fun initUiAndData() { override fun initUiAndData() {
super.initUiAndData() super.initUiAndData()
if (isFirstCreation()) { if (isFirstCreation()) {
replaceFragment(R.id.container, KeysBackupSetupStep1Fragment::class.java) replaceFragment(views.container, KeysBackupSetupStep1Fragment::class.java)
} }
viewModel = viewModelProvider.get(KeysBackupSetupSharedViewModel::class.java) viewModel = viewModelProvider.get(KeysBackupSetupSharedViewModel::class.java)
@ -80,11 +80,11 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
when (uxStateEvent) { when (uxStateEvent) {
KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2 -> { KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2 -> {
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
replaceFragment(R.id.container, KeysBackupSetupStep2Fragment::class.java) replaceFragment(views.container, KeysBackupSetupStep2Fragment::class.java)
} }
KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_3 -> { KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_3 -> {
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
replaceFragment(R.id.container, KeysBackupSetupStep3Fragment::class.java) replaceFragment(views.container, KeysBackupSetupStep3Fragment::class.java)
} }
KeysBackupSetupSharedViewModel.NAVIGATE_FINISH -> { KeysBackupSetupSharedViewModel.NAVIGATE_FINISH -> {
val resultIntent = Intent() val resultIntent = Intent()

View File

@ -31,7 +31,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.core.platform.SimpleFragmentActivity
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.crypto.recover.SetupMode
@ -84,7 +84,7 @@ class SharedSecureStorageActivity :
SharedSecureStorageViewState.Step.ResetAll -> SharedSecuredStorageResetAllFragment::class SharedSecureStorageViewState.Step.ResetAll -> SharedSecuredStorageResetAllFragment::class
} }
showFragment(fragment, Bundle()) showFragment(fragment)
} }
private fun observeViewEvents(it: SharedSecureStorageViewEvent?) { private fun observeViewEvents(it: SharedSecureStorageViewEvent?) {
@ -131,17 +131,16 @@ class SharedSecureStorageActivity :
} }
} }
private fun showFragment(fragmentClass: KClass<out Fragment>, bundle: Bundle) { private fun showFragment(fragmentClass: KClass<out Fragment>) {
if (supportFragmentManager.findFragmentByTag(fragmentClass.simpleName) == null) { if (supportFragmentManager.findFragmentByTag(fragmentClass.simpleName) == null) {
supportFragmentManager.commitTransaction { replaceFragment(
replace(R.id.container, views.container,
fragmentClass.java, fragmentClass.java,
bundle, null,
fragmentClass.simpleName fragmentClass.simpleName
) )
} }
} }
}
companion object { companion object {
const val EXTRA_DATA_RESULT = "EXTRA_DATA_RESULT" const val EXTRA_DATA_RESULT = "EXTRA_DATA_RESULT"

View File

@ -91,7 +91,7 @@ class RoomDevToolActivity : SimpleFragmentActivity(), FragmentManager.OnBackStac
val classJava = RoomDevToolFragment::class.java val classJava = RoomDevToolFragment::class.java
val tag = classJava.name val tag = classJava.name
if (supportFragmentManager.findFragmentByTag(tag) == null) { if (supportFragmentManager.findFragmentByTag(tag) == null) {
replaceFragment(R.id.container, RoomDevToolFragment::class.java) replaceFragment(views.container, RoomDevToolFragment::class.java)
} else { } else {
supportFragmentManager.popBackStack() supportFragmentManager.popBackStack()
} }
@ -155,14 +155,14 @@ class RoomDevToolActivity : SimpleFragmentActivity(), FragmentManager.OnBackStac
if (supportFragmentManager.findFragmentByTag(tag) == null) { if (supportFragmentManager.findFragmentByTag(tag) == null) {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) .setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out)
.replace(R.id.container, fragment, tag) .replace(views.container.id, fragment, tag)
.addToBackStack(tag) .addToBackStack(tag)
.commit() .commit()
} else { } else {
if (!supportFragmentManager.popBackStackImmediate(tag, 0)) { if (!supportFragmentManager.popBackStackImmediate(tag, 0)) {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) .setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out)
.replace(R.id.container, fragment, tag) .replace(views.container.id, fragment, tag)
.addToBackStack(tag) .addToBackStack(tag)
.commit() .commit()
} }

View File

@ -28,6 +28,10 @@ class RoomDevToolRootController @Inject constructor(
var interactionListener: DevToolsInteractionListener? = null var interactionListener: DevToolsInteractionListener? = null
init {
requestModelBuild()
}
override fun buildModels() { override fun buildModels() {
val host = this val host = this
genericButtonItem { genericButtonItem {

View File

@ -24,6 +24,7 @@ import im.vector.app.R
import im.vector.app.core.epoxy.ClickListener import im.vector.app.core.epoxy.ClickListener
import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.onClick import im.vector.app.core.epoxy.onClick
import im.vector.app.core.extensions.setTextOrHide
@EpoxyModelClass(layout = R.layout.item_discovery_policy) @EpoxyModelClass(layout = R.layout.item_discovery_policy)
abstract class DiscoveryPolicyItem : EpoxyModelWithHolder<DiscoveryPolicyItem.Holder>() { abstract class DiscoveryPolicyItem : EpoxyModelWithHolder<DiscoveryPolicyItem.Holder>() {
@ -40,7 +41,7 @@ abstract class DiscoveryPolicyItem : EpoxyModelWithHolder<DiscoveryPolicyItem.Ho
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
holder.title.text = name holder.title.text = name
holder.url.text = url holder.url.setTextOrHide(url)
holder.view.onClick(clickListener) holder.view.onClick(clickListener)
} }

View File

@ -433,6 +433,6 @@ class DiscoverySettingsController @Inject constructor(
fun onTapUpdateUserConsent(newValue: Boolean) fun onTapUpdateUserConsent(newValue: Boolean)
fun onTapRetryToRetrieveBindings() fun onTapRetryToRetrieveBindings()
fun onPolicyUrlsExpandedStateToggled(newExpandedState: Boolean) fun onPolicyUrlsExpandedStateToggled(newExpandedState: Boolean)
fun onPolicyTapped(policy: IdentityServerPolicy) fun onPolicyTapped(policy: ServerPolicy)
} }
} }

View File

@ -167,10 +167,11 @@ class DiscoverySettingsFragment @Inject constructor(
val pidList = state.emailList().orEmpty() + state.phoneNumbersList().orEmpty() val pidList = state.emailList().orEmpty() + state.phoneNumbersList().orEmpty()
val hasBoundIds = pidList.any { it.isShared() == SharedState.SHARED } val hasBoundIds = pidList.any { it.isShared() == SharedState.SHARED }
val serverUrl = state.identityServer()?.serverUrl.orEmpty()
val message = if (hasBoundIds) { val message = if (hasBoundIds) {
getString(R.string.settings_discovery_disconnect_with_bound_pid, state.identityServer(), state.identityServer()) getString(R.string.settings_discovery_disconnect_with_bound_pid, serverUrl, serverUrl)
} else { } else {
getString(R.string.disconnect_identity_server_dialog_content, state.identityServer()) getString(R.string.disconnect_identity_server_dialog_content, serverUrl)
} }
MaterialAlertDialogBuilder(requireActivity()) MaterialAlertDialogBuilder(requireActivity())
@ -203,7 +204,7 @@ class DiscoverySettingsFragment @Inject constructor(
viewModel.handle(DiscoverySettingsAction.SetPoliciesExpandState(expanded = newExpandedState)) viewModel.handle(DiscoverySettingsAction.SetPoliciesExpandState(expanded = newExpandedState))
} }
override fun onPolicyTapped(policy: IdentityServerPolicy) { override fun onPolicyTapped(policy: ServerPolicy) {
openUrlInChromeCustomTab(requireContext(), null, policy.url) openUrlInChromeCustomTab(requireContext(), null, policy.url)
} }

View File

@ -21,7 +21,7 @@ import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
data class DiscoverySettingsState( data class DiscoverySettingsState(
val identityServer: Async<IdentityServerWithTerms?> = Uninitialized, val identityServer: Async<ServerAndPolicies?> = Uninitialized,
val emailList: Async<List<PidInfo>> = Uninitialized, val emailList: Async<List<PidInfo>> = Uninitialized,
val phoneNumbersList: Async<List<PidInfo>> = Uninitialized, val phoneNumbersList: Async<List<PidInfo>> = Uninitialized,
// Can be true if terms are updated // Can be true if terms are updated

View File

@ -78,7 +78,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
init { init {
setState { setState {
copy( copy(
identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { IdentityServerWithTerms(it, emptyList()) }), identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) }),
userConsent = identityService.getUserConsent() userConsent = identityService.getUserConsent()
) )
} }
@ -151,7 +151,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
val data = session.identityService().setNewIdentityServer(action.url) val data = session.identityService().setNewIdentityServer(action.url)
setState { setState {
copy( copy(
identityServer = Success(IdentityServerWithTerms(data, emptyList())), identityServer = Success(ServerAndPolicies(data, emptyList())),
userConsent = false userConsent = false
) )
} }
@ -401,7 +401,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
} }
} }
private suspend fun fetchIdentityServerWithTerms(): IdentityServerWithTerms? { private suspend fun fetchIdentityServerWithTerms(): ServerAndPolicies? {
return session.fetchIdentityServerWithTerms(stringProvider.getString(R.string.resources_language)) return session.fetchIdentityServerWithTerms(stringProvider.getString(R.string.resources_language))
} }
} }

View File

@ -19,22 +19,35 @@ package im.vector.app.features.discovery
import im.vector.app.core.utils.ensureProtocol import im.vector.app.core.utils.ensureProtocol
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.terms.TermsService import org.matrix.android.sdk.api.session.terms.TermsService
import org.matrix.android.sdk.internal.session.terms.TermsResponse
suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): IdentityServerWithTerms? { suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): ServerAndPolicies? {
val identityServerUrl = identityService().getCurrentIdentityServerUrl() return identityService().getCurrentIdentityServerUrl()
return identityServerUrl?.let { ?.let { identityServerUrl ->
val terms = getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol()) val termsResponse = getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol())
.serverResponse .serverResponse
.getLocalizedTerms(userLanguage) buildServerAndPolicies(identityServerUrl, termsResponse, userLanguage)
}
}
suspend fun Session.fetchHomeserverWithTerms(userLanguage: String): ServerAndPolicies {
val homeserverUrl = sessionParams.homeServerUrl
val terms = getHomeserverTerms(homeserverUrl.ensureProtocol())
return buildServerAndPolicies(homeserverUrl, terms, userLanguage)
}
private fun buildServerAndPolicies(serviceUrl: String,
termsResponse: TermsResponse,
userLanguage: String): ServerAndPolicies {
val terms = termsResponse.getLocalizedTerms(userLanguage)
val policyUrls = terms.mapNotNull { val policyUrls = terms.mapNotNull {
val name = it.localizedName ?: it.policyName val name = it.localizedName ?: it.policyName
val url = it.localizedUrl val url = it.localizedUrl
if (name == null || url == null) { if (name == null || url == null) {
null null
} else { } else {
IdentityServerPolicy(name = name, url = url) ServerPolicy(name = name, url = url)
} }
} }
IdentityServerWithTerms(identityServerUrl, policyUrls) return ServerAndPolicies(serviceUrl, policyUrls)
}
} }

View File

@ -16,12 +16,12 @@
package im.vector.app.features.discovery package im.vector.app.features.discovery
data class IdentityServerWithTerms( data class ServerAndPolicies(
val serverUrl: String, val serverUrl: String,
val policies: List<IdentityServerPolicy> val policies: List<ServerPolicy>
) )
data class IdentityServerPolicy( data class ServerPolicy(
val name: String, val name: String,
val url: String val url: String
) )

View File

@ -178,8 +178,8 @@ class HomeActivity :
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java) sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
views.drawerLayout.addDrawerListener(drawerListener) views.drawerLayout.addDrawerListener(drawerListener)
if (isFirstCreation()) { if (isFirstCreation()) {
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java) replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java)
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java) replaceFragment(views.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
} }
sharedActionViewModel sharedActionViewModel
@ -195,7 +195,7 @@ class HomeActivity :
// When switching from space to group or group to space, we need to reload the fragment // When switching from space to group or group to space, we need to reload the fragment
// To be removed when dropping legacy groups // To be removed when dropping legacy groups
if (sharedAction.clearFragment) { if (sharedAction.clearFragment) {
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true) replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
} else { } else {
// nop // nop
} }

View File

@ -29,7 +29,6 @@ import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.endKeepScreenOn import im.vector.app.core.extensions.endKeepScreenOn
import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.keepScreenOn import im.vector.app.core.extensions.keepScreenOn
@ -108,8 +107,8 @@ class RoomDetailActivity :
currentRoomId = roomDetailArgs.roomId currentRoomId = roomDetailArgs.roomId
if (isFirstCreation()) { if (isFirstCreation()) {
replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, roomDetailArgs) replaceFragment(views.roomDetailContainer, RoomDetailFragment::class.java, roomDetailArgs)
replaceFragment(R.id.roomDetailDrawerContainer, BreadcrumbsFragment::class.java) replaceFragment(views.roomDetailDrawerContainer, BreadcrumbsFragment::class.java)
} }
sharedActionViewModel = viewModelProvider.get(RoomDetailSharedActionViewModel::class.java) sharedActionViewModel = viewModelProvider.get(RoomDetailSharedActionViewModel::class.java)
@ -146,7 +145,7 @@ class RoomDetailActivity :
if (currentRoomId != switchToRoom.roomId) { if (currentRoomId != switchToRoom.roomId) {
currentRoomId = switchToRoom.roomId currentRoomId = switchToRoom.roomId
requireActiveMembershipViewModel.handle(RequireActiveMembershipAction.ChangeRoom(switchToRoom.roomId)) requireActiveMembershipViewModel.handle(RequireActiveMembershipAction.ChangeRoom(switchToRoom.roomId))
replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, RoomDetailArgs(switchToRoom.roomId)) replaceFragment(views.roomDetailContainer, RoomDetailFragment::class.java, RoomDetailArgs(switchToRoom.roomId))
} }
} }

View File

@ -22,7 +22,6 @@ import android.os.Bundle
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Mavericks
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySearchBinding import im.vector.app.databinding.ActivitySearchBinding
@ -47,7 +46,7 @@ class SearchActivity : VectorBaseActivity<ActivitySearchBinding>() {
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return val fragmentArgs: SearchArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return
addFragment(R.id.searchFragmentContainer, SearchFragment::class.java, fragmentArgs, FRAGMENT_TAG) addFragment(views.searchFragmentContainer, SearchFragment::class.java, fragmentArgs, FRAGMENT_TAG)
} }
views.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { views.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {

View File

@ -43,22 +43,12 @@ abstract class BaseEventItem<H : BaseEventItem.BaseHolder> : VectorEpoxyModel<H>
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
lateinit var dimensionConverter: DimensionConverter lateinit var dimensionConverter: DimensionConverter
protected var ignoreSendStatusVisibility = false
@CallSuper @CallSuper
override fun bind(holder: H) { override fun bind(holder: H) {
super.bind(holder) super.bind(holder)
holder.leftGuideline.updateLayoutParams<RelativeLayout.LayoutParams> { holder.leftGuideline.updateLayoutParams<RelativeLayout.LayoutParams> {
this.marginStart = leftGuideline this.marginStart = leftGuideline
} }
// Ignore visibility of the send status icon?
holder.contentContainer.updateLayoutParams<RelativeLayout.LayoutParams> {
if (ignoreSendStatusVisibility) {
addRule(RelativeLayout.ALIGN_PARENT_END)
} else {
removeRule(RelativeLayout.ALIGN_PARENT_END)
}
}
holder.checkableBackground.isChecked = highlighted holder.checkableBackground.isChecked = highlighted
} }

View File

@ -33,10 +33,6 @@ import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlayb
@EpoxyModelClass(layout = R.layout.item_timeline_event_base) @EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageVoiceItem : AbsMessageItem<MessageVoiceItem.Holder>() { abstract class MessageVoiceItem : AbsMessageItem<MessageVoiceItem.Holder>() {
init {
ignoreSendStatusVisibility = true
}
@EpoxyAttribute @EpoxyAttribute
var mxcUrl: String = "" var mxcUrl: String = ""

View File

@ -19,13 +19,14 @@ package im.vector.app.features.home.room.detail.timeline.url
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.google.android.material.card.MaterialCardView
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.databinding.ViewUrlPreviewBinding import im.vector.app.databinding.ViewUrlPreviewBinding
import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.media.ImageContentRenderer import im.vector.app.features.media.ImageContentRenderer
import im.vector.app.features.themes.ThemeUtils
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.media.PreviewUrlData import org.matrix.android.sdk.api.session.media.PreviewUrlData
@ -36,7 +37,7 @@ class PreviewUrlView @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = 0 defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener { ) : MaterialCardView(context, attrs, defStyleAttr), View.OnClickListener {
private lateinit var views: ViewUrlPreviewBinding private lateinit var views: ViewUrlPreviewBinding
@ -44,6 +45,9 @@ class PreviewUrlView @JvmOverloads constructor(
init { init {
setupView() setupView()
radius = resources.getDimensionPixelSize(R.dimen.preview_url_view_corner_radius).toFloat()
cardElevation = 0f
setCardBackgroundColor(ThemeUtils.getColor(context, R.attr.vctr_system))
} }
private var state: PreviewUrlUiState = PreviewUrlUiState.Unknown private var state: PreviewUrlUiState = PreviewUrlUiState.Unknown
@ -121,9 +125,15 @@ class PreviewUrlView @JvmOverloads constructor(
private fun renderData(previewUrlData: PreviewUrlData, imageContentRenderer: ImageContentRenderer) { private fun renderData(previewUrlData: PreviewUrlData, imageContentRenderer: ImageContentRenderer) {
isVisible = true isVisible = true
views.urlPreviewTitle.setTextOrHide(previewUrlData.title) views.urlPreviewTitle.setTextOrHide(previewUrlData.title)
views.urlPreviewImage.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, views.urlPreviewImage) }.orFalse() views.urlPreviewImage.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, views.urlPreviewImage) }.orFalse()
views.urlPreviewDescription.setTextOrHide(previewUrlData.description) views.urlPreviewDescription.setTextOrHide(previewUrlData.description)
views.urlPreviewDescription.maxLines = when {
previewUrlData.mxcUrl != null -> 2
previewUrlData.title != null -> 3
else -> 5
}
views.urlPreviewSite.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title }) views.urlPreviewSite.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title })
} }

View File

@ -21,7 +21,6 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivityFilteredRoomsBinding import im.vector.app.databinding.ActivityFilteredRoomsBinding
@ -46,7 +45,7 @@ class FilteredRoomsActivity : VectorBaseActivity<ActivityFilteredRoomsBinding>()
configureToolbar(views.filteredRoomsToolbar) configureToolbar(views.filteredRoomsToolbar)
if (isFirstCreation()) { if (isFirstCreation()) {
val params = RoomListParams(RoomListDisplayMode.FILTERED) val params = RoomListParams(RoomListDisplayMode.FILTERED)
replaceFragment(R.id.filteredRoomsFragmentContainer, RoomListFragment::class.java, params, FRAGMENT_TAG) replaceFragment(views.filteredRoomsFragmentContainer, RoomListFragment::class.java, params, FRAGMENT_TAG)
} }
views.filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { views.filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {

View File

@ -44,7 +44,6 @@ import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.databinding.FragmentRoomListBinding import im.vector.app.databinding.FragmentRoomListBinding
import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.RoomListDisplayMode
import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem
import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
@ -476,7 +475,7 @@ class RoomListFragment @Inject constructor(
footerController.setData(it) footerController.setData(it)
} }
RoomListQuickActionsBottomSheet RoomListQuickActionsBottomSheet
.newInstance(room.roomId, RoomListActionsArgs.Mode.FULL) .newInstance(room.roomId)
.show(childFragmentManager, "ROOM_LIST_QUICK_ACTIONS") .show(childFragmentManager, "ROOM_LIST_QUICK_ACTIONS")
return true return true
} }

View File

@ -43,15 +43,8 @@ import javax.inject.Inject
@Parcelize @Parcelize
data class RoomListActionsArgs( data class RoomListActionsArgs(
val roomId: String, val roomId: String
val mode: Mode ) : Parcelable
) : Parcelable {
enum class Mode {
FULL,
NOTIFICATIONS
}
}
/** /**
* Bottom sheet fragment that shows room information with list of contextual actions * Bottom sheet fragment that shows room information with list of contextual actions
@ -124,9 +117,9 @@ class RoomListQuickActionsBottomSheet :
} }
companion object { companion object {
fun newInstance(roomId: String, mode: RoomListActionsArgs.Mode): RoomListQuickActionsBottomSheet { fun newInstance(roomId: String): RoomListQuickActionsBottomSheet {
return RoomListQuickActionsBottomSheet().apply { return RoomListQuickActionsBottomSheet().apply {
setArguments(RoomListActionsArgs(roomId, mode)) setArguments(RoomListActionsArgs(roomId))
} }
} }
} }

View File

@ -24,7 +24,6 @@ import im.vector.app.core.epoxy.bottomsheet.bottomSheetRoomPreviewItem
import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem
import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.VectorFeatures
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.roomprofile.notifications.notificationOptions import im.vector.app.features.roomprofile.notifications.notificationOptions
import im.vector.app.features.roomprofile.notifications.notificationStateMapped import im.vector.app.features.roomprofile.notifications.notificationStateMapped
@ -39,7 +38,6 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val colorProvider: ColorProvider, private val colorProvider: ColorProvider,
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val features: VectorFeatures
) : TypedEpoxyController<RoomListQuickActionViewState>() { ) : TypedEpoxyController<RoomListQuickActionViewState>() {
var listener: Listener? = null var listener: Listener? = null
@ -48,11 +46,6 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
val notificationViewState = state.notificationSettingsViewState val notificationViewState = state.notificationSettingsViewState
val roomSummary = notificationViewState.roomSummary() ?: return val roomSummary = notificationViewState.roomSummary() ?: return
val host = this val host = this
val isV2 = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2
// V2 always shows full details as we no longer display the sheet from RoomProfile > Notifications
val showFull = state.roomListActionsArgs.mode == RoomListActionsArgs.Mode.FULL || isV2
if (showFull) {
// Preview, favorite, settings // Preview, favorite, settings
bottomSheetRoomPreviewItem { bottomSheetRoomPreviewItem {
id("room_preview") id("room_preview")
@ -71,9 +64,7 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
bottomSheetDividerItem { bottomSheetDividerItem {
id("notifications_separator") id("notifications_separator")
} }
}
if (isV2) {
notificationViewState.notificationOptions.forEach { notificationState -> notificationViewState.notificationOptions.forEach { notificationState ->
val title = titleForNotificationState(notificationState) val title = titleForNotificationState(notificationState)
radioButtonItem { radioButtonItem {
@ -85,17 +76,8 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
} }
} }
} }
} else {
val selectedRoomState = notificationViewState.notificationState()
RoomListQuickActionsSharedAction.NotificationsAllNoisy(roomSummary.roomId).toBottomSheetItem(0, selectedRoomState)
RoomListQuickActionsSharedAction.NotificationsAll(roomSummary.roomId).toBottomSheetItem(1, selectedRoomState)
RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState)
RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState)
}
if (showFull) { RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !true).toBottomSheetItem()
RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !isV2).toBottomSheetItem(5)
}
} }
@StringRes @StringRes
@ -106,18 +88,11 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
else -> null else -> null
} }
private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) { private fun RoomListQuickActionsSharedAction.Leave.toBottomSheetItem() {
val host = this@RoomListQuickActionsEpoxyController val host = this@RoomListQuickActionsEpoxyController
val selected = when (this) {
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> roomNotificationState == RoomNotificationState.ALL_MESSAGES_NOISY
is RoomListQuickActionsSharedAction.NotificationsAll -> roomNotificationState == RoomNotificationState.ALL_MESSAGES
is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> roomNotificationState == RoomNotificationState.MENTIONS_ONLY
is RoomListQuickActionsSharedAction.NotificationsMute -> roomNotificationState == RoomNotificationState.MUTE
else -> false
}
return bottomSheetActionItem { return bottomSheetActionItem {
id("action_$index") id("action_leave")
selected(selected) selected(false)
if (iconResId != null) { if (iconResId != null) {
iconRes(iconResId) iconRes(iconResId)
} else { } else {

View File

@ -81,7 +81,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() {
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment( addFragment(
R.id.container, views.container,
UserListFragment::class.java, UserListFragment::class.java,
UserListFragmentArgs( UserListFragmentArgs(
title = getString(R.string.invite_users_to_room_title), title = getString(R.string.invite_users_to_room_title),
@ -104,13 +104,13 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() {
private fun openPhoneBook() { private fun openPhoneBook() {
// Check permission first // Check permission first
if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, this, permissionContactLauncher)) { if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, this, permissionContactLauncher)) {
addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) addFragmentToBackstack(views.container, ContactsBookFragment::class.java)
} }
} }
private val permissionContactLauncher = registerForPermissionsResult { allGranted, deniedPermanently -> private val permissionContactLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->
if (allGranted) { if (allGranted) {
doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } doOnPostResume { addFragmentToBackstack(views.container, ContactsBookFragment::class.java) }
} else if (deniedPermanently) { } else if (deniedPermanently) {
onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact) onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact)
} }

View File

@ -64,7 +64,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
private val popExitAnim = R.anim.exit_fade_out private val popExitAnim = R.anim.exit_fade_out
private val topFragment: Fragment? private val topFragment: Fragment?
get() = supportFragmentManager.findFragmentById(R.id.loginFragmentContainer) get() = supportFragmentManager.findFragmentById(views.loginFragmentContainer.id)
private val commonOption: (FragmentTransaction) -> Unit = { ft -> private val commonOption: (FragmentTransaction) -> Unit = { ft ->
// Find the loginLogo on the current Fragment, this should not return null // Find the loginLogo on the current Fragment, this should not return null
@ -100,7 +100,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
} }
protected open fun addFirstFragment() { protected open fun addFirstFragment() {
addFragment(R.id.loginFragmentContainer, LoginSplashFragment::class.java) addFragment(views.loginFragmentContainer, LoginSplashFragment::class.java)
} }
private fun handleLoginViewEvents(loginViewEvents: LoginViewEvents) { private fun handleLoginViewEvents(loginViewEvents: LoginViewEvents) {
@ -118,7 +118,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
// First ask for login and password // First ask for login and password
// I add a tag to indicate that this fragment is a registration stage. // I add a tag to indicate that this fragment is a registration stage.
// This way it will be automatically popped in when starting the next registration stage // This way it will be automatically popped in when starting the next registration stage
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginFragment::class.java, LoginFragment::class.java,
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption option = commonOption
@ -135,7 +135,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
Unit Unit
} }
is LoginViewEvents.OpenServerSelection -> is LoginViewEvents.OpenServerSelection ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginServerSelectionFragment::class.java, LoginServerSelectionFragment::class.java,
option = { ft -> option = { ft ->
findViewById<View?>(R.id.loginSplashLogo)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") } findViewById<View?>(R.id.loginSplashLogo)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") }
@ -149,23 +149,23 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
is LoginViewEvents.OnServerSelectionDone -> onServerSelectionDone(loginViewEvents) is LoginViewEvents.OnServerSelectionDone -> onServerSelectionDone(loginViewEvents)
is LoginViewEvents.OnSignModeSelected -> onSignModeSelected(loginViewEvents) is LoginViewEvents.OnSignModeSelected -> onSignModeSelected(loginViewEvents)
is LoginViewEvents.OnLoginFlowRetrieved -> is LoginViewEvents.OnLoginFlowRetrieved ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginSignUpSignInSelectionFragment::class.java, LoginSignUpSignInSelectionFragment::class.java,
option = commonOption) option = commonOption)
is LoginViewEvents.OnWebLoginError -> onWebLoginError(loginViewEvents) is LoginViewEvents.OnWebLoginError -> onWebLoginError(loginViewEvents)
is LoginViewEvents.OnForgetPasswordClicked -> is LoginViewEvents.OnForgetPasswordClicked ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginResetPasswordFragment::class.java, LoginResetPasswordFragment::class.java,
option = commonOption) option = commonOption)
is LoginViewEvents.OnResetPasswordSendThreePidDone -> { is LoginViewEvents.OnResetPasswordSendThreePidDone -> {
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginResetPasswordMailConfirmationFragment::class.java, LoginResetPasswordMailConfirmationFragment::class.java,
option = commonOption) option = commonOption)
} }
is LoginViewEvents.OnResetPasswordMailConfirmationSuccess -> { is LoginViewEvents.OnResetPasswordMailConfirmationSuccess -> {
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginResetPasswordSuccessFragment::class.java, LoginResetPasswordSuccessFragment::class.java,
option = commonOption) option = commonOption)
} }
@ -176,7 +176,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
is LoginViewEvents.OnSendEmailSuccess -> { is LoginViewEvents.OnSendEmailSuccess -> {
// Pop the enter email Fragment // Pop the enter email Fragment
supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE)
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginWaitForEmailFragment::class.java, LoginWaitForEmailFragment::class.java,
LoginWaitForEmailFragmentArgument(loginViewEvents.email), LoginWaitForEmailFragmentArgument(loginViewEvents.email),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
@ -185,7 +185,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
is LoginViewEvents.OnSendMsisdnSuccess -> { is LoginViewEvents.OnSendMsisdnSuccess -> {
// Pop the enter Msisdn Fragment // Pop the enter Msisdn Fragment
supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE)
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginGenericTextInputFormFragment::class.java, LoginGenericTextInputFormFragment::class.java,
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.ConfirmMsisdn, true, loginViewEvents.msisdn), LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.ConfirmMsisdn, true, loginViewEvents.msisdn),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
@ -229,7 +229,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
when (loginViewEvents.serverType) { when (loginViewEvents.serverType) {
ServerType.MatrixOrg -> Unit // In this case, we wait for the login flow ServerType.MatrixOrg -> Unit // In this case, we wait for the login flow
ServerType.EMS, ServerType.EMS,
ServerType.Other -> addFragmentToBackstack(R.id.loginFragmentContainer, ServerType.Other -> addFragmentToBackstack(views.loginFragmentContainer,
LoginServerUrlFormFragment::class.java, LoginServerUrlFormFragment::class.java,
option = commonOption) option = commonOption)
ServerType.Unknown -> Unit /* Should not happen */ ServerType.Unknown -> Unit /* Should not happen */
@ -249,14 +249,14 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
LoginMode.Unknown, LoginMode.Unknown,
is LoginMode.Sso -> error("Developer error") is LoginMode.Sso -> error("Developer error")
is LoginMode.SsoAndPassword, is LoginMode.SsoAndPassword,
LoginMode.Password -> addFragmentToBackstack(R.id.loginFragmentContainer, LoginMode.Password -> addFragmentToBackstack(views.loginFragmentContainer,
LoginFragment::class.java, LoginFragment::class.java,
tag = FRAGMENT_LOGIN_TAG, tag = FRAGMENT_LOGIN_TAG,
option = commonOption) option = commonOption)
LoginMode.Unsupported -> onLoginModeNotSupported(state.loginModeSupportedTypes) LoginMode.Unsupported -> onLoginModeNotSupported(state.loginModeSupportedTypes)
}.exhaustive }.exhaustive
} }
SignMode.SignInWithMatrixId -> addFragmentToBackstack(R.id.loginFragmentContainer, SignMode.SignInWithMatrixId -> addFragmentToBackstack(views.loginFragmentContainer,
LoginFragment::class.java, LoginFragment::class.java,
tag = FRAGMENT_LOGIN_TAG, tag = FRAGMENT_LOGIN_TAG,
option = commonOption) option = commonOption)
@ -279,7 +279,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
.setTitle(R.string.app_name) .setTitle(R.string.app_name)
.setMessage(getString(R.string.login_registration_not_supported)) .setMessage(getString(R.string.login_registration_not_supported))
.setPositiveButton(R.string.yes) { _, _ -> .setPositiveButton(R.string.yes) { _, _ ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginWebFragment::class.java, LoginWebFragment::class.java,
option = commonOption) option = commonOption)
} }
@ -292,7 +292,7 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
.setTitle(R.string.app_name) .setTitle(R.string.app_name)
.setMessage(getString(R.string.login_mode_not_supported, supportedTypes.joinToString { "'$it'" })) .setMessage(getString(R.string.login_mode_not_supported, supportedTypes.joinToString { "'$it'" }))
.setPositiveButton(R.string.yes) { _, _ -> .setPositiveButton(R.string.yes) { _, _ ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginWebFragment::class.java, LoginWebFragment::class.java,
option = commonOption) option = commonOption)
} }
@ -322,22 +322,22 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE)
when (stage) { when (stage) {
is Stage.ReCaptcha -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.ReCaptcha -> addFragmentToBackstack(views.loginFragmentContainer,
LoginCaptchaFragment::class.java, LoginCaptchaFragment::class.java,
LoginCaptchaFragmentArgument(stage.publicKey), LoginCaptchaFragmentArgument(stage.publicKey),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
is Stage.Email -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.Email -> addFragmentToBackstack(views.loginFragmentContainer,
LoginGenericTextInputFormFragment::class.java, LoginGenericTextInputFormFragment::class.java,
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetEmail, stage.mandatory), LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetEmail, stage.mandatory),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
is Stage.Msisdn -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.Msisdn -> addFragmentToBackstack(views.loginFragmentContainer,
LoginGenericTextInputFormFragment::class.java, LoginGenericTextInputFormFragment::class.java,
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetMsisdn, stage.mandatory), LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetMsisdn, stage.mandatory),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
is Stage.Terms -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.Terms -> addFragmentToBackstack(views.loginFragmentContainer,
LoginTermsFragment::class.java, LoginTermsFragment::class.java,
LoginTermsFragmentArgument(stage.policies.toLocalizedLoginTerms(getString(R.string.resources_language))), LoginTermsFragmentArgument(stage.policies.toLocalizedLoginTerms(getString(R.string.resources_language))),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,

View File

@ -71,7 +71,7 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
private val popExitAnim = R.anim.exit_fade_out private val popExitAnim = R.anim.exit_fade_out
private val topFragment: Fragment? private val topFragment: Fragment?
get() = supportFragmentManager.findFragmentById(R.id.loginFragmentContainer) get() = supportFragmentManager.findFragmentById(views.loginFragmentContainer.id)
private val commonOption: (FragmentTransaction) -> Unit = { ft -> private val commonOption: (FragmentTransaction) -> Unit = { ft ->
// Find the loginLogo on the current Fragment, this should not return null // Find the loginLogo on the current Fragment, this should not return null
@ -108,7 +108,7 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
} }
protected open fun addFirstFragment() { protected open fun addFirstFragment() {
addFragment(R.id.loginFragmentContainer, LoginSplashSignUpSignInSelectionFragment2::class.java) addFragment(views.loginFragmentContainer, LoginSplashSignUpSignInSelectionFragment2::class.java)
} }
private fun handleLoginViewEvents(event: LoginViewEvents2) { private fun handleLoginViewEvents(event: LoginViewEvents2) {
@ -127,7 +127,7 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
// First ask for login and password // First ask for login and password
// I add a tag to indicate that this fragment is a registration stage. // I add a tag to indicate that this fragment is a registration stage.
// This way it will be automatically popped in when starting the next registration stage // This way it will be automatically popped in when starting the next registration stage
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginFragment2::class.java, LoginFragment2::class.java,
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption option = commonOption
@ -146,7 +146,7 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
Unit Unit
} }
is LoginViewEvents2.OpenServerSelection -> is LoginViewEvents2.OpenServerSelection ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginServerSelectionFragment2::class.java, LoginServerSelectionFragment2::class.java,
option = { ft -> option = { ft ->
findViewById<View?>(R.id.loginSplashLogo)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") } findViewById<View?>(R.id.loginSplashLogo)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") }
@ -158,12 +158,12 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
// ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim) // ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim)
}) })
is LoginViewEvents2.OpenHomeServerUrlFormScreen -> { is LoginViewEvents2.OpenHomeServerUrlFormScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginServerUrlFormFragment2::class.java, LoginServerUrlFormFragment2::class.java,
option = commonOption) option = commonOption)
} }
is LoginViewEvents2.OpenSignInEnterIdentifierScreen -> { is LoginViewEvents2.OpenSignInEnterIdentifierScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginFragmentSigninUsername2::class.java, LoginFragmentSigninUsername2::class.java,
option = { ft -> option = { ft ->
findViewById<View?>(R.id.loginSplashLogo)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") } findViewById<View?>(R.id.loginSplashLogo)?.let { ft.addSharedElement(it, ViewCompat.getTransitionName(it) ?: "") }
@ -176,24 +176,24 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
}) })
} }
is LoginViewEvents2.OpenSsoOnlyScreen -> { is LoginViewEvents2.OpenSsoOnlyScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginSsoOnlyFragment2::class.java, LoginSsoOnlyFragment2::class.java,
option = commonOption) option = commonOption)
} }
is LoginViewEvents2.OnWebLoginError -> onWebLoginError(event) is LoginViewEvents2.OnWebLoginError -> onWebLoginError(event)
is LoginViewEvents2.OpenResetPasswordScreen -> is LoginViewEvents2.OpenResetPasswordScreen ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginResetPasswordFragment2::class.java, LoginResetPasswordFragment2::class.java,
option = commonOption) option = commonOption)
is LoginViewEvents2.OnResetPasswordSendThreePidDone -> { is LoginViewEvents2.OnResetPasswordSendThreePidDone -> {
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginResetPasswordMailConfirmationFragment2::class.java, LoginResetPasswordMailConfirmationFragment2::class.java,
option = commonOption) option = commonOption)
} }
is LoginViewEvents2.OnResetPasswordMailConfirmationSuccess -> { is LoginViewEvents2.OnResetPasswordMailConfirmationSuccess -> {
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginResetPasswordSuccessFragment2::class.java, LoginResetPasswordSuccessFragment2::class.java,
option = commonOption) option = commonOption)
} }
@ -202,37 +202,37 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
} }
is LoginViewEvents2.OnSendEmailSuccess -> is LoginViewEvents2.OnSendEmailSuccess ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginWaitForEmailFragment2::class.java, LoginWaitForEmailFragment2::class.java,
LoginWaitForEmailFragmentArgument(event.email), LoginWaitForEmailFragmentArgument(event.email),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
is LoginViewEvents2.OpenSigninPasswordScreen -> { is LoginViewEvents2.OpenSigninPasswordScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginFragmentSigninPassword2::class.java, LoginFragmentSigninPassword2::class.java,
tag = FRAGMENT_LOGIN_TAG, tag = FRAGMENT_LOGIN_TAG,
option = commonOption) option = commonOption)
} }
is LoginViewEvents2.OpenSignupPasswordScreen -> { is LoginViewEvents2.OpenSignupPasswordScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginFragmentSignupPassword2::class.java, LoginFragmentSignupPassword2::class.java,
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
} }
is LoginViewEvents2.OpenSignUpChooseUsernameScreen -> { is LoginViewEvents2.OpenSignUpChooseUsernameScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginFragmentSignupUsername2::class.java, LoginFragmentSignupUsername2::class.java,
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
} }
is LoginViewEvents2.OpenSignInWithAnythingScreen -> { is LoginViewEvents2.OpenSignInWithAnythingScreen -> {
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginFragmentToAny2::class.java, LoginFragmentToAny2::class.java,
tag = FRAGMENT_LOGIN_TAG, tag = FRAGMENT_LOGIN_TAG,
option = commonOption) option = commonOption)
} }
is LoginViewEvents2.OnSendMsisdnSuccess -> is LoginViewEvents2.OnSendMsisdnSuccess ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginGenericTextInputFormFragment2::class.java, LoginGenericTextInputFormFragment2::class.java,
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.ConfirmMsisdn, true, event.msisdn), LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.ConfirmMsisdn, true, event.msisdn),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
@ -257,7 +257,7 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
if (event.newAccount) { if (event.newAccount) {
// Propose to set avatar and display name // Propose to set avatar and display name
// Back on this Fragment will finish the Activity // Back on this Fragment will finish the Activity
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
AccountCreatedFragment::class.java, AccountCreatedFragment::class.java,
option = commonOption) option = commonOption)
} else { } else {
@ -312,7 +312,7 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
.setTitle(R.string.app_name) .setTitle(R.string.app_name)
.setMessage(getString(R.string.login_registration_not_supported)) .setMessage(getString(R.string.login_registration_not_supported))
.setPositiveButton(R.string.yes) { _, _ -> .setPositiveButton(R.string.yes) { _, _ ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginWebFragment2::class.java, LoginWebFragment2::class.java,
option = commonOption) option = commonOption)
} }
@ -325,7 +325,7 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
.setTitle(R.string.app_name) .setTitle(R.string.app_name)
.setMessage(getString(R.string.login_mode_not_supported, supportedTypes.joinToString { "'$it'" })) .setMessage(getString(R.string.login_mode_not_supported, supportedTypes.joinToString { "'$it'" }))
.setPositiveButton(R.string.yes) { _, _ -> .setPositiveButton(R.string.yes) { _, _ ->
addFragmentToBackstack(R.id.loginFragmentContainer, addFragmentToBackstack(views.loginFragmentContainer,
LoginWebFragment2::class.java, LoginWebFragment2::class.java,
option = commonOption) option = commonOption)
} }
@ -355,22 +355,22 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE) supportFragmentManager.popBackStack(FRAGMENT_REGISTRATION_STAGE_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE)
when (stage) { when (stage) {
is Stage.ReCaptcha -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.ReCaptcha -> addFragmentToBackstack(views.loginFragmentContainer,
LoginCaptchaFragment2::class.java, LoginCaptchaFragment2::class.java,
LoginCaptchaFragmentArgument(stage.publicKey), LoginCaptchaFragmentArgument(stage.publicKey),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
is Stage.Email -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.Email -> addFragmentToBackstack(views.loginFragmentContainer,
LoginGenericTextInputFormFragment2::class.java, LoginGenericTextInputFormFragment2::class.java,
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetEmail, stage.mandatory), LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetEmail, stage.mandatory),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
is Stage.Msisdn -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.Msisdn -> addFragmentToBackstack(views.loginFragmentContainer,
LoginGenericTextInputFormFragment2::class.java, LoginGenericTextInputFormFragment2::class.java,
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetMsisdn, stage.mandatory), LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetMsisdn, stage.mandatory),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,
option = commonOption) option = commonOption)
is Stage.Terms -> addFragmentToBackstack(R.id.loginFragmentContainer, is Stage.Terms -> addFragmentToBackstack(views.loginFragmentContainer,
LoginTermsFragment2::class.java, LoginTermsFragment2::class.java,
LoginTermsFragmentArgument(stage.policies.toLocalizedLoginTerms(getString(R.string.resources_language))), LoginTermsFragmentArgument(stage.policies.toLocalizedLoginTerms(getString(R.string.resources_language))),
tag = FRAGMENT_REGISTRATION_STAGE_TAG, tag = FRAGMENT_REGISTRATION_STAGE_TAG,

View File

@ -21,7 +21,6 @@ import android.content.Intent
import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Mavericks
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
@ -45,7 +44,7 @@ class PinActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigur
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
val fragmentArgs: PinArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return val fragmentArgs: PinArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return
addFragment(R.id.simpleFragmentContainer, PinFragment::class.java, fragmentArgs) addFragment(views.simpleFragmentContainer, PinFragment::class.java, fragmentArgs)
} }
} }

View File

@ -21,7 +21,6 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.core.platform.SimpleFragmentActivity
@ -36,7 +35,7 @@ class CreatePollActivity : SimpleFragmentActivity() {
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment( addFragment(
R.id.container, views.container,
CreatePollFragment::class.java, CreatePollFragment::class.java,
createPollArgs createPollArgs
) )

View File

@ -104,7 +104,7 @@ class PopupAlertManager @Inject constructor() {
// we want to remove existing popup on previous activity and display it on new one // we want to remove existing popup on previous activity and display it on new one
if (currentAlerter != null) { if (currentAlerter != null) {
weakCurrentActivity?.get()?.let { weakCurrentActivity?.get()?.let {
Alerter.clearCurrent(it, null) Alerter.clearCurrent(it, null, null)
if (currentAlerter?.isLight == false) { if (currentAlerter?.isLight == false) {
setLightStatusBar() setLightStatusBar()
} }

View File

@ -24,7 +24,6 @@ import com.google.zxing.BarcodeFormat
import com.google.zxing.Result import com.google.zxing.Result
import com.google.zxing.ResultMetadataType import com.google.zxing.ResultMetadataType
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.databinding.ActivitySimpleBinding
@ -39,7 +38,7 @@ class QrCodeScannerActivity : VectorBaseActivity<ActivitySimpleBinding>() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (isFirstCreation()) { if (isFirstCreation()) {
replaceFragment(R.id.simpleFragmentContainer, QrCodeScannerFragment::class.java) replaceFragment(views.simpleFragmentContainer, QrCodeScannerFragment::class.java)
} }
} }

View File

@ -23,7 +23,6 @@ import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.extensions.popBackstack import im.vector.app.core.extensions.popBackstack
@ -66,14 +65,14 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>(), Matri
// Transmit the filter to the CreateRoomFragment // Transmit the filter to the CreateRoomFragment
withState(roomDirectoryViewModel) { withState(roomDirectoryViewModel) {
addFragmentToBackstack( addFragmentToBackstack(
R.id.simpleFragmentContainer, views.simpleFragmentContainer,
CreateRoomFragment::class.java, CreateRoomFragment::class.java,
CreateRoomArgs(it.currentFilter) CreateRoomArgs(it.currentFilter)
) )
} }
} }
is RoomDirectorySharedAction.ChangeProtocol -> is RoomDirectorySharedAction.ChangeProtocol ->
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomDirectoryPickerFragment::class.java) addFragmentToBackstack(views.simpleFragmentContainer, RoomDirectoryPickerFragment::class.java)
is RoomDirectorySharedAction.Close -> finish() is RoomDirectorySharedAction.Close -> finish()
} }
} }
@ -82,7 +81,7 @@ class RoomDirectoryActivity : VectorBaseActivity<ActivitySimpleBinding>(), Matri
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment(R.id.simpleFragmentContainer, PublicRoomsFragment::class.java) addFragment(views.simpleFragmentContainer, PublicRoomsFragment::class.java)
} }
} }

View File

@ -22,7 +22,6 @@ import android.os.Bundle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
@ -51,7 +50,7 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment( addFragment(
R.id.simpleFragmentContainer, views.simpleFragmentContainer,
CreateRoomFragment::class.java, CreateRoomFragment::class.java,
CreateRoomArgs( CreateRoomArgs(
intent?.getStringExtra(INITIAL_NAME) ?: "", intent?.getStringExtra(INITIAL_NAME) ?: "",

View File

@ -21,7 +21,6 @@ import android.content.Intent
import android.os.Parcelable import android.os.Parcelable
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
@ -94,9 +93,9 @@ class RoomPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), Toolbar
// TODO Room preview: Note: M does not recommend to use /events anymore, so for now we just display the room preview // TODO Room preview: Note: M does not recommend to use /events anymore, so for now we just display the room preview
// TODO the same way if it was not world readable // TODO the same way if it was not world readable
Timber.d("just display the room preview the same way if it was not world readable") Timber.d("just display the room preview the same way if it was not world readable")
addFragment(R.id.simpleFragmentContainer, RoomPreviewNoPreviewFragment::class.java, args) addFragment(views.simpleFragmentContainer, RoomPreviewNoPreviewFragment::class.java, args)
} else { } else {
addFragment(R.id.simpleFragmentContainer, RoomPreviewNoPreviewFragment::class.java, args) addFragment(views.simpleFragmentContainer, RoomPreviewNoPreviewFragment::class.java, args)
} }
} }
} }

View File

@ -24,7 +24,6 @@ import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
@ -54,7 +53,7 @@ class RoomMemberProfileActivity :
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
val fragmentArgs: RoomMemberProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return val fragmentArgs: RoomMemberProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return
addFragment(R.id.simpleFragmentContainer, RoomMemberProfileFragment::class.java, fragmentArgs) addFragment(views.simpleFragmentContainer, RoomMemberProfileFragment::class.java, fragmentArgs)
} }
requireActiveMembershipViewModel.observeViewEvents { requireActiveMembershipViewModel.observeViewEvents {

View File

@ -25,7 +25,6 @@ import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
@ -86,13 +85,13 @@ class RoomProfileActivity :
if (isFirstCreation()) { if (isFirstCreation()) {
when (intent?.extras?.getInt(EXTRA_DIRECT_ACCESS, EXTRA_DIRECT_ACCESS_ROOM_ROOT)) { when (intent?.extras?.getInt(EXTRA_DIRECT_ACCESS, EXTRA_DIRECT_ACCESS_ROOM_ROOT)) {
EXTRA_DIRECT_ACCESS_ROOM_SETTINGS -> { EXTRA_DIRECT_ACCESS_ROOM_SETTINGS -> {
addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs) addFragment(views.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomSettingsFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomSettingsFragment::class.java, roomProfileArgs)
} }
EXTRA_DIRECT_ACCESS_ROOM_MEMBERS -> { EXTRA_DIRECT_ACCESS_ROOM_MEMBERS -> {
addFragment(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs) addFragment(views.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs)
} }
else -> addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs) else -> addFragment(views.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
} }
} }
sharedActionViewModel sharedActionViewModel
@ -132,31 +131,31 @@ class RoomProfileActivity :
} }
private fun openRoomUploads() { private fun openRoomUploads() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomUploadsFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomUploadsFragment::class.java, roomProfileArgs)
} }
private fun openRoomSettings() { private fun openRoomSettings() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomSettingsFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomSettingsFragment::class.java, roomProfileArgs)
} }
private fun openRoomAlias() { private fun openRoomAlias() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomAliasFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomAliasFragment::class.java, roomProfileArgs)
} }
private fun openRoomPermissions() { private fun openRoomPermissions() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomPermissionsFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomPermissionsFragment::class.java, roomProfileArgs)
} }
private fun openRoomMembers() { private fun openRoomMembers() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs)
} }
private fun openBannedRoomMembers() { private fun openBannedRoomMembers() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomBannedMemberListFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomBannedMemberListFragment::class.java, roomProfileArgs)
} }
private fun openRoomNotificationSettings() { private fun openRoomNotificationSettings() {
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomNotificationSettingsFragment::class.java, roomProfileArgs) addFragmentToBackstack(views.simpleFragmentContainer, RoomNotificationSettingsFragment::class.java, roomProfileArgs)
} }
override fun configure(toolbar: MaterialToolbar) { override fun configure(toolbar: MaterialToolbar) {

View File

@ -44,13 +44,10 @@ import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.FragmentMatrixProfileBinding
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding
import im.vector.app.features.VectorFeatures
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.RoomDetailPendingAction import im.vector.app.features.home.room.detail.RoomDetailPendingAction
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet
import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -69,8 +66,7 @@ data class RoomProfileArgs(
class RoomProfileFragment @Inject constructor( class RoomProfileFragment @Inject constructor(
private val roomProfileController: RoomProfileController, private val roomProfileController: RoomProfileController,
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val roomDetailPendingActionStore: RoomDetailPendingActionStore, private val roomDetailPendingActionStore: RoomDetailPendingActionStore
private val features: VectorFeatures
) : ) :
VectorBaseFragment<FragmentMatrixProfileBinding>(), VectorBaseFragment<FragmentMatrixProfileBinding>(),
RoomProfileController.Callback { RoomProfileController.Callback {
@ -259,17 +255,8 @@ class RoomProfileFragment @Inject constructor(
} }
override fun onNotificationsClicked() { override fun onNotificationsClicked() {
when (features.notificationSettingsVersion()) {
VectorFeatures.NotificationSettingsVersion.V1 -> {
RoomListQuickActionsBottomSheet
.newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS)
.show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS")
}
VectorFeatures.NotificationSettingsVersion.V2 -> {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings) roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings)
} }
}
}
override fun onUploadsClicked() { override fun onUploadsClicked() {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomUploads) roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomUploads)

View File

@ -61,7 +61,7 @@ class RoomJoinRuleActivity : VectorBaseActivity<ActivitySimpleBinding>() {
roomProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return roomProfileArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment( addFragment(
R.id.simpleFragmentContainer, views.simpleFragmentContainer,
RoomJoinRuleFragment::class.java, RoomJoinRuleFragment::class.java,
roomProfileArgs roomProfileArgs
) )
@ -121,7 +121,7 @@ class RoomJoinRuleActivity : VectorBaseActivity<ActivitySimpleBinding>() {
supportFragmentManager.commitTransaction { supportFragmentManager.commitTransaction {
setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out)
val tag = RoomJoinRuleChooseRestrictedFragment::class.simpleName val tag = RoomJoinRuleChooseRestrictedFragment::class.simpleName
replace(R.id.simpleFragmentContainer, replace(views.simpleFragmentContainer.id,
RoomJoinRuleChooseRestrictedFragment::class.java, RoomJoinRuleChooseRestrictedFragment::class.java,
this@RoomJoinRuleActivity.roomProfileArgs.toMvRxBundle(), this@RoomJoinRuleActivity.roomProfileArgs.toMvRxBundle(),
tag tag

View File

@ -35,6 +35,7 @@ import javax.inject.Inject
class VectorPreferences @Inject constructor(private val context: Context) { class VectorPreferences @Inject constructor(private val context: Context) {
companion object { companion object {
const val SETTINGS_HELP_PREFERENCE_KEY = "SETTINGS_HELP_PREFERENCE_KEY"
const val SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY = "SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY" const val SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY = "SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY"
const val SETTINGS_VERSION_PREFERENCE_KEY = "SETTINGS_VERSION_PREFERENCE_KEY" const val SETTINGS_VERSION_PREFERENCE_KEY = "SETTINGS_VERSION_PREFERENCE_KEY"
const val SETTINGS_SDK_VERSION_PREFERENCE_KEY = "SETTINGS_SDK_VERSION_PREFERENCE_KEY" const val SETTINGS_SDK_VERSION_PREFERENCE_KEY = "SETTINGS_SDK_VERSION_PREFERENCE_KEY"
@ -42,17 +43,8 @@ class VectorPreferences @Inject constructor(private val context: Context) {
const val SETTINGS_LOGGED_IN_PREFERENCE_KEY = "SETTINGS_LOGGED_IN_PREFERENCE_KEY" const val SETTINGS_LOGGED_IN_PREFERENCE_KEY = "SETTINGS_LOGGED_IN_PREFERENCE_KEY"
const val SETTINGS_HOME_SERVER_PREFERENCE_KEY = "SETTINGS_HOME_SERVER_PREFERENCE_KEY" const val SETTINGS_HOME_SERVER_PREFERENCE_KEY = "SETTINGS_HOME_SERVER_PREFERENCE_KEY"
const val SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY = "SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY" const val SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY = "SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY"
const val SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY = "SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY"
const val SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY = "SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY"
const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY" const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY"
const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
const val SETTINGS_COPYRIGHT_PREFERENCE_KEY = "SETTINGS_COPYRIGHT_PREFERENCE_KEY"
const val SETTINGS_CLEAR_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_CACHE_PREFERENCE_KEY" const val SETTINGS_CLEAR_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_CACHE_PREFERENCE_KEY"
const val SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY" const val SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY"
const val SETTINGS_USER_SETTINGS_PREFERENCE_KEY = "SETTINGS_USER_SETTINGS_PREFERENCE_KEY" const val SETTINGS_USER_SETTINGS_PREFERENCE_KEY = "SETTINGS_USER_SETTINGS_PREFERENCE_KEY"

View File

@ -70,25 +70,25 @@ class VectorSettingsActivity : VectorBaseActivity<ActivityVectorSettingsBinding>
when (val payload = readPayload<SettingsActivityPayload>(SettingsActivityPayload.Root)) { when (val payload = readPayload<SettingsActivityPayload>(SettingsActivityPayload.Root)) {
SettingsActivityPayload.General -> SettingsActivityPayload.General ->
replaceFragment(R.id.vector_settings_page, VectorSettingsGeneralFragment::class.java, null, FRAGMENT_TAG) replaceFragment(views.vectorSettingsPage, VectorSettingsGeneralFragment::class.java, null, FRAGMENT_TAG)
SettingsActivityPayload.AdvancedSettings -> SettingsActivityPayload.AdvancedSettings ->
replaceFragment(R.id.vector_settings_page, VectorSettingsAdvancedSettingsFragment::class.java, null, FRAGMENT_TAG) replaceFragment(views.vectorSettingsPage, VectorSettingsAdvancedSettingsFragment::class.java, null, FRAGMENT_TAG)
SettingsActivityPayload.SecurityPrivacy -> SettingsActivityPayload.SecurityPrivacy ->
replaceFragment(R.id.vector_settings_page, VectorSettingsSecurityPrivacyFragment::class.java, null, FRAGMENT_TAG) replaceFragment(views.vectorSettingsPage, VectorSettingsSecurityPrivacyFragment::class.java, null, FRAGMENT_TAG)
SettingsActivityPayload.SecurityPrivacyManageSessions -> SettingsActivityPayload.SecurityPrivacyManageSessions ->
replaceFragment(R.id.vector_settings_page, replaceFragment(views.vectorSettingsPage,
VectorSettingsDevicesFragment::class.java, VectorSettingsDevicesFragment::class.java,
null, null,
FRAGMENT_TAG) FRAGMENT_TAG)
SettingsActivityPayload.Notifications -> { SettingsActivityPayload.Notifications -> {
requestHighlightPreferenceKeyOnResume(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY) requestHighlightPreferenceKeyOnResume(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)
replaceFragment(R.id.vector_settings_page, VectorSettingsNotificationPreferenceFragment::class.java, null, FRAGMENT_TAG) replaceFragment(views.vectorSettingsPage, VectorSettingsNotificationPreferenceFragment::class.java, null, FRAGMENT_TAG)
} }
is SettingsActivityPayload.DiscoverySettings -> { is SettingsActivityPayload.DiscoverySettings -> {
replaceFragment(R.id.vector_settings_page, DiscoverySettingsFragment::class.java, payload, FRAGMENT_TAG) replaceFragment(views.vectorSettingsPage, DiscoverySettingsFragment::class.java, payload, FRAGMENT_TAG)
} }
else -> else ->
replaceFragment(R.id.vector_settings_page, VectorSettingsRootFragment::class.java, null, FRAGMENT_TAG) replaceFragment(views.vectorSettingsPage, VectorSettingsRootFragment::class.java, null, FRAGMENT_TAG)
} }
} }
@ -123,7 +123,7 @@ class VectorSettingsActivity : VectorBaseActivity<ActivityVectorSettingsBinding>
// Replace the existing Fragment with the new Fragment // Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.right_in, R.anim.fade_out, R.anim.fade_in, R.anim.right_out) .setCustomAnimations(R.anim.right_in, R.anim.fade_out, R.anim.fade_in, R.anim.right_out)
.replace(R.id.vector_settings_page, oFragment, pref.title.toString()) .replace(views.vectorSettingsPage.id, oFragment, pref.title.toString())
.addToBackStack(null) .addToBackStack(null)
.commit() .commit()
return true return true
@ -154,7 +154,7 @@ class VectorSettingsActivity : VectorBaseActivity<ActivityVectorSettingsBinding>
fun <T : Fragment> navigateTo(fragmentClass: Class<T>, arguments: Bundle? = null) { fun <T : Fragment> navigateTo(fragmentClass: Class<T>, arguments: Bundle? = null) {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.right_in, R.anim.fade_out, R.anim.fade_in, R.anim.right_out) .setCustomAnimations(R.anim.right_in, R.anim.fade_out, R.anim.fade_in, R.anim.right_out)
.replace(R.id.vector_settings_page, fragmentClass, arguments) .replace(views.vectorSettingsPage.id, fragmentClass, arguments)
.addToBackStack(null) .addToBackStack(null)
.commit() .commit()
} }

View File

@ -22,11 +22,9 @@ import im.vector.app.R
import im.vector.app.core.preference.VectorPreference import im.vector.app.core.preference.VectorPreference
import im.vector.app.core.utils.FirstThrottler import im.vector.app.core.utils.FirstThrottler
import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.displayInWebView
import im.vector.app.core.utils.openAppSettingsPage import im.vector.app.core.utils.openAppSettingsPage
import im.vector.app.core.utils.openUrlInChromeCustomTab import im.vector.app.core.utils.openUrlInChromeCustomTab
import im.vector.app.features.version.VersionProvider import im.vector.app.features.version.VersionProvider
import im.vector.app.openOssLicensesMenuActivity
import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.Matrix
import javax.inject.Inject import javax.inject.Inject
@ -40,6 +38,15 @@ class VectorSettingsHelpAboutFragment @Inject constructor(
private val firstThrottler = FirstThrottler(1000) private val firstThrottler = FirstThrottler(1000)
override fun bindPref() { override fun bindPref() {
// Help
findPreference<VectorPreference>(VectorPreferences.SETTINGS_HELP_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) {
openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.HELP)
}
false
}
// preference to start the App info screen, to facilitate App permissions access // preference to start the App info screen, to facilitate App permissions access
findPreference<VectorPreference>(APP_INFO_LINK_PREFERENCE_KEY)!! findPreference<VectorPreference>(APP_INFO_LINK_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener { .onPreferenceClickListener = Preference.OnPreferenceClickListener {
@ -76,44 +83,6 @@ class VectorSettingsHelpAboutFragment @Inject constructor(
// olm version // olm version
findPreference<VectorPreference>(VectorPreferences.SETTINGS_OLM_VERSION_PREFERENCE_KEY)!! findPreference<VectorPreference>(VectorPreferences.SETTINGS_OLM_VERSION_PREFERENCE_KEY)!!
.summary = session.cryptoService().getCryptoVersion(requireContext(), false) .summary = session.cryptoService().getCryptoVersion(requireContext(), false)
// copyright
findPreference<VectorPreference>(VectorPreferences.SETTINGS_COPYRIGHT_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.COPYRIGHT)
false
}
// terms & conditions
findPreference<VectorPreference>(VectorPreferences.SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.TAC)
false
}
// privacy policy
findPreference<VectorPreference>(VectorPreferences.SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.PRIVACY_POLICY)
false
}
// third party notice
findPreference<VectorPreference>(VectorPreferences.SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) {
activity?.displayInWebView(VectorSettingsUrls.THIRD_PARTY_LICENSES)
}
false
}
// Note: preference is not visible on F-Droid build
findPreference<VectorPreference>(VectorPreferences.SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY)!!
.onPreferenceClickListener = Preference.OnPreferenceClickListener {
// See https://developers.google.com/android/guides/opensource
openOssLicensesMenuActivity(requireActivity())
false
}
} }
companion object { companion object {

View File

@ -17,7 +17,7 @@
package im.vector.app.features.settings package im.vector.app.features.settings
object VectorSettingsUrls { object VectorSettingsUrls {
const val HELP = "https://element.io/help"
const val COPYRIGHT = "https://element.io/copyright" const val COPYRIGHT = "https://element.io/copyright"
const val TAC = "https://element.io/terms-of-service" const val TAC = "https://element.io/terms-of-service"
const val PRIVACY_POLICY = "https://element.io/privacy" const val PRIVACY_POLICY = "https://element.io/privacy"

View File

@ -0,0 +1,38 @@
/*
* 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.legals
import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.discovery.ServerPolicy
import im.vector.app.features.settings.VectorSettingsUrls
import javax.inject.Inject
class ElementLegals @Inject constructor(
private val stringProvider: StringProvider
) {
/**
* Use ServerPolicy model
*/
fun getData(): List<ServerPolicy> {
return listOf(
ServerPolicy(stringProvider.getString(R.string.settings_copyright), VectorSettingsUrls.COPYRIGHT),
ServerPolicy(stringProvider.getString(R.string.settings_app_term_conditions), VectorSettingsUrls.TAC),
ServerPolicy(stringProvider.getString(R.string.settings_privacy_policy), VectorSettingsUrls.PRIVACY_POLICY)
)
}
}

View File

@ -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.legals
import im.vector.app.core.platform.VectorViewModelAction
sealed interface LegalsAction : VectorViewModelAction {
object Refresh : LegalsAction
}

View File

@ -0,0 +1,152 @@
/*
* 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.legals
import android.content.res.Resources
import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Async
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.ServerAndPolicies
import im.vector.app.features.discovery.ServerPolicy
import im.vector.app.features.discovery.discoveryPolicyItem
import im.vector.app.features.discovery.settingsInfoItem
import im.vector.app.features.discovery.settingsSectionTitleItem
import javax.inject.Inject
class LegalsController @Inject constructor(
private val stringProvider: StringProvider,
private val resources: Resources,
private val elementLegals: ElementLegals,
private val errorFormatter: ErrorFormatter
) : TypedEpoxyController<LegalsState>() {
var listener: Listener? = null
override fun buildModels(data: LegalsState) {
buildAppSection()
buildHomeserverSection(data)
buildIdentityServerSection(data)
buildThirdPartyNotices()
}
private fun buildAppSection() {
settingsSectionTitleItem {
id("appTitle")
titleResId(R.string.legals_application_title)
}
buildPolicies("el", elementLegals.getData())
}
private fun buildHomeserverSection(data: LegalsState) {
settingsSectionTitleItem {
id("hsServerTitle")
titleResId(R.string.legals_home_server_title)
}
buildPolicyAsync("hs", data.homeServer)
}
private fun buildIdentityServerSection(data: LegalsState) {
if (data.hasIdentityServer) {
settingsSectionTitleItem {
id("idServerTitle")
titleResId(R.string.legals_identity_server_title)
}
buildPolicyAsync("is", data.identityServer)
}
}
private fun buildPolicyAsync(tag: String, serverAndPolicies: Async<ServerAndPolicies?>) {
val host = this
when (serverAndPolicies) {
Uninitialized,
is Loading -> loadingItem {
id("loading_$tag")
}
is Success -> {
val policies = serverAndPolicies()?.policies
if (policies.isNullOrEmpty()) {
settingsInfoItem {
id("emptyPolicy")
helperText(host.stringProvider.getString(R.string.legals_no_policy_provided))
}
} else {
buildPolicies(tag, policies)
}
}
is Fail -> {
errorWithRetryItem {
id("errorRetry_$tag")
text(host.errorFormatter.toHumanReadable(serverAndPolicies.error))
listener { host.listener?.onTapRetry() }
}
}
}
}
private fun buildPolicies(tag: String, policies: List<ServerPolicy>) {
val host = this
policies.forEach { policy ->
discoveryPolicyItem {
id(tag + policy.url)
name(policy.name)
url(policy.url.takeIf { it.startsWith("http") })
clickListener { host.listener?.openPolicy(policy) }
}
}
}
private fun buildThirdPartyNotices() {
val host = this
settingsSectionTitleItem {
id("thirdTitle")
titleResId(R.string.legals_third_party_notices)
}
discoveryPolicyItem {
id("eltpn1")
name(host.stringProvider.getString(R.string.settings_third_party_notices))
clickListener { host.listener?.openThirdPartyNotice() }
}
// Only on Gplay
if (resources.getBoolean(R.bool.isGplay)) {
discoveryPolicyItem {
id("eltpn2")
name(host.stringProvider.getString(R.string.settings_other_third_party_notices))
clickListener { host.listener?.openThirdPartyNoticeGplay() }
}
}
}
interface Listener {
fun onTapRetry()
fun openPolicy(policy: ServerPolicy)
fun openThirdPartyNotice()
fun openThirdPartyNoticeGplay()
}
}

View File

@ -0,0 +1,101 @@
/*
* 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.legals
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.core.utils.FirstThrottler
import im.vector.app.core.utils.displayInWebView
import im.vector.app.core.utils.openUrlInChromeCustomTab
import im.vector.app.databinding.FragmentGenericRecyclerBinding
import im.vector.app.features.discovery.ServerPolicy
import im.vector.app.features.settings.VectorSettingsUrls
import im.vector.app.openOssLicensesMenuActivity
import javax.inject.Inject
class LegalsFragment @Inject constructor(
private val controller: LegalsController
) : VectorBaseFragment<FragmentGenericRecyclerBinding>(),
LegalsController.Listener {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding {
return FragmentGenericRecyclerBinding.inflate(inflater, container, false)
}
private val viewModel by fragmentViewModel(LegalsViewModel::class)
private val firstThrottler = FirstThrottler(1000)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
controller.listener = this
views.genericRecyclerView.configureWith(controller)
}
override fun onDestroyView() {
views.genericRecyclerView.cleanup()
controller.listener = null
super.onDestroyView()
}
override fun invalidate() = withState(viewModel) { state ->
controller.setData(state)
}
override fun onResume() {
super.onResume()
(activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.preference_root_legals)
viewModel.handle(LegalsAction.Refresh)
}
override fun onTapRetry() {
viewModel.handle(LegalsAction.Refresh)
}
override fun openPolicy(policy: ServerPolicy) {
openUrl(policy.url)
}
override fun openThirdPartyNotice() {
openUrl(VectorSettingsUrls.THIRD_PARTY_LICENSES)
}
private fun openUrl(url: String) {
if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) {
if (url.startsWith("file://")) {
activity?.displayInWebView(url)
} else {
openUrlInChromeCustomTab(requireContext(), null, url)
}
}
}
override fun openThirdPartyNoticeGplay() {
if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) {
// See https://developers.google.com/android/guides/opensource
openOssLicensesMenuActivity(requireActivity())
}
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.legals
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Uninitialized
import im.vector.app.features.discovery.ServerAndPolicies
data class LegalsState(
val homeServer: Async<ServerAndPolicies?> = Uninitialized,
val hasIdentityServer: Boolean = false,
val identityServer: Async<ServerAndPolicies?> = Uninitialized
) : MavericksState

View File

@ -0,0 +1,92 @@
/*
* 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.legals
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Success
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.R
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.discovery.fetchHomeserverWithTerms
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session
class LegalsViewModel @AssistedInject constructor(
@Assisted initialState: LegalsState,
private val session: Session,
private val stringProvider: StringProvider
) : VectorViewModel<LegalsState, LegalsAction, EmptyViewEvents>(initialState) {
@AssistedFactory
interface Factory : MavericksAssistedViewModelFactory<LegalsViewModel, LegalsState> {
override fun create(initialState: LegalsState): LegalsViewModel
}
companion object : MavericksViewModelFactory<LegalsViewModel, LegalsState> by hiltMavericksViewModelFactory()
override fun handle(action: LegalsAction) {
when (action) {
LegalsAction.Refresh -> loadData()
}.exhaustive
}
private fun loadData() = withState { state ->
loadHomeserver(state)
val url = session.identityService().getCurrentIdentityServerUrl()
if (url.isNullOrEmpty()) {
setState { copy(hasIdentityServer = false) }
} else {
setState { copy(hasIdentityServer = true) }
loadIdentityServer(state)
}
}
private fun loadHomeserver(state: LegalsState) {
if (state.homeServer !is Success) {
setState { copy(homeServer = Loading()) }
viewModelScope.launch {
runCatching { session.fetchHomeserverWithTerms(stringProvider.getString(R.string.resources_language)) }
.fold(
onSuccess = { setState { copy(homeServer = Success(it)) } },
onFailure = { setState { copy(homeServer = Fail(it)) } }
)
}
}
}
private fun loadIdentityServer(state: LegalsState) {
if (state.identityServer !is Success) {
setState { copy(identityServer = Loading()) }
viewModelScope.launch {
runCatching { session.fetchIdentityServerWithTerms(stringProvider.getString(R.string.resources_language)) }
.fold(
onSuccess = { setState { copy(identityServer = Success(it)) } },
onFailure = { setState { copy(identityServer = Fail(it)) } }
)
}
}
}
}

View File

@ -40,7 +40,6 @@ import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.core.utils.isIgnoringBatteryOptimizations import im.vector.app.core.utils.isIgnoringBatteryOptimizations
import im.vector.app.core.utils.requestDisablingBatteryOptimization import im.vector.app.core.utils.requestDisablingBatteryOptimization
import im.vector.app.features.VectorFeatures
import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.notifications.NotificationUtils
import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.BackgroundSyncMode
import im.vector.app.features.settings.BackgroundSyncModeChooserDialog import im.vector.app.features.settings.BackgroundSyncModeChooserDialog
@ -64,8 +63,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
private val pushManager: PushersManager, private val pushManager: PushersManager,
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val guardServiceStarter: GuardServiceStarter, private val guardServiceStarter: GuardServiceStarter
private val features: VectorFeatures
) : VectorSettingsBaseFragment(), ) : VectorSettingsBaseFragment(),
BackgroundSyncModeChooserDialog.InteractionListener { BackgroundSyncModeChooserDialog.InteractionListener {
@ -147,7 +145,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
refreshBackgroundSyncPrefs() refreshBackgroundSyncPrefs()
handleSystemPreference() handleSystemPreference()
handleVersionedSettings()
} }
private fun bindEmailNotifications() { private fun bindEmailNotifications() {
@ -312,15 +309,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
} }
} }
private fun handleVersionedSettings() {
val isNotificationSettingsV2Enabled = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY)?.isVisible = !isNotificationSettingsV2Enabled
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
activeSessionHolder.getSafeActiveSession()?.refreshPushers() activeSessionHolder.getSafeActiveSession()?.refreshPushers()

View File

@ -18,7 +18,6 @@ package im.vector.app.features.share
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
@ -33,7 +32,7 @@ class IncomingShareActivity : VectorBaseActivity<ActivitySimpleBinding>(), Toolb
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment(R.id.simpleFragmentContainer, IncomingShareFragment::class.java) addFragment(views.simpleFragmentContainer, IncomingShareFragment::class.java)
} }
} }

View File

@ -87,7 +87,7 @@ class SoftLogoutActivity : LoginActivity() {
} }
override fun addFirstFragment() { override fun addFirstFragment() {
replaceFragment(R.id.loginFragmentContainer, SoftLogoutFragment::class.java) replaceFragment(views.loginFragmentContainer, SoftLogoutFragment::class.java)
} }
private fun updateWithState(softLogoutViewState: SoftLogoutViewState) { private fun updateWithState(softLogoutViewState: SoftLogoutViewState) {

View File

@ -89,7 +89,7 @@ class SoftLogoutActivity2 : LoginActivity2() {
} }
override fun addFirstFragment() { override fun addFirstFragment() {
replaceFragment(R.id.loginFragmentContainer, SoftLogoutFragment::class.java) replaceFragment(views.loginFragmentContainer, SoftLogoutFragment::class.java)
} }
private fun updateWithState(softLogoutViewState: SoftLogoutViewState) { private fun updateWithState(softLogoutViewState: SoftLogoutViewState) {

View File

@ -123,7 +123,7 @@ class SpaceCreationActivity : SimpleFragmentActivity() {
val frag = supportFragmentManager.findFragmentByTag(fragmentClass.name) ?: createFragment(fragmentClass) val frag = supportFragmentManager.findFragmentByTag(fragmentClass.name) ?: createFragment(fragmentClass)
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out) .setCustomAnimations(R.anim.fade_in, R.anim.fade_out, R.anim.fade_in, R.anim.fade_out)
.replace(R.id.container, .replace(views.container.id,
frag, frag,
fragmentClass.name fragmentClass.name
) )

View File

@ -25,7 +25,7 @@ import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.matrixto.MatrixToBottomSheet
@ -65,18 +65,13 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), Matrix
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
if (isFirstCreation()) { if (isFirstCreation()) {
val simpleName = SpaceDirectoryFragment::class.java.simpleName
val args = intent?.getParcelableExtra<SpaceDirectoryArgs>(Mavericks.KEY_ARG) val args = intent?.getParcelableExtra<SpaceDirectoryArgs>(Mavericks.KEY_ARG)
if (supportFragmentManager.findFragmentByTag(simpleName) == null) { replaceFragment(
supportFragmentManager.commitTransaction { views.simpleFragmentContainer,
replace(R.id.simpleFragmentContainer,
SpaceDirectoryFragment::class.java, SpaceDirectoryFragment::class.java,
Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, args) }, args
simpleName
) )
} }
}
}
sharedViewModel.observeViewEvents { sharedViewModel.observeViewEvents {
when (it) { when (it) {

View File

@ -22,8 +22,7 @@ import android.os.Bundle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.Mavericks
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.spaces.preview.SpacePreviewArgs import im.vector.app.features.spaces.preview.SpacePreviewArgs
@ -54,19 +53,14 @@ class SpacePreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
if (isFirstCreation()) { if (isFirstCreation()) {
val simpleName = SpacePreviewFragment::class.java.simpleName
val args = intent?.getParcelableExtra<SpacePreviewArgs>(Mavericks.KEY_ARG) val args = intent?.getParcelableExtra<SpacePreviewArgs>(Mavericks.KEY_ARG)
if (supportFragmentManager.findFragmentByTag(simpleName) == null) { replaceFragment(
supportFragmentManager.commitTransaction { views.simpleFragmentContainer,
replace(R.id.simpleFragmentContainer,
SpacePreviewFragment::class.java, SpacePreviewFragment::class.java,
Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, args) }, args
simpleName
) )
} }
} }
}
}
companion object { companion object {
fun newIntent(context: Context, spaceIdOrAlias: String): Intent { fun newIntent(context: Context, spaceIdOrAlias: String): Intent {

View File

@ -31,8 +31,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
@ -69,19 +69,13 @@ class SpaceLeaveAdvancedActivity : VectorBaseActivity<ActivitySimpleLoadingBindi
val args = intent?.getParcelableExtra<SpaceBottomSheetSettingsArgs>(Mavericks.KEY_ARG) val args = intent?.getParcelableExtra<SpaceBottomSheetSettingsArgs>(Mavericks.KEY_ARG)
if (isFirstCreation()) { if (isFirstCreation()) {
val simpleName = SpaceLeaveAdvancedFragment::class.java.simpleName replaceFragment(
if (supportFragmentManager.findFragmentByTag(simpleName) == null) { views.simpleFragmentContainer,
supportFragmentManager.commitTransaction {
replace(
R.id.simpleFragmentContainer,
SpaceLeaveAdvancedFragment::class.java, SpaceLeaveAdvancedFragment::class.java,
Bundle().apply { this.putParcelable(Mavericks.KEY_ARG, args) }, args
simpleName
) )
} }
} }
}
}
override fun initUiAndData() { override fun initUiAndData() {
super.initUiAndData() super.initUiAndData()

Some files were not shown because too many files have changed in this diff Show More