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
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,30 @@ import io.github.wiiznokes.gitnote.data.AppPreferences
import io.github.wiiznokes.gitnote.data.room.Note
import io.github.wiiznokes.gitnote.data.room.NoteFolder
import io.github.wiiznokes.gitnote.data.room.RepoDatabase
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.Result.Companion.failure
import kotlin.Result.Companion.success

private const val TAG = "StorageManager"

sealed interface SyncState {

object Ok : SyncState

object Error : SyncState

object Pull : SyncState

object Push : SyncState

fun isLoading(): Boolean {
return this is Pull || this is Push
}
}

class StorageManager {


Expand All @@ -26,9 +43,11 @@ class StorageManager {

private val gitManager: GitManager = MyApp.appModule.gitManager


private val locker = Mutex()

private val _syncState: MutableStateFlow<SyncState> = MutableStateFlow(SyncState.Ok)
val syncState: StateFlow<SyncState> = _syncState


suspend fun updateDatabaseAndRepo(): Result<Unit> = locker.withLock {
Log.d(TAG, "updateDatabaseAndRepo")
Expand All @@ -46,17 +65,20 @@ class StorageManager {
}

if (remoteUrl.isNotEmpty()) {
_syncState.emit(SyncState.Pull)
gitManager.pull(cred).onFailure {
uiHelper.makeToast(it.message)
}
}

if (remoteUrl.isNotEmpty()) {
_syncState.emit(SyncState.Push)
// todo: maybe async this call
gitManager.push(cred).onFailure {
uiHelper.makeToast(it.message)
}
}
_syncState.emit(SyncState.Ok)

updateDatabaseWithoutLocker()

Expand Down Expand Up @@ -279,6 +301,7 @@ class StorageManager {
}

if (remoteUrl.isNotEmpty()) {
_syncState.emit(SyncState.Pull)
gitManager.pull(cred).onFailure {
it.printStackTrace()
}
Expand All @@ -302,13 +325,15 @@ class StorageManager {
}

if (remoteUrl.isNotEmpty()) {
_syncState.emit(SyncState.Push)
gitManager.push(cred).onFailure {
it.printStackTrace()
}
}

prefs.databaseCommit.update(gitManager.lastCommit())

_syncState.emit(SyncState.Ok)
return success(payload)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ package io.github.wiiznokes.gitnote.ui.screen.app.grid
import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand All @@ -16,17 +23,22 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CloudDone
import androidx.compose.material.icons.filled.CloudDownload
import androidx.compose.material.icons.filled.CloudUpload
import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.Menu
import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material3.DrawerState
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -35,22 +47,27 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
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.manager.SyncState
import io.github.wiiznokes.gitnote.ui.component.CustomDropDown
import io.github.wiiznokes.gitnote.ui.component.CustomDropDownModel
import io.github.wiiznokes.gitnote.ui.component.SimpleIcon
import io.github.wiiznokes.gitnote.ui.viewmodel.GridViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.roundToInt

Expand Down Expand Up @@ -172,40 +189,49 @@ private fun SearchBar(
},
trailingIcon = if (queryTextField.text.isEmpty()) {
{
Box {
val expanded = remember { mutableStateOf(false) }
IconButton(
onClick = {
expanded.value = true
Row(
verticalAlignment = Alignment.CenterVertically
) {

val syncState = vm.syncState.collectAsState()

SyncStateIcon(syncState.value)

Box {
val expanded = remember { mutableStateOf(false) }
IconButton(
onClick = {
expanded.value = true
}
) {
SimpleIcon(
imageVector = Icons.Rounded.MoreVert,
tint = MaterialTheme.colorScheme.onSurface
)
}
) {
SimpleIcon(
imageVector = Icons.Rounded.MoreVert,
tint = MaterialTheme.colorScheme.onSurface
)
}

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

CustomDropDown(
expanded = expanded,
options = listOf(
CustomDropDownModel(
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)
CustomDropDown(
expanded = expanded,
options = listOf(
CustomDropDownModel(
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)
}
}
}
),
),
)
)
)
}
}
}
} else {
Expand Down Expand Up @@ -306,3 +332,70 @@ private fun SelectableTopBar(
}
}
}




@Composable
private fun SyncStateIcon(
state: SyncState
) {
var modifier: Modifier = Modifier

if (state.isLoading()) {

val infiniteTransition = rememberInfiniteTransition()
val alpha = infiniteTransition.animateFloat(
initialValue = 0.3f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 500),
repeatMode = RepeatMode.Reverse
)
)

modifier = modifier.alpha(alpha.value)
}

