Merge branch 'release/25.09.1' into main
This commit is contained in:
2
.github/workflows/fork-pr-notice.yml
vendored
2
.github/workflows/fork-pr-notice.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
if: github.event.pull_request.base.repo.full_name != github.event.pull_request.head.repo.full_name
|
||||
steps:
|
||||
- name: Add auto-generated commit warning
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
|
||||
2
.github/workflows/generate_github_pages.yml
vendored
2
.github/workflows/generate_github_pages.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.13
|
||||
- name: Run World screenshots generation script
|
||||
|
||||
2
.github/workflows/post-release.yml
vendored
2
.github/workflows/post-release.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Trigger pipeline
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.ENTERPRISE_ACTIONS_TOKEN }}
|
||||
script: |
|
||||
|
||||
6
.github/workflows/pull_request.yml
vendored
6
.github/workflows/pull_request.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: Add notice
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
if: contains(github.event.pull_request.labels.*.name, 'X-Blocked')
|
||||
with:
|
||||
script: |
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN_READ_ORG }}
|
||||
- name: Add label
|
||||
if: steps.teams.outputs.isTeamMember == 'false'
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
github.event.pull_request.head.repo.full_name != github.repository
|
||||
steps:
|
||||
- name: Close pull request
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
|
||||
4
.github/workflows/quality.yml
vendored
4
.github/workflows/quality.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.13
|
||||
- name: Search for invalid screenshot files
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.13
|
||||
- name: Search for invalid dependencies
|
||||
|
||||
2
.github/workflows/sync-localazy.yml
vendored
2
.github/workflows/sync-localazy.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.13
|
||||
- name: Setup Localazy
|
||||
|
||||
2
.github/workflows/sync-sas-strings.yml
vendored
2
.github/workflows/sync-sas-strings.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.13
|
||||
- name: Install Prerequisite dependencies
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -82,7 +82,7 @@ jobs:
|
||||
|
||||
# https://github.com/codecov/codecov-action
|
||||
- name: ☂️ Upload coverage reports to codecov
|
||||
uses: codecov/codecov-action@fdcc8476540edceab3de004e990f80d881c6cc00 # v5.5.0
|
||||
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
16
CHANGES.md
16
CHANGES.md
@@ -1,3 +1,19 @@
|
||||
Changes in Element X v25.09.0
|
||||
=============================
|
||||
|
||||
This release is the same as `25.08.4` but it includes performance fixes for the timeline load times, included in the Rust SDK version upgrade and internal changes for Element Call.
|
||||
|
||||
## What's Changed
|
||||
### 🧱 Build
|
||||
* Revert "Try following KSP incremental best practices on `anvilcodegen`" by @bmarty in https://github.com/element-hq/element-x-android/pull/5233
|
||||
### Dependency upgrades
|
||||
* Update dependency io.element.android:element-call-embedded to v0.15.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5229
|
||||
* Update dependency org.matrix.rustcomponents:sdk-android to v25.8.26 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/5230
|
||||
* Downgrade sonar scanner gradle plugin to `v6.2.0.5505` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/5234
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v25.08.4...v25.09.0
|
||||
|
||||
Changes in Element X v25.08.4
|
||||
=============================
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.anvilannotations
|
||||
package io.element.android.annotations
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@@ -13,7 +13,7 @@ import kotlin.reflect.KClass
|
||||
* Adds Node to the specified component graph.
|
||||
* Equivalent to the following declaration:
|
||||
*
|
||||
* @Module
|
||||
* @BindingContainer
|
||||
* @ContributesTo(Scope::class)
|
||||
* abstract class YourNodeModule {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
io.element.android.anvilcodegen.ContributesNodeProcessorProvider
|
||||
@@ -13,7 +13,6 @@ import com.android.build.gradle.tasks.GenerateBuildConfig
|
||||
import com.google.firebase.appdistribution.gradle.firebaseAppDistribution
|
||||
import config.BuildTimeConfig
|
||||
import extension.AssetCopyTask
|
||||
import extension.ComponentMergingStrategy
|
||||
import extension.GitBranchNameValueSource
|
||||
import extension.GitRevisionValueSource
|
||||
import extension.allEnterpriseImpl
|
||||
@@ -23,7 +22,7 @@ import extension.allServicesImpl
|
||||
import extension.buildConfigFieldStr
|
||||
import extension.koverDependencies
|
||||
import extension.locales
|
||||
import extension.setupAnvil
|
||||
import extension.setupDependencyInjection
|
||||
import extension.setupKover
|
||||
import java.util.Locale
|
||||
|
||||
@@ -37,7 +36,7 @@ plugins {
|
||||
alias(libs.plugins.licensee)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
// To be able to update the firebase.xml files, uncomment and build the project
|
||||
// id("com.google.gms.google-services")
|
||||
// alias(libs.plugins.gms.google.services)
|
||||
}
|
||||
|
||||
setupKover()
|
||||
@@ -103,7 +102,8 @@ android {
|
||||
}
|
||||
|
||||
val baseAppName = BuildTimeConfig.APPLICATION_NAME
|
||||
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName)")
|
||||
val buildType = if (isEnterpriseBuild) "Enterprise" else "FOSS"
|
||||
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName) [$buildType]")
|
||||
|
||||
buildTypes {
|
||||
val oidcRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android"
|
||||
@@ -247,11 +247,7 @@ knit {
|
||||
}
|
||||
}
|
||||
|
||||
setupAnvil(
|
||||
generateDaggerCode = true,
|
||||
generateDaggerFactoriesUsingAnvil = false,
|
||||
componentMergingStrategy = ComponentMergingStrategy.KSP,
|
||||
)
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
allLibrariesImpl()
|
||||
@@ -260,6 +256,7 @@ dependencies {
|
||||
allEnterpriseImpl(project)
|
||||
implementation(projects.appicon.enterprise)
|
||||
} else {
|
||||
implementation(projects.features.enterprise.implFoss)
|
||||
implementation(projects.appicon.element)
|
||||
}
|
||||
allFeaturesImpl(project)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
|
||||
@@ -9,16 +9,16 @@ package io.element.android.x
|
||||
|
||||
import android.app.Application
|
||||
import androidx.startup.AppInitializer
|
||||
import dev.zacsweers.metro.createGraphFactory
|
||||
import io.element.android.features.cachecleaner.api.CacheCleanerInitializer
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.x.di.AppComponent
|
||||
import io.element.android.x.di.DaggerAppComponent
|
||||
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||
import io.element.android.x.di.AppGraph
|
||||
import io.element.android.x.info.logApplicationInfo
|
||||
import io.element.android.x.initializer.CrashInitializer
|
||||
import io.element.android.x.initializer.PlatformInitializer
|
||||
|
||||
class ElementXApplication : Application(), DaggerComponentOwner {
|
||||
override val daggerComponent: AppComponent = DaggerAppComponent.factory().create(this)
|
||||
class ElementXApplication : Application(), DependencyInjectionGraphOwner {
|
||||
override val graph: AppGraph = createGraphFactory<AppGraph.Factory>().create(this)
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
@@ -21,8 +21,8 @@ import com.bumble.appyx.core.node.ParentNode
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import io.element.android.appnav.RootFlowNode
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@@ -38,8 +38,8 @@ class MainNode(
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
),
|
||||
DaggerComponentOwner {
|
||||
override val daggerComponent = (context as DaggerComponentOwner).daggerComponent
|
||||
DependencyInjectionGraphOwner {
|
||||
override val graph = (context as DependencyInjectionGraphOwner).graph
|
||||
|
||||
override fun resolve(navTarget: RootNavTarget, buildContext: BuildContext): Node {
|
||||
return createNode<RootFlowNode>(buildContext = buildContext)
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import io.element.android.features.api.MigrationEntryPoint
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||
@@ -15,7 +16,6 @@ import io.element.android.features.lockscreen.api.LockScreenService
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.platform.InitPlatformService
|
||||
import io.element.android.libraries.matrix.api.tracing.TracingService
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.anvil.annotations.MergeComponent
|
||||
import dagger.BindsInstance
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
@MergeComponent(AppScope::class)
|
||||
interface AppComponent : NodeFactoriesBindings {
|
||||
@MergeComponent.Factory
|
||||
interface Factory {
|
||||
fun create(
|
||||
@ApplicationContext @BindsInstance
|
||||
context: Context
|
||||
): AppComponent
|
||||
}
|
||||
}
|
||||
28
app/src/main/kotlin/io/element/android/x/di/AppGraph.kt
Normal file
28
app/src/main/kotlin/io/element/android/x/di/AppGraph.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import android.content.Context
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.DependencyGraph
|
||||
import dev.zacsweers.metro.Provides
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
|
||||
@DependencyGraph(AppScope::class)
|
||||
interface AppGraph : NodeFactoriesBindings {
|
||||
val sessionGraphFactory: SessionGraph.Factory
|
||||
|
||||
@DependencyGraph.Factory
|
||||
interface Factory {
|
||||
fun create(
|
||||
@ApplicationContext @Provides
|
||||
context: Context
|
||||
): AppGraph
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,11 @@ import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.BindingContainer
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import dev.zacsweers.metro.Provides
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import io.element.android.appconfig.ApplicationConfig
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.features.messages.impl.timeline.components.customreaction.DefaultEmojibaseProvider
|
||||
@@ -23,11 +25,10 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.core.meta.BuildType
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.BaseDirectory
|
||||
import io.element.android.libraries.di.CacheDirectory
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import io.element.android.x.BuildConfig
|
||||
import io.element.android.x.R
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
@@ -37,10 +38,11 @@ import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.plus
|
||||
import java.io.File
|
||||
|
||||
@Module
|
||||
@BindingContainer
|
||||
@ContributesTo(AppScope::class)
|
||||
object AppModule {
|
||||
@Provides
|
||||
@BaseDirectory
|
||||
fun providesBaseDirectory(@ApplicationContext context: Context): File {
|
||||
return File(context.filesDir, "sessions")
|
||||
}
|
||||
|
||||
@@ -7,20 +7,19 @@
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.appnav.di.RoomComponentFactory
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(SessionScope::class)
|
||||
class DefaultRoomComponentFactory @Inject constructor(
|
||||
private val roomComponentBuilder: RoomComponent.Builder
|
||||
@Inject
|
||||
class DefaultRoomComponentFactory(
|
||||
private val sessionGraph: SessionGraph,
|
||||
) : RoomComponentFactory {
|
||||
override fun create(room: JoinedRoom): Any {
|
||||
return roomComponentBuilder
|
||||
.joinedRoom(room)
|
||||
.baseRoom(room)
|
||||
.build()
|
||||
return sessionGraph.roomGraphFactory
|
||||
.create(room, room)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.appnav.di.SessionComponentFactory
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultSessionComponentFactory @Inject constructor(
|
||||
private val sessionComponentBuilder: SessionComponent.Builder
|
||||
) : SessionComponentFactory {
|
||||
override fun create(client: MatrixClient): Any {
|
||||
return sessionComponentBuilder.client(client).build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.appnav.di.SessionGraphFactory
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
@Inject
|
||||
class DefaultSessionGraphFactory(
|
||||
private val appGraph: AppGraph
|
||||
) : SessionGraphFactory {
|
||||
override fun create(client: MatrixClient): Any {
|
||||
return appGraph.sessionGraphFactory.create(client)
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import com.squareup.anvil.annotations.MergeSubcomponent
|
||||
import dagger.BindsInstance
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
|
||||
@SingleIn(RoomScope::class)
|
||||
@MergeSubcomponent(RoomScope::class)
|
||||
interface RoomComponent : NodeFactoriesBindings {
|
||||
@MergeSubcomponent.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
fun joinedRoom(room: JoinedRoom): Builder
|
||||
|
||||
@BindsInstance
|
||||
fun baseRoom(room: BaseRoom): Builder
|
||||
|
||||
fun build(): RoomComponent
|
||||
}
|
||||
|
||||
@ContributesTo(SessionScope::class)
|
||||
interface ParentBindings {
|
||||
fun roomComponentBuilder(): Builder
|
||||
}
|
||||
}
|
||||
29
app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt
Normal file
29
app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import dev.zacsweers.metro.GraphExtension
|
||||
import dev.zacsweers.metro.Provides
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
|
||||
@GraphExtension(RoomScope::class)
|
||||
interface RoomGraph : NodeFactoriesBindings {
|
||||
@ContributesTo(SessionScope::class)
|
||||
@GraphExtension.Factory
|
||||
interface Factory {
|
||||
fun create(
|
||||
@Provides joinedRoom: JoinedRoom,
|
||||
@Provides baseRoom: BaseRoom
|
||||
): RoomGraph
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import com.squareup.anvil.annotations.MergeSubcomponent
|
||||
import dagger.BindsInstance
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
||||
@SingleIn(SessionScope::class)
|
||||
@MergeSubcomponent(SessionScope::class)
|
||||
interface SessionComponent : NodeFactoriesBindings {
|
||||
@MergeSubcomponent.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
fun client(matrixClient: MatrixClient): Builder
|
||||
|
||||
fun build(): SessionComponent
|
||||
}
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface ParentBindings {
|
||||
fun sessionComponentBuilder(): Builder
|
||||
}
|
||||
}
|
||||
27
app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt
Normal file
27
app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import dev.zacsweers.metro.GraphExtension
|
||||
import dev.zacsweers.metro.Provides
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
||||
@GraphExtension(SessionScope::class)
|
||||
interface SessionGraph : NodeFactoriesBindings {
|
||||
val roomGraphFactory: RoomGraph.Factory
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
@GraphExtension.Factory
|
||||
interface Factory {
|
||||
fun create(@Provides matrixClient: MatrixClient): SessionGraph
|
||||
}
|
||||
}
|
||||
@@ -10,19 +10,20 @@ package io.element.android.x.intent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.net.toUri
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.deeplink.api.DeepLinkCreator
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.push.impl.intent.IntentProvider
|
||||
import io.element.android.x.MainActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultIntentProvider @Inject constructor(
|
||||
@Inject
|
||||
class DefaultIntentProvider(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val deepLinkCreator: DeepLinkCreator,
|
||||
) : IntentProvider {
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
|
||||
package io.element.android.x.oidc
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import io.element.android.x.R
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultOidcRedirectUrlProvider @Inject constructor(
|
||||
@Inject
|
||||
class DefaultOidcRedirectUrlProvider(
|
||||
private val stringProvider: StringProvider,
|
||||
) : OidcRedirectUrlProvider {
|
||||
override fun provide() = buildString {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<locale android:name="in"/>
|
||||
<locale android:name="it"/>
|
||||
<locale android:name="ka"/>
|
||||
<locale android:name="ko"/>
|
||||
<locale android:name="lt"/>
|
||||
<locale android:name="nb"/>
|
||||
<locale android:name="nl"/>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
import extension.allFeaturesApi
|
||||
import extension.setupAnvil
|
||||
import extension.setupDependencyInjection
|
||||
|
||||
plugins {
|
||||
id("io.element.android-compose-library")
|
||||
@@ -19,7 +19,7 @@ android {
|
||||
namespace = "io.element.android.appnav"
|
||||
}
|
||||
|
||||
setupAnvil()
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
allFeaturesApi(project)
|
||||
|
||||
@@ -22,29 +22,30 @@ import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.node.ParentNode
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.appnav.di.SessionComponentFactory
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.appnav.di.SessionGraphFactory
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
/**
|
||||
* `LoggedInAppScopeFlowNode` is a Node responsible to set up the Dagger
|
||||
* `LoggedInAppScopeFlowNode` is a Node responsible to set up the Session graph.
|
||||
* [io.element.android.libraries.di.SessionScope]. It has only one child: [LoggedInFlowNode].
|
||||
* This allow to inject objects with SessionScope in the constructor of [LoggedInFlowNode].
|
||||
*/
|
||||
@ContributesNode(AppScope::class)
|
||||
class LoggedInAppScopeFlowNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class LoggedInAppScopeFlowNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
sessionComponentFactory: SessionComponentFactory,
|
||||
sessionGraphFactory: SessionGraphFactory,
|
||||
private val imageLoaderHolder: ImageLoaderHolder,
|
||||
) : ParentNode<LoggedInAppScopeFlowNode.NavTarget>(
|
||||
navModel = PermanentNavModel(
|
||||
@@ -53,7 +54,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
|
||||
),
|
||||
buildContext = buildContext,
|
||||
plugins = plugins
|
||||
), DaggerComponentOwner {
|
||||
), DependencyInjectionGraphOwner {
|
||||
interface Callback : Plugin {
|
||||
fun onOpenBugReport()
|
||||
}
|
||||
@@ -66,7 +67,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
|
||||
) : NodeInputs
|
||||
|
||||
private val inputs: Inputs = inputs()
|
||||
override val daggerComponent = sessionComponentFactory.create(inputs.matrixClient)
|
||||
override val graph = sessionGraphFactory.create(inputs.matrixClient)
|
||||
|
||||
override fun onBuilt() {
|
||||
super.onBuilt()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.appnav
|
||||
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
@@ -18,9 +19,9 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoggedInEventProcessor @Inject constructor(
|
||||
@Inject
|
||||
class LoggedInEventProcessor(
|
||||
private val snackbarDispatcher: SnackbarDispatcher,
|
||||
private val roomMembershipObserver: RoomMembershipObserver,
|
||||
) {
|
||||
|
||||
@@ -36,10 +36,11 @@ import com.bumble.appyx.navmodel.backstack.operation.pop
|
||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import com.bumble.appyx.navmodel.backstack.operation.replace
|
||||
import com.bumble.appyx.navmodel.backstack.operation.singleTop
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import im.vector.app.features.analytics.plan.JoinedRoom
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.appnav.loggedin.LoggedInNode
|
||||
import io.element.android.appnav.loggedin.MediaPreviewConfigMigration
|
||||
import io.element.android.appnav.loggedin.SendQueues
|
||||
@@ -67,7 +68,6 @@ import io.element.android.libraries.architecture.BaseFlowNode
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.architecture.waitForNavTargetAttached
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
@@ -100,7 +100,8 @@ import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.toKotlinDuration
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class LoggedInFlowNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class LoggedInFlowNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val homeEntryPoint: HomeEntryPoint,
|
||||
@@ -560,14 +561,15 @@ class LoggedInFlowNode @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
class PlaceholderNode @AssistedInject constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
) : Node(buildContext, plugins = plugins)
|
||||
}
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
@Inject
|
||||
class PlaceholderNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
) : Node(buildContext, plugins = plugins)
|
||||
|
||||
@Parcelize
|
||||
private class AttachRoomOperation(
|
||||
val roomTarget: LoggedInFlowNode.NavTarget.Room,
|
||||
|
||||
@@ -20,9 +20,10 @@ import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.features.login.api.LoginEntryPoint
|
||||
import io.element.android.features.login.api.LoginParams
|
||||
import io.element.android.libraries.architecture.BackstackView
|
||||
@@ -31,12 +32,12 @@ import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.designsystem.utils.ForceOrientationInMobileDevices
|
||||
import io.element.android.libraries.designsystem.utils.ScreenOrientation
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.ui.media.NotLoggedInImageLoaderFactory
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
class NotLoggedInFlowNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class NotLoggedInFlowNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val loginEntryPoint: LoginEntryPoint,
|
||||
|
||||
@@ -23,10 +23,11 @@ import com.bumble.appyx.core.state.MutableSavedStateMap
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.pop
|
||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import im.vector.app.features.analytics.plan.JoinedRoom
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.appnav.di.MatrixSessionCache
|
||||
import io.element.android.appnav.intent.IntentResolver
|
||||
import io.element.android.appnav.intent.ResolvedIntent
|
||||
@@ -46,7 +47,6 @@ import io.element.android.libraries.architecture.waitForChildAttached
|
||||
import io.element.android.libraries.core.uri.ensureProtocol
|
||||
import io.element.android.libraries.deeplink.api.DeeplinkData
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
@@ -61,7 +61,8 @@ import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
class RootFlowNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class RootFlowNode(
|
||||
@Assisted val buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val authenticationService: MatrixAuthenticationService,
|
||||
|
||||
@@ -10,9 +10,10 @@ package io.element.android.appnav.di
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.bumble.appyx.core.state.MutableSavedStateMap
|
||||
import com.bumble.appyx.core.state.SavedStateMap
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
@@ -22,7 +23,6 @@ import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val SAVE_INSTANCE_KEY = "io.element.android.x.di.MatrixClientsHolder.SaveInstanceKey"
|
||||
|
||||
@@ -33,7 +33,8 @@ private const val SAVE_INSTANCE_KEY = "io.element.android.x.di.MatrixClientsHold
|
||||
*/
|
||||
@SingleIn(AppScope::class)
|
||||
@ContributesBinding(AppScope::class)
|
||||
class MatrixSessionCache @Inject constructor(
|
||||
@Inject
|
||||
class MatrixSessionCache(
|
||||
private val authenticationService: MatrixAuthenticationService,
|
||||
private val syncOrchestratorFactory: SyncOrchestrator.Factory,
|
||||
) : MatrixClientProvider {
|
||||
|
||||
@@ -9,6 +9,6 @@ package io.element.android.appnav.di
|
||||
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
||||
interface SessionComponentFactory {
|
||||
interface SessionGraphFactory {
|
||||
fun create(client: MatrixClient): Any
|
||||
}
|
||||
@@ -8,9 +8,9 @@
|
||||
package io.element.android.appnav.di
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
@@ -30,7 +30,8 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class SyncOrchestrator @AssistedInject constructor(
|
||||
@Inject
|
||||
class SyncOrchestrator(
|
||||
@Assisted matrixClient: MatrixClient,
|
||||
private val appForegroundStateService: AppForegroundStateService,
|
||||
private val networkMonitor: NetworkMonitor,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package io.element.android.appnav.intent
|
||||
|
||||
import android.content.Intent
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.login.api.LoginIntentResolver
|
||||
import io.element.android.features.login.api.LoginParams
|
||||
import io.element.android.libraries.deeplink.api.DeeplinkData
|
||||
@@ -17,7 +18,6 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||
import io.element.android.libraries.oidc.api.OidcAction
|
||||
import io.element.android.libraries.oidc.api.OidcIntentResolver
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
sealed interface ResolvedIntent {
|
||||
data class Navigation(val deeplinkData: DeeplinkData) : ResolvedIntent
|
||||
@@ -27,7 +27,8 @@ sealed interface ResolvedIntent {
|
||||
data class IncomingShare(val intent: Intent) : ResolvedIntent
|
||||
}
|
||||
|
||||
class IntentResolver @Inject constructor(
|
||||
@Inject
|
||||
class IntentResolver(
|
||||
private val deeplinkParser: DeeplinkParser,
|
||||
private val loginIntentResolver: LoginIntentResolver,
|
||||
private val oidcIntentResolver: OidcIntentResolver,
|
||||
|
||||
@@ -13,13 +13,14 @@ import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class LoggedInNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class LoggedInNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val loggedInPresenter: LoggedInPresenter,
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.zacsweers.metro.Inject
|
||||
import im.vector.app.features.analytics.plan.CryptoSessionStateChange
|
||||
import im.vector.app.features.analytics.plan.UserProperties
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
@@ -42,11 +43,11 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val pusherTag = LoggerTag("Pusher", LoggerTag.PushLoggerTag)
|
||||
|
||||
class LoggedInPresenter @Inject constructor(
|
||||
@Inject
|
||||
class LoggedInPresenter(
|
||||
private val matrixClient: MatrixClient,
|
||||
private val syncService: SyncService,
|
||||
private val pushService: PushService,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.appnav.loggedin
|
||||
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.media.MediaPreviewService
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
@@ -14,13 +15,13 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* This migration is temporary, will be safe to remove after some time.
|
||||
* The goal is to set the server config if it's not set, and remove the local data.
|
||||
*/
|
||||
class MediaPreviewConfigMigration @Inject constructor(
|
||||
@Inject
|
||||
class MediaPreviewConfigMigration(
|
||||
private val mediaPreviewService: MediaPreviewService,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
@SessionCoroutineScope
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
package io.element.android.appnav.loggedin
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||
@@ -21,13 +22,13 @@ import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@VisibleForTesting
|
||||
const val SEND_QUEUES_RETRY_DELAY_MILLIS = 500L
|
||||
|
||||
@SingleIn(SessionScope::class)
|
||||
class SendQueues @Inject constructor(
|
||||
@Inject
|
||||
class SendQueues(
|
||||
private val matrixClient: MatrixClient,
|
||||
private val syncService: SyncService,
|
||||
) {
|
||||
|
||||
@@ -21,10 +21,10 @@ import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.newRoot
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import im.vector.app.features.analytics.plan.JoinedRoom
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.appnav.room.joined.JoinedRoomFlowNode
|
||||
import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
|
||||
import io.element.android.appnav.room.joined.LoadingRoomNodeView
|
||||
@@ -63,7 +63,8 @@ import java.util.Optional
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class RoomFlowNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class RoomFlowNode(
|
||||
@Assisted val buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val client: MatrixClient,
|
||||
|
||||
@@ -24,9 +24,9 @@ import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.core.plugin.plugins
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.newRoot
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.appnav.room.RoomNavigationTarget
|
||||
import io.element.android.libraries.architecture.BackstackView
|
||||
import io.element.android.libraries.architecture.BaseFlowNode
|
||||
@@ -45,7 +45,8 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class JoinedRoomFlowNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class JoinedRoomFlowNode(
|
||||
@Assisted val buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory,
|
||||
|
||||
@@ -17,9 +17,9 @@ import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.appnav.di.RoomComponentFactory
|
||||
import io.element.android.appnav.room.RoomNavigationTarget
|
||||
import io.element.android.features.messages.api.MessagesEntryPoint
|
||||
@@ -28,7 +28,7 @@ import io.element.android.libraries.architecture.BackstackView
|
||||
import io.element.android.libraries.architecture.BaseFlowNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
@@ -45,7 +45,8 @@ import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class JoinedRoomLoadedFlowNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class JoinedRoomLoadedFlowNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val messagesEntryPoint: MessagesEntryPoint,
|
||||
@@ -67,7 +68,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor(
|
||||
),
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
), DaggerComponentOwner {
|
||||
), DependencyInjectionGraphOwner {
|
||||
interface Callback : Plugin {
|
||||
fun onOpenRoom(roomId: RoomId, serverNames: List<String>)
|
||||
fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean)
|
||||
@@ -82,7 +83,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor(
|
||||
|
||||
private val inputs: Inputs = inputs()
|
||||
private val callbacks = plugins.filterIsInstance<Callback>()
|
||||
override val daggerComponent = roomComponentFactory.create(inputs.room)
|
||||
override val graph = roomComponentFactory.create(inputs.room)
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
|
||||
@@ -9,18 +9,16 @@ package io.element.android.appnav.root
|
||||
|
||||
import com.bumble.appyx.core.state.MutableSavedStateMap
|
||||
import com.bumble.appyx.core.state.SavedStateMap
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.appnav.di.MatrixSessionCache
|
||||
import io.element.android.features.login.api.LoginUserStory
|
||||
import io.element.android.features.preferences.api.CacheService
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStoreFactory
|
||||
import io.element.android.libraries.sessionstorage.api.LoggedInState
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val SAVE_INSTANCE_KEY = "io.element.android.x.RootNavStateFlowFactory.SAVE_INSTANCE_KEY"
|
||||
|
||||
@@ -28,12 +26,12 @@ private const val SAVE_INSTANCE_KEY = "io.element.android.x.RootNavStateFlowFact
|
||||
* This class is responsible for creating a flow of [RootNavState].
|
||||
* It gathers data from multiple datasource and creates a unique one.
|
||||
*/
|
||||
class RootNavStateFlowFactory @Inject constructor(
|
||||
@Inject
|
||||
class RootNavStateFlowFactory(
|
||||
private val authenticationService: MatrixAuthenticationService,
|
||||
private val cacheService: CacheService,
|
||||
private val matrixSessionCache: MatrixSessionCache,
|
||||
private val imageLoaderHolder: ImageLoaderHolder,
|
||||
private val loginUserStory: LoginUserStory,
|
||||
private val sessionPreferencesStoreFactory: SessionPreferencesStoreFactory,
|
||||
) {
|
||||
private var currentCacheIndex = 0
|
||||
@@ -42,13 +40,11 @@ class RootNavStateFlowFactory @Inject constructor(
|
||||
return combine(
|
||||
cacheIndexFlow(savedStateMap),
|
||||
authenticationService.loggedInStateFlow(),
|
||||
loginUserStory.loginFlowIsDone,
|
||||
) { cacheIndex, loggedInState, loginFlowIsDone ->
|
||||
if (loginFlowIsDone) {
|
||||
RootNavState(cacheIndex = cacheIndex, loggedInState = loggedInState)
|
||||
} else {
|
||||
RootNavState(cacheIndex = cacheIndex, loggedInState = LoggedInState.NotLoggedIn)
|
||||
}
|
||||
) { cacheIndex, loggedInState ->
|
||||
RootNavState(
|
||||
cacheIndex = cacheIndex,
|
||||
loggedInState = loggedInState,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import dev.zacsweers.metro.Inject
|
||||
import im.vector.app.features.analytics.plan.SuperProperties
|
||||
import io.element.android.features.rageshake.api.crash.CrashDetectionState
|
||||
import io.element.android.features.rageshake.api.detection.RageshakeDetectionState
|
||||
@@ -18,9 +19,9 @@ import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.matrix.api.SdkMetadata
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.apperror.api.AppErrorStateService
|
||||
import javax.inject.Inject
|
||||
|
||||
class RootPresenter @Inject constructor(
|
||||
@Inject
|
||||
class RootPresenter(
|
||||
private val crashDetectionPresenter: Presenter<CrashDetectionState>,
|
||||
private val rageshakeDetectionPresenter: Presenter<RageshakeDetectionState>,
|
||||
private val appErrorStateService: AppErrorStateService,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="banner_migrate_to_native_sliding_sync_action">"Abmelden und aktualisieren"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s unterstützt das alte Protokoll nicht mehr. Bitte melden Sie sich ab und wieder an, um die App weiter nutzen zu können."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s unterstützt das alte Protokoll nicht mehr. Bitte melde dich ab und wieder an, um die App weiter nutzen zu können."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Dein Homeserver unterstützt das alte Protokoll nicht mehr. Bitte logge dich aus und melde dich wieder an, um die App weiter zu nutzen."</string>
|
||||
</resources>
|
||||
|
||||
6
appnav/src/main/res/values-ko/translations.xml
Normal file
6
appnav/src/main/res/values-ko/translations.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="banner_migrate_to_native_sliding_sync_action">"로그아웃 및 업그레이드"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s 더 이상 이전 프로토콜을 지원하지 않습니다. 계속 사용하려면 로그아웃 후 다시 로그인해 주세요."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"귀하의 홈서버는 더 이상 이전 프로토콜을 지원하지 않습니다. 앱을 계속 사용하려면 로그아웃한 후 다시 로그인하세요."</string>
|
||||
</resources>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="banner_migrate_to_native_sliding_sync_action">"Sair e atualizar"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s não suporta mais o protocolo antigo. Termine sessão e volte a iniciar sessão para continuar a utilizar a aplicação."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Seu servidor doméstico não é mais compatível com o protocolo antigo. Faça logout e login novamente para continuar usando o aplicativo."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s não tem mais suporte ao protocolo antigo. Saia da sua conta e entre novamente para continuar utilizando o aplicativo."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Seu servidor-casa não é mais compatível com o protocolo antigo. Saia da sua conta e entre novamente para continuar usando o aplicativo."</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="banner_migrate_to_native_sliding_sync_action">"Deconectați-vă și faceți upgrade"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s nu mai acceptă vechiul protocol. Vă rugăm să vă deconectați și să vă reconectați pentru a continua utilizarea aplicației."</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Serverul dvs. de acasă nu mai acceptă vechiul protocol. Vă rugăm să vă deconectați și să vă conectați din nou pentru a continua să utilizați aplicația."</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="banner_migrate_to_native_sliding_sync_action">"Çıkış Yap ve Yükselt"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s artık eski protokolü destekleniyor. Uygulamayı kullanmaya devam etmek için lütfen çıkış yapın ve tekrar giriş yapın
|
||||
"</string>
|
||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"Ana sunucunuz artık eski protokolü desteklemiyor. Lütfen oturumu kapatın ve uygulamayı kullanmaya devam etmek için tekrar oturum açın."</string>
|
||||
</resources>
|
||||
|
||||
@@ -5,24 +5,15 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath(libs.kotlin.gradle.plugin)
|
||||
classpath(libs.gms.google.services)
|
||||
}
|
||||
}
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id("io.element.android-root")
|
||||
alias(libs.plugins.kotlin.jvm) apply false
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.android.library) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.compose.compiler) apply false
|
||||
alias(libs.plugins.ksp) apply false
|
||||
alias(libs.plugins.anvil) apply false
|
||||
alias(libs.plugins.kotlin.jvm) apply false
|
||||
alias(libs.plugins.kapt) apply false
|
||||
alias(libs.plugins.dependencycheck) apply false
|
||||
alias(libs.plugins.dependencyanalysis)
|
||||
alias(libs.plugins.detekt)
|
||||
|
||||
@@ -10,11 +10,10 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.anvilannotations)
|
||||
api(libs.anvil.compiler.api)
|
||||
implementation(libs.anvil.compiler.utils)
|
||||
implementation(projects.annotations)
|
||||
implementation(libs.metro.runtime)
|
||||
implementation(libs.kotlin.compiler)
|
||||
implementation(libs.kotlinpoet)
|
||||
implementation(libs.dagger)
|
||||
implementation(libs.ksp.plugin)
|
||||
implementation(libs.kotlinpoet.ksp)
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.anvilcodegen
|
||||
package io.element.android.codegen
|
||||
|
||||
import com.google.devtools.ksp.KspExperimental
|
||||
import com.google.devtools.ksp.getConstructors
|
||||
@@ -19,7 +19,6 @@ import com.google.devtools.ksp.symbol.KSAnnotated
|
||||
import com.google.devtools.ksp.symbol.KSClassDeclaration
|
||||
import com.google.devtools.ksp.symbol.KSType
|
||||
import com.google.devtools.ksp.validate
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import com.squareup.kotlinpoet.AnnotationSpec
|
||||
import com.squareup.kotlinpoet.ClassName
|
||||
import com.squareup.kotlinpoet.FileSpec
|
||||
@@ -30,13 +29,13 @@ import com.squareup.kotlinpoet.STAR
|
||||
import com.squareup.kotlinpoet.TypeSpec
|
||||
import com.squareup.kotlinpoet.ksp.toTypeName
|
||||
import com.squareup.kotlinpoet.ksp.writeTo
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.multibindings.IntoMap
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.BindingContainer
|
||||
import dev.zacsweers.metro.Binds
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import dev.zacsweers.metro.IntoMap
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class ContributesNodeProcessor(
|
||||
@@ -77,9 +76,8 @@ class ContributesNodeProcessor(
|
||||
fileName = moduleClassName,
|
||||
)
|
||||
.addType(
|
||||
TypeSpec.classBuilder(moduleClassName)
|
||||
.addModifiers(KModifier.ABSTRACT)
|
||||
.addAnnotation(Module::class)
|
||||
TypeSpec.interfaceBuilder(moduleClassName)
|
||||
.addAnnotation(BindingContainer::class)
|
||||
.addAnnotation(AnnotationSpec.builder(ContributesTo::class).addMember("%T::class", scope.toTypeName()).build())
|
||||
.addFunction(
|
||||
FunSpec.builder("bind${ksClass.simpleName.asString()}Factory")
|
||||
@@ -103,7 +101,7 @@ class ContributesNodeProcessor(
|
||||
content.writeTo(
|
||||
codeGenerator = codeGenerator,
|
||||
dependencies = Dependencies(
|
||||
aggregating = true,
|
||||
aggregating = false,
|
||||
ksClass.containingFile!!
|
||||
),
|
||||
)
|
||||
@@ -113,23 +111,23 @@ class ContributesNodeProcessor(
|
||||
private fun generateFactory(ksClass: KSClassDeclaration) {
|
||||
val generatedPackage = ksClass.packageName.asString()
|
||||
val assistedFactoryClassName = "${ksClass.simpleName.asString()}_AssistedFactory"
|
||||
val constructor = ksClass.getConstructors().singleOrNull { it.isAnnotationPresent(AssistedInject::class) }
|
||||
val assistedParameters = constructor?.parameters?.filter { it.isAnnotationPresent(Assisted::class) }.orEmpty()
|
||||
if (constructor == null || assistedParameters.size != 2) {
|
||||
val constructor = ksClass.getConstructors().first { it.parameters.isNotEmpty() }
|
||||
val assistedParameters = constructor.parameters.filter { it.isAnnotationPresent(Assisted::class) }
|
||||
if (assistedParameters.size != 2) {
|
||||
error(
|
||||
"${ksClass.qualifiedName} must have an @AssistedInject constructor with 2 @Assisted parameters",
|
||||
"${ksClass.qualifiedName?.asString()} must have an @Inject constructor with 2 @Assisted parameters. Found: ${assistedParameters.size}",
|
||||
)
|
||||
}
|
||||
val contextAssistedParam = assistedParameters[0]
|
||||
if (contextAssistedParam.name?.asString() != "buildContext") {
|
||||
error(
|
||||
"${ksClass.qualifiedName} @Assisted parameter must be named buildContext",
|
||||
"${ksClass.qualifiedName?.asString()} @Assisted parameter must be named buildContext",
|
||||
)
|
||||
}
|
||||
val pluginsAssistedParam = assistedParameters[1]
|
||||
if (pluginsAssistedParam.name?.asString() != "plugins") {
|
||||
error(
|
||||
"${ksClass.qualifiedName} @Assisted parameter must be named plugins",
|
||||
"${ksClass.qualifiedName?.asString()} @Assisted parameter must be named plugins",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -156,7 +154,7 @@ class ContributesNodeProcessor(
|
||||
content.writeTo(
|
||||
codeGenerator = codeGenerator,
|
||||
dependencies = Dependencies(
|
||||
aggregating = true,
|
||||
aggregating = false,
|
||||
ksClass.containingFile!!
|
||||
),
|
||||
)
|
||||
@@ -5,7 +5,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.anvilcodegen
|
||||
package io.element.android.codegen
|
||||
|
||||
import com.google.devtools.ksp.processing.SymbolProcessor
|
||||
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
|
||||
@@ -0,0 +1 @@
|
||||
io.element.android.codegen.ContributesNodeProcessorProvider
|
||||
@@ -249,8 +249,7 @@ Main libraries and frameworks used in this application:
|
||||
|
||||
- Navigation state with [Appyx](https://bumble-tech.github.io/appyx/). Please
|
||||
watch [this video](https://www.droidcon.com/2022/11/15/model-driven-navigation-with-appyx-from-zero-to-hero/) to learn more about Appyx!
|
||||
- DI: [Dagger](https://dagger.dev/) and [Anvil](https://github.com/square/anvil). Please
|
||||
watch [this video](https://www.droidcon.com/2022/06/28/dagger-anvil-learning-to-love-dependency-injection/) to learn more about Anvil!
|
||||
- Dependency injection: [Metro](https://zacsweers.github.io/metro/latest/)
|
||||
- Reactive State management with Compose runtime and [Molecule](https://github.com/cashapp/molecule)
|
||||
|
||||
Some patterns are inspired by [Circuit](https://slackhq.github.io/circuit/)
|
||||
@@ -261,7 +260,7 @@ Here are the main points:
|
||||
2. Views are compose first
|
||||
3. Presenters are also compose first, and have a single `present(): State` method. It's using the power of compose-runtime/compiler.
|
||||
4. The point of connection between a `View` and a `Presenter` is a `Node`.
|
||||
5. A `Node` is also responsible for managing Dagger components if any.
|
||||
5. A `Node` is also responsible for managing DI graph if any, see for instance `LoggedInAppScopeFlowNode`.
|
||||
6. A `ParentNode` has some children `Node` and only know about them.
|
||||
7. This is a single activity full compose application. The `MainActivity` is responsible for holding and configuring the `RootNode`.
|
||||
8. There is no more needs for Android Architecture Component ViewModel as configuration change should be handled by Composable if needed.
|
||||
@@ -423,7 +422,7 @@ Rageshake can be very useful to get logs from a release version of the applicati
|
||||
- When this is possible, prefer using `sealed interface` instead of `sealed class`;
|
||||
- When writing temporary code, using the string "DO NOT COMMIT" in a comment can help to avoid committing things by mistake. If committed and pushed, the CI
|
||||
will detect this String and will warn the user about it. (TODO Not supported yet!)
|
||||
- Very occasionally the gradle cache misbehaves and causes problems with Dagger. Try building with `--no-build-cache` if Dagger isn't behaving how you expect.
|
||||
- Very occasionally the gradle cache misbehaves and causes problems with code generation. Adding `--no-build-cache` to the `gradlew` command line can help to fix compilation issue.
|
||||
|
||||
## Happy coding!
|
||||
|
||||
|
||||
15
docs/migration_to_metro.md
Normal file
15
docs/migration_to_metro.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Migration to Metro
|
||||
|
||||
The dependency injection library is now [Metro](https://zacsweers.github.io/metro/latest/). It replaces both Dagger and Anvil.
|
||||
|
||||
Migration of the current Element X code has been performed in https://github.com/element-hq/element-x-android/pull/5253.
|
||||
|
||||
To migrate other existing code you will need to:
|
||||
|
||||
- replace `setupAnvil()` with `setupDependencyInjection()` in your `build.gradle.kts` files
|
||||
- replace the Dagger and Anvil imports with Metro ones
|
||||
- move the `@Inject` apply to the constructor to the class itself (only applicable if there is only one primary constructor
|
||||
- replace `@AssistedInject` with `@Inject`
|
||||
- replace `@Module` with `@BindingContainer`
|
||||
|
||||
This should help to migrate your existing code.
|
||||
Submodule enterprise updated: 76e10f6fa4...95789d4011
2
fastlane/metadata/android/en-US/changelogs/202509010.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/202509010.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Main changes in this version: bug fixes and improvements.
|
||||
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_settings_help_us_improve">"Teile anonyme Nutzungsdaten, um uns bei der Identifizierung von Problemen zu helfen."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"Sie können unsere Bedingungen %1$s lesen."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"Weitere Informationen findest du %1$s."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"hier"</string>
|
||||
<string name="screen_analytics_settings_share_data">"Analysedaten teilen"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_settings_help_us_improve">"익명화된 사용 데이터를 공유하여 문제점을 파악하는 데 도움을 주십시오."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"모든 이용 약관은 %1$s 에서 확인하실 수 있습니다."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"여기"</string>
|
||||
<string name="screen_analytics_settings_share_data">"분석 데이터 공유"</string>
|
||||
</resources>
|
||||
@@ -3,5 +3,5 @@
|
||||
<string name="screen_analytics_settings_help_us_improve">"Compartilhe dados de uso anônimos para nos ajudar a identificar problemas."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"Você pode ler todos os nossos termos %1$s."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"aqui"</string>
|
||||
<string name="screen_analytics_settings_share_data">"Compartilhar dados de utilização"</string>
|
||||
<string name="screen_analytics_settings_share_data">"Compartilhar dados analíticos"</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import extension.setupAnvil
|
||||
import extension.setupDependencyInjection
|
||||
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
@@ -16,7 +16,7 @@ android {
|
||||
namespace = "io.element.android.features.analytics.impl"
|
||||
}
|
||||
|
||||
setupAnvil()
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.androidutils)
|
||||
|
||||
@@ -14,16 +14,17 @@ import androidx.compose.ui.Modifier
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.annotations.ContributesNode
|
||||
import io.element.android.appconfig.AnalyticsConfig
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
|
||||
import io.element.android.libraries.di.AppScope
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
class AnalyticsOptInNode @AssistedInject constructor(
|
||||
@Inject
|
||||
class AnalyticsOptInNode(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
private val presenter: AnalyticsOptInPresenter,
|
||||
|
||||
@@ -9,6 +9,7 @@ package io.element.android.features.analytics.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.appconfig.AnalyticsConfig
|
||||
import io.element.android.features.analytics.api.AnalyticsOptInEvents
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
@@ -16,9 +17,9 @@ import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class AnalyticsOptInPresenter @Inject constructor(
|
||||
@Inject
|
||||
class AnalyticsOptInPresenter(
|
||||
private val buildMeta: BuildMeta,
|
||||
private val analyticsService: AnalyticsService,
|
||||
) : Presenter<AnalyticsOptInState> {
|
||||
|
||||
@@ -9,14 +9,15 @@ package io.element.android.features.analytics.impl
|
||||
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.analytics.api.AnalyticsEntryPoint
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultAnalyticsEntryPoint @Inject constructor() : AnalyticsEntryPoint {
|
||||
@Inject
|
||||
class DefaultAnalyticsEntryPoint : AnalyticsEntryPoint {
|
||||
override fun createNode(parentNode: Node, buildContext: BuildContext): Node {
|
||||
return parentNode.createNode<AnalyticsOptInNode>(buildContext)
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
|
||||
package io.element.android.features.analytics.impl.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.BindingContainer
|
||||
import dev.zacsweers.metro.Binds
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
|
||||
import io.element.android.features.analytics.impl.preferences.AnalyticsPreferencesPresenter
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.di.AppScope
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
@Module
|
||||
@BindingContainer
|
||||
interface AnalyticsModule {
|
||||
@Binds
|
||||
fun bindAnalyticsPreferencesPresenter(presenter: AnalyticsPreferencesPresenter): Presenter<AnalyticsPreferencesState>
|
||||
|
||||
@@ -10,6 +10,7 @@ package io.element.android.features.analytics.impl.preferences
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.appconfig.AnalyticsConfig
|
||||
import io.element.android.features.analytics.api.AnalyticsOptInEvents
|
||||
import io.element.android.features.analytics.api.preferences.AnalyticsPreferencesState
|
||||
@@ -18,9 +19,9 @@ import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class AnalyticsPreferencesPresenter @Inject constructor(
|
||||
@Inject
|
||||
class AnalyticsPreferencesPresenter(
|
||||
private val analyticsService: AnalyticsService,
|
||||
private val buildMeta: BuildMeta,
|
||||
) : Presenter<AnalyticsPreferencesState> {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_prompt_data_usage">"Wir zeichnen keine persönlichen Daten auf und erstellen keine Profile."</string>
|
||||
<string name="screen_analytics_prompt_data_usage">"Wir speichern oder profilieren keine personenbezogenen Daten."</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Teile anonyme Nutzungsdaten, um uns bei der Identifizierung von Problemen zu helfen."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"Sie können unsere Bedingungen %1$s lesen."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"Weitere Informationen findest du %1$s."</string>
|
||||
<string name="screen_analytics_prompt_read_terms_content_link">"hier"</string>
|
||||
<string name="screen_analytics_prompt_settings">"Sie können dies jederzeit beenden"</string>
|
||||
<string name="screen_analytics_prompt_settings">"Du kannst diese Funktion jederzeit deaktivieren"</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing">"Wir geben deine Daten nicht an Dritte weiter"</string>
|
||||
<string name="screen_analytics_prompt_title">"Hilf uns %1$s zu verbessern"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_prompt_data_usage">"개인 데이터는 기록하거나 프로파일링하지 않습니다."</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"익명화된 사용 데이터를 공유하여 문제점을 파악하는 데 도움을 주십시오."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"모든 이용 약관은 %1$s 에서 확인하실 수 있습니다."</string>
|
||||
<string name="screen_analytics_prompt_read_terms_content_link">"여기"</string>
|
||||
<string name="screen_analytics_prompt_settings">"이 기능을 언제든지 비활성화할 수 있습니다."</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing">"우리는 귀하의 데이터를 제3자와 공유하지 않습니다."</string>
|
||||
<string name="screen_analytics_prompt_title">"%1$s 개선하기"</string>
|
||||
</resources>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="screen_analytics_prompt_data_usage">"Não registraremos nem criaremos perfil baseado em qualquer dado pessoal"</string>
|
||||
<string name="screen_analytics_prompt_data_usage">"Não iremos gravar ou personificar qualquer dado pessoal"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Compartilhe dados de uso anônimos para nos ajudar a identificar problemas."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"Você pode ler todos os nossos termos %1$s."</string>
|
||||
<string name="screen_analytics_prompt_read_terms_content_link">"aqui"</string>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import extension.setupAnvil
|
||||
import extension.setupDependencyInjection
|
||||
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
@@ -15,7 +15,7 @@ android {
|
||||
namespace = "io.element.android.features.cachecleaner.api"
|
||||
}
|
||||
|
||||
setupAnvil()
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.architecture)
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
package io.element.android.features.cachecleaner.api
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface CacheCleanerBindings {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import extension.setupAnvil
|
||||
import extension.setupDependencyInjection
|
||||
|
||||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
@@ -15,7 +15,7 @@ android {
|
||||
namespace = "io.element.android.features.cachecleaner.impl"
|
||||
}
|
||||
|
||||
setupAnvil()
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
api(projects.features.cachecleaner.api)
|
||||
|
||||
@@ -7,24 +7,25 @@
|
||||
|
||||
package io.element.android.features.cachecleaner.impl
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.cachecleaner.api.CacheCleaner
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.CacheDirectory
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Default implementation of [CacheCleaner].
|
||||
*/
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultCacheCleaner @Inject constructor(
|
||||
@Inject
|
||||
class DefaultCacheCleaner(
|
||||
@AppCoroutineScope
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
|
||||
@@ -15,7 +15,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.anvilannotations)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import extension.buildConfigFieldStr
|
||||
import extension.readLocalProperty
|
||||
import extension.setupAnvil
|
||||
import extension.setupDependencyInjection
|
||||
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
@@ -60,7 +60,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
setupAnvil()
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
implementation(projects.appconfig)
|
||||
|
||||
@@ -8,20 +8,21 @@
|
||||
package io.element.android.features.call.impl
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.call.api.CallType
|
||||
import io.element.android.features.call.api.ElementCallEntryPoint
|
||||
import io.element.android.features.call.impl.notifications.CallNotificationData
|
||||
import io.element.android.features.call.impl.utils.ActiveCallManager
|
||||
import io.element.android.features.call.impl.utils.IntentProvider
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultElementCallEntryPoint @Inject constructor(
|
||||
@Inject
|
||||
class DefaultElementCallEntryPoint(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val activeCallManager: ActiveCallManager,
|
||||
) : ElementCallEntryPoint {
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
package io.element.android.features.call.impl.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesTo
|
||||
import io.element.android.features.call.impl.receivers.DeclineCallBroadcastReceiver
|
||||
import io.element.android.features.call.impl.ui.ElementCallActivity
|
||||
import io.element.android.features.call.impl.ui.IncomingCallActivity
|
||||
import io.element.android.libraries.di.AppScope
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface CallBindings {
|
||||
|
||||
@@ -15,13 +15,14 @@ import android.provider.Settings
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.core.app.Person
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.appconfig.ElementCallConfig
|
||||
import io.element.android.features.call.api.CallType
|
||||
import io.element.android.features.call.impl.receivers.DeclineCallBroadcastReceiver
|
||||
import io.element.android.features.call.impl.ui.IncomingCallActivity
|
||||
import io.element.android.features.call.impl.utils.IntentProvider
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
@@ -29,13 +30,13 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
/**
|
||||
* Creates a notification for a ringing call.
|
||||
*/
|
||||
class RingingCallNotificationCreator @Inject constructor(
|
||||
@Inject
|
||||
class RingingCallNotificationCreator(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val matrixClientProvider: MatrixClientProvider,
|
||||
private val imageLoaderHolder: ImageLoaderHolder,
|
||||
|
||||
@@ -13,16 +13,17 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.call.impl.utils.PipController
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("PiP")
|
||||
|
||||
class PictureInPicturePresenter @Inject constructor(
|
||||
@Inject
|
||||
class PictureInPicturePresenter(
|
||||
pipSupportProvider: PipSupportProvider,
|
||||
) : Presenter<PictureInPictureState> {
|
||||
private val isPipSupported = pipSupportProvider.isPipSupported()
|
||||
|
||||
@@ -11,11 +11,11 @@ import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.annotation.ChecksSdkIntAtLeast
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
|
||||
interface PipSupportProvider {
|
||||
@ChecksSdkIntAtLeast(Build.VERSION_CODES.O)
|
||||
@@ -23,7 +23,8 @@ interface PipSupportProvider {
|
||||
}
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultPipSupportProvider @Inject constructor(
|
||||
@Inject
|
||||
class DefaultPipSupportProvider(
|
||||
@ApplicationContext private val context: Context,
|
||||
) : PipSupportProvider {
|
||||
override fun isPipSupported(): Boolean {
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.content.IntentCompat
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.call.api.CallType
|
||||
import io.element.android.features.call.impl.di.CallBindings
|
||||
import io.element.android.features.call.impl.notifications.CallNotificationData
|
||||
@@ -19,7 +20,6 @@ import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Broadcast receiver to decline the incoming call.
|
||||
|
||||
@@ -17,9 +17,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.Inject
|
||||
import im.vector.app.features.analytics.plan.MobileScreen
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.call.api.CallType
|
||||
@@ -49,7 +49,8 @@ import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class CallScreenPresenter @AssistedInject constructor(
|
||||
@Inject
|
||||
class CallScreenPresenter(
|
||||
@Assisted private val callType: CallType,
|
||||
@Assisted private val navigator: CallScreenNavigator,
|
||||
private val callWidgetProvider: CallWidgetProvider,
|
||||
|
||||
@@ -30,6 +30,7 @@ import androidx.core.app.PictureInPictureModeChangedInfo
|
||||
import androidx.core.content.IntentCompat
|
||||
import androidx.core.util.Consumer
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.call.api.CallType
|
||||
import io.element.android.features.call.api.CallType.ExternalUrl
|
||||
import io.element.android.features.call.impl.DefaultElementCallEntryPoint
|
||||
@@ -50,7 +51,6 @@ import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.designsystem.theme.ElementThemeApp
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("ElementCallActivity")
|
||||
|
||||
@@ -79,7 +79,7 @@ class ElementCallActivity :
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
applicationContext.bindings<CallBindings>().inject(this)
|
||||
bindings<CallBindings>().inject(this)
|
||||
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.activity.compose.setContent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.IntentCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.call.api.CallType
|
||||
import io.element.android.features.call.api.ElementCallEntryPoint
|
||||
import io.element.android.features.call.impl.di.CallBindings
|
||||
@@ -30,7 +31,6 @@ import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Activity that's displayed as a full screen intent when an incoming call is received.
|
||||
@@ -64,7 +64,7 @@ class IncomingCallActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
applicationContext.bindings<CallBindings>().inject(this)
|
||||
bindings<CallBindings>().inject(this)
|
||||
|
||||
// Set flags so it can be displayed in the lock screen
|
||||
@Suppress("DEPRECATION")
|
||||
|
||||
@@ -9,9 +9,9 @@ package io.element.android.features.call.impl.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import javax.inject.Inject
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
|
||||
interface LanguageTagProvider {
|
||||
@Composable
|
||||
@@ -19,7 +19,8 @@ interface LanguageTagProvider {
|
||||
}
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultLanguageTagProvider @Inject constructor() : LanguageTagProvider {
|
||||
@Inject
|
||||
class DefaultLanguageTagProvider : LanguageTagProvider {
|
||||
@Composable
|
||||
override fun provideLanguageTag(): String? {
|
||||
return LocalConfiguration.current.locales.get(0)?.toLanguageTag()
|
||||
|
||||
@@ -15,17 +15,18 @@ import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import coil3.SingletonImageLoader
|
||||
import coil3.annotation.DelicateCoilApi
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import io.element.android.appconfig.ElementCallConfig
|
||||
import io.element.android.features.call.api.CallType
|
||||
import io.element.android.features.call.api.CurrentCall
|
||||
import io.element.android.features.call.impl.notifications.CallNotificationData
|
||||
import io.element.android.features.call.impl.notifications.RingingCallNotificationCreator
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||
@@ -52,7 +53,6 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
/**
|
||||
@@ -86,7 +86,8 @@ interface ActiveCallManager {
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultActiveCallManager @Inject constructor(
|
||||
@Inject
|
||||
class DefaultActiveCallManager(
|
||||
@ApplicationContext context: Context,
|
||||
@AppCoroutineScope
|
||||
private val coroutineScope: CoroutineScope,
|
||||
|
||||
@@ -9,9 +9,10 @@ package io.element.android.features.call.impl.utils
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import javax.inject.Inject
|
||||
import dev.zacsweers.metro.Inject
|
||||
|
||||
class CallIntentDataParser @Inject constructor() {
|
||||
@Inject
|
||||
class CallIntentDataParser {
|
||||
private val validHttpSchemes = sequenceOf("https")
|
||||
private val knownHosts = sequenceOf(
|
||||
"call.element.io",
|
||||
|
||||
@@ -7,14 +7,15 @@
|
||||
|
||||
package io.element.android.features.call.impl.utils
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.call.impl.BuildConfig
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.widget.CallAnalyticCredentialsProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultCallAnalyticCredentialsProvider @Inject constructor() : CallAnalyticCredentialsProvider {
|
||||
@Inject
|
||||
class DefaultCallAnalyticCredentialsProvider : CallAnalyticCredentialsProvider {
|
||||
override val posthogUserId: String? = BuildConfig.POSTHOG_USER_ID.takeIf { it.isNotBlank() }
|
||||
override val posthogApiHost: String? = BuildConfig.POSTHOG_API_HOST.takeIf { it.isNotBlank() }
|
||||
override val posthogApiKey: String? = BuildConfig.POSTHOG_API_KEY.takeIf { it.isNotBlank() }
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
|
||||
package io.element.android.features.call.impl.utils
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
@@ -18,12 +19,12 @@ import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val EMBEDDED_CALL_WIDGET_BASE_URL = "https://appassets.androidplatform.net/element-call/index.html"
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultCallWidgetProvider @Inject constructor(
|
||||
@Inject
|
||||
class DefaultCallWidgetProvider(
|
||||
private val matrixClientsProvider: MatrixClientProvider,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val callWidgetSettingsProvider: CallWidgetSettingsProvider,
|
||||
|
||||
@@ -7,17 +7,18 @@
|
||||
|
||||
package io.element.android.features.call.impl.utils
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import io.element.android.features.call.api.CurrentCall
|
||||
import io.element.android.features.call.api.CurrentCallService
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultCurrentCallService @Inject constructor() : CurrentCallService {
|
||||
@Inject
|
||||
class DefaultCurrentCallService : CurrentCallService {
|
||||
override val currentCall = MutableStateFlow<CurrentCall>(CurrentCall.None)
|
||||
|
||||
fun onCallStarted(call: CurrentCall) {
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
<string name="call_foreground_service_channel_title_android">"Laufender Anruf"</string>
|
||||
<string name="call_foreground_service_message_android">"Tippen, um zum Anruf zurückzukehren"</string>
|
||||
<string name="call_foreground_service_title_android">"☎️ Anruf läuft"</string>
|
||||
<string name="call_invalid_audio_device_bluetooth_devices_disabled">"In dieser Android-Version unterstützt Element Call derzeit keine Bluetooth-Audiogeräte. Bitte wählen Sie ein anderes Audiogerät aus."</string>
|
||||
<string name="call_invalid_audio_device_bluetooth_devices_disabled">"Element Call unterstützt in dieser Android-Version keine Bluetooth Geräte. Bitte wähle ein anderes Audiogerät."</string>
|
||||
<string name="screen_incoming_call_subtitle_android">"Eingehender Element Call"</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="call_foreground_service_channel_title_android">"수신 중인 통화"</string>
|
||||
<string name="call_foreground_service_message_android">"탭해서 통화로 돌아가기"</string>
|
||||
<string name="call_foreground_service_title_android">"☎️ 통화 진행 중"</string>
|
||||
<string name="call_invalid_audio_device_bluetooth_devices_disabled">"Element Call은 이 Android 버전에서 Bluetooth 오디오 장치 사용을 지원하지 않습니다. 다른 오디오 장치를 선택하세요."</string>
|
||||
<string name="screen_incoming_call_subtitle_android">"Element 전화 수신"</string>
|
||||
</resources>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user