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,70 @@
|
||||
package com.tt.honeyDue.storage
|
||||
|
||||
import platform.Foundation.NSUserDefaults
|
||||
import kotlin.concurrent.Volatile
|
||||
|
||||
/**
|
||||
* iOS implementation of TaskCacheManager using NSUserDefaults.
|
||||
* Note: iOS widget dirty flag is handled by native Swift WidgetDataManager
|
||||
* using App Groups shared storage, but we provide these methods for KMM compatibility.
|
||||
*/
|
||||
actual class TaskCacheManager {
|
||||
private val userDefaults = NSUserDefaults.standardUserDefaults
|
||||
|
||||
actual fun saveTasks(tasksJson: String) {
|
||||
userDefaults.setObject(tasksJson, KEY_TASKS)
|
||||
userDefaults.synchronize()
|
||||
}
|
||||
|
||||
actual fun getTasks(): String? {
|
||||
return userDefaults.stringForKey(KEY_TASKS)
|
||||
}
|
||||
|
||||
actual fun clearTasks() {
|
||||
userDefaults.removeObjectForKey(KEY_TASKS)
|
||||
userDefaults.synchronize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tasks need refresh due to widget interactions.
|
||||
* Note: iOS primarily uses native Swift WidgetDataManager for this.
|
||||
*/
|
||||
actual fun areTasksDirty(): Boolean {
|
||||
return userDefaults.boolForKey(KEY_DIRTY_FLAG)
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark tasks as dirty (needs refresh).
|
||||
*/
|
||||
actual fun markTasksDirty() {
|
||||
userDefaults.setBool(true, KEY_DIRTY_FLAG)
|
||||
userDefaults.synchronize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the dirty flag after tasks have been refreshed.
|
||||
*/
|
||||
actual fun clearDirtyFlag() {
|
||||
userDefaults.setBool(false, KEY_DIRTY_FLAG)
|
||||
userDefaults.synchronize()
|
||||
}
|
||||
|
||||
companion object {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for synchronization on iOS
|
||||
private fun <T> synchronized(lock: Any, block: () -> T): T {
|
||||
return block()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.tt.honeyDue.storage
|
||||
|
||||
internal actual fun getPlatformTaskCacheManager(): TaskCacheManager? {
|
||||
return TaskCacheManager.getInstance()
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.tt.honeyDue.storage
|
||||
|
||||
import platform.Foundation.NSUserDefaults
|
||||
|
||||
/**
|
||||
* iOS implementation of theme storage using NSUserDefaults.
|
||||
*/
|
||||
actual class ThemeStorageManager {
|
||||
private val defaults = NSUserDefaults.standardUserDefaults
|
||||
|
||||
actual fun saveThemeId(themeId: String) {
|
||||
defaults.setObject(themeId, forKey = KEY_THEME_ID)
|
||||
defaults.synchronize()
|
||||
}
|
||||
|
||||
actual fun getThemeId(): String? {
|
||||
return defaults.stringForKey(KEY_THEME_ID)
|
||||
}
|
||||
|
||||
actual fun clearThemeId() {
|
||||
defaults.removeObjectForKey(KEY_THEME_ID)
|
||||
defaults.synchronize()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_THEME_ID = "theme_id"
|
||||
|
||||
private val instance by lazy { ThemeStorageManager() }
|
||||
|
||||
fun getInstance(): ThemeStorageManager = instance
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.tt.honeyDue.storage
|
||||
|
||||
import kotlin.concurrent.Volatile
|
||||
|
||||
/**
|
||||
* Protocol for iOS Keychain operations. Implemented in Swift (KeychainHelper)
|
||||
* and injected before DataManager initialization.
|
||||
*
|
||||
* Kotlin/Native cannot directly use the Security framework (SecItem* APIs)
|
||||
* because CFStringRef keys like kSecClass don't bridge to NSCopying.
|
||||
*/
|
||||
interface KeychainDelegate {
|
||||
fun save(key: String, value: String): Boolean
|
||||
fun get(key: String): String?
|
||||
fun delete(key: String): Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* iOS implementation of TokenManager.
|
||||
*
|
||||
* Uses iOS Keychain via [KeychainDelegate] for secure token storage.
|
||||
* If delegate is missing, operations fail closed (no insecure fallback).
|
||||
*
|
||||
* On first read, migrates any existing NSUserDefaults token to Keychain.
|
||||
*/
|
||||
actual class TokenManager {
|
||||
private val prefs = platform.Foundation.NSUserDefaults.standardUserDefaults
|
||||
|
||||
actual fun saveToken(token: String) {
|
||||
val delegate = keychainDelegate
|
||||
if (delegate != null) {
|
||||
delegate.save(TOKEN_KEY, token)
|
||||
// Clean up old NSUserDefaults entry if it exists
|
||||
prefs.removeObjectForKey(TOKEN_KEY)
|
||||
prefs.synchronize()
|
||||
} else {
|
||||
// Fail closed: never store auth tokens in insecure storage.
|
||||
println("TokenManager: Keychain delegate not set, refusing to save token insecurely")
|
||||
}
|
||||
}
|
||||
|
||||
actual fun getToken(): String? {
|
||||
val delegate = keychainDelegate
|
||||
|
||||
// Try Keychain first
|
||||
if (delegate != null) {
|
||||
val keychainToken = delegate.get(TOKEN_KEY)
|
||||
if (keychainToken != null) return keychainToken
|
||||
|
||||
// Check NSUserDefaults for migration
|
||||
val oldToken = prefs.stringForKey(TOKEN_KEY)
|
||||
if (oldToken != null) {
|
||||
// Migrate to Keychain
|
||||
delegate.save(TOKEN_KEY, oldToken)
|
||||
prefs.removeObjectForKey(TOKEN_KEY)
|
||||
prefs.synchronize()
|
||||
return oldToken
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Fail closed: no insecure fallback reads.
|
||||
println("TokenManager: Keychain delegate not set, refusing insecure token read")
|
||||
return null
|
||||
}
|
||||
|
||||
actual fun clearToken() {
|
||||
keychainDelegate?.delete(TOKEN_KEY)
|
||||
prefs.removeObjectForKey(TOKEN_KEY)
|
||||
prefs.synchronize()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TOKEN_KEY = "auth_token"
|
||||
|
||||
/**
|
||||
* Set from Swift in iOSApp.init() BEFORE DataManager.initialize().
|
||||
* This enables Keychain storage for auth tokens.
|
||||
*/
|
||||
var keychainDelegate: KeychainDelegate? = null
|
||||
|
||||
@Volatile
|
||||
private var instance: TokenManager? = null
|
||||
|
||||
fun getInstance(): TokenManager {
|
||||
return instance ?: synchronized(this) {
|
||||
instance ?: TokenManager().also { instance = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for synchronization on iOS
|
||||
private fun <T> synchronized(lock: Any, block: () -> T): T {
|
||||
return block()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.tt.honeyDue.storage
|
||||
|
||||
internal actual fun getPlatformTokenManager(): TokenManager? {
|
||||
return TokenManager.getInstance()
|
||||
}
|
||||
Reference in New Issue
Block a user