More work on notebook using bottom sheet

This commit is contained in:
Jackson Harper
2023-05-08 17:06:27 +08:00
parent e4e153e01f
commit dc7c992ed2
3 changed files with 117 additions and 45 deletions

View File

@ -156,8 +156,6 @@ interface SavedItemDao {
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " + "LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"WHERE SavedItem.savedItemId = :savedItemId " + "WHERE SavedItem.savedItemId = :savedItemId " +
"AND SavedItem.serverSyncStatus != 2 " +
"AND Highlight.serverSyncStatus != 2 " +
"GROUP BY SavedItem.savedItemId " "GROUP BY SavedItem.savedItemId "
) )

View File

@ -46,7 +46,10 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import dev.jeziellago.compose.markdowntext.MarkdownText import dev.jeziellago.compose.markdowntext.MarkdownText
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import android.util.Log
import androidx.compose.ui.platform.LocalDensity
import app.omnivore.omnivore.persistence.entities.Highlight
import kotlin.math.roundToInt
@AndroidEntryPoint @AndroidEntryPoint
class NotebookActivity: ComponentActivity() { class NotebookActivity: ComponentActivity() {
@ -102,61 +105,105 @@ class NotebookActivity: ComponentActivity() {
} }
} }
fun notebookMD(notes: List<Highlight>, highlights: List<Highlight>): String {
var result = ""
if (notes.isNotEmpty()) {
result += "## Notes\n"
notes.forEach {
result += it.annotation + "\n"
}
result += "\n"
}
if (highlights.isNotEmpty()) {
result += "## Highlights\n"
highlights.forEach {
result += "> ${it.quote}\n"
if ((it.annotation?: "").isNotEmpty()) {
result += it.annotation + "\n"
}
}
result += "\n"
}
return result
}
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
@Composable @Composable
fun NotebookView(savedItemId: String, viewModel: NotebookViewModel) { fun NotebookView(savedItemId: String, viewModel: NotebookViewModel) {
val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher var isMenuOpen by remember {
mutableStateOf(false)
}
val savedItem = viewModel.getLibraryItemById(savedItemId).observeAsState() val savedItem = viewModel.getLibraryItemById(savedItemId).observeAsState()
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
val modalBottomSheetState = rememberModalBottomSheetState( val modalBottomSheetState = rememberModalBottomSheetState(
ModalBottomSheetValue.Hidden, ModalBottomSheetValue.Hidden,
) )
val coroutineScope = rememberCoroutineScope()
val snackBarHostState = remember { SnackbarHostState() }
val clipboard: ClipboardManager? =
LocalContext.current.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?
val notes = savedItem.value?.highlights?.filter { it.type == "NOTE" } ?: listOf() val notes = savedItem.value?.highlights?.filter { it.type == "NOTE" } ?: listOf()
val highlights = savedItem.value?.highlights?.filter { it.type == "HIGHLIGHT" } ?: listOf() val highlights = savedItem.value?.highlights?.filter { it.type == "HIGHLIGHT" } ?: listOf()
ModalBottomSheetLayout( ModalBottomSheetLayout(
modifier = Modifier.statusBarsPadding(),
sheetBackgroundColor = Color.Transparent, sheetBackgroundColor = Color.Transparent,
sheetState = modalBottomSheetState, sheetState = modalBottomSheetState,
sheetContent = { sheetContent = {
EditNoteModal() // EditNoteModal()
Spacer(modifier = Modifier.weight(1.0F))
} }
) { ) {
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Notebook") }, title = { Text("Notebook") },
modifier = Modifier.statusBarsPadding(),
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.background containerColor = MaterialTheme.colorScheme.background
), ),
navigationIcon = { actions = {
IconButton(onClick = { Box {
onBackPressedDispatcher?.onBackPressed() IconButton(onClick = {
}) { isMenuOpen = true
Icon( }) {
imageVector = androidx.compose.material.icons.Icons.Filled.ArrowBack, Icon(
modifier = Modifier, imageVector = Icons.Default.MoreVert,
contentDescription = "Back" contentDescription = null
) )
}
if (isMenuOpen) {
DropdownMenu(
expanded = isMenuOpen,
onDismissRequest = { isMenuOpen = false }
) {
DropdownMenuItem(
text = { Text("Copy") },
onClick = {
val clip = ClipData.newPlainText("notebook", notebookMD(notes, highlights))
clipboard?.let {
it
clipboard?.setPrimaryClip(clip)
} ?: run {
coroutineScope.launch {
snackBarHostState
.showSnackbar("Notebook copied")
}
}
isMenuOpen = false
}
)
}
}
} }
}, }
// actions = {
// IconButton(onClick = {
//
// }) {
// Icon(
// imageVector = Icons.Default.MoreVert,
// contentDescription = null
// )
// }
// }
) )
} }
) { paddingValues -> ) { paddingValues ->
Column( Column(
modifier = Modifier modifier = Modifier
.padding(paddingValues)
.verticalScroll(scrollState) .verticalScroll(scrollState)
.fillMaxSize() .fillMaxSize()
) { ) {
@ -166,7 +213,6 @@ fun NotebookView(savedItemId: String, viewModel: NotebookViewModel) {
} }
HighlightsList(it) HighlightsList(it)
} }
Spacer(Modifier.weight(100f))
} }
} }
} }

