1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-2722 Membership | Open tier deeplink (#1493)

This commit is contained in:
Konstantin Ivanov 2024-08-22 10:07:48 +02:00 committed by GitHub
parent 3104a623c0
commit e7a37b4299
Signed by: github
GPG key ID: B5690EEEBB952194
9 changed files with 95 additions and 2 deletions

View file

@ -66,6 +66,13 @@
<data android:scheme="anytype" />
<data android:host="object" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="anytype" />
<data android:host="membership" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />

View file

@ -20,12 +20,14 @@ const val MAIN_PATH = "main"
const val OBJECT_PATH = "object"
const val IMPORT_PATH = "import"
const val INVITE_PATH = "invite"
const val MEMBERSHIP_PATH = "membership"
const val TYPE_PARAM = "type"
const val OBJECT_ID_PARAM = "objectId"
const val SPACE_ID_PARAM = "spaceId"
const val SOURCE_PARAM = "source"
const val TYPE_VALUE_EXPERIENCE = "experience"
const val TIER_ID_PARAM = "tier"
const val IMPORT_EXPERIENCE_DEEPLINK = "$DEEP_LINK_PATTERN$MAIN_PATH/$IMPORT_PATH/?$TYPE_PARAM=$TYPE_VALUE_EXPERIENCE"
@ -67,6 +69,12 @@ object DefaultDeepLinkResolver : DeepLinkResolver {
DeepLinkResolver.Action.Unknown
}
}
deeplink.contains(MEMBERSHIP_PATH) -> {
val uri = Uri.parse(deeplink)
DeepLinkResolver.Action.DeepLinkToMembership(
tierId = uri.getQueryParameter(TIER_ID_PARAM)
)
}
else -> DeepLinkResolver.Action.Unknown
}

View file

@ -16,6 +16,7 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavOptions
import androidx.navigation.fragment.findNavController
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
@ -36,6 +37,7 @@ import com.anytypeio.anytype.ui.gallery.GalleryInstallationFragment
import com.anytypeio.anytype.ui.multiplayer.RequestJoinSpaceFragment
import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment
import com.anytypeio.anytype.ui.objects.creation.SelectObjectTypeFragment
import com.anytypeio.anytype.ui.payments.MembershipFragment
import com.anytypeio.anytype.ui.settings.space.SpaceSettingsFragment
import com.anytypeio.anytype.ui.settings.typography
import com.anytypeio.anytype.ui.widgets.SelectWidgetSourceFragment
@ -245,6 +247,13 @@ class HomeScreenFragment : BaseComposeFragment() {
)
)
}
is Command.Deeplink.MembershipScreen -> {
findNavController().navigate(
R.id.paymentsScreen,
MembershipFragment.args(command.tierId),
NavOptions.Builder().setLaunchSingleTop(true).build()
)
}
is Command.Deeplink.DeepLinkToObjectNotWorking -> {
toast(
getString(R.string.multiplayer_deeplink_to_your_object_error)

View file

@ -55,6 +55,7 @@ import com.anytypeio.anytype.ui.multiplayer.RequestJoinSpaceFragment
import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment
import com.anytypeio.anytype.ui.multiplayer.SpaceJoinRequestFragment
import com.anytypeio.anytype.ui.notifications.NotificationsFragment
import com.anytypeio.anytype.ui.payments.MembershipFragment
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
import com.anytypeio.anytype.ui.sharing.SharingFragment
import com.anytypeio.anytype.ui_settings.appearance.ThemeApplicator
@ -251,6 +252,17 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
Timber.e(it, "Error while navigation for deep link invite")
}
}
is Command.Deeplink.MembershipScreen -> {
runCatching {
findNavController(R.id.fragment).navigate(
R.id.paymentsScreen,
MembershipFragment.args(tierId = command.tierId),
NavOptions.Builder().setLaunchSingleTop(true).build()
)
}.onFailure {
Timber.w(it, "Error while navigation for deep link membership tier")
}
}
}
}
}

View file

