From e8b6f9fca5fde0c88c01b57375933f2523e82152 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 18 Jan 2022 08:20:36 -0500 Subject: [PATCH 001/166] - version update --- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 206347043..c181adccd 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -1,5 +1,5 @@ object Deps { - const val otakuVersionName = "29.2.6" + const val otakuVersionName = "29.2.7" const val compileVersion = 31 const val minimumSdk = 23 const val targetSdk = 31 From c7ca609244712a9e603a4080b96f305aa6150b0b Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 18 Jan 2022 11:19:26 -0500 Subject: [PATCH 002/166] - fixed changing ability to check, not taking affect correctly. --- .../com/programmersbox/uiviews/OtakuApp.kt | 26 +++++++++++++++++++ .../uiviews/SettingsFragment.kt | 6 +++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt index 2f68db0dc..ea2a48358 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt @@ -134,6 +134,32 @@ abstract class OtakuApp : Application() { work.pruneWork() } } + + fun updateSetupNow(context: Context, check: Boolean) { + val work = WorkManager.getInstance(context) + //work.cancelAllWork() + //if (context.shouldCheck) { + if (check) { + work.enqueueUniquePeriodicWork( + "updateChecks", + ExistingPeriodicWorkPolicy.KEEP, + PeriodicWorkRequestBuilder( + 1, TimeUnit.HOURS, + 5, TimeUnit.MINUTES + ) + .setConstraints( + Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + ) + .setInitialDelay(10, TimeUnit.SECONDS) + .build() + ).state.observeForever { println(it) } + } else { + work.cancelUniqueWork("updateChecks") + work.pruneWork() + } + } } } \ No newline at end of file diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt index fd0ff7743..0670894d4 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt @@ -515,8 +515,10 @@ private fun AboutSettings( settingTitle = { Text(stringResource(R.string.check_for_periodic_updates)) }, value = aboutViewModel.canCheck, updateValue = { - scope.launch { context.updatePref(SHOULD_CHECK, it) } - OtakuApp.updateSetup(context) + scope.launch { + context.updatePref(SHOULD_CHECK, it) + OtakuApp.updateSetupNow(context, it) + } } ) From 2e83cac4b8a2d70239f6e1081e2b642e679675e1 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 18 Jan 2022 11:20:09 -0500 Subject: [PATCH 003/166] - cleanup --- .../com/programmersbox/uiviews/OtakuApp.kt | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt index ea2a48358..77b3dbd9f 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt @@ -110,29 +110,7 @@ abstract class OtakuApp : Application() { companion object { fun updateSetup(context: Context) { - val work = WorkManager.getInstance(context) - //work.cancelAllWork() - //if (context.shouldCheck) { - if (runBlocking { context.shouldCheckFlow.first() }) { - work.enqueueUniquePeriodicWork( - "updateChecks", - ExistingPeriodicWorkPolicy.KEEP, - PeriodicWorkRequestBuilder( - 1, TimeUnit.HOURS, - 5, TimeUnit.MINUTES - ) - .setConstraints( - Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build() - ) - .setInitialDelay(10, TimeUnit.SECONDS) - .build() - ).state.observeForever { println(it) } - } else { - work.cancelUniqueWork("updateChecks") - work.pruneWork() - } + updateSetupNow(context, runBlocking { context.shouldCheckFlow.first() }) } fun updateSetupNow(context: Context, check: Boolean) { From 0eceefd94d1e73baff041da5c1c92d48f65c9519 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 19 Jan 2022 06:47:40 -0500 Subject: [PATCH 004/166] - playing around with motionlayout compose --- .../otakuworld/DialogScreens.kt | 118 +++++++++++++++++- 1 file changed, 112 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt index 5e0a452a5..b8cb36584 100644 --- a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt +++ b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt @@ -6,6 +6,8 @@ import android.view.View import android.view.ViewGroup import android.view.WindowManager import androidx.activity.compose.BackHandler +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -35,10 +37,7 @@ import androidx.compose.ui.composed import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.layout.LayoutModifier -import androidx.compose.ui.layout.Measurable -import androidx.compose.ui.layout.MeasureResult -import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.layout.* import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalViewConfiguration @@ -46,6 +45,10 @@ import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import androidx.constraintlayout.compose.ExperimentalMotionApi +import androidx.constraintlayout.compose.MotionLayout +import androidx.constraintlayout.compose.MotionLayoutDebugFlags +import androidx.constraintlayout.compose.MotionScene import com.google.accompanist.insets.ProvideWindowInsets import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager @@ -55,6 +58,7 @@ import kotlinx.coroutines.channels.ticker import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import java.util.* import kotlin.math.roundToInt import kotlin.random.Random import kotlin.random.nextInt @@ -66,7 +70,8 @@ class TestDialogFragment : BaseBottomSheetDialogFragment() { ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class, ExperimentalPagerApi::class, - ExperimentalFoundationApi::class + ExperimentalFoundationApi::class, + ExperimentalMotionApi::class ) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -87,9 +92,10 @@ class TestDialogFragment : BaseBottomSheetDialogFragment() { } enum class SettingLocation { - CHECK, SWITCH, PAGER, OPTIMISTIC + CHECK, SWITCH, PAGER, OPTIMISTIC, MOTIONLAYOUT } +@ExperimentalMotionApi @ExperimentalPagerApi @ExperimentalComposeUiApi @ExperimentalMaterial3Api @@ -133,6 +139,7 @@ fun TestView(closeClick: () -> Unit) { SettingLocation.SWITCH -> SwitchView { scope.launch { state.bottomSheetState.collapse() } } SettingLocation.PAGER -> PagerView { scope.launch { state.bottomSheetState.collapse() } } SettingLocation.OPTIMISTIC -> OptimisticView { scope.launch { state.bottomSheetState.collapse() } } + SettingLocation.MOTIONLAYOUT -> MotionLayoutView { scope.launch { state.bottomSheetState.collapse() } } else -> {} } } @@ -188,6 +195,17 @@ fun TestView(closeClick: () -> Unit) { } ) { Icon(Icons.Default.ChevronRight, null) } } + + item { + PreferenceSetting( + settingTitle = { Text("MotionLayout Settings") }, + settingIcon = { Icon(Icons.Default.MotionPhotosAuto, null) }, + modifier = Modifier.clickable { + location = SettingLocation.MOTIONLAYOUT + scope.launch { state.bottomSheetState.expand() } + } + ) { Icon(Icons.Default.ChevronRight, null) } + } } } } @@ -702,4 +720,92 @@ fun OptimisticView(closeClick: () -> Unit) { } } } +} + +@ExperimentalMaterial3Api +@ExperimentalMotionApi +@Composable +fun MotionLayoutView(closeClick: () -> Unit) { + val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } + + Scaffold( + topBar = { + Column { + CenterAlignedTopAppBar( + title = { Text("MotionLayout Views") }, + actions = { IconButton(onClick = { closeClick() }) { Icon(imageVector = Icons.Default.Close, contentDescription = null) } }, + scrollBehavior = scrollBehavior + ) + Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + } + }, + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) + ) { p -> + var animateToEnd by remember { mutableStateOf(false) } + + val progress by animateFloatAsState( + targetValue = if (animateToEnd) 1f else 0f, + animationSpec = tween(1000) + ) + Column(modifier = Modifier.padding(p)) { + MotionLayout( + modifier = Modifier + .fillMaxWidth() + .height(400.dp) + .background(Color.White), + motionScene = MotionScene( + """{ + ConstraintSets: { // all ConstraintSets + start: { // constraint set id = "start" + a: { // Constraint for widget id='a' + width: 40, + height: 40, + start: ['parent', 'start', 16], + bottom: ['parent', 'bottom', 16] + } + }, + end: { // constraint set id = "start" + a: { + width: 40, + height: 40, + //rotationZ: 390, + end: ['parent', 'end', 16], + top: ['parent', 'top', 16] + } + } + }, + Transitions: { // All Transitions in here + default: { // transition named 'default' + from: 'start', // go from Transition "start" + to: 'end', // go to Transition "end" + pathMotionArc: 'startHorizontal', // move in arc + KeyFrames: { // All keyframes go here + KeyAttributes: [ // keyAttributes key frames go here + { + target: ['a'], // This keyAttributes group target id "a" + frames: [25,50,75], // 3 points on progress 25% , 50% and 75% + rotationX: [0, 45, 60], // the rotationX angles are a spline from 0,0,45,60,0 + rotationY: [60, 45, 0] // the rotationX angles are a spline from 0,60,45,0,0 + } + ] + } + } + } + }""" + ), + debug = EnumSet.of(MotionLayoutDebugFlags.SHOW_ALL), + progress = progress + ) { + Box( + modifier = Modifier + .layoutId("a") + .background(Color.Red) + ) + } + + androidx.compose.material3.Button(onClick = { animateToEnd = !animateToEnd }) { + androidx.compose.material3.Text(text = "Run") + } + } + } } \ No newline at end of file From 91a9dea7cc80ace7ae4c5c877d7ae4731079592b Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 19 Jan 2022 07:03:47 -0500 Subject: [PATCH 005/166] - lib update --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 64420e1a3..9fa92cd04 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { ext.androidCore = 'androidx.core:core-ktx:1.7.0' ext.appCompat = 'androidx.appcompat:appcompat:1.4.1' - ext.material = 'com.google.android.material:material:1.6.0-alpha01' + ext.material = 'com.google.android.material:material:1.6.0-alpha02' ext.preference = "androidx.preference:preference-ktx:1.1.1" From 59fabafcebfd1ed747f9fe1a2f06144b92d55ee1 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 19 Jan 2022 10:24:17 -0500 Subject: [PATCH 006/166] - converted HistoryFragment.kt to use Paging 3. It seems and feels a bit smoother and better - also added a history save count to limit how much history should be saved --- UIViews/build.gradle | 5 + .../programmersbox/uiviews/DetailsFragment.kt | 5 +- .../programmersbox/uiviews/HistoryFragment.kt | 127 +++++++++--------- .../uiviews/SettingsFragment.kt | 14 ++ .../uiviews/utils/ComposableUtils.kt | 4 +- .../uiviews/utils/ContextUtils.kt | 3 + UIViews/src/main/res/values/strings.xml | 2 + build.gradle | 2 + favoritesdatabase/build.gradle | 11 +- .../favoritesdatabase/HistoryDatabase.kt | 8 +- 10 files changed, 104 insertions(+), 77 deletions(-) diff --git a/UIViews/build.gradle b/UIViews/build.gradle index 7b5f98847..4a87ce4fd 100644 --- a/UIViews/build.gradle +++ b/UIViews/build.gradle @@ -136,6 +136,11 @@ dependencies { implementation "com.google.accompanist:accompanist-systemuicontroller:$accompanist" implementation "me.onebone:toolbar-compose:2.3.0" implementation 'com.github.nanihadesuka:LazyColumnScrollbar:1.0.3' + implementation "androidx.paging:paging-compose:1.0.0-alpha14" + + implementation "androidx.paging:paging-runtime-ktx:$paging_version" + // alternatively - without Android dependencies for tests + testImplementation "androidx.paging:paging-common-ktx:$paging_version" implementation datastore.datastore } \ No newline at end of file diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index a667af2bf..154e344d9 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -94,7 +94,9 @@ import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import me.onebone.toolbar.CollapsingToolbarScaffold import me.onebone.toolbar.ScrollStrategy import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState @@ -1046,7 +1048,8 @@ class DetailsFragment : Fragment() { timestamp = System.currentTimeMillis() ) ) - historyDao.removeOldData() + val save = runBlocking { context.historySave.first() } + if (save != -1) historyDao.removeOldData(save) } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt index d9d9bc348..b3144e40e 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt @@ -7,10 +7,10 @@ import android.view.ViewGroup import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.exponentialDecay -import androidx.compose.animation.core.tween import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons @@ -26,9 +26,9 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.ComposeView @@ -36,7 +36,6 @@ import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.util.fastMap import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.fragment.app.Fragment @@ -44,7 +43,12 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.lifecycleScope import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.fragment.findNavController +import androidx.paging.* +import androidx.paging.compose.collectAsLazyPagingItems +import androidx.paging.compose.items import coil.compose.rememberImagePainter +import com.google.accompanist.placeholder.material.placeholder +import com.programmersbox.favoritesdatabase.HistoryDao import com.programmersbox.favoritesdatabase.HistoryDatabase import com.programmersbox.favoritesdatabase.RecentModel import com.programmersbox.sharedutils.MainLogo @@ -83,21 +87,21 @@ class HistoryFragment : Fragment() { setContent { M3MaterialTheme(currentColorScheme) { RecentlyViewedUi() } } } - class HistoryViewModel : ViewModel() { - var sortedChoice by mutableStateOf>(SortRecentlyBy.TIMESTAMP) - var reverse by mutableStateOf(false) - - fun sortChange(item: SortRecentlyBy<*>) { - if (sortedChoice != item) sortedChoice = item else reverse = !reverse - } + class HistoryViewModel(private val dao: HistoryDao) : ViewModel() { + val historyItems = Pager( + config = PagingConfig( + pageSize = 10, + enablePlaceholders = true + ) + ) { dao.getRecentlyViewedPaging() } } @ExperimentalMaterial3Api @ExperimentalMaterialApi @Composable - private fun RecentlyViewedUi(hm: HistoryViewModel = viewModel()) { + private fun RecentlyViewedUi(hm: HistoryViewModel = viewModel(factory = factoryCreate { HistoryViewModel(dao) })) { - val recentItems by dao.getRecentlyViewed().collectAsState(initial = emptyList()) + val recentItems = hm.historyItems.flow.collectAsLazyPagingItems() val scope = rememberCoroutineScope() var clearAllDialog by remember { mutableStateOf(false) } @@ -134,68 +138,23 @@ class HistoryFragment : Fragment() { }, title = { Text(stringResource(R.string.history)) }, actions = { - IconButton(onClick = { clearAllDialog = true }) { Icon(Icons.Default.DeleteForever, null) } - - val rotateIcon: @Composable (SortRecentlyBy<*>) -> Float = { - animateFloatAsState( - if (it == hm.sortedChoice && hm.reverse) 180f else 0f, - animationSpec = tween(500) - ).value - } - - GroupButton( - selected = hm.sortedChoice, - options = listOf( - GroupButtonModel(SortRecentlyBy.TITLE) { - Icon( - Icons.Default.SortByAlpha, - null, - modifier = Modifier.rotate(rotateIcon(SortRecentlyBy.TITLE)) - ) - }, - GroupButtonModel(SortRecentlyBy.TIMESTAMP) { - Icon( - Icons.Default.CalendarToday, - null, - modifier = Modifier.rotate(rotateIcon(SortRecentlyBy.TIMESTAMP)) - ) - } - ), - onClick = hm::sortChange - ) } ) } ) { p -> - AnimatedLazyColumn( - contentPadding = p, - verticalArrangement = Arrangement.spacedBy(4.dp), - items = recentItems - .let { - when (val s = hm.sortedChoice) { - is SortRecentlyBy.TITLE -> it.sortedBy(s.sort) - is SortRecentlyBy.TIMESTAMP -> it.sortedByDescending(s.sort) - } - } - .let { if (hm.reverse) it.reversed() else it } - .fastMap { AnimatedLazyListItem(it.url, it) { HistoryItem(it, scope) } } - ) - /*LazyColumn( + LazyColumn( contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp) ) { - items( - recentItems - .let { - when (val s = hm.sortedChoice) { - is SortRecentlyBy.TITLE -> it.sortedBy(s.sort) - is SortRecentlyBy.TIMESTAMP -> it.sortedByDescending(s.sort) - } - } - .let { if (hm.reverse) it.reversed() else it } - ) { HistoryItem(it, scope) } - }*/ + items(recentItems) { item -> + if (item != null) { + HistoryItem(item, scope) + } else { + HistoryItemPlaceholder() + } + } + } } } @@ -356,6 +315,42 @@ class HistoryFragment : Fragment() { } } + @ExperimentalMaterialApi + @Composable + private fun HistoryItemPlaceholder() { + val placeholderColor = androidx.compose.material3.contentColorFor(backgroundColor = M3MaterialTheme.colorScheme.surface) + .copy(0.1f) + .compositeOver(M3MaterialTheme.colorScheme.surface) + + Surface( + tonalElevation = 5.dp, + shape = MaterialTheme.shapes.medium, + modifier = Modifier.placeholder(true, color = placeholderColor) + ) { + ListItem( + modifier = Modifier.placeholder(true, color = placeholderColor), + text = { Text("Otaku") }, + overlineText = { Text("Otaku") }, + secondaryText = { Text("Otaku") }, + icon = { + Surface(shape = MaterialTheme.shapes.medium) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = null, + modifier = Modifier.size(ComposableUtils.IMAGE_WIDTH, ComposableUtils.IMAGE_HEIGHT) + ) + } + }, + trailing = { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon(imageVector = Icons.Default.Delete, contentDescription = null) + Icon(imageVector = Icons.Default.PlayArrow, contentDescription = null) + } + } + ) + } + } + sealed class SortRecentlyBy(val sort: (RecentModel) -> K) { object TIMESTAMP : SortRecentlyBy(RecentModel::timestamp) object TITLE : SortRecentlyBy(RecentModel::title) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt index 0670894d4..83ac46d92 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt @@ -778,6 +778,20 @@ private fun GeneralSettings( updateValue = { scope.launch { context.updatePref(SHOW_ALL, it) } } ) + var sliderValue by remember { mutableStateOf(runBlocking { context.historySave.first().toFloat() }) } + + SliderSetting( + sliderValue = sliderValue, + settingTitle = { Text(stringResource(R.string.history_save_title)) }, + settingSummary = { Text(stringResource(R.string.history_save_summary)) }, + settingIcon = { Icon(Icons.Default.ChangeHistory, null) }, + range = -1f..100f, + updateValue = { + sliderValue = it + scope.launch { context.updatePref(HISTORY_SAVE, sliderValue.toInt()) } + } + ) + customSettings?.invoke() } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index cc6311965..db314747a 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -1054,13 +1054,13 @@ fun BannerBox( showBanner: Boolean = false, bannerEnter: EnterTransition = slideInVertically( animationSpec = tween( - durationMillis = 200, + durationMillis = 150, easing = LinearOutSlowInEasing ) ) { -it }, bannerExit: ExitTransition = slideOutVertically( animationSpec = tween( - durationMillis = 200, + durationMillis = 150, easing = LinearOutSlowInEasing ) ) { -it }, diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ContextUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ContextUtils.kt index 87d9c95d8..6a656c0f5 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ContextUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ContextUtils.kt @@ -95,6 +95,9 @@ val Context.themeSetting get() = dataStore.data.map { it[THEME_SETTING] ?: "Syst val SHOW_ALL = booleanPreferencesKey("show_all") val Context.showAll get() = dataStore.data.map { it[SHOW_ALL] ?: true } +val HISTORY_SAVE = intPreferencesKey("history_save") +val Context.historySave get() = dataStore.data.map { it[HISTORY_SAVE] ?: 50 } + suspend fun Context.updatePref(key: Preferences.Key, value: T) = dataStore.edit { it[key] = value } @JvmInline diff --git a/UIViews/src/main/res/values/strings.xml b/UIViews/src/main/res/values/strings.xml index 0c3dc43b9..61f8717c3 100644 --- a/UIViews/src/main/res/values/strings.xml +++ b/UIViews/src/main/res/values/strings.xml @@ -98,6 +98,8 @@ Finished Downloading Error: Try Again Loading… + History Limit + The number of items to save in history. (Default is 50) System diff --git a/build.gradle b/build.gradle index 9fa92cd04..8e26f6c3a 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,8 @@ buildscript { ext.glide = "com.github.bumptech.glide:glide:$glideVersion" ext.glideCompiler = "com.github.bumptech.glide:compiler:$glideVersion" + ext.paging_version = "3.1.0" + ext.rxkotlin = "io.reactivex.rxjava2:rxkotlin:2.4.0" ext.rxandroid = "io.reactivex.rxjava2:rxandroid:2.1.1" ext.rxbinding = 'com.jakewharton.rxbinding2:rxbinding:2.2.0' diff --git a/favoritesdatabase/build.gradle b/favoritesdatabase/build.gradle index 2b776d3ab..41136e2bb 100644 --- a/favoritesdatabase/build.gradle +++ b/favoritesdatabase/build.gradle @@ -51,13 +51,12 @@ dependencies { implementation project(':Models') - //def room_version = "2.3.0" implementation room.room - //implementation "androidx.room:room-runtime:$room_version" // For Kotlin use kapt instead of annotationProcessor kapt "androidx.room:room-compiler:$room_version" - //ksp "androidx.room:room-compiler:$room_version" - // optional - Kotlin Extensions and Coroutines support for Room - //implementation "androidx.room:room-ktx:$room_version" - //implementation "androidx.room:room-rxjava2:$room_version" + + implementation "androidx.paging:paging-runtime-ktx:$paging_version" + // alternatively - without Android dependencies for tests + testImplementation "androidx.paging:paging-common-ktx:$paging_version" + implementation "androidx.room:room-paging:2.4.1" } \ No newline at end of file diff --git a/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/HistoryDatabase.kt b/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/HistoryDatabase.kt index 00ae9fe59..2a4c49611 100644 --- a/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/HistoryDatabase.kt +++ b/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/HistoryDatabase.kt @@ -1,6 +1,7 @@ package com.programmersbox.favoritesdatabase import android.content.Context +import androidx.paging.PagingSource import androidx.room.* import kotlinx.coroutines.flow.Flow @@ -51,14 +52,17 @@ interface HistoryDao { @Query("SELECT * FROM RecentlyViewed ORDER BY timestamp ASC") fun getRecentlyViewed(): Flow> + @Query("SELECT * FROM RecentlyViewed ORDER BY timestamp DESC") + fun getRecentlyViewedPaging(): PagingSource + @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertRecentlyViewed(model: RecentModel) @Delete suspend fun deleteRecent(model: RecentModel) - @Query("DELETE FROM RecentlyViewed WHERE url IN (SELECT url FROM RecentlyViewed ORDER BY timestamp DESC LIMIT 1 OFFSET 20)") - suspend fun removeOldData() + @Query("DELETE FROM RecentlyViewed WHERE url IN (SELECT url FROM RecentlyViewed ORDER BY timestamp DESC LIMIT 1 OFFSET :limit)") + suspend fun removeOldData(limit: Int) @Query("DELETE FROM RecentlyViewed") suspend fun deleteAllRecentHistory(): Int From 1883cfb15c091f7349a13851692cbae4f792c02b Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 19 Jan 2022 15:31:41 -0500 Subject: [PATCH 007/166] - converted NotificationFragment.kt to use Paging 3. The loss of animation is a bit of a bummer, but its probably possible to implement that in again. - also added a dynamic theme thing from JetCaster --- .../uiviews/NotificationFragment.kt | 47 +- .../uiviews/utils/ComposableUtils.kt | 421 ++++++++++++++++++ .../favoritesdatabase/ItemDao.kt | 4 + 3 files changed, 462 insertions(+), 10 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt index 1c9fbf48a..4c6c0e257 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt @@ -11,6 +11,7 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.* 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.* @@ -30,12 +31,17 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.* import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.util.fastMap +import androidx.lifecycle.ViewModel import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.compose.collectAsLazyPagingItems +import androidx.paging.compose.items import androidx.work.Data import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder @@ -47,6 +53,7 @@ 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 import com.programmersbox.favoritesdatabase.ItemDatabase import com.programmersbox.favoritesdatabase.NotificationItem import com.programmersbox.gsonutils.toJson @@ -76,6 +83,19 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { private val logo: MainLogo by inject() private val notificationLogo: NotificationLogo by inject() + class NotificationViewModel(private val dao: ItemDao) : ViewModel() { + + val notificationItems = Pager( + config = PagingConfig( + pageSize = 10, + enablePlaceholders = false + ) + ) { dao.getAllNotificationsFlowPaging() } + + val notificationCount = dao.getAllNotificationCountFlow() + + } + @OptIn( ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class, @@ -89,7 +109,10 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { setContent { M3MaterialTheme(currentColorScheme) { - val items by db.getAllNotificationsFlow().collectAsState(emptyList()) + val vm: NotificationViewModel = viewModel(factory = factoryCreate { NotificationViewModel(db) }) + + val items = vm.notificationItems.flow.collectAsLazyPagingItems() + val itemCount by vm.notificationCount.collectAsState(0) val state = rememberBottomSheetScaffoldState() val scope = rememberCoroutineScope() @@ -100,7 +123,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } - BottomSheetDeleteScaffold( + BottomSheetDeleteScaffoldPaging( listOfItems = items, state = state, multipleTitle = stringResource(R.string.areYouSureRemoveNoti), @@ -142,7 +165,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { SmallTopAppBar( scrollBehavior = scrollBehavior, - title = { Text(stringResource(id = R.string.current_notification_count, items.size)) }, + title = { Text(stringResource(id = R.string.current_notification_count, itemCount)) }, actions = { IconButton(onClick = { showPopup = true }) { Icon(Icons.Default.ClearAll, null) } IconButton(onClick = { scope.launch { state.bottomSheetState.expand() } }) { Icon(Icons.Default.Delete, null) } @@ -172,6 +195,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { .subscribe { d.clear() } .addTo(disposable) }, + deleteTitle = { stringResource(R.string.removeNoti, it.notiTitle) }, itemUi = { item -> ListItem( modifier = Modifier.padding(5.dp), @@ -204,7 +228,9 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { onClick = { Completable.merge( items - .filter { it.notiTitle == item.notiTitle } + .itemSnapshotList + .filter { it?.notiTitle == item.notiTitle } + .filterNotNull() .map { cancelNotification(it) db.deleteNotification(it) @@ -227,20 +253,21 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { ) } ) { p, itemList -> - AnimatedLazyColumn( + + /*AnimatedLazyColumn( contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.padding(vertical = 4.dp), items = itemList.fastMap { AnimatedLazyListItem(key = it.url, value = it) { NotificationItem(item = it, navController = findNavController()) } } - ) - //TODO: This will be used when native lazycolumn/lazyrow gains support for animations - /*LazyColumn( + )*/ + + LazyColumn( contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.padding(vertical = 4.dp) - ) { items(itemList) { NotificationItem(item = it, navController = findNavController()) } }*/ + ) { items(itemList) { NotificationItem(item = it!!, navController = findNavController()) } } } } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index db314747a..403de2c2e 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -2,11 +2,13 @@ package com.programmersbox.uiviews.utils import android.app.Activity import android.app.Dialog +import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build import android.os.Bundle import android.provider.Settings +import android.util.LruCache import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -59,9 +61,17 @@ import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed import androidx.compose.ui.util.fastMap import androidx.compose.ui.window.PopupProperties +import androidx.core.graphics.drawable.toBitmap +import androidx.paging.compose.LazyPagingItems +import androidx.paging.compose.items +import androidx.palette.graphics.Palette import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListUpdateCallback import androidx.window.layout.WindowMetricsCalculator +import coil.Coil +import coil.request.ImageRequest +import coil.request.SuccessResult +import coil.size.Scale import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.PermissionsRequired import com.google.accompanist.permissions.rememberMultiplePermissionsState @@ -559,6 +569,237 @@ private fun DeleteItemView( } +//TODO: For paging animation, map the data around the AnimatedItem +// along with modifying an animatedItems for the LazyPagingItems + +@ExperimentalMaterial3Api +@ExperimentalMaterialApi +@Composable +fun BottomSheetDeleteScaffoldPaging( + listOfItems: LazyPagingItems, + state: BottomSheetScaffoldState = rememberBottomSheetScaffoldState(), + multipleTitle: String, + onRemove: (T) -> Unit, + onMultipleRemove: (SnapshotStateList) -> Unit, + customSingleRemoveDialog: (T) -> Boolean = { true }, + bottomScrollBehavior: TopAppBarScrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }, + deleteTitle: @Composable (T) -> String = { stringResource(R.string.remove) }, + topBar: @Composable (() -> Unit)? = null, + itemUi: @Composable (T) -> Unit, + mainView: @Composable (PaddingValues, LazyPagingItems) -> Unit +) { + val scope = rememberCoroutineScope() + val context = LocalContext.current + + BottomSheetScaffold( + scaffoldState = state, + modifier = Modifier.nestedScroll(bottomScrollBehavior.nestedScrollConnection), + topBar = topBar, + backgroundColor = M3MaterialTheme.colorScheme.background, + contentColor = m3ContentColorFor(M3MaterialTheme.colorScheme.background), + sheetShape = MaterialTheme.shapes.medium.copy(CornerSize(4.dp), CornerSize(4.dp), CornerSize(0.dp), CornerSize(0.dp)), + sheetPeekHeight = ButtonDefaults.MinHeight + 4.dp, + sheetContent = { + + val itemsToDelete = remember { mutableStateListOf() } + + LaunchedEffect(state) { + snapshotFlow { state.bottomSheetState.isCollapsed } + .distinctUntilChanged() + .filter { it } + .collect { itemsToDelete.clear() } + } + + var showPopup by remember { mutableStateOf(false) } + + if (showPopup) { + + val onDismiss = { showPopup = false } + + androidx.compose.material3.AlertDialog( + onDismissRequest = onDismiss, + title = { androidx.compose.material3.Text(multipleTitle) }, + text = { + androidx.compose.material3.Text( + context.resources.getQuantityString( + R.plurals.areYouSureRemove, + itemsToDelete.size, + itemsToDelete.size + ) + ) + }, + confirmButton = { + androidx.compose.material3.TextButton( + onClick = { + onDismiss() + scope.launch { state.bottomSheetState.collapse() } + onMultipleRemove(itemsToDelete) + } + ) { androidx.compose.material3.Text(stringResource(R.string.yes)) } + }, + dismissButton = { androidx.compose.material3.TextButton(onClick = onDismiss) { androidx.compose.material3.Text(stringResource(R.string.no)) } } + ) + + } + + val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } + + androidx.compose.material3.Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + androidx.compose.material3.Button( + onClick = { + scope.launch { + if (state.bottomSheetState.isCollapsed) state.bottomSheetState.expand() + else state.bottomSheetState.collapse() + } + }, + modifier = Modifier + .fillMaxWidth() + .heightIn(ButtonDefaults.MinHeight + 4.dp), + shape = RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp) + ) { androidx.compose.material3.Text(stringResource(R.string.delete_multiple)) } + }, + bottomBar = { + BottomAppBar( + contentPadding = PaddingValues(0.dp), + backgroundColor = TopAppBarDefaults.centerAlignedTopAppBarColors() + .containerColor(scrollFraction = scrollBehavior.scrollFraction).value, + contentColor = TopAppBarDefaults.centerAlignedTopAppBarColors() + .titleContentColor(scrollFraction = scrollBehavior.scrollFraction).value + ) { + androidx.compose.material3.Button( + onClick = { scope.launch { state.bottomSheetState.collapse() } }, + modifier = Modifier + .weight(1f) + .padding(horizontal = 5.dp) + ) { androidx.compose.material3.Text(stringResource(id = R.string.cancel)) } + + androidx.compose.material3.Button( + onClick = { showPopup = true }, + enabled = itemsToDelete.isNotEmpty(), + modifier = Modifier + .weight(1f) + .padding(horizontal = 5.dp) + ) { androidx.compose.material3.Text(stringResource(id = R.string.remove)) } + } + } + ) { + LazyColumn( + verticalArrangement = Arrangement.spacedBy(4.dp), + contentPadding = it, + modifier = Modifier.padding(5.dp) + ) { + items(listOfItems, key = { i -> i.hashCode().toString() }) { i -> + i?.let { d -> + DeleteItemView( + item = d, + selectedForDeletion = d in itemsToDelete, + onClick = { item -> if (item in itemsToDelete) itemsToDelete.remove(item) else itemsToDelete.add(item) }, + customSingleRemoveDialog = customSingleRemoveDialog, + deleteTitle = deleteTitle, + onRemove = onRemove, + itemUi = itemUi + ) + } + } + } + } + } + ) { mainView(it, listOfItems) } +} + +@ExperimentalMaterialApi +@Composable +private fun DeleteItemView( + item: T, + selectedForDeletion: Boolean, + deleteTitle: @Composable (T) -> String = { stringResource(R.string.remove) }, + onClick: (T) -> Unit, + customSingleRemoveDialog: (T) -> Boolean, + onRemove: (T) -> Unit, + itemUi: @Composable (T) -> Unit +) { + + var showPopup by remember { mutableStateOf(false) } + + if (showPopup) { + + val onDismiss = { showPopup = false } + androidx.compose.material3.AlertDialog( + onDismissRequest = onDismiss, + title = { androidx.compose.material3.Text(deleteTitle(item)) }, + confirmButton = { + androidx.compose.material3.TextButton( + onClick = { + onDismiss() + onRemove(item) + } + ) { androidx.compose.material3.Text(stringResource(R.string.yes)) } + }, + dismissButton = { androidx.compose.material3.TextButton(onClick = onDismiss) { androidx.compose.material3.Text(stringResource(R.string.no)) } } + ) + + } + + val dismissState = rememberDismissState( + confirmStateChange = { + if (it == DismissValue.DismissedToEnd || it == DismissValue.DismissedToStart) { + if (customSingleRemoveDialog(item)) { + showPopup = true + } + } + false + } + ) + + SwipeToDismiss( + state = dismissState, + background = { + val direction = dismissState.dismissDirection ?: return@SwipeToDismiss + val color by animateColorAsState( + when (dismissState.targetValue) { + DismissValue.Default -> Color.Transparent + DismissValue.DismissedToEnd -> Color.Red + DismissValue.DismissedToStart -> Color.Red + } + ) + val alignment = when (direction) { + DismissDirection.StartToEnd -> Alignment.CenterStart + DismissDirection.EndToStart -> Alignment.CenterEnd + } + val scale by animateFloatAsState(if (dismissState.targetValue == DismissValue.Default) 0.75f else 1f) + + Box( + Modifier + .fillMaxSize() + .background(color) + .padding(horizontal = 20.dp), + contentAlignment = alignment + ) { + androidx.compose.material3.Icon( + Icons.Default.Delete, + contentDescription = null, + modifier = Modifier.scale(scale) + ) + } + } + ) { + androidx.compose.material3.Surface( + tonalElevation = 5.dp, + modifier = Modifier.fillMaxSize(), + shape = MaterialTheme.shapes.medium, + indication = rememberRipple(), + border = BorderStroke( + animateDpAsState(targetValue = if (selectedForDeletion) 5.dp else 1.dp).value, + animateColorAsState(if (selectedForDeletion) Color(0xfff44336) else Color.Transparent).value + ), + onClick = { onClick(item) }, + ) { itemUi(item) } + } + +} + interface AutoCompleteEntity { fun filter(query: String): Boolean } @@ -1168,4 +1409,184 @@ fun getWindowSizeClass(windowDpSize: DpSize): WindowSize = when { windowDpSize.width < 600.dp -> WindowSize.Compact windowDpSize.width < 840.dp -> WindowSize.Medium else -> WindowSize.Expanded +} + +fun Color.contrastAgainst(background: Color): Float { + val fg = if (alpha < 1f) compositeOver(background) else this + + val fgLuminance = fg.luminance() + 0.05f + val bgLuminance = background.luminance() + 0.05f + + return kotlin.math.max(fgLuminance, bgLuminance) / kotlin.math.min(fgLuminance, bgLuminance) +} + +@Composable +fun rememberDominantColorState( + context: Context = LocalContext.current, + defaultColor: Color = M3MaterialTheme.colorScheme.primary, + defaultOnColor: Color = M3MaterialTheme.colorScheme.onPrimary, + cacheSize: Int = 12, + isColorValid: (Color) -> Boolean = { true } +): DominantColorState = remember { + DominantColorState(context, defaultColor, defaultOnColor, cacheSize, isColorValid) +} + +//TODO: Try converting DetailsFragment to use this + +/* +val surfaceColor = M3MaterialTheme.colorScheme.surface +val dominantColor = rememberDominantColorState { color -> + // We want a color which has sufficient contrast against the surface color + color.contrastAgainst(surfaceColor) >= 3f +} + +DynamicThemePrimaryColorsFromImage(dominantColor) { + LaunchedEffect(item.imageUrl) { + if (item.imageUrl != null) { + dominantColor.updateColorsFromImageUrl(item.imageUrl) + } else { + dominantColor.reset() + } + } + HistoryItem(item, scope) +} + */ + +/** + * A composable which allows dynamic theming of the [androidx.compose.material.Colors.primary] + * color from an image. + */ +@Composable +fun DynamicThemePrimaryColorsFromImage( + dominantColorState: DominantColorState = rememberDominantColorState(), + content: @Composable () -> Unit +) { + val colors = M3MaterialTheme.colorScheme.copy( + primary = animateColorAsState( + dominantColorState.color, + spring(stiffness = Spring.StiffnessLow) + ).value, + onPrimary = animateColorAsState( + dominantColorState.onColor, + spring(stiffness = Spring.StiffnessLow) + ).value, + surface = animateColorAsState( + dominantColorState.color, + spring(stiffness = Spring.StiffnessLow) + ).value, + onSurface = animateColorAsState( + dominantColorState.onColor, + spring(stiffness = Spring.StiffnessLow) + ).value + ) + M3MaterialTheme(colorScheme = colors, content = content) +} + +/** + * A class which stores and caches the result of any calculated dominant colors + * from images. + * + * @param context Android context + * @param defaultColor The default color, which will be used if [calculateDominantColor] fails to + * calculate a dominant color + * @param defaultOnColor The default foreground 'on color' for [defaultColor]. + * @param cacheSize The size of the [LruCache] used to store recent results. Pass `0` to + * disable the cache. + * @param isColorValid A lambda which allows filtering of the calculated image colors. + */ +@Stable +class DominantColorState( + private val context: Context, + private val defaultColor: Color, + private val defaultOnColor: Color, + cacheSize: Int = 12, + private val isColorValid: (Color) -> Boolean = { true } +) { + var color by mutableStateOf(defaultColor) + private set + var onColor by mutableStateOf(defaultOnColor) + private set + + private val cache = when { + cacheSize > 0 -> LruCache(cacheSize) + else -> null + } + + suspend fun updateColorsFromImageUrl(url: String) { + val result = calculateDominantColor(url) + color = result?.color ?: defaultColor + onColor = result?.onColor ?: defaultOnColor + } + + private suspend fun calculateDominantColor(url: String): DominantColors? { + val cached = cache?.get(url) + if (cached != null) { + // If we already have the result cached, return early now... + return cached + } + + // Otherwise we calculate the swatches in the image, and return the first valid color + return calculateSwatchesInImage(context, url) + // First we want to sort the list by the color's population + .sortedByDescending { swatch -> swatch.population } + // Then we want to find the first valid color + .firstOrNull { swatch -> isColorValid(Color(swatch.rgb)) } + // If we found a valid swatch, wrap it in a [DominantColors] + ?.let { swatch -> + DominantColors( + color = Color(swatch.rgb), + onColor = Color(swatch.bodyTextColor).copy(alpha = 1f) + ) + } + // Cache the resulting [DominantColors] + ?.also { result -> cache?.put(url, result) } + } + + /** + * Reset the color values to [defaultColor]. + */ + fun reset() { + color = defaultColor + onColor = defaultColor + } +} + +@Immutable +private data class DominantColors(val color: Color, val onColor: Color) + +/** + * Fetches the given [imageUrl] with [Coil], then uses [Palette] to calculate the dominant color. + */ +private suspend fun calculateSwatchesInImage( + context: Context, + imageUrl: String +): List { + val r = ImageRequest.Builder(context) + .data(imageUrl) + // We scale the image to cover 128px x 128px (i.e. min dimension == 128px) + .size(128).scale(Scale.FILL) + // Disable hardware bitmaps, since Palette uses Bitmap.getPixels() + .allowHardware(false) + .build() + + val bitmap = when (val result = Coil.execute(r)) { + is SuccessResult -> result.drawable.toBitmap() + else -> null + } + + return bitmap?.let { + withContext(Dispatchers.Default) { + val palette = Palette.Builder(bitmap) + // Disable any bitmap resizing in Palette. We've already loaded an appropriately + // sized bitmap through Coil + .resizeBitmapArea(0) + // Clear any built-in filters. We want the unfiltered dominant color + .clearFilters() + // We reduce the maximum color count down to 8 + .maximumColorCount(8) + .generate() + + palette.vibrantSwatch?.let { listOfNotNull(it) } ?: palette.swatches + } + } ?: emptyList() } \ No newline at end of file diff --git a/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt b/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt index c610a6bf1..b1a689641 100644 --- a/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt +++ b/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt @@ -1,5 +1,6 @@ package com.programmersbox.favoritesdatabase +import androidx.paging.PagingSource import androidx.room.* import io.reactivex.Completable import io.reactivex.Flowable @@ -79,6 +80,9 @@ interface ItemDao { @Query("SELECT * FROM Notifications") fun getAllNotificationsFlow(): Flow> + @Query("SELECT * FROM Notifications") + fun getAllNotificationsFlowPaging(): PagingSource + @Query("SELECT COUNT(id) FROM Notifications") fun getAllNotificationCountFlow(): Flow From c0725faed995d87500a864954c7cb9742c0e9ba8 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 20 Jan 2022 06:38:15 -0500 Subject: [PATCH 008/166] - added a history count on the history screen. - updated a library --- .../com/programmersbox/uiviews/HistoryFragment.kt | 14 ++++++++++++++ .../programmersbox/uiviews/NotificationFragment.kt | 4 ++-- .../uiviews/utils/ComposableUtils.kt | 3 --- mangaworld/build.gradle | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt index b3144e40e..431bfdb13 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt @@ -94,6 +94,8 @@ class HistoryFragment : Fragment() { enablePlaceholders = true ) ) { dao.getRecentlyViewedPaging() } + + val historyCount = dao.getAllRecentHistoryCount() } @ExperimentalMaterial3Api @@ -102,6 +104,7 @@ class HistoryFragment : Fragment() { private fun RecentlyViewedUi(hm: HistoryViewModel = viewModel(factory = factoryCreate { HistoryViewModel(dao) })) { val recentItems = hm.historyItems.flow.collectAsLazyPagingItems() + val recentSize by hm.historyCount.collectAsState(initial = 0) val scope = rememberCoroutineScope() var clearAllDialog by remember { mutableStateOf(false) } @@ -138,11 +141,22 @@ class HistoryFragment : Fragment() { }, title = { Text(stringResource(R.string.history)) }, actions = { + Text("$recentSize") IconButton(onClick = { clearAllDialog = true }) { Icon(Icons.Default.DeleteForever, null) } } ) } ) { p -> + + /*AnimatedLazyColumn( + contentPadding = p, + verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.padding(vertical = 4.dp), + items = recentItems.itemSnapshotList.fastMap { item -> + AnimatedLazyListItem(key = item!!.url, value = item) { HistoryItem(item, scope) } + } + )*/ + LazyColumn( contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt index 4c6c0e257..ee7feaeb1 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt @@ -258,8 +258,8 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.padding(vertical = 4.dp), - items = itemList.fastMap { - AnimatedLazyListItem(key = it.url, value = it) { NotificationItem(item = it, navController = findNavController()) } + items = itemList.itemSnapshotList.fastMap { + AnimatedLazyListItem(key = it!!.url, value = it) { NotificationItem(item = it, navController = findNavController()) } } )*/ diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 403de2c2e..6b3964cda 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -569,9 +569,6 @@ private fun DeleteItemView( } -//TODO: For paging animation, map the data around the AnimatedItem -// along with modifying an animatedItems for the LazyPagingItems - @ExperimentalMaterial3Api @ExperimentalMaterialApi @Composable diff --git a/mangaworld/build.gradle b/mangaworld/build.gradle index 4aeac77d9..d027c598c 100644 --- a/mangaworld/build.gradle +++ b/mangaworld/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation firebaseCrash.crash implementation 'com.github.hedzr:android-file-chooser:v1.2.0-final' - implementation "com.anggrayudi:storage:0.14.0" + implementation "com.anggrayudi:storage:1.0.0" implementation 'de.helmbold:rxfilewatcher:1.0.0' implementation project(':UIViews') From 93d518ba454d3013394c6b0bebf302b6f6cde5f3 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Fri, 21 Jan 2022 08:54:08 -0500 Subject: [PATCH 009/166] - added some insets for mangaworld....for some reason, mangaworld's performance improved when doing this --- .../main/res/layout/base_main_activity.xml | 1 + .../programmersbox/mangaworld/MainActivity.kt | 25 ++++++++++++++++--- .../programmersbox/mangaworld/ReadActivity.kt | 5 +++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/UIViews/src/main/res/layout/base_main_activity.xml b/UIViews/src/main/res/layout/base_main_activity.xml index 96861cb25..057f02c67 100644 --- a/UIViews/src/main/res/layout/base_main_activity.xml +++ b/UIViews/src/main/res/layout/base_main_activity.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:id="@+id/main_layout" android:orientation="vertical" tools:context=".BaseMainActivity"> diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt index 631309b6e..852526652 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt @@ -1,8 +1,7 @@ package com.programmersbox.mangaworld -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat -import androidx.core.view.WindowInsetsControllerCompat +import android.view.ViewGroup +import androidx.core.view.* import com.github.piasy.biv.BigImageViewer import com.github.piasy.biv.loader.glide.GlideImageLoader import com.google.android.gms.ads.MobileAds @@ -33,6 +32,26 @@ class MainActivity : BaseMainActivity() { MobileAds.initialize(this) + WindowCompat.setDecorFitsSystemWindows(window, false) + + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main_layout)) { view, windowInsets -> + val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) + // Apply the insets as a margin to the view. Here the system is setting + // only the bottom, left, and right dimensions, but apply whichever insets are + // appropriate to your layout. You can also update the view padding + // if that's more appropriate. + view.updateLayoutParams { + leftMargin = insets.left + bottomMargin = insets.bottom + rightMargin = insets.right + topMargin = insets.top + } + + // Return CONSUMED if you don't want want the window insets to keep being + // passed down to descendant views. + WindowInsetsCompat.CONSUMED + } + val bottomNav = findViewById(R.id.navLayout2) showOrHideNav diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index 800d84d75..ccbcc023a 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -114,7 +114,9 @@ import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.koin.android.ext.android.inject @@ -1333,13 +1335,14 @@ class ReadActivity : AppCompatActivity() { lifecycleScope.launch { pagePadding .flowWithLifecycle(lifecycle) - .collect { + .onEach { runOnUiThread { binding.readView.removeItemDecoration(decor) decor = VerticalSpaceItemDecoration(it) binding.readView.addItemDecoration(decor) } } + .collect() } binding.readerSettings.setOnClickListener { From 3cc262b28aeed1a17f167e6b7df1ce3ce0b22200 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 06:55:20 -0500 Subject: [PATCH 010/166] - lib updates --- UIViews/build.gradle | 2 +- build.gradle | 2 +- sharedutils/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UIViews/build.gradle b/UIViews/build.gradle index 4a87ce4fd..c4a1a5ea7 100644 --- a/UIViews/build.gradle +++ b/UIViews/build.gradle @@ -134,7 +134,7 @@ dependencies { implementation "com.airbnb.android:lottie-compose:$lottieVersion" implementation "com.google.accompanist:accompanist-swiperefresh:$accompanist" implementation "com.google.accompanist:accompanist-systemuicontroller:$accompanist" - implementation "me.onebone:toolbar-compose:2.3.0" + implementation "me.onebone:toolbar-compose:2.3.1" implementation 'com.github.nanihadesuka:LazyColumnScrollbar:1.0.3' implementation "androidx.paging:paging-compose:1.0.0-alpha14" diff --git a/build.gradle b/build.gradle index 8e26f6c3a..1add10f07 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ buildscript { ext.jsoup = 'org.jsoup:jsoup:1.14.3' - ext.crashlytics = 'com.google.firebase:firebase-crashlytics:18.2.6' + ext.crashlytics = 'com.google.firebase:firebase-crashlytics:18.2.7' ext.analytics = 'com.google.firebase:firebase-analytics:20.0.2' ext.play_services = 'com.google.android.gms:play-services-auth:20.0.1' diff --git a/sharedutils/build.gradle b/sharedutils/build.gradle index d3057d55c..a63c9bf96 100644 --- a/sharedutils/build.gradle +++ b/sharedutils/build.gradle @@ -45,7 +45,7 @@ dependencies { implementation 'com.google.firebase:firebase-auth:21.0.1' implementation play_services implementation 'com.firebaseui:firebase-ui-auth:8.0.0' - implementation 'com.google.firebase:firebase-firestore-ktx:24.0.0' + implementation 'com.google.firebase:firebase-firestore-ktx:24.0.1' implementation 'com.google.firebase:firebase-database-ktx:20.0.3' implementation coroutinesCore From cd189564061fa6b2d57470d424cc9e464a026f84 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 07:24:59 -0500 Subject: [PATCH 011/166] - added a Dynamic theme based on the dominant but with more dynamic-ness --- .../uiviews/utils/ComposableUtils.kt | 144 +++++++++++++++++- .../otakuworld/DialogScreens.kt | 103 ++++++++++++- 2 files changed, 245 insertions(+), 2 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 6b3964cda..cc8f6d5ac 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -1428,6 +1428,15 @@ fun rememberDominantColorState( DominantColorState(context, defaultColor, defaultOnColor, cacheSize, isColorValid) } +@Composable +fun rememberDynamicColorState( + context: Context = LocalContext.current, + defaultColorScheme: ColorScheme = M3MaterialTheme.colorScheme, + cacheSize: Int = 12 +): DynamicColorState = remember { + DynamicColorState(context, defaultColorScheme, cacheSize) +} + //TODO: Try converting DetailsFragment to use this /* @@ -1479,6 +1488,40 @@ fun DynamicThemePrimaryColorsFromImage( M3MaterialTheme(colorScheme = colors, content = content) } +@Composable +fun FullDynamicThemePrimaryColorsFromImage( + dominantColorState: DynamicColorState = rememberDynamicColorState(), + content: @Composable () -> Unit +) { + val colors = M3MaterialTheme.colorScheme.copy( + primary = animateColorAsState( + dominantColorState.colorScheme.primary, + spring(stiffness = Spring.StiffnessLow) + ).value, + onPrimary = animateColorAsState( + dominantColorState.colorScheme.onPrimary, + spring(stiffness = Spring.StiffnessLow) + ).value, + surface = animateColorAsState( + dominantColorState.colorScheme.surface, + spring(stiffness = Spring.StiffnessLow) + ).value, + onSurface = animateColorAsState( + dominantColorState.colorScheme.onSurface, + spring(stiffness = Spring.StiffnessLow) + ).value, + background = animateColorAsState( + dominantColorState.colorScheme.background, + spring(stiffness = Spring.StiffnessLow) + ).value, + onBackground = animateColorAsState( + dominantColorState.colorScheme.onBackground, + spring(stiffness = Spring.StiffnessLow) + ).value, + ) + M3MaterialTheme(colorScheme = colors, content = content) +} + /** * A class which stores and caches the result of any calculated dominant colors * from images. @@ -1548,6 +1591,66 @@ class DominantColorState( } } +@Stable +class DynamicColorState( + private val context: Context, + private val defaultColorScheme: ColorScheme, + cacheSize: Int = 12 +) { + var colorScheme by mutableStateOf(defaultColorScheme) + private set + + private val cache = when { + cacheSize > 0 -> LruCache(cacheSize) + else -> null + } + + suspend fun updateColorsFromImageUrl(url: String) { + val result = calculateDominantColor(url) + colorScheme = result?.let { + defaultColorScheme.copy( + primary = it.dominantSwatch?.rgb?.let { it1 -> Color(it1) } ?: defaultColorScheme.primary, + onPrimary = it.dominantSwatch?.let { it1 -> Color(it1.bodyTextColor) } ?: defaultColorScheme.onPrimary, + surface = it.vibrantSwatch?.let { it1 -> Color(it1.rgb) } ?: defaultColorScheme.surface, + onSurface = it.vibrantSwatch?.let { it1 -> Color(it1.bodyTextColor) } ?: defaultColorScheme.onSurface, + background = it.mutedSwatch?.let { it1 -> Color(it1.rgb) } ?: defaultColorScheme.background, + onBackground = it.mutedSwatch?.let { it1 -> Color(it1.bodyTextColor) } ?: defaultColorScheme.onBackground, + ) + } ?: defaultColorScheme + } + + private suspend fun calculateDominantColor(url: String): Palette? { + val cached = cache?.get(url) + if (cached != null) { + // If we already have the result cached, return early now... + return cached + } + + // Otherwise we calculate the swatches in the image, and return the first valid color + return calculateAllSwatchesInImage(context, url) + // First we want to sort the list by the color's population + //.sortedByDescending { swatch -> swatch.population } + // Then we want to find the first valid color + //.firstOrNull { swatch -> isColorValid(Color(swatch.rgb)) } + // If we found a valid swatch, wrap it in a [DominantColors] + /*?.let { swatch -> + DominantColors( + color = Color(swatch.rgb), + onColor = Color(swatch.bodyTextColor).copy(alpha = 1f) + ) + }*/ + // Cache the resulting [DominantColors] + ?.also { result -> cache?.put(url, result) } + } + + /** + * Reset the color values to [defaultColor]. + */ + fun reset() { + colorScheme = defaultColorScheme + } +} + @Immutable private data class DominantColors(val color: Color, val onColor: Color) @@ -1582,8 +1685,47 @@ private suspend fun calculateSwatchesInImage( // We reduce the maximum color count down to 8 .maximumColorCount(8) .generate() - + //TODO: Maybe change this to return the palette and choose the kind of swatch afterwards + // dominant + // vibrant + // muted palette.vibrantSwatch?.let { listOfNotNull(it) } ?: palette.swatches } } ?: emptyList() +} + +private suspend fun calculateAllSwatchesInImage( + context: Context, + imageUrl: String +): Palette? { + val r = ImageRequest.Builder(context) + .data(imageUrl) + // We scale the image to cover 128px x 128px (i.e. min dimension == 128px) + .size(128).scale(Scale.FILL) + // Disable hardware bitmaps, since Palette uses Bitmap.getPixels() + .allowHardware(false) + .build() + + val bitmap = when (val result = Coil.execute(r)) { + is SuccessResult -> result.drawable.toBitmap() + else -> null + } + + return bitmap?.let { + withContext(Dispatchers.Default) { + val palette = Palette.Builder(bitmap) + // Disable any bitmap resizing in Palette. We've already loaded an appropriately + // sized bitmap through Coil + .resizeBitmapArea(0) + // Clear any built-in filters. We want the unfiltered dominant color + .clearFilters() + // We reduce the maximum color count down to 8 + .maximumColorCount(8) + .generate() + // dominant + // vibrant + // muted + palette + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt index b8cb36584..3f205e21c 100644 --- a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt +++ b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt @@ -15,6 +15,7 @@ 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.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* @@ -92,7 +93,7 @@ class TestDialogFragment : BaseBottomSheetDialogFragment() { } enum class SettingLocation { - CHECK, SWITCH, PAGER, OPTIMISTIC, MOTIONLAYOUT + CHECK, SWITCH, PAGER, OPTIMISTIC, MOTIONLAYOUT, THEME } @ExperimentalMotionApi @@ -140,6 +141,7 @@ fun TestView(closeClick: () -> Unit) { SettingLocation.PAGER -> PagerView { scope.launch { state.bottomSheetState.collapse() } } SettingLocation.OPTIMISTIC -> OptimisticView { scope.launch { state.bottomSheetState.collapse() } } SettingLocation.MOTIONLAYOUT -> MotionLayoutView { scope.launch { state.bottomSheetState.collapse() } } + SettingLocation.THEME -> ThemeingView { scope.launch { state.bottomSheetState.collapse() } } else -> {} } } @@ -206,6 +208,18 @@ fun TestView(closeClick: () -> Unit) { } ) { Icon(Icons.Default.ChevronRight, null) } } + + item { + PreferenceSetting( + settingTitle = { Text("Theme Settings") }, + settingIcon = { Icon(Icons.Default.SettingsBrightness, null) }, + modifier = Modifier.clickable { + location = SettingLocation.THEME + scope.launch { state.bottomSheetState.expand() } + } + ) { Icon(Icons.Default.ChevronRight, null) } + + } } } } @@ -808,4 +822,91 @@ fun MotionLayoutView(closeClick: () -> Unit) { } } } +} + +@ExperimentalMaterial3Api +@ExperimentalFoundationApi +@Composable +fun ThemeingView(closeClick: () -> Unit) { + val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } + val scope = rememberCoroutineScope() + + Scaffold( + topBar = { + Column { + CenterAlignedTopAppBar( + title = { Text("Theme Views") }, + actions = { IconButton(onClick = { closeClick() }) { Icon(imageVector = Icons.Default.Close, contentDescription = null) } }, + scrollBehavior = scrollBehavior + ) + Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + } + }, + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) + ) { p -> + + val current = currentColorScheme + + val dominantColor = rememberDynamicColorState() + val url: String? = remember { + "https://upload.wikimedia.org/wikipedia/en/c/c3/OnePunchMan_manga_cover.png" + } + LaunchedEffect(url) { + if (url != null) { + dominantColor.updateColorsFromImageUrl(url) + } else { + dominantColor.reset() + } + } + + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(p), + horizontalAlignment = Alignment.CenterHorizontally + ) { + + stickyHeader { + Row { + Text("Option", modifier = Modifier.weight(1f)) + Text("M3", modifier = Modifier.weight(1f)) + Text("Dynamic", modifier = Modifier.weight(1f)) + } + } + + fun LazyListScope.row(type: String, choice: ColorScheme.() -> Color) { + item { + Row(verticalAlignment = Alignment.CenterVertically) { + Text(type, modifier = Modifier.weight(1f)) + + MaterialTheme(current) { + Box( + modifier = Modifier + .height(15.dp) + .weight(1f) + .background(MaterialTheme.colorScheme.choice()) + ) + } + + FullDynamicThemePrimaryColorsFromImage(dominantColor) { + Box( + modifier = Modifier + .height(15.dp) + .weight(1f) + .background(MaterialTheme.colorScheme.choice()) + ) + } + } + } + } + + row("Primary") { primary } + row("onPrimary") { onPrimary } + row("surface") { surface } + row("onSurface") { onSurface } + row("Background") { background } + row("onBackground") { onBackground } + + } + } } \ No newline at end of file From 0ca6627784d8b1d549975d132f3634399ef6cb85 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 08:46:41 -0500 Subject: [PATCH 012/166] - got the topappbar to change color on scrolling in DetailsFragment.kt --- .../programmersbox/uiviews/DetailsFragment.kt | 68 +++++++++++++++++-- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index 154e344d9..69dba4020 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -22,21 +22,19 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* +import androidx.compose.material.SnackbarDuration 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.AlertDialog -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SmallTopAppBar import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.* import androidx.compose.runtime.rxjava2.subscribeAsState import androidx.compose.ui.Alignment @@ -56,6 +54,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.util.fastAny @@ -102,6 +101,7 @@ import me.onebone.toolbar.ScrollStrategy import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState import my.nanihadesuka.compose.LazyColumnScrollbar import org.koin.android.ext.android.inject +import kotlin.math.ln import androidx.compose.material3.MaterialTheme as M3MaterialTheme import androidx.compose.material3.contentColorFor as m3ContentColorFor @@ -687,20 +687,30 @@ class DetailsFragment : Fragment() { BottomSheetScaffold( backgroundColor = Color.Transparent, sheetContent = { + val scrollBehaviorMarkAs = remember { TopAppBarDefaults.pinnedScrollBehavior() } + Scaffold( topBar = { SmallTopAppBar( title = { Text(stringResource(id = R.string.markAs), color = topBarColor) }, colors = TopAppBarDefaults.smallTopAppBarColors( - containerColor = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value ?: M3MaterialTheme.colorScheme.surface + 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 + ) ), navigationIcon = { IconButton(onClick = { scope.launch { scaffoldState.bottomSheetState.collapse() } }) { Icon(Icons.Default.Close, null, tint = topBarColor) } - } + }, + scrollBehavior = scrollBehaviorMarkAs ) }, + modifier = Modifier.nestedScroll(scrollBehaviorMarkAs.nestedScrollConnection) ) { p -> LazyColumn( contentPadding = p, @@ -768,7 +778,13 @@ class DetailsFragment : Fragment() { SmallTopAppBar( colors = TopAppBarDefaults.smallTopAppBarColors( titleContentColor = topBarColor, - containerColor = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value ?: M3MaterialTheme.colorScheme.surface + 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 + ) ), modifier = Modifier.zIndex(2f), scrollBehavior = scrollBehavior, @@ -1509,6 +1525,44 @@ class DetailsFragment : Fragment() { } } + + /** + * Returns the new background [Color] to use, representing the original background [color] with an + * overlay corresponding to [elevation] applied. The overlay will only be applied to + * [ColorScheme.surface]. + */ + private fun ColorScheme.applyTonalElevation(backgroundColor: Color, elevation: Dp): Color { + return if (backgroundColor == surface) { + surfaceColorAtElevation(elevation) + } else { + backgroundColor + } + } + + /** + * Returns the [ColorScheme.surface] color with an alpha of the [ColorScheme.primary] color overlaid + * on top of it. + * Computes the surface tonal color at different elevation levels e.g. surface1 through surface5. + * + * @param elevation Elevation value used to compute alpha of the color overlay layer. + */ + private fun ColorScheme.surfaceColorAtElevation( + elevation: Dp, + ): Color { + if (elevation == 0.dp) return surface + val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f + return primary.copy(alpha = alpha).compositeOver(surface) + } + + private fun Color.surfaceColorAtElevation( + elevation: Dp, + surface: Color + ): Color { + if (elevation == 0.dp) return surface + val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f + return copy(alpha = alpha).compositeOver(surface) + } + override fun onDestroy() { super.onDestroy() disposable.dispose() From be8fab0e24b6488e8e0dbad5365d22dd8471d041 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 10:13:02 -0500 Subject: [PATCH 013/166] - added a key to MangaWorld main screens, so far its improving performance. Still testing - fixed an issue on startup where the main screens would get the source twice --- .../src/main/java/com/programmersbox/uiviews/AllFragment.kt | 2 +- .../main/java/com/programmersbox/uiviews/RecentFragment.kt | 2 +- .../main/java/com/programmersbox/mangaworld/GenericManga.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt index 59971e995..d7a1803f1 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt @@ -204,7 +204,7 @@ class AllFragment : BaseFragmentCompose() { val source by sourcePublish.subscribeAsState(initial = null) LaunchedEffect(isConnected) { - if (allVm.sourceList.isEmpty() && source != null && isConnected) allVm.reset(context, source!!) + if (allVm.sourceList.isEmpty() && source != null && isConnected && allVm.count != 1) allVm.reset(context, source!!) } val scaffoldState = rememberBottomSheetScaffoldState() diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt index 9f1739c94..6a332ba4b 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt @@ -171,7 +171,7 @@ class RecentFragment : BaseFragmentCompose() { .subscribeAsState(initial = true) LaunchedEffect(isConnected) { - if (recentVm.sourceList.isEmpty() && source != null && isConnected) recentVm.reset(context, source!!) + if (recentVm.sourceList.isEmpty() && source != null && isConnected && recentVm.count != 1) recentVm.reset(context, source!!) } val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt index 905aec2c2..7781a080e 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt @@ -15,7 +15,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.GridCells import androidx.compose.foundation.lazy.LazyGridState import androidx.compose.foundation.lazy.LazyVerticalGrid -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* @@ -183,7 +183,7 @@ class GenericManga(val context: Context) : GenericInfo { horizontalArrangement = Arrangement.spacedBy(4.dp), state = listState ) { - items(list) { + itemsIndexed(list, key = { i, it -> "${it.url}$i" }) { _, it -> M3CoverCard( onLongPress = { c -> onLongPress(it, c) }, imageUrl = it.imageUrl, From 384f83e96345b5602d7564ba9c75fae7289cbded Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 11:06:42 -0500 Subject: [PATCH 014/166] - lib update --- mangaworld/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangaworld/build.gradle b/mangaworld/build.gradle index d027c598c..0f79b7634 100644 --- a/mangaworld/build.gradle +++ b/mangaworld/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation firebaseCrash.crash implementation 'com.github.hedzr:android-file-chooser:v1.2.0-final' - implementation "com.anggrayudi:storage:1.0.0" + implementation "com.anggrayudi:storage:1.1.0" implementation 'de.helmbold:rxfilewatcher:1.0.0' implementation project(':UIViews') From a7a11687cd422da37b9b2c4587de265584d57e37 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 11:07:33 -0500 Subject: [PATCH 015/166] - updating build to try something --- .github/workflows/build_check.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_check.yaml b/.github/workflows/build_check.yaml index 4038ad366..454e50174 100644 --- a/.github/workflows/build_check.yaml +++ b/.github/workflows/build_check.yaml @@ -45,7 +45,7 @@ jobs: with: java-version: 11 - name: Build APK - run: bash ./gradlew assembleDebug --stacktrace + run: bash ./gradlew assembleRelease --stacktrace - name: Upload APK uses: actions/upload-artifact@v1 From c13621ef9fbe78caedbac8e1d54c652158ca2c03 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 11:09:24 -0500 Subject: [PATCH 016/166] - still trying --- .github/workflows/build_check.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_check.yaml b/.github/workflows/build_check.yaml index 454e50174..19c8e8b2c 100644 --- a/.github/workflows/build_check.yaml +++ b/.github/workflows/build_check.yaml @@ -51,24 +51,24 @@ jobs: uses: actions/upload-artifact@v1 with: name: apk - path: animeworld/build/outputs/apk/debug/animeworld-debug.apk + path: animeworld/build/outputs/apk/release/animeworld-release.apk - name: Upload APK uses: actions/upload-artifact@v1 with: name: apk - path: mangaworld/build/outputs/apk/debug/mangaworld-debug.apk + path: mangaworld/build/outputs/apk/release/mangaworld-release.apk - name: Upload APK uses: actions/upload-artifact@v1 with: name: apk - path: novelworld/build/outputs/apk/debug/novelworld-debug.apk + path: novelworld/build/outputs/apk/release/novelworld-release.apk - name: Upload APK uses: actions/upload-artifact@v1 with: name: apk - path: animeworldtv/build/outputs/apk/debug/animeworldtv-debug.apk + path: animeworldtv/build/outputs/apk/release/animeworldtv-release.apk - name: Upload APK uses: actions/upload-artifact@v1 with: name: apk - path: otakumanager/build/outputs/apk/debug/otakumanager-debug.apk + path: otakumanager/build/outputs/apk/release/otakumanager-release.apk From 733b1af71999db078381d211c676e5bb70bf85fb Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 25 Jan 2022 11:11:10 -0500 Subject: [PATCH 017/166] - build thing! --- .github/workflows/main_release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main_release.yml b/.github/workflows/main_release.yml index 4c6ee073a..39cedb718 100644 --- a/.github/workflows/main_release.yml +++ b/.github/workflows/main_release.yml @@ -109,7 +109,6 @@ jobs: cp ${{ steps.animetv_sign.outputs.signedReleaseFile }} animeworldtv-release.apk cp ${{ steps.otakumanager_sign.outputs.signedReleaseFile }} otakumanager-release.apk - - uses: actions/upload-artifact@v2 with: name: Signed Manga App From 523594d08231beafdd7618cdaee448fa2ede275b Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 26 Jan 2022 06:39:55 -0500 Subject: [PATCH 018/166] - setup gradle like how new gradles are setup --- build.gradle | 11 ----------- settings.gradle.kts | 12 ++++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 1add10f07..0df3d73f1 100644 --- a/build.gradle +++ b/build.gradle @@ -151,17 +151,6 @@ buildscript { } } -allprojects { - repositories { - google() - gradlePluginPortal() - mavenCentral() - maven { url "https://jitpack.io" } - //maven { url "https://dl.bintray.com/piasy/maven" } - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - } -} - task clean(type: Delete) { delete rootProject.buildDir } diff --git a/settings.gradle.kts b/settings.gradle.kts index 3c50872a3..e3a09c068 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,15 @@ +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + gradlePluginPortal() + mavenCentral() + maven("https://jitpack.io") + //maven { url "https://dl.bintray.com/piasy/maven" } + maven("https://oss.sonatype.org/content/repositories/snapshots") + } +} + include( ":favoritesdatabase", ":anime_sources", From 6e7b9660f67c78f5958605828efb963fdf5d03f1 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 26 Jan 2022 07:18:05 -0500 Subject: [PATCH 019/166] - build check change again --- .github/workflows/build_check.yaml | 118 ++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build_check.yaml b/.github/workflows/build_check.yaml index 19c8e8b2c..5956cb59f 100644 --- a/.github/workflows/build_check.yaml +++ b/.github/workflows/build_check.yaml @@ -44,31 +44,97 @@ jobs: uses: actions/setup-java@v1 with: java-version: 11 - - name: Build APK - run: bash ./gradlew assembleRelease --stacktrace - - name: Upload APK - uses: actions/upload-artifact@v1 + - name: Build all artifacts + id: buildAllApks + uses: eskatos/gradle-command-action@v1.3.3 with: - name: apk - path: animeworld/build/outputs/apk/release/animeworld-release.apk - - name: Upload APK - uses: actions/upload-artifact@v1 - with: - name: apk - path: mangaworld/build/outputs/apk/release/mangaworld-release.apk - - name: Upload APK - uses: actions/upload-artifact@v1 - with: - name: apk - path: novelworld/build/outputs/apk/release/novelworld-release.apk - - name: Upload APK - uses: actions/upload-artifact@v1 - with: - name: apk - path: animeworldtv/build/outputs/apk/release/animeworldtv-release.apk - - name: Upload APK - uses: actions/upload-artifact@v1 - with: - name: apk - path: otakumanager/build/outputs/apk/release/otakumanager-release.apk + gradle-version: 7.0.2 + wrapper-cache-enabled: true + dependencies-cache-enabled: true + configuration-cache-enabled: true + arguments: assembleRelease + + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: manga_sign + with: + releaseDirectory: mangaworld/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: anime_sign + with: + releaseDirectory: animeworld/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: novel_sign + with: + releaseDirectory: novelworld/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: animetv_sign + with: + releaseDirectory: animeworldtv/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: otakumanager_sign + with: + releaseDirectory: otakumanager/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} + + # ${{steps.sign_app.outputs.signedReleaseFile}} + - name: Clean up build artifacts + run: | + cp ${{ steps.manga_sign.outputs.signedReleaseFile }} mangaworld-release.apk + cp ${{ steps.anime_sign.outputs.signedReleaseFile }} animeworld-release.apk + cp ${{ steps.novel_sign.outputs.signedReleaseFile }} novelworld-release.apk + cp ${{ steps.animetv_sign.outputs.signedReleaseFile }} animeworldtv-release.apk + cp ${{ steps.otakumanager_sign.outputs.signedReleaseFile }} otakumanager-release.apk + + - uses: actions/upload-artifact@v2 + with: + name: Signed Manga App + path: mangaworld-release.apk + + - uses: actions/upload-artifact@v2 + with: + name: Signed Anime App + path: animeworld-release.apk + + - uses: actions/upload-artifact@v2 + with: + name: Signed Novel App + path: novelworld-release.apk + + - uses: actions/upload-artifact@v2 + with: + name: Signed AnimeTV App + path: animeworldtv-release.apk + + - uses: actions/upload-artifact@v2 + with: + name: Signed OtakuManager App + path: otakumanager-release.apk From 73d1211f19f9df5578f6b1b0ecd5b3a5106e6e6f Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 26 Jan 2022 07:18:55 -0500 Subject: [PATCH 020/166] - build check error fixed --- .github/workflows/build_check.yaml | 146 ++++++++++++++--------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/.github/workflows/build_check.yaml b/.github/workflows/build_check.yaml index 5956cb59f..7e18fbf1a 100644 --- a/.github/workflows/build_check.yaml +++ b/.github/workflows/build_check.yaml @@ -55,86 +55,86 @@ jobs: configuration-cache-enabled: true arguments: assembleRelease - - uses: r0adkll/sign-android-release@v1 - name: Sign app APK - id: manga_sign - with: - releaseDirectory: mangaworld/build/outputs/apk/release - signingKeyBase64: ${{ secrets.SIGNING_KEY }} - alias: ${{ secrets.ALIAS }} - keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} - keyPassword: ${{ secrets.KEY_PASSWORD }} + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: manga_sign + with: + releaseDirectory: mangaworld/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} - - uses: r0adkll/sign-android-release@v1 - name: Sign app APK - id: anime_sign - with: - releaseDirectory: animeworld/build/outputs/apk/release - signingKeyBase64: ${{ secrets.SIGNING_KEY }} - alias: ${{ secrets.ALIAS }} - keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} - keyPassword: ${{ secrets.KEY_PASSWORD }} + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: anime_sign + with: + releaseDirectory: animeworld/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} - - uses: r0adkll/sign-android-release@v1 - name: Sign app APK - id: novel_sign - with: - releaseDirectory: novelworld/build/outputs/apk/release - signingKeyBase64: ${{ secrets.SIGNING_KEY }} - alias: ${{ secrets.ALIAS }} - keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} - keyPassword: ${{ secrets.KEY_PASSWORD }} + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: novel_sign + with: + releaseDirectory: novelworld/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} - - uses: r0adkll/sign-android-release@v1 - name: Sign app APK - id: animetv_sign - with: - releaseDirectory: animeworldtv/build/outputs/apk/release - signingKeyBase64: ${{ secrets.SIGNING_KEY }} - alias: ${{ secrets.ALIAS }} - keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} - keyPassword: ${{ secrets.KEY_PASSWORD }} + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: animetv_sign + with: + releaseDirectory: animeworldtv/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} - - uses: r0adkll/sign-android-release@v1 - name: Sign app APK - id: otakumanager_sign - with: - releaseDirectory: otakumanager/build/outputs/apk/release - signingKeyBase64: ${{ secrets.SIGNING_KEY }} - alias: ${{ secrets.ALIAS }} - keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} - keyPassword: ${{ secrets.KEY_PASSWORD }} + - uses: r0adkll/sign-android-release@v1 + name: Sign app APK + id: otakumanager_sign + with: + releaseDirectory: otakumanager/build/outputs/apk/release + signingKeyBase64: ${{ secrets.SIGNING_KEY }} + alias: ${{ secrets.ALIAS }} + keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} + keyPassword: ${{ secrets.KEY_PASSWORD }} - # ${{steps.sign_app.outputs.signedReleaseFile}} - - name: Clean up build artifacts - run: | - cp ${{ steps.manga_sign.outputs.signedReleaseFile }} mangaworld-release.apk - cp ${{ steps.anime_sign.outputs.signedReleaseFile }} animeworld-release.apk - cp ${{ steps.novel_sign.outputs.signedReleaseFile }} novelworld-release.apk - cp ${{ steps.animetv_sign.outputs.signedReleaseFile }} animeworldtv-release.apk - cp ${{ steps.otakumanager_sign.outputs.signedReleaseFile }} otakumanager-release.apk + # ${{steps.sign_app.outputs.signedReleaseFile}} + - name: Clean up build artifacts + run: | + cp ${{ steps.manga_sign.outputs.signedReleaseFile }} mangaworld-release.apk + cp ${{ steps.anime_sign.outputs.signedReleaseFile }} animeworld-release.apk + cp ${{ steps.novel_sign.outputs.signedReleaseFile }} novelworld-release.apk + cp ${{ steps.animetv_sign.outputs.signedReleaseFile }} animeworldtv-release.apk + cp ${{ steps.otakumanager_sign.outputs.signedReleaseFile }} otakumanager-release.apk - - uses: actions/upload-artifact@v2 - with: - name: Signed Manga App - path: mangaworld-release.apk + - uses: actions/upload-artifact@v2 + with: + name: Signed Manga App + path: mangaworld-release.apk - - uses: actions/upload-artifact@v2 - with: - name: Signed Anime App - path: animeworld-release.apk + - uses: actions/upload-artifact@v2 + with: + name: Signed Anime App + path: animeworld-release.apk - - uses: actions/upload-artifact@v2 - with: - name: Signed Novel App - path: novelworld-release.apk + - uses: actions/upload-artifact@v2 + with: + name: Signed Novel App + path: novelworld-release.apk - - uses: actions/upload-artifact@v2 - with: - name: Signed AnimeTV App - path: animeworldtv-release.apk + - uses: actions/upload-artifact@v2 + with: + name: Signed AnimeTV App + path: animeworldtv-release.apk - - uses: actions/upload-artifact@v2 - with: - name: Signed OtakuManager App - path: otakumanager-release.apk + - uses: actions/upload-artifact@v2 + with: + name: Signed OtakuManager App + path: otakumanager-release.apk From 2eb899f0912a9f89daa75bb9c2cdf0faff5349ec Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 26 Jan 2022 14:35:51 -0500 Subject: [PATCH 021/166] - library updates! New compose version! --- .../programmersbox/uiviews/DetailsFragment.kt | 1 + .../programmersbox/uiviews/HistoryFragment.kt | 22 +++++++++----- .../uiviews/NotificationFragment.kt | 23 ++++++++++---- .../uiviews/SettingsFragment.kt | 30 +++++++++++-------- .../uiviews/utils/ComposableUtils.kt | 2 +- .../uiviews/utils/SettingsComposables.kt | 4 +++ build.gradle | 7 +++-- .../programmersbox/mangaworld/ReadActivity.kt | 12 ++------ 8 files changed, 64 insertions(+), 37 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index 69dba4020..ad085587f 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -1038,6 +1038,7 @@ class DetailsFragment : Fragment() { } } + @ExperimentalMaterial3Api @ExperimentalMaterialApi @Composable private fun ChapterItem( diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt index 431bfdb13..f4a63802b 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt @@ -14,15 +14,21 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.DeleteForever +import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.ripple.rememberRipple -import androidx.compose.material3.* import androidx.compose.material3.AlertDialog +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MediumTopAppBar +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -43,7 +49,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.lifecycleScope import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.fragment.findNavController -import androidx.paging.* +import androidx.paging.Pager +import androidx.paging.PagingConfig import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.items import coil.compose.rememberImagePainter @@ -60,9 +67,9 @@ import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import org.koin.android.ext.android.inject -import java.util.* import androidx.compose.material3.MaterialTheme as M3MaterialTheme class HistoryFragment : Fragment() { @@ -94,6 +101,8 @@ class HistoryFragment : Fragment() { enablePlaceholders = true ) ) { dao.getRecentlyViewedPaging() } + .flow + .flowOn(Dispatchers.IO) val historyCount = dao.getAllRecentHistoryCount() } @@ -103,7 +112,7 @@ class HistoryFragment : Fragment() { @Composable private fun RecentlyViewedUi(hm: HistoryViewModel = viewModel(factory = factoryCreate { HistoryViewModel(dao) })) { - val recentItems = hm.historyItems.flow.collectAsLazyPagingItems() + val recentItems = hm.historyItems.collectAsLazyPagingItems() val recentSize by hm.historyCount.collectAsState(initial = 0) val scope = rememberCoroutineScope() @@ -256,8 +265,7 @@ class HistoryFragment : Fragment() { .background(M3MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(28.0.dp)) ) { Column { - CircularProgressIndicator( - color = M3MaterialTheme.colorScheme.primary, + androidx.compose.material3.CircularProgressIndicator( modifier = Modifier.align(Alignment.CenterHorizontally) ) Text(text = stringResource(id = R.string.loading), Modifier.align(Alignment.CenterHorizontally)) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt index ee7feaeb1..aa4bd9ac6 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt @@ -9,26 +9,36 @@ import android.widget.Toast import androidx.activity.compose.BackHandler import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.* +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.background 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.* +import androidx.compose.material.icons.filled.ArrowBack +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.ripple.rememberRipple -import androidx.compose.material3.* import androidx.compose.material3.AlertDialog +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.SmallTopAppBar +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.* +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModel @@ -68,6 +78,7 @@ import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import java.util.* @@ -91,6 +102,8 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { enablePlaceholders = false ) ) { dao.getAllNotificationsFlowPaging() } + .flow + .flowOn(Dispatchers.IO) val notificationCount = dao.getAllNotificationCountFlow() @@ -111,7 +124,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { val vm: NotificationViewModel = viewModel(factory = factoryCreate { NotificationViewModel(db) }) - val items = vm.notificationItems.flow.collectAsLazyPagingItems() + val items = vm.notificationItems.collectAsLazyPagingItems() val itemCount by vm.notificationCount.collectAsState(0) val state = rememberBottomSheetScaffoldState() diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt index 83ac46d92..d68b6b92b 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt @@ -19,7 +19,6 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* @@ -34,19 +33,22 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.* +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties import androidx.core.graphics.drawable.toBitmap import androidx.fragment.app.Fragment -import androidx.lifecycle.* +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import androidx.navigation.navOptions -import androidx.preference.* import androidx.work.Constraints import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder @@ -74,11 +76,13 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.rxkotlin.Observables import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import org.koin.android.ext.android.inject import java.io.File -import java.util.* class SettingsDsl { companion object { @@ -240,7 +244,7 @@ fun SettingScreen( logo = logo ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider() /*About*/ AboutSettings( @@ -251,7 +255,7 @@ fun SettingScreen( logo = logo ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), modifier = Modifier.padding(top = 5.dp)) + androidx.compose.material3.Divider(modifier = Modifier.padding(top = 5.dp)) /*Notifications*/ NotificationSettings( @@ -268,7 +272,7 @@ fun SettingScreen( historyClick = historyClick ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider() /*General*/ GeneralSettings( @@ -280,7 +284,7 @@ fun SettingScreen( globalSearchClick = globalSearchClick ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider() /*Player*/ PlaySettings( @@ -289,7 +293,7 @@ fun SettingScreen( customSettings = customPreferences.playerSettings ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), modifier = Modifier.padding(top = 5.dp)) + androidx.compose.material3.Divider(modifier = Modifier.padding(top = 5.dp)) /*More Info*/ InfoSettings( @@ -624,7 +628,7 @@ private fun NotificationSettings( .padding(bottom = 16.dp, top = 8.dp) ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider() } } @@ -678,6 +682,7 @@ private fun ViewSettings( customSettings?.invoke() } +@ExperimentalMaterial3Api @ExperimentalComposeUiApi @ExperimentalMaterialApi @Composable @@ -862,6 +867,7 @@ private fun InfoSettings(context: Context, usedLibraryClick: () -> Unit) { } +@ExperimentalMaterial3Api @ExperimentalComposeUiApi @ExperimentalMaterialApi @Composable diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index cc8f6d5ac..44fc17c75 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -1117,7 +1117,7 @@ class ListBottomSheet( secondaryText = c.secondaryText?.let { i -> { Text(i) } }, overlineText = c.overlineText?.let { i -> { Text(i) } } ) - if (index < list.size - 1) Divider() + if (index < list.size - 1) androidx.compose.material.Divider() } } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt index 327a64269..bae6e446b 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt @@ -14,6 +14,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.AlertDialog +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -62,6 +63,7 @@ fun defaultSliderColors() = SliderDefaults.colors( activeTickColor = contentColorFor(MaterialTheme.colorScheme.primary).copy(alpha = SliderDefaults.TickAlpha) ) +@ExperimentalMaterial3Api @ExperimentalComposeUiApi @ExperimentalMaterialApi @Composable @@ -135,6 +137,7 @@ fun ListSetting( ) } +@ExperimentalMaterial3Api @ExperimentalComposeUiApi @ExperimentalMaterialApi @Composable @@ -252,6 +255,7 @@ fun SwitchSetting( } } +@ExperimentalMaterial3Api @ExperimentalMaterialApi @Composable fun CheckBoxSetting( diff --git a/build.gradle b/build.gradle index 0df3d73f1..5a509fc84 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ buildscript { ext.exoplayer_version = "2.16.1" ext.room_version = "2.4.1" - ext.nav_version = "2.4.0-rc01" + ext.nav_version = "2.4.0" def koin_version = "3.0.2" @@ -52,7 +52,7 @@ buildscript { ext.lottieVersion = "4.2.2" - ext.jetpack = "1.2.0-alpha01" + ext.jetpack = "1.2.0-alpha02" ext.accompanist = "0.20.3" @@ -63,7 +63,7 @@ buildscript { ext.composeFoundation = "androidx.compose.foundation:foundation:$jetpack" // Material Design ext.composeMaterial = "androidx.compose.material:material:$jetpack" - ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha03" + ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha04" // Material design icons ext.composeMaterialIconsCore = "androidx.compose.material:material-icons-core:$jetpack" ext.composeMaterialIconsExtended = "androidx.compose.material:material-icons-extended:$jetpack" @@ -147,6 +147,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files + //Note: Update this to the alpha version in order to be able to upgrade the gradle to 7.1.0 classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } } diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index ccbcc023a..8100853f9 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -347,7 +347,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { initialValue = runBlocking { requireContext().dataStore.data.first()[BATTERY_PERCENT] ?: 20 }, range = 1f..100f ) - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = .12f)) + androidx.compose.material3.Divider() SliderSetting( scope = scope, settingIcon = Icons.Default.FormatLineSpacing, @@ -443,10 +443,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { imageModel = it, contentScale = ContentScale.Crop, loading = { - CircularProgressIndicator( - modifier = Modifier.align(Alignment.Center), - color = M3MaterialTheme.colorScheme.primary - ) + androidx.compose.material3.CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) }, modifier = Modifier .fillMaxWidth() @@ -906,10 +903,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { imageModel = painter, contentScale = ContentScale.FillWidth, loading = { - CircularProgressIndicator( - modifier = Modifier.align(Alignment.Center), - color = M3MaterialTheme.colorScheme.primary - ) + androidx.compose.material3.CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) }, modifier = Modifier .fillMaxSize() From e3f7dfc4e5898ad76f34ef74c1ab63983455643f Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 26 Jan 2022 15:46:20 -0500 Subject: [PATCH 022/166] - using the NEW actual native Chip! With some small changes --- .../programmersbox/uiviews/DetailsFragment.kt | 15 +++-- .../uiviews/FavoriteFragment.kt | 57 ++++++++++--------- .../uiviews/utils/ComposableUtils.kt | 57 ++++++++++++++++++- .../animeworld/DownloadViewerFragment.kt | 17 +++--- .../otakumanager/MainActivity.kt | 21 +++++-- .../otakumanager/OtakuDetails.kt | 2 +- 6 files changed, 122 insertions(+), 47 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index ad085587f..160678132 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -1382,12 +1382,15 @@ class DetailsFragment : Fragment() { LazyRow(horizontalArrangement = Arrangement.spacedBy(4.dp)) { items(model.genres) { CustomChip( - category = it, - textColor = (swatchInfo.value?.rgb?.toComposeColor() ?: M3MaterialTheme.colorScheme.onSurface).animate().value, - backgroundColor = (swatchInfo.value?.bodyColor?.toComposeColor()?.copy(1f) ?: M3MaterialTheme.colorScheme.surface) - .animate().value, - modifier = Modifier.fadeInAnimation() - ) + modifier = Modifier.fadeInAnimation(), + colors = ChipDefaults.outlinedChipColors( + backgroundColor = (swatchInfo.value?.bodyColor?.toComposeColor()?.copy(1f) ?: M3MaterialTheme.colorScheme.surface) + .animate().value, + contentColor = (swatchInfo.value?.rgb?.toComposeColor() ?: M3MaterialTheme.colorScheme.onSurface) + .animate().value + .copy(alpha = ChipDefaults.ContentOpacity) + ) + ) { Text(it) } } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt index 121a2cc8d..47c23f4ab 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt @@ -14,11 +14,14 @@ import androidx.compose.foundation.lazy.* 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.OutlinedTextField +import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material3.* +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment @@ -231,15 +234,15 @@ class FavoriteFragment : Fragment() { item { CustomChip( - "ALL", - modifier = Modifier - .combinedClickable( - onClick = { viewModel.resetSources() }, - onLongClick = { viewModel.selectedSources.clear() } - ), - backgroundColor = M3MaterialTheme.colorScheme.primary, - textColor = M3MaterialTheme.colorScheme.onPrimary - ) + modifier = Modifier.combinedClickable( + onClick = { viewModel.resetSources() }, + onLongClick = { viewModel.selectedSources.clear() } + ), + colors = ChipDefaults.outlinedChipColors( + backgroundColor = M3MaterialTheme.colorScheme.primary, + contentColor = M3MaterialTheme.colorScheme.onPrimary.copy(alpha = ChipDefaults.ContentOpacity) + ) + ) { Text("ALL") } } items( @@ -249,21 +252,23 @@ class FavoriteFragment : Fragment() { .sortedBy { it.first } ) { CustomChip( - "${it.first}: ${it.second.size - 1}", - modifier = Modifier - .combinedClickable( - onClick = { viewModel.newSource(it.first) }, - onLongClick = { viewModel.singleSource(it.first) } - ), - backgroundColor = animateColorAsState( - if (it.first in viewModel.selectedSources) M3MaterialTheme.colorScheme.primary - else M3MaterialTheme.colorScheme.surface - ).value, - textColor = animateColorAsState( - if (it.first in viewModel.selectedSources) M3MaterialTheme.colorScheme.onPrimary - else M3MaterialTheme.colorScheme.onSurface - ).value - ) + modifier = Modifier.combinedClickable( + onClick = { viewModel.newSource(it.first) }, + onLongClick = { viewModel.singleSource(it.first) } + ), + colors = ChipDefaults.outlinedChipColors( + backgroundColor = animateColorAsState( + if (it.first in viewModel.selectedSources) M3MaterialTheme.colorScheme.primary + else M3MaterialTheme.colorScheme.surface + ).value, + contentColor = animateColorAsState( + if (it.first in viewModel.selectedSources) M3MaterialTheme.colorScheme.onPrimary + else M3MaterialTheme.colorScheme.onSurface + ).value + .copy(alpha = ChipDefaults.ContentOpacity) + ), + leadingIcon = { Text("${it.second.size - 1}") } + ) { Text(it.first) } } } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 44fc17c75..ad353afec 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -187,7 +187,7 @@ private fun shortestColumn(colHeights: IntArray): Int { fun Int.toComposeColor() = Color(this) @Composable -fun CustomChip( +fun CustomChip2( category: String, modifier: Modifier = Modifier, textColor: Color = MaterialTheme.colors.onSurface, @@ -213,6 +213,61 @@ fun CustomChip( } } +@ExperimentalMaterialApi +@Composable +fun CustomChip( + modifier: Modifier = Modifier, + enabled: Boolean = true, + shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), + border: BorderStroke? = null, + colors: ChipColors = ChipDefaults.chipColors(), + leadingIcon: @Composable (() -> Unit)? = null, + content: @Composable RowScope.() -> Unit +) { + val contentColor by colors.contentColor(enabled) + androidx.compose.material3.Surface( + modifier = modifier, + shape = shape, + color = colors.backgroundColor(enabled).value, + contentColor = contentColor.copy(1.0f), + border = border, + tonalElevation = 8.dp + ) { + CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) { + ProvideTextStyle( + value = M3MaterialTheme.typography.bodyMedium + ) { + Row( + Modifier + .defaultMinSize( + minHeight = ChipDefaults.MinHeight + ) + .padding( + start = if (leadingIcon == null) { + 12.dp + } else 0.dp, + end = 12.dp, + ), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + if (leadingIcon != null) { + Spacer(Modifier.width(4.dp)) + val leadingIconContentColor by colors.leadingIconContentColor(enabled) + CompositionLocalProvider( + androidx.compose.material3.LocalContentColor provides leadingIconContentColor, + LocalContentAlpha provides leadingIconContentColor.alpha, + content = leadingIcon + ) + Spacer(Modifier.width(8.dp)) + } + content() + } + } + } + } +} + @ExperimentalAnimationApi /** * @param state Use [updateAnimatedItemsState]. diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/DownloadViewerFragment.kt b/animeworld/src/main/java/com/programmersbox/animeworld/DownloadViewerFragment.kt index f423a2381..b699856b5 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/DownloadViewerFragment.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/DownloadViewerFragment.kt @@ -17,12 +17,15 @@ import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.Delete -import androidx.compose.material3.* import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.SmallTopAppBar +import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -40,10 +43,12 @@ import androidx.compose.ui.util.fastMap import androidx.constraintlayout.compose.ConstraintLayout import androidx.core.net.toUri import androidx.navigation.fragment.findNavController -import com.programmersbox.dragswipe.* import com.programmersbox.helpfulutils.notificationManager import com.programmersbox.uiviews.BaseMainActivity -import com.programmersbox.uiviews.utils.* +import com.programmersbox.uiviews.utils.BaseBottomSheetDialogFragment +import com.programmersbox.uiviews.utils.BottomSheetDeleteScaffold +import com.programmersbox.uiviews.utils.currentColorScheme +import com.programmersbox.uiviews.utils.currentScreen import com.tonyodev.fetch2.* import kotlinx.coroutines.launch import java.text.DecimalFormat @@ -236,9 +241,8 @@ class DownloadViewerFragment : BaseBottomSheetDialogFragment(), ActionListener { Row(verticalAlignment = Alignment.CenterVertically) { val progress = download.download.progress.coerceAtLeast(0) Text(stringResource(R.string.percent_progress, progress)) - LinearProgressIndicator( + androidx.compose.material3.LinearProgressIndicator( progress = animateFloatAsState(targetValue = progress.toFloat() / 100f).value, - color = M3MaterialTheme.colorScheme.primary, modifier = Modifier .padding(horizontal = 8.dp) .fillMaxWidth() @@ -380,9 +384,8 @@ class DownloadViewerFragment : BaseBottomSheetDialogFragment(), ActionListener { val prog = download.download.progress.coerceAtLeast(0) - LinearProgressIndicator( + androidx.compose.material3.LinearProgressIndicator( progress = animateFloatAsState(targetValue = prog.toFloat() / 100f).value, - color = M3MaterialTheme.colorScheme.primary, modifier = Modifier .constrainAs(progress) { start.linkTo(parent.start) diff --git a/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt b/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt index 563209a34..28ac694a2 100644 --- a/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt +++ b/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt @@ -9,13 +9,19 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.lazy.GridCells +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.LazyVerticalGrid +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.* import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* +import androidx.compose.material.icons.filled.Book +import androidx.compose.material.icons.filled.Cancel +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material.icons.filled.Settings import androidx.compose.runtime.* import androidx.compose.runtime.rxjava2.subscribeAsState import androidx.compose.runtime.saveable.rememberSaveable @@ -30,7 +36,10 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavController import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavGraph.Companion.findStartDestination -import androidx.navigation.compose.* +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.android.material.composethemeadapter.MdcTheme import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -46,7 +55,7 @@ import com.programmersbox.sharedutils.appUpdateCheck import com.programmersbox.uiviews.GenericInfo import com.programmersbox.uiviews.utils.ComposableUtils import com.programmersbox.uiviews.utils.CoverCard -import com.programmersbox.uiviews.utils.CustomChip +import com.programmersbox.uiviews.utils.CustomChip2 import io.reactivex.Flowable import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers @@ -247,7 +256,7 @@ class MainActivity : ComponentActivity() { LazyRow { item { - CustomChip( + CustomChip2( "ALL", modifier = Modifier .combinedClickable( @@ -271,7 +280,7 @@ class MainActivity : ComponentActivity() { .sortedBy { it.first } ) { - CustomChip( + CustomChip2( "${it.first}: ${it.second.size - 1}", modifier = Modifier .combinedClickable( diff --git a/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuDetails.kt b/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuDetails.kt index d0eefa9dd..cf82cfe80 100644 --- a/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuDetails.kt +++ b/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuDetails.kt @@ -349,7 +349,7 @@ fun DetailsHeader( horizontalArrangement = Arrangement.spacedBy(5.dp) ) { items(model.genres) { - CustomChip( + CustomChip2( category = it, textColor = swatchInfo?.rgb?.toComposeColor() ?: MaterialTheme.colors.onSurface, backgroundColor = swatchInfo?.bodyColor?.toComposeColor()?.copy(1f) ?: MaterialTheme.colors.surface, From edc472941d64c64213807c9ab40bdebb13437ec7 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 27 Jan 2022 06:34:53 -0500 Subject: [PATCH 023/166] - lib update --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5a509fc84..726a7f448 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ buildscript { ext.appCompat = 'androidx.appcompat:appcompat:1.4.1' ext.material = 'com.google.android.material:material:1.6.0-alpha02' - ext.preference = "androidx.preference:preference-ktx:1.1.1" + ext.preference = "androidx.preference:preference-ktx:1.2.0" ext.recyclerview = 'androidx.recyclerview:recyclerview:1.2.1' ext.constraintlayout = 'androidx.constraintlayout:constraintlayout:2.1.3' From 686a98e1cad394798008197dcf8f2ae116df0753 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 27 Jan 2022 08:53:22 -0500 Subject: [PATCH 024/166] - some small cleanup --- .../programmersbox/uiviews/DebugFragment.kt | 103 +++--------------- .../uiviews/utils/ComposableUtils.kt | 10 +- 2 files changed, 24 insertions(+), 89 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DebugFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DebugFragment.kt index e30d7e224..0b5340bbb 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DebugFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DebugFragment.kt @@ -6,35 +6,27 @@ import android.view.View import android.view.ViewGroup import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable +import androidx.compose.foundation.excludeFromSystemGesture import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.BatteryAlert import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Deck import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.runtime.rxjava2.subscribeAsState import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.compose.ui.res.stringResource import androidx.navigation.fragment.findNavController -import com.programmersbox.models.sourcePublish import com.programmersbox.uiviews.utils.* -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.rxkotlin.Observables -import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import org.koin.android.ext.android.get import org.koin.android.ext.android.inject import androidx.compose.material3.MaterialTheme as M3MaterialTheme @@ -108,79 +100,16 @@ class DebugFragment : BaseBottomSheetDialogFragment() { LazyColumn(contentPadding = p) { item { - val time by Observables.combineLatest( - updateCheckPublish.map { "Start: ${requireContext().getSystemDateTimeFormat().format(it)}" }, - updateCheckPublishEnd.map { "End: ${requireContext().getSystemDateTimeFormat().format(it)}" } - ) - .map { "${it.first}\n${it.second}" } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeAsState( - listOfNotNull( - requireContext().lastUpdateCheck - ?.let { "Start: ${requireContext().getSystemDateTimeFormat().format(it)}" }, - requireContext().lastUpdateCheckEnd - ?.let { "End: ${requireContext().getSystemDateTimeFormat().format(it)}" } - ) - .joinToString("\n") - ) - - PreferenceSetting( - settingTitle = { Text("Last Time Updates Were Checked") }, - summaryValue = { Text(time) } - ) - } - item { - var batteryPercent by remember { - mutableStateOf(runBlocking { context.dataStore.data.first()[BATTERY_PERCENT] ?: 20 }.toFloat()) + Surface( + color = Color.Blue, + modifier = Modifier + .fillMaxWidth() + .excludeFromSystemGesture() + ) { + Text("Here!") } - SliderSetting( - sliderValue = batteryPercent, - settingIcon = { Icon(Icons.Default.BatteryAlert, null) }, - settingTitle = { Text(stringResource(R.string.battery_alert_percentage)) }, - settingSummary = { Text(stringResource(R.string.battery_default)) }, - range = 1f..100f, - updateValue = { - batteryPercent = it - scope.launch { context.updatePref(BATTERY_PERCENT, it.toInt()) } - } - ) - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) - } - - item { - var value by remember { mutableStateOf(sourcePublish.value) } - ListSetting( - settingIcon = { Icon(Icons.Default.Deck, null) }, - settingTitle = { Text("Current Source") }, - dialogTitle = { Text("Choose a Source") }, - confirmText = { TextButton(onClick = { it.value = false }) { Text("OK") } }, - value = value, - options = genericInfo.sourceList(), - updateValue = { it, d -> - value = it - d.value = false - } - ) - - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) - } - - item { - val value = remember { mutableStateListOf(sourcePublish.value) } - - MultiSelectListSetting( - settingIcon = { Icon(Icons.Default.Deck, null) }, - settingTitle = { Text("Current Source") }, - dialogTitle = { Text("Choose a Source") }, - confirmText = { TextButton(onClick = { it.value = false }) { Text("OK") } }, - values = value, - options = genericInfo.sourceList(), - updateValue = { it, d -> if (d) value.add(it) else value.remove(it) } - ) - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } item { @@ -205,7 +134,7 @@ class DebugFragment : BaseBottomSheetDialogFragment() { ) { println("Hello") } ) - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + Divider() } item { @@ -238,7 +167,7 @@ class DebugFragment : BaseBottomSheetDialogFragment() { ) } - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + Divider() } item { @@ -266,7 +195,7 @@ class DebugFragment : BaseBottomSheetDialogFragment() { ) } - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + Divider() } item { @@ -295,7 +224,7 @@ class DebugFragment : BaseBottomSheetDialogFragment() { updateValue = { value = it } ) - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + Divider() } item { @@ -325,12 +254,12 @@ class DebugFragment : BaseBottomSheetDialogFragment() { updateValue = { value = it } ) - Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + Divider() } itemsIndexed(moreSettings) { index, build -> build() - if (index < moreSettings.size - 1) Divider(color = M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + if (index < moreSettings.size - 1) Divider() } } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index ad353afec..818d6f0f0 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -391,6 +391,7 @@ suspend fun calculateDiff( @ExperimentalMaterialApi @Composable fun BottomSheetDeleteScaffold( + modifier: Modifier = Modifier, listOfItems: List, state: BottomSheetScaffoldState = rememberBottomSheetScaffoldState(), multipleTitle: String, @@ -407,7 +408,9 @@ fun BottomSheetDeleteScaffold( BottomSheetScaffold( scaffoldState = state, - modifier = Modifier.nestedScroll(bottomScrollBehavior.nestedScrollConnection), + modifier = Modifier + .nestedScroll(bottomScrollBehavior.nestedScrollConnection) + .then(modifier), topBar = topBar, backgroundColor = M3MaterialTheme.colorScheme.background, contentColor = m3ContentColorFor(M3MaterialTheme.colorScheme.background), @@ -628,6 +631,7 @@ private fun DeleteItemView( @ExperimentalMaterialApi @Composable fun BottomSheetDeleteScaffoldPaging( + modifier: Modifier = Modifier, listOfItems: LazyPagingItems, state: BottomSheetScaffoldState = rememberBottomSheetScaffoldState(), multipleTitle: String, @@ -645,7 +649,9 @@ fun BottomSheetDeleteScaffoldPaging( BottomSheetScaffold( scaffoldState = state, - modifier = Modifier.nestedScroll(bottomScrollBehavior.nestedScrollConnection), + modifier = Modifier + .nestedScroll(bottomScrollBehavior.nestedScrollConnection) + .then(modifier), topBar = topBar, backgroundColor = M3MaterialTheme.colorScheme.background, contentColor = m3ContentColorFor(M3MaterialTheme.colorScheme.background), From 73a351f4a2230bf4abfe962ab688acc6fedecb3b Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Mon, 7 Feb 2022 07:17:32 -0500 Subject: [PATCH 025/166] - lib update - added a key to FavoriteFragment.kt --- .../main/java/com/programmersbox/uiviews/FavoriteFragment.kt | 3 ++- build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt index 47c23f4ab..28d2e6cf5 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt @@ -341,7 +341,8 @@ class FavoriteFragment : Fragment() { } } .let { if (viewModel.reverse) it.reversed() else it } - .toTypedArray() + .toTypedArray(), + key = { it.key } ) { info -> M3CoverCard( onLongPress = { c -> diff --git a/build.gradle b/build.gradle index 726a7f448..a913a57a9 100644 --- a/build.gradle +++ b/build.gradle @@ -36,8 +36,8 @@ buildscript { ext.crashlytics = 'com.google.firebase:firebase-crashlytics:18.2.7' ext.analytics = 'com.google.firebase:firebase-analytics:20.0.2' - ext.play_services = 'com.google.android.gms:play-services-auth:20.0.1' - + ext.play_services = 'com.google.android.gms:play-services-auth:20.1.0' +0 ext.exoplayer_version = "2.16.1" ext.room_version = "2.4.1" From 84d0275d2a7cbb151c4dccc4784e6c3ee834277b Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Mon, 7 Feb 2022 08:26:39 -0500 Subject: [PATCH 026/166] - lib update --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a913a57a9..2b3b7ffda 100644 --- a/build.gradle +++ b/build.gradle @@ -76,7 +76,7 @@ buildscript { ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.3" ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.3" - ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.5" + ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.6" ext.composeConstraintLayout = "androidx.constraintlayout:constraintlayout-compose:1.0.0" ext.composeAnimation = "androidx.compose.animation:animation:$jetpack" ext.materialPlaceholder = "com.google.accompanist:accompanist-placeholder-material:$accompanist" From b7f7d0ededa22b57d74df24dfbe248c2cee56384 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Mon, 7 Feb 2022 10:53:35 -0500 Subject: [PATCH 027/166] - fixing errors --- .../programmersbox/otakuworld/DialogScreens.kt | 18 +++++++++--------- .../programmersbox/otakuworld/MainActivity.kt | 10 +++++++--- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt index 3f205e21c..f2dc19c98 100644 --- a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt +++ b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt @@ -127,7 +127,7 @@ fun TestView(closeClick: () -> Unit) { actions = { IconButton(onClick = { closeClick() }) { Icon(imageVector = Icons.Default.Close, contentDescription = null) } }, scrollBehavior = scrollBehavior ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } }, sheetPeekHeight = 0.dp, @@ -245,7 +245,7 @@ fun SwitchView(closeClick: () -> Unit) { }, scrollBehavior = scrollBehavior ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) @@ -284,7 +284,7 @@ fun CheckView(closeClick: () -> Unit) { }, scrollBehavior = scrollBehavior ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) @@ -325,7 +325,7 @@ fun PagerView(closeClick: () -> Unit) { actions = { IconButton(onClick = { closeClick() }) { Icon(imageVector = Icons.Default.Close, contentDescription = null) } }, scrollBehavior = scrollBehavior ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) @@ -480,7 +480,7 @@ fun PagerView(closeClick: () -> Unit) { }, ) { Text(settingLocation.toString()) } if (index < optionsList.value.size - 1) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } } } @@ -631,7 +631,7 @@ fun OptimisticView(closeClick: () -> Unit) { actions = { IconButton(onClick = { closeClick() }) { Icon(imageVector = Icons.Default.Close, contentDescription = null) } }, scrollBehavior = scrollBehavior ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) @@ -682,7 +682,7 @@ fun OptimisticView(closeClick: () -> Unit) { onClick = { scope.launch { count2.emit(++count) } } ) { Text("Hi: $timer") } - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } item { @@ -750,7 +750,7 @@ fun MotionLayoutView(closeClick: () -> Unit) { actions = { IconButton(onClick = { closeClick() }) { Icon(imageVector = Icons.Default.Close, contentDescription = null) } }, scrollBehavior = scrollBehavior ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) @@ -839,7 +839,7 @@ fun ThemeingView(closeClick: () -> Unit) { actions = { IconButton(onClick = { closeClick() }) { Icon(imageVector = Icons.Default.Close, contentDescription = null) } }, scrollBehavior = scrollBehavior ) - Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) + androidx.compose.material3.Divider() } }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) diff --git a/app/src/main/java/com/programmersbox/otakuworld/MainActivity.kt b/app/src/main/java/com/programmersbox/otakuworld/MainActivity.kt index 99e91a6f1..51b8832d6 100644 --- a/app/src/main/java/com/programmersbox/otakuworld/MainActivity.kt +++ b/app/src/main/java/com/programmersbox/otakuworld/MainActivity.kt @@ -163,7 +163,9 @@ class MainActivity : AppCompatActivity() { androidx.compose.material3.contentColorFor(androidx.compose.material3.MaterialTheme.colorScheme.surface) .animate().value ) { - Divider(color = androidx.compose.material3.MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f).animate().value) + androidx.compose.material3.Divider( + color = androidx.compose.material3.MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f).animate().value + ) PreferenceSetting(settingTitle = { Text("") }) { androidx.compose.material3.IconButton(onClick = showSettings) { @@ -212,7 +214,9 @@ class MainActivity : AppCompatActivity() { title = { androidx.compose.material3.Text("Fun Playground") }, scrollBehavior = scrollBehavior ) - Divider(color = androidx.compose.material3.MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f).animate().value) + androidx.compose.material3.Divider( + color = androidx.compose.material3.MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f).animate().value + ) } }, backgroundColor = androidx.compose.material3.MaterialTheme.colorScheme.background.animate().value, @@ -804,7 +808,7 @@ fun InfoCard( } - Divider( + androidx.compose.material3.Divider( thickness = 0.5.dp, color = swatchInfo.value?.titleColor?.toComposeColor()?.animate()?.value ?: MaterialTheme.colors.onSurface.copy(alpha = .12f) ) From 4643b27162c647e018511370ebc1bc13a972eea6 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 8 Feb 2022 06:28:51 -0500 Subject: [PATCH 028/166] - lib updates --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 2b3b7ffda..13e6bc8af 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { ext.gson = 'com.google.code.gson:gson:2.8.9' - ext.glideVersion = "4.12.0" + ext.glideVersion = "4.13.0" ext.glide = "com.github.bumptech.glide:glide:$glideVersion" ext.glideCompiler = "com.github.bumptech.glide:compiler:$glideVersion" @@ -76,7 +76,7 @@ buildscript { ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.3" ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.3" - ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.6" + ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.7" ext.composeConstraintLayout = "androidx.constraintlayout:constraintlayout-compose:1.0.0" ext.composeAnimation = "androidx.compose.animation:animation:$jetpack" ext.materialPlaceholder = "com.google.accompanist:accompanist-placeholder-material:$accompanist" From e4e2eb1adb6e3bc27fe3a3ce1647d02ed0a26dd1 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 9 Feb 2022 07:46:28 -0500 Subject: [PATCH 029/166] - Removed paging from NotificationFragment.kt since it would jump around when removing --- .../uiviews/NotificationFragment.kt | 51 ++++--------------- .../uiviews/utils/ComposableUtils.kt | 5 +- 2 files changed, 15 insertions(+), 41 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt index aa4bd9ac6..468581629 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background 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.ArrowBack @@ -41,17 +40,12 @@ import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.lifecycle.ViewModel +import androidx.compose.ui.util.fastMap import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.items import androidx.work.Data import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder @@ -63,7 +57,6 @@ 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 import com.programmersbox.favoritesdatabase.ItemDatabase import com.programmersbox.favoritesdatabase.NotificationItem import com.programmersbox.gsonutils.toJson @@ -78,7 +71,6 @@ import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import java.util.* @@ -94,21 +86,6 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { private val logo: MainLogo by inject() private val notificationLogo: NotificationLogo by inject() - class NotificationViewModel(private val dao: ItemDao) : ViewModel() { - - val notificationItems = Pager( - config = PagingConfig( - pageSize = 10, - enablePlaceholders = false - ) - ) { dao.getAllNotificationsFlowPaging() } - .flow - .flowOn(Dispatchers.IO) - - val notificationCount = dao.getAllNotificationCountFlow() - - } - @OptIn( ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class, @@ -121,11 +98,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnLifecycleDestroyed(viewLifecycleOwner)) setContent { M3MaterialTheme(currentColorScheme) { - - val vm: NotificationViewModel = viewModel(factory = factoryCreate { NotificationViewModel(db) }) - - val items = vm.notificationItems.collectAsLazyPagingItems() - val itemCount by vm.notificationCount.collectAsState(0) + val items by db.getAllNotificationsFlow().collectAsState(initial = emptyList()) val state = rememberBottomSheetScaffoldState() val scope = rememberCoroutineScope() @@ -136,7 +109,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } - BottomSheetDeleteScaffoldPaging( + BottomSheetDeleteScaffold( listOfItems = items, state = state, multipleTitle = stringResource(R.string.areYouSureRemoveNoti), @@ -178,7 +151,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { SmallTopAppBar( scrollBehavior = scrollBehavior, - title = { Text(stringResource(id = R.string.current_notification_count, itemCount)) }, + title = { Text(stringResource(id = R.string.current_notification_count, items.size)) }, actions = { IconButton(onClick = { showPopup = true }) { Icon(Icons.Default.ClearAll, null) } IconButton(onClick = { scope.launch { state.bottomSheetState.expand() } }) { Icon(Icons.Default.Delete, null) } @@ -241,9 +214,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { onClick = { Completable.merge( items - .itemSnapshotList - .filter { it?.notiTitle == item.notiTitle } - .filterNotNull() + .filter { it.notiTitle == item.notiTitle } .map { cancelNotification(it) db.deleteNotification(it) @@ -267,20 +238,20 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { } ) { p, itemList -> - /*AnimatedLazyColumn( + AnimatedLazyColumn( contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.padding(vertical = 4.dp), - items = itemList.itemSnapshotList.fastMap { - AnimatedLazyListItem(key = it!!.url, value = it) { NotificationItem(item = it, navController = findNavController()) } + items = itemList.fastMap { + AnimatedLazyListItem(key = it.url, value = it) { NotificationItem(item = it, navController = findNavController()) } } - )*/ + ) - LazyColumn( + /*LazyColumn( contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.padding(vertical = 4.dp) - ) { items(itemList) { NotificationItem(item = it!!, navController = findNavController()) } } + ) { items(itemList) { NotificationItem(item = it!!, navController = findNavController()) } }*/ } } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 818d6f0f0..92cfdef7c 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -397,6 +397,7 @@ fun BottomSheetDeleteScaffold( multipleTitle: String, onRemove: (T) -> Unit, onMultipleRemove: (SnapshotStateList) -> Unit, + deleteTitle: @Composable (T) -> String = { stringResource(R.string.remove) }, customSingleRemoveDialog: (T) -> Boolean = { true }, bottomScrollBehavior: TopAppBarScrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }, topBar: @Composable (() -> Unit)? = null, @@ -511,6 +512,7 @@ fun BottomSheetDeleteScaffold( DeleteItemView( item = i, deleteItemList = itemsToDelete, + deleteTitle = deleteTitle, customSingleRemoveDialog = customSingleRemoveDialog, onRemove = onRemove, itemUi = itemUi @@ -544,6 +546,7 @@ private fun DeleteItemView( item: T, deleteItemList: SnapshotStateList, customSingleRemoveDialog: (T) -> Boolean, + deleteTitle: @Composable (T) -> String = { stringResource(R.string.remove) }, onRemove: (T) -> Unit, itemUi: @Composable (T) -> Unit ) { @@ -555,7 +558,7 @@ private fun DeleteItemView( val onDismiss = { showPopup = false } androidx.compose.material3.AlertDialog( onDismissRequest = onDismiss, - title = { androidx.compose.material3.Text(stringResource(R.string.remove)) }, + title = { androidx.compose.material3.Text(deleteTitle(item)) }, confirmButton = { androidx.compose.material3.TextButton( onClick = { From 4d63596f5e07393d93568b785c645571228256e0 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 10 Feb 2022 07:37:54 -0500 Subject: [PATCH 030/166] - updated to latest libraries --- .../programmersbox/uiviews/DetailsFragment.kt | 341 ++++++++---------- .../uiviews/GlobalSearchFragment.kt | 81 ++--- .../programmersbox/uiviews/HistoryFragment.kt | 14 +- .../uiviews/NotificationFragment.kt | 235 ++++++------ .../uiviews/utils/ComposableUtils.kt | 69 ++-- .../programmersbox/animeworld/GenericAnime.kt | 10 +- .../animeworld/ViewVideosFragment.kt | 93 ++--- build.gradle | 11 +- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../mangaworld/DownloadViewerFragment.kt | 120 +++--- .../programmersbox/novelworld/GenericNovel.kt | 4 +- 12 files changed, 487 insertions(+), 495 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index 160678132..95cea2a9a 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -73,7 +73,6 @@ import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.google.accompanist.placeholder.material.placeholder import com.google.accompanist.systemuicontroller.rememberSystemUiController -import com.google.android.material.composethemeadapter.MdcTheme import com.programmersbox.favoritesdatabase.* import com.programmersbox.helpfulutils.colorFromTheme import com.programmersbox.models.ChapterModel @@ -357,11 +356,14 @@ class DetailsFragment : Fragment() { } Surface( - onClick = { markAs(!chapters.fastAny { it.url == c.url }) }, shape = RoundedCornerShape(0.dp), tonalElevation = 5.dp, - modifier = Modifier.fillMaxWidth(), - indication = rememberRipple(), + modifier = Modifier + .fillMaxWidth() + .clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() }, + ) { markAs(!chapters.fastAny { it.url == c.url }) }, color = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value ?: M3MaterialTheme.colorScheme.surface ) { ListItem( @@ -416,101 +418,74 @@ class DetailsFragment : Fragment() { val dropDownDismiss = { showDropDown = false } - MdcTheme { - DropdownMenu( - expanded = showDropDown, - onDismissRequest = dropDownDismiss, - ) { + androidx.compose.material3.DropdownMenu( + expanded = showDropDown, + onDismissRequest = dropDownDismiss, + ) { - DropdownMenuItem( - onClick = { - dropDownDismiss() - scope.launch { scaffoldState.bottomSheetState.expand() } - } - ) { - Icon( - Icons.Default.Check, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.markAs)) - } + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + scope.launch { scaffoldState.bottomSheetState.expand() } + }, + text = { Text(stringResource(id = R.string.markAs)) }, + leadingIcon = { Icon(Icons.Default.Check, null) } + ) - DropdownMenuItem( + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + requireContext().openInCustomChromeBrowser(info.url) { setShareState(CustomTabsIntent.SHARE_STATE_ON) } + }, + text = { Text(stringResource(id = R.string.fallback_menu_item_open_in_browser)) }, + leadingIcon = { Icon(Icons.Default.OpenInBrowser, null) } + ) + + if (!isSaved) { + androidx.compose.material3.DropdownMenuItem( onClick = { dropDownDismiss() - requireContext().openInCustomChromeBrowser(info.url) { setShareState(CustomTabsIntent.SHARE_STATE_ON) } - } - ) { - Icon( - Icons.Default.OpenInBrowser, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.fallback_menu_item_open_in_browser)) - } - - if (!isSaved) { - DropdownMenuItem( - onClick = { - dropDownDismiss() - lifecycleScope.launch(Dispatchers.IO) { - dao.insertNotification( - NotificationItem( - id = info.hashCode(), - url = info.url, - summaryText = requireContext() - .getString( - R.string.hadAnUpdate, - info.title, - info.chapters.firstOrNull()?.name.orEmpty() - ), - notiTitle = info.title, - imageUrl = info.imageUrl, - source = info.source.serviceName, - contentTitle = info.title - ) - ).subscribe() - } + lifecycleScope.launch(Dispatchers.IO) { + dao.insertNotification( + NotificationItem( + id = info.hashCode(), + url = info.url, + summaryText = requireContext() + .getString( + R.string.hadAnUpdate, + info.title, + info.chapters.firstOrNull()?.name.orEmpty() + ), + notiTitle = info.title, + imageUrl = info.imageUrl, + source = info.source.serviceName, + contentTitle = info.title + ) + ).subscribe() } - ) { - Icon( - Icons.Default.Save, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.save_for_later)) - } - } + }, + text = { Text(stringResource(id = R.string.save_for_later)) }, + leadingIcon = { Icon(Icons.Default.Save, null) } + ) + } - DropdownMenuItem( - onClick = { - dropDownDismiss() - findNavController().navigate(GlobalNavDirections.showGlobalSearch(info.title)) - } - ) { - Icon( - Icons.Default.Search, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.global_search_by_name)) - } + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + findNavController().navigate(GlobalNavDirections.showGlobalSearch(info.title)) + }, + text = { Text(stringResource(id = R.string.global_search_by_name)) }, + leadingIcon = { Icon(Icons.Default.Search, null) } + ) - DropdownMenuItem( - onClick = { - dropDownDismiss() - reverseChapters = !reverseChapters - } - ) { - Icon( - Icons.Default.Sort, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.reverseOrder)) - } - } + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + reverseChapters = !reverseChapters + }, + text = { Text(stringResource(id = R.string.reverseOrder)) }, + leadingIcon = { Icon(Icons.Default.Sort, null) } + ) } IconButton( @@ -733,11 +708,14 @@ class DetailsFragment : Fragment() { } Surface( - onClick = { markAs(!chapters.fastAny { it.url == c.url }) }, shape = RoundedCornerShape(0.dp), tonalElevation = 5.dp, - modifier = Modifier.fillMaxWidth(), - indication = rememberRipple(), + modifier = Modifier + .fillMaxWidth() + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple() + ) { markAs(!chapters.fastAny { it.url == c.url }) }, color = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value ?: M3MaterialTheme.colorScheme.surface ) { ListItem( @@ -799,101 +777,74 @@ class DetailsFragment : Fragment() { val dropDownDismiss = { showDropDown = false } - MdcTheme { - DropdownMenu( - expanded = showDropDown, - onDismissRequest = dropDownDismiss, - ) { + androidx.compose.material3.DropdownMenu( + expanded = showDropDown, + onDismissRequest = dropDownDismiss, + ) { - DropdownMenuItem( - onClick = { - dropDownDismiss() - scope.launch { scaffoldState.bottomSheetState.expand() } - } - ) { - Icon( - Icons.Default.Check, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.markAs)) - } + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + scope.launch { scaffoldState.bottomSheetState.expand() } + }, + text = { Text(stringResource(id = R.string.markAs)) }, + leadingIcon = { Icon(Icons.Default.Check, null) } + ) - DropdownMenuItem( + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + requireContext().openInCustomChromeBrowser(info.url) { setShareState(CustomTabsIntent.SHARE_STATE_ON) } + }, + text = { Text(stringResource(id = R.string.fallback_menu_item_open_in_browser)) }, + leadingIcon = { Icon(Icons.Default.OpenInBrowser, null) } + ) + + if (!isSaved) { + androidx.compose.material3.DropdownMenuItem( onClick = { dropDownDismiss() - requireContext().openInCustomChromeBrowser(info.url) { setShareState(CustomTabsIntent.SHARE_STATE_ON) } - } - ) { - Icon( - Icons.Default.OpenInBrowser, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.fallback_menu_item_open_in_browser)) - } - - if (!isSaved) { - DropdownMenuItem( - onClick = { - dropDownDismiss() - lifecycleScope.launch(Dispatchers.IO) { - dao.insertNotification( - NotificationItem( - id = info.hashCode(), - url = info.url, - summaryText = requireContext() - .getString( - R.string.hadAnUpdate, - info.title, - info.chapters.firstOrNull()?.name.orEmpty() - ), - notiTitle = info.title, - imageUrl = info.imageUrl, - source = info.source.serviceName, - contentTitle = info.title - ) - ).subscribe() - } + lifecycleScope.launch(Dispatchers.IO) { + dao.insertNotification( + NotificationItem( + id = info.hashCode(), + url = info.url, + summaryText = requireContext() + .getString( + R.string.hadAnUpdate, + info.title, + info.chapters.firstOrNull()?.name.orEmpty() + ), + notiTitle = info.title, + imageUrl = info.imageUrl, + source = info.source.serviceName, + contentTitle = info.title + ) + ).subscribe() } - ) { - Icon( - Icons.Default.Save, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.save_for_later)) - } - } + }, + text = { Text(stringResource(id = R.string.save_for_later)) }, + leadingIcon = { Icon(Icons.Default.Save, null) } + ) + } - DropdownMenuItem( - onClick = { - dropDownDismiss() - findNavController().navigate(GlobalNavDirections.showGlobalSearch(info.title)) - } - ) { - Icon( - Icons.Default.Search, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.global_search_by_name)) - } + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + findNavController().navigate(GlobalNavDirections.showGlobalSearch(info.title)) + }, + text = { Text(stringResource(id = R.string.global_search_by_name)) }, + leadingIcon = { Icon(Icons.Default.Search, null) } + ) - DropdownMenuItem( - onClick = { - dropDownDismiss() - reverseChapters = !reverseChapters - } - ) { - Icon( - Icons.Default.Sort, - null, - modifier = Modifier.padding(end = 8.dp) - ) - Text(stringResource(id = R.string.reverseOrder)) - } - } + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + reverseChapters = !reverseChapters + }, + text = { Text(stringResource(id = R.string.reverseOrder)) }, + leadingIcon = { Icon(Icons.Default.Sort, null) } + ) } IconButton( @@ -1084,13 +1035,18 @@ class DetailsFragment : Fragment() { .addTo(disposable) } - Surface( - onClick = { markAs(!read.fastAny { it.url == c.url }) }, - shape = RoundedCornerShape(0.dp), - indication = rememberRipple(), - modifier = Modifier.fillMaxWidth(), - color = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value ?: M3MaterialTheme.colorScheme.surface, - tonalElevation = 5.dp, + val interactionSource = remember { MutableInteractionSource() } + + androidx.compose.material3.ElevatedCard( + shape = RoundedCornerShape(2.dp), + interactionSource = interactionSource, + modifier = Modifier + .fillMaxWidth() + .clickable( + indication = rememberRipple(), + interactionSource = interactionSource, + ) { markAs(!read.fastAny { it.url == c.url }) }, + containerColor = swatchInfo.value?.rgb?.toComposeColor()?.animate()?.value ?: M3MaterialTheme.colorScheme.surface, ) { Column(modifier = Modifier.padding(16.dp)) { @@ -1455,6 +1411,7 @@ class DetailsFragment : Fragment() { } } + @OptIn(ExperimentalMaterial3Api::class) @ExperimentalFoundationApi @ExperimentalMaterialApi @Composable @@ -1468,7 +1425,7 @@ class DetailsFragment : Fragment() { Row(modifier = Modifier.padding(5.dp)) { - Card( + androidx.compose.material3.Card( shape = RoundedCornerShape(5.dp), modifier = Modifier.padding(5.dp) ) { @@ -1476,7 +1433,7 @@ class DetailsFragment : Fragment() { imageVector = Icons.Default.CloudOff, contentDescription = null, modifier = Modifier - .align(Alignment.CenterVertically) + .align(Alignment.CenterHorizontally) .placeholder(true, color = placeholderColor) .size(ComposableUtils.IMAGE_WIDTH, ComposableUtils.IMAGE_HEIGHT) ) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt index f88bd9209..46510d7cf 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt @@ -10,6 +10,7 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.compose.animation.Crossfade import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.* +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* import androidx.compose.foundation.text.KeyboardActions @@ -202,43 +203,39 @@ class GlobalSearchFragment : Fragment() { }, title = { Text(stringResource(R.string.global_search)) } ) - MdcTheme { - AutoCompleteBox( - items = history.asAutoCompleteEntities { _, _ -> true }, - itemContent = { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically - ) { - androidx.compose.material.Text( - text = it.value.searchText, - style = MaterialTheme.typography.subtitle2, - modifier = Modifier - .padding(horizontal = 16.dp, vertical = 8.dp) - .weight(.9f) - ) - androidx.compose.material.IconButton( - onClick = { scope.launch { dao.deleteHistory(it.value) } }, - modifier = Modifier.weight(.1f) - ) { androidx.compose.material.Icon(Icons.Default.Cancel, null) } - } - }, - content = { - - boxWidthPercentage = 1f - boxBorderStroke = BorderStroke(2.dp, Color.Transparent) + AutoCompleteBox( + items = history.asAutoCompleteEntities { _, _ -> true }, + trailingIcon = { + androidx.compose.material3.IconButton( + onClick = { scope.launch { dao.deleteHistory(it.value) } }, + modifier = Modifier.weight(.1f) + ) { androidx.compose.material3.Icon(Icons.Default.Cancel, null) } + }, + itemContent = { + androidx.compose.material3.Text( + text = it.value.searchText, + style = M3MaterialTheme.typography.titleSmall, + modifier = Modifier + .padding(horizontal = 16.dp, vertical = 8.dp) + .weight(.9f) + ) + }, + content = { - onItemSelected { - viewModel.searchText = it.value.searchText - filter(viewModel.searchText) - focusManager.clearFocus() - viewModel.searchForItems( - disposable = disposable, - onSubscribe = { isRefreshing = true }, - subscribe = { isRefreshing = false } - ) - } + boxWidthPercentage = 1f + boxBorderStroke = BorderStroke(2.dp, Color.Transparent) + onItemSelected { + viewModel.searchText = it.value.searchText + filter(viewModel.searchText) + focusManager.clearFocus() + viewModel.searchForItems( + disposable = disposable, + onSubscribe = { isRefreshing = true }, + subscribe = { isRefreshing = false } + ) + } + MdcTheme { OutlinedTextField( value = viewModel.searchText, onValueChange = { @@ -276,8 +273,8 @@ class GlobalSearchFragment : Fragment() { }) ) } - ) - } + } + ) } } ) { @@ -404,7 +401,8 @@ class GlobalSearchFragment : Fragment() { } else if (viewModel.searchListPublisher.isNotEmpty()) { items(viewModel.searchListPublisher) { i -> Surface( - onClick = { + interactionSource = remember { MutableInteractionSource() }, + modifier = Modifier.clickable { searchModelBottom = i scope.launch { bottomScaffold.bottomSheetState.expand() } }, @@ -477,6 +475,7 @@ class GlobalSearchFragment : Fragment() { disposable.dispose() } + @OptIn(ExperimentalMaterial3Api::class) @ExperimentalMaterialApi @Composable fun SearchCoverCard( @@ -487,16 +486,14 @@ class GlobalSearchFragment : Fragment() { onLongPress: (ComponentState) -> Unit, onClick: () -> Unit = {} ) { - Surface( + androidx.compose.material3.ElevatedCard( modifier = Modifier .size( ComposableUtils.IMAGE_WIDTH, ComposableUtils.IMAGE_HEIGHT ) .combineClickableWithIndication(onLongPress, onClick) - .then(modifier), - tonalElevation = 5.dp, - shape = MaterialTheme.shapes.medium + .then(modifier) ) { Box( modifier = Modifier.fillMaxSize(), diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt index f4a63802b..dae72cf37 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/HistoryFragment.kt @@ -9,6 +9,8 @@ import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.exponentialDecay import androidx.compose.foundation.Image import androidx.compose.foundation.background +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.foundation.shape.RoundedCornerShape @@ -275,7 +277,12 @@ class HistoryFragment : Fragment() { } Surface( - onClick = { + tonalElevation = 5.dp, + shape = MaterialTheme.shapes.medium, + modifier = Modifier.clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() }, + ) { info.toSource(item.source) ?.getSourceByUrl(item.url) ?.subscribeOn(Schedulers.io()) @@ -290,10 +297,7 @@ class HistoryFragment : Fragment() { findNavController().navigate(HistoryFragmentDirections.actionHistoryFragmentToDetailsFragment(m)) } ?.addTo(disposable) - }, - tonalElevation = 5.dp, - shape = MaterialTheme.shapes.medium, - indication = rememberRipple() + } ) { ListItem( text = { Text(item.title) }, diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt index 468581629..7f5a8ee7d 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt @@ -12,6 +12,8 @@ import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.material.icons.Icons @@ -25,7 +27,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.SmallTopAppBar -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults @@ -51,7 +52,6 @@ import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import coil.compose.rememberImagePainter -import com.google.android.material.composethemeadapter.MdcTheme import com.google.android.material.datepicker.CalendarConstraints import com.google.android.material.datepicker.DateValidatorPointForward import com.google.android.material.datepicker.MaterialDatePicker @@ -205,31 +205,30 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { trailing = { var showDropDown by remember { mutableStateOf(false) } - MdcTheme { - DropdownMenu( - expanded = showDropDown, - onDismissRequest = { showDropDown = false } - ) { - DropdownMenuItem( - onClick = { - Completable.merge( - items - .filter { it.notiTitle == item.notiTitle } - .map { - cancelNotification(it) - db.deleteNotification(it) - } - ) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - showDropDown = false - Toast.makeText(requireContext(), R.string.done, Toast.LENGTH_SHORT).show() + androidx.compose.material3.DropdownMenu( + expanded = showDropDown, + onDismissRequest = { showDropDown = false } + ) { + androidx.compose.material3.DropdownMenuItem( + text = { Text(stringResource(id = R.string.remove_same_name)) }, + onClick = { + Completable.merge( + items + .filter { it.notiTitle == item.notiTitle } + .map { + cancelNotification(it) + db.deleteNotification(it) } - .addTo(disposable) - } - ) { Text(stringResource(id = R.string.remove_same_name)) } - } + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + showDropDown = false + Toast.makeText(requireContext(), R.string.done, Toast.LENGTH_SHORT).show() + } + .addTo(disposable) + } + ) } IconButton(onClick = { showDropDown = true }) { Icon(Icons.Default.MoreVert, null) } @@ -281,6 +280,7 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { disposable.dispose() } + @OptIn(ExperimentalMaterial3Api::class) @ExperimentalMaterialApi @Composable private fun NotificationItem(item: NotificationItem, navController: NavController) { @@ -358,23 +358,27 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { } ) { - Surface( - onClick = { - genericInfo.toSource(item.source) - ?.getSourceByUrl(item.url) - ?.subscribeOn(Schedulers.io()) - ?.doOnError { context?.showErrorToast() } - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribeBy { navController.navigate(NotificationFragmentDirections.actionNotificationFragmentToDetailsFragment(it)) } - ?.addTo(disposable) - }, - tonalElevation = 5.dp, - indication = rememberRipple(), - onClickLabel = item.notiTitle, - shape = MaterialTheme.shapes.medium, - modifier = Modifier.padding(horizontal = 5.dp) - ) { + val interactionSource = remember { MutableInteractionSource() } + androidx.compose.material3.ElevatedCard( + interactionSource = interactionSource, + modifier = Modifier + .padding(horizontal = 5.dp) + .clickable( + onClickLabel = item.notiTitle, + interactionSource = interactionSource, + indication = rememberRipple() + ) { + genericInfo + .toSource(item.source) + ?.getSourceByUrl(item.url) + ?.subscribeOn(Schedulers.io()) + ?.doOnError { context?.showErrorToast() } + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeBy { navController.navigate(NotificationFragmentDirections.actionNotificationFragmentToDetailsFragment(it)) } + ?.addTo(disposable) + } + ) { Row { Image( painter = rememberImagePainter(data = item.imageUrl.orEmpty()) { @@ -410,88 +414,89 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { val dropDownDismiss = { showDropDown = false } - MdcTheme { - DropdownMenu( - expanded = showDropDown, - onDismissRequest = dropDownDismiss - ) { - DropdownMenuItem( - onClick = { - dropDownDismiss() - lifecycleScope.launch(Dispatchers.IO) { - SavedNotifications.viewNotificationFromDb(requireContext(), item, notificationLogo, genericInfo) - } + androidx.compose.material3.DropdownMenu( + expanded = showDropDown, + onDismissRequest = dropDownDismiss + ) { + androidx.compose.material3.DropdownMenuItem( + text = { Text(stringResource(R.string.notify)) }, + onClick = { + dropDownDismiss() + lifecycleScope.launch(Dispatchers.IO) { + SavedNotifications.viewNotificationFromDb(requireContext(), item, notificationLogo, genericInfo) } - ) { Text(stringResource(R.string.notify)) } - DropdownMenuItem( - onClick = { - dropDownDismiss() - val datePicker = MaterialDatePicker.Builder.datePicker() - .setTitleText(R.string.selectDate) - .setCalendarConstraints( - CalendarConstraints.Builder() - .setOpenAt(System.currentTimeMillis()) - .setValidator(DateValidatorPointForward.now()) - .build() + } + ) + androidx.compose.material3.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(requireContext())) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H ) - .setSelection(System.currentTimeMillis()) + .setHour(c[Calendar.HOUR_OF_DAY]) + .setMinute(c[Calendar.MINUTE]) .build() - datePicker.addOnPositiveButtonClickListener { - val c = Calendar.getInstance() - val timePicker = MaterialTimePicker.Builder() - .setTitleText(R.string.selectTime) - .setPositiveButtonText(R.string.ok) - .setTimeFormat( - if (DateFormat.is24HourFormat(requireContext())) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H + 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(requireContext()) + .enqueueUniqueWork( + item.notiTitle, + ExistingWorkPolicy.REPLACE, + OneTimeWorkRequestBuilder() + .setInputData( + Data.Builder() + .putString("notiData", item.toJson()) + .build() + ) + .setInitialDelay(c.timeInMillis - System.currentTimeMillis(), TimeUnit.MILLISECONDS) + .build() ) - .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(requireContext()) - .enqueueUniqueWork( - item.notiTitle, - ExistingWorkPolicy.REPLACE, - OneTimeWorkRequestBuilder() - .setInputData( - Data.Builder() - .putString("notiData", item.toJson()) - .build() - ) - .setInitialDelay(c.timeInMillis - System.currentTimeMillis(), TimeUnit.MILLISECONDS) - .build() - ) - - Toast.makeText( - requireContext(), - getString( - R.string.willNotifyAt, - requireContext().getSystemDateTimeFormat().format(c.timeInMillis) - ), - Toast.LENGTH_SHORT - ).show() - } - - timePicker.show(parentFragmentManager, "timePicker") + Toast.makeText( + requireContext(), + getString( + R.string.willNotifyAt, + requireContext().getSystemDateTimeFormat().format(c.timeInMillis) + ), + Toast.LENGTH_SHORT + ).show() } - datePicker.show(parentFragmentManager, "datePicker") - } - ) { Text(stringResource(R.string.notifyAtTime)) } - DropdownMenuItem( - onClick = { - dropDownDismiss() - showPopup = true + timePicker.show(parentFragmentManager, "timePicker") } - ) { Text(stringResource(R.string.remove)) } - } + + datePicker.show(parentFragmentManager, "datePicker") + } + ) + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + showPopup = true + }, + text = { Text(stringResource(R.string.remove)) } + ) } IconButton(onClick = { showDropDown = true }) { Icon(Icons.Default.MoreVert, null) } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 92cfdef7c..817cf9eda 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -17,12 +17,12 @@ import androidx.appcompat.app.AppCompatDelegate import androidx.compose.animation.* import androidx.compose.animation.core.* import androidx.compose.foundation.* +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* import androidx.compose.foundation.shape.CornerSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* -import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -540,6 +540,7 @@ fun BottomSheetDeleteScaffold( ) { mainView(it, listOfItems) } } +@OptIn(ExperimentalMaterial3Api::class) @ExperimentalMaterialApi @Composable private fun DeleteItemView( @@ -615,16 +616,17 @@ private fun DeleteItemView( } } ) { - androidx.compose.material3.Surface( - tonalElevation = 5.dp, - modifier = Modifier.fillMaxSize(), - shape = MaterialTheme.shapes.medium, - indication = rememberRipple(), + androidx.compose.material3.OutlinedCard( + modifier = Modifier + .fillMaxSize() + .clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() } + ) { if (item in deleteItemList) deleteItemList.remove(item) else deleteItemList.add(item) }, border = BorderStroke( animateDpAsState(targetValue = if (item in deleteItemList) 5.dp else 1.dp).value, - animateColorAsState(if (item in deleteItemList) Color(0xfff44336) else Color.Transparent).value - ), - onClick = { if (item in deleteItemList) deleteItemList.remove(item) else deleteItemList.add(item) }, + animateColorAsState(if (item in deleteItemList) Color(0xfff44336) else M3MaterialTheme.colorScheme.outline).value + ) ) { itemUi(item) } } @@ -848,14 +850,17 @@ private fun DeleteItemView( ) { androidx.compose.material3.Surface( tonalElevation = 5.dp, - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize() + .clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() } + ) { onClick(item) }, shape = MaterialTheme.shapes.medium, - indication = rememberRipple(), border = BorderStroke( animateDpAsState(targetValue = if (selectedForDeletion) 5.dp else 1.dp).value, animateColorAsState(if (selectedForDeletion) Color(0xfff44336) else Color.Transparent).value - ), - onClick = { onClick(item) }, + ) ) { itemUi(item) } } @@ -925,6 +930,8 @@ fun List.asAutoCompleteEntities(filter: CustomFilter): List AutoCompleteBox( items: List, itemContent: @Composable (T) -> Unit, + trailingIcon: (@Composable (T) -> Unit)? = null, + leadingIcon: (@Composable (T) -> Unit)? = null, content: @Composable AutoCompleteScope.() -> Unit ) { val autoCompleteState = remember { AutoCompleteState(startItems = items) } @@ -935,13 +942,20 @@ fun AutoCompleteBox( ) { autoCompleteState.content() - DropdownMenu( + androidx.compose.material3.DropdownMenu( expanded = autoCompleteState.isSearching && items.isNotEmpty(), onDismissRequest = { }, modifier = Modifier.autoComplete(autoCompleteState), properties = PopupProperties(focusable = false) ) { - items.fastForEach { item -> DropdownMenuItem(onClick = { autoCompleteState.selectItem(item) }) { itemContent(item) } } + items.fastForEach { item -> + androidx.compose.material3.DropdownMenuItem( + onClick = { autoCompleteState.selectItem(item) }, + text = { itemContent(item) }, + trailingIcon = trailingIcon?.let { { it.invoke(item) } }, + leadingIcon = leadingIcon?.let { { it.invoke(item) } } + ) + } } } } @@ -1042,40 +1056,37 @@ fun PermissionRequest(permissionsList: List, content: @Composable () -> ) } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun NeedsPermissions(onClick: () -> Unit) { Box(modifier = Modifier.fillMaxSize()) { - Card( + androidx.compose.material3.Card( modifier = Modifier .fillMaxWidth() .padding(5.dp), - elevation = 5.dp, shape = RoundedCornerShape(5.dp) ) { Column(modifier = Modifier) { - Text( + androidx.compose.material3.Text( text = stringResource(R.string.please_enable_permissions), - style = MaterialTheme.typography.h5, + style = M3MaterialTheme.typography.titleLarge, modifier = Modifier.align(Alignment.CenterHorizontally) ) - Text( + androidx.compose.material3.Text( text = stringResource(R.string.need_permissions_to_work), - style = MaterialTheme.typography.body2, - modifier = Modifier.align(Alignment.CenterHorizontally) + style = M3MaterialTheme.typography.bodyMedium, + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(horizontal = 4.dp) ) - Button( + androidx.compose.material3.Button( onClick = onClick, modifier = Modifier .align(Alignment.CenterHorizontally) .padding(bottom = 5.dp) - ) { - Text( - text = stringResource(R.string.enable), - style = MaterialTheme.typography.button - ) - } + ) { androidx.compose.material3.Text(text = stringResource(R.string.enable)) } } } } diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt index d285f3d77..1e0ae740e 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt @@ -16,6 +16,7 @@ import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material.ripple.rememberRipple +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.* import androidx.compose.runtime.rxjava2.subscribeAsState @@ -319,7 +320,8 @@ class GenericAnime(val context: Context) : GenericInfo { @OptIn( ExperimentalMaterialApi::class, ExperimentalAnimationApi::class, - ExperimentalFoundationApi::class + ExperimentalFoundationApi::class, + ExperimentalMaterial3Api::class, ) @Composable override fun ItemListView( @@ -335,16 +337,14 @@ class GenericAnime(val context: Context) : GenericInfo { verticalArrangement = Arrangement.spacedBy(4.dp) ) { items(list) { - androidx.compose.material3.Surface( + androidx.compose.material3.ElevatedCard( modifier = Modifier .fillMaxWidth() .padding(horizontal = 5.dp) .combineClickableWithIndication( onLongPress = { c -> onLongPress(it, c) }, onClick = { onClick(it) } - ), - tonalElevation = 5.dp, - shape = androidx.compose.material.MaterialTheme.shapes.medium + ) ) { ListItem( icon = { diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/ViewVideosFragment.kt b/animeworld/src/main/java/com/programmersbox/animeworld/ViewVideosFragment.kt index 167a1df23..e7c1159a7 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/ViewVideosFragment.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/ViewVideosFragment.kt @@ -14,12 +14,19 @@ import androidx.activity.compose.BackHandler import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.* +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.* import androidx.compose.material3.Button @@ -32,7 +39,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.* +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -47,9 +57,7 @@ import androidx.navigation.fragment.findNavController import com.bumptech.glide.Glide import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.google.accompanist.permissions.ExperimentalPermissionsApi -import com.google.android.material.composethemeadapter.MdcTheme -import com.programmersbox.dragswipe.* -import com.programmersbox.helpfulutils.* +import com.programmersbox.helpfulutils.stringForTime import com.programmersbox.uiviews.BaseMainActivity import com.programmersbox.uiviews.utils.* import com.skydoves.landscapist.glide.GlideImage @@ -143,6 +151,7 @@ class ViewVideosFragment : BaseBottomSheetDialogFragment() { state = state, listOfItems = items, multipleTitle = stringResource(id = R.string.delete), + deleteTitle = { it.videoName.orEmpty() }, onRemove = { itemToDelete = it showDialog.value = true @@ -311,6 +320,7 @@ class ViewVideosFragment : BaseBottomSheetDialogFragment() { } + @OptIn(ExperimentalMaterial3Api::class) @ExperimentalAnimationApi @ExperimentalMaterialApi @Composable @@ -381,29 +391,32 @@ class ViewVideosFragment : BaseBottomSheetDialogFragment() { } } ) { - Surface( - modifier = Modifier.fillMaxSize(), - indication = rememberRipple(), - onClick = { - if (MainActivity.cast.isCastActive()) { - MainActivity.cast.loadMedia( - File(item.path!!), - context?.getSharedPreferences("videos", Context.MODE_PRIVATE)?.getLong(item.assetFileStringUri, 0) ?: 0L, - null, null - ) - } else { - context?.startActivity( - Intent(context, VideoPlayerActivity::class.java).apply { - putExtra("showPath", item.assetFileStringUri) - putExtra("showName", item.videoName) - putExtra("downloadOrStream", true) - data = item.assetFileStringUri?.toUri() - } - ) + androidx.compose.material3.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) ?: 0L, + null, null + ) + } else { + context?.startActivity( + Intent(context, VideoPlayerActivity::class.java).apply { + putExtra("showPath", item.assetFileStringUri) + putExtra("showName", item.videoName) + putExtra("downloadOrStream", true) + data = item.assetFileStringUri?.toUri() + } + ) + } } - }, - shape = MaterialTheme.shapes.medium, - tonalElevation = 5.dp ) { Row { Box { @@ -474,18 +487,17 @@ class ViewVideosFragment : BaseBottomSheetDialogFragment() { val dropDownDismiss = { showDropDown = false } - MdcTheme { - DropdownMenu( - expanded = showDropDown, - onDismissRequest = dropDownDismiss - ) { - DropdownMenuItem( - onClick = { - dropDownDismiss() - showDialog.value = true - } - ) { 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) } @@ -494,5 +506,4 @@ class ViewVideosFragment : BaseBottomSheetDialogFragment() { } } } - } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 13e6bc8af..17a10948b 100644 --- a/build.gradle +++ b/build.gradle @@ -41,7 +41,7 @@ buildscript { ext.exoplayer_version = "2.16.1" ext.room_version = "2.4.1" - ext.nav_version = "2.4.0" + ext.nav_version = "2.4.1" def koin_version = "3.0.2" @@ -52,7 +52,7 @@ buildscript { ext.lottieVersion = "4.2.2" - ext.jetpack = "1.2.0-alpha02" + ext.jetpack = "1.2.0-alpha03" ext.accompanist = "0.20.3" @@ -63,14 +63,14 @@ buildscript { ext.composeFoundation = "androidx.compose.foundation:foundation:$jetpack" // Material Design ext.composeMaterial = "androidx.compose.material:material:$jetpack" - ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha04" + ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha05" // Material design icons ext.composeMaterialIconsCore = "androidx.compose.material:material-icons-core:$jetpack" ext.composeMaterialIconsExtended = "androidx.compose.material:material-icons-extended:$jetpack" // Integration with activities ext.composeActivity = 'androidx.activity:activity-compose:1.4.0' // Integration with ViewModels - ext.composeLifecycle = 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0' + ext.composeLifecycle = 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1' // Integration with observables ext.composeRuntimeLivedata = "androidx.compose.runtime:runtime-livedata:$jetpack" ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" @@ -139,7 +139,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.4' + classpath 'com.android.tools.build:gradle:7.1.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' @@ -147,7 +147,6 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files - //Note: Update this to the alpha version in order to be able to upgrade the gradle to 7.1.0 classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } } diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index c181adccd..05930d98d 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -3,7 +3,7 @@ object Deps { const val compileVersion = 31 const val minimumSdk = 23 const val targetSdk = 31 - const val buildVersion = "30.0.2" + const val buildVersion = "30.0.3" private const val jakepurple13 = "10.6.5" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a488ebd41..0e8b42da8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt index 41da8b8c4..4cee0b0be 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt @@ -14,6 +14,8 @@ import androidx.compose.animation.* import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background +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.* @@ -89,10 +91,25 @@ class DownloadViewerFragment : BaseBottomSheetDialogFragment() { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnLifecycleDestroyed(viewLifecycleOwner)) setContent { M3MaterialTheme(currentColorScheme) { - PermissionRequest(listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)) { - val context = LocalContext.current - val viewModel: DownloadViewModel = viewModel(factory = factoryCreate { DownloadViewModel(context, defaultPathname) }) - DownloadViewer(viewModel) + val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } + + Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + SmallTopAppBar( + scrollBehavior = scrollBehavior, + title = { Text(stringResource(R.string.downloaded_chapters)) }, + navigationIcon = { + IconButton(onClick = { findNavController().popBackStack() }) { Icon(Icons.Default.ArrowBack, null) } + } + ) + } + ) { p1 -> + PermissionRequest(listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)) { + val context = LocalContext.current + val viewModel: DownloadViewModel = viewModel(factory = factoryCreate { DownloadViewModel(context, defaultPathname) }) + DownloadViewer(viewModel, p1) + } } } } @@ -130,38 +147,23 @@ class DownloadViewerFragment : BaseBottomSheetDialogFragment() { @ExperimentalAnimationApi @ExperimentalMaterialApi @Composable - private fun DownloadViewer(viewModel: DownloadViewModel) { - + private fun DownloadViewer(viewModel: DownloadViewModel, p1: PaddingValues) { val fileList = viewModel.fileList - val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() } - - Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), - topBar = { - SmallTopAppBar( - scrollBehavior = scrollBehavior, - title = { Text(stringResource(R.string.downloaded_chapters)) }, - navigationIcon = { - IconButton(onClick = { findNavController().popBackStack() }) { Icon(Icons.Default.ArrowBack, null) } - } - ) - } - ) { p1 -> - val f by updateAnimatedItemsState(newList = fileList.entries.toList()) + val f by updateAnimatedItemsState(newList = fileList.entries.toList()) - if (fileList.isEmpty()) EmptyState() - else LazyColumn( - contentPadding = p1, - verticalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.padding(horizontal = 5.dp, vertical = 4.dp) - ) { - animatedItems( - f, - enterTransition = fadeIn(), - exitTransition = fadeOut() - ) { file -> ChapterItem(file) } - } + if (fileList.isEmpty()) EmptyState() + else LazyColumn( + contentPadding = p1, + verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.padding(horizontal = 5.dp, vertical = 4.dp) + ) { + //TODO: Change this to having a sticky header...same concept of animating the expand/close + animatedItems( + f, + enterTransition = fadeIn(), + exitTransition = fadeOut() + ) { file -> ChapterItem(file) } } } @@ -215,11 +217,14 @@ class DownloadViewerFragment : BaseBottomSheetDialogFragment() { verticalArrangement = Arrangement.spacedBy(4.dp) ) { androidx.compose.material3.Surface( - indication = rememberRipple(), shape = MaterialTheme.shapes.medium, tonalElevation = 4.dp, - onClick = { expanded = !expanded }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() } + ) { expanded = !expanded } ) { ListItem( modifier = Modifier.padding(5.dp), @@ -323,28 +328,31 @@ class DownloadViewerFragment : BaseBottomSheetDialogFragment() { androidx.compose.material3.Surface( shape = MaterialTheme.shapes.medium, tonalElevation = 4.dp, - indication = rememberRipple(), - onClick = { - if (runBlocking { context.useNewReaderFlow.first() }) { - findNavController() - .navigate( - ReadActivityComposeFragment::class.java.hashCode(), - Bundle().apply { - putBoolean("downloaded", true) - putSerializable("filePath", c?.chapterFolder?.let { f -> File(f) }) - }, - SettingsDsl.customAnimationOptions + modifier = Modifier + .fillMaxWidth() + .clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() } + ) { + if (runBlocking { context.useNewReaderFlow.first() }) { + 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) }) + } ) - } else { - context.startActivity( - Intent(context, ReadActivity::class.java).apply { - putExtra("downloaded", true) - putExtra("filePath", c?.chapterFolder?.let { f -> File(f) }) - } - ) + } } - }, - modifier = Modifier.fillMaxWidth() ) { ListItem( modifier = Modifier.padding(5.dp), diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt index 7b82879b3..1629ecfb8 100644 --- a/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt +++ b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt @@ -23,7 +23,8 @@ import androidx.compose.ui.util.fastAny import androidx.navigation.NavController import com.google.accompanist.placeholder.material.placeholder import com.programmersbox.favoritesdatabase.DbModel -import com.programmersbox.gsonutils.* +import com.programmersbox.gsonutils.getObject +import com.programmersbox.gsonutils.toJson import com.programmersbox.helpfulutils.defaultSharedPref import com.programmersbox.models.ApiService import com.programmersbox.models.ChapterModel @@ -164,5 +165,4 @@ class GenericNovel(val context: Context) : GenericInfo { } } } - } \ No newline at end of file From 88ac549f42133478c4a860b8496c170bdcd6bcd1 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 10 Feb 2022 08:04:58 -0500 Subject: [PATCH 031/166] - lib updates --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 17a10948b..cafcc055b 100644 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,7 @@ buildscript { ext.jetpack = "1.2.0-alpha03" - ext.accompanist = "0.20.3" + ext.accompanist = "0.23.0" ext.composeUi = "androidx.compose.ui:ui:$jetpack" // Tooling support (Previews, etc.) @@ -76,7 +76,7 @@ buildscript { ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.3" ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.3" - ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.7" + ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.8" ext.composeConstraintLayout = "androidx.constraintlayout:constraintlayout-compose:1.0.0" ext.composeAnimation = "androidx.compose.animation:animation:$jetpack" ext.materialPlaceholder = "com.google.accompanist:accompanist-placeholder-material:$accompanist" From cb9980f39a4cb7dd2a12b939b48f69ea05d7a031 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 10 Feb 2022 09:23:06 -0500 Subject: [PATCH 032/166] - lib updates --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index cafcc055b..5618683c4 100644 --- a/build.gradle +++ b/build.gradle @@ -74,8 +74,8 @@ buildscript { // Integration with observables ext.composeRuntimeLivedata = "androidx.compose.runtime:runtime-livedata:$jetpack" ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" - ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.3" - ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.3" + ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.4" + ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.4" ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.8" ext.composeConstraintLayout = "androidx.constraintlayout:constraintlayout-compose:1.0.0" ext.composeAnimation = "androidx.compose.animation:animation:$jetpack" From fffe4ba01b1258fbbac145d2dd1ddee9db2dfd5b Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 22 Feb 2022 08:45:35 -0500 Subject: [PATCH 033/166] - lib updates - added a dialog asking if the user wants to disable checking - hopefully fixed an ANR issue --- .../com/programmersbox/uiviews/AllFragment.kt | 24 +++++++------- .../uiviews/FavoriteFragment.kt | 30 +++++++----------- .../uiviews/NotificationFragment.kt | 5 ++- .../programmersbox/uiviews/RecentFragment.kt | 24 +++++++------- .../uiviews/SettingsFragment.kt | 31 +++++++++++++++++-- UIViews/src/main/res/values/strings.xml | 1 + build.gradle | 6 ++-- .../mangaworld/DownloadViewerFragment.kt | 1 - .../programmersbox/mangaworld/GenericManga.kt | 2 +- 9 files changed, 73 insertions(+), 51 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt index d7a1803f1..0683f4274 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt @@ -45,6 +45,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastMaxBy import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.fragment.findNavController import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork @@ -62,11 +63,11 @@ import com.programmersbox.sharedutils.MainLogo import com.programmersbox.uiviews.utils.* import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.Flowables import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import io.reactivex.subjects.BehaviorSubject +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import androidx.compose.material3.MaterialTheme as M3MaterialTheme @@ -98,18 +99,18 @@ class AllFragment : BaseFragmentCompose() { private val disposable: CompositeDisposable = CompositeDisposable() private val itemListener = FirebaseDb.FirebaseListener() - private val sub = Flowables.combineLatest( - itemListener.getAllShowsFlowable(), - dao.getAllFavorites() - ) { f, d -> (f + d).groupBy(DbModel::url).map { it.value.fastMaxBy(DbModel::numChapters)!! } } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - favoriteList.clear() - favoriteList.addAll(it) + init { + viewModelScope.launch { + combine( + itemListener.getAllShowsFlow(), + dao.getAllFavoritesFlow() + ) { f, d -> (f + d).groupBy(DbModel::url).map { it.value.fastMaxBy(DbModel::numChapters)!! } } + .collect { + favoriteList.clear() + favoriteList.addAll(it) + } } - init { sourcePublish .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -164,7 +165,6 @@ class AllFragment : BaseFragmentCompose() { override fun onCleared() { super.onCleared() itemListener.unregister() - sub.dispose() disposable.dispose() } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt index 28d2e6cf5..dade0efc9 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt @@ -38,6 +38,7 @@ import androidx.compose.ui.util.fastMap import androidx.compose.ui.util.fastMaxBy import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.fragment.findNavController import com.google.android.material.composethemeadapter.MdcTheme @@ -49,14 +50,12 @@ import com.programmersbox.models.ApiService import com.programmersbox.sharedutils.FirebaseDb import com.programmersbox.sharedutils.MainLogo import com.programmersbox.uiviews.utils.* -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.rxkotlin.Flowables -import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.launch import me.onebone.toolbar.CollapsingToolbarScaffold import me.onebone.toolbar.ScrollStrategy import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState import org.koin.android.ext.android.inject -import java.util.concurrent.TimeUnit import androidx.compose.material3.MaterialTheme as M3MaterialTheme class FavoriteFragment : Fragment() { @@ -77,23 +76,18 @@ class FavoriteFragment : Fragment() { var favoriteList by mutableStateOf>(emptyList()) private set - private val sub = Flowables.combineLatest( - fireListener.getAllShowsFlowable() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()), - dao.getAllFavorites() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - ) { fire, db -> (db + fire).groupBy(DbModel::url).map { it.value.fastMaxBy(DbModel::numChapters)!! } } - .replay(1) - .refCount(1, TimeUnit.SECONDS) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { favoriteList = it } + init { + viewModelScope.launch { + combine( + fireListener.getAllShowsFlow(), + dao.getAllFavoritesFlow() + ) { f, d -> (f + d).groupBy(DbModel::url).map { it.value.fastMaxBy(DbModel::numChapters)!! } } + .collect { favoriteList = it } + } + } override fun onCleared() { super.onCleared() - sub.dispose() fireListener.unregister() } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt index 7f5a8ee7d..5f5c08c09 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt @@ -71,6 +71,7 @@ import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import java.util.* @@ -98,7 +99,9 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnLifecycleDestroyed(viewLifecycleOwner)) setContent { M3MaterialTheme(currentColorScheme) { - val items by db.getAllNotificationsFlow().collectAsState(initial = emptyList()) + val items by db.getAllNotificationsFlow() + .flowOn(Dispatchers.IO) + .collectAsState(initial = emptyList()) val state = rememberBottomSheetScaffoldState() val scope = rememberCoroutineScope() diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt index 6a332ba4b..4b8b71286 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastMaxBy import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.fragment.findNavController import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork @@ -46,10 +47,10 @@ import com.programmersbox.sharedutils.MainLogo import com.programmersbox.uiviews.utils.* import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.Flowables import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import androidx.compose.material3.MaterialTheme as M3MaterialTheme @@ -81,18 +82,18 @@ class RecentFragment : BaseFragmentCompose() { private val disposable: CompositeDisposable = CompositeDisposable() private val itemListener = FirebaseDb.FirebaseListener() - private val sub = Flowables.combineLatest( - itemListener.getAllShowsFlowable(), - dao.getAllFavorites() - ) { f, d -> (f + d).groupBy(DbModel::url).map { it.value.fastMaxBy(DbModel::numChapters)!! } } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - favoriteList.clear() - favoriteList.addAll(it) + init { + viewModelScope.launch { + combine( + itemListener.getAllShowsFlow(), + dao.getAllFavoritesFlow() + ) { f, d -> (f + d).groupBy(DbModel::url).map { it.value.fastMaxBy(DbModel::numChapters)!! } } + .collect { + favoriteList.clear() + favoriteList.addAll(it) + } } - init { sourcePublish .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -133,7 +134,6 @@ class RecentFragment : BaseFragmentCompose() { override fun onCleared() { super.onCleared() itemListener.unregister() - sub.dispose() disposable.dispose() } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt index d68b6b92b..ae316a859 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt @@ -515,13 +515,38 @@ private fun AboutSettings( val aboutViewModel: AboutViewModel = viewModel() LaunchedEffect(Unit) { aboutViewModel.init(context) } + var showDialog by remember { mutableStateOf(false) } + + if (showDialog) { + AlertDialog( + onDismissRequest = { showDialog = false }, + title = { Text(stringResource(R.string.are_you_sure_stop_checking)) }, + confirmButton = { + TextButton( + onClick = { + scope.launch { + context.updatePref(SHOULD_CHECK, false) + OtakuApp.updateSetupNow(context, false) + } + showDialog = false + } + ) { Text(stringResource(R.string.yes)) } + }, + dismissButton = { TextButton(onClick = { showDialog = false }) { Text(stringResource(R.string.no)) } } + ) + } + SwitchSetting( settingTitle = { Text(stringResource(R.string.check_for_periodic_updates)) }, value = aboutViewModel.canCheck, updateValue = { - scope.launch { - context.updatePref(SHOULD_CHECK, it) - OtakuApp.updateSetupNow(context, it) + if (!it) { + showDialog = true + } else { + scope.launch { + context.updatePref(SHOULD_CHECK, it) + OtakuApp.updateSetupNow(context, it) + } } } ) diff --git a/UIViews/src/main/res/values/strings.xml b/UIViews/src/main/res/values/strings.xml index 61f8717c3..0dee92635 100644 --- a/UIViews/src/main/res/values/strings.xml +++ b/UIViews/src/main/res/values/strings.xml @@ -145,6 +145,7 @@ Search Global Search by Name Are you sure you want to delete all notifications? + Are you sure you want to not check for updates on this device? Clear Update Queue Clear queue if the update checker seems to not run consistently. Cleared diff --git a/build.gradle b/build.gradle index 5618683c4..5a1accbb3 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { ext.coroutinesAndroid = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" ext.coroutinesRX = "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$coroutinesVersion" - ext.gson = 'com.google.code.gson:gson:2.8.9' + ext.gson = 'com.google.code.gson:gson:2.9.0' ext.glideVersion = "4.13.0" ext.glide = "com.github.bumptech.glide:glide:$glideVersion" @@ -34,8 +34,8 @@ buildscript { ext.jsoup = 'org.jsoup:jsoup:1.14.3' - ext.crashlytics = 'com.google.firebase:firebase-crashlytics:18.2.7' - ext.analytics = 'com.google.firebase:firebase-analytics:20.0.2' + ext.crashlytics = 'com.google.firebase:firebase-crashlytics:18.2.8' + ext.analytics = 'com.google.firebase:firebase-analytics:20.1.0' ext.play_services = 'com.google.android.gms:play-services-auth:20.1.0' 0 ext.exoplayer_version = "2.16.1" diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt index 4cee0b0be..959444d30 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/DownloadViewerFragment.kt @@ -158,7 +158,6 @@ class DownloadViewerFragment : BaseBottomSheetDialogFragment() { verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.padding(horizontal = 5.dp, vertical = 4.dp) ) { - //TODO: Change this to having a sticky header...same concept of animating the expand/close animatedItems( f, enterTransition = fadeIn(), diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt index 7781a080e..f1b894e38 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt @@ -137,7 +137,7 @@ class GenericManga(val context: Context) : GenericInfo { override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, context: Context) { MainActivity.activity.requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) { p -> - if (p.isGranted) downloadFullChapter(model, infoModel.title) + if (p.isGranted) downloadFullChapter(model, infoModel.title.ifBlank { infoModel.url }) } } From 6c24eb3f85c9ebc1795a1eb04f916104031d672a Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 23 Feb 2022 14:44:30 -0500 Subject: [PATCH 034/166] - updated to latest libraries --- .../com/programmersbox/uiviews/utils/ComposableUtils.kt | 4 ++-- .../programmersbox/uiviews/utils/SettingsComposables.kt | 7 ++++--- build.gradle | 6 +++--- .../java/com/programmersbox/mangaworld/ReadActivity.kt | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 817cf9eda..2ebf2880e 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -481,7 +481,7 @@ fun BottomSheetDeleteScaffold( bottomBar = { BottomAppBar( contentPadding = PaddingValues(0.dp), - backgroundColor = TopAppBarDefaults.centerAlignedTopAppBarColors() + containerColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .containerColor(scrollFraction = scrollBehavior.scrollFraction).value, contentColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .titleContentColor(scrollFraction = scrollBehavior.scrollFraction).value @@ -726,7 +726,7 @@ fun BottomSheetDeleteScaffoldPaging( bottomBar = { BottomAppBar( contentPadding = PaddingValues(0.dp), - backgroundColor = TopAppBarDefaults.centerAlignedTopAppBarColors() + containerColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .containerColor(scrollFraction = scrollBehavior.scrollFraction).value, contentColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .titleContentColor(scrollFraction = scrollBehavior.scrollFraction).value diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt index bae6e446b..a45fec8ca 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/SettingsComposables.kt @@ -17,6 +17,7 @@ import androidx.compose.material3.AlertDialog import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SliderColors import androidx.compose.material3.Text import androidx.compose.material3.contentColorFor import androidx.compose.runtime.* @@ -54,7 +55,7 @@ fun defaultSwitchColors() = SwitchDefaults.colors( ) @Composable -fun defaultSliderColors() = SliderDefaults.colors( +fun defaultSliderColors() = androidx.compose.material3.SliderDefaults.colors( thumbColor = MaterialTheme.colorScheme.primary, disabledThumbColor = MaterialTheme.colorScheme.onSurface.copy(alpha = ContentAlpha.disabled) .compositeOver(MaterialTheme.colorScheme.surface), @@ -293,7 +294,7 @@ fun SliderSetting( settingSummary: (@Composable () -> Unit)? = null, range: ClosedFloatingPointRange, steps: Int = 0, - colors: SliderColors = defaultSliderColors(), + colors: SliderColors = androidx.compose.material3.SliderDefaults.colors(), format: (Float) -> String = { it.toInt().toString() }, onValueChangedFinished: (() -> Unit)? = null, updateValue: (Float) -> Unit @@ -338,7 +339,7 @@ fun SliderSetting( } } - Slider( + androidx.compose.material3.Slider( value = sliderValue, onValueChange = updateValue, onValueChangeFinished = onValueChangedFinished, diff --git a/build.gradle b/build.gradle index 5a1accbb3..63d2aa3db 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ buildscript { ext.crashlytics = 'com.google.firebase:firebase-crashlytics:18.2.8' ext.analytics = 'com.google.firebase:firebase-analytics:20.1.0' ext.play_services = 'com.google.android.gms:play-services-auth:20.1.0' -0 + ext.exoplayer_version = "2.16.1" ext.room_version = "2.4.1" @@ -52,7 +52,7 @@ buildscript { ext.lottieVersion = "4.2.2" - ext.jetpack = "1.2.0-alpha03" + ext.jetpack = "1.2.0-alpha04" ext.accompanist = "0.23.0" @@ -63,7 +63,7 @@ buildscript { ext.composeFoundation = "androidx.compose.foundation:foundation:$jetpack" // Material Design ext.composeMaterial = "androidx.compose.material:material:$jetpack" - ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha05" + ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha06" // Material design icons ext.composeMaterialIconsCore = "androidx.compose.material:material-icons-core:$jetpack" ext.composeMaterialIconsExtended = "androidx.compose.material:material-icons-extended:$jetpack" diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index 8100853f9..4e599bf23 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -1018,7 +1018,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { ) { BottomAppBar( modifier = modifier, - backgroundColor = TopAppBarDefaults.centerAlignedTopAppBarColors() + containerColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .containerColor(scrollFraction = scrollBehavior.scrollFraction).value, contentColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .titleContentColor(scrollFraction = scrollBehavior.scrollFraction).value From 97616d9b35ea0c7cd870cf87dcd4819089296970 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 24 Feb 2022 06:58:31 -0500 Subject: [PATCH 035/166] - updated to latest libraries --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 63d2aa3db..7572e4842 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { ext.gson = 'com.google.code.gson:gson:2.9.0' - ext.glideVersion = "4.13.0" + ext.glideVersion = "4.13.1" ext.glide = "com.github.bumptech.glide:glide:$glideVersion" ext.glideCompiler = "com.github.bumptech.glide:compiler:$glideVersion" @@ -139,7 +139,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.1' + classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' From 359ebfca7a698ec2939f66b2f3be9f22ef3bd109 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 24 Feb 2022 07:52:14 -0500 Subject: [PATCH 036/166] - made a visualization changes that are pretty nice. Changed MangaWorld's reader's chapter selector items to use the new NavigationDrawerItem --- .../programmersbox/mangaworld/ReadActivity.kt | 97 +++++++++++++------ .../novelworld/ReadingActivity.kt | 15 +-- 2 files changed, 72 insertions(+), 40 deletions(-) diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index 4e599bf23..bac8a57e0 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -23,18 +23,18 @@ import androidx.compose.foundation.* import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.rememberTransformableState import androidx.compose.foundation.gestures.transformable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* -import androidx.compose.material.* +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.BottomSheetScaffold +import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* +import androidx.compose.material.rememberBottomSheetScaffoldState import androidx.compose.material3.* -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -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.ExperimentalComposeUiApi @@ -45,6 +45,7 @@ import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.NestedScrollConnection @@ -58,6 +59,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp @@ -541,26 +543,17 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { ) } - Surface( - modifier = Modifier.padding(horizontal = 5.dp), - tonalElevation = 4.dp, - shape = MaterialTheme.shapes.medium, - border = BorderStroke( - 1.dp, - animateColorAsState( - if (readVm.currentChapter == i) M3MaterialTheme.colorScheme.onSurface - else M3MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f) - ).value - ) - ) { - ListItem( - text = { Text(c.name) }, - icon = if (readVm.currentChapter == i) { - { Icon(Icons.Default.ArrowRight, null) } - } else null, - modifier = Modifier.clickable { showChangeChapter = true } - ) - } + WrapHeightNavigationDrawerItem( + modifier = Modifier + .padding(bottom = 4.dp) + .padding(horizontal = 4.dp), + label = { Text(c.name) }, + selected = readVm.currentChapter == i, + onClick = { showChangeChapter = true }, + shape = RoundedCornerShape(8.0.dp)//MaterialTheme.shapes.medium + ) + + if (i < readVm.list.lastIndex) androidx.compose.material3.Divider() } } } @@ -1092,6 +1085,56 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { } } + @Composable + @ExperimentalMaterial3Api + private fun WrapHeightNavigationDrawerItem( + label: @Composable () -> Unit, + selected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, + icon: (@Composable () -> Unit)? = null, + badge: (@Composable () -> Unit)? = null, + shape: Shape = CircleShape, + colors: NavigationDrawerItemColors = NavigationDrawerItemDefaults.colors(), + interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } + ) { + Surface( + shape = shape, + color = colors.containerColor(selected).value, + interactionSource = interactionSource, + modifier = modifier + .heightIn(min = 56.dp) + .fillMaxWidth() + .selectable( + selected = selected, + onClick = onClick, + interactionSource = interactionSource, + role = Role.Tab, + indication = null + ) + ) { + Row( + Modifier.padding(start = 16.dp, end = 24.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (icon != null) { + val iconColor = colors.iconColor(selected).value + CompositionLocalProvider(androidx.compose.material3.LocalContentColor provides iconColor, content = icon) + Spacer(Modifier.width(12.dp)) + } + Box(Modifier.weight(1f)) { + val labelColor = colors.textColor(selected).value + CompositionLocalProvider(androidx.compose.material3.LocalContentColor provides labelColor, content = label) + } + if (badge != null) { + Spacer(Modifier.width(12.dp)) + val badgeColor = colors.badgeColor(selected).value + CompositionLocalProvider(androidx.compose.material3.LocalContentColor provides badgeColor, content = badge) + } + } + } + } + @ExperimentalAnimationApi @Composable private fun PageIndicator(modifier: Modifier = Modifier, currentPage: Int, pageCount: Int) { diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt b/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt index ffb82f5dd..c26eca463 100644 --- a/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt +++ b/novelworld/src/main/java/com/programmersbox/novelworld/ReadingActivity.kt @@ -36,7 +36,6 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource @@ -87,7 +86,6 @@ import kotlinx.coroutines.runBlocking import org.koin.android.ext.android.inject import kotlin.math.roundToInt import androidx.compose.material3.MaterialTheme as M3MaterialTheme -import androidx.compose.material3.contentColorFor as m3ContentColorFor class ReadingActivity : ComponentActivity() { @@ -516,7 +514,7 @@ class ReadingActivity : ComponentActivity() { .align(Alignment.BottomCenter) .alpha(1f - (animateBar / toolbarHeightPx)) .offset { IntOffset(x = 0, y = animateBar) }, - backgroundColor = TopAppBarDefaults.centerAlignedTopAppBarColors() + containerColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .containerColor(scrollFraction = contentScrollBehavior.scrollFraction).value, contentColor = TopAppBarDefaults.centerAlignedTopAppBarColors() .titleContentColor(scrollFraction = contentScrollBehavior.scrollFraction).value @@ -727,7 +725,7 @@ class ReadingActivity : ComponentActivity() { var sliderValue by remember { mutableStateOf(initialValue.toFloat()) } - Slider( + androidx.compose.material3.Slider( value = sliderValue, onValueChange = { sliderValue = it @@ -735,15 +733,6 @@ class ReadingActivity : ComponentActivity() { }, valueRange = range, steps = steps, - colors = SliderDefaults.colors( - thumbColor = M3MaterialTheme.colorScheme.primary, - disabledThumbColor = M3MaterialTheme.colorScheme.onSurface.copy(alpha = ContentAlpha.disabled) - .compositeOver(M3MaterialTheme.colorScheme.surface), - activeTrackColor = M3MaterialTheme.colorScheme.primary, - disabledActiveTrackColor = M3MaterialTheme.colorScheme.onSurface.copy(alpha = SliderDefaults.DisabledActiveTrackAlpha), - activeTickColor = m3ContentColorFor(M3MaterialTheme.colorScheme.primary) - .copy(alpha = SliderDefaults.TickAlpha) - ), modifier = Modifier.constrainAs(slider) { top.linkTo(summary.bottom) end.linkTo(value.start) From 13db1172fa7e0628587449dd5c89ac0305f2d91f Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 24 Feb 2022 12:07:33 -0500 Subject: [PATCH 037/166] - updated to latest libraries --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 7572e4842..214fc24b6 100644 --- a/build.gradle +++ b/build.gradle @@ -74,8 +74,8 @@ buildscript { // Integration with observables ext.composeRuntimeLivedata = "androidx.compose.runtime:runtime-livedata:$jetpack" ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" - ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.4" - ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.4" + ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.5" + ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.5" ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.8" ext.composeConstraintLayout = "androidx.constraintlayout:constraintlayout-compose:1.0.0" ext.composeAnimation = "androidx.compose.animation:animation:$jetpack" From b9b1bad55c347efab93d256eb61b00ef09f43008 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Fri, 25 Feb 2022 07:03:44 -0500 Subject: [PATCH 038/166] - updated to latest libraries --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 214fc24b6..d625a80ef 100644 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,7 @@ buildscript { ext.jetpack = "1.2.0-alpha04" - ext.accompanist = "0.23.0" + ext.accompanist = "0.23.1" ext.composeUi = "androidx.compose.ui:ui:$jetpack" // Tooling support (Previews, etc.) From b363e45113e451c460870516c6b26e0f69271eec Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Mon, 28 Feb 2022 06:33:50 -0500 Subject: [PATCH 039/166] - updated to latest libraries --- UIViews/build.gradle | 2 +- build.gradle | 2 +- sharedutils/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UIViews/build.gradle b/UIViews/build.gradle index c4a1a5ea7..a1c20ab3c 100644 --- a/UIViews/build.gradle +++ b/UIViews/build.gradle @@ -134,7 +134,7 @@ dependencies { implementation "com.airbnb.android:lottie-compose:$lottieVersion" implementation "com.google.accompanist:accompanist-swiperefresh:$accompanist" implementation "com.google.accompanist:accompanist-systemuicontroller:$accompanist" - implementation "me.onebone:toolbar-compose:2.3.1" + implementation "me.onebone:toolbar-compose:2.3.2" implementation 'com.github.nanihadesuka:LazyColumnScrollbar:1.0.3' implementation "androidx.paging:paging-compose:1.0.0-alpha14" diff --git a/build.gradle b/build.gradle index d625a80ef..fe22b196a 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ buildscript { ext.androidCore = 'androidx.core:core-ktx:1.7.0' ext.appCompat = 'androidx.appcompat:appcompat:1.4.1' - ext.material = 'com.google.android.material:material:1.6.0-alpha02' + ext.material = 'com.google.android.material:material:1.6.0-alpha03' ext.preference = "androidx.preference:preference-ktx:1.2.0" diff --git a/sharedutils/build.gradle b/sharedutils/build.gradle index a63c9bf96..5492f5802 100644 --- a/sharedutils/build.gradle +++ b/sharedutils/build.gradle @@ -37,7 +37,7 @@ dependencies { implementation appCompat implementation material testImplementation Deps.junit - testImplementation "com.jakewharton.picnic:picnic:0.5.0" + testImplementation "com.jakewharton.picnic:picnic:0.6.0" testImplementation 'com.lordcodes.turtle:turtle:0.6.0' androidTestImplementation Deps.androidJunit androidTestImplementation Deps.androidEspresso From 9d1d432813a8376da20615365119b112e39cd89e Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 1 Mar 2022 14:35:25 -0500 Subject: [PATCH 040/166] - small updates --- UIViews/build.gradle | 2 ++ .../programmersbox/uiviews/DetailsFragment.kt | 16 +++++++++++++++- .../com/programmersbox/uiviews/GenericInfo.kt | 2 +- .../java/com/programmersbox/uiviews/OtakuApp.kt | 14 +++++++++++++- .../programmersbox/animeworld/GenericAnime.kt | 12 ++++++------ .../programmersbox/favoritesdatabase/ItemDao.kt | 3 +++ .../programmersbox/mangaworld/GenericManga.kt | 4 ++-- .../programmersbox/mangaworld/MainActivity.kt | 6 ------ .../programmersbox/novelworld/GenericNovel.kt | 3 ++- .../otakumanager/OtakuManagerApp.kt | 3 ++- 10 files changed, 46 insertions(+), 19 deletions(-) diff --git a/UIViews/build.gradle b/UIViews/build.gradle index a1c20ab3c..c2ca223f1 100644 --- a/UIViews/build.gradle +++ b/UIViews/build.gradle @@ -143,4 +143,6 @@ dependencies { testImplementation "androidx.paging:paging-common-ktx:$paging_version" implementation datastore.datastore + + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1' } \ No newline at end of file diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index 95cea2a9a..ab24223b7 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -93,6 +93,7 @@ import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import me.onebone.toolbar.CollapsingToolbarScaffold @@ -826,6 +827,19 @@ class DetailsFragment : Fragment() { text = { Text(stringResource(id = R.string.save_for_later)) }, leadingIcon = { Icon(Icons.Default.Save, null) } ) + } else { + androidx.compose.material3.DropdownMenuItem( + onClick = { + dropDownDismiss() + lifecycleScope.launch(Dispatchers.IO) { + dao.getNotificationItemFlow(info.url) + .firstOrNull() + ?.let { dao.deleteNotification(it).subscribe() } + } + }, + text = { Text(stringResource(R.string.removeNotification)) }, + leadingIcon = { Icon(Icons.Default.Delete, null) } + ) } androidx.compose.material3.DropdownMenuItem( @@ -1180,7 +1194,7 @@ class DetailsFragment : Fragment() { if (infoModel.source.canDownload) { OutlinedButton( onClick = { - genericInfo.downloadChapter(c, chapters, infoModel, context) + genericInfo.downloadChapter(c, chapters, infoModel, this@DetailsFragment) insertRecent() if (!read.fastAny { it.url == c.url }) markAs(true) }, diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt b/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt index 0692fe465..f751e35c1 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt @@ -33,7 +33,7 @@ interface GenericInfo { fun searchList(): List = sourceList() fun toSource(s: String): ApiService? fun composeCustomPreferences(navController: NavController): ComposeSettingsDsl.() -> Unit = {} - fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, context: Context) + fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, fragment: Fragment) @Composable fun DetailActions(infoModel: InfoModel, tint: Color) = Unit diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt index 77b3dbd9f..6a9ddf6f5 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt @@ -18,20 +18,32 @@ import com.programmersbox.uiviews.utils.shouldCheckFlow import io.reactivex.plugins.RxJavaPlugins import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking +import leakcanary.LeakCanary import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.loadKoinModules import org.koin.core.context.startKoin import org.koin.dsl.module +import shark.AndroidReferenceMatchers import java.util.concurrent.TimeUnit abstract class OtakuApp : Application() { override fun onCreate() { super.onCreate() - //TODO: This acts funky if user enabled force dark mode from developer options + //This acts funky if user enabled force dark mode from developer options DynamicColors.applyToActivitiesIfAvailable(this) + LeakCanary.config = LeakCanary.config.copy( + referenceMatchers = AndroidReferenceMatchers.appDefaults + + AndroidReferenceMatchers.staticFieldLeak( + className = "com.google.firebase.auth", + fieldName = "sContext", + description = "We know about this", + patternApplies = { true } + ) + ) + if (BuildConfig.DEBUG) Stetho.initializeWithDefaults(this) Loged.FILTER_BY_PACKAGE_NAME = "programmersbox" diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt index 1e0ae740e..5791d8db9 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt @@ -121,22 +121,22 @@ class GenericAnime(val context: Context) : GenericInfo { private val fetch = Fetch.getDefaultInstance() - override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, context: Context) { + override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, fragment: Fragment) { if ((model.source as? ShowApi)?.canDownload == false) { Toast.makeText( - context, - context.getString(R.string.source_no_download, model.source.serviceName), + fragment.requireContext(), + fragment.getString(R.string.source_no_download, model.source.serviceName), Toast.LENGTH_SHORT ).show() return } - MainActivity.activity.requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) { p -> + fragment.activity?.requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) { p -> if (p.isGranted) { - Toast.makeText(context, R.string.downloading_dots_no_percent, Toast.LENGTH_SHORT).show() + Toast.makeText(fragment.requireContext(), R.string.downloading_dots_no_percent, Toast.LENGTH_SHORT).show() getEpisodes( R.string.source_no_download, model, - context, + fragment.requireContext(), { !it.link.orEmpty().endsWith(".m3u8") } ) { fetchIt(it, model) } } diff --git a/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt b/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt index b1a689641..6818679e8 100644 --- a/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt +++ b/favoritesdatabase/src/main/java/com/programmersbox/favoritesdatabase/ItemDao.kt @@ -65,6 +65,9 @@ interface ItemDao { @Query("SELECT * FROM Notifications where url = :url") fun getNotificationItem(url: String): NotificationItem + @Query("SELECT * FROM Notifications where url = :url") + fun getNotificationItemFlow(url: String): Flow + @Query("SELECT * FROM Notifications") fun getAllNotifications(): Single> diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt index f1b894e38..c08dad0eb 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt @@ -135,8 +135,8 @@ class GenericManga(val context: Context) : GenericInfo { .addTo(disposable) } - override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, context: Context) { - MainActivity.activity.requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) { p -> + override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, fragment: Fragment) { + fragment.activity?.requestPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) { p -> if (p.isGranted) downloadFullChapter(model, infoModel.title.ifBlank { infoModel.url }) } } diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt index 852526652..4eb0a0272 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/MainActivity.kt @@ -15,14 +15,8 @@ import io.reactivex.rxkotlin.addTo class MainActivity : BaseMainActivity() { - companion object { - lateinit var activity: MainActivity - } - override fun onCreate() { - activity = this - BigImageViewer.initialize(GlideImageLoader.with(applicationContext)) if (currentService == null) { diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt index 1629ecfb8..bf625a9f8 100644 --- a/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt +++ b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastAny +import androidx.fragment.app.Fragment import androidx.navigation.NavController import com.google.accompanist.placeholder.material.placeholder import com.programmersbox.favoritesdatabase.DbModel @@ -84,7 +85,7 @@ class GenericNovel(val context: Context) : GenericInfo { null } - override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, context: Context) {} + override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, fragment: Fragment) {} override val apkString: AppUpdate.AppUpdates.() -> String? get() = { novel_file } diff --git a/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt b/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt index 11c898b0e..0d0e5bc45 100644 --- a/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt +++ b/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.lazy.LazyGridState import androidx.compose.runtime.Composable +import androidx.fragment.app.Fragment import androidx.navigation.NavController import com.programmersbox.favoritesdatabase.DbModel import com.programmersbox.manga_sources.utilities.NetworkHelper @@ -72,7 +73,7 @@ val appModule = module { null } - override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, context: Context) { + override fun downloadChapter(model: ChapterModel, allChapters: List, infoModel: InfoModel, fragment: Fragment) { throw Exception("This should not be seen") } From fd7957b619aaa1e21183dd707ed4b318e3adf984 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 9 Mar 2022 16:07:12 -0500 Subject: [PATCH 041/166] - updated to latest libraries --- .idea/misc.xml | 7 +++ .../com/programmersbox/uiviews/AllFragment.kt | 2 +- .../programmersbox/uiviews/DetailsFragment.kt | 1 - .../uiviews/FavoriteFragment.kt | 6 ++- .../com/programmersbox/uiviews/GenericInfo.kt | 2 +- .../uiviews/GlobalSearchFragment.kt | 13 +++--- .../uiviews/NotificationFragment.kt | 1 - .../programmersbox/uiviews/RecentFragment.kt | 2 +- .../uiviews/utils/ComposableUtils.kt | 45 +++++++++++++++++-- .../programmersbox/animeworld/GenericAnime.kt | 13 ++++-- build.gradle | 4 +- .../programmersbox/mangaworld/GenericManga.kt | 19 ++++---- .../programmersbox/mangaworld/ReadActivity.kt | 11 ++--- .../programmersbox/novelworld/GenericNovel.kt | 16 ++++--- .../otakumanager/MainActivity.kt | 8 ++-- .../otakumanager/OtakuManagerApp.kt | 2 +- 16 files changed, 105 insertions(+), 47 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index c78004923..e5df6f961 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -41,9 +41,12 @@ + + + @@ -66,13 +69,16 @@ + + + @@ -80,6 +86,7 @@ + diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt index 0683f4274..28588aa3c 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/AllFragment.kt @@ -13,7 +13,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.rememberLazyGridState +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index ab24223b7..dd9a459e0 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -1053,7 +1053,6 @@ class DetailsFragment : Fragment() { androidx.compose.material3.ElevatedCard( shape = RoundedCornerShape(2.dp), - interactionSource = interactionSource, modifier = Modifier .fillMaxWidth() .clickable( diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt index dade0efc9..2e8ef8ac7 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/FavoriteFragment.kt @@ -11,6 +11,8 @@ import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.lazy.grid.* +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -317,11 +319,11 @@ class FavoriteFragment : Fragment() { } } else { LazyVerticalGrid( - cells = GridCells.Adaptive(ComposableUtils.IMAGE_WIDTH), + columns = adaptiveGridCell(), + state = rememberLazyGridState(), contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), - state = rememberLazyGridState() ) { items( showing diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt b/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt index f751e35c1..f38682620 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/GenericInfo.kt @@ -2,8 +2,8 @@ package com.programmersbox.uiviews import android.content.Context import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.lazy.LazyGridState import androidx.compose.foundation.lazy.LazyItemScope +import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import androidx.fragment.app.Fragment diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt index 46510d7cf..378152193 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/GlobalSearchFragment.kt @@ -10,9 +10,13 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.compose.animation.Crossfade import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.* -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +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.* @@ -315,7 +319,7 @@ class GlobalSearchFragment : Fragment() { } ) { p -> LazyVerticalGrid( - cells = GridCells.Adaptive(ComposableUtils.IMAGE_WIDTH), + columns = adaptiveGridCell(), verticalArrangement = Arrangement.spacedBy(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), contentPadding = p @@ -400,8 +404,7 @@ class GlobalSearchFragment : Fragment() { } } else if (viewModel.searchListPublisher.isNotEmpty()) { items(viewModel.searchListPublisher) { i -> - Surface( - interactionSource = remember { MutableInteractionSource() }, + androidx.compose.material3.Surface( modifier = Modifier.clickable { searchModelBottom = i scope.launch { bottomScaffold.bottomSheetState.expand() } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt index 5f5c08c09..831c25dcf 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/NotificationFragment.kt @@ -364,7 +364,6 @@ class NotificationFragment : BaseBottomSheetDialogFragment() { val interactionSource = remember { MutableInteractionSource() } androidx.compose.material3.ElevatedCard( - interactionSource = interactionSource, modifier = Modifier .padding(horizontal = 5.dp) .clickable( diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt index 4b8b71286..fb706b252 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/RecentFragment.kt @@ -10,7 +10,7 @@ import androidx.compose.animation.Crossfade import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.rememberLazyGridState +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowUpward diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 2ebf2880e..489a76a9d 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -20,6 +20,8 @@ import androidx.compose.foundation.* import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.shape.CornerSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* @@ -53,10 +55,7 @@ import androidx.compose.ui.layout.Placeable import androidx.compose.ui.platform.* import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.IntOffset -import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.* import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed import androidx.compose.ui.util.fastMap @@ -1803,4 +1802,42 @@ private suspend fun calculateAllSwatchesInImage( palette } } +} + +@Composable +fun adaptiveGridCell(): GridCells = CustomAdaptive(ComposableUtils.IMAGE_WIDTH) + +class CustomAdaptive(private val minSize: Dp) : GridCells { + init { + require(minSize > 0.dp) + } + + override fun Density.calculateCrossAxisCellSizes( + availableSize: Int, + spacing: Int + ): List { + val count = maxOf((availableSize + spacing) / (minSize.roundToPx() + spacing), 1) + 1 + return calculateCellsCrossAxisSizeImpl(availableSize, count, spacing) + } + + override fun hashCode(): Int { + return minSize.hashCode() + } + + override fun equals(other: Any?): Boolean { + return other is CustomAdaptive && minSize == other.minSize + } +} + +private fun calculateCellsCrossAxisSizeImpl( + gridSize: Int, + slotCount: Int, + spacing: Int +): List { + val gridSizeWithoutSpacing = gridSize - spacing * (slotCount - 1) + val slotSize = gridSizeWithoutSpacing / slotCount + val remainingPixels = gridSizeWithoutSpacing % slotCount + return List(slotCount) { + slotSize + if (it < remainingPixels) 1 else 0 + } } \ No newline at end of file diff --git a/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt index 5791d8db9..95e65dfa0 100644 --- a/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt +++ b/animeworld/src/main/java/com/programmersbox/animeworld/GenericAnime.kt @@ -11,11 +11,16 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material.ripple.rememberRipple +import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.* @@ -332,12 +337,12 @@ class GenericAnime(val context: Context) : GenericInfo { onClick: (ItemModel) -> Unit ) { LazyVerticalGrid( - cells = GridCells.Fixed(1), + columns = GridCells.Fixed(1), state = listState, - verticalArrangement = Arrangement.spacedBy(4.dp) + verticalArrangement = Arrangement.spacedBy(4.dp), ) { items(list) { - androidx.compose.material3.ElevatedCard( + ElevatedCard( modifier = Modifier .fillMaxWidth() .padding(horizontal = 5.dp) diff --git a/build.gradle b/build.gradle index fe22b196a..d789d7115 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ buildscript { ext.lottieVersion = "4.2.2" - ext.jetpack = "1.2.0-alpha04" + ext.jetpack = "1.2.0-alpha05" ext.accompanist = "0.23.1" @@ -63,7 +63,7 @@ buildscript { ext.composeFoundation = "androidx.compose.foundation:foundation:$jetpack" // Material Design ext.composeMaterial = "androidx.compose.material:material:$jetpack" - ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha06" + ext.materialYou = "androidx.compose.material3:material3:1.0.0-alpha07" // Material design icons ext.composeMaterialIconsCore = "androidx.compose.material:material-icons-core:$jetpack" ext.composeMaterialIconsExtended = "androidx.compose.material:material-icons-extended:$jetpack" diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt index c08dad0eb..08c618cad 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/GenericManga.kt @@ -12,10 +12,9 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.GridCells -import androidx.compose.foundation.lazy.LazyGridState -import androidx.compose.foundation.lazy.LazyVerticalGrid -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* @@ -157,10 +156,10 @@ class GenericManga(val context: Context) : GenericInfo { @Composable override fun ComposeShimmerItem() { LazyVerticalGrid( - cells = GridCells.Adaptive(ComposableUtils.IMAGE_WIDTH), + columns = adaptiveGridCell(), + modifier = Modifier.padding(vertical = 4.dp), verticalArrangement = Arrangement.spacedBy(4.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.padding(vertical = 4.dp) + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { items(10) { M3PlaceHolderCoverCard(placeHolder = R.drawable.manga_world_round_logo) } } } @@ -178,10 +177,10 @@ class GenericManga(val context: Context) : GenericInfo { ) { //TODO: See if you can modify this to perform better LazyVerticalGrid( - cells = GridCells.Adaptive(ComposableUtils.IMAGE_WIDTH), + columns = adaptiveGridCell(), + state = listState, verticalArrangement = Arrangement.spacedBy(4.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp), - state = listState + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { itemsIndexed(list, key = { i, it -> "${it.url}$i" }) { _, it -> M3CoverCard( diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index bac8a57e0..e456a22a9 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -26,6 +26,8 @@ import androidx.compose.foundation.gestures.transformable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -417,10 +419,10 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { ) { p -> if (scaffoldState.bottomSheetState.isExpanded) { LazyVerticalGrid( - cells = GridCells.Adaptive(ComposableUtils.IMAGE_WIDTH), + columns = adaptiveGridCell(), + contentPadding = p, verticalArrangement = Arrangement.spacedBy(4.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp), - contentPadding = p + horizontalArrangement = Arrangement.spacedBy(4.dp) ) { itemsIndexed(pages) { i, it -> Box( @@ -445,7 +447,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { imageModel = it, contentScale = ContentScale.Crop, loading = { - androidx.compose.material3.CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) }, modifier = Modifier .fillMaxWidth() @@ -1101,7 +1103,6 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { Surface( shape = shape, color = colors.containerColor(selected).value, - interactionSource = interactionSource, modifier = modifier .heightIn(min = 56.dp) .fillMaxWidth() diff --git a/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt index bf625a9f8..5a28b7941 100644 --- a/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt +++ b/novelworld/src/main/java/com/programmersbox/novelworld/GenericNovel.kt @@ -7,7 +7,11 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ListItem import androidx.compose.material.MaterialTheme @@ -15,6 +19,8 @@ import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.FavoriteBorder +import androidx.compose.material3.Icon +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.compositeOver @@ -133,12 +139,12 @@ class GenericNovel(val context: Context) : GenericInfo { onClick: (ItemModel) -> Unit ) { LazyVerticalGrid( - cells = GridCells.Fixed(1), + columns = GridCells.Fixed(1), state = listState, - verticalArrangement = Arrangement.spacedBy(4.dp) + verticalArrangement = Arrangement.spacedBy(4.dp), ) { items(list) { - androidx.compose.material3.Surface( + Surface( modifier = Modifier .fillMaxWidth() .padding(horizontal = 5.dp) @@ -151,7 +157,7 @@ class GenericNovel(val context: Context) : GenericInfo { ) { ListItem( icon = { - androidx.compose.material3.Icon( + Icon( if (favorites.fastAny { f -> f.url == it.url }) Icons.Default.Favorite else Icons.Default.FavoriteBorder, contentDescription = null, ) diff --git a/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt b/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt index 28ac694a2..1c49107e3 100644 --- a/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt +++ b/otakumanager/src/main/java/com/programmersbox/otakumanager/MainActivity.kt @@ -9,9 +9,10 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.GridCells import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardActions @@ -310,9 +311,8 @@ class MainActivity : ComponentActivity() { else -> { LazyVerticalGrid( - cells = GridCells.Adaptive(ComposableUtils.IMAGE_WIDTH), + columns = GridCells.Adaptive(ComposableUtils.IMAGE_WIDTH), contentPadding = it, - //state = rememberLazyListState() ) { items( showing diff --git a/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt b/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt index 0d0e5bc45..cd49caa3e 100644 --- a/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt +++ b/otakumanager/src/main/java/com/programmersbox/otakumanager/OtakuManagerApp.kt @@ -2,7 +2,7 @@ package com.programmersbox.otakumanager import android.content.Context import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.lazy.LazyGridState +import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable import androidx.fragment.app.Fragment import androidx.navigation.NavController From 44d1e1fa1982c6ee246cad1c98a2236d2e27c974 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Thu, 10 Mar 2022 06:23:18 -0500 Subject: [PATCH 042/166] - updated to latest libraries --- .../java/com/programmersbox/otakuworld/DialogScreens.kt | 7 ++++--- build.gradle | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt index f2dc19c98..17a8fb2c2 100644 --- a/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt +++ b/app/src/main/java/com/programmersbox/otakuworld/DialogScreens.kt @@ -465,7 +465,7 @@ fun PagerView(closeClick: () -> Unit) { ) } - DropdownMenu( + androidx.compose.material3.DropdownMenu( expanded = showPopup && popUpOrDialog, onDismissRequest = { showPopup = false }, modifier = Modifier @@ -473,12 +473,13 @@ fun PagerView(closeClick: () -> Unit) { .border(1.dp, MaterialTheme.colorScheme.outline) ) { optionsList.value.forEachIndexed { index, settingLocation -> - DropdownMenuItem( + androidx.compose.material3.DropdownMenuItem( onClick = { dropDownSetting = settingLocation showPopup = false }, - ) { Text(settingLocation.toString()) } + text = { androidx.compose.material3.Text(settingLocation.toString()) } + ) if (index < optionsList.value.size - 1) androidx.compose.material3.Divider(color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)) } diff --git a/build.gradle b/build.gradle index d789d7115..6d04abef6 100644 --- a/build.gradle +++ b/build.gradle @@ -76,7 +76,7 @@ buildscript { ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.5" ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.5" - ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.8" + ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.9" ext.composeConstraintLayout = "androidx.constraintlayout:constraintlayout-compose:1.0.0" ext.composeAnimation = "androidx.compose.animation:animation:$jetpack" ext.materialPlaceholder = "com.google.accompanist:accompanist-placeholder-material:$accompanist" From becfca577e577e055bafc8a28d7fab9a509e9c2f Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Fri, 11 Mar 2022 07:00:38 -0500 Subject: [PATCH 043/166] - added a retry option on for the ReadActivity.kt if loading the image fails --- .../programmersbox/mangaworld/ReadActivity.kt | 62 ++++++++++++------- mangaworld/src/main/res/values/strings.xml | 1 + 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index e456a22a9..5c2fa0d42 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -116,13 +116,10 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.subscribeBy import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.* import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import org.koin.android.ext.android.inject import java.io.File import kotlin.math.roundToInt @@ -894,25 +891,44 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { ) } ) { - GlideImage( - imageModel = painter, - contentScale = ContentScale.FillWidth, - loading = { - androidx.compose.material3.CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) - }, - modifier = Modifier - .fillMaxSize() - .heightIn(min = ComposableUtils.IMAGE_HEIGHT) - .align(Alignment.Center) - .clipToBounds() - .graphicsLayer { - translationX = offset.x - translationY = offset.y - - scaleX = scaleAnim - scaleY = scaleAnim - } - ) + + val scope = rememberCoroutineScope() + var showTheThing by remember { mutableStateOf(true) } + + if (showTheThing) + GlideImage( + imageModel = painter, + contentScale = ContentScale.FillWidth, + loading = { + androidx.compose.material3.CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + }, + failure = { + Text( + stringResource(R.string.pressToRefresh), + modifier = Modifier + .align(Alignment.Center) + .clickable { + scope.launch { + showTheThing = false + delay(1000) + showTheThing = true + } + } + ) + }, + modifier = Modifier + .fillMaxSize() + .heightIn(min = ComposableUtils.IMAGE_HEIGHT) + .align(Alignment.Center) + .clipToBounds() + .graphicsLayer { + translationX = offset.x + translationY = offset.y + + scaleX = scaleAnim + scaleY = scaleAnim + } + ) } } diff --git a/mangaworld/src/main/res/values/strings.xml b/mangaworld/src/main/res/values/strings.xml index 7024d2003..ef68abb65 100644 --- a/mangaworld/src/main/res/values/strings.xml +++ b/mangaworld/src/main/res/values/strings.xml @@ -23,4 +23,5 @@ Reader Settings Change to %s Double Tap to Reset + Press to Refresh \ No newline at end of file From 63dde1e4d6216e744f500ae7b404574180f5e2e9 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Mon, 14 Mar 2022 08:36:02 -0400 Subject: [PATCH 044/166] - updated to latest libraries - added two broadcast receiver compose functions --- UIViews/build.gradle | 2 +- .../uiviews/utils/ComposableUtils.kt | 52 +++++++++++++++++++ build.gradle | 2 +- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/UIViews/build.gradle b/UIViews/build.gradle index c2ca223f1..0cd001348 100644 --- a/UIViews/build.gradle +++ b/UIViews/build.gradle @@ -134,7 +134,7 @@ dependencies { implementation "com.airbnb.android:lottie-compose:$lottieVersion" implementation "com.google.accompanist:accompanist-swiperefresh:$accompanist" implementation "com.google.accompanist:accompanist-systemuicontroller:$accompanist" - implementation "me.onebone:toolbar-compose:2.3.2" + implementation "me.onebone:toolbar-compose:2.3.3" implementation 'com.github.nanihadesuka:LazyColumnScrollbar:1.0.3' implementation "androidx.paging:paging-compose:1.0.0-alpha14" diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt index 489a76a9d..ca6f4d58f 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/utils/ComposableUtils.kt @@ -2,8 +2,10 @@ package com.programmersbox.uiviews.utils import android.app.Activity import android.app.Dialog +import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.content.IntentFilter import android.net.Uri import android.os.Build import android.os.Bundle @@ -1840,4 +1842,54 @@ private fun calculateCellsCrossAxisSizeImpl( return List(slotCount) { slotSize + if (it < remainingPixels) 1 else 0 } +} + +/** + * Registers a broadcast receiver and unregisters at the end of the composable lifecycle + * + * @param defaultValue the default value that this starts as + * @param intentFilter the filter for intents + * @see IntentFilter + * @param tick the callback from the broadcast receiver + */ +@Composable +fun broadcastReceiver(defaultValue: T, intentFilter: IntentFilter, tick: (context: Context, intent: Intent) -> T): State { + val item: MutableState = remember { mutableStateOf(defaultValue) } + val context = LocalContext.current + + DisposableEffect(context) { + val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + item.value = tick(context, intent) + } + } + context.registerReceiver(receiver, intentFilter) + onDispose { context.unregisterReceiver(receiver) } + } + return item +} + +/** + * Registers a broadcast receiver and unregisters at the end of the composable lifecycle + * + * @param defaultValue the default value that this starts as + * @param intentFilter the filter for intents. + * @see IntentFilter + * @param tick the callback from the broadcast receiver + */ +@Composable +fun broadcastReceiverNullable(defaultValue: T?, intentFilter: IntentFilter, tick: (context: Context, intent: Intent) -> T?): State { + val item: MutableState = remember { mutableStateOf(defaultValue) } + val context = LocalContext.current + + DisposableEffect(context) { + val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + item.value = tick(context, intent) + } + } + context.registerReceiver(receiver, intentFilter) + onDispose { context.unregisterReceiver(receiver) } + } + return item } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 6d04abef6..a8f719ea9 100644 --- a/build.gradle +++ b/build.gradle @@ -76,7 +76,7 @@ buildscript { ext.composeRuntimeRxjava2 = "androidx.compose.runtime:runtime-rxjava2:$jetpack" ext.composeMaterialThemeAdapter = "com.google.android.material:compose-theme-adapter:1.1.5" ext.composeMaterial3ThemeAdapter = "com.google.android.material:compose-theme-adapter-3:1.0.5" - ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.4.9" + ext.landscapistGlide = "com.github.skydoves:landscapist-glide:1.5.0" ext.composeConstraintLayout = "androidx.constraintlayout:constraintlayout-compose:1.0.0" ext.composeAnimation = "androidx.compose.animation:animation:$jetpack" ext.materialPlaceholder = "com.google.accompanist:accompanist-placeholder-material:$accompanist" From c38341a6acf48dc33e506a32f6f7e55abe66df0d Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Fri, 18 Mar 2022 09:43:53 -0400 Subject: [PATCH 045/166] - added machine learning translation kit to translate some descriptions that aren't in english --- UIViews/build.gradle | 3 +- .../programmersbox/uiviews/DetailsFragment.kt | 122 +++++++++++++++--- .../com/programmersbox/uiviews/OtakuApp.kt | 11 -- mangaworld/build.gradle | 1 - 4 files changed, 109 insertions(+), 28 deletions(-) diff --git a/UIViews/build.gradle b/UIViews/build.gradle index 0cd001348..1d8d3a681 100644 --- a/UIViews/build.gradle +++ b/UIViews/build.gradle @@ -144,5 +144,6 @@ dependencies { implementation datastore.datastore - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1' + implementation 'com.google.mlkit:translate:17.0.0' + implementation 'com.google.mlkit:language-id:17.0.3' } \ No newline at end of file diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index dd9a459e0..54f038e6a 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -73,6 +73,12 @@ import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.google.accompanist.placeholder.material.placeholder import com.google.accompanist.systemuicontroller.rememberSystemUiController +import com.google.mlkit.common.model.DownloadConditions +import com.google.mlkit.nl.languageid.LanguageIdentification +import com.google.mlkit.nl.translate.TranslateLanguage +import com.google.mlkit.nl.translate.Translation +import com.google.mlkit.nl.translate.Translator +import com.google.mlkit.nl.translate.TranslatorOptions import com.programmersbox.favoritesdatabase.* import com.programmersbox.helpfulutils.colorFromTheme import com.programmersbox.models.ChapterModel @@ -209,6 +215,7 @@ class DetailsFragment : Fragment() { details.info!!, details.chapters, details.favoriteListener, + details, isSaved, shareChapter, swatchInfo @@ -237,6 +244,8 @@ class DetailsFragment : Fragment() { var favoriteListener by mutableStateOf(false) var chapters: List by mutableStateOf(emptyList()) + var description: String by mutableStateOf("") + private val itemSub = itemModel ?.toInfoModel() ?.doOnError { context.showErrorToast() } @@ -244,9 +253,74 @@ class DetailsFragment : Fragment() { ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribeBy { info = it + description = it.description setup(it) } + private var englishTranslator: Translator? = null + + fun translateDescription(progress: MutableState) { + progress.value = true + val languageIdentifier = LanguageIdentification.getClient() + languageIdentifier.identifyLanguage(info!!.description) + .addOnSuccessListener { languageCode -> + if (languageCode == "und") { + println("Can't identify language.") + } else if (languageCode != "en") { + println("Language: $languageCode") + + if (englishTranslator == null) { + val options = TranslatorOptions.Builder() + .setSourceLanguage(TranslateLanguage.fromLanguageTag(languageCode)!!) + .setTargetLanguage(TranslateLanguage.ENGLISH) + .build() + englishTranslator = Translation.getClient(options) + + val conditions = DownloadConditions.Builder() + .requireWifi() + .build() + + englishTranslator!!.downloadModelIfNeeded(conditions) + .addOnSuccessListener { _ -> + // Model downloaded successfully. Okay to start translating. + // (Set a flag, unhide the translation UI, etc.) + englishTranslator!!.translate(info!!.description) + .addOnSuccessListener { translated -> + // Model downloaded successfully. Okay to start translating. + // (Set a flag, unhide the translation UI, etc.) + + description = translated + progress.value = false + } + } + .addOnFailureListener { exception -> + // Model couldn’t be downloaded or other internal error. + // ... + progress.value = false + } + } else { + englishTranslator!!.translate(info!!.description) + .addOnSuccessListener { translated -> + // Model downloaded successfully. Okay to start translating. + // (Set a flag, unhide the translation UI, etc.) + + description = translated + progress.value = false + } + .addOnFailureListener { progress.value = false } + } + + } else { + progress.value = false + } + } + .addOnFailureListener { + // Model couldn’t be loaded or other internal error. + // ... + progress.value = false + } + } + private fun setup(info: InfoModel) { viewModelScope.launch(Dispatchers.IO) { combine( @@ -272,6 +346,7 @@ class DetailsFragment : Fragment() { disposable.dispose() itemListener.unregister() chapterListener.unregister() + englishTranslator?.close() } } @@ -628,6 +703,7 @@ class DetailsFragment : Fragment() { info: InfoModel, chapters: List, favoriteListener: Boolean, + details: DetailViewModel, isSaved: Boolean, shareChapter: Boolean, swatchInfo: MutableState @@ -968,21 +1044,37 @@ class DetailsFragment : Fragment() { if (info.description.isNotEmpty()) { item { - Text( - info.description, - modifier = Modifier - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple() - ) { descriptionVisibility = !descriptionVisibility } - .padding(horizontal = 5.dp) - .fillMaxWidth() - .animateContentSize(), - overflow = TextOverflow.Ellipsis, - maxLines = if (descriptionVisibility) Int.MAX_VALUE else 3, - style = M3MaterialTheme.typography.bodyMedium, - color = M3MaterialTheme.colorScheme.onSurface - ) + Box { + val progress = remember { mutableStateOf(false) } + + Text( + details.description,//info.description, + modifier = Modifier + .combinedClickable( + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple(), + onClick = { descriptionVisibility = !descriptionVisibility }, + onLongClick = { details.translateDescription(progress) } + ) + /*.clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = rememberRipple() + ) { descriptionVisibility = !descriptionVisibility }*/ + .padding(horizontal = 5.dp) + .fillMaxWidth() + .animateContentSize(), + overflow = TextOverflow.Ellipsis, + maxLines = if (descriptionVisibility) Int.MAX_VALUE else 3, + style = M3MaterialTheme.typography.bodyMedium, + color = M3MaterialTheme.colorScheme.onSurface + ) + + if (progress.value) { + androidx.compose.material3.CircularProgressIndicator( + modifier = Modifier.align(Alignment.Center) + ) + } + } } } diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt index 6a9ddf6f5..89a090a90 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/OtakuApp.kt @@ -18,13 +18,11 @@ import com.programmersbox.uiviews.utils.shouldCheckFlow import io.reactivex.plugins.RxJavaPlugins import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking -import leakcanary.LeakCanary import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.loadKoinModules import org.koin.core.context.startKoin import org.koin.dsl.module -import shark.AndroidReferenceMatchers import java.util.concurrent.TimeUnit abstract class OtakuApp : Application() { @@ -34,15 +32,6 @@ abstract class OtakuApp : Application() { //This acts funky if user enabled force dark mode from developer options DynamicColors.applyToActivitiesIfAvailable(this) - LeakCanary.config = LeakCanary.config.copy( - referenceMatchers = AndroidReferenceMatchers.appDefaults + - AndroidReferenceMatchers.staticFieldLeak( - className = "com.google.firebase.auth", - fieldName = "sContext", - description = "We know about this", - patternApplies = { true } - ) - ) if (BuildConfig.DEBUG) Stetho.initializeWithDefaults(this) diff --git a/mangaworld/build.gradle b/mangaworld/build.gradle index 0f79b7634..7dddfbb68 100644 --- a/mangaworld/build.gradle +++ b/mangaworld/build.gradle @@ -116,5 +116,4 @@ dependencies { implementation datastore.datastore - //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8' } \ No newline at end of file From e274dec618b0f6ef7eb0f2e3acf16f73cf1905c9 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Fri, 18 Mar 2022 12:20:16 -0400 Subject: [PATCH 046/166] - added a way for users to delete models since they take up around 30mb --- .../programmersbox/uiviews/DetailsFragment.kt | 6 +- .../uiviews/SettingsFragment.kt | 56 +++++++++++++++++++ UIViews/src/main/res/values/strings.xml | 3 + 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index 54f038e6a..3d9fb2a32 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -1048,7 +1048,7 @@ class DetailsFragment : Fragment() { val progress = remember { mutableStateOf(false) } Text( - details.description,//info.description, + details.description, modifier = Modifier .combinedClickable( interactionSource = remember { MutableInteractionSource() }, @@ -1056,10 +1056,6 @@ class DetailsFragment : Fragment() { onClick = { descriptionVisibility = !descriptionVisibility }, onLongClick = { details.translateDescription(progress) } ) - /*.clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = rememberRipple() - ) { descriptionVisibility = !descriptionVisibility }*/ .padding(horizontal = 5.dp) .fillMaxWidth() .animateContentSize(), diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt index ae316a859..840c6fcfd 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/SettingsFragment.kt @@ -58,6 +58,8 @@ import coil.transform.CircleCropTransformation import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.firebase.auth.FirebaseAuth import com.google.firebase.auth.FirebaseUser +import com.google.mlkit.common.model.RemoteModelManager +import com.google.mlkit.nl.translate.TranslateRemoteModel import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.LibsBuilder import com.programmersbox.favoritesdatabase.HistoryDatabase @@ -83,6 +85,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.koin.android.ext.android.inject import java.io.File +import java.util.* class SettingsDsl { companion object { @@ -279,6 +282,7 @@ fun SettingScreen( context = context, scope = scope, activity = activity, + fragment = fragment, genericInfo = genericInfo, customSettings = customPreferences.generalSettings, globalSearchClick = globalSearchClick @@ -715,12 +719,15 @@ private fun GeneralSettings( context: Context, scope: CoroutineScope, activity: ComponentActivity, + fragment: Fragment, genericInfo: GenericInfo, customSettings: (@Composable () -> Unit)?, globalSearchClick: () -> Unit ) { CategorySetting { Text(stringResource(R.string.general_menu_title)) } + val vm: GeneralViewModel = viewModel() + val source: ApiService? by sourcePublish.subscribeAsState(initial = null) DynamicListSetting( @@ -757,6 +764,33 @@ private fun GeneralSettings( } ) + PreferenceSetting( + settingTitle = { Text(stringResource(R.string.viewTranslationModels)) }, + settingIcon = { Icon(Icons.Default.Language, null, modifier = Modifier.fillMaxSize()) }, + modifier = Modifier.clickable( + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() }, + onClick = { + vm.getModels { + ListBottomSheet( + title = fragment.getString(R.string.chooseModelToDelete), + list = vm.translationModels.toList(), + onClick = { item -> vm.deleteModel(item) } + ) { + ListBottomSheetItemModel( + primaryText = it.language, + overlineText = try { + Locale.forLanguageTag(it.language).displayLanguage + } catch (e: Exception) { + null + } + ) + }.show(fragment.parentFragmentManager, "sourceChooser") + } + } + ) + ) + PreferenceSetting( settingTitle = { Text(stringResource(R.string.global_search)) }, settingIcon = { Icon(Icons.Default.Search, null, modifier = Modifier.fillMaxSize()) }, @@ -825,6 +859,28 @@ private fun GeneralSettings( customSettings?.invoke() } +class GeneralViewModel : ViewModel() { + + var translationModels: Set by mutableStateOf(emptySet()) + private set + + private val modelManager by lazy { RemoteModelManager.getInstance() } + + fun getModels(onSuccess: () -> Unit) { + modelManager.getDownloadedModels(TranslateRemoteModel::class.java) + .addOnSuccessListener { models -> + translationModels = models + onSuccess() + } + .addOnFailureListener { } + } + + fun deleteModel(model: TranslateRemoteModel) { + modelManager.deleteDownloadedModel(model).addOnSuccessListener {} + } + +} + @ExperimentalMaterialApi @Composable private fun PlaySettings(context: Context, scope: CoroutineScope, customSettings: (@Composable () -> Unit)?) { diff --git a/UIViews/src/main/res/values/strings.xml b/UIViews/src/main/res/values/strings.xml index 0dee92635..ff5a5cc6e 100644 --- a/UIViews/src/main/res/values/strings.xml +++ b/UIViews/src/main/res/values/strings.xml @@ -174,4 +174,7 @@ Select Time to be Notified At Notify At… Will Notify at %s + + View Translation Models + Choose a Model to Delete \ No newline at end of file From 13d5d4b22fb8e2fcf7e96ce2718f396370281ab1 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Mon, 21 Mar 2022 07:42:01 -0400 Subject: [PATCH 047/166] - updated libs --- build.gradle | 2 +- mangaworld/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a8f719ea9..a54c5faea 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ buildscript { ext.play_services = 'com.google.android.gms:play-services-auth:20.1.0' ext.exoplayer_version = "2.16.1" - ext.room_version = "2.4.1" + ext.room_version = "2.4.2" ext.nav_version = "2.4.1" diff --git a/mangaworld/build.gradle b/mangaworld/build.gradle index 7dddfbb68..60dc3e98c 100644 --- a/mangaworld/build.gradle +++ b/mangaworld/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation firebaseCrash.crash implementation 'com.github.hedzr:android-file-chooser:v1.2.0-final' - implementation "com.anggrayudi:storage:1.1.0" + implementation "com.anggrayudi:storage:1.2.0" implementation 'de.helmbold:rxfilewatcher:1.0.0' implementation project(':UIViews') From f6ef3665cf839e1075d1789eea421f04ecc1d772 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Mon, 21 Mar 2022 08:37:59 -0400 Subject: [PATCH 048/166] - updated libs --- mangaworld/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangaworld/build.gradle b/mangaworld/build.gradle index 60dc3e98c..e35940f64 100644 --- a/mangaworld/build.gradle +++ b/mangaworld/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation firebaseCrash.crash implementation 'com.github.hedzr:android-file-chooser:v1.2.0-final' - implementation "com.anggrayudi:storage:1.2.0" + implementation "com.anggrayudi:storage:1.2.1" implementation 'de.helmbold:rxfilewatcher:1.0.0' implementation project(':UIViews') From 647bd6a48b09f218aab7baff2e4a53950b4b2363 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 22 Mar 2022 08:44:32 -0400 Subject: [PATCH 049/166] - added some build types for organization. Using easylauncher to tag the icons with a ribbon --- animeworld/build.gradle | 5 ++++- buildtypes.gradle | 22 ++++++++++++++++++++++ mangaworld/build.gradle | 5 ++++- novelworld/build.gradle | 5 ++++- 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 buildtypes.gradle diff --git a/animeworld/build.gradle b/animeworld/build.gradle index e48abb72f..a7c0b954b 100644 --- a/animeworld/build.gradle +++ b/animeworld/build.gradle @@ -6,6 +6,7 @@ plugins { id 'com.google.gms.google-services' id 'com.google.firebase.crashlytics' id 'com.mikepenz.aboutlibraries.plugin' + id "com.starter.easylauncher" version "5.0.1" } android { @@ -131,4 +132,6 @@ dependencies { implementation datastore.datastore //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8' -} \ No newline at end of file +} + +apply from: "$rootDir/buildtypes.gradle" \ No newline at end of file diff --git a/buildtypes.gradle b/buildtypes.gradle new file mode 100644 index 000000000..7e2104cd5 --- /dev/null +++ b/buildtypes.gradle @@ -0,0 +1,22 @@ +android { + buildTypes { + beta { + initWith debug + matchingFallbacks = ['debug', 'release'] + debuggable false + } + } + + easylauncher { + defaultFlavorNaming true + buildTypes { + debug { + filters blueRibbonFilter() + } + beta { + enable true + filters blueRibbonFilter() + } + } + } +} \ No newline at end of file diff --git a/mangaworld/build.gradle b/mangaworld/build.gradle index e35940f64..a1637ea21 100644 --- a/mangaworld/build.gradle +++ b/mangaworld/build.gradle @@ -6,6 +6,7 @@ plugins { id 'com.google.gms.google-services' id 'com.google.firebase.crashlytics' id 'com.mikepenz.aboutlibraries.plugin' + id "com.starter.easylauncher" version "5.0.1" } android { @@ -116,4 +117,6 @@ dependencies { implementation datastore.datastore -} \ No newline at end of file +} + +apply from: "$rootDir/buildtypes.gradle" \ No newline at end of file diff --git a/novelworld/build.gradle b/novelworld/build.gradle index 04baac985..9d7cd4d6e 100644 --- a/novelworld/build.gradle +++ b/novelworld/build.gradle @@ -6,6 +6,7 @@ plugins { id 'com.google.gms.google-services' id 'com.google.firebase.crashlytics' id 'com.mikepenz.aboutlibraries.plugin' + id "com.starter.easylauncher" version "5.0.1" } android { @@ -92,4 +93,6 @@ dependencies { implementation koin.koin //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8' -} \ No newline at end of file +} + +apply from: "$rootDir/buildtypes.gradle" \ No newline at end of file From b0c342e6342813243746191f3db47b67aba7cfa3 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 22 Mar 2022 08:52:55 -0400 Subject: [PATCH 050/166] - removed ribbon for beta --- buildtypes.gradle | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/buildtypes.gradle b/buildtypes.gradle index 7e2104cd5..51be18537 100644 --- a/buildtypes.gradle +++ b/buildtypes.gradle @@ -10,13 +10,8 @@ android { easylauncher { defaultFlavorNaming true buildTypes { - debug { - filters blueRibbonFilter() - } - beta { - enable true - filters blueRibbonFilter() - } + debug { filters blueRibbonFilter() } + beta { enable false } } } } \ No newline at end of file From 9c570c28f6b8964c07515f55e456e8ed4694d840 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Tue, 22 Mar 2022 10:47:28 -0400 Subject: [PATCH 051/166] - only show ads in mangaworld in the release build so we don't accidentally press on them --- .../main/java/com/programmersbox/mangaworld/ReadActivity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index 5c2fa0d42..cf397a7fb 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -398,7 +398,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { ) }, bottomBar = { - if (!BuildConfig.DEBUG) { + if (BuildConfig.BUILD_TYPE == "release") { AndroidView( modifier = Modifier .fillMaxWidth() @@ -497,7 +497,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { ) }, bottomBar = { - if (!BuildConfig.DEBUG) { + if (BuildConfig.BUILD_TYPE == "release") { AndroidView( modifier = Modifier .fillMaxWidth() @@ -805,7 +805,7 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { .align(Alignment.CenterHorizontally) ) } - if (!BuildConfig.DEBUG) { + if (BuildConfig.BUILD_TYPE == "release") { AndroidView( modifier = Modifier.fillMaxWidth(), factory = { From d53f74f992ea2de357df080b0629de9c40ce7877 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 23 Mar 2022 08:29:56 -0400 Subject: [PATCH 052/166] - made the top bar scroll up and down on scroll --- .../main/java/com/programmersbox/mangaworld/ReadActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt index cf397a7fb..86a4521dd 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/ReadActivity.kt @@ -658,7 +658,8 @@ class ReadActivityComposeFragment : BaseBottomSheetDialogFragment() { modifier = Modifier .height(topBarHeight) .align(Alignment.TopCenter) - .alpha(animateTopBar), + .alpha(animateTopBar) + .offset { IntOffset(x = 0, y = if (showItems) 0 else (topBarOffsetHeightPx.value.roundToInt())) }, pages = pages, currentPage = currentPage, vm = readVm From 597a139835ef0060f9269c5e84234215280f8d79 Mon Sep 17 00:00:00 2001 From: jakepurple13 Date: Wed, 23 Mar 2022 09:03:08 -0400 Subject: [PATCH 053/166] - fixed bug where status bar icons wouldn't update to the correct color --- .../programmersbox/uiviews/DetailsFragment.kt | 30 +++++++++++++++---- .../src/main/res/values-night-v31/themes.xml | 1 + UIViews/src/main/res/values-night/themes.xml | 1 + UIViews/src/main/res/values-v31/themes.xml | 1 + UIViews/src/main/res/values/themes.xml | 1 + 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt index 3d9fb2a32..a03b88224 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/DetailsFragment.kt @@ -4,10 +4,12 @@ import android.animation.ValueAnimator import android.content.Context import android.content.Intent import android.content.res.Configuration +import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.WindowInsetsController import androidx.activity.compose.BackHandler import androidx.browser.customtabs.CustomTabsIntent import androidx.compose.animation.ExperimentalAnimationApi @@ -40,10 +42,7 @@ import androidx.compose.runtime.rxjava2.subscribeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.compositeOver -import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.graphics.* import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.ComposeView @@ -62,6 +61,7 @@ import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.zIndex import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension +import androidx.core.animation.doOnEnd import androidx.core.graphics.ColorUtils import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel @@ -1630,7 +1630,27 @@ class DetailsFragment : Fragment() { disposable.dispose() val window = requireActivity().window ValueAnimator.ofArgb(window.statusBarColor, requireContext().colorFromTheme(R.attr.colorSurface)) - .apply { addUpdateListener { window.statusBarColor = it.animatedValue as Int } } + .apply { + addUpdateListener { window.statusBarColor = it.animatedValue as Int } + doOnEnd { + val isLightStatusBar = window.statusBarColor.toComposeColor().luminance() > .5f + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val systemUiAppearance = if (isLightStatusBar) { + WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS + } else { + 0 + } + window.insetsController?.setSystemBarsAppearance(systemUiAppearance, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS) + } else { + val systemUiVisibilityFlags = if (isLightStatusBar) { + window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } else { + window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() + } + window.decorView.systemUiVisibility = systemUiVisibilityFlags + } + } + } .start() } diff --git a/UIViews/src/main/res/values-night-v31/themes.xml b/UIViews/src/main/res/values-night-v31/themes.xml index dbe9265dc..c1cf051d8 100644 --- a/UIViews/src/main/res/values-night-v31/themes.xml +++ b/UIViews/src/main/res/values-night-v31/themes.xml @@ -13,5 +13,6 @@ ?attr/colorSurface + false \ No newline at end of file diff --git a/UIViews/src/main/res/values-night/themes.xml b/UIViews/src/main/res/values-night/themes.xml index c944a5e90..646c7e3e4 100644 --- a/UIViews/src/main/res/values-night/themes.xml +++ b/UIViews/src/main/res/values-night/themes.xml @@ -12,5 +12,6 @@ ?attr/colorSurface + false \ No newline at end of file diff --git a/UIViews/src/main/res/values-v31/themes.xml b/UIViews/src/main/res/values-v31/themes.xml index 1f7eed2bc..35e701985 100644 --- a/UIViews/src/main/res/values-v31/themes.xml +++ b/UIViews/src/main/res/values-v31/themes.xml @@ -13,5 +13,6 @@ ?attr/colorSurface + true \ No newline at end of file diff --git a/UIViews/src/main/res/values/themes.xml b/UIViews/src/main/res/values/themes.xml index e409e2e03..dfb6ad3d4 100644 --- a/UIViews/src/main/res/values/themes.xml +++ b/UIViews/src/main/res/values/themes.xml @@ -12,6 +12,7 @@ ?attr/colorSurface + true