Rebrand from MyCrib to Casera
- Rename Kotlin package from com.example.mycrib to com.example.casera - Update Android app name, namespace, and application ID - Update iOS bundle identifiers and project settings - Rename iOS directories (MyCribTests -> CaseraTests, etc.) - Update deep link schemes from mycrib:// to casera:// - Update app group identifiers - Update subscription product IDs - Update all UI strings and branding 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
package com.example.casera.utils
|
||||
|
||||
import com.example.casera.cache.SubscriptionCache
|
||||
|
||||
/**
|
||||
* Helper for checking subscription limits and determining when to show upgrade prompts.
|
||||
*
|
||||
* RULES:
|
||||
* 1. Backend limitations OFF: Never show upgrade view, allow everything
|
||||
* 2. Backend limitations ON + limit=0: Show upgrade view, block access entirely (no add button)
|
||||
* 3. Backend limitations ON + limit>0: Allow access with add button, show upgrade when limit reached
|
||||
*
|
||||
* These rules apply to: residence, task, contractors, documents
|
||||
*/
|
||||
object SubscriptionHelper {
|
||||
/**
|
||||
* Result of a usage/access check
|
||||
* @param allowed Whether the action is allowed
|
||||
* @param triggerKey The upgrade trigger key to use if not allowed (null if allowed)
|
||||
*/
|
||||
data class UsageCheck(val allowed: Boolean, val triggerKey: String?)
|
||||
|
||||
// NOTE: For Android, currentTier should be set from Google Play Billing
|
||||
// For iOS, tier is managed by SubscriptionCacheWrapper from StoreKit
|
||||
var currentTier: String = "free"
|
||||
|
||||
// ===== PROPERTY (RESIDENCE) =====
|
||||
|
||||
/**
|
||||
* Check if the user should see an upgrade view instead of the residences screen.
|
||||
* Returns true (blocked) only when limitations are ON and limit=0.
|
||||
*/
|
||||
fun isResidencesBlocked(): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(false, null) // Allow access while loading
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(false, null) // Limitations disabled, never block
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(false, null) // Pro users never blocked
|
||||
}
|
||||
|
||||
val limit = subscription.limits[currentTier]?.properties
|
||||
|
||||
// If limit is 0, block access entirely
|
||||
if (limit == 0) {
|
||||
return UsageCheck(true, "add_second_property")
|
||||
}
|
||||
|
||||
return UsageCheck(false, null) // limit > 0 or unlimited, allow access
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user can add a property (when trying to add, not for blocking the screen).
|
||||
* Used when limit > 0 and user has reached the limit.
|
||||
*/
|
||||
fun canAddProperty(currentCount: Int = 0): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(true, null) // Allow if no subscription data
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(true, null) // Limitations disabled, allow everything
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(true, null) // Pro tier gets unlimited access
|
||||
}
|
||||
|
||||
// Get limit for current tier (null = unlimited)
|
||||
val limit = subscription.limits[currentTier]?.properties
|
||||
|
||||
// null means unlimited
|
||||
if (limit == null) {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
// If limit is 0, they shouldn't even be here (screen should be blocked)
|
||||
// But if they somehow are, block the add
|
||||
if (limit == 0) {
|
||||
return UsageCheck(false, "add_second_property")
|
||||
}
|
||||
|
||||
// limit > 0: check if they've reached it
|
||||
if (currentCount >= limit) {
|
||||
return UsageCheck(false, "add_second_property")
|
||||
}
|
||||
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
// ===== TASKS =====
|
||||
|
||||
/**
|
||||
* Check if the user should see an upgrade view instead of the tasks screen.
|
||||
* Returns true (blocked) only when limitations are ON and limit=0.
|
||||
*/
|
||||
fun isTasksBlocked(): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(false, null) // Allow access while loading
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
val limit = subscription.limits[currentTier]?.tasks
|
||||
|
||||
if (limit == 0) {
|
||||
return UsageCheck(true, "add_11th_task")
|
||||
}
|
||||
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user can add a task (when trying to add).
|
||||
*/
|
||||
fun canAddTask(currentCount: Int = 0): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(true, null)
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
val limit = subscription.limits[currentTier]?.tasks
|
||||
|
||||
if (limit == null) {
|
||||
return UsageCheck(true, null) // Unlimited
|
||||
}
|
||||
|
||||
if (limit == 0) {
|
||||
return UsageCheck(false, "add_11th_task")
|
||||
}
|
||||
|
||||
if (currentCount >= limit) {
|
||||
return UsageCheck(false, "add_11th_task")
|
||||
}
|
||||
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
// ===== CONTRACTORS =====
|
||||
|
||||
/**
|
||||
* Check if the user should see an upgrade view instead of the contractors screen.
|
||||
* Returns true (blocked) only when limitations are ON and limit=0.
|
||||
*/
|
||||
fun isContractorsBlocked(): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(false, null) // Allow access while loading
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
val limit = subscription.limits[currentTier]?.contractors
|
||||
|
||||
if (limit == 0) {
|
||||
return UsageCheck(true, "view_contractors")
|
||||
}
|
||||
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user can add a contractor (when trying to add).
|
||||
*/
|
||||
fun canAddContractor(currentCount: Int = 0): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(true, null)
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
val limit = subscription.limits[currentTier]?.contractors
|
||||
|
||||
if (limit == null) {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
if (limit == 0) {
|
||||
return UsageCheck(false, "view_contractors")
|
||||
}
|
||||
|
||||
if (currentCount >= limit) {
|
||||
return UsageCheck(false, "view_contractors")
|
||||
}
|
||||
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
// ===== DOCUMENTS =====
|
||||
|
||||
/**
|
||||
* Check if the user should see an upgrade view instead of the documents screen.
|
||||
* Returns true (blocked) only when limitations are ON and limit=0.
|
||||
*/
|
||||
fun isDocumentsBlocked(): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(false, null) // Allow access while loading
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
val limit = subscription.limits[currentTier]?.documents
|
||||
|
||||
if (limit == 0) {
|
||||
return UsageCheck(true, "view_documents")
|
||||
}
|
||||
|
||||
return UsageCheck(false, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user can add a document (when trying to add).
|
||||
*/
|
||||
fun canAddDocument(currentCount: Int = 0): UsageCheck {
|
||||
val subscription = SubscriptionCache.currentSubscription.value
|
||||
?: return UsageCheck(true, null)
|
||||
|
||||
if (!subscription.limitationsEnabled) {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
if (currentTier == "pro") {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
val limit = subscription.limits[currentTier]?.documents
|
||||
|
||||
if (limit == null) {
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
if (limit == 0) {
|
||||
return UsageCheck(false, "view_documents")
|
||||
}
|
||||
|
||||
if (currentCount >= limit) {
|
||||
return UsageCheck(false, "view_documents")
|
||||
}
|
||||
|
||||
return UsageCheck(true, null)
|
||||
}
|
||||
|
||||
// ===== DEPRECATED - Keep for backwards compatibility =====
|
||||
|
||||
@Deprecated("Use isContractorsBlocked() instead", ReplaceWith("isContractorsBlocked()"))
|
||||
fun shouldShowUpgradePromptForContractors(): UsageCheck = isContractorsBlocked()
|
||||
|
||||
@Deprecated("Use isDocumentsBlocked() instead", ReplaceWith("isDocumentsBlocked()"))
|
||||
fun shouldShowUpgradePromptForDocuments(): UsageCheck = isDocumentsBlocked()
|
||||
}
|
||||
Reference in New Issue
Block a user