View File

@ -24,7 +24,6 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -34,7 +33,8 @@ import androidx.core.view.WindowInsetsCompat
import app.omnivore.omnivore.MainActivity import app.omnivore.omnivore.MainActivity
import app.omnivore.omnivore.R import app.omnivore.omnivore.R
import app.omnivore.omnivore.ui.components.WebReaderLabelsSelectionSheet import app.omnivore.omnivore.ui.components.WebReaderLabelsSelectionSheet
import app.omnivore.omnivore.ui.notebook.NotebookActivity import app.omnivore.omnivore.ui.notebook.NotebookView
import app.omnivore.omnivore.ui.notebook.NotebookViewModel
import app.omnivore.omnivore.ui.savedItemViews.SavedItemContextMenu import app.omnivore.omnivore.ui.savedItemViews.SavedItemContextMenu
import app.omnivore.omnivore.ui.theme.OmnivoreTheme import app.omnivore.omnivore.ui.theme.OmnivoreTheme
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
@ -46,6 +46,7 @@ import kotlin.math.roundToInt
@AndroidEntryPoint @AndroidEntryPoint
class WebReaderLoadingContainerActivity: ComponentActivity() { class WebReaderLoadingContainerActivity: ComponentActivity() {
val viewModel: WebReaderViewModel by viewModels() val viewModel: WebReaderViewModel by viewModels()
val notebookViewModel: NotebookViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -79,6 +80,7 @@ class WebReaderLoadingContainerActivity: ComponentActivity() {
slug = slug, slug = slug,
onLibraryIconTap = if (requestID != null) { { startMainActivity() } } else null, onLibraryIconTap = if (requestID != null) { { startMainActivity() } } else null,
webReaderViewModel = viewModel, webReaderViewModel = viewModel,
notebookViewModel = notebookViewModel,
) )
} }
} }
@ -101,13 +103,25 @@ class WebReaderLoadingContainerActivity: ComponentActivity() {
} }
} }
enum class BottomSheetState(
) {
NONE(),
PREFERENCES(),
NOTEBOOK(),
HIGHLIGHTNOTE()
}
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Composable @Composable
fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, onLibraryIconTap: (() -> Unit)? = null, webReaderViewModel: WebReaderViewModel) { fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null,
onLibraryIconTap: (() -> Unit)? = null,
webReaderViewModel: WebReaderViewModel,
notebookViewModel: NotebookViewModel) {
val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
var isMenuExpanded by remember { mutableStateOf(false) } var isMenuExpanded by remember { mutableStateOf(false) }
var showWebPreferencesDialog by remember { mutableStateOf(false ) } var bottomSheetState by remember { mutableStateOf(app.omnivore.omnivore.ui.reader.BottomSheetState.NONE)}
val currentThemeKey = webReaderViewModel.currentThemeKey.observeAsState() val currentThemeKey = webReaderViewModel.currentThemeKey.observeAsState()
val currentTheme = Themes.values().find { it.themeKey == currentThemeKey.value } val currentTheme = Themes.values().find { it.themeKey == currentThemeKey.value }
@ -121,7 +135,6 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
webReaderViewModel.maxToolbarHeightPx = with(LocalDensity.current) { maxToolbarHeight.roundToPx().toFloat() } webReaderViewModel.maxToolbarHeightPx = with(LocalDensity.current) { maxToolbarHeight.roundToPx().toFloat() }
webReaderViewModel.loadItem(slug = slug, requestID = requestID) webReaderViewModel.loadItem(slug = slug, requestID = requestID)
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val styledContent = webReaderParams?.let { val styledContent = webReaderParams?.let {
@ -140,13 +153,29 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
val themeTintColor = Color(currentTheme?.foregroundColor ?: 0xFFFFFFFF) val themeTintColor = Color(currentTheme?.foregroundColor ?: 0xFFFFFFFF)
ModalBottomSheetLayout( ModalBottomSheetLayout(
modifier = Modifier.statusBarsPadding(), modifier = Modifier
.statusBarsPadding(),
sheetBackgroundColor = Color.Transparent, sheetBackgroundColor = Color.Transparent,
sheetState = modalBottomSheetState, sheetState = modalBottomSheetState,
sheetContent = { sheetContent = {
if (showWebPreferencesDialog) { when (bottomSheetState) {
BottomSheetUI("Reader Preferences") { BottomSheetState.PREFERENCES -> {
ReaderPreferencesView(webReaderViewModel) BottomSheetUI("Reader Preferences") {
ReaderPreferencesView(webReaderViewModel)
}
}
BottomSheetState.NOTEBOOK -> {
webReaderParams?.let { params ->
BottomSheetUI(title = "Notebook") {
NotebookView(savedItemId = params.item.savedItemId, viewModel = notebookViewModel)
}
}
}
BottomSheetState.HIGHLIGHTNOTE -> {
}
BottomSheetState.NONE -> {
} }
} }
Spacer(modifier = Modifier.weight(1.0F)) Spacer(modifier = Modifier.weight(1.0F))
@ -186,9 +215,10 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
} }
webReaderParams?.let { webReaderParams?.let {
IconButton(onClick = { IconButton(onClick = {
val intent = Intent(context, NotebookActivity::class.java) bottomSheetState = BottomSheetState.NOTEBOOK
intent.putExtra("SAVED_ITEM_ID", it.item.savedItemId) coroutineScope.launch {
context.startActivity(intent) modalBottomSheetState.show()
}
}) { }) {
Icon( Icon(
painter = painterResource(id = R.drawable.notebook), painter = painterResource(id = R.drawable.notebook),
@ -198,7 +228,7 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
} }
} }
IconButton(onClick = { IconButton(onClick = {
showWebPreferencesDialog = true bottomSheetState = BottomSheetState.PREFERENCES
coroutineScope.launch { coroutineScope.launch {
modalBottomSheetState.show() modalBottomSheetState.show()
} }
@ -219,7 +249,7 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
webReaderParams?.let { params -> webReaderParams?.let { params ->
SavedItemContextMenu( SavedItemContextMenu(
isExpanded = isMenuExpanded, isExpanded = isMenuExpanded,
isArchived = webReaderParams!!.item.isArchived, isArchived = params.item.isArchived,
onDismiss = { isMenuExpanded = false }, onDismiss = { isMenuExpanded = false },
actionHandler = { actionHandler = {
webReaderViewModel.handleSavedItemAction( webReaderViewModel.handleSavedItemAction(
@ -269,8 +299,6 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
@Composable @Composable
fun BottomSheetUI(title: String?, content: @Composable () -> Unit) { fun BottomSheetUI(title: String?, content: @Composable () -> Unit) {
val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
Box( Box(
modifier = Modifier modifier = Modifier
.wrapContentHeight() .wrapContentHeight()