diff --git a/app/src/main/java/org/futo/circles/extensions/ContextExtensions.kt b/app/src/main/java/org/futo/circles/extensions/ContextExtensions.kt index cf6045dcd2946f279282fd6e2dd4a98a847ab249..7f1f2964139e33c58ab01357285ea1210146163d 100644 --- a/app/src/main/java/org/futo/circles/extensions/ContextExtensions.kt +++ b/app/src/main/java/org/futo/circles/extensions/ContextExtensions.kt @@ -2,6 +2,7 @@ package org.futo.circles.extensions import android.content.Context import android.content.pm.PackageManager +import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.Canvas import android.util.DisplayMetrics @@ -45,4 +46,13 @@ fun Context.getApplicationLabel(packageName: String): String { } catch (e: PackageManager.NameNotFoundException) { packageName } +} + +fun Context.isNightMode(): Boolean { + return when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) { + Configuration.UI_MODE_NIGHT_YES -> true + Configuration.UI_MODE_NIGHT_NO -> false + Configuration.UI_MODE_NIGHT_UNDEFINED -> false + else -> false + } } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt index aa245cebf6501bf4d1888c2844264d928aed4e48..563209e532f3dacf0e56b84098efdccd0d101fec 100644 --- a/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt +++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsFragment.kt @@ -18,6 +18,7 @@ import org.futo.circles.core.extensions.notEmptyDisplayName import org.futo.circles.core.extensions.observeData import org.futo.circles.core.extensions.observeResponse import org.futo.circles.core.extensions.setEnabledViews +import org.futo.circles.core.extensions.setIsVisible import org.futo.circles.core.extensions.showError import org.futo.circles.core.extensions.showSuccess import org.futo.circles.core.extensions.withConfirmation @@ -45,6 +46,11 @@ class SettingsFragment : Fragment(R.layout.fragment_settings) { private fun setupViews() { with(binding) { + tvSubscriptionTitle.setIsVisible(CirclesAppConfig.isGplayFlavor()) + tvManageSubscription.apply { + setIsVisible(CirclesAppConfig.isGplayFlavor()) + setOnClickListener { navigator.navigateToSubscriptionInfo() } + } tvLogout.setOnClickListener { withConfirmation(LogOut()) { loadingDialog.handleLoading(LoadingData(R.string.log_out)) diff --git a/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt b/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt index 1f5a46452a67060390b67e67a4bb7b131f4461c9..eadb9cd58cfc3d33452c7811cfbd7b9dfa8c2550 100644 --- a/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt +++ b/app/src/main/java/org/futo/circles/feature/settings/SettingsNavigator.kt @@ -42,8 +42,16 @@ class SettingsNavigator(private val fragment: SettingsFragment) { } fragment.findNavController() .navigateSafe( - SettingsFragmentDirections.toShareProfileDialogFragment(sharedSpaceId, ShareUrlTypeArg.PROFILE) + SettingsFragmentDirections.toShareProfileDialogFragment( + sharedSpaceId, + ShareUrlTypeArg.PROFILE + ) ) } + fun navigateToSubscriptionInfo() { + fragment.findNavController() + .navigateSafe(SettingsFragmentDirections.toManageSubscriptionDialogFragment()) + } + } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/emoji/EmojiBottomSheet.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/emoji/EmojiBottomSheet.kt index d11becdc83f2c8e5c2ede6085d53b3eb9ceb4ad0..bcda7fd006d7a91e8e4b8fc351fbe9cdd1b5464e 100644 --- a/app/src/main/java/org/futo/circles/feature/timeline/post/emoji/EmojiBottomSheet.kt +++ b/app/src/main/java/org/futo/circles/feature/timeline/post/emoji/EmojiBottomSheet.kt @@ -1,7 +1,6 @@ package org.futo.circles.feature.timeline.post.emoji import android.content.Context -import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -13,6 +12,7 @@ import com.vanniktech.emoji.EmojiTheming import org.futo.circles.R import org.futo.circles.core.base.fragment.TransparentBackgroundBottomSheetDialogFragment import org.futo.circles.databinding.BottomSheetEmojiBinding +import org.futo.circles.extensions.isNightMode interface EmojiPickerListener { fun onEmojiSelected(roomId: String?, eventId: String?, emoji: String) @@ -57,17 +57,20 @@ class EmojiBottomSheet : TransparentBackgroundBottomSheetDialogFragment() { org.futo.circles.core.R.color.post_card_background_color ), primaryColor = ContextCompat.getColor( + requireContext(), + R.color.gray + ), + secondaryColor = ContextCompat.getColor( requireContext(), R.color.blue ), - secondaryColor = Color.RED, dividerColor = ContextCompat.getColor( requireContext(), org.futo.circles.core.R.color.divider_color ), textColor = ContextCompat.getColor( requireContext(), - R.color.black + if (context.isNightMode()) R.color.white else R.color.black ), textSecondaryColor = ContextCompat.getColor( requireContext(), diff --git a/app/src/main/res/drawable/ic_payment.xml b/app/src/main/res/drawable/ic_payment.xml new file mode 100644 index 0000000000000000000000000000000000000000..47ac6382ad2e1f868d4344686d7eed59e41b24eb --- /dev/null +++ b/app/src/main/res/drawable/ic_payment.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#FFFFFF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,18L4,18v-6h16v6zM20,8L4,8L4,6h16v2z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_phone.xml b/app/src/main/res/drawable/ic_phone.xml index 7e2286849a5a46c9f5cea1bbcafd7475b81f0396..49425332d6b1a9285a342aaa64d97c10cab66602 100644 --- a/app/src/main/res/drawable/ic_phone.xml +++ b/app/src/main/res/drawable/ic_phone.xml @@ -1,5 +1,10 @@ -<vector android:height="24dp" android:tint="#000000" - android:viewportHeight="24" android:viewportWidth="24" - android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> - <path android:fillColor="@android:color/white" android:pathData="M16,1L8,1C6.34,1 5,2.34 5,4v16c0,1.66 1.34,3 3,3h8c1.66,0 3,-1.34 3,-3L19,4c0,-1.66 -1.34,-3 -3,-3zM14,21h-4v-1h4v1zM17.25,18L6.75,18L6.75,4h10.5v14z"/> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="#000000" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M16,1L8,1C6.34,1 5,2.34 5,4v16c0,1.66 1.34,3 3,3h8c1.66,0 3,-1.34 3,-3L19,4c0,-1.66 -1.34,-3 -3,-3zM14,21h-4v-1h4v1zM17.25,18L6.75,18L6.75,4h10.5v14z" /> </vector> diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 1d221311d89980068474569a9dbc07ea9a10da26..ab9bc900c322198ab721f638e5eae45ec05dafb6 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -144,6 +144,22 @@ app:optionName="@string/login_sessions" /> + <TextView + android:id="@+id/tvSubscriptionTitle" + style="@style/settingMenuHeader" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/subscription" /> + + <org.futo.circles.core.view.SettingsMenuItemView + android:id="@+id/tvManageSubscription" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:hasDivider="false" + app:optionIcon="@drawable/ic_payment" + app:optionName="@string/manage_subscription" /> + + <TextView style="@style/settingMenuHeader" android:layout_width="match_parent" diff --git a/app/src/main/res/navigation/settings_nav_graph.xml b/app/src/main/res/navigation/settings_nav_graph.xml index d2c5326e308072f691612c09e4fc4a755d129e78..3b0c5d72e44eb15170cf0ca5fc1564219961acbd 100644 --- a/app/src/main/res/navigation/settings_nav_graph.xml +++ b/app/src/main/res/navigation/settings_nav_graph.xml @@ -40,6 +40,9 @@ <action android:id="@+id/to_pushNotificationsSettingsDialogFragment" app:destination="@id/pushNotificationsSettingsDialogFragment" /> + <action + android:id="@+id/to_manageSubscriptionDialogFragment" + app:destination="@id/manageSubscriptionDialogFragment" /> </fragment> <dialog @@ -75,4 +78,9 @@ android:name="org.futo.circles.auth.feature.reauth.ReAuthStagesDialogFragment" tools:layout="@layout/fragment_login_stages" /> + <dialog + android:id="@+id/manageSubscriptionDialogFragment" + android:name="org.futo.circles.auth.feature.manage_subscription.ManageSubscriptionDialogFragment" + tools:layout="@layout/dialog_fragment_manage_subscription" /> + </navigation> \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInFragment.kt index 65b724dd10e40fb364b5809ace58d2bf00a884c2..ec5d06f5d8ea1f4b295b3741a4d1a28c557d4cdb 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInFragment.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/log_in/LogInFragment.kt @@ -16,6 +16,7 @@ import org.futo.circles.auth.feature.log_in.switch_user.list.SwitchUsersViewHold import org.futo.circles.auth.model.RemoveUser import org.futo.circles.core.base.CirclesAppConfig import org.futo.circles.core.base.NetworkObserver +import org.futo.circles.core.base.fragment.HasLoadingState import org.futo.circles.core.base.list.BaseRvDecoration import org.futo.circles.core.extensions.getText import org.futo.circles.core.extensions.navigateSafe @@ -25,7 +26,6 @@ import org.futo.circles.core.extensions.setEnabledViews import org.futo.circles.core.extensions.setIsVisible import org.futo.circles.core.extensions.showError import org.futo.circles.core.extensions.withConfirmation -import org.futo.circles.core.base.fragment.HasLoadingState @AndroidEntryPoint @@ -66,6 +66,7 @@ class LogInFragment : Fragment(R.layout.fragment_log_in), HasLoadingState { private fun setupViews() { with(binding) { + groupSignup.setIsVisible(CirclesAppConfig.isGplayFlavor()) tvDomain.apply { setAdapter(autocompleteAdapter) onFocusChangeListener = OnFocusChangeListener { _, hasFocus -> @@ -87,7 +88,7 @@ class LogInFragment : Fragment(R.layout.fragment_log_in), HasLoadingState { } private fun setupObservers() { - NetworkObserver.observe(this){ setEnabledViews(it) } + NetworkObserver.observe(this) { setEnabledViews(it) } viewModel.loginResultLiveData.observeResponse(this, success = { findNavController().navigateSafe(LogInFragmentDirections.toLoginStagesFragment()) diff --git a/auth/src/main/java/org/futo/circles/auth/feature/manage_subscription/ManageSubscriptionDialogFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/manage_subscription/ManageSubscriptionDialogFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..d5d5b4133a4a6245c29b33f73990d23d133b28ff --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/manage_subscription/ManageSubscriptionDialogFragment.kt @@ -0,0 +1,104 @@ +package org.futo.circles.auth.feature.manage_subscription + +import android.content.ActivityNotFoundException +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.text.format.DateFormat +import android.view.View +import androidx.fragment.app.viewModels +import dagger.hilt.android.AndroidEntryPoint +import org.futo.circles.auth.R +import org.futo.circles.auth.databinding.DialogFragmentManageSubscriptionBinding +import org.futo.circles.auth.model.ActiveSubscriptionInfo +import org.futo.circles.auth.subscriptions.SubscriptionProvider +import org.futo.circles.core.base.fragment.BaseFullscreenDialogFragment +import org.futo.circles.core.extensions.gone +import org.futo.circles.core.extensions.observeResponse +import org.futo.circles.core.extensions.showError +import org.futo.circles.core.extensions.visible +import java.util.Date +import javax.inject.Inject + +@AndroidEntryPoint +class ManageSubscriptionDialogFragment : + BaseFullscreenDialogFragment(DialogFragmentManageSubscriptionBinding::inflate) { + + private val viewModel by viewModels<ManageSubscriptionViewModel>() + + private val binding by lazy { + getBinding() as DialogFragmentManageSubscriptionBinding + } + + @Inject + lateinit var subscriptionProvider: SubscriptionProvider + + private val subscriptionManager by lazy { + subscriptionProvider.getManager(this, null) + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + viewModel.getSubscriptionInfo(subscriptionManager) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupViews() + setupObservers() + } + + private fun setupViews() { + + } + + private fun setupObservers() { + viewModel.subscriptionInfoLiveData.observeResponse( + this, + onRequestInvoked = { binding.vLoading.gone() }, + success = { + binding.lSubscriptionInfo.visible() + bindSubscriptionInfo(it) + }, + error = { + binding.tvEmptyMessage.visible() + }) + } + + private fun bindSubscriptionInfo(subscriptionInfo: ActiveSubscriptionInfo) { + with(binding) { + tvName.text = subscriptionInfo.name + tvDescription.text = subscriptionInfo.description + tvPrice.text = getString(R.string.price_format, subscriptionInfo.price) + tvDuration.text = getString(R.string.duration_format, subscriptionInfo.duration) + tvProductId.text = getString(R.string.product_id_format, subscriptionInfo.productId) + val purchaseDate = + DateFormat.format("MMM dd yyyy, h:mm a", Date(subscriptionInfo.purchaseTime)) + tvPurchasedAt.text = getString(R.string.purchase_time_format, purchaseDate) + tvAutoRenewMessage.text = getString( + if (subscriptionInfo.isAutoRenewing) R.string.is_auto_renew_message + else R.string.is_not_auto_renew_message + ) + btnManageGp.setOnClickListener { + openPlayStoreSubscriptionInfo( + subscriptionInfo.productId, + subscriptionInfo.packageName + ) + } + } + } + + private fun openPlayStoreSubscriptionInfo(sku: String, packageName: String) { + try { + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse("https://play.google.com/store/account/subscriptions?sku=$sku&package=$packageName") + ) + ) + } catch (e: ActivityNotFoundException) { + showError(getString(R.string.can_not_open_google_play)) + } + } +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/manage_subscription/ManageSubscriptionViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/manage_subscription/ManageSubscriptionViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..715e3b4b394d3d90e62029c4990ff325f6872717 --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/feature/manage_subscription/ManageSubscriptionViewModel.kt @@ -0,0 +1,54 @@ +package org.futo.circles.auth.feature.manage_subscription + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import org.futo.circles.auth.model.ActiveSubscriptionInfo +import org.futo.circles.auth.subscriptions.SubscriptionManager +import org.futo.circles.core.base.SingleEventLiveData +import org.futo.circles.core.extensions.Response +import org.futo.circles.core.extensions.launchBg +import javax.inject.Inject + +@HiltViewModel +class ManageSubscriptionViewModel @Inject constructor( +) : ViewModel() { + + val subscriptionInfoLiveData = SingleEventLiveData<Response<ActiveSubscriptionInfo>>() + + fun getSubscriptionInfo(subscriptionManager: SubscriptionManager) { + launchBg { + val activeReceipt = + (subscriptionManager.getActiveSubscriptionReceipt() as? Response.Success)?.data + ?: kotlin.run { + subscriptionInfoLiveData.postValue( + Response.Error("Failed to fetch active subscription info") + ) + return@launchBg + } + val details = + (subscriptionManager.getDetails(listOf(activeReceipt.productId)) as? Response.Success)?.data?.lastOrNull() + ?: kotlin.run { + subscriptionInfoLiveData.postValue( + Response.Error("Failed to fetch active subscription details") + ) + return@launchBg + } + subscriptionInfoLiveData.postValue( + Response.Success( + ActiveSubscriptionInfo( + packageName = activeReceipt.packageName, + productId = activeReceipt.productId, + purchaseTime = activeReceipt.purchaseTime, + isAutoRenewing = activeReceipt.isAutoRenewing, + name = details.name, + description = details.description, + price = details.price, + duration = details.duration + ) + ) + ) + } + } + + +} \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt index 4f2448a7de9735c57ea309bc276c8d6b04d24481..f918bc02a6b7587260b81a1ff073addc076793cd 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignUpDataSource.kt @@ -6,8 +6,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.auth.R import org.futo.circles.auth.bsspeke.BSSpekeClientProvider import org.futo.circles.auth.feature.pass_phrase.create.CreatePassPhraseDataSource -import org.futo.circles.auth.feature.sign_up.subscription_stage.SubscriptionStageDataSource -import org.futo.circles.auth.model.SubscriptionReceiptData import org.futo.circles.core.base.SingleEventLiveData import org.futo.circles.core.extensions.Response import org.futo.circles.core.extensions.createResult @@ -45,35 +43,15 @@ class SignUpDataSource @Inject constructor( var domain: String = "" private set - private val subscriptionStageDataSource = SubscriptionStageDataSource(this) - - suspend fun startSignUpStages( + fun startSignUpStages( stages: List<Stage>, - serverDomain: String, - subscriptionReceiptData: SubscriptionReceiptData? + serverDomain: String ) { currentStage = null stagesToComplete.clear() domain = serverDomain stagesToComplete.addAll(stages) - subscriptionReceiptData?.let { skipSubscriptionStageIfValid(it) } ?: navigateToNextStage() - } - - private suspend fun skipSubscriptionStageIfValid(subscriptionReceiptData: SubscriptionReceiptData) { - setNextStage() - (currentStage as? Stage.Other)?.takeIf { - it.type == REGISTRATION_SUBSCRIPTION_TYPE - } ?: run { - currentStage = null - navigateToNextStage() - return - } - val response = subscriptionStageDataSource.validateSubscription(subscriptionReceiptData) - - if (response is Response.Error) { - currentStage = null - navigateToNextStage() - } + navigateToNextStage() } suspend fun performRegistrationStage( @@ -82,7 +60,11 @@ class SignUpDataSource @Inject constructor( ): Response<RegistrationResult> { val wizard = MatrixInstanceProvider.matrix.authenticationService().getRegistrationWizard() val result = createResult { - wizard.registrationCustom(authParams, context.getString(R.string.initial_device_name), true) + wizard.registrationCustom( + authParams, + context.getString(R.string.initial_device_name), + true + ) } (result as? Response.Success)?.let { diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeDataSource.kt index c7ad4cf4927163a28a17806477abd5cafc61a360..e4fcd63c850fc6c298217eb8e7d1812389062548 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeDataSource.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeDataSource.kt @@ -4,12 +4,9 @@ import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import org.futo.circles.auth.R import org.futo.circles.auth.feature.sign_up.SignUpDataSource -import org.futo.circles.auth.feature.sign_up.SignUpDataSource.Companion.REGISTRATION_SUBSCRIPTION_TYPE -import org.futo.circles.auth.model.SubscriptionReceiptData import org.futo.circles.core.extensions.createResult import org.futo.circles.core.provider.MatrixInstanceProvider import org.futo.circles.core.utils.HomeServerUtils.buildHomeServerConfigFromDomain -import org.matrix.android.sdk.api.auth.registration.Stage import javax.inject.Inject class SelectSignUpTypeDataSource @Inject constructor( @@ -17,35 +14,19 @@ class SelectSignUpTypeDataSource @Inject constructor( private val signUpDataSource: SignUpDataSource ) { - private val authService by lazy { MatrixInstanceProvider.matrix.authenticationService() } - fun clearSubtitle() { signUpDataSource.clearSubtitle() } - suspend fun startNewRegistration( - domain: String, - isSubscription: Boolean, - subscriptionReceiptData: SubscriptionReceiptData? - ) = createResult { - authService.cancelPendingLoginOrRegistration() - authService.initiateAuth(buildHomeServerConfigFromDomain(domain)) - val flows = authService.getRegistrationWizard().getAllRegistrationFlows() - signUpDataSource.startSignUpStages( - prepareStagesList(isSubscription, flows), - domain, - subscriptionReceiptData - ) + suspend fun startNewRegistration(domain: String) = createResult { + val authService = MatrixInstanceProvider.matrix.authenticationService().apply { + cancelPendingLoginOrRegistration() + initiateAuth(buildHomeServerConfigFromDomain(domain)) + } + val stages = authService.getRegistrationWizard().getAllRegistrationFlows().firstOrNull() + ?: throw IllegalArgumentException(context.getString(R.string.wrong_signup_config)) + + signUpDataSource.startSignUpStages(stages, domain) } - private fun prepareStagesList(isSubscription: Boolean, flows: List<List<Stage>>): List<Stage> = - if (isSubscription) { - flows.firstOrNull { - (it.firstOrNull() as? Stage.Other)?.type == REGISTRATION_SUBSCRIPTION_TYPE - } - } else { - flows.firstOrNull { - it.firstOrNull { (it as? Stage.Other)?.type == REGISTRATION_SUBSCRIPTION_TYPE } == null - } - } ?: throw IllegalArgumentException(context.getString(R.string.wrong_signup_config)) } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeFragment.kt index 68be8af73789b0c2e823858832bef291088810dd..47eefff35c557e61587fd8d5a6506dd5ade389fd 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeFragment.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeFragment.kt @@ -9,13 +9,9 @@ import by.kirich1409.viewbindingdelegate.viewBinding import dagger.hilt.android.AndroidEntryPoint import org.futo.circles.auth.R import org.futo.circles.auth.databinding.FragmentSelectSignUpTypeBinding -import org.futo.circles.auth.subscriptions.SubscriptionProvider import org.futo.circles.core.base.CirclesAppConfig -import org.futo.circles.core.extensions.observeData -import org.futo.circles.core.extensions.observeResponse -import org.futo.circles.core.extensions.setIsVisible import org.futo.circles.core.base.fragment.HasLoadingState -import javax.inject.Inject +import org.futo.circles.core.extensions.observeResponse @AndroidEntryPoint class SelectSignUpTypeFragment : Fragment(R.layout.fragment_select_sign_up_type), @@ -26,19 +22,6 @@ class SelectSignUpTypeFragment : Fragment(R.layout.fragment_select_sign_up_type) private val binding by viewBinding(FragmentSelectSignUpTypeBinding::bind) private val viewModel by viewModels<SelectSignUpTypeViewModel>() - @Inject - lateinit var subscriptionProvider: SubscriptionProvider - - private val subscriptionManager by lazy { - subscriptionProvider.getManager(this, null) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (CirclesAppConfig.isSubscriptionsEnabled) - viewModel.getLastActiveSubscriptionReceipt(subscriptionManager) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.clearSubtitle() @@ -48,7 +31,6 @@ class SelectSignUpTypeFragment : Fragment(R.layout.fragment_select_sign_up_type) private fun setupViews() { with(binding) { - groupSubscription.setIsVisible(CirclesAppConfig.isSubscriptionsEnabled) btnEU.text = Html.fromHtml( getString(R.string.eu_server_format, CirclesAppConfig.euServerDomain), Html.FROM_HTML_MODE_COMPACT @@ -58,29 +40,15 @@ class SelectSignUpTypeFragment : Fragment(R.layout.fragment_select_sign_up_type) getString(R.string.us_server_format, CirclesAppConfig.usServerDomain), Html.FROM_HTML_MODE_COMPACT ) - btnToken.setOnClickListener { - startLoading(btnToken) + btnSignup.setOnClickListener { + startLoading(btnSignup) viewModel.startSignUp(getDomain()) } - btnSubscription.setOnClickListener { - startLoading(btnSubscription) - viewModel.startSignUp(getDomain(), true) - } } } private fun setupObservers() { viewModel.startSignUpEventLiveData.observeResponse(this) - viewModel.isSubscribedLiveData.observeData(this) { isSubscribed -> - binding.tvSubscriptionTitle.text = - getString( - if (isSubscribed) R.string.sign_up_using_active_subscription - else R.string.create_a_subscription - ) - binding.btnSubscription.setText( - getString(if (isSubscribed) R.string.sign_up else R.string.choose_a_subscription) - ) - } } private fun getDomain() = when (binding.serverLocationGroup.checkedRadioButtonId) { diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeViewModel.kt index 6675e7b9d0a63aa30921379885b974f96344efaf..79e0b26ff764e47fd0bc86f83ccf57ea16a4f243 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeViewModel.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/sign_up_type/SelectSignUpTypeViewModel.kt @@ -1,10 +1,7 @@ package org.futo.circles.auth.feature.sign_up.sign_up_type -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel -import org.futo.circles.auth.model.SubscriptionReceiptData -import org.futo.circles.auth.subscriptions.SubscriptionManager import org.futo.circles.core.base.SingleEventLiveData import org.futo.circles.core.extensions.Response import org.futo.circles.core.extensions.launchBg @@ -16,21 +13,10 @@ class SelectSignUpTypeViewModel @Inject constructor( ) : ViewModel() { val startSignUpEventLiveData = SingleEventLiveData<Response<Unit?>>() - val isSubscribedLiveData = MutableLiveData(false) - var subscriptionReceiptData: SubscriptionReceiptData? = null - fun startSignUp( - serverDomain: String, - isSubscription: Boolean = false - ) { + fun startSignUp(serverDomain: String) { launchBg { - startSignUpEventLiveData.postValue( - dataSource.startNewRegistration( - serverDomain, - isSubscription, - subscriptionReceiptData - ) - ) + startSignUpEventLiveData.postValue(dataSource.startNewRegistration(serverDomain)) } } @@ -38,16 +24,4 @@ class SelectSignUpTypeViewModel @Inject constructor( dataSource.clearSubtitle() } - fun getLastActiveSubscriptionReceipt(subscriptionManager: SubscriptionManager) { - launchBg { - when (val result = subscriptionManager.getActiveSubscriptionReceipt()) { - is Response.Success -> { - subscriptionReceiptData = result.data - isSubscribedLiveData.postValue(true) - } - - is Response.Error -> isSubscribedLiveData.postValue(false) - } - } - } } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageDataSource.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageDataSource.kt index 36fcba934c027e716aeb0fe69994478c5a17165b..c5504441bd078e6d26374535a7fe74a13e051dba 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageDataSource.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageDataSource.kt @@ -4,7 +4,6 @@ import org.futo.circles.auth.base.BaseLoginStagesDataSource.Companion.TYPE_PARAM import org.futo.circles.auth.feature.sign_up.SignUpDataSource import org.futo.circles.auth.feature.sign_up.SignUpDataSource.Companion.REGISTRATION_SUBSCRIPTION_TYPE import org.futo.circles.auth.model.SubscriptionReceiptData -import org.futo.circles.core.base.CirclesAppConfig import org.futo.circles.core.extensions.Response import org.matrix.android.sdk.api.auth.registration.RegistrationResult import org.matrix.android.sdk.api.auth.registration.Stage @@ -20,7 +19,8 @@ class SubscriptionStageDataSource @Inject constructor( signUpDataSource.performRegistrationStage( mapOf( TYPE_PARAM_KEY to REGISTRATION_SUBSCRIPTION_TYPE, - PACKAGE_KEY to CirclesAppConfig.appId, + ORDER_ID_KEY to subscriptionReceiptData.orderId, + PACKAGE_KEY to subscriptionReceiptData.packageName, SUBSCRIPTION_ID_KEY to subscriptionReceiptData.productId, TOKEN_KEY to subscriptionReceiptData.purchaseToken ) @@ -32,9 +32,10 @@ class SubscriptionStageDataSource @Inject constructor( ?: emptyList() companion object { + private const val ORDER_ID_KEY = "order_id" private const val PACKAGE_KEY = "package" private const val SUBSCRIPTION_ID_KEY = "subscription_id" private const val TOKEN_KEY = "token" - private const val SUBSCRIPTION_IDS_PARAMS_KEY = "subscription_ids" + private const val SUBSCRIPTION_IDS_PARAMS_KEY = "product_ids" } } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageFragment.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageFragment.kt index 00d2e66f1730a5e3b74445bb894022faf476d966..6e723478ab4b6c616af2f1559e655f86bec18c3d 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageFragment.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageFragment.kt @@ -3,7 +3,9 @@ package org.futo.circles.auth.feature.sign_up.subscription_stage import android.os.Bundle import android.view.View import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.DividerItemDecoration import by.kirich1409.viewbindingdelegate.viewBinding +import com.google.android.material.divider.MaterialDividerItemDecoration import dagger.hilt.android.AndroidEntryPoint import org.futo.circles.auth.R import org.futo.circles.auth.databinding.FragmentSubscriptionStageBinding @@ -11,9 +13,9 @@ import org.futo.circles.auth.feature.sign_up.subscription_stage.list.Subscriptio import org.futo.circles.auth.model.SubscriptionReceiptData import org.futo.circles.auth.subscriptions.ItemPurchasedListener import org.futo.circles.auth.subscriptions.SubscriptionProvider +import org.futo.circles.core.base.fragment.ParentBackPressOwnerFragment import org.futo.circles.core.extensions.observeResponse import org.futo.circles.core.extensions.showError -import org.futo.circles.core.base.fragment.ParentBackPressOwnerFragment import javax.inject.Inject @AndroidEntryPoint @@ -46,7 +48,7 @@ class SubscriptionStageFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - viewModel.loadSubscriptionsList(subscriptionManager) + viewModel.initiateSubscriptionStage(subscriptionManager) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -56,7 +58,13 @@ class SubscriptionStageFragment : } private fun setupViews() { - binding.rvSubscriptions.adapter = listAdapter + binding.rvSubscriptions.apply { + addItemDecoration( + MaterialDividerItemDecoration(context, DividerItemDecoration.VERTICAL).apply { + isLastItemDecorated = false + }) + adapter = listAdapter + } } private fun setupObservers() { diff --git a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageViewModel.kt b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageViewModel.kt index fbe82ca2daba5d5fa72a73ac0461a3ea682c8fcc..65d58bc5e206c0c1510c65ae44b45ff15ea5526c 100644 --- a/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageViewModel.kt +++ b/auth/src/main/java/org/futo/circles/auth/feature/sign_up/subscription_stage/SubscriptionStageViewModel.kt @@ -22,15 +22,19 @@ class SubscriptionStageViewModel @Inject constructor( val purchaseLiveData = SingleEventLiveData<Response<Unit>>() val subscriptionsListLiveData = MutableLiveData<Response<List<SubscriptionListItem>>>() - fun validateSubscription(subscriptionReceiptData: SubscriptionReceiptData) { + fun initiateSubscriptionStage(subscriptionManager: SubscriptionManager) { launchBg { - subscribeLiveData.postValue(dataSource.validateSubscription(subscriptionReceiptData)) + when (val activeSubscriptionResult = + getLastActiveSubscriptionReceipt(subscriptionManager)) { + is Response.Success -> validateSubscription(activeSubscriptionResult.data) + is Response.Error -> loadSubscriptionsList(subscriptionManager) + } } } - fun loadSubscriptionsList(subscriptionManager: SubscriptionManager) { + fun validateSubscription(subscriptionReceiptData: SubscriptionReceiptData) { launchBg { - subscriptionsListLiveData.postValue(subscriptionManager.getDetails(dataSource.getProductIdsList())) + subscribeLiveData.postValue(dataSource.validateSubscription(subscriptionReceiptData)) } } @@ -40,4 +44,12 @@ class SubscriptionStageViewModel @Inject constructor( } } + private suspend fun loadSubscriptionsList(subscriptionManager: SubscriptionManager) { + val details = subscriptionManager.getDetails(dataSource.getProductIdsList()) + subscriptionsListLiveData.postValue(details) + } + + private suspend fun getLastActiveSubscriptionReceipt(subscriptionManager: SubscriptionManager) = + subscriptionManager.getActiveSubscriptionReceipt() + } \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/model/ActiveSubscriptionInfo.kt b/auth/src/main/java/org/futo/circles/auth/model/ActiveSubscriptionInfo.kt new file mode 100644 index 0000000000000000000000000000000000000000..88ddce7fc11314869bc6272fa6ca5105a8e7b957 --- /dev/null +++ b/auth/src/main/java/org/futo/circles/auth/model/ActiveSubscriptionInfo.kt @@ -0,0 +1,12 @@ +package org.futo.circles.auth.model + +data class ActiveSubscriptionInfo( + val packageName: String, + val productId: String, + val purchaseTime: Long, + val isAutoRenewing: Boolean, + val name: String, + val description: String, + val price: String, + val duration: String +) \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/model/SubscriptionReceiptData.kt b/auth/src/main/java/org/futo/circles/auth/model/SubscriptionReceiptData.kt index 71a96506c06015ec216624ad213092e4797fd283..19d516ccdbf40835900c5203151cea343eee6c9e 100644 --- a/auth/src/main/java/org/futo/circles/auth/model/SubscriptionReceiptData.kt +++ b/auth/src/main/java/org/futo/circles/auth/model/SubscriptionReceiptData.kt @@ -2,5 +2,9 @@ package org.futo.circles.auth.model data class SubscriptionReceiptData( val productId: String, - val purchaseToken: String + val purchaseToken: String, + val orderId: String, + val packageName: String, + val purchaseTime: Long, + val isAutoRenewing: Boolean ) \ No newline at end of file diff --git a/auth/src/main/java/org/futo/circles/auth/subscriptions/GoogleSubscriptionsManager.kt b/auth/src/main/java/org/futo/circles/auth/subscriptions/GoogleSubscriptionsManager.kt index cce071d6b3979b9f03ca96cd4ffb3f05674c3cde..4e6404053c084b3901b7cf38bc4131b000c6d8b9 100644 --- a/auth/src/main/java/org/futo/circles/auth/subscriptions/GoogleSubscriptionsManager.kt +++ b/auth/src/main/java/org/futo/circles/auth/subscriptions/GoogleSubscriptionsManager.kt @@ -3,6 +3,7 @@ package org.futo.circles.auth.subscriptions import androidx.fragment.app.Fragment import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner +import com.android.billingclient.api.AcknowledgePurchaseParams import com.android.billingclient.api.BillingClient import com.android.billingclient.api.BillingClient.BillingResponseCode.BILLING_UNAVAILABLE import com.android.billingclient.api.BillingClient.BillingResponseCode.DEVELOPER_ERROR @@ -41,14 +42,28 @@ class GoogleSubscriptionsManager( private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> - purchases?.let { - if (billingResult.responseCode == OK) { - purchases.lastOrNull()?.toSubscriptionReceiptData()?.let { - itemPurchasedListener?.onItemPurchased(it) - } ?: itemPurchasedListener?.onPurchaseFailed(ERROR) - } else itemPurchasedListener?.onPurchaseFailed(billingResult.responseCode) + if (billingResult.responseCode == OK && purchases != null) { + purchases.lastOrNull()?.let { + acknowledgePurchase(it) + } ?: kotlin.run { itemPurchasedListener?.onPurchaseFailed(ERROR) } + } else itemPurchasedListener?.onPurchaseFailed(billingResult.responseCode) + } + + private fun acknowledgePurchase(purchase: Purchase) { + if (purchase.purchaseState != Purchase.PurchaseState.PURCHASED) return + if (purchase.isAcknowledged) { + itemPurchasedListener?.onItemPurchased(purchase.toSubscriptionReceiptData()) + return + } + val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() + .setPurchaseToken(purchase.purchaseToken) + client.acknowledgePurchase(acknowledgePurchaseParams.build()) { result -> + when (val code = result.responseCode) { + OK -> itemPurchasedListener?.onItemPurchased(purchase.toSubscriptionReceiptData()) + else -> itemPurchasedListener?.onPurchaseFailed(code) } } + } private val client = BillingClient.newBuilder(fragment.requireContext()) .setListener(purchasesUpdatedListener) @@ -207,8 +222,16 @@ class GoogleSubscriptionsManager( else -> Response.Error(fragment.getString(R.string.purchase_failed_format, code)) } - private fun Purchase.toSubscriptionReceiptData(): SubscriptionReceiptData? { - val productId = products.lastOrNull() ?: return null - return SubscriptionReceiptData(productId, purchaseToken) + private fun Purchase.toSubscriptionReceiptData(): SubscriptionReceiptData { + val orderId = orderId ?: "" + val productId = products.lastOrNull() ?: "" + return SubscriptionReceiptData( + productId, + purchaseToken, + orderId, + packageName, + purchaseTime, + isAutoRenewing + ) } } \ No newline at end of file diff --git a/auth/src/main/res/layout/dialog_fragment_manage_subscription.xml b/auth/src/main/res/layout/dialog_fragment_manage_subscription.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d9a01aaad7447647d1ee82d71ea30572572dd22 --- /dev/null +++ b/auth/src/main/res/layout/dialog_fragment_manage_subscription.xml @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + + <com.google.android.material.appbar.MaterialToolbar + android:id="@+id/toolbar" + android:layout_width="0dp" + android:layout_height="?attr/actionBarSize" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:navigationIcon="?attr/homeAsUpIndicator" + app:title="@string/manage_subscription" + app:titleCentered="true" /> + + + <View + android:id="@+id/toolbarDivider" + android:layout_width="0dp" + android:layout_height="@dimen/divider_height" + android:background="@color/divider_color" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbar" /> + + + <TextView + android:id="@+id/tvEmptyMessage" + style="@style/subheadline" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:gravity="center" + android:paddingHorizontal="16dp" + android:text="@string/you_don_t_have_any_active_subscriptions" + android:textSize="22sp" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbarDivider" + tools:visibility="visible" /> + + <ProgressBar + android:id="@+id/vLoading" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbarDivider" /> + + + <LinearLayout + android:id="@+id/lSubscriptionInfo" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_marginTop="36dp" + android:layout_marginBottom="24dp" + android:gravity="center_horizontal" + android:orientation="vertical" + android:paddingHorizontal="16dp" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/toolbarDivider" + tools:visibility="visible"> + + <com.google.android.material.imageview.ShapeableImageView + android:id="@+id/ivCover" + style="@style/AuthLogoStyle" + android:layout_width="@dimen/group_icon_size" + android:layout_height="@dimen/group_icon_size" + + android:scaleType="centerCrop" + app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.GroupIconRadius" /> + + + <TextView + android:id="@+id/tvName" + style="@style/title2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="36dp" + android:gravity="center" + tools:text="Aasdsadasdsaf" /> + + <TextView + android:id="@+id/tvDescription" + style="@style/body" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:gravity="center" + tools:text="Aasdsadasdsaf" /> + + <TextView + android:id="@+id/tvStatus" + style="@style/body" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:gravity="center" + android:text="@string/status_active" /> + + <TextView + android:id="@+id/tvPrice" + style="@style/body" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:gravity="center" + tools:text="Price: " /> + + <TextView + android:id="@+id/tvDuration" + style="@style/body" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:gravity="center" + tools:text="Duration" /> + + <TextView + android:id="@+id/tvPurchasedAt" + style="@style/body" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:gravity="center" + tools:text="Purchased at" /> + + <TextView + android:id="@+id/tvProductId" + style="@style/body" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:gravity="center" + android:textSize="14sp" + tools:text="ProductId: " /> + + <TextView + android:id="@+id/tvAutoRenewMessage" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:gravity="center" + android:textSize="17sp" + tools:text="AutoRenew" /> + + <Space + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + <com.google.android.material.button.MaterialButton + android:id="@+id/btnManageGp" + style="@style/AccentButtonStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:text="@string/manage_on_google_play" /> + </LinearLayout> + + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/auth/src/main/res/layout/fragment_log_in.xml b/auth/src/main/res/layout/fragment_log_in.xml index dcfac58515b1b0975c361b7e9f46e82c35a87908..3f5ecbe3b1383735bd4f3d4c26ada8919f8279bb 100644 --- a/auth/src/main/res/layout/fragment_log_in.xml +++ b/auth/src/main/res/layout/fragment_log_in.xml @@ -194,6 +194,11 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> + <androidx.constraintlayout.widget.Group + android:id="@+id/groupSignup" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:constraint_referenced_ids="tvNotMember, btnSignUp" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/auth/src/main/res/layout/fragment_select_sign_up_type.xml b/auth/src/main/res/layout/fragment_select_sign_up_type.xml index b1a1395650e5e7029981abda1bdf40ecef500d23..41faa2fff30ec1154dd456d232dd39a6bb8bc5b7 100644 --- a/auth/src/main/res/layout/fragment_select_sign_up_type.xml +++ b/auth/src/main/res/layout/fragment_select_sign_up_type.xml @@ -66,53 +66,13 @@ <org.futo.circles.core.view.LoadingButton - android:id="@+id/btnToken" + android:id="@+id/btnSignup" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="24dp" - android:text="@string/sign_up_for_free_account" + android:text="@string/sign_up_with_subscription" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/serverLocationGroup" /> - <TextView - android:id="@+id/tvOr" - style="@style/headline" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:gravity="center" - android:text="@string/or" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/btnToken" /> - - <TextView - android:id="@+id/tvSubscriptionTitle" - style="@style/headline" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:gravity="center" - android:text="@string/create_a_subscription" - app:layout_constraintBottom_toTopOf="@id/btnSubscription" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/tvOr" /> - - <org.futo.circles.core.view.LoadingButton - android:id="@+id/btnSubscription" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:text="@string/choose_a_subscription" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/tvSubscriptionTitle" /> - - <androidx.constraintlayout.widget.Group - android:id="@+id/groupSubscription" - android:layout_width="0dp" - android:layout_height="0dp" - app:constraint_referenced_ids="tvOr,tvSubscriptionTitle,btnSubscription" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/auth/src/main/res/layout/fragment_subscription_stage.xml b/auth/src/main/res/layout/fragment_subscription_stage.xml index e3c692a23edbd9fa34d3112c0b4ce4c02c682772..3998ec5208288f7d6f16f05ebd5b0d389e8c2f45 100644 --- a/auth/src/main/res/layout/fragment_subscription_stage.xml +++ b/auth/src/main/res/layout/fragment_subscription_stage.xml @@ -36,7 +36,7 @@ app:layout_constraintVertical_bias="0.3" app:layout_constraintVertical_chainStyle="packed" /> - <androidx.recyclerview.widget.RecyclerView + <org.futo.circles.core.view.LoadingRecyclerView android:id="@+id/rvSubscriptions" android:layout_width="0dp" android:layout_height="0dp" diff --git a/auth/src/main/res/layout/list_item_subscription.xml b/auth/src/main/res/layout/list_item_subscription.xml index 24d9a48ab7b058aed2919a7d88dd31b9be64934b..624f83c15f3416c7ba9813710036fb463b7901ac 100644 --- a/auth/src/main/res/layout/list_item_subscription.xml +++ b/auth/src/main/res/layout/list_item_subscription.xml @@ -14,9 +14,8 @@ android:id="@+id/ivIcon" style="@style/AuthLogoStyle" android:layout_width="@dimen/group_icon_size" - android:layout_height="0dp" + android:layout_height="@dimen/group_icon_size" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintDimensionRatio="W,1:1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 70e3c137c6332eb0355a8bcd93ba06b8c19fc62d..cd4e34c606e1a9c908c84899bdf50f35a3e91941 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -62,13 +62,15 @@ <string name="password">Password</string> <string name="repeat_password">Repeat password</string> <string name="server_location">Server Location</string> - <string name="sign_up_for_free_account">Sign up for a free account</string> + <string name="sign_up_with_subscription">Sign up with subscription</string> <string name="or">Or</string> <string name="setup_profile">Setup profile</string> <string name="upload_a_profile_photo">Upload a profile photo</string> <string name="save">Save</string> <string name="skip">Skip</string> <string name="subscriptions">Subscriptions</string> + <string name="subscription">Subscription</string> + <string name="manage_subscription">Manage subscription</string> <string name="enter_your_username">Enter your username</string> <string name="set_username">Set username</string> <string name="send_validation_code">Send validation code</string> @@ -156,6 +158,17 @@ Or, think about all of your friends across all of the places you\'ve ever lived. <br/><br/>If you want to share with lots of different people who <i>don\'t</i> all know each other, then you should invite those people to follow you in a <b>Circle</b> instead.]]></string> <string name="configure">Configure</string> <string name="receive_email_updates">Receive email updates</string> + <string name="you_don_t_have_any_active_subscriptions">You don\'t have any active subscriptions</string> + <string name="manage_on_google_play">Manage on Google Play</string> + <string name="status_active">Status: Active</string> + <string name="price_format">Price: %s</string> + <string name="duration_format">Duration: %s</string> + <string name="purchase_time_format">Purchase time: %s</string> + <string name="product_id_format">Product id: %s</string> + <string name="is_auto_renew_message">Subscription will renew automatically</string> + <string name="is_not_auto_renew_message">Subscription will not renew automatically</string> + <string name="can_not_open_google_play">Can not open Google Play</string> + <plurals name="days"> <item quantity="one">%1$d day</item> diff --git a/core/src/main/java/org/futo/circles/core/base/CirclesAppConfig.kt b/core/src/main/java/org/futo/circles/core/base/CirclesAppConfig.kt index 018546a7ebd97017c059423435996e57d383bef9..e5337064d96c32a3261a87d680c9ec22a38df27e 100644 --- a/core/src/main/java/org/futo/circles/core/base/CirclesAppConfig.kt +++ b/core/src/main/java/org/futo/circles/core/base/CirclesAppConfig.kt @@ -20,14 +20,13 @@ object CirclesAppConfig { var euServerDomain = "" private set - var isSubscriptionsEnabled = false - private set - var isMediaBackupEnabled = false private set var isRageshakeEnabled = false private set + fun isGplayFlavor(): Boolean = buildFlavourName.contains("gplay", true) + data class Initializer( private var appId: String? = null, private var version: String? = null, @@ -53,9 +52,6 @@ object CirclesAppConfig { fun euDomain(domain: String) = apply { this.euDomain = domain } - fun isSubscriptionEnabled(isEnabled: Boolean) = - apply { this.subscriptionEnabled = isEnabled } - fun isMediaBackupEnabled(isEnabled: Boolean) = apply { this.mediaBackupEnabled = isEnabled } fun isRageshakeEnabled(isEnabled: Boolean) = apply { this.rageshakeEnabled = isEnabled } @@ -80,7 +76,6 @@ object CirclesAppConfig { euServerDomain = euDomain?.takeIf { it.isNotEmpty() } ?: throw IllegalArgumentException("Illegal EU server domain $euDomain") - isSubscriptionsEnabled = subscriptionEnabled isMediaBackupEnabled = mediaBackupEnabled isRageshakeEnabled = rageshakeEnabled }