Rebrand from Casera/MyCrib to honeyDue

Total rebrand across KMM project:
- Kotlin package: com.example.casera -> com.tt.honeyDue (dirs + declarations)
- Gradle: rootProject.name, namespace, applicationId
- Android: manifest, strings.xml (all languages), widget resources
- iOS: pbxproj bundle IDs, Info.plist, entitlements, xcconfig
- iOS directories: Casera/ -> HoneyDue/, CaseraTests/ -> HoneyDueTests/, etc.
- Swift source: all class/struct/enum renames
- Deep links: casera:// -> honeydue://, .casera -> .honeydue
- App icons replaced with honeyDue honeycomb icon
- Domains: casera.treytartt.com -> honeyDue.treytartt.com
- Bundle IDs: com.tt.casera -> com.tt.honeyDue
- Database table names preserved

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-03-07 06:33:57 -06:00
parent 9c574c4343
commit 1e2adf7660
450 changed files with 1730 additions and 1788 deletions

View File

@@ -0,0 +1,7 @@
package com.tt.honeyDue
class JVMPlatform: Platform {
override val name: String = "Java ${System.getProperty("java.version")}"
}
actual fun getPlatform(): Platform = JVMPlatform()

View File

@@ -0,0 +1,31 @@
package com.tt.honeyDue.analytics
/**
* JVM/Desktop implementation of PostHog Analytics.
* Currently a no-op stub - PostHog doesn't have a native JVM SDK.
*/
actual object PostHogAnalytics {
actual fun initialize() {
// No-op for desktop
}
actual fun identify(userId: String, properties: Map<String, Any>?) {
// No-op for desktop
}
actual fun capture(event: String, properties: Map<String, Any>?) {
// No-op for desktop
}
actual fun screen(screenName: String, properties: Map<String, Any>?) {
// No-op for desktop
}
actual fun reset() {
// No-op for desktop
}
actual fun flush() {
// No-op for desktop
}
}

View File

@@ -0,0 +1,65 @@
package com.tt.honeyDue.data
import java.io.File
import java.util.Properties
/**
* JVM/Desktop implementation of PersistenceManager using Properties file.
*/
actual class PersistenceManager {
private val properties = Properties()
private val storageFile: File
init {
val userHome = System.getProperty("user.home")
val appDir = File(userHome, ".honeydue")
if (!appDir.exists()) {
appDir.mkdirs()
}
storageFile = File(appDir, "data.properties")
loadProperties()
}
private fun loadProperties() {
if (storageFile.exists()) {
try {
storageFile.inputStream().use { properties.load(it) }
} catch (e: Exception) {
// Ignore load errors
}
}
}
private fun saveProperties() {
try {
storageFile.outputStream().use { properties.store(it, "honeyDue Data Manager") }
} catch (e: Exception) {
// Ignore save errors
}
}
actual fun save(key: String, value: String) {
properties.setProperty(key, value)
saveProperties()
}
actual fun load(key: String): String? {
return properties.getProperty(key)
}
actual fun remove(key: String) {
properties.remove(key)
saveProperties()
}
actual fun clear() {
properties.clear()
saveProperties()
}
companion object {
private val instance by lazy { PersistenceManager() }
fun getInstance(): PersistenceManager = instance
}
}

View File

@@ -0,0 +1,23 @@
package com.tt.honeyDue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.honeydue.storage.TokenManager
import com.honeydue.storage.TokenStorage
import com.honeydue.storage.TaskCacheManager
import com.honeydue.storage.TaskCacheStorage
fun main() = application {
// Initialize TokenStorage with JVM TokenManager
TokenStorage.initialize(TokenManager.getInstance())
// Initialize TaskCacheStorage for offline task caching
TaskCacheStorage.initialize(TaskCacheManager.getInstance())
Window(
onCloseRequest = ::exitApplication,
title = "honeyDue",
) {
App()
}
}

View File

