Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ dependencies {
implementation(libs.androidx.documentfile)
implementation(libs.androidx.work.runtime.ktx)
implementation(libs.androidx.compose.foundation.layout)
implementation(libs.androidx.compose.adaptive)
implementation(libs.androidx.compose.foundation)
implementation(libs.androidx.navigation.common.ktx)

// Hilt
ksp(libs.hilt.android.compiler)
Expand Down
47 changes: 30 additions & 17 deletions app/src/main/java/com/flux/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,24 @@ import androidx.compose.ui.Modifier
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.rememberNavController
import com.flux.navigation.AppNavHost
import com.flux.navigation.Loader
import com.flux.other.Constants.Other
import com.flux.other.createNotificationChannel
import com.flux.ui.effects.ScreenEffect
import com.flux.ui.state.States
import com.flux.ui.theme.FluxTheme
import com.flux.ui.viewModel.BackupViewModel
import com.flux.ui.viewModel.EventViewModel
import com.flux.ui.viewModel.HabitViewModel
import com.flux.ui.viewModel.JournalViewModel
import com.flux.ui.viewModel.LabelViewModel
import com.flux.ui.viewModel.NotesViewModel
import com.flux.ui.viewModel.ProgressBoardViewModel
import com.flux.ui.viewModel.SettingsViewModel
import com.flux.ui.viewModel.TodoViewModel
import com.flux.ui.viewModel.ViewModels
import com.flux.ui.viewModel.WorkspaceViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.Flow
Expand Down Expand Up @@ -68,6 +72,7 @@ class MainActivity : AppCompatActivity() {
val todoViewModel: TodoViewModel = hiltViewModel()
val journalViewModel: JournalViewModel = hiltViewModel()
val backupViewModel: BackupViewModel = hiltViewModel()
val labelViewModel: LabelViewModel = hiltViewModel()
val progressBoardViewModel: ProgressBoardViewModel = hiltViewModel()

// States
Expand All @@ -78,6 +83,7 @@ class MainActivity : AppCompatActivity() {
val habitState by habitViewModel.state.collectAsStateWithLifecycle()
val todoState by todoViewModel.state.collectAsStateWithLifecycle()
val journalState by journalViewModel.state.collectAsStateWithLifecycle()
val labelState by labelViewModel.state.collectAsStateWithLifecycle()
val progressBoardState by progressBoardViewModel.state.collectAsStateWithLifecycle()

// Stop splash screen when settings are loaded
Expand All @@ -96,24 +102,31 @@ class MainActivity : AppCompatActivity() {
color = MaterialTheme.colorScheme.surfaceContainerLow
) {
AppNavHost(
navController = rememberNavController(),
snackbarHostState = snackBarHostState,
settingsViewModel = settingsViewModel,
notesViewModel = notesViewModel,
workspaceViewModel = workspaceViewModel,
eventViewModel = eventViewModel,
habitViewModel = habitViewModel,
todoViewModel = todoViewModel,
journalViewModel = journalViewModel,
backupViewModel = backupViewModel,
progressBoardViewModel = progressBoardViewModel,
settings = settings,
notesState = notesState,
workspaceState = workspaceState,
eventState = eventState,
habitState = habitState,
todoState = todoState,
journalState = journalState,
progressBoardState = progressBoardState
viewModels = ViewModels(
notesViewModel,
eventViewModel,
todoViewModel,
habitViewModel,
workspaceViewModel,
journalViewModel,
settingsViewModel,
backupViewModel,
labelViewModel,
progressBoardViewModel
),
states = States(
notesState,
eventState,
habitState,
todoState,
workspaceState,
journalState,
progressBoardState,
labelState,
settings
)
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/flux/data/dao/EventDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ interface EventDao {
@Query("Delete FROM EventModel where workspaceId = :workspaceId")
suspend fun deleteAllWorkspaceEvents(workspaceId: String)

@Query("SELECT * FROM EventModel WHERE workspaceId = :workspaceId")
fun loadAllEvents(workspaceId: String): Flow<List<EventModel>>
@Query("SELECT * FROM EventModel")
fun loadEventData(): Flow<List<EventModel>>

@Query("SELECT * FROM EventModel")
suspend fun loadAllEvents(): List<EventModel>
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/flux/data/dao/EventInstanceDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ interface EventInstanceDao {
@Query("DELETE FROM EventInstanceModel WHERE workspaceId = :workspaceId")
suspend fun deleteAllWorkspaceInstance(workspaceId: String)

@Query("SELECT * FROM EventInstanceModel where workspaceId in (:workspaceId)")
fun loadAllWorkspaceInstances(workspaceId: String): Flow<List<EventInstanceModel>>
@Query("SELECT * FROM EventInstanceModel")
fun loadEventInstanceData(): Flow<List<EventInstanceModel>>

@Query("SELECT * FROM EventInstanceModel")
suspend fun getAll(): List<EventInstanceModel>
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/com/flux/data/dao/HabitInstanceDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ interface HabitInstanceDao {
@Query("DELETE FROM HabitInstanceModel WHERE habitId IN (:habitId)")
suspend fun deleteAllInstances(habitId: String)

@Query("SELECT * FROM HabitInstanceModel WHERE habitId = :habitId AND instanceDate = :date LIMIT 1")
suspend fun getHabitInstance(habitId: String, date: Long): HabitInstanceModel?

@Delete
suspend fun deleteInstance(habitInstance: HabitInstanceModel)

@Query("DELETE FROM HabitInstanceModel WHERE workspaceId = :workspaceId")
suspend fun deleteAllWorkspaceInstance(workspaceId: String)

@Query("SELECT * FROM HabitInstanceModel where workspaceId in (:workspaceId)")
fun loadAllInstances(workspaceId: String): Flow<List<HabitInstanceModel>>
@Query("SELECT * FROM HabitInstanceModel")
fun loadHabitInstanceData(): Flow<List<HabitInstanceModel>>

@Query("SELECT * FROM HabitInstanceModel")
suspend fun loadAllInstances(): List<HabitInstanceModel>
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/com/flux/data/dao/HabitsDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ interface HabitsDao {
@Query("DELETE FROM HabitModel WHERE workspaceId = :workspaceId")
suspend fun deleteAllWorkspaceHabit(workspaceId: String)

@Query("SELECT * FROM HabitModel WHERE workspaceId = :workspaceId")
fun loadAllHabitsOfWorkspace(workspaceId: String): Flow<List<HabitModel>>
@Query("SELECT * FROM HabitModel")
fun loadHabitData(): Flow<List<HabitModel>>

@Query("Select * FROM HabitModel")
suspend fun loadAllHabits(): List<HabitModel>
fun loadAllHabits(): List<HabitModel>
}
10 changes: 2 additions & 8 deletions app/src/main/java/com/flux/data/dao/JournalDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,8 @@ interface JournalDao {
@Query("Delete FROM JournalModel where workspaceId = :workspaceId")
suspend fun deleteAllWorkspaceEntries(workspaceId: String)

@Query(
"""
SELECT * FROM JournalModel
WHERE workspaceId = :workspaceId
ORDER BY dateTime DESC
"""
)
fun loadAllEntries(workspaceId: String): Flow<List<JournalModel>>
@Query("SELECT * FROM JournalModel ORDER BY dateTime DESC")
fun loadJournalData(): Flow<List<JournalModel>>

@Query("SELECT * FROM JournalModel")
suspend fun loadAllEntries(): List<JournalModel>
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/flux/data/dao/LabelDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ interface LabelDao {
@Query("DELETE FROM LabelModel WHERE workspaceId = :workspaceId")
suspend fun deleteAllWorkspaceLabels(workspaceId: String)

@Query("SELECT * FROM LabelModel where workspaceId IN (:workspaceId)")
fun loadAllLabels(workspaceId: String): Flow<List<LabelModel>>
@Query("SELECT * FROM LabelModel")
fun loadAllLabels(): Flow<List<LabelModel>>

@Query("SELECT * FROM LabelModel")
suspend fun getAll(): List<LabelModel>
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/flux/data/dao/NotesDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ interface NotesDao {
@Query("DELETE FROM NotesModel WHERE workspaceId = :workspaceId")
suspend fun deleteAllWorkspaceNotes(workspaceId: String)

@Query("SELECT * FROM NotesModel where workspaceId IN (:workspaceId)")
fun loadAllNotes(workspaceId: String): Flow<List<NotesModel>>
@Query("SELECT * FROM NotesModel ORDER by lastEdited DESC")
fun loadNotesData(): Flow<List<NotesModel>>

@Query("SELECT * FROM NotesModel")
fun loadAllNotes(): List<NotesModel>
Expand Down
7 changes: 3 additions & 4 deletions app/src/main/java/com/flux/data/dao/ProgressBoardDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ interface ProgressBoardDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun upsertBoardItem(item: ProgressBoardModel)

@Query("SELECT * FROM ProgressBoardModel WHERE workspaceId = :workspaceId")
fun getBoardItemsByWorkspace(workspaceId: String): Flow<List<ProgressBoardModel>>
@Query("SELECT * FROM ProgressBoardModel")
fun getProgressBoardData(): Flow<List<ProgressBoardModel>>

@Delete
suspend fun deleteBoardItem(item: ProgressBoardModel)
Expand All @@ -27,5 +27,4 @@ interface ProgressBoardDao {

@Query("SELECT * FROM ProgressBoardModel")
fun getAllBoardItems(): List<ProgressBoardModel>
}

}
4 changes: 2 additions & 2 deletions app/src/main/java/com/flux/data/dao/TodoDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ interface TodoDao {
@Query("DELETE FROM TodoModel WHERE workspaceId = :workspaceId")
fun deleteAllWorkspaceLists(workspaceId: String)

@Query("SELECT * FROM TodoModel where workspaceId IN (:workspaceId)")
fun loadAllLists(workspaceId: String): Flow<List<TodoModel>>
@Query("SELECT * FROM TodoModel")
fun loadTodoData(): Flow<List<TodoModel>>

@Query("SELECT * FROM TodoModel")
suspend fun loadAllLists(): List<TodoModel>
Expand Down
97 changes: 96 additions & 1 deletion app/src/main/java/com/flux/data/database/FluxDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import java.util.UUID

@Database(
entities = [EventModel::class, LabelModel::class, EventInstanceModel::class, SettingsModel::class, NotesModel::class, HabitModel::class, HabitInstanceModel::class, WorkspaceModel::class, TodoModel::class, JournalModel::class, ProgressBoardModel::class],
version = 7,
version = 11,
exportSchema = false
)
@TypeConverters(Converter::class)
Expand Down Expand Up @@ -260,4 +260,99 @@ val MIGRATION_6_7 = object : Migration(6, 7) {
if (!db.columnExists("SettingsModel", "useSystemTimeFormat"))
db.safeExec("ALTER TABLE SettingsModel ADD COLUMN useSystemTimeFormat INTEGER NOT NULL DEFAULT 0")
}
}

val MIGRATION_7_8 = object : Migration(7, 8) {
override fun migrate(db: SupportSQLiteDatabase) {

// ---------------------- HabitModel rebuild ----------------------
if (!db.tableExists("HabitModel_new")) {

db.safeExec("""
CREATE TABLE HabitModel_new (
id TEXT NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL,
recurrence TEXT NOT NULL,
startDateTime INTEGER NOT NULL,
endDateTime INTEGER NOT NULL,
notificationOffset INTEGER NOT NULL,
workspaceId TEXT NOT NULL,
habitConfig TEXT NOT NULL
)
""")

// Default HabitConfig → Simple
val defaultConfig = """{"type":"Simple"}"""

db.safeExec("""
INSERT INTO HabitModel_new (
id, title, description, recurrence,
startDateTime, endDateTime,
notificationOffset, workspaceId, habitConfig
)
SELECT
id, title, description, recurrence,
startDateTime, endDateTime,
notificationOffset, workspaceId,
'$defaultConfig'
FROM HabitModel
""")

db.safeExec("DROP TABLE HabitModel")
db.safeExec("ALTER TABLE HabitModel_new RENAME TO HabitModel")
}
}
}

val Migration_8_9 = object : Migration(8, 9){
override fun migrate(db: SupportSQLiteDatabase) {
db.safeExec("ALTER TABLE HabitInstanceModel ADD COLUMN completed INTEGER NOT NULL DEFAULT 0")
db.safeExec("ALTER TABLE HabitInstanceModel ADD COLUMN timeSpent INTEGER NOT NULL DEFAULT 0")
db.safeExec("ALTER TABLE HabitInstanceModel ADD COLUMN isRunning INTEGER NOT NULL DEFAULT 0")
db.safeExec("ALTER TABLE HabitInstanceModel ADD COLUMN count INTEGER NOT NULL DEFAULT 0")
}
}

val MIGRATION_9_10 = object : Migration(9, 10) {
override fun migrate(db: SupportSQLiteDatabase) {

if (!db.tableExists("WorkspaceModel_new")) {
db.execSQL("""
CREATE TABLE WorkspaceModel_new (
workspaceId TEXT NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL,
colorInd INTEGER NOT NULL,
cover TEXT NOT NULL,
icon INTEGER NOT NULL,
passKey TEXT,
isPinned INTEGER NOT NULL,
selectedSpaces TEXT NOT NULL
)
""".trimIndent())

db.execSQL("""
INSERT INTO WorkspaceModel_new (
workspaceId, title, description, colorInd,
cover, icon, passKey, isPinned, selectedSpaces
)
SELECT
workspaceId, title, description, colorInd,
cover, icon,
CASE WHEN passKey = '' THEN NULL ELSE passKey END,
isPinned, selectedSpaces
FROM WorkspaceModel
""".trimIndent())

db.execSQL("DROP TABLE WorkspaceModel")
db.execSQL("ALTER TABLE WorkspaceModel_new RENAME TO WorkspaceModel")
}
}
}

val MIGRATION_10_11 = object : Migration(10, 11) {
override fun migrate(db: SupportSQLiteDatabase) {
db.safeExec("ALTER TABLE JournalModel ADD COLUMN labels TEXT NOT NULL DEFAULT '[]'")
}
}
16 changes: 16 additions & 0 deletions app/src/main/java/com/flux/data/model/Converter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Converter {
encodeDefaults = true
ignoreUnknownKeys = true
coerceInputValues = true
classDiscriminator = "type"
}

@TypeConverter
Expand Down Expand Up @@ -84,6 +85,21 @@ class Converter {
val listType = object : TypeToken<List<String>>() {}.type
return Gson().fromJson(value, listType)
}

@TypeConverter
fun fromConfig(config: HabitConfig): String {
return json.encodeToString(config)
}

@TypeConverter
fun toConfig(value: String): HabitConfig {
return try {
json.decodeFromString(value)
} catch (
_: Exception) {
HabitConfig.Simple // fallback (critical)
}
}
}

// Helper class for parsing old data format (without id field)
Expand Down
Loading
Loading