@ -12,6 +12,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.res.stringResource
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
@ -23,6 +24,7 @@ import com.anytypeio.anytype.BuildConfig
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.ComposeDialogView
import com.anytypeio.anytype.core_ui.views.BaseTwoButtonsDarkThemeAlertDialog
import com.anytypeio.anytype.core_utils.ext.argOrNull
import com.anytypeio.anytype.core_utils.ext.setupBottomSheetBehavior
import com.anytypeio.anytype.core_utils.ext.subscribe
import com.anytypeio.anytype.core_utils.ext.toast
@ -59,6 +61,8 @@ class MembershipFragment : BaseBottomSheetComposeFragment() {
private val vm by viewModels<MembershipViewModel> { factory }
private lateinit var navController: NavHostController
private val argTierId get() = argOrNull<String>(ARG_TIER_ID)
@Inject
lateinit var billingClientLifecycle: BillingClientLifecycle
@ -183,6 +187,7 @@ class MembershipFragment : BaseBottomSheetComposeFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
vm.showTierOnStart(tierId = argTierId)
setupBottomSheetBehavior(DEFAULT_PADDING_TOP)
subscribe(vm.navigation) { command ->
Timber.d("MembershipFragment command: $command")
@ -209,10 +214,12 @@ class MembershipFragment : BaseBottomSheetComposeFragment() {
toast("Couldn't parse url: ${command.url}")
}
}
MembershipNavigation.Main -> {}
is MembershipNavigation.OpenEmail -> {
val mail = resources.getString(R.string.payments_email_to)
val subject = resources.getString(R.string.payments_email_subject, command.accountId)
val subject =
resources.getString(R.string.payments_email_subject, command.accountId)
val body = resources.getString(R.string.payments_email_body)
val mailBody = mail +
"?subject=$subject" +
@ -228,7 +235,8 @@ class MembershipFragment : BaseBottomSheetComposeFragment() {
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
currentDateTime = sdf.format(Date())
val mail = resources.getString(R.string.membership_support_email)
val subject = resources.getString(R.string.membership_support_subject, command.accountId)
val subject =
resources.getString(R.string.membership_support_subject, command.accountId)
val body = getString(
R.string.membership_support_body,
command.error, currentDateTime, deviceModel, osVersion, appVersion
@ -260,4 +268,9 @@ class MembershipFragment : BaseBottomSheetComposeFragment() {
override fun releaseDependencies() {
componentManager().membershipComponent.release()
}
companion object {
const val ARG_TIER_ID = "args.membership.tier"
fun args(tierId: String?) = bundleOf(ARG_TIER_ID to tierId)
}
}

View file

@ -2,6 +2,7 @@ package com.anytypeio.anytype.domain.misc
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_models.membership.TierId
import com.anytypeio.anytype.core_models.primitives.SpaceId
interface DeepLinkResolver {
@ -22,5 +23,8 @@ interface DeepLinkResolver {
val obj: Id,
val space: SpaceId
) : Action()
data class DeepLinkToMembership(
val tierId: String?
) : Action()
}
}

View file

@ -22,6 +22,7 @@ import com.anytypeio.anytype.domain.payments.SetMembershipEmail
import com.anytypeio.anytype.domain.payments.VerifyMembershipEmailCode
import com.anytypeio.anytype.core_models.membership.MembershipConstants.EXPLORER_ID
import com.anytypeio.anytype.core_models.membership.MembershipConstants.MEMBERSHIP_NAME_MIN_LENGTH
import com.anytypeio.anytype.core_models.membership.MembershipConstants.NONE_ID
import com.anytypeio.anytype.payments.mapping.toMainView
import com.anytypeio.anytype.payments.models.MembershipPurchase
import com.anytypeio.anytype.payments.models.TierAnyName
@ -46,6 +47,8 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import timber.log.Timber
@ -71,6 +74,8 @@ class MembershipViewModel(
val navigation = MutableSharedFlow<MembershipNavigation>(0)
private val _showTierOnStart = MutableStateFlow(NONE_ID)
/**
* Local billing purchase data.
*/
@ -93,6 +98,17 @@ class MembershipViewModel(
val anyEmailState = TextFieldState(initialText = "")
init {
Timber.i("MembershipViewModel, init")
viewModelScope.launch {
combine(
_showTierOnStart.filter { it != NONE_ID },
viewState.filterIsInstance<MembershipMainState.Default>()
) { tierId, _ -> tierId }.collect { tierId ->
Timber.d("_showTierOnStart, get new value:$tierId")
proceedWithShowingTier(TierId(tierId))
}
}
viewModelScope.launch {
val account = getAccount.async(Unit)
val accountId = account.getOrNull()?.id.orEmpty()
@ -131,6 +147,13 @@ class MembershipViewModel(
}
}
fun showTierOnStart(tierId: String?) {
val tier = tierId?.toIntOrNull()
if (tier != null && tier != NONE_ID) {
_showTierOnStart.value = tier
}
}
private fun proceedWithUpdatingVisibleTier(mainState: MembershipMainState) {
val actualTier = tierState.value
if (actualTier is MembershipTierState.Visible && mainState is MembershipMainState.Default) {

View file

@ -1272,6 +1272,15 @@ class HomeScreenViewModel(
}
}
}
is DeepLinkResolver.Action.DeepLinkToMembership -> {
viewModelScope.launch {
commands.emit(
Command.Deeplink.MembershipScreen(
tierId = deeplink.tierId
)
)
}
}
else -> {
Timber.d("No deep link")
}
@ -2190,6 +2199,7 @@ sealed class Command {
val deepLinkType: String,
val deepLinkSource: String
) : Deeplink()
data class MembershipScreen(val tierId: String?) : Deeplink()
}
}

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.membership.TierId
import com.anytypeio.anytype.core_utils.ext.cancel
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
import com.anytypeio.anytype.domain.account.InterceptAccountStatus
@ -350,6 +351,11 @@ class MainViewModel(
}
}
}
is DeepLinkResolver.Action.DeepLinkToMembership -> {
commands.emit(
Command.Deeplink.MembershipScreen(tierId = deeplink.tierId)
)
}
else -> {
Timber.d("No deep link")
}
@ -381,6 +387,7 @@ class MainViewModel(
val deepLinkType: String,
val deepLinkSource: String
) : Deeplink()
data class MembershipScreen(val tierId: String?) : Deeplink()
}
}