@@ -0,0 +1,43 @@
package com.tt.honeyDue.network
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.logging.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
import java.util.Locale
import java.util.TimeZone
actual fun getLocalhostAddress(): String = "127.0.0.1"
actual fun getDeviceLanguage(): String {
return Locale.getDefault().language
}
actual fun getDeviceTimezone(): String {
return TimeZone.getDefault().id
}
actual fun createHttpClient(): HttpClient {
return HttpClient(CIO) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
isLenient = true
prettyPrint = true
})
}
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.ALL
}
install(DefaultRequest) {
headers.append("Accept-Language", getDeviceLanguage())
headers.append("X-Timezone", getDeviceTimezone())
}
}
}

View File

@@ -0,0 +1,13 @@
package com.tt.honeyDue.platform
import androidx.compose.runtime.Composable
import com.tt.honeyDue.models.Contractor
@Composable
actual fun ContractorImportHandler(
pendingContractorImportUri: Any?,
onClearContractorImport: () -> Unit,
onImportSuccess: (Contractor) -> Unit
) {
// Not implemented for JVM desktop
}

View File

@@ -0,0 +1,11 @@
package com.tt.honeyDue.platform
import androidx.compose.runtime.Composable
import com.tt.honeyDue.models.Contractor
@Composable
actual fun rememberShareContractor(): (Contractor) -> Unit {
return { _: Contractor ->
// Not implemented for JVM desktop
}
}

View File

@@ -0,0 +1,18 @@
package com.tt.honeyDue.platform
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
/**
* JVM/Desktop implementation - no-op since desktop doesn't have haptic feedback.
*/
class JvmHapticFeedbackPerformer : HapticFeedbackPerformer {
override fun perform(type: HapticFeedbackType) {
// Desktop doesn't support haptic feedback
}
}
@Composable
actual fun rememberHapticFeedback(): HapticFeedbackPerformer {
return remember { JvmHapticFeedbackPerformer() }
}

View File

@@ -0,0 +1,19 @@
package com.tt.honeyDue.platform
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.toComposeImageBitmap
import org.jetbrains.skia.Image
@Composable
actual fun rememberImageBitmap(imageData: ImageData): ImageBitmap? {
return remember(imageData) {
try {
val skiaImage = Image.makeFromEncoded(imageData.bytes)
skiaImage.toComposeImageBitmap()
} catch (e: Exception) {
null
}
}
}

View File

@@ -0,0 +1,27 @@
package com.honeydue.platform
import androidx.compose.runtime.Composable
@Composable
actual fun rememberImagePicker(
onImagesPicked: (List<ImageData>) -> Unit
): () -> Unit {
// Desktop image picker would require platform-specific file chooser
// This is a placeholder implementation
return {
// TODO: Implement desktop file chooser
println("Image picker not yet implemented for desktop")
}
}
@Composable
actual fun rememberCameraPicker(
onImageCaptured: (ImageData) -> Unit
): () -> Unit {
// Desktop camera picker would require platform-specific camera access
// This is a placeholder implementation
return {
// TODO: Implement desktop camera capture
println("Camera picker not yet implemented for desktop")
}
}

View File

@@ -0,0 +1,16 @@
package com.tt.honeyDue.platform
import androidx.compose.runtime.Composable
import com.tt.honeyDue.ui.subscription.UpgradeScreen
@Composable
actual fun PlatformUpgradeScreen(
onNavigateBack: () -> Unit,
onSubscriptionChanged: () -> Unit
) {
UpgradeScreen(
onNavigateBack = onNavigateBack,
onPurchase = { _ -> onNavigateBack() },
onRestorePurchases = { }
)
}

View File

@@ -0,0 +1,16 @@
package com.tt.honeyDue.platform
import androidx.compose.runtime.Composable
import com.tt.honeyDue.models.JoinResidenceResponse
/**
* JVM implementation is a no-op - file imports are not supported on desktop.
*/
@Composable
actual fun ResidenceImportHandler(
pendingResidenceImportUri: Any?,
onClearResidenceImport: () -> Unit,
onImportSuccess: (JoinResidenceResponse) -> Unit
) {
// No-op on JVM - desktop doesn't support file imports
}

