More work on notebook using bottom sheet
This commit is contained in:
@ -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 "
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user