1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-07 21:37:02 +09:00

DROID-3637 Chats | Enhancement | Open chat by push notification (#2425)

This commit is contained in:
Evgenii Kozlov 2025-05-21 16:39:08 +02:00 committed by GitHub
parent 89c9ef6ad9
commit 6ff5b57790
Signed by: github
GPG key ID: B5690EEEBB952194
4 changed files with 96 additions and 10 deletions

View file

@ -11,6 +11,8 @@ import androidx.core.app.NotificationCompat
import com.anytypeio.anytype.R
import com.anytypeio.anytype.app.AndroidApplication
import com.anytypeio.anytype.core_models.DecryptedPushContent
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_ui.views.Relations1
import com.anytypeio.anytype.domain.device.DeviceTokenStoringService
import com.anytypeio.anytype.presentation.notifications.DecryptionPushContentService
import com.anytypeio.anytype.ui.main.MainActivity
@ -87,11 +89,11 @@ class AnytypePushService : FirebaseMessagingService() {
Timber.d("New message received: $message")
// Create an intent to open the app when notification is tapped
//todo extra task on Navigation
val intent = Intent(this, MainActivity::class.java).apply {
action = ACTION_OPEN_CHAT
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
putExtra(EXTRA_CHAT_ID, message.chatId)
putExtra(EXTRA_SPACE_ID, message.spaceName)
putExtra(Relations.CHAT_ID, message.chatId)
putExtra(Relations.SPACE_ID, message.spaceName)
}
val pendingIntent = PendingIntent.getActivity(
@ -145,9 +147,7 @@ class AnytypePushService : FirebaseMessagingService() {
private const val PAYLOAD_KEY = "x-any-payload"
private const val KEY_ID_KEY = "x-any-key-id"
private const val CHANNEL_NAME = "Chat Messages"
val EXTRA_CHAT_ID = "chatId"
val EXTRA_SPACE_ID = "spaceId"
private const val NOTIFICATION_REQUEST_CODE = 100
const val ACTION_OPEN_CHAT = "com.anytype.ACTION_OPEN_CHAT"
}
}

View file

@ -69,7 +69,7 @@ class ChatFragment : BaseComposeFragment() {
private val vm by viewModels<ChatViewModel> { factory }
private val ctx get() = arg<Id>(CTX_KEY)
val ctx get() = arg<Id>(CTX_KEY)
private val space get() = arg<Id>(SPACE_KEY)
// Rendering

View file

@ -20,6 +20,7 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavOptions
import androidx.navigation.NavOptions.*
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import com.anytypeio.anytype.BuildConfig
import com.anytypeio.anytype.R
import com.anytypeio.anytype.analytics.base.EventsDictionary
@ -29,6 +30,7 @@ import com.anytypeio.anytype.app.DefaultAppActionManager
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.ThemeMode
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.core_models.multiplayer.SpaceType
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_utils.ext.Mimetype
import com.anytypeio.anytype.core_utils.ext.parseActionSendMultipleUris
@ -36,6 +38,7 @@ import com.anytypeio.anytype.core_utils.ext.parseActionSendUri
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
import com.anytypeio.anytype.device.AnytypePushService
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.theme.GetTheme
@ -205,13 +208,37 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
is Command.Deeplink.DeepLinkToObjectNotWorking -> {
toast(getString(R.string.multiplayer_deeplink_to_your_object_error))
}
is Command.LaunchChat -> {
runCatching {
val controller = findNavController(R.id.fragment)
controller.popBackStack(R.id.vaultScreen, false)
controller.navigate(
R.id.actionOpenSpaceFromVault,
HomeScreenFragment.args(
space = command.space,
deeplink = null
)
)
controller.navigate(
R.id.chatScreen,
ChatFragment.args(
space = command.space,
ctx = command.chat
)
)
}.onFailure {
if (BuildConfig.DEBUG) {
toast("Failed to open chat from push notification")
}
}
}
is Command.Deeplink.DeepLinkToObject -> {
when(val effect = command.sideEffect) {
is Command.Deeplink.DeepLinkToObject.SideEffect.SwitchSpace -> {
runCatching {
val controller = findNavController(R.id.fragment)
controller.popBackStack(R.id.vaultScreen, false)
if (effect.chat != null) {
if (effect.chat != null && effect.spaceType == SpaceType.CHAT) {
controller.navigate(
R.id.actionOpenChatFromVault,
ChatFragment.args(
@ -449,6 +476,34 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
AnytypeNotificationService.NOTIFICATION_INTENT_ACTION -> {
proceedWithNotificationIntent(intent)
}
AnytypePushService.ACTION_OPEN_CHAT -> {
proceedWithOpenChatIntent(intent)
}
}
}
private fun proceedWithOpenChatIntent(intent: Intent) {
val chatId = intent.getStringExtra(Relations.CHAT_ID)
val spaceId = intent.getStringExtra(Relations.SPACE_ID)
if (!chatId.isNullOrEmpty() && !spaceId.isNullOrEmpty()) {
if (!isChatFragmentVisible(chatId)) {
vm.onOpenChatTriggeredByPush(
chatId = chatId,
spaceId = spaceId
)
} else {
// Do nothing, already there.
}
}
}
private fun isChatFragmentVisible(chatId: String): Boolean {
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment) as? NavHostFragment
val currentFragment = navHostFragment?.childFragmentManager?.fragments?.firstOrNull()
return if (currentFragment is ChatFragment) {
currentFragment.ctx == chatId
} else {
false
}
}
@ -720,7 +775,6 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
}
companion object {
const val AUTO_UPDATE_URL = "https://fra1.digitaloceanspaces.com/anytype-release/latest-android.json"
const val SHARE_DIALOG_LABEL = "anytype.dialog.share.label"
const val SHARE_IMAGE_INTENT_PATTERN = "image/"
const val SHARE_VIDEO_INTENT_PATTERN = "video/"

View file

@ -12,6 +12,7 @@ import com.anytypeio.anytype.core_models.NotificationPayload
import com.anytypeio.anytype.core_models.NotificationStatus
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.core_models.exceptions.NeedToUpdateApplicationException
import com.anytypeio.anytype.core_models.multiplayer.SpaceType
import com.anytypeio.anytype.core_utils.ext.cancel
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
import com.anytypeio.anytype.domain.account.InterceptAccountStatus
@ -451,6 +452,31 @@ class MainViewModel(
}
}
fun onOpenChatTriggeredByPush(chatId: String, spaceId: String) {
viewModelScope.launch {
if (spaceManager.get() != spaceId) {
spaceManager.set(spaceId)
.onSuccess {
commands.emit(
Command.LaunchChat(
space = spaceId,
chat = chatId
)
)
}.onFailure {
Timber.e(it, "Error while switching space when launching chat from push notification")
}
} else {
commands.emit(
Command.LaunchChat(
space = spaceId,
chat = chatId
)
)
}
}
}
sealed class Command {
data class ShowDeletedAccountScreen(val deadline: Long) : Command()
data object LogoutDueToAccountDeletion : Command()
@ -467,6 +493,11 @@ class MainViewModel(
data object Notifications: Command()
data object RequestNotificationPermission: Command()
data class LaunchChat(
val space: Id,
val chat: Id
): Command()
data class Navigate(val destination: OpenObjectNavigation): Command()
sealed class Deeplink : Command() {
@ -480,7 +511,8 @@ class MainViewModel(
sealed class SideEffect {
data class SwitchSpace(
val home: Id,
val chat: Id?
val chat: Id? = null,
val spaceType: SpaceType? = null
): SideEffect()
}
}