diff --git a/.gitignore b/.gitignore
index b2779be..7d2ee0d 100755
--- a/.gitignore
+++ b/.gitignore
@@ -19,7 +19,6 @@ captures/
output.json
# IntelliJ
-*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
@@ -34,4 +33,4 @@ google-services.json
# Android Profiling
*.hprof
-xcuserdata
\ No newline at end of file
+xcuserdata
diff --git a/apps/androidApp/build.gradle.kts b/apps/androidApp/build.gradle.kts
index 5a78ce2..c826d0f 100755
--- a/apps/androidApp/build.gradle.kts
+++ b/apps/androidApp/build.gradle.kts
@@ -46,7 +46,9 @@ android {
dependencies {
implementation(project(":shared"))
- implementation(platform(libs.compose.bom))
+ val composeBom = platform(libs.androidx.compose.bom)
+ implementation(composeBom)
+ androidTestImplementation(composeBom)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.core.splashscreen)
diff --git a/apps/androidApp/src/main/AndroidManifest.xml b/apps/androidApp/src/main/AndroidManifest.xml
index 3cf92e4..f5d1472 100755
--- a/apps/androidApp/src/main/AndroidManifest.xml
+++ b/apps/androidApp/src/main/AndroidManifest.xml
@@ -15,6 +15,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MindSync"
+ android:windowSoftInputMode="adjustResize"
tools:targetApi="31"
android:usesCleartextTraffic="true">
diff --git a/apps/androidApp/src/main/kotlin/io/astrum/mindsync/app/android/MainActivity.kt b/apps/androidApp/src/main/kotlin/io/astrum/mindsync/app/android/MainActivity.kt
index ee6a63b..6d8836a 100755
--- a/apps/androidApp/src/main/kotlin/io/astrum/mindsync/app/android/MainActivity.kt
+++ b/apps/androidApp/src/main/kotlin/io/astrum/mindsync/app/android/MainActivity.kt
@@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
+import androidx.core.view.WindowCompat
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import io.astrum.mindsync.app.MainApp
import io.astrum.mindsync.app.common.model.theme.DarkThemeConfig
@@ -17,6 +18,8 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+
val uiState: MainActivityUiState by mutableStateOf(MainActivityUiState.Loading)
setContent {
diff --git a/apps/iosApp/iosApp.xcodeproj/project.pbxproj b/apps/iosApp/iosApp.xcodeproj/project.pbxproj
index bd79aec..e3d21a1 100755
--- a/apps/iosApp/iosApp.xcodeproj/project.pbxproj
+++ b/apps/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -323,6 +323,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
+ DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -331,17 +332,19 @@
);
INFOPLIST_FILE = iosApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MindSync;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
+ MARKETING_VERSION = 0.0.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
shared,
);
PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp;
- PRODUCT_NAME = "$(TARGET_NAME)";
+ PRODUCT_NAME = "MindSync (Debug)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -354,6 +357,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
+ DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -362,17 +366,19 @@
);
INFOPLIST_FILE = iosApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MindSync;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
+ MARKETING_VERSION = 0.0.1;
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
shared,
);
PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp;
- PRODUCT_NAME = "$(TARGET_NAME)";
+ PRODUCT_NAME = "MindSync";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
diff --git a/apps/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme b/apps/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme
index f2368c9..a229b5e 100755
--- a/apps/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme
+++ b/apps/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme
@@ -15,7 +15,7 @@
@@ -44,7 +44,7 @@
@@ -61,7 +61,7 @@
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 17e12bc..513cf2c 100755
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -3,15 +3,16 @@ kotlin = "1.9.20"
ktor-client = "2.3.6"
ktor-server = "2.3.6"
multiplatform-settings = "1.1.0"
+uiToolingPreviewAndroid = "1.5.4"
voyager = "1.0.0-rc10"
koin = "3.5.0"
koin-compose = "1.1.0"
junit = "4.13.2"
androidGradlePlugin = "8.1.4"
-composeMultiplatform = "1.5.10"
+composeMultiplatform = "1.5.11"
compose-compiler = "1.5.4"
exposed = "0.37.3"
-skiko = "0.7.85"
+skiko = "0.7.85.4"
klint-plugin = "11.6.1"
klint = "1.0.1"
detekt = "1.23.3"
@@ -20,14 +21,16 @@ androidx-junit = "1.1.5"
espressoCore = "3.5.1"
accompanistSystemuicontroller = "0.32.0"
activityCompose = "1.8.1"
-firebase = "32.5.0"
+firebase = "32.6.0"
owasp = "8.4.3"
asciidoctor = "4.0.0-alpha.1"
dokka = "1.9.10"
+androidxComposeBom = "2023.10.01"
[libraries]
# Gradle Plugins
+androidx-ui-tooling-preview-android = { module = "androidx.compose.ui:ui-tooling-preview-android", version.ref = "uiToolingPreviewAndroid" }
gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
gradle-ktlint = { module = "org.jlleitschuh.gradle.ktlint:org.jlleitschuh.gradle.ktlint.gradle.plugin", version.ref = "klint-plugin" }
gradle-ktlint-idea = { module = "org.jlleitschuh.gradle.ktlint-idea:org.jlleitschuh.gradle.ktlint-idea.gradle.plugin", version.ref = "klint-plugin" }
@@ -72,8 +75,12 @@ voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voy
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" }
+# External Libs
+rich-editor = { module = "com.mohamedrejeb.richeditor:richeditor-compose", version = "1.0.0-beta03"}
+
# Android
-compose-bom = "androidx.compose:compose-bom:2023.10.01"
+androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidxComposeBom" }
+androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" }
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
androidx-core-ktx = "androidx.core:core-ktx:1.12.0"
diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts
index 8d7c2a9..0f2369b 100755
--- a/shared/build.gradle.kts
+++ b/shared/build.gradle.kts
@@ -7,7 +7,7 @@ plugins {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
kotlin {
- targetHierarchy.default()
+ kotlin.applyDefaultHierarchyTemplate()
androidTarget {
compilations.all {
@@ -70,14 +70,19 @@ kotlin {
// Logging
implementation(libs.kermit)
+
+ implementation(libs.rich.editor)
}
}
val androidMain by getting {
+ dependsOn(commonMain)
dependencies {
implementation(libs.ktor.client.android)
+ implementation(libs.androidx.core.ktx)
}
}
val iosMain by getting {
+ dependsOn(commonMain)
dependencies {
implementation(libs.ktor.client.darwin)
}
@@ -112,3 +117,7 @@ android {
targetCompatibility = JavaVersion.VERSION_17
}
}
+dependencies {
+ implementation("androidx.core:core-ktx:+")
+ implementation("org.jetbrains.kotlin:kotlin-stdlib:1.0.0")
+}
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/data/repositories/SimpleRowCalendarDataSource.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/data/repositories/SimpleRowCalendarDataSource.kt
new file mode 100644
index 0000000..d4aec10
--- /dev/null
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/data/repositories/SimpleRowCalendarDataSource.kt
@@ -0,0 +1,61 @@
+package io.astrum.mindsync.app.data.repositories
+
+import io.astrum.mindsync.app.ui.screens.viewmodel.SimpleRowCalendarUiModel
+import kotlinx.datetime.Clock
+import kotlinx.datetime.DateTimeUnit.Companion.DAY
+import kotlinx.datetime.DayOfWeek
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.TimeZone
+import kotlinx.datetime.minus
+import kotlinx.datetime.plus
+import kotlinx.datetime.todayIn
+
+class SimpleRowCalendarDataSource {
+ private val today: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault())
+
+ fun getData(
+ startDate: LocalDate = today,
+ lastSelectedDate: LocalDate
+ ): SimpleRowCalendarUiModel {
+ val visibleDates = getVisibleDates(startDate)
+ val selectedDate = getSelectedDate(visibleDates, lastSelectedDate)
+ return SimpleRowCalendarUiModel(selectedDate, visibleDates)
+ }
+
+ private fun getSelectedDate(
+ visibleDates: List,
+ lastSelectedDate: LocalDate
+ ): SimpleRowCalendarUiModel.Date {
+ /* if the lastSelectedDate is not in the visibleDates,
+ then return the same position as the lastSelectedDate was before */
+ val index = visibleDates.indexOfFirst { it.date == lastSelectedDate }
+ val selectedDate = if (index == -1) {
+ // the day that has the same day of the week as the lastSelectedDate
+ val dayOfWeek = lastSelectedDate.dayOfWeek
+ visibleDates.firstOrNull { it.date.dayOfWeek == dayOfWeek } ?: visibleDates.first()
+ } else {
+ visibleDates[index]
+ }
+ return selectedDate.copy(isSelected = true)
+ }
+
+ private fun getVisibleDates(startDate: LocalDate): List {
+ val dates = mutableListOf()
+ // Get the current week day
+ val currentDayOfWeek: DayOfWeek = startDate.dayOfWeek
+ // Get the first day of the week
+ val firstDayOfWeek: LocalDate = startDate.minus(currentDayOfWeek.ordinal, DAY)
+ // fill the dates with the days of the week
+ for (i in 0.. Unit,
+ onItalicClick: (TextFormatOptionUiModel) -> Unit,
+ onUnderlinedClick: (TextFormatOptionUiModel) -> Unit
+) {
+ Divider(
+ color = MaterialTheme.colorScheme.primary,
+ modifier = Modifier
+ .height(0.8.dp)
+ .fillMaxHeight()
+ .fillMaxWidth()
+ )
+ Row(
+ modifier = Modifier
+ .background(MaterialTheme.colorScheme.surface)
+ .fillMaxWidth()
+ .height(38.dp)
+ .padding(1.dp),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Row {
+ IconButton(
+ onClick = {}
+ ) {
+ Icon(
+ imageVector = Icons.Filled.Add,
+ contentDescription = "Insert Block",
+ )
+ }
+ EditorToolbarButton(
+ Icons.Filled.FormatBold,
+ "Format Bold",
+ textFormatOptionUiModel.isBold
+ ){
+ onBoldClick(textFormatOptionUiModel)
+ }
+ EditorToolbarButton(
+ Icons.Filled.FormatItalic,
+ "Format Italic",
+ textFormatOptionUiModel.isItalic
+ ) {
+ onItalicClick(textFormatOptionUiModel)
+ }
+ EditorToolbarButton(
+ Icons.Filled.FormatUnderlined,
+ "Format Underline",
+ textFormatOptionUiModel.isUnderlined
+ ) {
+ onUnderlinedClick(textFormatOptionUiModel)
+ }
+ // Add other formatting options as needed
+ }
+ Row {
+ Divider(
+ color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f),
+ modifier = Modifier
+ .fillMaxHeight()
+ .width(0.5.dp).padding(vertical = 5.dp)
+ )
+ IconButton(
+ onClick = {
+ keyboardController?.hide()
+ }
+ ) {
+ Icon(
+ imageVector = Icons.Filled.KeyboardHide,
+ contentDescription = "Hide Keyboard",
+ )
+ }
+ }
+ }
+}
+
+@Composable
+fun EditorToolbarButton(
+ imageVector: ImageVector,
+ contentDescription: String,
+ isSelected: Boolean,
+ onClick: () -> Unit
+) {
+ IconButton(
+ onClick = onClick
+ ) {
+ Icon(
+ imageVector = imageVector,
+ contentDescription = contentDescription
+ )
+ }
+}
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/components/SimpleRowCalendar.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/components/SimpleRowCalendar.kt
new file mode 100644
index 0000000..63afc70
--- /dev/null
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/components/SimpleRowCalendar.kt
@@ -0,0 +1,143 @@
+package io.astrum.mindsync.app.ui.components
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ChevronLeft
+import androidx.compose.material.icons.filled.ChevronRight
+import androidx.compose.material3.Divider
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ShapeDefaults
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import io.astrum.mindsync.app.ui.screens.viewmodel.SimpleRowCalendarUiModel
+import kotlinx.datetime.LocalDate
+
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun SimpleRowCalendar(
+ data: SimpleRowCalendarUiModel,
+ // calbacks to click previous & back button should be registered outside
+ onPrevClickListener: (LocalDate) -> Unit,
+ onNextClickListener: (LocalDate) -> Unit,
+ onDateClickListener: (SimpleRowCalendarUiModel.Date) -> Unit,
+) {
+ Row(modifier = Modifier.windowInsetsPadding(
+ TopAppBarDefaults.windowInsets
+ )) {
+ IconButton(onClick = { onPrevClickListener(data.startDate.date) }) {
+ Icon(
+ imageVector = Icons.Filled.ChevronLeft,
+ contentDescription = "Previous"
+ )
+ }
+ SimpleRowCalendarContent(data, onDateClickListener)
+ IconButton(onClick = { onNextClickListener(data.endDate.date) }) {
+ Icon(
+ imageVector = Icons.Filled.ChevronRight,
+ contentDescription = "Next"
+ )
+ }
+ }
+ Divider(
+ color = MaterialTheme.colorScheme.primary,
+ modifier = Modifier
+ .height(0.8.dp)
+ .fillMaxHeight()
+ .fillMaxWidth()
+ )
+}
+
+@Composable
+private fun SimpleRowCalendarContent(
+ data: SimpleRowCalendarUiModel,
+ onDateClickListener: (SimpleRowCalendarUiModel.Date) -> Unit,
+) {
+ LazyRow {
+ items(items = data.visibleDates) { date ->
+ ContentSimpleRowCalendarItem(date, onDateClickListener)
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun ContentSimpleRowCalendarItem(
+ date: SimpleRowCalendarUiModel.Date,
+ onDateClickListener: (SimpleRowCalendarUiModel.Date) -> Unit
+) {
+ val isSelected = date.isSelected
+ val modifier: Modifier = Modifier
+ .width(40.dp)
+ .height(48.dp)
+ .padding(1.dp)
+ .clickable {
+ onDateClickListener(date)
+ }
+ Column(
+ modifier = if (isSelected) {
+ modifier.border(
+ BorderStroke(0.4.dp, MaterialTheme.colorScheme.primary),
+ ShapeDefaults.ExtraSmall
+ ).background(MaterialTheme.colorScheme.primary.copy(alpha = 0.2f))
+ } else {
+ modifier
+ }
+ ) {
+ Text(
+ text = date.date.dayOfMonth.toString(),
+ modifier = Modifier.align(Alignment.CenterHorizontally),
+ fontSize = 14.sp,
+ fontWeight = if(date.isSelected) {
+ FontWeight.Bold
+ } else {
+ FontWeight.Normal
+ },
+ color = if (date.isToday) {
+ Color.Red
+ } else if(date.isSelected) {
+ MaterialTheme.colorScheme.primary
+ } else {
+ MaterialTheme.colorScheme.secondary
+ }
+ )
+ Text(
+ text = date.day.substring(0, 3),
+ modifier = Modifier.align(Alignment.CenterHorizontally),
+ fontSize = 8.sp,
+ fontWeight = if(date.isSelected) {
+ FontWeight.Bold
+ } else {
+ FontWeight.Light
+ },
+ color = if (date.isSelected) {
+ MaterialTheme.colorScheme.primary
+ } else {
+ MaterialTheme.colorScheme.onSurface
+ }
+ )
+ }
+}
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/CurrentDayScreen.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/CurrentDayScreen.kt
new file mode 100755
index 0000000..548d956
--- /dev/null
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/CurrentDayScreen.kt
@@ -0,0 +1,252 @@
+package io.astrum.mindsync.app.ui.screens
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.ime
+import androidx.compose.foundation.layout.imePadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Divider
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.platform.SoftwareKeyboardController
+import androidx.compose.ui.unit.dp
+import cafe.adriel.voyager.core.screen.Screen
+import io.astrum.mindsync.app.data.repositories.SimpleRowCalendarDataSource
+import io.astrum.mindsync.app.ui.components.DailyNote
+import io.astrum.mindsync.app.ui.components.SimpleRowCalendar
+import io.astrum.mindsync.app.ui.icon.ApplicationIcons
+import io.astrum.mindsync.app.ui.screens.viewmodel.SimpleRowCalendarUiModel
+import io.astrum.mindsync.app.ui.theme.ApplicationTheme
+import kotlinx.datetime.Clock
+import kotlinx.datetime.DateTimeUnit
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.TimeZone
+import kotlinx.datetime.minus
+import kotlinx.datetime.plus
+import kotlinx.datetime.todayIn
+
+class CurrentDayScreen(
+ private val date: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault())
+) : Screen {
+ private val toolbarButtons = listOf(
+ ToolbarButton(id = "ai_block",
+ icon = ApplicationIcons.Sparkle,
+ contentDescription = "Insert Block",
+ onClick = {}),
+ ToolbarButton(id = "insert_block",
+ icon = ApplicationIcons.Add,
+ contentDescription = "Insert Block",
+ onClick = {}),
+ ToolbarButton(id = "transform_block",
+ icon = ApplicationIcons.Repeat,
+ contentDescription = "Transform a Block to another",
+ onClick = {}),
+ ToolbarButton(id = "image_block",
+ icon = ApplicationIcons.PhotoLibrary,
+ contentDescription = "Insert Image",
+ onClick = {}),
+ ToolbarButton(id = "format_text",
+ icon = ApplicationIcons.TextFormat,
+ contentDescription = "Format Text",
+ onClick = {}),
+ ToolbarButton(id = "undo",
+ icon = ApplicationIcons.Undo,
+ contentDescription = "Undo",
+ onClick = {}),
+ ToolbarButton(id = "mention_someone",
+ icon = ApplicationIcons.AlternateEmail,
+ contentDescription = "Mention someone",
+ onClick = {}),
+ ToolbarButton(id = "delete_block",
+ icon = ApplicationIcons.Delete,
+ contentDescription = "Delete Block",
+ onClick = {}),
+ ToolbarButton(id = "increase_indentation",
+ icon = ApplicationIcons.FormatIndentIncrease,
+ contentDescription = "Increase Indentation",
+ onClick = {}),
+ ToolbarButton(id = "decrease_indentation",
+ icon = ApplicationIcons.FormatIndentDecrease,
+ contentDescription = "Decrease Indentation",
+ onClick = {}),
+ ToolbarButton(id = "align_bottom",
+ icon = ApplicationIcons.VerticalAlignBottom,
+ contentDescription = "Align Bottom",
+ onClick = {}),
+ ToolbarButton(id = "align_top",
+ icon = ApplicationIcons.VerticalAlignTop,
+ contentDescription = "Align Top",
+ onClick = {}),
+ ToolbarButton(id = "more_options",
+ icon = ApplicationIcons.MoreHoriz,
+ contentDescription = "More Options",
+ onClick = {}),
+ )
+
+ @Composable
+ override fun Content() {
+ ApplicationTheme {
+ CurrentDayView(date)
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
+ @Composable
+ fun CurrentDayView(
+ date: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault())
+ ) {
+ val dataSource = SimpleRowCalendarDataSource()
+ // we use `mutableStateOf` and `remember` inside composable function to schedules recomposition
+ var calendarUiModel by remember { mutableStateOf(dataSource.getData(lastSelectedDate = date)) }
+ fun onDateClickListener(date: SimpleRowCalendarUiModel.Date) {
+ // refresh the CalendarUiModel with new data
+ // by changing only the `selectedDate` with the date selected by User
+ calendarUiModel = calendarUiModel.copy(selectedDate = date,
+ visibleDates = calendarUiModel.visibleDates.map {
+ it.copy(
+ isSelected = it.date == date.date
+ )
+ })
+ }
+ onDateClickListener(calendarUiModel.selectedDate)
+ fun onPreviousClickListener(
+ startDate: LocalDate
+ ) {
+ calendarUiModel = dataSource.getData(
+ startDate.minus(1, DateTimeUnit.DAY), calendarUiModel.selectedDate.date
+ )
+ }
+
+ fun onNextClickListener(
+ startDate: LocalDate
+ ) {
+ calendarUiModel = dataSource.getData(
+ startDate.plus(2, DateTimeUnit.DAY),
+ calendarUiModel.selectedDate.date
+ )
+ }
+
+ ApplicationTheme {
+ Scaffold(topBar = {
+ SimpleRowCalendar(calendarUiModel, onPrevClickListener = { startDate ->
+ onPreviousClickListener(startDate)
+ }, onNextClickListener = { startDate ->
+ onNextClickListener(startDate)
+ }, onDateClickListener = { date ->
+ onDateClickListener(date)
+ })
+ }, bottomBar = {
+ DailyNoteEditorToolbar()
+ }) {
+ val scrollState = rememberScrollState()
+
+ Column(
+ modifier = Modifier.padding(it).padding(bottom = 46.dp)
+ .background(MaterialTheme.colorScheme.background)
+ .verticalScroll(scrollState)
+ ) {
+ DailyNote(calendarUiModel)
+ Text(text = "This part is for the 'Created today' row")
+
+ Column(modifier = Modifier.fillMaxWidth()) {
+ Text(
+ text = "Hello World! -> ${
+ WindowInsets.Companion.ime.getBottom(
+ LocalDensity.current
+ )
+ }"
+ )
+ Text(text = "Not Visible")
+ }
+ }
+ }
+ }
+ }
+
+ @OptIn(ExperimentalComposeUiApi::class, ExperimentalFoundationApi::class)
+ @Composable
+ private fun DailyNoteEditorToolbar(
+ keyboardController: SoftwareKeyboardController? = LocalSoftwareKeyboardController.current
+ ) {
+ Column(
+ modifier = Modifier.windowInsetsPadding(WindowInsets.ime).imePadding().fillMaxWidth()
+ ) {
+ val dividerColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f)
+ Divider(
+ color = dividerColor,
+ modifier = Modifier.height(0.8.dp).fillMaxHeight().fillMaxWidth()
+ )
+
+ Row(modifier = Modifier.fillMaxWidth()) {
+ LazyRow(modifier = Modifier.weight(1F)) {
+ items(toolbarButtons) { button ->
+ IconButton(
+ onClick = button.onClick
+ ) {
+ Icon(
+ imageVector = button.icon,
+ contentDescription = button.contentDescription,
+ )
+ }
+ }
+ }
+
+ Row(
+ modifier = Modifier.drawBehind {
+ val strokeWidth = 1 * density
+ val topSpace = 8.dp.toPx()
+ val bottomSpace = 8.dp.toPx()
+ // Draw line function for left border with space at top and bottom
+ drawLine(
+ dividerColor,
+ start = Offset(0f, topSpace),
+ end = Offset(0f, size.height - bottomSpace),
+ strokeWidth
+ )
+ }
+ ) {
+ IconButton(onClick = {
+ keyboardController?.hide()
+ }) {
+ Icon(
+ imageVector = ApplicationIcons.KeyboardHide,
+ contentDescription = "Hide Keyboard",
+ )
+ }
+ }
+ }
+ }
+ }
+}
+
+data class ToolbarButton(
+ val id: String, val icon: ImageVector, val contentDescription: String, val onClick: () -> Unit
+)
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/MainScreen.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/MainScreen.kt
index ac19f4c..4394e39 100755
--- a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/MainScreen.kt
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/MainScreen.kt
@@ -17,7 +17,7 @@ import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabNavigator
import cafe.adriel.voyager.transitions.SlideTransition
import io.astrum.mindsync.app.feature.petupload.PetUploadScreen
-import io.astrum.mindsync.app.navigation.FavoritesTab
+import io.astrum.mindsync.app.navigation.CurrentDayTab
import io.astrum.mindsync.app.navigation.HomeTab
import io.astrum.mindsync.app.navigation.InboxTab
import io.astrum.mindsync.app.navigation.PetUploadTab
@@ -41,24 +41,24 @@ class MainScreen : Screen {
@Composable
fun MainScreenView() {
- val snackbarHostState = remember { SnackbarHostState() }
+ val snackBarHostState = remember { SnackbarHostState() }
val rootNavigator = LocalNavigator.currentOrThrow
TabNavigator(
- HomeTab,
+ CurrentDayTab,
disposeNestedNavigators = false
) { _ ->
val rootNavigatorRepository = setupRootNavigator(rootNavigator, LocalTabNavigator.current)
- val rootSnackbarHostStateRepository = setupRootSnackbarHostState(snackbarHostState)
+ val rootSnackBarHostStateRepository = setupRootSnackBarHostState(snackBarHostState)
Scaffold(
containerColor = MaterialTheme.colorScheme.background,
contentColor = MaterialTheme.colorScheme.onBackground,
contentWindowInsets = WindowInsets(0, 0, 0, 0),
- snackbarHost = { SnackbarHost(rootSnackbarHostStateRepository.snackbarHostState) },
+ snackbarHost = { SnackbarHost(rootSnackBarHostStateRepository.snackbarHostState) },
bottomBar = {
ApplicationNavigationBar {
TabNavigationItem(HomeTab, rootNavigatorRepository)
- TabNavigationItem(FavoritesTab, rootNavigatorRepository)
+ TabNavigationItem(CurrentDayTab, rootNavigatorRepository)
TabNavigationItem(PetUploadTab, rootNavigatorRepository)
TabNavigationItem(InboxTab, rootNavigatorRepository)
TabNavigationItem(ProfileTab, rootNavigatorRepository)
@@ -77,9 +77,9 @@ fun setupRootNavigator(rootNavigator: Navigator, tabNavigator: TabNavigator): Ro
return koin.get(null, parameters = { ParametersHolder(listOf(rootNavigator, tabNavigator).toMutableList(), false) })
}
-fun setupRootSnackbarHostState(snackbarHostState: SnackbarHostState): RootSnackbarHostStateRepository {
+fun setupRootSnackBarHostState(snackBarHostState: SnackbarHostState): RootSnackbarHostStateRepository {
val koin = KoinPlatform.getKoin()
- return koin.get(null, parameters = { ParametersHolder(listOf(snackbarHostState).toMutableList(), false) })
+ return koin.get(null, parameters = { ParametersHolder(listOf(snackBarHostState).toMutableList(), false) })
}
@Composable
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/PetDetailScreen.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/PetDetailScreen.kt
index d0cfda9..461c3ca 100755
--- a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/PetDetailScreen.kt
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/PetDetailScreen.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalMaterial3Api::class)
-
package io.astrum.mindsync.app.ui.screens
import androidx.compose.foundation.background
@@ -57,6 +55,7 @@ class PetDetailScreen(private val petId: Int) : Screen {
}
}
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PetDetailView(petModel: PetModel, onClose: () -> Unit) {
val scrollState = rememberScrollState()
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/viewmodel/SimpleRowCalendarUiModel.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/viewmodel/SimpleRowCalendarUiModel.kt
new file mode 100644
index 0000000..cb456e8
--- /dev/null
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/viewmodel/SimpleRowCalendarUiModel.kt
@@ -0,0 +1,20 @@
+package io.astrum.mindsync.app.ui.screens.viewmodel
+
+import kotlinx.datetime.LocalDate
+
+data class SimpleRowCalendarUiModel(
+ val selectedDate: Date, // the date selected by the User. by default is Today.
+ val visibleDates: List // the dates shown on the screen
+) {
+
+ val startDate: Date = visibleDates.first() // the first of the visible dates
+ val endDate: Date = visibleDates.last() // the last of the visible dates
+
+ data class Date(
+ val date: LocalDate,
+ val isSelected: Boolean,
+ val isToday: Boolean
+ ) {
+ val day: String = date.dayOfWeek.name // get the day by accessing the dayOfWeek property
+ }
+}
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/viewmodel/TextFormatOptionUiModel.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/viewmodel/TextFormatOptionUiModel.kt
new file mode 100644
index 0000000..254f6b8
--- /dev/null
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/screens/viewmodel/TextFormatOptionUiModel.kt
@@ -0,0 +1,29 @@
+package io.astrum.mindsync.app.ui.screens.viewmodel
+
+data class TextFormatOptionUiModel(
+ val isBold: Boolean,
+ val isItalic: Boolean,
+ val isUnderlined: Boolean,
+ val isStrikethrough: Boolean,
+ val isBullet: Boolean,
+ val isNumbered: Boolean,
+ val isQuote: Boolean,
+ val isLink: Boolean,
+ val isCode: Boolean,
+ val isClear: Boolean
+) {
+ companion object {
+ val Default = TextFormatOptionUiModel(
+ isBold = false,
+ isItalic = false,
+ isUnderlined = false,
+ isStrikethrough = false,
+ isBullet = false,
+ isNumbered = false,
+ isQuote = false,
+ isLink = false,
+ isCode = false,
+ isClear = false
+ )
+ }
+}
diff --git a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/theme/Color.kt b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/theme/Color.kt
index b6011e4..087098e 100755
--- a/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/theme/Color.kt
+++ b/shared/src/commonMain/kotlin/io/astrum/mindsync/app/ui/theme/Color.kt
@@ -2,59 +2,60 @@ package io.astrum.mindsync.app.ui.theme
import androidx.compose.ui.graphics.Color
-val lightPrimary = Color(0xFF825500)
+val lightPrimary = Color(0xFF6750A4)
val lightOnPrimary = Color(0xFFFFFFFF)
-val lightPrimaryContainer = Color(0xFFFFDDAE)
-val lightOnPrimaryContainer = Color(0xFF2A1800)
-val lightSecondary = Color(0xFF6F5B40)
+val lightPrimaryContainer = Color(0xFFEADDFF)
+val lightOnPrimaryContainer = Color(0xFF21005D)
+val lightSecondary = Color(0xFF625B71)
val lightOnSecondary = Color(0xFFFFFFFF)
-val lightSecondaryContainer = Color(0xFFFADEBC)
-val lightOnSecondaryContainer = Color(0xFF271904)
-val lightTertiary = Color(0xFF516440)
+val lightSecondaryContainer = Color(0xFFE8DEF8)
+val lightOnSecondaryContainer = Color(0xFF1D192B)
+val lightTertiary = Color(0xFF7D5260)
val lightOnTertiary = Color(0xFFFFFFFF)
-val lightTertiaryContainer = Color(0xFFD3EABC)
-val lightOnTertiaryContainer = Color(0xFF102004)
-val lightError = Color(0xFFBA1B1B)
-val lightErrorContainer = Color(0xFFFFDAD4)
+val lightTertiaryContainer = Color(0xFFFFD8E4)
+val lightOnTertiaryContainer = Color(0xFF31111D)
+val lightError = Color(0xFFB3261E)
+val lightErrorContainer = Color(0xFFF9DEDC)
val lightOnError = Color(0xFFFFFFFF)
-val lightOnErrorContainer = Color(0xFF410001)
-val lightBackground = Color(0xFFFCFCFC)
-val lightOnBackground = Color(0xFF1F1B16)
-val lightSurface = Color(0xFFFCFCFC)
-val lightOnSurface = Color(0xFF1F1B16)
-val lightSurfaceVariant = Color(0xFFF0E0CF)
-val lightOnSurfaceVariant = Color(0xFF4F4539)
-val lightOutline = Color(0xFF817567)
-val lightInverseOnSurface = Color(0xFFF9EFE6)
-val lightInverseSurface = Color(0xFF34302A)
-val lightPrimaryInverse = Color(0xFFFFB945)
+val lightOnErrorContainer = Color(0xFF410E0B)
+val lightBackground = Color(0xFFFFFBFE)
+val lightOnBackground = Color(0xFF1C1B1F)
+val lightSurface = Color(0xFFFFFBFE)
+val lightOnSurface = Color(0xFF1C1B1F)
+val lightSurfaceVariant = Color(0xFFE7E0EC)
+val lightOnSurfaceVariant = Color(0xFF49454F)
+val lightOutline = Color(0xFF79747E)
+val lightInverseOnSurface = Color(0xFFF4EFF4)
+val lightInverseSurface = Color(0xFF313033)
+val lightPrimaryInverse = Color(0xFFD0BCFF)
+
+val darkPrimary = Color(0xFFD0BCFF)
+val darkOnPrimary = Color(0xFF381E72)
+val darkPrimaryContainer = Color(0xFF4F378B)
+val darkOnPrimaryContainer = Color(0xFFEADDFF)
+val darkSecondary = Color(0xFFCCC2DC)
+val darkOnSecondary = Color(0xFF332D41)
+val darkSecondaryContainer = Color(0xFF4A4458)
+val darkOnSecondaryContainer = Color(0xFFE8DEF8)
+val darkTertiary = Color(0xFFEFB8C8)
+val darkOnTertiary = Color(0xFF492532)
+val darkTertiaryContainer = Color(0xFF633B48)
+val darkOnTertiaryContainer = Color(0xFFFFD8E4)
+val darkError = Color(0xFFF2B8B5)
+val darkErrorContainer = Color(0xFF8C1D18)
+val darkOnError = Color(0xFF601410)
+val darkOnErrorContainer = Color(0xFFF9DEDC)
+val darkBackground = Color(0xFF1C1B1F)
+val darkOnBackground = Color(0xFFE6E1E5)
+val darkSurface = Color(0xFF1C1B1F)
+val darkOnSurface = Color(0xFFE6E1E5)
+val darkSurfaceVariant = Color(0xFF49454F)
+val darkOnSurfaceVariant = Color(0xFFCAC4D0)
+val darkOutline = Color(0xFF938F99)
+val darkInverseOnSurface = Color(0xFF313033)
+val darkInverseSurface = Color(0xFFE6E1E5)
+val darkPrimaryInverse = Color(0xFF6750A4)
-val darkPrimary = Color(0xFFFFB945)
-val darkOnPrimary = Color(0xFF452B00)
-val darkPrimaryContainer = Color(0xFF624000)
-val darkOnPrimaryContainer = Color(0xFFFFDDAE)
-val darkSecondary = Color(0xFFDDC3A2)
-val darkOnSecondary = Color(0xFF3E2E16)
-val darkSecondaryContainer = Color(0xFF56442B)
-val darkOnSecondaryContainer = Color(0xFFFADEBC)
-val darkTertiary = Color(0xFFB8CEA2)
-val darkOnTertiary = Color(0xFF243516)
-val darkTertiaryContainer = Color(0xFF3A4C2B)
-val darkOnTertiaryContainer = Color(0xFFD3EABC)
-val darkError = Color(0xFFFFB4A9)
-val darkErrorContainer = Color(0xFF930006)
-val darkOnError = Color(0xFF680003)
-val darkOnErrorContainer = Color(0xFFFFDAD4)
-val darkBackground = Color(0xFF1F1B16)
-val darkOnBackground = Color(0xFFEAE1D9)
-val darkSurface = Color(0xFF1F1B16)
-val darkOnSurface = Color(0xFFEAE1D9)
-val darkSurfaceVariant = Color(0xFF4F4539)
-val darkOnSurfaceVariant = Color(0xFFD3C4B4)
-val darkOutline = Color(0xFF9C8F80)
-val darkInverseOnSurface = Color(0xFF32281A)
-val darkInverseSurface = Color(0xFFEAE1D9)
-val darkPrimaryInverse = Color(0xFF624000)
val successContainer = Color(0xFF017943)
val errorContainer = Color(0xFFB21229)
diff --git a/shared/src/iosMain/kotlin/io/astrum/mindsync/app/main.ios.kt b/shared/src/iosMain/kotlin/io/astrum/mindsync/app/main.ios.kt
index 9fa6860..e2b2dde 100755
--- a/shared/src/iosMain/kotlin/io/astrum/mindsync/app/main.ios.kt
+++ b/shared/src/iosMain/kotlin/io/astrum/mindsync/app/main.ios.kt
@@ -4,10 +4,9 @@ package io.astrum.mindsync.app
import androidx.compose.ui.window.ComposeUIViewController
-import io.astrum.mindsync.app.MainApp
import platform.UIKit.UIViewController
-fun homeScreenViewController(): UIViewController = ComposeUIViewController {
+fun homeScreenViewController(): UIViewController = ComposeUIViewController{
MainApp()
}