First Commit

This commit is contained in:
2025-12-18 16:28:50 +07:00
commit 8c3e4f491f
9974 changed files with 396488 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.services.toolbox.api"
}
dependencies {
implementation(libs.androidx.corektx)
}
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 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.services.toolbox.api.intent
import android.content.Intent
/**
* Used to launch external intents from anywhere in the app.
*/
interface ExternalIntentLauncher {
fun launch(intent: Intent)
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.api.sdk
import androidx.annotation.ChecksSdkIntAtLeast
interface BuildVersionSdkIntProvider {
/**
* Return the current version of the Android SDK.
*/
fun get(): Int
/**
* Checks the if the current OS version is equal or greater than [version].
* @return A `non-null` result if true, `null` otherwise.
*/
@ChecksSdkIntAtLeast(parameter = 0, lambda = 1)
fun <T> whenAtLeast(version: Int, result: () -> T): T? {
return if (get() >= version) {
result()
} else {
null
}
}
@ChecksSdkIntAtLeast(parameter = 0)
fun isAtLeast(version: Int) = get() >= version
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.api.strings
import androidx.annotation.PluralsRes
import androidx.annotation.StringRes
interface StringProvider {
/**
* Returns a localized string from the application's package's
* default string table.
*
* @param resId Resource id for the string
* @return The string data associated with the resource, stripped of styled
* text information.
*/
fun getString(@StringRes resId: Int): String
/**
* Returns a localized formatted string from the application's package's
* default string table, substituting the format arguments as defined in
* [java.util.Formatter] and [java.lang.String.format].
*
* @param resId Resource id for the format string
* @param formatArgs The format arguments that will be used for
* substitution.
* @return The string data associated with the resource, formatted and
* stripped of styled text information.
*/
fun getString(@StringRes resId: Int, vararg formatArgs: Any?): String
fun getQuantityString(@PluralsRes resId: Int, quantity: Int, vararg formatArgs: Any?): String
}
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.api.systemclock
fun interface SystemClock {
fun epochMillis(): Long
}
+25
View File
@@ -0,0 +1,25 @@
import extension.setupDependencyInjection
/*
* Copyright (c) 2025 Element Creations Ltd.
* 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.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.services.toolbox.impl"
}
setupDependencyInjection()
dependencies {
implementation(projects.libraries.androidutils)
implementation(projects.libraries.di)
api(projects.services.toolbox.api)
implementation(libs.androidx.corektx)
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 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.services.toolbox.impl.intent
import android.content.Context
import android.content.Intent
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.services.toolbox.api.intent.ExternalIntentLauncher
@ContributesBinding(AppScope::class)
class DefaultExternalIntentLauncher(
@ApplicationContext private val context: Context,
) : ExternalIntentLauncher {
override fun launch(intent: Intent) {
context.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}
}
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.impl.sdk
import android.os.Build
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
@ContributesBinding(AppScope::class)
class DefaultBuildVersionSdkIntProvider :
BuildVersionSdkIntProvider {
override fun get() = Build.VERSION.SDK_INT
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.impl.strings
import android.content.res.Resources
import androidx.annotation.PluralsRes
import androidx.annotation.StringRes
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.services.toolbox.api.strings.StringProvider
@ContributesBinding(AppScope::class)
class AndroidStringProvider(private val resources: Resources) : StringProvider {
override fun getString(@StringRes resId: Int): String {
return resources.getString(resId)
}
override fun getString(@StringRes resId: Int, vararg formatArgs: Any?): String {
return resources.getString(resId, *formatArgs)
}
override fun getQuantityString(@PluralsRes resId: Int, quantity: Int, vararg formatArgs: Any?): String {
return resources.getQuantityString(resId, quantity, *formatArgs)
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.impl.systemclock
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.services.toolbox.api.systemclock.SystemClock
@ContributesBinding(AppScope::class)
class DefaultSystemClock : SystemClock {
/**
* Provides a UTC epoch in milliseconds
*
* This value is not guaranteed to be correct with reality
* as a User can override the system time and date to any values.
*/
override fun epochMillis(): Long {
return System.currentTimeMillis()
}
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.impl.systemclock
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import kotlin.time.TimeSource
@BindingContainer
@ContributesTo(AppScope::class)
object TimeModule {
@Provides
fun timeSource(): TimeSource {
return TimeSource.Monotonic
}
}
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.services.toolbox.test"
}
dependencies {
api(projects.services.toolbox.api)
implementation(projects.tests.testutils)
}
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 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.services.toolbox.test.intent
import android.content.Intent
import io.element.android.services.toolbox.api.intent.ExternalIntentLauncher
import io.element.android.tests.testutils.lambda.lambdaError
class FakeExternalIntentLauncher(
var launchLambda: (Intent) -> Unit = { lambdaError() },
) : ExternalIntentLauncher {
override fun launch(intent: Intent) {
launchLambda(intent)
}
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.test.sdk
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
class FakeBuildVersionSdkIntProvider(
private val sdkInt: Int
) : BuildVersionSdkIntProvider {
override fun get(): Int = sdkInt
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.test.strings
import io.element.android.services.toolbox.api.strings.StringProvider
class FakeStringProvider(
private val defaultResult: String = "A string"
) : StringProvider {
var lastResIdParam: Int? = null
override fun getString(resId: Int): String {
lastResIdParam = resId
return defaultResult
}
override fun getString(resId: Int, vararg formatArgs: Any?): String {
lastResIdParam = resId
return defaultResult + formatArgs.joinToString()
}
override fun getQuantityString(resId: Int, quantity: Int, vararg formatArgs: Any?): String {
lastResIdParam = resId
return defaultResult + " ($quantity) " + formatArgs.joinToString()
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-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.services.toolbox.test.systemclock
import io.element.android.services.toolbox.api.systemclock.SystemClock
const val A_FAKE_TIMESTAMP = 123L
class FakeSystemClock(
var epochMillisResult: Long = A_FAKE_TIMESTAMP
) : SystemClock {
override fun epochMillis() = epochMillisResult
}