Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-23 11:56:00 +03:00
parent 929317d15c
commit 12e53a3aa3
24 changed files with 205 additions and 95 deletions

View file

@ -217,6 +217,8 @@ dependencies {
implementation(projects.features.usedesk.impl)
implementation(projects.features.hotWallet.api)
implementation(projects.features.hotWallet.impl)
implementation(projects.features.kyc.api)
implementation(projects.features.kyc.impl)
/** AndroidX libraries */
implementation(deps.androidx.core.ktx)

View file

@ -45,7 +45,14 @@
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
tools:ignore="GoogleAppIndexingWarning"
tools:replace="android:allowBackup, android:fullBackupContent, android:label">
tools:replace="android:allowBackup, android:fullBackupContent, android:label, android:largeHeap">
<!--
property to make the "android:screenOrientation" work on API <37
https://developer.android.com/about/versions/16/behavior-changes-16
-->
<property android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
android:value="true" />
<meta-data
android:name="com.google.android.gms.wallet.api.enabled"

View file

@ -30,8 +30,10 @@ internal object RootAppComponentContextModule {
componentBuilder: ModelComponent.Builder,
@GlobalUiMessageSender messageSender: UiMessageSender,
): AppComponentContext {
val activity = context as AppCompatActivity
return DefaultAppComponentContext(
componentContext = (context as AppCompatActivity).defaultComponentContext(),
componentContext = activity.defaultComponentContext(),
activity = activity,
dispatchers = dispatchers,
hiltComponentBuilder = componentBuilder,
messageSender = messageSender,

View file

@ -1,54 +0,0 @@
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
ENV ANDROID_HOME=/opt/android-sdk
ENV BUNDLE_PATH=vendor/bundle
ENV PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/34.0.0:$BUNDLE_PATH/bin
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
RUN apt-get update && apt-get install -y \
locales \
openjdk-17-jdk \
wget \
unzip \
curl \
git \
ruby \
ruby-dev \
build-essential \
jq \
&& locale-gen en_US.UTF-8 \
&& update-locale LANG=en_US.UTF-8 \
&& apt-get clean
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list && \
apt-get update && apt-get install -y gh && \
apt-get clean
RUN mkdir -p $ANDROID_HOME/cmdline-tools/latest && \
wget https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip -O /tmp/cmdline-tools.zip && \
unzip /tmp/cmdline-tools.zip -d $ANDROID_HOME/cmdline-tools/latest && \
mv $ANDROID_HOME/cmdline-tools/latest/cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest/ && \
rm -rf $ANDROID_HOME/cmdline-tools/latest/cmdline-tools && \
rm -f /tmp/cmdline-tools.zip && \
yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses && \
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "platform-tools" "platforms;android-31" "platforms;android-34" "build-tools;34.0.0"
RUN wget https://github.com/lzhiyong/android-sdk-tools/releases/download/34.0.3/android-sdk-tools-static-aarch64.zip -O /tmp/android-sdk-tools-static-aarch64.zip && \
unzip /tmp/android-sdk-tools-static-aarch64.zip -d /tmp/android-sdk-tools-static-arm && \
cp -r /tmp/android-sdk-tools-static-arm/build-tools/* $ANDROID_HOME/build-tools/34.0.0/ && \
rm -rf /tmp/android-sdk-tools-static-arm /tmp/android-sdk-tools-static-aarch64.zip
RUN gem install bundler:2.5.23
RUN gem install fastlane -v 2.225.0 -N -V
RUN gem install fastlane-plugin-firebase_app_distribution -v 0.9.1 -N -V
COPY ../Gemfile Gemfile.lock ./
RUN bundle install --jobs=4 --retry=3 --verbose
RUN bundle exec fastlane -v
CMD ["bash"]

View file

@ -1,26 +0,0 @@
FROM ubuntu:24.04
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
locales \
curl \
git \
&& locale-gen en_US.UTF-8 \
&& update-locale LANG=en_US.UTF-8 \
&& apt-get clean
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list && \
apt-get update && apt-get install -y gh && \
apt-get clean
RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
apt-get install -y git-lfs && \
git lfs install && \
apt-get clean
CMD ["bash"]

View file

@ -8,6 +8,6 @@ org.gradle.caching=false
android.useAndroidX=true
android.nonTransitiveRClass=false
android.aapt2FromMavenOverride=/opt/android-sdk/build-tools/34.0.0/aapt2
android.aapt2FromMavenOverride=/opt/android-sdk/build-tools/35.0.0/aapt2
kotlin.incremental=false

View file

@ -28,9 +28,9 @@ internal class DefaultVersionProvider @Inject constructor(
context.packageName,
PackageManager.PackageInfoFlags.of(0),
)
.versionName
.versionName!!
} else {
context.packageManager.getPackageInfo(context.packageName, 0).versionName
context.packageManager.getPackageInfo(context.packageName, 0).versionName!!
}
}

View file

@ -1,13 +1,19 @@
plugins {
alias(deps.plugins.kotlin.jvm)
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
alias(deps.plugins.kotlin.kapt)
id("configuration")
}
android {
namespace = "com.tangem.core.decompose"
}
dependencies {
api(projects.core.utils)
api(deps.decompose)
api(deps.androidx.appCompat)
implementation(deps.kotlin.coroutines)
implementation(deps.hilt.core)

View file

@ -4,6 +4,7 @@ import com.arkivanov.decompose.ComponentContext
import com.tangem.core.decompose.di.HiltComponentBuilderOwner
import com.tangem.core.decompose.navigation.NavigationOwner
import com.tangem.core.decompose.ui.UiMessageSenderOwner
import com.tangem.core.decompose.utils.ActivityHolder
import com.tangem.core.decompose.utils.ComponentScopeOwner
import com.tangem.core.decompose.utils.DispatchersOwner
import com.tangem.core.decompose.utils.TagsOwner
@ -20,4 +21,5 @@ interface AppComponentContext :
DispatchersOwner,
UiMessageSenderOwner,
HiltComponentBuilderOwner,
TagsOwner
TagsOwner,
ActivityHolder

View file

@ -10,6 +10,7 @@ import com.tangem.core.decompose.ui.DefaultUiMessageSender
import com.tangem.core.decompose.ui.UiMessageHandler
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.decompose.ui.UiMessageSenderOwner
import com.tangem.core.decompose.utils.ActivityHolder
import com.tangem.core.decompose.utils.ComponentCoroutineScope
import com.tangem.core.decompose.utils.DispatchersOwner
import kotlinx.coroutines.CoroutineScope
@ -58,7 +59,8 @@ fun AppComponentContext.childByContext(
NavigationOwner by this@childByContext,
UiMessageSenderOwner by this@childByContext,
DispatchersOwner by this@childByContext,
HiltComponentBuilderOwner by this@childByContext {
HiltComponentBuilderOwner by this@childByContext,
ActivityHolder by this@childByContext {
override val tags: HashMap<String, Any> = HashMap()

View file

@ -1,5 +1,6 @@
package com.tangem.core.decompose.context
import androidx.appcompat.app.AppCompatActivity
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.essenty.instancekeeper.getOrCreate
import com.tangem.core.decompose.di.ModelComponent
@ -17,6 +18,7 @@ class DefaultAppComponentContext(
override val dispatchers: CoroutineDispatcherProvider,
override val hiltComponentBuilder: ModelComponent.Builder,
override val messageSender: UiMessageSender,
override val activity: AppCompatActivity,
private val replaceRouter: Router? = null,
) : AppComponentContext, ComponentContext by componentContext {

View file

@ -0,0 +1,16 @@
package com.tangem.core.decompose.utils
import androidx.appcompat.app.AppCompatActivity
/**
* Interface for holding an [AppCompatActivity] instance.
*
* This interface is used to provide access to the activity in which the component is running.
*/
interface ActivityHolder {
/**
* The [AppCompatActivity] instance associated with this context.
*/
val activity: AppCompatActivity
}

View file

@ -19,7 +19,7 @@ platform :android do
desc "Run detekt"
lane :detekt do
FileUtils.cp("../ci_resources/tests_8gb_ram_ci_gradle.properties", "../gradle.properties")
FileUtils.cp("../ci_resources/tests_ci_gradle.properties", "../gradle.properties")
puts File.read("../gradle.properties")
gradle(task: "detekt")
end
@ -27,7 +27,7 @@ platform :android do
desc "Run tests"
lane :test do
FileUtils.cp("../app/src/main/assets/tangem-app-config/android/google-services/dev/google-services.json", "../app")
FileUtils.cp("../ci_resources/tests_8gb_ram_ci_gradle.properties", "../gradle.properties")
FileUtils.cp("../ci_resources/tests_ci_gradle.properties", "../gradle.properties")
puts File.read("../gradle.properties")
gradle(task: "testDebugUnitTest")
end

1
features/kyc/api/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,22 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
id("configuration")
}
android {
namespace = "com.tangem.features.kyc.api"
}
dependencies {
/* Project - Domain */
implementation(projects.domain.models)
/* Project - Core */
implementation(projects.core.decompose)
implementation(projects.core.ui)
/* Compose */
implementation(deps.compose.runtime)
}

View file

@ -0,0 +1,12 @@
package com.tangem.features.kyc
import com.tangem.core.decompose.context.AppComponentContext
interface KycComponent {
fun launch()
interface Factory {
fun create(appComponentContext: AppComponentContext): KycComponent
}
}

1
features/kyc/impl/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,54 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
alias(deps.plugins.kotlin.kapt)
alias(deps.plugins.kotlin.serialization)
alias(deps.plugins.hilt.android)
id("configuration")
}
android {
namespace = "com.tangem.features.kyc.impl"
}
dependencies {
/** Api */
implementation(projects.features.kyc.api)
/** Core modules */
implementation(projects.core.configToggles)
implementation(projects.core.analytics)
implementation(projects.core.analytics.models)
implementation(projects.core.utils)
implementation(projects.core.ui)
implementation(projects.core.res)
implementation(projects.core.decompose)
implementation(projects.core.navigation)
implementation(projects.core.datasource)
/** Common */
implementation(projects.common.ui)
implementation(projects.common.routing)
/** Compose libraries */
implementation(deps.compose.material3)
implementation(deps.compose.animation)
implementation(deps.compose.foundation)
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.compose.coil)
implementation(deps.lottie.compose)
implementation(deps.decompose.ext.compose)
implementation(deps.androidx.activity.compose)
/** Other libraries */
implementation(deps.kotlin.immutable.collections)
implementation(deps.kotlin.serialization)
implementation(deps.timber)
implementation(deps.firebase.crashlytics)
implementation(deps.sumsub.sdk)
/** DI */
implementation(deps.hilt.android)
kapt(deps.hilt.kapt)
}

