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