when (state) {
is SyncState.Error -> {
Icon(
painter = painterResource(R.drawable.cloud_alert_24px),
contentDescription = "Sync Error",
modifier = modifier,
)
}

is SyncState.Ok -> {
var visible by remember { mutableStateOf(true) }

LaunchedEffect(Unit) {
delay(1000)
visible = false
}

AnimatedVisibility(
visible = visible,
exit = fadeOut(animationSpec = tween(durationMillis = 500))
) {
Icon(
imageVector = Icons.Default.CloudDone,
contentDescription = "Sync Done",
modifier = modifier,
)
}
}

is SyncState.Pull -> Icon(
imageVector = Icons.Default.CloudDownload,
contentDescription = "Pulling",
modifier = modifier,
)

is SyncState.Push -> Icon(
imageVector = Icons.Default.CloudUpload,
contentDescription = "Pushing",
modifier = modifier,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,14 @@ class GridViewModel : ViewModel() {
val uiHelper = MyApp.appModule.uiHelper

private val _query = MutableStateFlow("")
val query = _query
val query: StateFlow<String> = _query

val syncState = storageManager.syncState

private val _isRefreshing = MutableStateFlow(false)
val isRefreshing: StateFlow<Boolean>
get() = _isRefreshing.asStateFlow()
val isRefreshing: StateFlow<Boolean> = _isRefreshing.asStateFlow()



private val _currentNoteFolderRelativePath = MutableStateFlow(
if (prefs.rememberLastOpenedFolder.getBlocking()) {
Expand Down Expand Up @@ -160,26 +163,19 @@ class GridViewModel : ViewModel() {
val currentSelectedNotes = selectedNotes.value
unselectAllNotes()
storageManager.deleteNotes(currentSelectedNotes)
uiHelper.makeToast(
uiHelper.getQuantityString(
R.plurals.success_notes_delete, currentSelectedNotes.size
)
)
}
}

fun deleteNote(note: Note) {
selectNote(note, false)
CoroutineScope(Dispatchers.IO).launch {
storageManager.deleteNote(note)
uiHelper.makeToast(uiHelper.getQuantityString(R.plurals.success_notes_delete, 1))
}
}

fun deleteFolder(noteFolder: NoteFolder) {
CoroutineScope(Dispatchers.IO).launch {
storageManager.deleteNoteFolder(noteFolder)
uiHelper.makeToast(uiHelper.getQuantityString(R.plurals.success_noteFolders_delete, 1))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,6 @@ open class TextVM() : ViewModel() {
return@launch
}

uiHelper.makeToast(uiHelper.getString(R.string.success_note_update))
}
return success(newNote)
}
Expand Down Expand Up @@ -409,7 +408,6 @@ open class TextVM() : ViewModel() {
uiHelper.makeToast(it.message)
return@launch
}
uiHelper.makeToast(uiHelper.getString(R.string.success_note_create))
}

return success(note)
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/cloud_alert_24px.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M260,800Q169,800 104.5,737Q40,674 40,583Q40,505 87,444Q134,383 210,366Q235,274 310,217Q385,160 480,160Q597,160 678.5,241.5Q760,323 760,440L760,440L760,440Q829,448 874.5,499.5Q920,551 920,620Q920,695 867.5,747.5Q815,800 740,800L260,800ZM480,640Q497,640 508.5,628.5Q520,617 520,600Q520,583 508.5,571.5Q497,560 480,560Q463,560 451.5,571.5Q440,583 440,600Q440,617 451.5,628.5Q463,640 480,640ZM440,500L520,500L520,320L440,320L440,500Z"/>
</vector>
Loading