Add residence sharing via .casera files

- Add SharedResidence model and package type detection for .casera files
- Add generateSharePackage API endpoint integration
- Create ResidenceSharingManager for iOS and Android
- Add share button to residence detail screens (owner only)
- Add residence import handling with confirmation dialogs
- Update Quick Look extensions to show house icon for residence packages
- Route .casera imports by type (contractor vs residence)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-06 18:54:46 -06:00
parent 04c3389e4d
commit 83e2cd14a6
27 changed files with 1445 additions and 43 deletions

View File

@@ -35,12 +35,15 @@ import com.example.casera.network.APILayer
import com.example.casera.sharing.ContractorSharingManager
import com.example.casera.data.DataManager
import com.example.casera.data.PersistenceManager
import com.example.casera.models.CaseraPackageType
import com.example.casera.models.detectCaseraPackageType
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity(), SingletonImageLoader.Factory {
private var deepLinkResetToken by mutableStateOf<String?>(null)
private var navigateToTaskId by mutableStateOf<Int?>(null)
private var pendingContractorImportUri by mutableStateOf<Uri?>(null)
private var pendingResidenceImportUri by mutableStateOf<Uri?>(null)
private lateinit var billingManager: BillingManager
override fun onCreate(savedInstanceState: Bundle?) {
@@ -92,6 +95,10 @@ class MainActivity : ComponentActivity(), SingletonImageLoader.Factory {
pendingContractorImportUri = pendingContractorImportUri,
onClearContractorImport = {
pendingContractorImportUri = null
},
pendingResidenceImportUri = pendingResidenceImportUri,
onClearResidenceImport = {
pendingResidenceImportUri = null
}
)
}
@@ -242,8 +249,35 @@ class MainActivity : ComponentActivity(), SingletonImageLoader.Factory {
if (intent?.action == Intent.ACTION_VIEW) {
val uri = intent.data
if (uri != null && ContractorSharingManager.isCaseraFile(applicationContext, uri)) {
Log.d("MainActivity", "Contractor file received: $uri")
pendingContractorImportUri = uri
Log.d("MainActivity", "Casera file received: $uri")
// Read file content to detect package type
try {
val inputStream = contentResolver.openInputStream(uri)
if (inputStream != null) {
val jsonString = inputStream.bufferedReader().use { it.readText() }
inputStream.close()
val packageType = detectCaseraPackageType(jsonString)
Log.d("MainActivity", "Detected package type: $packageType")
when (packageType) {
CaseraPackageType.RESIDENCE -> {
Log.d("MainActivity", "Routing to residence import")
pendingResidenceImportUri = uri
}
else -> {
// Default to contractor for backward compatibility
Log.d("MainActivity", "Routing to contractor import")
pendingContractorImportUri = uri
}
}
}
} catch (e: Exception) {
Log.e("MainActivity", "Failed to detect package type, defaulting to contractor", e)
// Default to contractor on error for backward compatibility
pendingContractorImportUri = uri
}
}
}
}