View file

@ -0,0 +1,39 @@
package com.tangem.features.kyc
import com.sumsub.sns.core.SNSMobileSDK
import com.sumsub.sns.core.data.listener.TokenExpirationHandler
import com.tangem.core.decompose.context.AppComponentContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.Locale
class DefaultKycComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
) : KycComponent, AppComponentContext by appComponentContext {
override fun launch() {
val accessToken = "123456"
val tokenExpirationHandler = object : TokenExpirationHandler {
override fun onTokenExpired(): String? {
// Access token expired
// get a new one and pass it to the callback to re-initiate the SDK
val newToken = "..." // get a new token from your backend
return newToken
}
}
val snsSdk = SNSMobileSDK.Builder(activity)
.withAccessToken(accessToken, onTokenExpiration = tokenExpirationHandler)
.withLocale(Locale("en"))
.build()
snsSdk.launch()
}
@AssistedFactory
interface Factory : KycComponent.Factory {
override fun create(appComponentContext: AppComponentContext): DefaultKycComponent
}
}

View file

@ -0,0 +1,16 @@
package com.tangem.features.kyc.di
import com.tangem.features.kyc.DefaultKycComponent
import com.tangem.features.kyc.KycComponent
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
internal interface FeatureModule {
@Binds
fun bindComponentFactory(impl: DefaultKycComponent.Factory): KycComponent.Factory
}

