diff --git a/app/build.gradle b/app/build.gradle index e4e6c2444c..6bf7f8bab2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -230,6 +230,9 @@ dependencies { implementation libs.room + implementation platform(libs.firebaseBom) + implementation libs.firebaseMessaging + implementation libs.exoPlayerCore implementation libs.exoPlayerUi diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 07cbba72cb..c5aaf10c78 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -160,6 +160,13 @@ + + + + + diff --git a/app/src/main/java/com/anytypeio/anytype/device/AnytypePushService.kt b/app/src/main/java/com/anytypeio/anytype/device/AnytypePushService.kt new file mode 100644 index 0000000000..b41dcd34a3 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/device/AnytypePushService.kt @@ -0,0 +1,33 @@ +package com.anytypeio.anytype.device + +import com.anytypeio.anytype.app.AndroidApplication +import com.anytypeio.anytype.domain.device.DeviceTokenStoringService +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage +import javax.inject.Inject +import timber.log.Timber + +class AnytypePushService : FirebaseMessagingService() { + + @Inject + lateinit var deviceTokenSavingService: DeviceTokenStoringService + + init { + Timber.d("AnytypePushService initialized") + } + + override fun onCreate() { + (application as AndroidApplication).componentManager.pushContentComponent.get().inject(this) + super.onCreate() + } + + override fun onNewToken(token: String) { + super.onNewToken(token) + Timber.d("New token received: $token") + deviceTokenSavingService.saveToken(token) + } + + override fun onMessageReceived(message: RemoteMessage) { + super.onMessageReceived(message) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt index 0949cc0ced..5746266259 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt @@ -65,6 +65,7 @@ import com.anytypeio.anytype.di.feature.multiplayer.DaggerRequestJoinSpaceCompon import com.anytypeio.anytype.di.feature.multiplayer.DaggerShareSpaceComponent import com.anytypeio.anytype.di.feature.multiplayer.DaggerSpaceJoinRequestComponent import com.anytypeio.anytype.di.feature.notifications.DaggerNotificationComponent +import com.anytypeio.anytype.di.feature.notifications.DaggerPushContentComponent import com.anytypeio.anytype.di.feature.objects.DaggerSelectObjectTypeComponent import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingComponent import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingStartComponent @@ -1137,6 +1138,12 @@ class ComponentManager( .create(params, findComponentDependencies()) } + val pushContentComponent = Component { + DaggerPushContentComponent + .factory() + .create(findComponentDependencies()) + } + class Component(private val builder: () -> T) { private var instance: T? = null diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/notifications/PushDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/notifications/PushDI.kt new file mode 100644 index 0000000000..612be0954b --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/notifications/PushDI.kt @@ -0,0 +1,31 @@ +package com.anytypeio.anytype.di.feature.notifications + +import com.anytypeio.anytype.device.AnytypePushService +import com.anytypeio.anytype.di.common.ComponentDependencies +import com.anytypeio.anytype.domain.device.DeviceTokenStoringService +import dagger.Component +import dagger.Module +import javax.inject.Singleton + +@Singleton +@Component( + dependencies = [PushContentDependencies::class], + modules = [PushContentModule::class], +) +interface PushContentComponent { + @Component.Factory + interface Factory { + fun create(dependency: PushContentDependencies): PushContentComponent + } + + fun inject(service: AnytypePushService) +} + +@Module +object PushContentModule { + +} + +interface PushContentDependencies : ComponentDependencies { + fun deviceTokenSavingService(): DeviceTokenStoringService +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt index 4dfa56b70e..c99f542499 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/EventModule.kt @@ -8,6 +8,7 @@ import com.anytypeio.anytype.data.auth.event.EventDataChannel import com.anytypeio.anytype.data.auth.event.EventRemoteChannel import com.anytypeio.anytype.data.auth.event.FileLimitsDataChannel import com.anytypeio.anytype.data.auth.event.FileLimitsRemoteChannel +import com.anytypeio.anytype.data.auth.event.PushKeyRemoteChannel import com.anytypeio.anytype.data.auth.event.SubscriptionDataChannel import com.anytypeio.anytype.data.auth.event.SubscriptionEventRemoteChannel import com.anytypeio.anytype.data.auth.status.SyncAndP2PStatusEventsStore @@ -128,12 +129,14 @@ object EventModule { logger: MiddlewareProtobufLogger, @Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope, channel: EventHandlerChannel, - syncP2PStore: SyncAndP2PStatusEventsStore + syncP2PStore: SyncAndP2PStatusEventsStore, + pushKeyRemoteChannel: PushKeyRemoteChannel ): EventProxy = EventHandler( scope = scope, logger = logger, channel = channel, - syncP2PStore = syncP2PStore + syncP2PStore = syncP2PStore, + pushKeyRemoteChannel = pushKeyRemoteChannel ) @JvmStatic diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt index b0e8489260..1f180008ac 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt @@ -36,6 +36,7 @@ import com.anytypeio.anytype.di.feature.multiplayer.RequestJoinSpaceDependencies import com.anytypeio.anytype.di.feature.multiplayer.ShareSpaceDependencies import com.anytypeio.anytype.di.feature.multiplayer.SpaceJoinRequestDependencies import com.anytypeio.anytype.di.feature.notifications.NotificationDependencies +import com.anytypeio.anytype.di.feature.notifications.PushContentDependencies import com.anytypeio.anytype.di.feature.objects.SelectObjectTypeDependencies import com.anytypeio.anytype.di.feature.onboarding.OnboardingDependencies import com.anytypeio.anytype.di.feature.onboarding.OnboardingStartDependencies @@ -143,7 +144,8 @@ interface MainComponent : DebugDependencies, CreateObjectTypeDependencies, SpaceTypesDependencies, - SpacePropertiesDependencies + SpacePropertiesDependencies, + PushContentDependencies { fun inject(app: AndroidApplication) @@ -414,4 +416,9 @@ abstract class ComponentDependenciesModule { @IntoMap @ComponentDependenciesKey(SpacePropertiesDependencies::class) abstract fun provideSpacePropertiesDependencies(component: MainComponent): ComponentDependencies + + @Binds + @IntoMap + @ComponentDependenciesKey(PushContentDependencies::class) + abstract fun providePushContentDependencies(component: MainComponent): ComponentDependencies } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt index 8676cde833..111da9952a 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/SubscriptionsModule.kt @@ -1,6 +1,8 @@ package com.anytypeio.anytype.di.main +import android.content.SharedPreferences import com.anytypeio.anytype.core_utils.di.scope.PerScreen +import com.anytypeio.anytype.device.DeviceTokenStoringServiceImpl import com.anytypeio.anytype.di.main.ConfigModule.DEFAULT_APP_COROUTINE_SCOPE import com.anytypeio.anytype.domain.account.AwaitAccountStartManager import com.anytypeio.anytype.domain.auth.repo.AuthRepository @@ -11,12 +13,14 @@ import com.anytypeio.anytype.domain.config.ConfigStorage import com.anytypeio.anytype.domain.debugging.DebugAccountSelectTrace import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.device.NetworkConnectionStatus +import com.anytypeio.anytype.domain.device.DeviceTokenStoringService import com.anytypeio.anytype.domain.event.interactor.SpaceSyncAndP2PStatusProvider import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.DefaultUserPermissionProvider import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider +import com.anytypeio.anytype.domain.notifications.RegisterDeviceToken import com.anytypeio.anytype.domain.objects.DefaultStoreOfObjectTypes import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes @@ -223,14 +227,16 @@ object SubscriptionsModule { permissions: UserPermissionProvider, isSpaceDeleted: SpaceDeletedStatusWatcher, profileSubscriptionManager: ProfileSubscriptionManager, - networkConnectionStatus: NetworkConnectionStatus + networkConnectionStatus: NetworkConnectionStatus, + deviceTokenStoringService: DeviceTokenStoringService ): GlobalSubscriptionManager = GlobalSubscriptionManager.Default( types = types, relations = relations, permissions = permissions, isSpaceDeleted = isSpaceDeleted, profile = profileSubscriptionManager, - networkConnectionStatus = networkConnectionStatus + networkConnectionStatus = networkConnectionStatus, + deviceTokenStoringService = deviceTokenStoringService ) @JvmStatic @@ -259,4 +265,19 @@ object SubscriptionsModule { repo = repo, dispatchers = dispatchers ) + + @JvmStatic + @Provides + @Singleton + fun deviceTokenStoreService( + @Named("encrypted") sharedPreferences: SharedPreferences, + registerDeviceToken: RegisterDeviceToken, + dispatchers: AppCoroutineDispatchers, + @Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope + ): DeviceTokenStoringService = DeviceTokenStoringServiceImpl( + sharedPreferences = sharedPreferences, + registerDeviceToken = registerDeviceToken, + dispatchers = dispatchers, + scope = scope + ) } \ No newline at end of file diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt index 150975cc38..539da80ff3 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Command.kt @@ -710,4 +710,8 @@ sealed class Command { val blockId: Id, val properties: List ) : Command() + + data class RegisterDeviceToken( + val token: String + ) : Command() } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt index bf5c1eaf56..518a23dd7c 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt @@ -105,4 +105,8 @@ class AuthCacheDataStore(private val cache: AuthCache) : AuthDataStore { override suspend fun cancelAccountMigration(account: Id) { throw UnsupportedOperationException() } + + override suspend fun registerDeviceToken(request: Command.RegisterDeviceToken) { + throw UnsupportedOperationException() + } } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt index 7d363ea2f8..949d025c79 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt @@ -121,4 +121,8 @@ class AuthDataRepository( override suspend fun debugExportLogs(dir: String): String { return factory.remote.debugExportLogs(dir) } + + override suspend fun registerDeviceToken(command: Command.RegisterDeviceToken) { + factory.remote.registerDeviceToken(command) + } } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt index fcf7fcd93b..42d8737fce 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt @@ -47,4 +47,6 @@ interface AuthDataStore { suspend fun getNetworkMode(): NetworkModeConfig suspend fun setNetworkMode(modeConfig: NetworkModeConfig) suspend fun debugExportLogs(dir: String): String + + suspend fun registerDeviceToken(request: Command.RegisterDeviceToken) } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt index c7a6233694..7f391c0b97 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemote.kt @@ -28,4 +28,6 @@ interface AuthRemote { suspend fun getVersion(): String suspend fun setInitialParams(command: Command.SetInitialParams) suspend fun debugExportLogs(dir: String): String + + suspend fun registerDeviceToken(command: Command.RegisterDeviceToken) } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt index 02a436335e..a38de2583f 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt @@ -110,4 +110,8 @@ class AuthRemoteDataStore( override suspend fun debugExportLogs(dir: String): String { return authRemote.debugExportLogs(dir) } + + override suspend fun registerDeviceToken(command: Command.RegisterDeviceToken) { + authRemote.registerDeviceToken(command) + } } \ No newline at end of file diff --git a/device/src/main/java/com/anytypeio/anytype/device/DeviceTokenStoringServiceImpl.kt b/device/src/main/java/com/anytypeio/anytype/device/DeviceTokenStoringServiceImpl.kt new file mode 100644 index 0000000000..65b8441bcb --- /dev/null +++ b/device/src/main/java/com/anytypeio/anytype/device/DeviceTokenStoringServiceImpl.kt @@ -0,0 +1,54 @@ +package com.anytypeio.anytype.device + +import android.content.SharedPreferences +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.base.fold +import com.anytypeio.anytype.domain.device.DeviceTokenStoringService +import com.anytypeio.anytype.domain.notifications.RegisterDeviceToken +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import timber.log.Timber + +class DeviceTokenStoringServiceImpl @Inject constructor( + private val sharedPreferences: SharedPreferences, + private val registerDeviceToken: RegisterDeviceToken, + private val dispatchers: AppCoroutineDispatchers, + private val scope: CoroutineScope +) : DeviceTokenStoringService { + + override fun saveToken(token: String) { + scope.launch(dispatchers.io) { + Timber.d("Saving token: $token") + sharedPreferences.edit().apply { + putString(PREF_KEY, token) + apply() + } + } + } + + override fun start() { + val token = sharedPreferences.getString(PREF_KEY, null) + if (!token.isNullOrEmpty()) { + scope.launch(dispatchers.io) { + val params = RegisterDeviceToken.Params(token = token) + registerDeviceToken.async(params).fold( + onSuccess = { + Timber.d("Successfully registered token: $token") + }, + onFailure = { error -> + Timber.w("Failed to register token: $token, error: $error") + } + ) + } + } + } + + override fun stop() { + // Nothing to do here + } + + companion object { + private const val PREF_KEY = "prefs.device_token" + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt index 228eeca2b3..9398c13bb3 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt @@ -64,4 +64,6 @@ interface AuthRepository { suspend fun getNetworkMode(): NetworkModeConfig suspend fun setNetworkMode(modeConfig: NetworkModeConfig) suspend fun debugExportLogs(dir: String): String + + suspend fun registerDeviceToken(command: Command.RegisterDeviceToken) } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/device/DeviceTokenStoringService.kt b/domain/src/main/java/com/anytypeio/anytype/domain/device/DeviceTokenStoringService.kt new file mode 100644 index 0000000000..e98f7d25e7 --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/device/DeviceTokenStoringService.kt @@ -0,0 +1,7 @@ +package com.anytypeio.anytype.domain.device + +interface DeviceTokenStoringService { + fun saveToken(token: String) + fun start() + fun stop() +} \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/notifications/RegisterDeviceToken.kt b/domain/src/main/java/com/anytypeio/anytype/domain/notifications/RegisterDeviceToken.kt new file mode 100644 index 0000000000..e2adc2566d --- /dev/null +++ b/domain/src/main/java/com/anytypeio/anytype/domain/notifications/RegisterDeviceToken.kt @@ -0,0 +1,24 @@ +package com.anytypeio.anytype.domain.notifications + +import com.anytypeio.anytype.core_models.Command +import com.anytypeio.anytype.domain.auth.repo.AuthRepository +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.base.ResultInteractor +import javax.inject.Inject + +class RegisterDeviceToken @Inject constructor( + private val repository: AuthRepository, + dispatchers: AppCoroutineDispatchers +) : ResultInteractor(dispatchers.io) { + + override suspend fun doWork(params: Params) { + val command = Command.RegisterDeviceToken( + token = params.token, + ) + repository.registerDeviceToken(command = command) + } + + data class Params( + val token: String + ) +} \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt b/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt index 12f3328aeb..a81871b08f 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/subscriptions/GlobalSubscriptionManager.kt @@ -1,5 +1,6 @@ package com.anytypeio.anytype.domain.subscriptions +import com.anytypeio.anytype.domain.device.DeviceTokenStoringService import com.anytypeio.anytype.domain.device.NetworkConnectionStatus import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager @@ -19,7 +20,8 @@ interface GlobalSubscriptionManager { private val permissions: UserPermissionProvider, private val isSpaceDeleted: SpaceDeletedStatusWatcher, private val profile: ProfileSubscriptionManager, - private val networkConnectionStatus: NetworkConnectionStatus + private val networkConnectionStatus: NetworkConnectionStatus, + private val deviceTokenStoringService: DeviceTokenStoringService ) : GlobalSubscriptionManager { override fun onStart() { @@ -29,6 +31,7 @@ interface GlobalSubscriptionManager { isSpaceDeleted.onStart() profile.onStart() networkConnectionStatus.start() + deviceTokenStoringService.start() } override fun onStop() { @@ -38,6 +41,7 @@ interface GlobalSubscriptionManager { isSpaceDeleted.onStop() profile.onStop() networkConnectionStatus.stop() + deviceTokenStoringService.stop() } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e0a8cdbdd2..fac531403a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -62,6 +62,7 @@ dataStoreVersion = '1.1.4' amplitudeVersion = '3.35.1' coilComposeVersion = '3.1.0' sentryVersion = '7.13.0' +firebaseBomVersion = "33.13.0" composeQrCodeVersion = '1.0.1' fragmentComposeVersion = "1.8.6" @@ -153,12 +154,14 @@ navigationCompose = { module = "androidx.navigation:navigation-compose", version composeQrCode = { module = "com.lightspark:compose-qr-code", version.ref = "composeQrCodeVersion" } playBilling = { module = "com.android.billingclient:billing", version = "7.1.1" } fragmentCompose = { group = "androidx.fragment", name = "fragment-compose", version.ref = "fragmentComposeVersion" } +firebaseBom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBomVersion" } +firebaseMessaging = { module = "com.google.firebase:firebase-messaging"} [bundles] [plugins] -application = { id = "com.android.application", version = "8.8.2" } -library = { id = "com.android.library", version = "8.8.2" } +application = { id = "com.android.application", version = "8.9.1" } +library = { id = "com.android.library", version = "8.9.1" } kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlinVersion" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokkaVersion" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df97d72b8b..e2847c8200 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt index 9ed98d94b7..ea33a8f17a 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/auth/AuthMiddleware.kt @@ -96,4 +96,8 @@ class AuthMiddleware( override suspend fun debugExportLogs(dir: String): String { return middleware.debugExportLogs(dir) } + + override suspend fun registerDeviceToken(command: Command.RegisterDeviceToken) { + middleware.registerDeviceToken(command = command) + } } \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventHandler.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventHandler.kt index 5dcdbde33c..1e41278207 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventHandler.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/EventHandler.kt @@ -1,6 +1,7 @@ package com.anytypeio.anytype.middleware.interactor import anytype.Event +import com.anytypeio.anytype.data.auth.event.PushKeyRemoteChannel import com.anytypeio.anytype.data.auth.status.SyncAndP2PStatusEventsStore import com.anytypeio.anytype.middleware.EventProxy import java.io.IOException @@ -17,10 +18,14 @@ class EventHandler @Inject constructor( private val logger: MiddlewareProtobufLogger, private val scope: CoroutineScope, private val channel: EventHandlerChannel, - private val syncP2PStore: SyncAndP2PStatusEventsStore + private val syncP2PStore: SyncAndP2PStatusEventsStore, + private val pushKeyRemoteChannel: PushKeyRemoteChannel ) : EventProxy { init { + scope.launch { + pushKeyRemoteChannel.start() + } scope.launch { syncP2PStore.start() } diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt index a75c5ef885..59fb6aa7e5 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/interactor/Middleware.kt @@ -2,6 +2,7 @@ package com.anytypeio.anytype.middleware.interactor import anytype.Rpc import anytype.Rpc.Chat.ReadMessages.ReadType +import anytype.Rpc.PushNotification.RegisterToken.Platform import anytype.model.Block import anytype.model.ParticipantPermissionChange import anytype.model.Range @@ -2978,6 +2979,17 @@ class Middleware @Inject constructor( return response.event.toPayload() } + @Throws(Exception::class) + fun registerDeviceToken(command: Command.RegisterDeviceToken) { + val request = Rpc.PushNotification.RegisterToken.Request( + token = command.token, + platform = Platform.Android + ) + logRequestIfDebug(request) + val (response, time) = measureTimedValue { service.pushNotificationRegisterToken(request) } + logResponseIfDebug(response, time) + } + private fun logRequestIfDebug(request: Any) { if (BuildConfig.DEBUG) { logger.logRequest(request).also { diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt index 0997c16bd5..c6d222c477 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareService.kt @@ -634,4 +634,7 @@ interface MiddlewareService { @Throws(Exception::class) fun blockDataViewRelationSet(request: Rpc.BlockDataview.Relation.Set.Request): Rpc.BlockDataview.Relation.Set.Response + + @Throws(Exception::class) + fun pushNotificationRegisterToken(request: Rpc.PushNotification.RegisterToken.Request): Rpc.PushNotification.RegisterToken.Response } \ No newline at end of file diff --git a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt index 4e87beda07..4977638efc 100644 --- a/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt +++ b/middleware/src/main/java/com/anytypeio/anytype/middleware/service/MiddlewareServiceImplementation.kt @@ -2573,4 +2573,17 @@ class MiddlewareServiceImplementation @Inject constructor( return response } } + + override fun pushNotificationRegisterToken(request: Rpc.PushNotification.RegisterToken.Request): Rpc.PushNotification.RegisterToken.Response { + val encoded = Service.pushNotificationRegisterToken( + Rpc.PushNotification.RegisterToken.Request.ADAPTER.encode(request) + ) + val response = Rpc.PushNotification.RegisterToken.Response.ADAPTER.decode(encoded) + val error = response.error + if (error != null && error.code != Rpc.PushNotification.RegisterToken.Response.Error.Code.NULL) { + throw Exception(error.description) + } else { + return response + } + } } \ No newline at end of file