Implement Android subscription system with freemium limitations
Major subscription system implementation for Android: BillingManager (Android): - Full Google Play Billing Library integration - Product loading, purchase flow, and acknowledgment - Backend verification via APILayer.verifyAndroidPurchase() - Purchase restoration for returning users - Error handling and connection state management SubscriptionHelper (Shared): - New limit checking methods: isResidencesBlocked(), isTasksBlocked(), isContractorsBlocked(), isDocumentsBlocked() - Add permission checks: canAddProperty(), canAddTask(), canAddContractor(), canAddDocument() - Enforces freemium rules based on backend limitationsEnabled flag Screen Updates: - ContractorsScreen: Show upgrade prompt when contractors limit=0 - DocumentsScreen: Show upgrade prompt when documents limit=0 - ResidencesScreen: Show upgrade prompt when properties limit reached - ResidenceDetailScreen: Show upgrade prompt when tasks limit reached UpgradeFeatureScreen: - Enhanced with feature benefits comparison - Dynamic content from backend upgrade triggers - Platform-specific purchase buttons Additional changes: - DataCache: Added O(1) lookup maps for ID resolution - New minimal models (TaskMinimal, ContractorMinimal, ResidenceMinimal) - TaskApi: Added archive/unarchive endpoints - Added Google Billing Library dependency - iOS SubscriptionCache and UpgradePromptView updates 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -155,6 +155,34 @@ data class MyResidencesResponse(
|
||||
val residences: List<ResidenceWithTasks>
|
||||
)
|
||||
|
||||
/**
|
||||
* Minimal residence model for list views.
|
||||
* Uses property_type_id and annotated counts instead of nested objects.
|
||||
* Resolve property type via DataCache.getResidenceType(residence.propertyTypeId)
|
||||
*/
|
||||
@Serializable
|
||||
data class ResidenceMinimal(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
@SerialName("property_type_id") val propertyTypeId: Int? = null,
|
||||
val bedrooms: Int? = null,
|
||||
val bathrooms: Float? = null,
|
||||
@SerialName("is_primary") val isPrimary: Boolean = false,
|
||||
@SerialName("is_primary_owner") val isPrimaryOwner: Boolean = false,
|
||||
@SerialName("user_count") val userCount: Int = 1,
|
||||
// Annotated counts from database (no N+1 queries)
|
||||
@SerialName("task_count") val taskCount: Int = 0,
|
||||
@SerialName("tasks_pending") val tasksPending: Int = 0,
|
||||
@SerialName("tasks_overdue") val tasksOverdue: Int = 0,
|
||||
@SerialName("tasks_due_week") val tasksDueWeek: Int = 0,
|
||||
// Reference to last/next task (just ID and date, not full object)
|
||||
@SerialName("last_completed_task_id") val lastCompletedTaskId: Int? = null,
|
||||
@SerialName("last_completed_date") val lastCompletedDate: String? = null,
|
||||
@SerialName("next_task_id") val nextTaskId: Int? = null,
|
||||
@SerialName("next_task_date") val nextTaskDate: String? = null,
|
||||
@SerialName("created_at") val createdAt: String
|
||||
)
|
||||
|
||||
// Share Code Models
|
||||
@Serializable
|
||||
data class ResidenceShareCode(
|
||||
|
||||
Reference in New Issue
Block a user