View file

@ -15,7 +15,7 @@ firebasePerf = "1.4.2"
androidxActivityCompose = "1.8.0"
androidxAppCompat = "1.5.1"
androidxBrowser = "1.4.0"
androidxConstraintLayout = "2.1.4"
androidxConstraintLayout = "2.2.1"
androidxKtx = "1.9.0"
androidxSplashScreen = "1.0.1"
androidxFragment = "1.8.5"
@ -32,7 +32,7 @@ compose-runtime = "1.7.4"
compose-foundation = "1.7.4"
compose-material = "1.7.4"
compose-material3 = "1.3.1"
compose-constraint = "1.0.1"
compose-constraint = "1.1.1"
compose-navigation = "2.7.7"
compose-accompanist = "0.30.1"
compose-paging = "3.2.1"
@ -90,6 +90,7 @@ room = "2.6.1"
markdown = "0.7.2"
markdownComposeView = "0.5.4"
usedesk = "4.4.0"
sumsub = "1.36.0"
# endregion Other libraries
# region Tools
@ -277,4 +278,5 @@ markdown = { module = "org.jetbrains:markdown", version.ref = "markdown" }
markdown-composeview = { module = "com.github.jeziellago:compose-markdown", version.ref = "markdownComposeView" }
usedesk-chat-sdk = { module = "com.github.Usedesk.Android_SDK:chat-sdk", version.ref = "usedesk" }
usedesk-chat-gui = { module = "com.github.Usedesk.Android_SDK:chat-gui", version.ref = "usedesk" }
sumsub-sdk = { module = "com.sumsub.sns:idensic-mobile-sdk", version.ref = "sumsub" }
# endregion Other

View file

@ -6,6 +6,6 @@ internal object AppConfig {
const val versionName = "1.0.0-SNAPSHOT"
// const val versionName = "100.0.0-SNAPSHOT" //TODO: [REDACTED_JIRA]
const val minSdkVersion = 24
const val targetSdkVersion = 34
const val compileSdkVersion = 34
const val targetSdkVersion = 35
const val compileSdkVersion = 35
}

View file

@ -118,6 +118,7 @@ dependencyResolutionManagement {
}
}
maven("https://jitpack.io")
maven("https://maven.sumsub.com/repository/maven-public/")
}
versionCatalogs {
@ -247,6 +248,9 @@ include(":features:walletconnect:impl")
include(":features:hot-wallet:api")
include(":features:hot-wallet:impl")
include(":features:kyc:api")
include(":features:kyc:impl")
// endregion Feature modules
// region Domain modules

@ -1 +1 @@
Subproject commit 53e359bc2ead37feeb9e70d7004c91cde07ccf9b
Subproject commit 8d971eb9d901358419da78408ecf7dc3f0c4331f