From 3bf74d1f75f5c3baf69cf43add77d3743e7d0717 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Thu, 26 Jan 2023 15:00:52 -0800 Subject: [PATCH 1/5] add read now button to android share ext --- .../omnivore/omnivore/ui/save/SaveContent.kt | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt index ff2146338..ee37a0f52 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt @@ -29,17 +29,37 @@ fun SaveContent(viewModel: SaveViewModel, modalBottomSheetState: ModalBottomShee .padding(top = 48.dp, bottom = 32.dp) ) { Text(text = viewModel.message ?: "Saving") - Button(onClick = { - coroutineScope.launch { - modalBottomSheetState.hide() + Row { + Button( + onClick = { + coroutineScope.launch { + modalBottomSheetState.hide() + // TODO: open app + } + }, + colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFF3D3D3D), + backgroundColor = Color.White + ) + ) { + Text(text = "Read Now") } - }, - colors = ButtonDefaults.buttonColors( + + Spacer(modifier = Modifier.width(8.dp)) + + Button( + onClick = { + coroutineScope.launch { + modalBottomSheetState.hide() + } + }, + colors = ButtonDefaults.buttonColors( contentColor = Color(0xFF3D3D3D), backgroundColor = Color(0xffffd234) - ) - ) { - Text(text = "Dismiss") + ) + ) { + Text(text = "Read Later") + } } } } From 00dfb9386cec870a1de41e88f349ec75e56416aa Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Mon, 30 Jan 2023 15:22:30 -0800 Subject: [PATCH 2/5] load web reader container from read now button action --- .../Omnivore/app/src/main/AndroidManifest.xml | 6 + .../omnivore/omnivore/ui/reader/WebReader.kt | 117 ---------- .../ui/reader/WebReaderLoadingContainer.kt | 200 ++++++++++++++++++ .../omnivore/ui/reader/WebReaderViewModel.kt | 11 +- .../omnivore/omnivore/ui/save/SaveContent.kt | 13 +- .../omnivore/ui/save/SaveViewModel.kt | 7 +- 6 files changed, 234 insertions(+), 120 deletions(-) create mode 100644 android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt diff --git a/android/Omnivore/app/src/main/AndroidManifest.xml b/android/Omnivore/app/src/main/AndroidManifest.xml index a78d2d2f0..8e8ed979a 100644 --- a/android/Omnivore/app/src/main/AndroidManifest.xml +++ b/android/Omnivore/app/src/main/AndroidManifest.xml @@ -51,5 +51,11 @@ android:name=".ui.reader.PDFReaderActivity" android:theme="@style/Theme.AppCompat.NoActionBar" android:windowSoftInputMode="adjustNothing" /> + + + diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt index ededf42ad..2d38bcef9 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt @@ -41,123 +41,6 @@ import kotlinx.coroutines.launch import java.util.* import kotlin.math.roundToInt - -@Composable -fun WebReaderLoadingContainer(slug: String, webReaderViewModel: WebReaderViewModel) { - val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher - - var isMenuExpanded by remember { mutableStateOf(false) } - var showWebPreferencesDialog by remember { mutableStateOf(false ) } - - val webReaderParams: WebReaderParams? by webReaderViewModel.webReaderParamsLiveData.observeAsState(null) - val annotation: String? by webReaderViewModel.annotationLiveData.observeAsState(null) - val shouldPopView: Boolean by webReaderViewModel.shouldPopViewLiveData.observeAsState(false) - - val maxToolbarHeight = 48.dp - val maxToolbarHeightPx = with(LocalDensity.current) { maxToolbarHeight.roundToPx().toFloat() } - val toolbarHeightPx = remember { mutableStateOf(maxToolbarHeightPx) } - - // Create a connection to the nested scroll system and listen to the scroll happening inside child Column - val nestedScrollConnection = remember { - object : NestedScrollConnection { - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - val delta = available.y - val newHeight = toolbarHeightPx.value + delta - toolbarHeightPx.value = newHeight.coerceIn(0f, maxToolbarHeightPx) - return Offset.Zero - } - } - } - - if (webReaderParams == null) { - webReaderViewModel.loadItem(slug = slug) - } - - if (webReaderParams != null) { - Box( - modifier = Modifier - .fillMaxSize() - .nestedScroll(nestedScrollConnection) - ) { - Column( - modifier = Modifier - .fillMaxSize() - .verticalScroll(webReaderViewModel.scrollState) - - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .requiredHeight(height = maxToolbarHeight) - ) { - } - WebReader(webReaderParams!!, webReaderViewModel.storedWebPreferences(isSystemInDarkTheme()), webReaderViewModel) - } - - TopAppBar( - modifier = Modifier - .height(height = with(LocalDensity.current) { - webReaderViewModel.currentToolbarHeight = toolbarHeightPx.value.toInt() - toolbarHeightPx.value.roundToInt().toDp() - } ), - backgroundColor = MaterialTheme.colorScheme.surfaceVariant, - title = {}, - actions = { - // Disabling menu until we implement local persistence - IconButton(onClick = { isMenuExpanded = true }) { - Icon( - imageVector = Icons.Filled.Menu, - contentDescription = null - ) - } - IconButton(onClick = { showWebPreferencesDialog = true }) { - Icon( - imageVector = Icons.Filled.Settings, // TODO: set a better icon - contentDescription = null - ) - } - SavedItemContextMenu( - isExpanded = isMenuExpanded, - isArchived = webReaderParams!!.item.isArchived, - onDismiss = { isMenuExpanded = false }, - actionHandler = { webReaderViewModel.handleSavedItemAction(webReaderParams!!.item.savedItemId, it) } - ) - } - ) - - if (showWebPreferencesDialog) { - WebPreferencesDialog( - onDismiss = { - showWebPreferencesDialog = false - }, - webReaderViewModel = webReaderViewModel - ) - } - - if (annotation != null) { - AnnotationEditView( - initialAnnotation = annotation!!, - onSave = { - webReaderViewModel.saveAnnotation(it) - }, - onCancel = { - webReaderViewModel.cancelAnnotationEdit() - } - ) - } - } - - LaunchedEffect(shouldPopView) { - if (shouldPopView) { - onBackPressedDispatcher?.onBackPressed() - } - } - } else { - // TODO: add a proper loading view - Text("Loading...") - } -} - @SuppressLint("SetJavaScriptEnabled") @Composable fun WebReader( diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt new file mode 100644 index 000000000..8313adb39 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt @@ -0,0 +1,200 @@ +package app.omnivore.omnivore.ui.reader + +import android.graphics.PointF +import android.os.Bundle +import android.util.Log +import android.view.View +import androidx.activity.compose.LocalOnBackPressedDispatcherOwner +import androidx.activity.compose.setContent +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Menu +import androidx.compose.material.icons.filled.Settings +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import app.omnivore.omnivore.R +import app.omnivore.omnivore.ui.root.RootView +import app.omnivore.omnivore.ui.savedItemViews.SavedItemContextMenu +import app.omnivore.omnivore.ui.theme.OmnivoreTheme +import com.pspdfkit.annotations.Annotation +import com.pspdfkit.annotations.HighlightAnnotation +import com.pspdfkit.configuration.PdfConfiguration +import com.pspdfkit.configuration.page.PageScrollDirection +import com.pspdfkit.listeners.DocumentListener +import com.pspdfkit.listeners.OnPreparePopupToolbarListener +import com.pspdfkit.ui.PdfFragment +import com.pspdfkit.ui.PdfThumbnailBar +import com.pspdfkit.ui.search.PdfSearchViewModular +import com.pspdfkit.ui.special_mode.controller.TextSelectionController +import com.pspdfkit.ui.special_mode.manager.TextSelectionManager +import dagger.hilt.android.AndroidEntryPoint +import kotlin.math.roundToInt + + +@AndroidEntryPoint +class WebReaderLoadingContainerActivity: AppCompatActivity() { + val viewModel: WebReaderViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val requestID = intent.getStringExtra("SAVED_ITEM_REQUEST_ID") ?: "" + + setContent { + OmnivoreTheme { + Box( + modifier = Modifier + .fillMaxSize() + .background(color = Color.Black) + ) { + WebReaderLoadingContainer(requestID = requestID, webReaderViewModel = viewModel) + } + } + } + + // animate the view up when keyboard appears + WindowCompat.setDecorFitsSystemWindows(window, false) + val rootView = findViewById(android.R.id.content).rootView + ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets -> + val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom + rootView.setPadding(0, 0, 0, imeHeight) + insets + } + } +} + +@Composable +fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, webReaderViewModel: WebReaderViewModel) { + val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher + + var isMenuExpanded by remember { mutableStateOf(false) } + var showWebPreferencesDialog by remember { mutableStateOf(false ) } + + val webReaderParams: WebReaderParams? by webReaderViewModel.webReaderParamsLiveData.observeAsState(null) + val annotation: String? by webReaderViewModel.annotationLiveData.observeAsState(null) + val shouldPopView: Boolean by webReaderViewModel.shouldPopViewLiveData.observeAsState(false) + + val maxToolbarHeight = 48.dp + val maxToolbarHeightPx = with(LocalDensity.current) { maxToolbarHeight.roundToPx().toFloat() } + val toolbarHeightPx = remember { mutableStateOf(maxToolbarHeightPx) } + + // Create a connection to the nested scroll system and listen to the scroll happening inside child Column + val nestedScrollConnection = remember { + object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + val delta = available.y + val newHeight = toolbarHeightPx.value + delta + toolbarHeightPx.value = newHeight.coerceIn(0f, maxToolbarHeightPx) + return Offset.Zero + } + } + } + + if (webReaderParams == null) { + webReaderViewModel.loadItem(slug = slug, requestID = requestID) + } + + if (webReaderParams != null) { + Box( + modifier = Modifier + .fillMaxSize() + .nestedScroll(nestedScrollConnection) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(webReaderViewModel.scrollState) + + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .requiredHeight(height = maxToolbarHeight) + ) { + } + WebReader(webReaderParams!!, webReaderViewModel.storedWebPreferences(isSystemInDarkTheme()), webReaderViewModel) + } + + TopAppBar( + modifier = Modifier + .height(height = with(LocalDensity.current) { + webReaderViewModel.currentToolbarHeight = toolbarHeightPx.value.toInt() + toolbarHeightPx.value.roundToInt().toDp() + } ), + backgroundColor = MaterialTheme.colorScheme.surfaceVariant, + title = {}, + actions = { + // Disabling menu until we implement local persistence + IconButton(onClick = { isMenuExpanded = true }) { + Icon( + imageVector = Icons.Filled.Menu, + contentDescription = null + ) + } + IconButton(onClick = { showWebPreferencesDialog = true }) { + Icon( + imageVector = Icons.Filled.Settings, // TODO: set a better icon + contentDescription = null + ) + } + SavedItemContextMenu( + isExpanded = isMenuExpanded, + isArchived = webReaderParams!!.item.isArchived, + onDismiss = { isMenuExpanded = false }, + actionHandler = { webReaderViewModel.handleSavedItemAction(webReaderParams!!.item.savedItemId, it) } + ) + } + ) + + if (showWebPreferencesDialog) { + WebPreferencesDialog( + onDismiss = { + showWebPreferencesDialog = false + }, + webReaderViewModel = webReaderViewModel + ) + } + + if (annotation != null) { + AnnotationEditView( + initialAnnotation = annotation!!, + onSave = { + webReaderViewModel.saveAnnotation(it) + }, + onCancel = { + webReaderViewModel.cancelAnnotationEdit() + } + ) + } + } + + LaunchedEffect(shouldPopView) { + if (shouldPopView) { + onBackPressedDispatcher?.onBackPressed() + } + } + } else { + // TODO: add a proper loading view + Text("Loading...") + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt index affa6166d..eca884c8b 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt @@ -45,7 +45,12 @@ class WebReaderViewModel @Inject constructor( var hasTappedExistingHighlight = false var lastTapCoordinates: TapCoordinates? = null - fun loadItem(slug: String) { + fun loadItem(slug: String?, requestID: String?) { + slug?.let { loadItemUsingSlug(it) } + requestID?.let { loadItemUsingRequestID(it) } + } + + private fun loadItemUsingSlug(slug: String) { viewModelScope.launch { val webReaderParams = loadItemFromServer(slug) @@ -58,6 +63,10 @@ class WebReaderViewModel @Inject constructor( } } + private fun loadItemUsingRequestID(requestID: String) { + // TODO: implement + } + private suspend fun loadItemFromDB(slug: String) { withContext(Dispatchers.IO) { val persistedItem = dataService.db.savedItemDao().getSavedItemWithLabelsAndHighlights(slug) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt index ee37a0f52..e0818befe 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveContent.kt @@ -1,5 +1,7 @@ package app.omnivore.omnivore.ui.save +import android.content.Intent +import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material.MaterialTheme @@ -11,13 +13,18 @@ import androidx.compose.material.* import androidx.compose.material.ButtonDefaults import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp +import app.omnivore.omnivore.MainActivity +import app.omnivore.omnivore.ui.reader.PDFReaderActivity +import app.omnivore.omnivore.ui.reader.WebReaderLoadingContainerActivity import kotlinx.coroutines.launch @Composable @OptIn(ExperimentalMaterialApi::class) fun SaveContent(viewModel: SaveViewModel, modalBottomSheetState: ModalBottomSheetState, modifier: Modifier) { val coroutineScope = rememberCoroutineScope() + val context = LocalContext.current Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { Column( @@ -34,7 +41,11 @@ fun SaveContent(viewModel: SaveViewModel, modalBottomSheetState: ModalBottomShee onClick = { coroutineScope.launch { modalBottomSheetState.hide() - // TODO: open app + viewModel.clientRequestID?.let { + val intent = Intent(context, WebReaderLoadingContainerActivity::class.java) + intent.putExtra("SAVED_ITEM_REQUEST_ID", it) + context.startActivity(intent) + } } }, colors = ButtonDefaults.buttonColors( diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveViewModel.kt index 0dbdc7222..b02e92f59 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/save/SaveViewModel.kt @@ -29,6 +29,9 @@ class SaveViewModel @Inject constructor( var message by mutableStateOf(null) private set + var clientRequestID by mutableStateOf(null) + private set + private fun getAuthToken(): String? = runBlocking { datastoreRepo.getString(DatastoreKeys.omnivoreAuthToken) } @@ -52,10 +55,12 @@ class SaveViewModel @Inject constructor( .build() try { + clientRequestID = UUID.randomUUID().toString() + val response = apolloClient.mutation( SaveUrlMutation( SaveUrlInput( - clientRequestId = UUID.randomUUID().toString(), + clientRequestId = clientRequestID!!, source = "android", url = url ) From 9894b8fb506acd575e644a43878dcdfa9236b533 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 31 Jan 2023 12:20:24 -0800 Subject: [PATCH 3/5] load web reader container when tapping read now --- .../Omnivore/app/src/main/AndroidManifest.xml | 5 +- .../omnivore/networking/SavedItemQuery.kt | 9 ++-- .../ui/reader/WebReaderLoadingContainer.kt | 52 ++++++++++++------- .../omnivore/ui/reader/WebReaderViewModel.kt | 44 ++++++++++------ 4 files changed, 68 insertions(+), 42 deletions(-) diff --git a/android/Omnivore/app/src/main/AndroidManifest.xml b/android/Omnivore/app/src/main/AndroidManifest.xml index 8e8ed979a..1667cf88b 100644 --- a/android/Omnivore/app/src/main/AndroidManifest.xml +++ b/android/Omnivore/app/src/main/AndroidManifest.xml @@ -54,8 +54,9 @@ + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.Omnivore"/> diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt index 9cc667461..bc5ec8840 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/networking/SavedItemQuery.kt @@ -8,11 +8,12 @@ import app.omnivore.omnivore.persistence.entities.Highlight data class SavedItemQueryResponse( val item: SavedItem?, val highlights: List, - val labels: List + val labels: List, + val state: String ) { companion object { fun emptyResponse(): SavedItemQueryResponse { - return SavedItemQueryResponse(null, listOf(), listOf()) + return SavedItemQueryResponse(null, listOf(), listOf(), state = "") } } } @@ -79,8 +80,8 @@ suspend fun Networker.savedItem(slug: String): SavedItemQueryResponse { content = article.articleFields.content ) - return SavedItemQueryResponse(item = savedItem, highlights, labels = savedItemLabels) + return SavedItemQueryResponse(item = savedItem, highlights, labels = savedItemLabels, state = article.articleFields.state?.rawValue ?: "") } catch (e: java.lang.Exception) { - return SavedItemQueryResponse(item = null, listOf(), labels = listOf()) + return SavedItemQueryResponse(item = null, listOf(), labels = listOf(), state = "") } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt index 8313adb39..a23ef6b53 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt @@ -1,14 +1,13 @@ package app.omnivore.omnivore.ui.reader -import android.graphics.PointF import android.os.Bundle -import android.util.Log import android.view.View +import androidx.activity.ComponentActivity import androidx.activity.compose.LocalOnBackPressedDispatcherOwner import androidx.activity.compose.setContent import androidx.activity.viewModels -import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* import androidx.compose.foundation.verticalScroll @@ -22,6 +21,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color @@ -33,27 +33,15 @@ import androidx.compose.ui.unit.dp import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat -import app.omnivore.omnivore.R -import app.omnivore.omnivore.ui.root.RootView import app.omnivore.omnivore.ui.savedItemViews.SavedItemContextMenu import app.omnivore.omnivore.ui.theme.OmnivoreTheme -import com.pspdfkit.annotations.Annotation -import com.pspdfkit.annotations.HighlightAnnotation -import com.pspdfkit.configuration.PdfConfiguration -import com.pspdfkit.configuration.page.PageScrollDirection -import com.pspdfkit.listeners.DocumentListener -import com.pspdfkit.listeners.OnPreparePopupToolbarListener -import com.pspdfkit.ui.PdfFragment -import com.pspdfkit.ui.PdfThumbnailBar -import com.pspdfkit.ui.search.PdfSearchViewModular -import com.pspdfkit.ui.special_mode.controller.TextSelectionController -import com.pspdfkit.ui.special_mode.manager.TextSelectionManager +import com.google.accompanist.systemuicontroller.rememberSystemUiController import dagger.hilt.android.AndroidEntryPoint import kotlin.math.roundToInt @AndroidEntryPoint -class WebReaderLoadingContainerActivity: AppCompatActivity() { +class WebReaderLoadingContainerActivity: ComponentActivity() { val viewModel: WebReaderViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { @@ -61,15 +49,32 @@ class WebReaderLoadingContainerActivity: AppCompatActivity() { val requestID = intent.getStringExtra("SAVED_ITEM_REQUEST_ID") ?: "" setContent { + val systemUiController = rememberSystemUiController() + val useDarkIcons = !isSystemInDarkTheme() + OmnivoreTheme { Box( modifier = Modifier .fillMaxSize() .background(color = Color.Black) + .systemBarsPadding() ) { - WebReaderLoadingContainer(requestID = requestID, webReaderViewModel = viewModel) + if (viewModel.hasFetchError.value == true) { + Text("We were unable to fetch your content.") + } else { + WebReaderLoadingContainer(requestID = requestID, webReaderViewModel = viewModel) + } } } + + DisposableEffect(systemUiController, useDarkIcons) { + systemUiController.setSystemBarsColor( + color = Color.Black, + darkIcons = false + ) + + onDispose {} + } } // animate the view up when keyboard appears @@ -194,7 +199,14 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, w } } } else { - // TODO: add a proper loading view - Text("Loading...") + Column( + verticalArrangement = Arrangement.SpaceAround, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + Text("Loading...", color = Color.White) + } } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt index eca884c8b..4bb3b4fa3 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt @@ -41,30 +41,42 @@ class WebReaderViewModel @Inject constructor( val annotationLiveData = MutableLiveData(null) val javascriptActionLoopUUIDLiveData = MutableLiveData(lastJavascriptActionLoopUUID) val shouldPopViewLiveData = MutableLiveData(false) + val hasFetchError = MutableLiveData(false) var hasTappedExistingHighlight = false var lastTapCoordinates: TapCoordinates? = null fun loadItem(slug: String?, requestID: String?) { - slug?.let { loadItemUsingSlug(it) } - requestID?.let { loadItemUsingRequestID(it) } - } - - private fun loadItemUsingSlug(slug: String) { viewModelScope.launch { - val webReaderParams = loadItemFromServer(slug) - - if (webReaderParams != null) { - Log.d("sync", "data loaded from server") - webReaderParamsLiveData.postValue(webReaderParams) - } else { - loadItemFromDB(slug) - } + slug?.let { loadItemUsingSlug(it) } + requestID?.let { loadItemUsingRequestID(it) } } } - private fun loadItemUsingRequestID(requestID: String) { - // TODO: implement + private suspend fun loadItemUsingSlug(slug: String) { + val webReaderParams = loadItemFromServer(slug) + + if (webReaderParams != null) { + Log.d("sync", "data loaded from server") + webReaderParamsLiveData.postValue(webReaderParams) + } else { + loadItemFromDB(slug) + } + } + + private suspend fun loadItemUsingRequestID(requestID: String, requestCount: Int = 0) { + val webReaderParams = loadItemFromServer(requestID) + val isSuccessful = webReaderParams?.articleContent?.contentStatus == "SUCCEEDED" + + if (webReaderParams != null && isSuccessful) { + webReaderParamsLiveData.postValue(webReaderParams) + } else if (requestCount < 7) { + // delay then try again + delay(2000L) + loadItemUsingRequestID(requestID = requestID, requestCount = requestCount + 1) + } else { + hasFetchError.postValue(true) + } } private suspend fun loadItemFromDB(slug: String) { @@ -96,7 +108,7 @@ class WebReaderViewModel @Inject constructor( title = article.title, htmlContent = article.content ?: "", highlights = articleQueryResult.highlights, - contentStatus = "SUCCEEDED", + contentStatus = articleQueryResult.state, objectID = "", labelsJSONString = Gson().toJson(articleQueryResult.labels) ) From 07fd550ee4688c4ffc672b49d2b38bf0bae55d89 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 31 Jan 2023 12:35:08 -0800 Subject: [PATCH 4/5] add shortcut to library when reader is opened from share ext --- .../Omnivore/app/src/main/AndroidManifest.xml | 1 - .../ui/reader/WebReaderLoadingContainer.kt | 25 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/android/Omnivore/app/src/main/AndroidManifest.xml b/android/Omnivore/app/src/main/AndroidManifest.xml index 1667cf88b..3983989ed 100644 --- a/android/Omnivore/app/src/main/AndroidManifest.xml +++ b/android/Omnivore/app/src/main/AndroidManifest.xml @@ -55,7 +55,6 @@ diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt index a23ef6b53..9e9e2d973 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt @@ -1,5 +1,6 @@ package app.omnivore.omnivore.ui.reader +import android.content.Intent import android.os.Bundle import android.view.View import androidx.activity.ComponentActivity @@ -13,6 +14,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.verticalScroll import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.Icon @@ -33,6 +35,7 @@ import androidx.compose.ui.unit.dp import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat +import app.omnivore.omnivore.MainActivity import app.omnivore.omnivore.ui.savedItemViews.SavedItemContextMenu import app.omnivore.omnivore.ui.theme.OmnivoreTheme import com.google.accompanist.systemuicontroller.rememberSystemUiController @@ -62,7 +65,11 @@ class WebReaderLoadingContainerActivity: ComponentActivity() { if (viewModel.hasFetchError.value == true) { Text("We were unable to fetch your content.") } else { - WebReaderLoadingContainer(requestID = requestID, webReaderViewModel = viewModel) + WebReaderLoadingContainer( + requestID = requestID, + onLibraryIconTap = { startMainActivity() }, + webReaderViewModel = viewModel + ) } } } @@ -86,10 +93,15 @@ class WebReaderLoadingContainerActivity: ComponentActivity() { insets } } + + private fun startMainActivity() { + val intent = Intent(this, MainActivity::class.java) + this.startActivity(intent) + } } @Composable -fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, webReaderViewModel: WebReaderViewModel) { +fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, onLibraryIconTap: (() -> Unit)? = null, webReaderViewModel: WebReaderViewModel) { val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher var isMenuExpanded by remember { mutableStateOf(false) } @@ -149,7 +161,14 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, w backgroundColor = MaterialTheme.colorScheme.surfaceVariant, title = {}, actions = { - // Disabling menu until we implement local persistence + if (onLibraryIconTap != null) { + IconButton(onClick = { onLibraryIconTap() }) { + Icon( + imageVector = Icons.Filled.List, + contentDescription = null + ) + } + } IconButton(onClick = { isMenuExpanded = true }) { Icon( imageVector = Icons.Filled.Menu, From 4be570b621a0a94146697fa3385b0c5ff997139e Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 31 Jan 2023 12:38:57 -0800 Subject: [PATCH 5/5] add library shorcut --- .../omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt index 9e9e2d973..0bee40bc6 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.verticalScroll import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Settings @@ -164,7 +165,7 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o if (onLibraryIconTap != null) { IconButton(onClick = { onLibraryIconTap() }) { Icon( - imageVector = Icons.Filled.List, + imageVector = Icons.Default.Home, contentDescription = null ) }