Skip to content

add markdown support #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 19, 2025
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: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ dependencies {
implementation(libs.about.libraries)

// Markdown to HTML
//implementation(libs.markdown)
implementation(libs.richtext.commonmark)
implementation(libs.richtext.ui.material3)

// unit test
testImplementation(libs.test.junit.ktx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class AppPreferences(
databaseCommit.update("")
}

val isReadOnlyModeActive = booleanPreference("isReadOnlyModeActive", false)

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContent
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Done
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.LockOpen
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
Expand Down Expand Up @@ -44,6 +45,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewModelScope
import com.halilibo.richtext.commonmark.Markdown
import com.halilibo.richtext.ui.material3.RichText
import io.github.wiiznokes.gitnote.R
import io.github.wiiznokes.gitnote.ui.component.CustomDropDown
import io.github.wiiznokes.gitnote.ui.component.CustomDropDownModel
Expand All @@ -52,6 +56,7 @@ import io.github.wiiznokes.gitnote.ui.destination.EditParams
import io.github.wiiznokes.gitnote.ui.model.EditType
import io.github.wiiznokes.gitnote.ui.model.FileExtension
import io.github.wiiznokes.gitnote.ui.viewmodel.newEditViewModel
import kotlinx.coroutines.launch


private const val TAG = "EditScreen"
Expand Down Expand Up @@ -83,11 +88,11 @@ fun EditScreen(
}
}

val isReadOnlyModeActive = vm.prefs.isReadOnlyModeActive.getAsState().value

Scaffold(
contentWindowInsets = WindowInsets.safeDrawing,
contentColor = MaterialTheme.colorScheme.background,
topBar = {

val backgroundColor = MaterialTheme.colorScheme.surfaceColorAtElevation(15.dp)

TopAppBar(
Expand All @@ -97,7 +102,7 @@ fun EditScreen(
navigationIcon = {
IconButton(
onClick = {
vm.onFinish()
vm.shouldSaveWhenQuitting = false
onFinished()
},
) {
Expand All @@ -117,6 +122,7 @@ fun EditScreen(
onValueChange = {
vm.name.value = it
},
readOnly = isReadOnlyModeActive,
singleLine = true,
placeholder = {
Text(text = stringResource(R.string.note_name))
Expand All @@ -137,36 +143,57 @@ fun EditScreen(
)
},
actions = {
ExtensionChooser(vm.fileExtension)
ExtensionChooser(vm.fileExtension, isReadOnlyModeActive)
Spacer(modifier = Modifier.width(10.dp))
IconButton(
colors = IconButtonDefaults.iconButtonColors(
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary
),
onClick = {
vm.onValidation(onSuccess = null)
}
vm.save()
},
enabled = !isReadOnlyModeActive
) {
SimpleIcon(
imageVector = Icons.Default.Save,
)
}

Spacer(modifier = Modifier.width(10.dp))

IconButton(
colors = IconButtonDefaults.iconButtonColors(
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary
),
onClick = {
vm.viewModelScope.launch {
vm.prefs.isReadOnlyModeActive.update(!isReadOnlyModeActive)
}
},
) {
SimpleIcon(
imageVector = if (isReadOnlyModeActive) {
Icons.Default.Lock
} else {
Icons.Default.LockOpen
},
)
}
}
)
},
floatingActionButton = {

// bug: https://issuetracker.google.com/issues/224005027
//AnimatedVisibility(visible = currentNoteFolderRelativePath.isNotEmpty()) {
if (vm.name.value.text.isNotEmpty()) {
if (!isReadOnlyModeActive && vm.name.value.text.isNotEmpty()) {
FloatingActionButton(
modifier = Modifier,
containerColor = MaterialTheme.colorScheme.primary,
shape = RoundedCornerShape(20.dp),
onClick = {
vm.onFinish()
vm.onValidation(onSuccess = onFinished)
vm.save(onSuccess = onFinished)
}
) {
SimpleIcon(
Expand All @@ -177,48 +204,60 @@ fun EditScreen(
}
}
) { paddingValues ->
TextField(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
.focusRequester(textFocusRequester),
value = vm.content.value,
onValueChange = {
vm.content.value = it
},
colors = TextFieldDefaults.colors(
focusedContainerColor = MaterialTheme.colorScheme.background,
unfocusedContainerColor = MaterialTheme.colorScheme.background,
focusedTextColor = MaterialTheme.colorScheme.onBackground,
unfocusedTextColor = MaterialTheme.colorScheme.onBackground,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
keyboardActions = KeyboardActions(
onDone = {
vm.onFinish()
vm.onValidation(onSuccess = onFinished)
}
)
)

if (isReadOnlyModeActive && vm.fileExtension.value is FileExtension.Md) {
RichText(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
) {
Markdown(vm.content.value.text)
}


} else {
TextField(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
.focusRequester(textFocusRequester),
value = vm.content.value,
onValueChange = {
vm.content.value = it
},
colors = TextFieldDefaults.colors(
focusedContainerColor = MaterialTheme.colorScheme.background,
unfocusedContainerColor = MaterialTheme.colorScheme.background,
focusedTextColor = MaterialTheme.colorScheme.onBackground,
unfocusedTextColor = MaterialTheme.colorScheme.onBackground,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
keyboardActions = KeyboardActions(
onDone = {
vm.save(onSuccess = onFinished)
}
),
readOnly = isReadOnlyModeActive
)
}
}
}


@Composable
private fun ExtensionChooser(
fileExtension: MutableState<FileExtension>
fileExtension: MutableState<FileExtension>,
isReadOnly: Boolean,
) {
Box {
val expanded = remember { mutableStateOf(false) }
Button(
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondary
),
onClick = {
expanded.value = true
}
onClick = { expanded.value = true },
enabled = !isReadOnly
) {
Text(
text = '.' + fileExtension.value.text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,14 @@ import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.halilibo.richtext.commonmark.Markdown
import com.halilibo.richtext.ui.material3.RichText
import io.github.wiiznokes.gitnote.R
import io.github.wiiznokes.gitnote.data.room.Note
import io.github.wiiznokes.gitnote.ui.component.CustomDropDown
import io.github.wiiznokes.gitnote.ui.component.CustomDropDownModel
import io.github.wiiznokes.gitnote.ui.model.EditType
import io.github.wiiznokes.gitnote.ui.model.FileExtension
import io.github.wiiznokes.gitnote.ui.screen.app.DrawerScreen
import io.github.wiiznokes.gitnote.ui.viewmodel.GridViewModel

Expand Down Expand Up @@ -311,12 +314,18 @@ private fun GridView(
color = MaterialTheme.colorScheme.tertiary
)

Text(
text = gridNote.note.content,
modifier = Modifier,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colorScheme.onSurface
)
if (gridNote.note.fileExtension() is FileExtension.Md) {
RichText {
Markdown(gridNote.note.content)
}
} else {
Text(
text = gridNote.note.content,
modifier = Modifier,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colorScheme.onSurface
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewModelScope
import io.github.wiiznokes.gitnote.R
import io.github.wiiznokes.gitnote.ui.component.CustomDropDown
import io.github.wiiznokes.gitnote.ui.component.CustomDropDownModel
Expand Down Expand Up @@ -183,6 +184,7 @@ private fun SearchBar(
)
}

val readOnlyMode = vm.prefs.isReadOnlyModeActive.getAsState().value

CustomDropDown(
expanded = expanded,
Expand All @@ -191,6 +193,16 @@ private fun SearchBar(
text = stringResource(R.string.settings),
onClick = onSettingsClick
),
CustomDropDownModel(
text = if (readOnlyMode) stringResource(
R.string.read_only_mode_deactive
) else stringResource(R.string.read_only_mode_activate),
onClick = {
vm.viewModelScope.launch {
vm.prefs.isReadOnlyModeActive.update(!readOnlyMode)
}
}
),
)
)
}
Expand Down
Loading
Loading