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:
@@ -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()
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
23
composeApp/src/jvmMain/kotlin/com/tt/honeyDue/main.kt
Normal file
23
composeApp/src/jvmMain/kotlin/com/tt/honeyDue/main.kt
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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 = { }
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.honeydue.storage
|
||||
|
||||
internal actual fun getPlatformTaskCacheManager(): TaskCacheManager? {
|
||||
return TaskCacheManager.getInstance()
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.honeydue.storage
|
||||
|
||||
internal actual fun getPlatformTokenManager(): TokenManager? {
|
||||
return TokenManager.getInstance()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user