From 21aeddaf99c3ac8fa4a389f5833896764df26725 Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 09:15:14 -0500 Subject: [PATCH 01/69] Updating libs! --- .../uiviews/favorite/FavoriteFragment.kt | 55 +++- .../globalsearch/GlobalSearchFragment.kt | 133 ++++---- .../notifications/NotificationFragment.kt | 298 +++++++++--------- .../uiviews/utils/NavigationUtils.kt | 2 +- .../components/BottomSheetDeleteScaffold.kt | 56 ++-- gradle/libs.versions.toml | 8 +- .../downloads/DownloadViewerFragment.kt | 102 +++--- .../mangaworld/reader/ReaderCompose.kt | 22 +- 8 files changed, 348 insertions(+), 328 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/favorite/FavoriteFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/favorite/FavoriteFragment.kt index b52a70d86..d1ba4d233 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/favorite/FavoriteFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/favorite/FavoriteFragment.kt @@ -2,6 +2,7 @@ package com.programmersbox.uiviews.favorite import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow @@ -10,8 +11,6 @@ import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* @@ -25,7 +24,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastMap import androidx.lifecycle.createSavedStateHandle @@ -139,10 +137,24 @@ fun FavoriteUi(logo: MainLogo) { } ) - OutlinedTextField( - value = searchText, - onValueChange = { searchText = it }, - label = { + var active by rememberSaveable { mutableStateOf(false) } + + fun closeSearchBar() { + focusManager.clearFocus() + active = false + } + SearchBar( + modifier = Modifier.fillMaxWidth(), + windowInsets = WindowInsets(0.dp), + query = searchText, + onQueryChange = { searchText = it }, + onSearch = { closeSearchBar() }, + active = active, + onActiveChange = { + active = it + if (!active) focusManager.clearFocus() + }, + placeholder = { Text( context.resources.getQuantityString( R.plurals.numFavorites, @@ -151,18 +163,33 @@ fun FavoriteUi(logo: MainLogo) { ) ) }, + leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) }, trailingIcon = { IconButton(onClick = { searchText = "" }) { Icon(Icons.Default.Cancel, null) } }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 5.dp), - singleLine = true, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onSearch = { focusManager.clearFocus() }) - ) + ) { + Column( + modifier = Modifier.padding(16.dp).fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + showing.take(4).forEachIndexed { index, dbModel -> + ListItem( + headlineText = { Text(dbModel.title) }, + supportingText = { Text(dbModel.source) }, + leadingContent = { Icon(Icons.Filled.Star, contentDescription = null) }, + modifier = Modifier.clickable { + searchText = dbModel.title + closeSearchBar() + } + ) + if (index != 3) { + Divider() + } + } + } + } LazyRow( horizontalArrangement = Arrangement.spacedBy(5.dp), diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt index d75bbd706..205985e5a 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt @@ -5,7 +5,6 @@ import androidx.activity.compose.BackHandler import androidx.appcompat.content.res.AppCompatResources import androidx.compose.animation.Crossfade import androidx.compose.animation.ExperimentalAnimationApi -import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -16,23 +15,22 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.BottomSheetScaffold import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Cancel import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.CloudOff +import androidx.compose.material.icons.filled.Search import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.material3.* import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter @@ -43,7 +41,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.createSavedStateHandle @@ -58,8 +55,6 @@ import com.programmersbox.models.ItemModel import com.programmersbox.sharedutils.MainLogo import com.programmersbox.uiviews.R import com.programmersbox.uiviews.utils.* -import com.programmersbox.uiviews.utils.components.AutoCompleteBox -import com.programmersbox.uiviews.utils.components.asAutoCompleteEntities import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import androidx.compose.material3.MaterialTheme as M3MaterialTheme @@ -135,69 +130,70 @@ fun GlobalSearchView( title = { Text(stringResource(R.string.global_search)) }, scrollBehavior = scrollBehavior ) - AutoCompleteBox( - items = history.asAutoCompleteEntities { _, _ -> true }, - trailingIcon = { - IconButton( - onClick = { scope.launch { dao.deleteHistory(it.value) } }, - modifier = Modifier.weight(.1f) - ) { Icon(Icons.Default.Cancel, null) } + var active by rememberSaveable { mutableStateOf(false) } + + fun closeSearchBar() { + focusManager.clearFocus() + active = false + } + SearchBar( + modifier = Modifier.fillMaxWidth(), + windowInsets = WindowInsets(0.dp), + query = viewModel.searchText, + onQueryChange = { viewModel.searchText = it }, + onSearch = { + closeSearchBar() + if (viewModel.searchText.isNotEmpty()) { + scope.launch(Dispatchers.IO) { + dao.insertHistory(HistoryItem(System.currentTimeMillis(), viewModel.searchText)) + } + } + viewModel.searchForItems() }, - itemContent = { - Text( - text = it.value.searchText, - style = M3MaterialTheme.typography.titleSmall, - modifier = Modifier - .padding(horizontal = 16.dp, vertical = 8.dp) - .weight(.9f) - ) + active = active, + onActiveChange = { + active = it + if (!active) focusManager.clearFocus() }, - content = { - - boxWidthPercentage = 1f - boxBorderStroke = BorderStroke(2.dp, Color.Transparent) - - onItemSelected { - viewModel.searchText = it.value.searchText - filter(viewModel.searchText) - focusManager.clearFocus() - viewModel.searchForItems() + placeholder = { Text(stringResource(id = R.string.search)) }, + leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) }, + trailingIcon = { + IconButton(onClick = { viewModel.searchText = "" }) { + Icon(Icons.Default.Cancel, null) } - - androidx.compose.material3.OutlinedTextField( - value = viewModel.searchText, - onValueChange = { - viewModel.searchText = it - filter(it) - }, - label = { Text(stringResource(id = R.string.search)) }, - trailingIcon = { - IconButton( - onClick = { - viewModel.searchText = "" - filter("") - viewModel.searchListPublisher = emptyList() - } - ) { Icon(Icons.Default.Cancel, null) } - }, - modifier = Modifier - .padding(5.dp) - .fillMaxWidth() - .onFocusChanged { isSearching = it.isFocused }, - singleLine = true, - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onSearch = { - focusManager.clearFocus() - if (viewModel.searchText.isNotEmpty()) { - scope.launch(Dispatchers.IO) { - dao.insertHistory(HistoryItem(System.currentTimeMillis(), viewModel.searchText)) + }, + ) { + Column( + modifier = Modifier.padding(16.dp).fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + history.forEachIndexed { index, historyModel -> + ListItem( + headlineText = { Text(historyModel.searchText) }, + leadingContent = { Icon(Icons.Filled.Search, contentDescription = null) }, + trailingContent = { + IconButton( + onClick = { scope.launch { dao.deleteHistory(historyModel) } }, + modifier = Modifier.weight(.1f) + ) { Icon(Icons.Default.Cancel, null) } + }, + modifier = Modifier.clickable { + viewModel.searchText = historyModel.searchText + closeSearchBar() + if (viewModel.searchText.isNotEmpty()) { + scope.launch(Dispatchers.IO) { + dao.insertHistory(HistoryItem(System.currentTimeMillis(), viewModel.searchText)) + } } + viewModel.searchForItems() } - viewModel.searchForItems() - }) - ) + ) + if (index != history.lastIndex) { + Divider() + } + } } - ) + } } }, sheetContent = searchModelBottom?.let { s -> @@ -234,14 +230,14 @@ fun GlobalSearchView( } } ?: {}, sheetPeekHeight = 0.dp, - ) { + ) { padding -> Crossfade(targetState = networkState) { network -> when (network) { false -> { Column( modifier = Modifier .fillMaxSize() - .padding(it), + .padding(padding), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { @@ -258,14 +254,17 @@ fun GlobalSearchView( ) } } + true -> { Box( modifier = Modifier.pullRefresh(pullRefreshState, false) ) { LazyColumn( state = listState, + contentPadding = padding, verticalArrangement = Arrangement.spacedBy(2.dp), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(top = 4.dp) ) { if (viewModel.isRefreshing) { items(3) { diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt index d27ab44f1..65d66d1e6 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt @@ -9,18 +9,14 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.material.* +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.LocalContentAlpha import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ClearAll import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.material3.* -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -78,7 +74,7 @@ private fun NotificationManager.cancelNotification(item: NotificationItem) { @OptIn( ExperimentalMaterial3Api::class, - ExperimentalMaterialApi::class, + ExperimentalMaterialApi::class, ExperimentalMaterialApi::class, ) @Composable fun NotificationsScreen( @@ -260,7 +256,6 @@ fun NotificationsScreen( } @OptIn(ExperimentalMaterial3Api::class) -@ExperimentalMaterialApi @Composable private fun NotificationItem( item: NotificationItem, @@ -305,7 +300,7 @@ private fun NotificationItem( ) val dismissState = rememberDismissState( - confirmStateChange = { + confirmValueChange = { if (it == DismissValue.DismissedToEnd || it == DismissValue.DismissedToStart) { showPopup = true } @@ -348,166 +343,167 @@ private fun NotificationItem( tint = M3MaterialTheme.colorScheme.onSurface.copy(alpha = LocalContentAlpha.current) ) } - } - ) { - ElevatedCard( - onClick = { - scope.launch { - genericInfo - .toSource(item.source) - ?.let { source -> - Cached.cache[item.url]?.let { - flow { - emit( - it - .toDbModel() - .toItemModel(source) - ) - } - } ?: source.getSourceByUrlFlow(item.url) - } - ?.dispatchIo() - ?.onStart { showLoadingDialog = true } - ?.onEach { - showLoadingDialog = false - navController.navigateToDetails(it) - } - ?.collect() - } - }, - modifier = Modifier.padding(horizontal = 5.dp) - ) { - Row { - val logoDrawable = remember { AppCompatResources.getDrawable(context, logo.logoId) } - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(item.imageUrl) - .lifecycle(LocalLifecycleOwner.current) - .crossfade(true) - .build(), - placeholder = rememberDrawablePainter(logoDrawable), - error = rememberDrawablePainter(logoDrawable), - contentScale = ContentScale.Crop, - contentDescription = item.notiTitle, - modifier = Modifier - .align(Alignment.CenterVertically) - .size(ComposableUtils.IMAGE_WIDTH, ComposableUtils.IMAGE_HEIGHT) - ) + }, + dismissContent = { + ElevatedCard( + onClick = { + scope.launch { + genericInfo + .toSource(item.source) + ?.let { source -> + Cached.cache[item.url]?.let { + flow { + emit( + it + .toDbModel() + .toItemModel(source) + ) + } + } ?: source.getSourceByUrlFlow(item.url) + } + ?.dispatchIo() + ?.onStart { showLoadingDialog = true } + ?.onEach { + showLoadingDialog = false + navController.navigateToDetails(it) + } + ?.collect() + } + }, + modifier = Modifier.padding(horizontal = 5.dp) + ) { + Row { + val logoDrawable = remember { AppCompatResources.getDrawable(context, logo.logoId) } + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(item.imageUrl) + .lifecycle(LocalLifecycleOwner.current) + .crossfade(true) + .build(), + placeholder = rememberDrawablePainter(logoDrawable), + error = rememberDrawablePainter(logoDrawable), + contentScale = ContentScale.Crop, + contentDescription = item.notiTitle, + modifier = Modifier + .align(Alignment.CenterVertically) + .size(ComposableUtils.IMAGE_WIDTH, ComposableUtils.IMAGE_HEIGHT) + ) - Column( - modifier = Modifier - .weight(1f) - .padding(start = 16.dp, top = 4.dp) - ) { - Text(item.source, style = M3MaterialTheme.typography.labelMedium) - Text(item.notiTitle, style = M3MaterialTheme.typography.titleSmall) - Text(item.summaryText, style = M3MaterialTheme.typography.bodyMedium) - } + Column( + modifier = Modifier + .weight(1f) + .padding(start = 16.dp, top = 4.dp) + ) { + Text(item.source, style = M3MaterialTheme.typography.labelMedium) + Text(item.notiTitle, style = M3MaterialTheme.typography.titleSmall) + Text(item.summaryText, style = M3MaterialTheme.typography.bodyMedium) + } - Box( - modifier = Modifier - .align(Alignment.Top) - .padding(horizontal = 2.dp) - ) { + Box( + modifier = Modifier + .align(Alignment.Top) + .padding(horizontal = 2.dp) + ) { - var showDropDown by remember { mutableStateOf(false) } + var showDropDown by remember { mutableStateOf(false) } - val dropDownDismiss = { showDropDown = false } + val dropDownDismiss = { showDropDown = false } - DropdownMenu( - expanded = showDropDown, - onDismissRequest = dropDownDismiss - ) { - DropdownMenuItem( - text = { Text(stringResource(R.string.notify)) }, - onClick = { - dropDownDismiss() - scope.launch(Dispatchers.IO) { - SavedNotifications.viewNotificationFromDb(context, item, notificationLogo, genericInfo) + DropdownMenu( + expanded = showDropDown, + onDismissRequest = dropDownDismiss + ) { + DropdownMenuItem( + text = { Text(stringResource(R.string.notify)) }, + onClick = { + dropDownDismiss() + scope.launch(Dispatchers.IO) { + SavedNotifications.viewNotificationFromDb(context, item, notificationLogo, genericInfo) + } } - } - ) - - Divider() - - DropdownMenuItem( - text = { Text(stringResource(R.string.notifyAtTime)) }, - onClick = { - dropDownDismiss() - val datePicker = MaterialDatePicker.Builder.datePicker() - .setTitleText(R.string.selectDate) - .setCalendarConstraints( - CalendarConstraints.Builder() - .setOpenAt(System.currentTimeMillis()) - .setValidator(DateValidatorPointForward.now()) - .build() - ) - .setSelection(System.currentTimeMillis()) - .build() - - datePicker.addOnPositiveButtonClickListener { - val c = Calendar.getInstance() - val timePicker = MaterialTimePicker.Builder() - .setTitleText(R.string.selectTime) - .setPositiveButtonText(R.string.ok) - .setTimeFormat( - if (DateFormat.is24HourFormat(context)) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H + ) + + Divider() + + DropdownMenuItem( + text = { Text(stringResource(R.string.notifyAtTime)) }, + onClick = { + dropDownDismiss() + val datePicker = MaterialDatePicker.Builder.datePicker() + .setTitleText(R.string.selectDate) + .setCalendarConstraints( + CalendarConstraints.Builder() + .setOpenAt(System.currentTimeMillis()) + .setValidator(DateValidatorPointForward.now()) + .build() ) - .setHour(c[Calendar.HOUR_OF_DAY]) - .setMinute(c[Calendar.MINUTE]) + .setSelection(System.currentTimeMillis()) .build() - timePicker.addOnPositiveButtonClickListener { _ -> - c.timeInMillis = it - c.add(Calendar.DAY_OF_YEAR, 1) - c[Calendar.HOUR_OF_DAY] = timePicker.hour - c[Calendar.MINUTE] = timePicker.minute - - WorkManager.getInstance(context) - .enqueueUniqueWork( - item.notiTitle, - ExistingWorkPolicy.REPLACE, - OneTimeWorkRequestBuilder() - .setInputData( - Data.Builder() - .putString("notiData", item.toJson()) - .build() - ) - .setInitialDelay(c.timeInMillis - System.currentTimeMillis(), TimeUnit.MILLISECONDS) - .build() + datePicker.addOnPositiveButtonClickListener { + val c = Calendar.getInstance() + val timePicker = MaterialTimePicker.Builder() + .setTitleText(R.string.selectTime) + .setPositiveButtonText(R.string.ok) + .setTimeFormat( + if (DateFormat.is24HourFormat(context)) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H ) + .setHour(c[Calendar.HOUR_OF_DAY]) + .setMinute(c[Calendar.MINUTE]) + .build() - Toast.makeText( - context, - context.getString( - R.string.willNotifyAt, - context.getSystemDateTimeFormat().format(c.timeInMillis) - ), - Toast.LENGTH_SHORT - ).show() + timePicker.addOnPositiveButtonClickListener { _ -> + c.timeInMillis = it + c.add(Calendar.DAY_OF_YEAR, 1) + c[Calendar.HOUR_OF_DAY] = timePicker.hour + c[Calendar.MINUTE] = timePicker.minute + + WorkManager.getInstance(context) + .enqueueUniqueWork( + item.notiTitle, + ExistingWorkPolicy.REPLACE, + OneTimeWorkRequestBuilder() + .setInputData( + Data.Builder() + .putString("notiData", item.toJson()) + .build() + ) + .setInitialDelay(c.timeInMillis - System.currentTimeMillis(), TimeUnit.MILLISECONDS) + .build() + ) + + Toast.makeText( + context, + context.getString( + R.string.willNotifyAt, + context.getSystemDateTimeFormat().format(c.timeInMillis) + ), + Toast.LENGTH_SHORT + ).show() + } + + timePicker.show(parentFragmentManager, "timePicker") } - timePicker.show(parentFragmentManager, "timePicker") + datePicker.show(parentFragmentManager, "datePicker") } + ) - datePicker.show(parentFragmentManager, "datePicker") - } - ) + Divider() - Divider() + DropdownMenuItem( + onClick = { + dropDownDismiss() + showPopup = true + }, + text = { Text(stringResource(R.string.remove)) } + ) + } - DropdownMenuItem( - onClick = { - dropDownDismiss() - showPopup = true - }, - text = { Text(stringResource(R.string.remove)) } - ) + IconButton(onClick = { showDropDown = true }) { Icon(Icons.Default.MoreVert, null) } } - - IconButton(onClick = { showDropDown = true }) { Icon(Icons.Default.MoreVert, null) } } } } - } + ) } \ No newline at end of file diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/NavigationUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/NavigationUtils.kt index 64027efeb..5347abb22 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/NavigationUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/NavigationUtils.kt @@ -31,7 +31,7 @@ fun rememberBottomSheetNavigator( val sheetState = rememberModalBottomSheetState( ModalBottomSheetValue.Hidden, animationSpec, - skipHalfExpanded, + skipHalfExpanded = skipHalfExpanded, ) return remember(sheetState) { BottomSheetNavigator(sheetState = sheetState) } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/components/BottomSheetDeleteScaffold.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/components/BottomSheetDeleteScaffold.kt index a5a11bbfa..aa30d400f 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/components/BottomSheetDeleteScaffold.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/components/BottomSheetDeleteScaffold.kt @@ -17,8 +17,11 @@ import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.* import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button +import androidx.compose.material3.DismissDirection +import androidx.compose.material3.DismissValue import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.contentColorFor @@ -232,7 +235,7 @@ private fun DeleteItemView( } val dismissState = rememberDismissState( - confirmStateChange = { + confirmValueChange = { if (it == DismissValue.DismissedToEnd || it == DismissValue.DismissedToStart) { if (customSingleRemoveDialog(item)) { showPopup = true @@ -272,18 +275,18 @@ private fun DeleteItemView( modifier = Modifier.scale(scale) ) } + }, + dismissContent = { + OutlinedCard( + onClick = { if (item in deleteItemList) deleteItemList.remove(item) else deleteItemList.add(item) }, + modifier = Modifier.fillMaxSize(), + border = BorderStroke( + animateDpAsState(targetValue = if (item in deleteItemList) 5.dp else 1.dp).value, + animateColorAsState(if (item in deleteItemList) Color(0xfff44336) else MaterialTheme.colorScheme.outline).value + ) + ) { itemUi(item) } } - ) { - OutlinedCard( - onClick = { if (item in deleteItemList) deleteItemList.remove(item) else deleteItemList.add(item) }, - modifier = Modifier.fillMaxSize(), - border = BorderStroke( - animateDpAsState(targetValue = if (item in deleteItemList) 5.dp else 1.dp).value, - animateColorAsState(if (item in deleteItemList) Color(0xfff44336) else MaterialTheme.colorScheme.outline).value - ) - ) { itemUi(item) } - } - + ) } @ExperimentalMaterial3Api @@ -432,7 +435,6 @@ fun BottomSheetDeleteScaffoldPaging( } @OptIn(ExperimentalMaterial3Api::class) -@ExperimentalMaterialApi @Composable private fun DeleteItemView( item: T, @@ -466,7 +468,7 @@ private fun DeleteItemView( } val dismissState = rememberDismissState( - confirmStateChange = { + confirmValueChange = { if (it == DismissValue.DismissedToEnd || it == DismissValue.DismissedToStart) { if (customSingleRemoveDialog(item)) { showPopup = true @@ -506,18 +508,18 @@ private fun DeleteItemView( modifier = Modifier.scale(scale) ) } + }, + dismissContent = { + Surface( + onClick = { onClick(item) }, + tonalElevation = 5.dp, + modifier = Modifier.fillMaxSize(), + shape = MaterialTheme.shapes.medium, + border = BorderStroke( + animateDpAsState(targetValue = if (selectedForDeletion) 5.dp else 1.dp).value, + animateColorAsState(if (selectedForDeletion) Color(0xfff44336) else Color.Transparent).value + ) + ) { itemUi(item) } } - ) { - Surface( - onClick = { onClick(item) }, - tonalElevation = 5.dp, - modifier = Modifier.fillMaxSize(), - shape = MaterialTheme.shapes.medium, - border = BorderStroke( - animateDpAsState(targetValue = if (selectedForDeletion) 5.dp else 1.dp).value, - animateColorAsState(if (selectedForDeletion) Color(0xfff44336) else Color.Transparent).value - ) - ) { itemUi(item) } - } - + ) } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2f3a7f38a..86ea52fb8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,14 +11,14 @@ koinVersion = "3.3.0" lottieVersion = "5.2.0" coil = "2.2.2" lifecycle = "2.5.1" -jetpack = "1.4.0-alpha03" +jetpack = "1.4.0-alpha04" jetpackCompiler = "1.3.2" accompanist = "0.28.0" okhttpVersion = "4.10.0" -ktorVersion = "2.2.1" +ktorVersion = "2.2.2" workVersion = "2.7.1" ziplineVersion = "0.9.12" -landscapist = "2.1.0" +landscapist = "2.1.1" protobufVersion = "3.21.1" ### MangaWorld @@ -44,7 +44,7 @@ composeUi = { module = "androidx.compose.ui:ui", version.ref = "jetpack" } composeUiTooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "jetpack" } composeFoundation = { module = "androidx.compose.foundation:foundation", version.ref = "jetpack" } composeMaterial = { module = "androidx.compose.material:material", version.ref = "jetpack" } -materialYou = "androidx.compose.material3:material3:1.1.0-alpha03" +materialYou = "androidx.compose.material3:material3:1.1.0-alpha04" composeMaterialIconsCore = { module = "androidx.compose.material:material-icons-core", version.ref = "jetpack" } composeMaterialIconsExtended = { module = "androidx.compose.material:material-icons-extended", version.ref = "jetpack" } composeActivity = "androidx.activity:activity-compose:1.6.1" diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/downloads/DownloadViewerFragment.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/downloads/DownloadViewerFragment.kt index f377cac2a..701bddf47 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/downloads/DownloadViewerFragment.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/downloads/DownloadViewerFragment.kt @@ -13,18 +13,12 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.Delete import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.* -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -64,7 +58,6 @@ import androidx.compose.material3.MaterialTheme as M3MaterialTheme ExperimentalPermissionsApi::class, ExperimentalFoundationApi::class, ExperimentalAnimationApi::class, - ExperimentalMaterialApi::class ) @Composable fun DownloadScreen() { @@ -101,7 +94,6 @@ fun DownloadScreen() { @ExperimentalMaterial3Api @ExperimentalFoundationApi @ExperimentalAnimationApi -@ExperimentalMaterialApi @Composable private fun DownloadViewer(viewModel: DownloadViewModel, p1: PaddingValues) { val fileList = viewModel.fileList @@ -134,7 +126,7 @@ private fun EmptyState(p1: PaddingValues) { .fillMaxSize() ) { Surface( - shape = MaterialTheme.shapes.medium, + shape = M3MaterialTheme.shapes.medium, tonalElevation = 4.dp, modifier = Modifier .fillMaxWidth() @@ -169,7 +161,6 @@ private fun EmptyState(p1: PaddingValues) { } @OptIn(ExperimentalMaterial3Api::class) -@ExperimentalMaterialApi @Composable private fun ChapterItem(file: Map.Entry>>) { val context = LocalContext.current @@ -181,7 +172,7 @@ private fun ChapterItem(file: Map.Entry File(f) }) - }, - SettingsDsl.customAnimationOptions - )*/ - } else { - context.startActivity( - Intent(context, ReadActivity::class.java).apply { - putExtra("downloaded", true) - putExtra("filePath", c?.chapterFolder?.let { f -> File(f) }) - } - ) + }, + dismissContent = { + val navController = LocalNavController.current + Surface( + shape = M3MaterialTheme.shapes.medium, + tonalElevation = 4.dp, + modifier = Modifier + .fillMaxWidth() + .clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() } + ) { + if (runBlocking { context.useNewReaderFlow.first() }) { + ReadViewModel.navigateToMangaReader( + navController, + filePath = c?.chapterFolder, + downloaded = true + ) + /*findNavController() + .navigate( + ReadActivityComposeFragment::class.java.hashCode(), + Bundle().apply { + putBoolean("downloaded", true) + putSerializable("filePath", c?.chapterFolder?.let { f -> File(f) }) + }, + SettingsDsl.customAnimationOptions + )*/ + } else { + context.startActivity( + Intent(context, ReadActivity::class.java).apply { + putExtra("downloaded", true) + putExtra("filePath", c?.chapterFolder?.let { f -> File(f) }) + } + ) + } } - } - ) { - ListItem( - modifier = Modifier.padding(5.dp), - headlineText = { Text(c?.chapterName.orEmpty()) }, - supportingText = { Text(stringResource(R.string.page_count, chapter.size)) }, - trailingContent = { Icon(Icons.Default.ChevronRight, null) } - ) + ) { + ListItem( + modifier = Modifier.padding(5.dp), + headlineText = { Text(c?.chapterName.orEmpty()) }, + supportingText = { Text(stringResource(R.string.page_count, chapter.size)) }, + trailingContent = { Icon(Icons.Default.ChevronRight, null) } + ) + } } - } + ) } } } diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt index 4634b6477..4a3d6fc8c 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt @@ -32,6 +32,8 @@ import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.DismissDirection +import androidx.compose.material3.DismissValue import androidx.compose.material3.DrawerValue import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -657,7 +659,7 @@ private fun LastPageReached( } } -@OptIn(ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @Composable fun ChangeChapterSwipe( nextChapter: () -> Unit, @@ -672,7 +674,7 @@ fun ChangeChapterSwipe( .wrapContentHeight() ) { val dismissState = rememberDismissState( - confirmStateChange = { + confirmValueChange = { when (it) { DismissValue.DismissedToEnd -> nextChapter() DismissValue.DismissedToStart -> previousChapter() @@ -718,14 +720,15 @@ fun ChangeChapterSwipe( tint = MaterialTheme.colorScheme.onSurface.copy(alpha = LocalContentAlpha.current) ) } + }, + dismissContent = { + OutlinedCard( + modifier = Modifier + .fillMaxWidth() + .height(this@BoxWithConstraints.maxHeight / 2) + ) { content() } } - ) { - OutlinedCard( - modifier = Modifier - .fillMaxWidth() - .height(this@BoxWithConstraints.maxHeight / 2) - ) { content() } - } + ) } } @@ -813,6 +816,7 @@ private fun ZoomableImage( scale > 2f -> { scale = 1f } + else -> { scale = 3f From 0e0c495db9392f652cdfce09617060d2517f5502 Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 09:29:27 -0500 Subject: [PATCH 02/69] Bringing global search up to view --- .../uiviews/settings/SettingsFragment.kt | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/settings/SettingsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/settings/SettingsFragment.kt index 197e6c86e..9bfb81bfd 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/settings/SettingsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/settings/SettingsFragment.kt @@ -151,7 +151,8 @@ fun SettingScreen( customSettings = customPreferences.viewSettings, debugMenuClick = debugMenuClick, favoritesClick = favoritesClick, - historyClick = historyClick + historyClick = historyClick, + globalSearchClick = globalSearchClick ) Divider() @@ -161,7 +162,6 @@ fun SettingScreen( context = context, scope = scope, customSettings = customPreferences.generalSettings, - globalSearchClick = globalSearchClick ) Divider() @@ -433,7 +433,8 @@ private fun ViewSettings( customSettings: (@Composable () -> Unit)?, debugMenuClick: () -> Unit, favoritesClick: () -> Unit, - historyClick: () -> Unit + historyClick: () -> Unit, + globalSearchClick: () -> Unit ) { CategorySetting { Text(stringResource(R.string.view_menu_category_title)) } @@ -459,6 +460,16 @@ private fun ViewSettings( ) ) + PreferenceSetting( + settingTitle = { Text(stringResource(R.string.global_search)) }, + settingIcon = { Icon(Icons.Default.Search, null, modifier = Modifier.fillMaxSize()) }, + modifier = Modifier.clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() }, + onClick = globalSearchClick + ) + ) + val context = LocalContext.current val dao = remember { HistoryDatabase.getInstance(context).historyDao() } val historyCount by dao.getAllRecentHistoryCount().collectAsState(initial = 0) @@ -484,7 +495,6 @@ private fun GeneralSettings( context: Context, scope: CoroutineScope, customSettings: (@Composable () -> Unit)?, - globalSearchClick: () -> Unit ) { CategorySetting { Text(stringResource(R.string.general_menu_title)) } @@ -528,16 +538,6 @@ private fun GeneralSettings( ) ) - PreferenceSetting( - settingTitle = { Text(stringResource(R.string.global_search)) }, - settingIcon = { Icon(Icons.Default.Search, null, modifier = Modifier.fillMaxSize()) }, - modifier = Modifier.clickable( - indication = rememberRipple(), - interactionSource = remember { MutableInteractionSource() }, - onClick = globalSearchClick - ) - ) - val handling = LocalSettingsHandling.current val themeSetting by handling.systemThemeMode.collectAsState(initial = SystemThemeMode.FollowSystem) From 66d1327ee0c3b1def05ecf58545aa2718c2b9451 Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 09:48:10 -0500 Subject: [PATCH 03/69] Fixing issues --- .../downloads/DownloadViewerFragment.kt | 234 +++++++++--------- .../animeworld/videos/ViewVideosFragment.kt | 200 +++++++-------- 2 files changed, 221 insertions(+), 213 deletions(-) diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/downloads/DownloadViewerFragment.kt b/animeworld/src/main/java/com/programmersbox/animeworld/downloads/DownloadViewerFragment.kt index a67709066..dc1a1075f 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/downloads/DownloadViewerFragment.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/downloads/DownloadViewerFragment.kt @@ -14,6 +14,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.* import androidx.compose.material3.Button +import androidx.compose.material3.DismissDirection +import androidx.compose.material3.DismissValue import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedButton @@ -186,6 +188,7 @@ private fun EmptyState(paddingValues: PaddingValues) { } } +@OptIn(ExperimentalMaterial3Api::class) @ExperimentalAnimationApi @ExperimentalMaterialApi @Composable @@ -195,7 +198,7 @@ private fun DownloadItem(download: DownloadData, actionListener: ActionListener) SlideToDeleteDialog(showDialog = showDialog, download = download.download) val dismissState = rememberDismissState( - confirmStateChange = { + confirmValueChange = { if (it == DismissValue.DismissedToEnd || it == DismissValue.DismissedToStart) { showDialog.value = true } @@ -234,137 +237,138 @@ private fun DownloadItem(download: DownloadData, actionListener: ActionListener) tint = M3MaterialTheme.colorScheme.onSurface ) } - } - ) { - Surface( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 5.dp), - tonalElevation = 5.dp, - shape = MaterialTheme.shapes.medium - ) { + }, + dismissContent = { + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 5.dp), + tonalElevation = 5.dp, + shape = MaterialTheme.shapes.medium + ) { - ConstraintLayout { + ConstraintLayout { - val ( - title, progress, - action, progressText, - speed, remaining, - status - ) = createRefs() + val ( + title, progress, + action, progressText, + speed, remaining, + status + ) = createRefs() - Text( - download.download.url.toUri().lastPathSegment.orEmpty(), - fontWeight = FontWeight.Bold, - fontSize = 17.sp, - textAlign = TextAlign.Start, - modifier = Modifier - .constrainAs(title) { - start.linkTo(parent.start) - top.linkTo(parent.top) - } - .padding(horizontal = 8.dp) - .padding(top = 8.dp) - ) + Text( + download.download.url.toUri().lastPathSegment.orEmpty(), + fontWeight = FontWeight.Bold, + fontSize = 17.sp, + textAlign = TextAlign.Start, + modifier = Modifier + .constrainAs(title) { + start.linkTo(parent.start) + top.linkTo(parent.top) + } + .padding(horizontal = 8.dp) + .padding(top = 8.dp) + ) - val prog = download.download.progress.coerceAtLeast(0) + val prog = download.download.progress.coerceAtLeast(0) - androidx.compose.material3.LinearProgressIndicator( - progress = animateFloatAsState(targetValue = prog.toFloat() / 100f).value, - modifier = Modifier - .constrainAs(progress) { - start.linkTo(parent.start) - bottom.linkTo(action.bottom) - end.linkTo(action.start) - top.linkTo(action.top) - } - .padding(8.dp) - ) + androidx.compose.material3.LinearProgressIndicator( + progress = animateFloatAsState(targetValue = prog.toFloat() / 100f).value, + modifier = Modifier + .constrainAs(progress) { + start.linkTo(parent.start) + bottom.linkTo(action.bottom) + end.linkTo(action.start) + top.linkTo(action.top) + } + .padding(8.dp) + ) - OutlinedButton( - onClick = { - when (download.download.status) { - Status.FAILED -> actionListener.onRetryDownload(download.download.id) - Status.PAUSED -> actionListener.onResumeDownload(download.download.id) - Status.DOWNLOADING, Status.QUEUED -> actionListener.onPauseDownload(download.download.id) - Status.ADDED -> actionListener.onResumeDownload(download.download.id) - else -> { + OutlinedButton( + onClick = { + when (download.download.status) { + Status.FAILED -> actionListener.onRetryDownload(download.download.id) + Status.PAUSED -> actionListener.onResumeDownload(download.download.id) + Status.DOWNLOADING, Status.QUEUED -> actionListener.onPauseDownload(download.download.id) + Status.ADDED -> actionListener.onResumeDownload(download.download.id) + else -> { + } } - } - }, - modifier = Modifier - .constrainAs(action) { - end.linkTo(parent.end) - top.linkTo(title.bottom) - } - .padding(top = 8.dp, end = 8.dp) - ) { - Text( - stringResource( - id = when (download.download.status) { - Status.COMPLETED -> R.string.view - Status.FAILED -> R.string.retry - Status.PAUSED -> R.string.resume - Status.DOWNLOADING, Status.QUEUED -> R.string.pause - Status.ADDED -> R.string.download - else -> R.string.error_text + }, + modifier = Modifier + .constrainAs(action) { + end.linkTo(parent.end) + top.linkTo(title.bottom) } + .padding(top = 8.dp, end = 8.dp) + ) { + Text( + stringResource( + id = when (download.download.status) { + Status.COMPLETED -> R.string.view + Status.FAILED -> R.string.retry + Status.PAUSED -> R.string.resume + Status.DOWNLOADING, Status.QUEUED -> R.string.pause + Status.ADDED -> R.string.download + else -> R.string.error_text + } + ) ) + } + + Text( + stringResource(R.string.percent_progress, prog), + modifier = Modifier + .constrainAs(progressText) { + top.linkTo(progress.bottom) + start.linkTo(progress.start) + } + .padding(horizontal = 8.dp) ) - } - Text( - stringResource(R.string.percent_progress, prog), - modifier = Modifier - .constrainAs(progressText) { - top.linkTo(progress.bottom) - start.linkTo(progress.start) - } - .padding(horizontal = 8.dp) - ) + Text( + if (download.downloadedBytesPerSecond == 0L) "" else getDownloadSpeedString(download.downloadedBytesPerSecond), + modifier = Modifier + .constrainAs(speed) { + top.linkTo(progress.bottom) + end.linkTo(progress.end) + } + .padding(horizontal = 8.dp) + .padding(bottom = 8.dp) + ) - Text( - if (download.downloadedBytesPerSecond == 0L) "" else getDownloadSpeedString(download.downloadedBytesPerSecond), - modifier = Modifier - .constrainAs(speed) { - top.linkTo(progress.bottom) - end.linkTo(progress.end) - } - .padding(horizontal = 8.dp) - .padding(bottom = 8.dp) - ) + Text( + if (download.eta == -1L) "" else getETAString(download.eta, true), + modifier = Modifier + .constrainAs(remaining) { + bottom.linkTo(parent.bottom) + baseline.linkTo(parent.baseline) + top.linkTo(progressText.bottom) + start.linkTo(parent.start) + } + .padding(8.dp) + ) - Text( - if (download.eta == -1L) "" else getETAString(download.eta, true), - modifier = Modifier - .constrainAs(remaining) { - bottom.linkTo(parent.bottom) - baseline.linkTo(parent.baseline) - top.linkTo(progressText.bottom) - start.linkTo(parent.start) - } - .padding(8.dp) - ) + Text( + stringResource(id = getStatusString(download.download.status)), + fontStyle = FontStyle.Italic, + fontWeight = FontWeight.Bold, + modifier = Modifier + .constrainAs(status) { + bottom.linkTo(parent.bottom) + baseline.linkTo(parent.baseline) + top.linkTo(remaining.top) + start.linkTo(remaining.end) + end.linkTo(parent.end) + } + .padding(8.dp) + ) - Text( - stringResource(id = getStatusString(download.download.status)), - fontStyle = FontStyle.Italic, - fontWeight = FontWeight.Bold, - modifier = Modifier - .constrainAs(status) { - bottom.linkTo(parent.bottom) - baseline.linkTo(parent.baseline) - top.linkTo(remaining.top) - start.linkTo(remaining.end) - end.linkTo(parent.end) - } - .padding(8.dp) - ) + } } - } - } + ) } private fun getStatusString(status: Status): Int = when (status) { diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/videos/ViewVideosFragment.kt b/animeworld/src/main/java/com/programmersbox/animeworld/videos/ViewVideosFragment.kt index 21f056f88..0fbc495c3 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/videos/ViewVideosFragment.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/videos/ViewVideosFragment.kt @@ -24,6 +24,8 @@ import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.* import androidx.compose.material3.Button +import androidx.compose.material3.DismissDirection +import androidx.compose.material3.DismissValue import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Text @@ -310,6 +312,7 @@ private fun EmptyState(paddingValues: PaddingValues) { } +@OptIn(ExperimentalMaterial3Api::class) @ExperimentalAnimationApi @ExperimentalMaterialApi @Composable @@ -322,7 +325,7 @@ private fun VideoContentView(item: VideoContent) { val context = LocalContext.current val dismissState = rememberDismissState( - confirmStateChange = { + confirmValueChange = { if (it == DismissValue.DismissedToEnd) { if (MainActivity.cast.isCastActive()) { MainActivity.cast.loadMedia( @@ -380,118 +383,119 @@ private fun VideoContentView(item: VideoContent) { modifier = Modifier.scale(scale) ) } - } - ) { - ElevatedCard( - modifier = Modifier - .fillMaxSize() - .clickable( - indication = rememberRipple(), - interactionSource = remember { MutableInteractionSource() } - ) { - if (MainActivity.cast.isCastActive()) { - MainActivity.cast.loadMedia( - File(item.path!!), - context - .getSharedPreferences("videos", Context.MODE_PRIVATE) - .getLong(item.assetFileStringUri, 0), - null, null - ) - } else { - context.navigateToVideoPlayer( - navController, - item.assetFileStringUri, - item.videoName, - true, - "" - ) - } - } - ) { - Row { - Box { - /*convert millis to appropriate time*/ - val runTimeString = remember { - val duration = item.videoDuration - if (duration > TimeUnit.HOURS.toMillis(1)) { - String.format( - "%02d:%02d:%02d", - TimeUnit.MILLISECONDS.toHours(duration), - TimeUnit.MILLISECONDS.toMinutes(duration) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration)), - TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)) + }, + dismissContent = { + ElevatedCard( + modifier = Modifier + .fillMaxSize() + .clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() } + ) { + if (MainActivity.cast.isCastActive()) { + MainActivity.cast.loadMedia( + File(item.path!!), + context + .getSharedPreferences("videos", Context.MODE_PRIVATE) + .getLong(item.assetFileStringUri, 0), + null, null ) } else { - String.format( - "%02d:%02d", - TimeUnit.MILLISECONDS.toMinutes(duration), - TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)) + context.navigateToVideoPlayer( + navController, + item.assetFileStringUri, + item.videoName, + true, + "" ) } } + ) { + Row { + Box { + /*convert millis to appropriate time*/ + val runTimeString = remember { + val duration = item.videoDuration + if (duration > TimeUnit.HOURS.toMillis(1)) { + String.format( + "%02d:%02d:%02d", + TimeUnit.MILLISECONDS.toHours(duration), + TimeUnit.MILLISECONDS.toMinutes(duration) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration)), + TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)) + ) + } else { + String.format( + "%02d:%02d", + TimeUnit.MILLISECONDS.toMinutes(duration), + TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)) + ) + } + } - GlideImage( - imageModel = { item.assetFileStringUri.orEmpty() }, - imageOptions = ImageOptions(contentScale = ContentScale.Crop), - requestBuilder = { - Glide.with(LocalView.current) - .asDrawable() - .thumbnail(0.5f) - }, - modifier = Modifier - .align(Alignment.Center) - .size(ComposableUtils.IMAGE_HEIGHT, ComposableUtils.IMAGE_WIDTH), - failure = { Text(text = "image request failed.") } - ) + GlideImage( + imageModel = { item.assetFileStringUri.orEmpty() }, + imageOptions = ImageOptions(contentScale = ContentScale.Crop), + requestBuilder = { + Glide.with(LocalView.current) + .asDrawable() + .thumbnail(0.5f) + }, + modifier = Modifier + .align(Alignment.Center) + .size(ComposableUtils.IMAGE_HEIGHT, ComposableUtils.IMAGE_WIDTH), + failure = { Text(text = "image request failed.") } + ) - Text( - runTimeString, - color = Color.White, - modifier = Modifier - .align(Alignment.BottomEnd) - .background(Color(0x99000000)) - .border(BorderStroke(1.dp, Color(0x00000000)), shape = RoundedCornerShape(bottomEnd = 5.dp)) - ) + Text( + runTimeString, + color = Color.White, + modifier = Modifier + .align(Alignment.BottomEnd) + .background(Color(0x99000000)) + .border(BorderStroke(1.dp, Color(0x00000000)), shape = RoundedCornerShape(bottomEnd = 5.dp)) + ) - } + } - Column( - modifier = Modifier - .weight(1f) - .padding(start = 16.dp, top = 4.dp) - ) { - val shared = context.getSharedPreferences("videos", Context.MODE_PRIVATE) - if (shared.contains(item.assetFileStringUri)) - Text(shared.getLong(item.assetFileStringUri, 0).stringForTime(), style = M3MaterialTheme.typography.labelMedium) - Text(item.videoName.orEmpty(), style = M3MaterialTheme.typography.titleSmall) - Text(item.path.orEmpty(), style = M3MaterialTheme.typography.bodyMedium, fontSize = 10.sp) - } + Column( + modifier = Modifier + .weight(1f) + .padding(start = 16.dp, top = 4.dp) + ) { + val shared = context.getSharedPreferences("videos", Context.MODE_PRIVATE) + if (shared.contains(item.assetFileStringUri)) + Text(shared.getLong(item.assetFileStringUri, 0).stringForTime(), style = M3MaterialTheme.typography.labelMedium) + Text(item.videoName.orEmpty(), style = M3MaterialTheme.typography.titleSmall) + Text(item.path.orEmpty(), style = M3MaterialTheme.typography.bodyMedium, fontSize = 10.sp) + } - Box( - modifier = Modifier - .align(Alignment.Top) - .padding(horizontal = 2.dp) - ) { + Box( + modifier = Modifier + .align(Alignment.Top) + .padding(horizontal = 2.dp) + ) { - var showDropDown by remember { mutableStateOf(false) } + var showDropDown by remember { mutableStateOf(false) } - val dropDownDismiss = { showDropDown = false } + val dropDownDismiss = { showDropDown = false } - androidx.compose.material3.DropdownMenu( - expanded = showDropDown, - onDismissRequest = dropDownDismiss - ) { - androidx.compose.material3.DropdownMenuItem( - onClick = { - dropDownDismiss() - showDialog.value = true - }, - text = { Text(stringResource(R.string.remove)) } - ) - } + androidx.compose.material3.DropdownMenu( + expanded = showDropDown, + onDismissRequest = dropDownDismiss + ) { + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + showDialog.value = true + }, + text = { Text(stringResource(R.string.remove)) } + ) + } - IconButton(onClick = { showDropDown = true }) { Icon(Icons.Default.MoreVert, null) } + IconButton(onClick = { showDropDown = true }) { Icon(Icons.Default.MoreVert, null) } + } } } } - } + ) } \ No newline at end of file From aea4b2a56ee018d751ed122aff611254e49cda88 Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 10:19:13 -0500 Subject: [PATCH 04/69] Small change --- .../uiviews/globalsearch/GlobalSearchFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt index 205985e5a..dc8c93b48 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt @@ -167,7 +167,7 @@ fun GlobalSearchView( modifier = Modifier.padding(16.dp).fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(4.dp) ) { - history.forEachIndexed { index, historyModel -> + history.take(5).forEachIndexed { index, historyModel -> ListItem( headlineText = { Text(historyModel.searchText) }, leadingContent = { Icon(Icons.Filled.Search, contentDescription = null) }, @@ -264,7 +264,7 @@ fun GlobalSearchView( contentPadding = padding, verticalArrangement = Arrangement.spacedBy(2.dp), horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.padding(top = 4.dp) + modifier = Modifier.padding(top = 8.dp) ) { if (viewModel.isRefreshing) { items(3) { From 905fe2900a1578319fd651f4fdae751a150170c2 Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 10:48:32 -0500 Subject: [PATCH 05/69] Making GlobalSearchFragment.kt have lazycolumn --- .../uiviews/globalsearch/GlobalSearchFragment.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt index dc8c93b48..d4beb0af2 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/globalsearch/GlobalSearchFragment.kt @@ -9,12 +9,9 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.* import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.BottomSheetScaffold import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons @@ -163,11 +160,11 @@ fun GlobalSearchView( } }, ) { - Column( + LazyColumn( modifier = Modifier.padding(16.dp).fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(4.dp) ) { - history.take(5).forEachIndexed { index, historyModel -> + itemsIndexed(history) { index, historyModel -> ListItem( headlineText = { Text(historyModel.searchText) }, leadingContent = { Icon(Icons.Filled.Search, contentDescription = null) }, From 809dc1cea0927da108f1cd97903196828bba81ec Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 13:57:40 -0500 Subject: [PATCH 06/69] Lib update --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 86ea52fb8..2d3f5afab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ coil = "2.2.2" lifecycle = "2.5.1" jetpack = "1.4.0-alpha04" jetpackCompiler = "1.3.2" -accompanist = "0.28.0" +accompanist = "0.29.0-alpha" okhttpVersion = "4.10.0" ktorVersion = "2.2.2" workVersion = "2.7.1" From 2044679d2b6f25908628953dc7c815d3153511ea Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 15:37:08 -0500 Subject: [PATCH 07/69] Removed the xml DatePicker in exchange for the compose one --- .../notifications/NotificationFragment.kt | 127 ++++++++++-------- 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt index 65d66d1e6..26efc1473 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt @@ -38,9 +38,7 @@ import androidx.work.WorkManager import coil.compose.AsyncImage import coil.request.ImageRequest import com.google.accompanist.drawablepainter.rememberDrawablePainter -import com.google.android.material.datepicker.CalendarConstraints import com.google.android.material.datepicker.DateValidatorPointForward -import com.google.android.material.datepicker.MaterialDatePicker import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.TimeFormat import com.programmersbox.favoritesdatabase.ItemDao @@ -409,6 +407,73 @@ private fun NotificationItem( val dropDownDismiss = { showDropDown = false } + var showDatePicker by remember { mutableStateOf(false) } + + if (showDatePicker) { + val state = rememberDatePickerState( + initialSelectedDateMillis = System.currentTimeMillis() + ) + AlertDialog( + text = { + DatePicker( + datePickerState = state, + dateValidator = { DateValidatorPointForward.now().isValid(it) }, + title = { Text(stringResource(R.string.selectDate)) } + ) + }, + confirmButton = { + TextButton( + onClick = { + showDatePicker = false + val c = Calendar.getInstance() + val timePicker = MaterialTimePicker.Builder() + .setTitleText(R.string.selectTime) + .setPositiveButtonText(R.string.ok) + .setTimeFormat( + if (DateFormat.is24HourFormat(context)) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H + ) + .setHour(c[Calendar.HOUR_OF_DAY]) + .setMinute(c[Calendar.MINUTE]) + .build() + + timePicker.addOnPositiveButtonClickListener { _ -> + c.timeInMillis = state.selectedDateMillis ?: 0L + c[Calendar.HOUR_OF_DAY] = timePicker.hour + c[Calendar.MINUTE] = timePicker.minute + + WorkManager.getInstance(context) + .enqueueUniqueWork( + item.notiTitle, + ExistingWorkPolicy.REPLACE, + OneTimeWorkRequestBuilder() + .setInputData( + Data.Builder() + .putString("notiData", item.toJson()) + .build() + ) + .setInitialDelay(c.timeInMillis - System.currentTimeMillis(), TimeUnit.MILLISECONDS) + .build() + ) + + Toast.makeText( + context, + context.getString( + R.string.willNotifyAt, + context.getSystemDateTimeFormat().format(c.timeInMillis) + ), + Toast.LENGTH_SHORT + ).show() + } + + timePicker.show(parentFragmentManager, "timePicker") + } + ) { Text(stringResource(R.string.ok)) } + }, + dismissButton = { TextButton(onClick = { showDatePicker = false }) { Text(stringResource(R.string.cancel)) } }, + onDismissRequest = {} + ) + } + DropdownMenu( expanded = showDropDown, onDismissRequest = dropDownDismiss @@ -429,63 +494,7 @@ private fun NotificationItem( text = { Text(stringResource(R.string.notifyAtTime)) }, onClick = { dropDownDismiss() - val datePicker = MaterialDatePicker.Builder.datePicker() - .setTitleText(R.string.selectDate) - .setCalendarConstraints( - CalendarConstraints.Builder() - .setOpenAt(System.currentTimeMillis()) - .setValidator(DateValidatorPointForward.now()) - .build() - ) - .setSelection(System.currentTimeMillis()) - .build() - - datePicker.addOnPositiveButtonClickListener { - val c = Calendar.getInstance() - val timePicker = MaterialTimePicker.Builder() - .setTitleText(R.string.selectTime) - .setPositiveButtonText(R.string.ok) - .setTimeFormat( - if (DateFormat.is24HourFormat(context)) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H - ) - .setHour(c[Calendar.HOUR_OF_DAY]) - .setMinute(c[Calendar.MINUTE]) - .build() - - timePicker.addOnPositiveButtonClickListener { _ -> - c.timeInMillis = it - c.add(Calendar.DAY_OF_YEAR, 1) - c[Calendar.HOUR_OF_DAY] = timePicker.hour - c[Calendar.MINUTE] = timePicker.minute - - WorkManager.getInstance(context) - .enqueueUniqueWork( - item.notiTitle, - ExistingWorkPolicy.REPLACE, - OneTimeWorkRequestBuilder() - .setInputData( - Data.Builder() - .putString("notiData", item.toJson()) - .build() - ) - .setInitialDelay(c.timeInMillis - System.currentTimeMillis(), TimeUnit.MILLISECONDS) - .build() - ) - - Toast.makeText( - context, - context.getString( - R.string.willNotifyAt, - context.getSystemDateTimeFormat().format(c.timeInMillis) - ), - Toast.LENGTH_SHORT - ).show() - } - - timePicker.show(parentFragmentManager, "timePicker") - } - - datePicker.show(parentFragmentManager, "datePicker") + showDatePicker = true } ) From 0563cea2dc66f9e2109b794fc09889d89ef932e6 Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Thu, 12 Jan 2023 15:51:45 -0500 Subject: [PATCH 08/69] Using Marquee! --- .../uiviews/details/DetailsFragment.kt | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/details/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/details/DetailsFragment.kt index d8d08cab8..59c570b32 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/details/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/details/DetailsFragment.kt @@ -19,6 +19,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.* +import androidx.compose.material3.TopAppBarDefaults.topAppBarColors import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -100,7 +101,12 @@ fun DetailsScreen( topBar = { InsetSmallTopAppBar( modifier = Modifier.zIndex(2f), - title = { Text(details.itemModel?.title.orEmpty()) }, + title = { + Text( + details.itemModel?.title.orEmpty(), + maxLines = 1 + ) + }, navigationIcon = { BackButton() }, actions = { IconButton( @@ -579,18 +585,24 @@ private fun DetailsView( topBar = { InsetSmallTopAppBar( modifier = Modifier.zIndex(2f), - colors = TopAppBarDefaults.smallTopAppBarColors( - titleContentColor = topBarColor, - containerColor = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value ?: M3MaterialTheme.colorScheme.surface, + colors = topAppBarColors( + containerColor = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value + ?: M3MaterialTheme.colorScheme.surface, scrolledContainerColor = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value?.let { M3MaterialTheme.colorScheme.surface.surfaceColorAtElevation(1.dp, it) } ?: M3MaterialTheme.colorScheme.applyTonalElevation( backgroundColor = M3MaterialTheme.colorScheme.surface, elevation = 1.dp - ) + ), + titleContentColor = topBarColor ), scrollBehavior = scrollBehavior, - title = { Text(info.title) }, + title = { + Text( + info.title, + modifier = Modifier.basicMarquee() + ) + }, navigationIcon = { IconButton(onClick = { navController.popBackStack() }) { Icon(Icons.Default.ArrowBack, null, tint = topBarColor) From 5947483bbefdd804a0e229baa2ab6fc95fd118d7 Mon Sep 17 00:00:00 2001 From: Jacob Rein Date: Wed, 18 Jan 2023 06:13:45 -0500 Subject: [PATCH 09/69] Updating libs --- .idea/inspectionProfiles/Project_Default.xml | 16 ++++++++++++++++ gradle/libs.versions.toml | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index d235beba4..44ca2d9b0 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -5,10 +5,18 @@