Android: Add EditInfo sheet
Signed-off-by: Remy Chantenay <remy.chantenay@gmail.com>
This commit is contained in:
15
android/Omnivore/app/src/main/graphql/UpdatePage.graphql
Normal file
15
android/Omnivore/app/src/main/graphql/UpdatePage.graphql
Normal file
@ -0,0 +1,15 @@
|
||||
mutation UpdatePage($input: UpdatePageInput!) {
|
||||
updatePage(input: $input) {
|
||||
... on UpdatePageSuccess {
|
||||
updatedPage {
|
||||
title
|
||||
author
|
||||
description
|
||||
}
|
||||
}
|
||||
|
||||
... on UpdatePageError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,7 @@ import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import app.omnivore.omnivore.ui.auth.LoginViewModel
|
||||
import app.omnivore.omnivore.ui.components.LabelsViewModel
|
||||
import app.omnivore.omnivore.ui.editinfo.EditInfoViewModel
|
||||
import app.omnivore.omnivore.ui.library.LibraryViewModel
|
||||
import app.omnivore.omnivore.ui.library.SearchViewModel
|
||||
import app.omnivore.omnivore.ui.root.RootView
|
||||
@ -39,6 +40,7 @@ class MainActivity : ComponentActivity() {
|
||||
val searchViewModel: SearchViewModel by viewModels()
|
||||
val labelsViewModel: LabelsViewModel by viewModels()
|
||||
val saveViewModel: SaveViewModel by viewModels()
|
||||
val editInfoViewModel: EditInfoViewModel by viewModels()
|
||||
|
||||
val context = this
|
||||
|
||||
@ -65,7 +67,8 @@ class MainActivity : ComponentActivity() {
|
||||
libraryViewModel,
|
||||
settingsViewModel,
|
||||
labelsViewModel,
|
||||
saveViewModel)
|
||||
saveViewModel,
|
||||
editInfoViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,7 +226,7 @@ interface SavedItemDao {
|
||||
|
||||
|
||||
object SavedItemQueryConstants {
|
||||
const val columns = "savedItemId, slug, publisherURLString, title, author, imageURLString, isArchived, pageURLString, contentReader, savedAt, readingProgress, wordsCount"
|
||||
const val columns = "savedItemId, slug, publisherURLString, title, author, descriptionText, imageURLString, isArchived, pageURLString, contentReader, savedAt, readingProgress, wordsCount"
|
||||
const val libraryColumns = "SavedItem.savedItemId, " +
|
||||
"SavedItem.slug, " +
|
||||
"SavedItem.createdAt, " +
|
||||
@ -234,6 +234,7 @@ object SavedItemQueryConstants {
|
||||
"SavedItem.publisherURLString, " +
|
||||
"SavedItem.title, " +
|
||||
"SavedItem.author, " +
|
||||
"SavedItem.descriptionText, " +
|
||||
"SavedItem.imageURLString, " +
|
||||
"SavedItem.isArchived, " +
|
||||
"SavedItem.pageURLString, " +
|
||||
|
||||
@ -0,0 +1,146 @@
|
||||
package app.omnivore.omnivore.ui.editinfo
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import app.omnivore.omnivore.R
|
||||
|
||||
@Composable
|
||||
fun EditInfoSheetContent(
|
||||
savedItemId: String?,
|
||||
title: String?,
|
||||
author: String?,
|
||||
description: String?,
|
||||
viewModel: EditInfoViewModel,
|
||||
onCancel: () -> Unit,
|
||||
onUpdated: () -> Unit
|
||||
) {
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
var titleTextFieldValue by remember { mutableStateOf(TextFieldValue(title ?: "")) }
|
||||
var authorTextFieldValue by remember { mutableStateOf(TextFieldValue(author ?: "")) }
|
||||
var descriptionTextFieldValue by remember { mutableStateOf(TextFieldValue(description ?: "")) }
|
||||
|
||||
fun showToast(msg: String) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
msg,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
val state: EditInfoState by viewModel.state.observeAsState(EditInfoState.DEFAULT)
|
||||
val isUpdating = MutableLiveData(false)
|
||||
|
||||
when (state) {
|
||||
EditInfoState.DEFAULT -> {
|
||||
isUpdating.value = false
|
||||
}
|
||||
EditInfoState.UPDATING -> {
|
||||
isUpdating.value = true
|
||||
}
|
||||
EditInfoState.ERROR -> {
|
||||
isUpdating.value = false
|
||||
showToast(viewModel.message ?: context.getString(R.string.edit_info_sheet_error))
|
||||
|
||||
viewModel.resetState()
|
||||
}
|
||||
EditInfoState.UPDATED -> {
|
||||
isUpdating.value = false
|
||||
showToast(viewModel.message ?: context.getString(R.string.edit_info_sheet_success))
|
||||
|
||||
onUpdated()
|
||||
viewModel.resetState()
|
||||
}
|
||||
}
|
||||
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.background),
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Top,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
TextButton(onClick = onCancel) {
|
||||
Text(text = stringResource(R.string.edit_info_sheet_action_cancel))
|
||||
}
|
||||
|
||||
Text(stringResource(R.string.edit_info_sheet_title), fontWeight = FontWeight.ExtraBold)
|
||||
|
||||
TextButton(onClick = {
|
||||
val newTitle = titleTextFieldValue.text
|
||||
val newAuthor = authorTextFieldValue.text.ifEmpty { null }
|
||||
val newDescription = descriptionTextFieldValue.text.ifEmpty { null }
|
||||
|
||||
savedItemId?.let {
|
||||
viewModel.editInfo(it, newTitle, newAuthor, newDescription)
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(R.string.edit_info_sheet_action_save))
|
||||
}
|
||||
}
|
||||
|
||||
if (isUpdating.value == true) {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.height(16.dp)
|
||||
.width(16.dp),
|
||||
strokeWidth = 2.dp,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
value = titleTextFieldValue,
|
||||
label = { Text(stringResource(R.string.edit_info_sheet_text_field_label_title)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
|
||||
onValueChange = { titleTextFieldValue = it },
|
||||
modifier = Modifier.padding(top = 24.dp).fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = authorTextFieldValue,
|
||||
label = { Text(stringResource(R.string.edit_info_sheet_text_field_label_author)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
|
||||
onValueChange = { authorTextFieldValue = it },
|
||||
modifier = Modifier.padding(top = 24.dp).fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = descriptionTextFieldValue,
|
||||
label = { Text(stringResource(R.string.edit_info_sheet_text_field_label_description)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
|
||||
singleLine = false, minLines = 1, maxLines = 5,
|
||||
onValueChange = { descriptionTextFieldValue = it },
|
||||
modifier = Modifier.padding(top = 24.dp).fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
package app.omnivore.omnivore.ui.editinfo
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.omnivore.omnivore.Constants
|
||||
import app.omnivore.omnivore.DatastoreKeys
|
||||
import app.omnivore.omnivore.DatastoreRepository
|
||||
import app.omnivore.omnivore.R
|
||||
import app.omnivore.omnivore.dataService.DataService
|
||||
import app.omnivore.omnivore.graphql.generated.UpdatePageMutation
|
||||
import app.omnivore.omnivore.graphql.generated.type.UpdatePageInput
|
||||
import app.omnivore.omnivore.ui.ResourceProvider
|
||||
import com.apollographql.apollo3.ApolloClient
|
||||
import com.apollographql.apollo3.api.Optional
|
||||
import com.pspdfkit.internal.sa
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
enum class EditInfoState {
|
||||
DEFAULT(),
|
||||
UPDATING(),
|
||||
ERROR(),
|
||||
UPDATED()
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class EditInfoViewModel @Inject constructor(
|
||||
private val dataService: DataService,
|
||||
private val datastoreRepo: DatastoreRepository,
|
||||
private val resourceProvider: ResourceProvider
|
||||
) : ViewModel() {
|
||||
val state = MutableLiveData(EditInfoState.DEFAULT)
|
||||
|
||||
var isLoading by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var message by mutableStateOf<String?>(null)
|
||||
private set
|
||||
|
||||
private fun getAuthToken(): String? = runBlocking {
|
||||
datastoreRepo.getString(DatastoreKeys.omnivoreAuthToken)
|
||||
}
|
||||
|
||||
fun editInfo(itemId: String, title: String, author: String?, description: String?) {
|
||||
viewModelScope.launch {
|
||||
isLoading = true
|
||||
state.postValue(EditInfoState.UPDATING)
|
||||
|
||||
val authToken = getAuthToken()
|
||||
|
||||
if (authToken == null) {
|
||||
message = resourceProvider.getString(R.string.edit_info_view_model_error_not_logged_in)
|
||||
isLoading = false
|
||||
return@launch
|
||||
}
|
||||
|
||||
val apolloClient = ApolloClient.Builder()
|
||||
.serverUrl("${Constants.apiURL}/api/graphql")
|
||||
.addHttpHeader("Authorization", value = authToken)
|
||||
.build()
|
||||
|
||||
try {
|
||||
val response = apolloClient.mutation(
|
||||
UpdatePageMutation(
|
||||
UpdatePageInput(
|
||||
pageId = itemId,
|
||||
title = Optional.present(title),
|
||||
byline = Optional.presentIfNotNull(author),
|
||||
description = Optional.presentIfNotNull(description)
|
||||
)
|
||||
)
|
||||
).execute()
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
val savedItem = dataService.db.savedItemDao().findById(itemId) ?: return@withContext
|
||||
val updatedSavedItem = savedItem.copy(title = title, author = author, descriptionText = description)
|
||||
dataService.db.savedItemDao().update(updatedSavedItem)
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
|
||||
val success = (response.data?.updatePage?.onUpdatePageSuccess?.updatedPage != null)
|
||||
if (success) {
|
||||
message = resourceProvider.getString(R.string.edit_info_sheet_success)
|
||||
state.postValue(EditInfoState.UPDATED)
|
||||
} else {
|
||||
message = resourceProvider.getString(R.string.edit_info_sheet_error)
|
||||
state.postValue(EditInfoState.ERROR)
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
message = resourceProvider.getString(R.string.edit_info_sheet_error)
|
||||
state.postValue(EditInfoState.ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resetState() {
|
||||
state.postValue(EditInfoState.DEFAULT)
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
@ -49,7 +50,7 @@ fun LibraryNavigationBar(
|
||||
savedItemViewModel.actionsMenuItemLiveData.postValue(null)
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = androidx.compose.material.icons.Icons.Filled.ArrowBack,
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
modifier = Modifier,
|
||||
contentDescription = "Back"
|
||||
)
|
||||
@ -75,6 +76,12 @@ fun LibraryNavigationBar(
|
||||
)
|
||||
}
|
||||
}
|
||||
IconButton(onClick = { savedItemViewModel.handleSavedItemAction(it.savedItem.savedItemId, SavedItemAction.EditInfo) }) {
|
||||
Icon(
|
||||
Icons.Outlined.Info,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
IconButton(onClick = { savedItemViewModel.handleSavedItemAction(it.savedItem.savedItemId, SavedItemAction.EditLabels) }) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.tag),
|
||||
|
||||
@ -28,8 +28,10 @@ import app.omnivore.omnivore.Routes
|
||||
import app.omnivore.omnivore.persistence.entities.SavedItemLabel
|
||||
import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights
|
||||
import app.omnivore.omnivore.ui.components.AddLinkSheetContent
|
||||
import app.omnivore.omnivore.ui.editinfo.EditInfoSheetContent
|
||||
import app.omnivore.omnivore.ui.components.LabelsSelectionSheetContent
|
||||
import app.omnivore.omnivore.ui.components.LabelsViewModel
|
||||
import app.omnivore.omnivore.ui.editinfo.EditInfoViewModel
|
||||
import app.omnivore.omnivore.ui.savedItemViews.SavedItemCard
|
||||
import app.omnivore.omnivore.ui.reader.PDFReaderActivity
|
||||
import app.omnivore.omnivore.ui.reader.WebReaderLoadingContainerActivity
|
||||
@ -45,11 +47,13 @@ fun LibraryView(
|
||||
libraryViewModel: LibraryViewModel,
|
||||
labelsViewModel: LabelsViewModel,
|
||||
saveViewModel: SaveViewModel,
|
||||
editInfoViewModel: EditInfoViewModel,
|
||||
navController: NavHostController
|
||||
) {
|
||||
val scaffoldState: ScaffoldState = rememberScaffoldState()
|
||||
val showLabelsSelectionSheet: Boolean by libraryViewModel.showLabelsSelectionSheetLiveData.observeAsState(false)
|
||||
val showAddLinkSheet: Boolean by libraryViewModel.showAddLinkSheetLiveData.observeAsState(false)
|
||||
val showEditInfoSheet: Boolean by libraryViewModel.showEditInfoSheetLiveData.observeAsState(false)
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val modalBottomSheetState = rememberModalBottomSheetState(
|
||||
@ -57,7 +61,7 @@ fun LibraryView(
|
||||
confirmStateChange = { it != ModalBottomSheetValue.Hidden }
|
||||
)
|
||||
|
||||
if (showLabelsSelectionSheet || showAddLinkSheet) {
|
||||
if (showLabelsSelectionSheet || showAddLinkSheet || showEditInfoSheet) {
|
||||
coroutineScope.launch {
|
||||
modalBottomSheetState.show()
|
||||
}
|
||||
@ -78,7 +82,7 @@ fun LibraryView(
|
||||
sheetBackgroundColor = Color.Transparent,
|
||||
sheetState = modalBottomSheetState,
|
||||
sheetContent = {
|
||||
BottomSheetContent(libraryViewModel, labelsViewModel, saveViewModel)
|
||||
BottomSheetContent(libraryViewModel, labelsViewModel, saveViewModel,editInfoViewModel)
|
||||
Spacer(modifier = Modifier.weight(1.0F))
|
||||
}
|
||||
) {
|
||||
@ -103,9 +107,13 @@ fun LibraryView(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BottomSheetContent(libraryViewModel: LibraryViewModel, labelsViewModel: LabelsViewModel, saveViewModel: SaveViewModel) {
|
||||
fun BottomSheetContent(libraryViewModel: LibraryViewModel,
|
||||
labelsViewModel: LabelsViewModel,
|
||||
saveViewModel: SaveViewModel,
|
||||
editInfoViewModel: EditInfoViewModel) {
|
||||
val showLabelsSelectionSheet: Boolean by libraryViewModel.showLabelsSelectionSheetLiveData.observeAsState(false)
|
||||
val showAddLinkSheet: Boolean by libraryViewModel.showAddLinkSheetLiveData.observeAsState(false)
|
||||
val showEditInfoSheet: Boolean by libraryViewModel.showEditInfoSheetLiveData.observeAsState(false)
|
||||
val currentSavedItemData = libraryViewModel.currentSavedItemUnderEdit()
|
||||
val labels: List<SavedItemLabel> by libraryViewModel.savedItemLabelsLiveData.observeAsState(listOf())
|
||||
|
||||
@ -118,7 +126,7 @@ fun BottomSheetContent(libraryViewModel: LibraryViewModel, labelsViewModel: Labe
|
||||
initialSelectedLabels = currentSavedItemData.labels,
|
||||
onCancel = {
|
||||
libraryViewModel.showLabelsSelectionSheetLiveData.value = false
|
||||
libraryViewModel.labelsSelectionCurrentItemLiveData.value = null
|
||||
libraryViewModel.currentItemLiveData.value = null
|
||||
},
|
||||
isLibraryMode = false,
|
||||
onSave = {
|
||||
@ -128,7 +136,7 @@ fun BottomSheetContent(libraryViewModel: LibraryViewModel, labelsViewModel: Labe
|
||||
labels = it
|
||||
)
|
||||
}
|
||||
libraryViewModel.labelsSelectionCurrentItemLiveData.value = null
|
||||
libraryViewModel.currentItemLiveData.value = null
|
||||
libraryViewModel.showLabelsSelectionSheetLiveData.value = false
|
||||
},
|
||||
onCreateLabel = { newLabelName, labelHexValue ->
|
||||
@ -144,7 +152,7 @@ fun BottomSheetContent(libraryViewModel: LibraryViewModel, labelsViewModel: Labe
|
||||
isLibraryMode = true,
|
||||
onSave = {
|
||||
libraryViewModel.updateAppliedLabels(it)
|
||||
libraryViewModel.labelsSelectionCurrentItemLiveData.value = null
|
||||
libraryViewModel.currentItemLiveData.value = null
|
||||
libraryViewModel.showLabelsSelectionSheetLiveData.value = false
|
||||
},
|
||||
onCreateLabel = { newLabelName, labelHexValue ->
|
||||
@ -167,6 +175,25 @@ fun BottomSheetContent(libraryViewModel: LibraryViewModel, labelsViewModel: Labe
|
||||
}
|
||||
)
|
||||
}
|
||||
} else if (showEditInfoSheet) {
|
||||
BottomSheetUI {
|
||||
EditInfoSheetContent(
|
||||
savedItemId = currentSavedItemData?.savedItem?.savedItemId,
|
||||
title = currentSavedItemData?.savedItem?.title,
|
||||
author = currentSavedItemData?.savedItem?.author,
|
||||
description = currentSavedItemData?.savedItem?.descriptionText,
|
||||
viewModel = editInfoViewModel,
|
||||
onCancel = {
|
||||
libraryViewModel.showEditInfoSheetLiveData.value = false
|
||||
libraryViewModel.currentItemLiveData.value = null
|
||||
},
|
||||
onUpdated = {
|
||||
libraryViewModel.showEditInfoSheetLiveData.value = false
|
||||
libraryViewModel.currentItemLiveData.value = null
|
||||
libraryViewModel.refresh()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,8 +62,9 @@ class LibraryViewModel @Inject constructor(
|
||||
val appliedFilterLiveData = MutableLiveData(SavedItemFilter.INBOX)
|
||||
val appliedSortFilterLiveData = MutableLiveData(SavedItemSortFilter.NEWEST)
|
||||
val showLabelsSelectionSheetLiveData = MutableLiveData(false)
|
||||
val showEditInfoSheetLiveData = MutableLiveData(false)
|
||||
val showAddLinkSheetLiveData = MutableLiveData(false)
|
||||
val labelsSelectionCurrentItemLiveData = MutableLiveData<String?>(null)
|
||||
val currentItemLiveData = MutableLiveData<String?>(null)
|
||||
val savedItemLabelsLiveData = dataService.db.savedItemLabelDao().getSavedItemLabelsLiveData()
|
||||
val activeLabelsLiveData = MutableLiveData<List<SavedItemLabel>>(listOf())
|
||||
|
||||
@ -296,9 +297,13 @@ class LibraryViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
SavedItemAction.EditLabels -> {
|
||||
labelsSelectionCurrentItemLiveData.value = itemID
|
||||
currentItemLiveData.value = itemID
|
||||
showLabelsSelectionSheetLiveData.value = true
|
||||
}
|
||||
SavedItemAction.EditInfo -> {
|
||||
currentItemLiveData.value = itemID
|
||||
showEditInfoSheetLiveData.value = true
|
||||
}
|
||||
else -> {
|
||||
|
||||
}
|
||||
@ -350,7 +355,7 @@ class LibraryViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun currentSavedItemUnderEdit(): SavedItemWithLabelsAndHighlights? {
|
||||
labelsSelectionCurrentItemLiveData.value?.let { itemID ->
|
||||
currentItemLiveData.value?.let { itemID ->
|
||||
return itemsLiveData.value?.first { it.savedItem.savedItemId == itemID }
|
||||
}
|
||||
|
||||
@ -376,4 +381,5 @@ enum class SavedItemAction {
|
||||
Archive,
|
||||
Unarchive,
|
||||
EditLabels,
|
||||
EditInfo,
|
||||
}
|
||||
|
||||
@ -167,6 +167,9 @@ class SearchViewModel @Inject constructor(
|
||||
SavedItemAction.EditLabels -> {
|
||||
// TODO
|
||||
}
|
||||
SavedItemAction.EditInfo -> {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
actionsMenuItemLiveData.postValue(null)
|
||||
}
|
||||
|
||||
@ -44,7 +44,9 @@ import kotlinx.coroutines.launch
|
||||
import kotlin.math.roundToInt
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.omnivore.omnivore.ui.editinfo.EditInfoSheetContent
|
||||
import app.omnivore.omnivore.ui.components.LabelsViewModel
|
||||
import app.omnivore.omnivore.ui.editinfo.EditInfoViewModel
|
||||
import app.omnivore.omnivore.ui.notebook.EditNoteModal
|
||||
|
||||
@AndroidEntryPoint
|
||||
@ -52,6 +54,7 @@ class WebReaderLoadingContainerActivity: ComponentActivity() {
|
||||
val viewModel: WebReaderViewModel by viewModels()
|
||||
private val notebookViewModel: NotebookViewModel by viewModels()
|
||||
private val labelsViewModel: LabelsViewModel by viewModels()
|
||||
private val editInfoViewModel: EditInfoViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -89,6 +92,7 @@ class WebReaderLoadingContainerActivity: ComponentActivity() {
|
||||
webReaderViewModel = viewModel,
|
||||
notebookViewModel = notebookViewModel,
|
||||
labelsViewModel = labelsViewModel,
|
||||
editInfoViewModel = editInfoViewModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -119,7 +123,8 @@ enum class BottomSheetState(
|
||||
EDITNOTE(),
|
||||
HIGHLIGHTNOTE(),
|
||||
LABELS(),
|
||||
LINK()
|
||||
LINK(),
|
||||
EDIT_INFO(),
|
||||
}
|
||||
|
||||
|
||||
@ -129,7 +134,8 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null,
|
||||
onLibraryIconTap: (() -> Unit)? = null,
|
||||
webReaderViewModel: WebReaderViewModel,
|
||||
notebookViewModel: NotebookViewModel,
|
||||
labelsViewModel: LabelsViewModel) {
|
||||
labelsViewModel: LabelsViewModel,
|
||||
editInfoViewModel: EditInfoViewModel) {
|
||||
val currentThemeKey = webReaderViewModel.currentThemeKey.observeAsState()
|
||||
val currentTheme = Themes.values().find { it.themeKey == currentThemeKey.value }
|
||||
val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
||||
@ -181,7 +187,7 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null,
|
||||
}
|
||||
}
|
||||
BottomSheetState.NOTEBOOK, BottomSheetState.EDITNOTE,
|
||||
BottomSheetState.HIGHLIGHTNOTE, BottomSheetState.LABELS,
|
||||
BottomSheetState.HIGHLIGHTNOTE, BottomSheetState.LABELS, BottomSheetState.EDIT_INFO,
|
||||
BottomSheetState.LINK, -> {
|
||||
showMenu()
|
||||
}
|
||||
@ -282,6 +288,28 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
BottomSheetState.EDIT_INFO -> {
|
||||
BottomSheetUI(title = stringResource(R.string.web_reader_loading_container_bottom_sheet_edit_info)) {
|
||||
EditInfoSheetContent(
|
||||
savedItemId = webReaderParams?.item?.savedItemId,
|
||||
title = webReaderParams?.item?.title,
|
||||
author = webReaderParams?.item?.author,
|
||||
description = webReaderParams?.item?.descriptionText,
|
||||
viewModel = editInfoViewModel,
|
||||
onCancel = {
|
||||
coroutineScope.launch {
|
||||
webReaderViewModel.resetBottomSheet()
|
||||
}
|
||||
},
|
||||
onUpdated = {
|
||||
coroutineScope.launch {
|
||||
webReaderViewModel.updateItemTitle()
|
||||
webReaderViewModel.resetBottomSheet()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
BottomSheetState.LINK -> {
|
||||
BottomSheetUI(title = stringResource(R.string.web_reader_loading_container_bottom_sheet_open_link)) {
|
||||
OpenLinkView(webReaderViewModel)
|
||||
|
||||
@ -296,6 +296,9 @@ class WebReaderViewModel @Inject constructor(
|
||||
SavedItemAction.EditLabels -> {
|
||||
bottomSheetStateLiveData.postValue(BottomSheetState.LABELS)
|
||||
}
|
||||
SavedItemAction.EditInfo -> {
|
||||
bottomSheetStateLiveData.postValue(BottomSheetState.EDIT_INFO)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,6 +528,25 @@ class WebReaderViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun updateItemTitle() {
|
||||
viewModelScope.launch {
|
||||
slug?.let {
|
||||
loadItemFromDB(it)
|
||||
}
|
||||
|
||||
webReaderParamsLiveData.value?.item?.title?.let {
|
||||
updateItemTitleInWebView(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateItemTitleInWebView(title: String) {
|
||||
val script = "var event = new Event('updateTitle');event.title = '${title}';document.dispatchEvent(event);"
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
enqueueScript(script)
|
||||
}
|
||||
}
|
||||
|
||||
fun createNewSavedItemLabel(labelName: String, hexColorValue: String) {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
|
||||
@ -17,6 +17,7 @@ import app.omnivore.omnivore.Routes
|
||||
import app.omnivore.omnivore.ui.auth.LoginViewModel
|
||||
import app.omnivore.omnivore.ui.auth.WelcomeScreen
|
||||
import app.omnivore.omnivore.ui.components.LabelsViewModel
|
||||
import app.omnivore.omnivore.ui.editinfo.EditInfoViewModel
|
||||
import app.omnivore.omnivore.ui.library.LibraryView
|
||||
import app.omnivore.omnivore.ui.library.SearchView
|
||||
import app.omnivore.omnivore.ui.library.LibraryViewModel
|
||||
@ -34,6 +35,7 @@ fun RootView(
|
||||
settingsViewModel: SettingsViewModel,
|
||||
labelsViewModel: LabelsViewModel,
|
||||
saveViewModel: SaveViewModel,
|
||||
editInfoViewModel: EditInfoViewModel,
|
||||
) {
|
||||
val hasAuthToken: Boolean by loginViewModel.hasAuthTokenLiveData.observeAsState(false)
|
||||
val systemUiController = rememberSystemUiController()
|
||||
@ -59,7 +61,8 @@ fun RootView(
|
||||
libraryViewModel = libraryViewModel,
|
||||
settingsViewModel = settingsViewModel,
|
||||
labelsViewModel = labelsViewModel,
|
||||
saveViewModel = saveViewModel
|
||||
saveViewModel = saveViewModel,
|
||||
editInfoViewModel = editInfoViewModel,
|
||||
)
|
||||
} else {
|
||||
WelcomeScreen(viewModel = loginViewModel)
|
||||
@ -82,6 +85,7 @@ fun PrimaryNavigator(
|
||||
settingsViewModel: SettingsViewModel,
|
||||
labelsViewModel: LabelsViewModel,
|
||||
saveViewModel: SaveViewModel,
|
||||
editInfoViewModel: EditInfoViewModel,
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
|
||||
@ -92,6 +96,7 @@ fun PrimaryNavigator(
|
||||
navController = navController,
|
||||
labelsViewModel = labelsViewModel,
|
||||
saveViewModel = saveViewModel,
|
||||
editInfoViewModel = editInfoViewModel,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.CheckCircle
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material.icons.outlined.List
|
||||
import androidx.compose.material.icons.outlined.Share
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
@ -31,6 +32,19 @@ fun SavedItemContextMenu(
|
||||
expanded = isExpanded,
|
||||
onDismissRequest = onDismiss
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.saved_item_context_menu_action_edit_info)) },
|
||||
onClick = {
|
||||
actionHandler(SavedItemAction.EditInfo)
|
||||
onDismiss()
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Outlined.Info,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.saved_item_context_menu_action_edit_labels)) },
|
||||
onClick = {
|
||||
|
||||
@ -152,6 +152,7 @@
|
||||
<string name="web_reader_loading_container_error_msg">我们无法取得您的内容。</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_reader_preferences">阅读器偏好设定</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_notebook">笔记</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_edit_info">编辑信息</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_open_link">开启链接</string>
|
||||
|
||||
<!-- OpenLinkView -->
|
||||
@ -178,6 +179,7 @@
|
||||
<string name="save_view_model_page_saved_error">保存您的页面时出错</string>
|
||||
|
||||
<!-- SavedItemContextMenu -->
|
||||
<string name="saved_item_context_menu_action_edit_info">编辑信息</string>
|
||||
<string name="saved_item_context_menu_action_edit_labels">编辑标签</string>
|
||||
<string name="saved_item_context_menu_action_archive">封存</string>
|
||||
<string name="saved_item_context_menu_action_unarchive">取消封存</string>
|
||||
@ -222,4 +224,17 @@
|
||||
<string name="library_sort_oldest">从旧到新</string>
|
||||
<string name="library_sort_recently_read">最近阅读</string>
|
||||
<string name="library_sort_recently_published">最近发布</string>
|
||||
|
||||
<!-- EditInfoViewModel -->
|
||||
<string name="edit_info_view_model_error_not_logged_in">您尚未登入。请在保存前登入。</string>
|
||||
|
||||
<!-- EditInfoSheet -->
|
||||
<string name="edit_info_sheet_title">编辑信息</string>
|
||||
<string name="edit_info_sheet_text_field_label_title">标题</string>
|
||||
<string name="edit_info_sheet_text_field_label_author">作者</string>
|
||||
<string name="edit_info_sheet_text_field_label_description">说明</string>
|
||||
<string name="edit_info_sheet_action_save">节省</string>
|
||||
<string name="edit_info_sheet_action_cancel">取消</string>
|
||||
<string name="edit_info_sheet_error">编辑文章时出错</string>
|
||||
<string name="edit_info_sheet_success">文章信息更新成功</string>
|
||||
</resources>
|
||||
|
||||
@ -151,6 +151,7 @@
|
||||
<string name="web_reader_loading_container_error_msg">我們無法取得您的內容。</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_reader_preferences">閱讀器偏好設定</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_notebook">筆記本</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_edit_info">编辑信息</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_open_link">開啟連結</string>
|
||||
|
||||
<!-- OpenLinkView -->
|
||||
@ -177,6 +178,7 @@
|
||||
<string name="save_view_model_page_saved_error">儲存您的頁面時出錯</string>
|
||||
|
||||
<!-- SavedItemContextMenu -->
|
||||
<string name="saved_item_context_menu_action_edit_info">编辑信息</string>
|
||||
<string name="saved_item_context_menu_action_edit_labels">編輯標籤</string>
|
||||
<string name="saved_item_context_menu_action_archive">封存</string>
|
||||
<string name="saved_item_context_menu_action_unarchive">取消封存</string>
|
||||
|
||||
@ -151,6 +151,8 @@
|
||||
<string name="web_reader_loading_container_error_msg">We were unable to fetch your content.</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_reader_preferences">Reader Preferences</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_notebook">Notebook</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_edit_info">Edit Info</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_e">Notebook</string>
|
||||
<string name="web_reader_loading_container_bottom_sheet_open_link">Open Link</string>
|
||||
|
||||
<!-- OpenLinkView -->
|
||||
@ -177,6 +179,7 @@
|
||||
<string name="save_view_model_page_saved_error">There was an error saving your page</string>
|
||||
|
||||
<!-- SavedItemContextMenu -->
|
||||
<string name="saved_item_context_menu_action_edit_info">Edit Info</string>
|
||||
<string name="saved_item_context_menu_action_edit_labels">Edit Labels</string>
|
||||
<string name="saved_item_context_menu_action_archive">Archive</string>
|
||||
<string name="saved_item_context_menu_action_unarchive">Unarchive</string>
|
||||
@ -214,4 +217,17 @@
|
||||
<string name="add_link_sheet_invalid_url_error">Invalid URL</string>
|
||||
<string name="add_link_sheet_save_url_error">Error while saving link!</string>
|
||||
<string name="add_link_sheet_save_url_success">Link successfully saved!</string>
|
||||
|
||||
<!-- EditInfoViewModel -->
|
||||
<string name="edit_info_view_model_error_not_logged_in">You are not logged in. Please login before saving.</string>
|
||||
|
||||
<!-- EditInfoSheet -->
|
||||
<string name="edit_info_sheet_title">Edit Info</string>
|
||||
<string name="edit_info_sheet_text_field_label_title">Title</string>
|
||||
<string name="edit_info_sheet_text_field_label_author">Author</string>
|
||||
<string name="edit_info_sheet_text_field_label_description">Description</string>
|
||||
<string name="edit_info_sheet_action_save">Save</string>
|
||||
<string name="edit_info_sheet_action_cancel">Cancel</string>
|
||||
<string name="edit_info_sheet_error">Error while editing article!</string>
|
||||
<string name="edit_info_sheet_success">Article info successfully updated!</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user