View File

@@ -0,0 +1,15 @@
package com.tt.honeyDue.platform
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.tt.honeyDue.models.Residence
/**
* JVM implementation is a no-op - sharing is not supported on desktop.
*/
@Composable
actual fun rememberShareResidence(): Pair<ResidenceSharingState, (Residence) -> Unit> {
val state = remember { ResidenceSharingState() }
val noOp: (Residence) -> Unit = { /* No-op on JVM */ }
return Pair(state, noOp)
}

View File

@@ -0,0 +1,63 @@
package com.tt.honeyDue.storage
import java.util.prefs.Preferences
/**
* JVM implementation of TaskCacheManager using Java Preferences.
* Note: JVM/Desktop doesn't have widgets, so dirty flag methods are no-ops.
*/
actual class TaskCacheManager {
private val prefs = Preferences.userRoot().node(NODE_NAME)
actual fun saveTasks(tasksJson: String) {
prefs.put(KEY_TASKS, tasksJson)
prefs.flush()
}
actual fun getTasks(): String? {
return prefs.get(KEY_TASKS, null)
}
actual fun clearTasks() {
prefs.remove(KEY_TASKS)
prefs.flush()
}
/**
* Check if tasks need refresh. JVM doesn't have widgets, always returns false.
*/
actual fun areTasksDirty(): Boolean {
return prefs.getBoolean(KEY_DIRTY_FLAG, false)
}
/**
* Mark tasks as dirty. JVM doesn't have widgets but supports the interface.
*/
actual fun markTasksDirty() {
prefs.putBoolean(KEY_DIRTY_FLAG, true)
prefs.flush()
}
/**
* Clear the dirty flag.
*/
actual fun clearDirtyFlag() {
prefs.putBoolean(KEY_DIRTY_FLAG, false)
prefs.flush()
}
companion object {
private const val NODE_NAME = "com.honeydue.cache"
private const val KEY_TASKS = "cached_tasks"
private const val KEY_DIRTY_FLAG = "tasks_dirty"
@Volatile
private var instance: TaskCacheManager? = null
fun getInstance(): TaskCacheManager {
return instance ?: synchronized(this) {
instance ?: TaskCacheManager().also { instance = it }
}
}
}
}

View File

@@ -0,0 +1,5 @@
package com.honeydue.storage
internal actual fun getPlatformTaskCacheManager(): TaskCacheManager? {
return TaskCacheManager.getInstance()
}

View File

@@ -0,0 +1,38 @@
package com.honeydue.storage
import java.util.prefs.Preferences
/**
* JVM implementation of TokenManager using Java Preferences API.
*/
actual class TokenManager {
private val prefs: Preferences = Preferences.userRoot().node(PREFS_NODE)
actual fun saveToken(token: String) {
prefs.put(KEY_TOKEN, token)
prefs.flush()
}
actual fun getToken(): String? {
return prefs.get(KEY_TOKEN, null)
}
actual fun clearToken() {
prefs.remove(KEY_TOKEN)
prefs.flush()
}
companion object {
private const val PREFS_NODE = "com.honeyDue.treytartt.com"
private const val KEY_TOKEN = "auth_token"
@Volatile
private var instance: TokenManager? = null
fun getInstance(): TokenManager {
return instance ?: synchronized(this) {
instance ?: TokenManager().also { instance = it }
}
}
}
}

View File

@@ -0,0 +1,5 @@
package com.honeydue.storage
internal actual fun getPlatformTokenManager(): TokenManager? {
return TokenManager.getInstance()
}

View File

@@ -0,0 +1,16 @@
package com.tt.honeyDue.ui.components.auth
import androidx.compose.runtime.Composable
/**
* JVM/Desktop stub - Google Sign In not implemented for desktop
*/
@Composable
actual fun GoogleSignInButton(
onSignInStarted: () -> Unit,
onSignInSuccess: (idToken: String) -> Unit,
onSignInError: (message: String) -> Unit,
enabled: Boolean
) {
// No-op on JVM/Desktop
}