From 6b6ba917214b89f27ab50b8dcca0219cf67fd455 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 20:12:13 +0000 Subject: [PATCH 01/44] Update dependency androidx.activity:activity-compose to v1.8.0-rc01 --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ef07a39e2..05ff49bb8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -167,7 +167,7 @@ android { dependencies { // https://developer.android.com/jetpack/androidx/releases/activity - implementation("androidx.activity:activity-compose:1.8.0-beta01") + implementation("androidx.activity:activity-compose:1.8.0-rc01") implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.biometric:biometric-ktx:1.2.0-alpha05") implementation("androidx.browser:browser:1.6.0") From 8306342ab6725587302585a9cc2076de3af588e6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 22:32:15 +0000 Subject: [PATCH 02/44] Update dependency androidx.fragment:fragment-ktx to v1.7.0-alpha05 --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 05ff49bb8..552f775a3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -185,7 +185,7 @@ dependencies { implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha12") implementation("androidx.coordinatorlayout:coordinatorlayout:1.2.0") - implementation("androidx.fragment:fragment-ktx:1.7.0-alpha04") + implementation("androidx.fragment:fragment-ktx:1.7.0-alpha05") // https://developer.android.com/jetpack/androidx/releases/lifecycle implementation("androidx.lifecycle:lifecycle-process:2.6.2") From 2bd24b6a8b501c24da384b7dc873982aaec010be Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 00:45:19 +0000 Subject: [PATCH 03/44] Update dependency com.google.android.material:material to v1.11.0-alpha03 --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 552f775a3..6a5d302a7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -216,7 +216,7 @@ dependencies { val accompanist_version = "0.32.0" implementation("com.google.accompanist:accompanist-themeadapter-material3:$accompanist_version") implementation("com.google.accompanist:accompanist-webview:$accompanist_version") - implementation("com.google.android.material:material:1.11.0-alpha02") + implementation("com.google.android.material:material:1.11.0-alpha03") val splitties = "3.0.0" implementation("com.louiscad.splitties:splitties-appctx:$splitties") From eda97347fcdbf929d54dfa89552de6c3f696e758 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 04:57:10 +0000 Subject: [PATCH 04/44] Update nav_version to v2.7.3 --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6a5d302a7..48219d9f5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -190,7 +190,7 @@ dependencies { implementation("androidx.lifecycle:lifecycle-process:2.6.2") // https://developer.android.com/jetpack/androidx/releases/navigation - val nav_version = "2.7.2" + val nav_version = "2.7.3" implementation("androidx.navigation:navigation-fragment-ktx:$nav_version") implementation("androidx.navigation:navigation-ui-ktx:$nav_version") implementation("androidx.navigation:navigation-compose:$nav_version") From 0f9e1819c150c07817f1964e79d3c02111b32b16 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 08:09:36 +0000 Subject: [PATCH 05/44] Update room_version to v2.6.0-rc01 --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 48219d9f5..a7663dfc0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -203,7 +203,7 @@ dependencies { implementation("androidx.recyclerview:recyclerview-selection:1.2.0-alpha01") // https://developer.android.com/jetpack/androidx/releases/room - val room_version = "2.6.0-beta01" + val room_version = "2.6.0-rc01" ksp("androidx.room:room-compiler:$room_version") implementation("androidx.room:room-paging:$room_version") From b9e1d79be6a132a2c9ac964b5086e4ac4b671641 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Thu, 21 Sep 2023 21:33:21 +0800 Subject: [PATCH 06/44] Switch to branch automerging --- renovate.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/renovate.json b/renovate.json index b36b11be7..ec9c04b1e 100644 --- a/renovate.json +++ b/renovate.json @@ -4,8 +4,7 @@ ], "automerge": true, - "automergeType": "pr", - "automergeStrategy": "squash", + "automergeType": "branch", "extends": [ "config:base" From 2b8bfab44bf0adae16d3d47cb698921d3db1c09c Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 22 Sep 2023 13:41:22 +0800 Subject: [PATCH 07/44] Fix minRating advanced search --- app/src/main/java/com/hippo/ehviewer/ui/main/AdvanceTable.kt | 2 +- .../main/java/com/hippo/ehviewer/ui/main/AdvancedSearch.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/main/AdvanceTable.kt b/app/src/main/java/com/hippo/ehviewer/ui/main/AdvanceTable.kt index 8d43e73dc..47166c558 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/main/AdvanceTable.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/main/AdvanceTable.kt @@ -10,7 +10,7 @@ object AdvanceTable { data class AdvancedSearchOption( val advanceSearch: Int = 0, - val minRating: Int = 0, + val minRating: Int = -1, val fromPage: Int = -1, val toPage: Int = -1, ) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/main/AdvancedSearch.kt b/app/src/main/java/com/hippo/ehviewer/ui/main/AdvancedSearch.kt index a0249fec5..d8420fb96 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/main/AdvancedSearch.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/main/AdvancedSearch.kt @@ -59,7 +59,7 @@ fun SearchAdvanced( OutlinedTextField( modifier = Modifier.menuAnchor(), readOnly = true, - value = minRatingItems[state.minRating], + value = minRatingItems[if (state.minRating in 2..5) state.minRating - 1 else 0], onValueChange = {}, label = { Text(stringResource(id = R.string.search_sr)) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, @@ -77,7 +77,8 @@ fun SearchAdvanced( text = { Text(selectionOption) }, onClick = { expanded = false - onStateChanged(state.copy(minRating = minRatingItems.indexOf(selectionOption))) + val index = minRatingItems.indexOf(selectionOption) + onStateChanged(state.copy(minRating = if (index > 0) index + 1 else -1)) }, contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, ) From 6a65b61785193c1a41ae585dc2f333efb913e296 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:02:18 +0800 Subject: [PATCH 08/44] Store SearchLayout state in ViewModel --- .../hippo/ehviewer/ui/legacy/SearchLayout.kt | 98 ++++++++++--------- .../ehviewer/ui/scene/GalleryListScene.kt | 2 + 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt b/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt index 7f6e1c688..ac0f7718d 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt @@ -34,6 +34,10 @@ import androidx.compose.ui.platform.AbstractComposeView import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.findViewTreeViewModelStoreOwner +import androidx.lifecycle.get import com.google.accompanist.themeadapter.material3.Mdc3Theme import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings @@ -49,87 +53,93 @@ import com.hippo.ehviewer.util.pickVisualMedia import com.hippo.unifile.UniFile import kotlinx.coroutines.launch +class SearchViewModel : ViewModel() { + var isNormalMode by mutableStateOf(true) // else ImageSearch mode + var isAdvancedMode by mutableStateOf(false) + var mCategory by mutableIntStateOf(Settings.searchCategory) + var mSearchMode by mutableIntStateOf(1) + var advancedState by mutableStateOf(AdvancedSearchOption()) + var uss by mutableStateOf(false) + var osc by mutableStateOf(false) + var path by mutableStateOf("") +} + class SearchLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0, ) : AbstractComposeView(context, attrs, defStyle) { - private var isNormalMode by mutableStateOf(true) // else ImageSearch mode - private var isAdvancedMode by mutableStateOf(false) - private var mCategory by mutableIntStateOf(Settings.searchCategory) - private var mSearchMode by mutableIntStateOf(1) - private var advancedState by mutableStateOf(AdvancedSearchOption()) - private var uss by mutableStateOf(false) - private var osc by mutableStateOf(false) - private var path by mutableStateOf("") + private val vm by lazy { + ViewModelProvider(findViewTreeViewModelStoreOwner()!!).get() + } @Composable override fun Content() { val coroutineScope = rememberCoroutineScope() fun selectImage() = coroutineScope.launch { context.pickVisualMedia(ActivityResultContracts.PickVisualMedia.ImageOnly)?.let { - path = it.toString() + vm.path = it.toString() } } Mdc3Theme { Column(modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.search_layout_margin_h)).imePadding().verticalScroll(rememberScrollState())) { - AnimatedVisibility(visible = isNormalMode) { + AnimatedVisibility(visible = vm.isNormalMode) { ElevatedCard(modifier = Modifier.fillMaxWidth().padding(vertical = dimensionResource(id = R.dimen.search_layout_margin_v))) { Column(modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.search_category_padding_h), vertical = dimensionResource(id = R.dimen.search_category_padding_v))) { Text(text = stringResource(id = R.string.search_normal), modifier = Modifier.height(dimensionResource(id = R.dimen.search_category_title_height)), fontWeight = FontWeight.Bold, style = MaterialTheme.typography.titleMedium) NormalSearch( - category = mCategory, + category = vm.mCategory, onCategoryChanged = { Settings.searchCategory = it - mCategory = it + vm.mCategory = it }, - searchMode = mSearchMode, - onSearchModeChanged = { mSearchMode = it }, - isAdvanced = isAdvancedMode, - onAdvancedChanged = { isAdvancedMode = it }, + searchMode = vm.mSearchMode, + onSearchModeChanged = { vm.mSearchMode = it }, + isAdvanced = vm.isAdvancedMode, + onAdvancedChanged = { vm.isAdvancedMode = it }, showInfo = { BaseDialogBuilder(context).setMessage(R.string.search_tip).show() }, ) } } } - AnimatedVisibility(visible = isNormalMode && isAdvancedMode) { + AnimatedVisibility(visible = vm.isNormalMode && vm.isAdvancedMode) { ElevatedCard(modifier = Modifier.fillMaxWidth().padding(vertical = dimensionResource(id = R.dimen.search_layout_margin_v))) { Column(modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.search_category_padding_h), vertical = dimensionResource(id = R.dimen.search_category_padding_v))) { Text(text = stringResource(id = R.string.search_advance), modifier = Modifier.height(dimensionResource(id = R.dimen.search_category_title_height)), fontWeight = FontWeight.Bold, style = MaterialTheme.typography.titleMedium) SearchAdvanced( - state = advancedState, - onStateChanged = { advancedState = it }, + state = vm.advancedState, + onStateChanged = { vm.advancedState = it }, ) } } } - AnimatedVisibility(visible = !isNormalMode) { + AnimatedVisibility(visible = !vm.isNormalMode) { ElevatedCard(modifier = Modifier.fillMaxWidth().padding(vertical = dimensionResource(id = R.dimen.search_layout_margin_v))) { Column(modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.search_category_padding_h), vertical = dimensionResource(id = R.dimen.search_category_padding_v))) { Text(text = stringResource(id = R.string.search_image), modifier = Modifier.height(dimensionResource(id = R.dimen.search_category_title_height)), fontWeight = FontWeight.Bold, style = MaterialTheme.typography.titleMedium) ImageSearch( - imagePath = path, + imagePath = vm.path, onSelectImage = ::selectImage, - uss = uss, - onUssChecked = { uss = it }, - osc = osc, - onOscChecked = { osc = it }, + uss = vm.uss, + onUssChecked = { vm.uss = it }, + osc = vm.osc, + onOscChecked = { vm.osc = it }, ) } } } TabRow( - selectedTabIndex = if (isNormalMode) 0 else 1, + selectedTabIndex = if (vm.isNormalMode) 0 else 1, divider = {}, ) { Tab( - selected = isNormalMode, - onClick = { isNormalMode = true }, + selected = vm.isNormalMode, + onClick = { vm.isNormalMode = true }, text = { Text(text = stringResource(id = R.string.keyword_search)) }, ) Tab( - selected = !isNormalMode, - onClick = { isNormalMode = false }, + selected = !vm.isNormalMode, + onClick = { vm.isNormalMode = false }, text = { Text(text = stringResource(id = R.string.search_image)) }, ) } @@ -139,30 +149,30 @@ class SearchLayout @JvmOverloads constructor( } fun setSearchMyTags(isMyTags: Boolean) { - if (isMyTags) mSearchMode = 2 + if (isMyTags) vm.mSearchMode = 2 } fun setCategory(category: Int) { - mCategory = category + vm.mCategory = category } fun formatListUrlBuilder(urlBuilder: ListUrlBuilder, query: String?) { urlBuilder.reset() - when (isNormalMode) { + when (vm.isNormalMode) { true -> { - when (mSearchMode) { + when (vm.mSearchMode) { 1 -> urlBuilder.mode = ListUrlBuilder.MODE_NORMAL 2 -> urlBuilder.mode = ListUrlBuilder.MODE_SUBSCRIPTION 3 -> urlBuilder.mode = ListUrlBuilder.MODE_UPLOADER 4 -> urlBuilder.mode = ListUrlBuilder.MODE_TAG } urlBuilder.keyword = query - urlBuilder.category = mCategory - if (isAdvancedMode) { - urlBuilder.advanceSearch = advancedState.advanceSearch - urlBuilder.minRating = advancedState.minRating - val pageFrom = advancedState.fromPage - val pageTo = advancedState.toPage + urlBuilder.category = vm.mCategory + if (vm.isAdvancedMode) { + urlBuilder.advanceSearch = vm.advancedState.advanceSearch + urlBuilder.minRating = vm.advancedState.minRating + val pageFrom = vm.advancedState.fromPage + val pageTo = vm.advancedState.toPage if (pageTo != -1 && pageTo < 10) { throw EhException(context.getString(R.string.search_sp_err1)) } else if (pageFrom != -1 && pageTo != -1 && pageTo - pageFrom < 20) { @@ -175,15 +185,15 @@ class SearchLayout @JvmOverloads constructor( false -> { urlBuilder.mode = ListUrlBuilder.MODE_IMAGE_SEARCH - if (path.isBlank()) throw EhException(context.getString(R.string.select_image_first)) - val uri = Uri.parse(path) + if (vm.path.isBlank()) throw EhException(context.getString(R.string.select_image_first)) + val uri = Uri.parse(vm.path) val src = UniFile.fromUri(context, uri)?.imageSource ?: return val temp = AppConfig.createTempFile() ?: return val bitmap = ImageDecoder.decodeBitmap(src, Image.imageSearchDecoderSampleListener) temp.outputStream().use { bitmap.compress(Bitmap.CompressFormat.JPEG, 90, it) } urlBuilder.imagePath = temp.path - urlBuilder.isUseSimilarityScan = uss - urlBuilder.isOnlySearchCovers = osc + urlBuilder.isUseSimilarityScan = vm.uss + urlBuilder.isOnlySearchCovers = vm.osc } } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt index c0fe7ab77..514f5ca4d 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt @@ -39,6 +39,7 @@ import androidx.drawerlayout.widget.DrawerLayout import androidx.fragment.app.viewModels import androidx.lifecycle.ViewModel import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.setViewTreeViewModelStoreOwner import androidx.lifecycle.viewModelScope import androidx.paging.LoadState import androidx.paging.Pager @@ -331,6 +332,7 @@ class GalleryListScene : SearchBarScene() { ), ) mViewTransition = BringOutTransition(binding.contentLayout.contentView, binding.searchLayout) + binding.searchLayout.setViewTreeViewModelStoreOwner(this) binding.fastScroller.setOnDragHandlerListener(object : OnDragHandlerListener { override fun onStartDragHandler() {} override fun onEndDragHandler() { From d13b09aaf350e25be75a86c84466e4b26e611579 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:46:57 +0800 Subject: [PATCH 09/44] Fix swipe-to-refresh --- .../main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt | 2 +- .../java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt index 9d8c43f0e..ac2024447 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/FavoritesScene.kt @@ -333,7 +333,7 @@ class FavoritesScene : SearchBarScene() { drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) binding.tip.setCompoundDrawables(null, drawable, null, null) binding.tip.setOnClickListener { mAdapter?.refresh() } - binding.refreshLayout.setOnRefreshListener { mAdapter?.refresh() } + binding.refreshLayout.setOnRefreshListener { switchFav(urlBuilder.favCat) } val transition = ViewTransition(binding.refreshLayout, binding.progress, binding.tip) val empty = getString(R.string.gallery_list_empty_hit) viewLifecycleOwner.lifecycleScope.launch { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt index 514f5ca4d..84b87aa5b 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt @@ -362,7 +362,11 @@ class GalleryListScene : SearchBarScene() { drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) binding.tip.setCompoundDrawables(null, drawable, null, null) binding.tip.setOnClickListener { mAdapter?.refresh() } - binding.refreshLayout.setOnRefreshListener { mAdapter?.refresh() } + binding.refreshLayout.setOnRefreshListener { + mUrlBuilder.setIndex(null, true) + mUrlBuilder.mJumpTo = null + mAdapter?.refresh() + } val transition = ViewTransition(binding.refreshLayout, binding.progress, binding.tip) val empty = getString(R.string.gallery_list_empty_hit) launch { From 26701d84f76f7addf19c7c07913ff0d54c401646 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:56:27 +0800 Subject: [PATCH 10/44] Cleanup redundant .gitignore --- app/src/main/rust/catch_panic/.gitignore | 2 -- app/src/main/rust/catch_panic_macros/.gitignore | 2 -- app/src/main/rust/jnix/.gitignore | 2 -- 3 files changed, 6 deletions(-) delete mode 100644 app/src/main/rust/catch_panic/.gitignore delete mode 100644 app/src/main/rust/catch_panic_macros/.gitignore delete mode 100644 app/src/main/rust/jnix/.gitignore diff --git a/app/src/main/rust/catch_panic/.gitignore b/app/src/main/rust/catch_panic/.gitignore deleted file mode 100644 index 96ef6c0b9..000000000 --- a/app/src/main/rust/catch_panic/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/app/src/main/rust/catch_panic_macros/.gitignore b/app/src/main/rust/catch_panic_macros/.gitignore deleted file mode 100644 index 96ef6c0b9..000000000 --- a/app/src/main/rust/catch_panic_macros/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/app/src/main/rust/jnix/.gitignore b/app/src/main/rust/jnix/.gitignore deleted file mode 100644 index 96ef6c0b9..000000000 --- a/app/src/main/rust/jnix/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock From 5a975613897b30465d9edfc9e5a4886ad85941a0 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 22 Sep 2023 16:24:48 +0800 Subject: [PATCH 11/44] Upgrade gradle wrapper --- gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 63721 bytes gradlew | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cdf41af1ab109bc7f253b2b887023340..7f93135c49b765f8051ef9d0a6055ff8e46073d8 100644 GIT binary patch delta 28216 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 diff --git a/gradlew b/gradlew index fcb6fca14..0adc8e1a5 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum From 33e24aa46c94ef30db223cc9a2ff274c85fab7f9 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 23 Sep 2023 13:49:34 +0800 Subject: [PATCH 12/44] Fix CI for renovate --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b55afcf7..d44027b79 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,9 +3,7 @@ name: CI on: push: branches: - - '*' - tags-ignore: - - "*" + - '**' jobs: linux: From 40af1862a00abec778c66667e3500b94a0ab1e6e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Sep 2023 05:50:16 +0000 Subject: [PATCH 13/44] Update actions/checkout digest to 8ade135 --- .github/workflows/ci.yml | 2 +- .github/workflows/pull_request.yml | 2 +- .github/workflows/releases.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d44027b79..66c6a1ace 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 with: submodules: 'recursive' diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 946bf28b4..64705f013 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 with: submodules: 'recursive' diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 951332ef0..66f8188ab 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 with: submodules: 'recursive' From d0e3de7121279611fc993242190518e27a19bb9e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Sep 2023 07:37:51 +0000 Subject: [PATCH 14/44] Update dependency com.mikepenz:aboutlibraries-core to v10.9.0 --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a7663dfc0..390f05b31 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -231,7 +231,7 @@ dependencies { implementation("com.squareup.okio:okio-jvm:3.5.0") - implementation("com.mikepenz:aboutlibraries-core:10.8.3") + implementation("com.mikepenz:aboutlibraries-core:10.9.0") implementation("dev.chrisbanes.insetter:insetter:0.6.1") // Dead Dependency implementation("dev.rikka.rikkax.core:core-ktx:1.4.1") From 7704fa93188263a58f055035b982531403da034a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Sep 2023 09:34:12 +0000 Subject: [PATCH 15/44] Update plugin com.mikepenz.aboutlibraries.plugin to v10.9.0 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index f2852e193..3029f112b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ plugins { kotlin("android") version "1.9.10" apply false kotlin("plugin.serialization") version "1.9.10" apply false id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false - id("com.mikepenz.aboutlibraries.plugin") version "10.8.3" apply false + id("com.mikepenz.aboutlibraries.plugin") version "10.9.0" apply false id("org.mozilla.rust-android-gradle.rust-android") version "0.9.3" apply false id("dev.shreyaspatil.compose-compiler-report-generator") version "1.1.0" apply false } From 8ea731159f69b57e88eda999c3350d9499d043f2 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 23 Sep 2023 18:59:29 +0800 Subject: [PATCH 16/44] Prevent unnecessary regeneration of BuildConfig --- app/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 390f05b31..c64b397e7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -82,7 +82,6 @@ android { ), ) buildConfigField("String", "COMMIT_SHA", "\"$commitSha\"") - buildConfigField("String", "BUILD_TIME", "\"$buildTime\"") buildConfigField("String", "REPO_NAME", "\"$repoName\"") } @@ -146,9 +145,11 @@ android { isShrinkResources = true proguardFiles("proguard-rules.pro") signingConfig = signConfig + buildConfigField("String", "BUILD_TIME", "\"$buildTime\"") } debug { applicationIdSuffix = ".debug" + buildConfigField("String", "BUILD_TIME", "\"\"") } } From 534f6aa22ca3f3b4b447520ee299cd20fe06a899 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 23 Sep 2023 19:13:43 +0800 Subject: [PATCH 17/44] Merge pull request workflow to CI --- .github/workflows/ci.yml | 5 ++- .github/workflows/pull_request.yml | 66 ------------------------------ 2 files changed, 4 insertions(+), 67 deletions(-) delete mode 100644 .github/workflows/pull_request.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66c6a1ace..e047c35fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,10 @@ name: CI on: push: branches: - - '**' + - '*' + - 'renovate/**' + pull_request: + workflow_dispatch: jobs: linux: diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml deleted file mode 100644 index 64705f013..000000000 --- a/.github/workflows/pull_request.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Pull Request Check - -on: [ pull_request ] - -jobs: - linux: - name: Build - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4 - with: - submodules: 'recursive' - - - name: Setup Java 17 - uses: actions/setup-java@v3 - with: - distribution: temurin - java-version: 17 - - - name: Install NDK - run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;26.0.10636728" --channel=1 --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null - - - name: Install Rust Toolchain - run: rustup update && rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android && rustup component add rustfmt clippy - - - name: Rustfmt Check - working-directory: ./app/src/main/rust - run: cargo fmt --all -- --check - - - name: Clippy Check - working-directory: ./app/src/main/rust - run: cargo clippy --all-targets --all-features -- -D warnings - - - name: Ktlint Check - run: ./gradlew ktlintCheck - - - name: Gradle Build - uses: gradle/gradle-build-action@v2 - with: - arguments: assembleRelease - - - name: Update ARM64 - uses: actions/upload-artifact@v3 - with: - name: arm64-v8a-${{ github.sha }} - path: app/build/outputs/apk/release/app-arm64-v8a-release.apk - - - name: Update x86_64 - uses: actions/upload-artifact@v3 - with: - name: x86_64-${{ github.sha }} - path: app/build/outputs/apk/release/app-x86_64-release.apk - - - name: Update ARM32 - uses: actions/upload-artifact@v3 - with: - name: armeabi-v7a-${{ github.sha }} - path: app/build/outputs/apk/release/app-armeabi-v7a-release.apk - - - name: Update x86 - uses: actions/upload-artifact@v3 - with: - name: x86-${{ github.sha }} - path: app/build/outputs/apk/release/app-x86-release.apk From d08b7c2d943fc25cee9403f671a819dea43183fb Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 23 Sep 2023 22:32:54 +0800 Subject: [PATCH 18/44] Update README --- README.md | 45 ++++++++++--------- docs/README/en.md | 103 ------------------------------------------- docs/README/zh-cn.md | 41 +++++++++-------- docs/README/zh-tw.md | 41 +++++++++-------- 4 files changed, 68 insertions(+), 162 deletions(-) delete mode 100644 docs/README/en.md diff --git a/README.md b/README.md index ac285be73..be762941f 100644 --- a/README.md +++ b/README.md @@ -5,60 +5,60 @@ The project is in maintenance mode, will only receive bugfixes.

English | - + 简体中文 | - + 正體中文

- + EhViewer
EhViewer

- - Github Actions + + Github Actions - - LICENSE + + LICENSE - - CodeFactor + + CodeFactor - - Downloads + + Downloads - - Release + + Release - - Issues + + Issues

- + Description | - + Download | - + Screenshot | - + Thanks | - + License

@@ -73,7 +73,9 @@ and [Dynamic Color](https://m3.material.io/styles/color/dynamic-color/overview) # Download -Get it on GitHub Get it on F-Droid + +Get it on GitHub + # Screenshot @@ -103,6 +105,7 @@ Specially thanks [Tachiyomi](https://tachiyomi.org/) for its reader implementati Copyright 2014-2019 Hippo Seven Copyright 2020-2022 NekoInverter Copyright 2022-2023 Tarsin Norbin + Copyright 2023 Foolbar EhViewer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. diff --git a/docs/README/en.md b/docs/README/en.md deleted file mode 100644 index 30b4708dd..000000000 --- a/docs/README/en.md +++ /dev/null @@ -1,103 +0,0 @@ -

- English - | - - 简体中文 - - | - - 正體中文 - -

- -

- -
EhViewer
-

- -

- - Github Actions - - - LICENSE - - - CodeFactor - - - Release - - - Issues - -

- - - -# Description - -EhViewer fork dedicated to lightweight and high-performance - -with Material Design 3 and Dynamic Color Support - -# Download - -Get it on GitHub Get it on F-Droid - -# Screenshot - -![screenshot-01](https://github.com/Ehviewer-Overhauled/Art/blob/master/screenshot-01.png) -![screenshot-02](https://github.com/Ehviewer-Overhauled/Art/blob/master/screenshot-02.png) - -# Thanks - -Here is the libraries - -- [Arrow](https://arrow-kt.io/) -- [AOSP & AndroidX](http://source.android.com/) -- [Kotlin & KotlinX](https://kotlinlang.org/) -- [FullDraggableDrawer](https://github.com/PureWriter/FullDraggableDrawer) -- [MCA](https://github.com/material-components/material-components-android) -- [material-design-icons](https://github.com/google/material-design-icons) -- [Okhttp](https://square.github.io/okhttp/) -- [RikkaX](https://github.com/RikkaApps/RikkaX) -- [Libarchive](http://www.libarchive.org/) -- [Coil](https://coil-kt.github.io/coil/) -- [Jsoup](https://jsoup.org/) - -Specially thanks [Tachiyomi](https://tachiyomi.org/) for its reader implementation! - -# License - - Copyright 2014-2019 Hippo Seven - Copyright 2020-2022 NekoInverter - Copyright 2022-2023 Tarsin Norbin - - EhViewer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - - EhViewer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with EhViewer. If not, see . diff --git a/docs/README/zh-cn.md b/docs/README/zh-cn.md index ecfc41215..97b5a668d 100644 --- a/docs/README/zh-cn.md +++ b/docs/README/zh-cn.md @@ -1,57 +1,57 @@

- + English | 简体中文 | - + 正體中文

- + EhViewer
EhViewer

- - Github Actions + + Github Actions - - LICENSE + + LICENSE - - CodeFactor + + CodeFactor - - Release + + Release - - Issues + + Issues

- + 描述 | - + 下载 | - + 截图 | - + 感谢 | - + 许可证

@@ -65,7 +65,9 @@ # 下载 -Get it on GitHub Get it on F-Droid + +Get it on GitHub + # 截图 @@ -95,6 +97,7 @@ Copyright 2014-2019 Hippo Seven Copyright 2020-2022 NekoInverter Copyright 2022-2023 Tarsin Norbin + Copyright 2023 Foolbar EhViewer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. diff --git a/docs/README/zh-tw.md b/docs/README/zh-tw.md index 1d497846f..d29acf2bb 100644 --- a/docs/README/zh-tw.md +++ b/docs/README/zh-tw.md @@ -1,9 +1,9 @@

- + English | - + 简体中文 | @@ -11,47 +11,47 @@

- + EhViewer
EhViewer

- - Github Actions + + Github Actions - - LICENSE + + LICENSE - - CodeFactor + + CodeFactor - - Release + + Release - - Issues + + Issues

- + 說明 | - + 下載 | - + 截圖 | - + 感謝 | - + 許可證書

@@ -65,7 +65,9 @@ # 下載 -Get it on GitHub Get it on F-Droid + +Get it on GitHub + # 截圖 @@ -93,6 +95,7 @@ Copyright 2014-2019 Hippo Seven Copyright 2020-2022 NekoInverter Copyright 2022-2023 Tarsin Norbin + Copyright 2023 Foolbar EhViewer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. From 669a9ee1e3d04d49d042ae9b422ba921ba4a82fc Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 24 Sep 2023 01:52:02 +0800 Subject: [PATCH 19/44] Use spotless for ktlint integration --- .github/workflows/ci.yml | 12 +++++++----- app/build.gradle.kts | 10 ++++++++++ build.gradle.kts | 5 +---- ktlint.gradle.kts | 38 -------------------------------------- 4 files changed, 18 insertions(+), 47 deletions(-) delete mode 100644 ktlint.gradle.kts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e047c35fa..6ef0d8d30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,14 +39,16 @@ jobs: working-directory: ./app/src/main/rust run: cargo clippy --all-targets --all-features -- -D warnings - - name: Ktlint Check - run: ./gradlew ktlintCheck - - - name: Gradle Build + - name: Setup Gradle uses: gradle/gradle-build-action@v2 with: gradle-home-cache-cleanup: true - arguments: assembleRelease + + - name: Spotless Check + run: ./gradlew spotlessCheck + + - name: Gradle Build + run: ./gradlew assembleRelease - name: Update ARM64 uses: actions/upload-artifact@v3 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c64b397e7..2b3e1f783 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,6 +13,7 @@ plugins { id("kotlin-parcelize") kotlin("plugin.serialization") id("com.google.devtools.ksp") + id("com.diffplug.spotless") id("com.mikepenz.aboutlibraries.plugin") id("org.mozilla.rust-android-gradle.rust-android") id("dev.shreyaspatil.compose-compiler-report-generator") @@ -293,6 +294,15 @@ cargo { if (isRelease) profile = "release" } +spotless { + kotlin { + ktlint() + } + kotlinGradle { + ktlint() + } +} + tasks.configureEach { if ((name == "mergeDebugJniLibFolders" || name == "mergeReleaseJniLibFolders")) { dependsOn("cargoBuild") diff --git a/build.gradle.kts b/build.gradle.kts index 3029f112b..a1395b061 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,15 +3,12 @@ plugins { kotlin("android") version "1.9.10" apply false kotlin("plugin.serialization") version "1.9.10" apply false id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false + id("com.diffplug.spotless") version "6.21.0" apply false id("com.mikepenz.aboutlibraries.plugin") version "10.9.0" apply false id("org.mozilla.rust-android-gradle.rust-android") version "0.9.3" apply false id("dev.shreyaspatil.compose-compiler-report-generator") version "1.1.0" apply false } -allprojects { - apply(from = "$rootDir/ktlint.gradle.kts") -} - tasks.register("Delete", Delete::class) { delete(rootProject.layout.buildDirectory) } diff --git a/ktlint.gradle.kts b/ktlint.gradle.kts deleted file mode 100644 index f53814dc7..000000000 --- a/ktlint.gradle.kts +++ /dev/null @@ -1,38 +0,0 @@ -val ktlint by configurations.creating - -dependencies { - ktlint("com.pinterest:ktlint:0.50.0") { - attributes { - attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) - } - } - // ktlint(project(":custom-ktlint-ruleset")) // in case of custom ruleset -} - -val ktlintCheck by tasks.registering(JavaExec::class) { - group = LifecycleBasePlugin.VERIFICATION_GROUP - description = "Check Kotlin code style" - classpath = ktlint - mainClass.set("com.pinterest.ktlint.Main") - // see https://pinterest.github.io/ktlint/install/cli/#command-line-usage for more information - args( - "**/*.kt", - "**/*.kts", - "!**/build/**", - ) -} - -val ktlintFormat by tasks.registering(JavaExec::class) { - group = LifecycleBasePlugin.VERIFICATION_GROUP - description = "Check Kotlin code style and format" - classpath = ktlint - mainClass.set("com.pinterest.ktlint.Main") - jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") - // see https://pinterest.github.io/ktlint/install/cli/#command-line-usage for more information - args( - "-F", - "**/*.kt", - "**/*.kts", - "!**/build/**", - ) -} From 9496b9396a8ae6244243f0285b75049e386ed595 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 24 Sep 2023 02:52:46 +0800 Subject: [PATCH 20/44] Upgrade ndk to 26.0.10792818 (#24) --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/releases.yml | 2 +- app/build.gradle.kts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ef0d8d30..dcad98a07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,10 +24,6 @@ jobs: distribution: temurin java-version: 17 - - name: Install NDK - run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;26.0.10636728" --channel=1 --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null - - name: Install Rust Toolchain run: rustup update && rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android && rustup component add rustfmt clippy @@ -47,6 +43,10 @@ jobs: - name: Spotless Check run: ./gradlew spotlessCheck + - name: Install NDK + run: | + echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;26.0.10792818" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + - name: Gradle Build run: ./gradlew assembleRelease diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 66f8188ab..552a5068d 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -23,7 +23,7 @@ jobs: - name: Install NDK run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;26.0.10636728" --channel=1 --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null + echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;26.0.10792818" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null - name: Install Rust Toolchain run: rustup update && rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2b3e1f783..defb0fe6d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ plugins { android { compileSdk = 34 buildToolsVersion = "34.0.0" - ndkVersion = "26.0.10636728" + ndkVersion = "26.0.10792818" splits { abi { From 4c467c304f26fba299ffc8327f6f023b60d8f7f2 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 24 Sep 2023 03:17:12 +0800 Subject: [PATCH 21/44] NDK will be installed automatically --- .github/workflows/ci.yml | 4 ---- .github/workflows/releases.yml | 4 ---- 2 files changed, 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcad98a07..7645c7235 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,10 +43,6 @@ jobs: - name: Spotless Check run: ./gradlew spotlessCheck - - name: Install NDK - run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;26.0.10792818" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null - - name: Gradle Build run: ./gradlew assembleRelease diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 552a5068d..00b761f02 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -21,10 +21,6 @@ jobs: distribution: temurin java-version: 17 - - name: Install NDK - run: | - echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;26.0.10792818" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null - - name: Install Rust Toolchain run: rustup update && rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android From 26a589fc1d6f00960b65b12e06fbc140b33afe60 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 24 Sep 2023 16:10:17 +0800 Subject: [PATCH 22/44] Add native build cache for CI (#26) * Add rust cache for CI * Add cmake cache for CI * Use cache for release as well * Add build cache for CI --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ .github/workflows/releases.yml | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7645c7235..c60c5560f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,12 @@ jobs: - name: Install Rust Toolchain run: rustup update && rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android && rustup component add rustfmt clippy + - name: Rust Cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: "./app/src/main/rust" + cache-all-crates: "true" + - name: Rustfmt Check working-directory: ./app/src/main/rust run: cargo fmt --all -- --check @@ -43,6 +49,20 @@ jobs: - name: Spotless Check run: ./gradlew spotlessCheck + - name: CMake Cache + uses: actions/cache@v3 + with: + path: app/.cxx + key: ${{ runner.os }}-cmake-${{ github.run_id }} + restore-keys: ${{ runner.os }}-cmake- + + - name: Build Cache + uses: actions/cache@v3 + with: + path: app/build + key: ${{ runner.os }}-build-${{ github.run_id }} + restore-keys: ${{ runner.os }}-build- + - name: Gradle Build run: ./gradlew assembleRelease diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 00b761f02..55786be4e 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -24,6 +24,26 @@ jobs: - name: Install Rust Toolchain run: rustup update && rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android + - name: Rust Cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: "./app/src/main/rust" + cache-all-crates: "true" + + - name: CMake Cache + uses: actions/cache@v3 + with: + path: app/.cxx + key: ${{ runner.os }}-cmake-${{ github.run_id }} + restore-keys: ${{ runner.os }}-cmake- + + - name: Build Cache + uses: actions/cache@v3 + with: + path: app/build + key: ${{ runner.os }}-build-${{ github.run_id }} + restore-keys: ${{ runner.os }}-build- + - name: Gradle Build uses: gradle/gradle-build-action@v2 with: From 7783a8de15b2a7ba186603e42d28c84afbe5f839 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 24 Sep 2023 17:52:06 +0800 Subject: [PATCH 23/44] Cleanup build cache for CI --- .github/workflows/ci.yml | 8 -------- .github/workflows/releases.yml | 8 -------- 2 files changed, 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c60c5560f..065bfaf7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,6 @@ jobs: uses: Swatinem/rust-cache@v2 with: workspaces: "./app/src/main/rust" - cache-all-crates: "true" - name: Rustfmt Check working-directory: ./app/src/main/rust @@ -56,13 +55,6 @@ jobs: key: ${{ runner.os }}-cmake-${{ github.run_id }} restore-keys: ${{ runner.os }}-cmake- - - name: Build Cache - uses: actions/cache@v3 - with: - path: app/build - key: ${{ runner.os }}-build-${{ github.run_id }} - restore-keys: ${{ runner.os }}-build- - - name: Gradle Build run: ./gradlew assembleRelease diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 55786be4e..9d1498d29 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -28,7 +28,6 @@ jobs: uses: Swatinem/rust-cache@v2 with: workspaces: "./app/src/main/rust" - cache-all-crates: "true" - name: CMake Cache uses: actions/cache@v3 @@ -37,13 +36,6 @@ jobs: key: ${{ runner.os }}-cmake-${{ github.run_id }} restore-keys: ${{ runner.os }}-cmake- - - name: Build Cache - uses: actions/cache@v3 - with: - path: app/build - key: ${{ runner.os }}-build-${{ github.run_id }} - restore-keys: ${{ runner.os }}-build- - - name: Gradle Build uses: gradle/gradle-build-action@v2 with: From 363029cbdd9e6f4c035a800d9c5a762648bccc95 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sun, 24 Sep 2023 23:55:51 +0800 Subject: [PATCH 24/44] Upgrade r8 (#27) --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index a1395b061..f2ea7ff54 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,6 +15,6 @@ tasks.register("Delete", Delete::class) { buildscript { dependencies { - classpath("com.android.tools:r8:8.2.20-dev") + classpath("com.android.tools:r8:8.3.6-dev") } } From 96b92239b028ba28fdabb77cbfc19753a2962b7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 08:06:51 +0000 Subject: [PATCH 25/44] Update plugin com.mikepenz.aboutlibraries.plugin to v10.9.1-debug01 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index f2ea7ff54..89a5b1634 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { kotlin("plugin.serialization") version "1.9.10" apply false id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false id("com.diffplug.spotless") version "6.21.0" apply false - id("com.mikepenz.aboutlibraries.plugin") version "10.9.0" apply false + id("com.mikepenz.aboutlibraries.plugin") version "10.9.1-debug01" apply false id("org.mozilla.rust-android-gradle.rust-android") version "0.9.3" apply false id("dev.shreyaspatil.compose-compiler-report-generator") version "1.1.0" apply false } From 510719f8901d14dcca91e95c7878277b574d4722 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 25 Sep 2023 22:51:28 +0800 Subject: [PATCH 26/44] Convert libnettle build to FetchContent --- .gitmodules | 3 -- app/src/main/cpp/CMakeLists.txt | 7 ++++ app/src/main/cpp/nettle/.gitignore | 1 + app/src/main/cpp/nettle/CMakeLists.txt | 3 +- app/src/main/cpp/nettle/config.h | 45 ++++++++++++++------------ app/src/main/cpp/nettle/nettle | 1 - app/src/main/cpp/nettle/version.h | 2 +- 7 files changed, 35 insertions(+), 27 deletions(-) delete mode 100644 .gitmodules create mode 100644 app/src/main/cpp/nettle/.gitignore delete mode 160000 app/src/main/cpp/nettle/nettle diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 14a2bece7..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "app/src/main/cpp/nettle/nettle"] - path = app/src/main/cpp/nettle/nettle - url = https://github.com/Ehviewer-Overhauled/nettle diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 56b1797cf..678e8a434 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -32,6 +32,13 @@ FetchContent_MakeAvailable(liblzma) include_directories(${liblzma_SOURCE_DIR}/src/liblzma/api) # Build GNUTLS libnettle +FetchContent_Declare(nettle + URL https://ftp.gnu.org/gnu/nettle/nettle-3.9.1.tar.gz + URL_MD5 29fcd2dec6bf5b48e5e3ffb3cbc4779e + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/nettle/nettle + ) + +FetchContent_MakeAvailable(nettle) add_subdirectory(nettle) # Configure libnettle support for libarchive diff --git a/app/src/main/cpp/nettle/.gitignore b/app/src/main/cpp/nettle/.gitignore new file mode 100644 index 000000000..62edb50a4 --- /dev/null +++ b/app/src/main/cpp/nettle/.gitignore @@ -0,0 +1 @@ +/nettle \ No newline at end of file diff --git a/app/src/main/cpp/nettle/CMakeLists.txt b/app/src/main/cpp/nettle/CMakeLists.txt index e63dbb33d..ef44eff96 100644 --- a/app/src/main/cpp/nettle/CMakeLists.txt +++ b/app/src/main/cpp/nettle/CMakeLists.txt @@ -32,7 +32,6 @@ set(LIBNETTLE_SOURCES nettle/aes256-meta.c nettle/nist-keywrap.c nettle/arcfour.c - nettle/arcfour-crypt.c nettle/arctwo.c nettle/arctwo-meta.c nettle/blowfish.c @@ -177,7 +176,7 @@ set(LIBNETTLE_SOURCES nettle/sha1-compress.c nettle/sha1-meta.c nettle/sha256.c - nettle/sha256-compress.c + nettle/sha256-compress-n.c nettle/sha224-meta.c nettle/sha256-meta.c nettle/sha512.c diff --git a/app/src/main/cpp/nettle/config.h b/app/src/main/cpp/nettle/config.h index 3db1a66ef..f98d965fd 100644 --- a/app/src/main/cpp/nettle/config.h +++ b/app/src/main/cpp/nettle/config.h @@ -4,13 +4,19 @@ /* Define if building universal (internal helper macro) */ /* #undef AC_APPLE_UNIVERSAL_BUILD */ -/* Define to 1 if using 'alloca.c'. */ +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ -/* Define to 1 if you have 'alloca', as a function or macro. */ +/* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 -/* Define to 1 if works. */ +/* Define to 1 if you have and it should be used (not on Ultrix). + */ #define HAVE_ALLOCA_H 1 /* Define if __builtin_bswap64 is available */ @@ -46,6 +52,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_MALLOC_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + /* Define to 1 each of the following for which a native (ie. CPU specific) implementation of the corresponding routine exists. */ /* #undef HAVE_NATIVE_memxor3 */ @@ -71,7 +80,7 @@ /* #undef HAVE_NATIVE_cbc_aes256_encrypt */ /* #undef HAVE_NATIVE_chacha_core */ /* #undef HAVE_NATIVE_chacha_2core */ -/* #undef HAVE_NATIVE_chacha_3core */ +#define HAVE_NATIVE_chacha_3core 1 /* #undef HAVE_NATIVE_chacha_4core */ /* #undef HAVE_NATIVE_fat_chacha_2core */ /* #undef HAVE_NATIVE_fat_chacha_3core */ @@ -88,13 +97,18 @@ /* #undef HAVE_NATIVE_ecc_secp384r1_redc */ /* #undef HAVE_NATIVE_ecc_secp521r1_modp */ /* #undef HAVE_NATIVE_ecc_secp521r1_redc */ +/* #undef HAVE_NATIVE_poly1305_set_key */ +/* #undef HAVE_NATIVE_poly1305_block */ +/* #undef HAVE_NATIVE_poly1305_digest */ +/* #undef HAVE_NATIVE_poly1305_blocks */ +/* #undef HAVE_NATIVE_fat_poly1305_blocks */ /* #undef HAVE_NATIVE_ghash_set_key */ /* #undef HAVE_NATIVE_ghash_update */ /* #undef HAVE_NATIVE_salsa20_core */ -/* #undef HAVE_NATIVE_salsa20_2core */ +#define HAVE_NATIVE_salsa20_2core 1 /* #undef HAVE_NATIVE_fat_salsa20_2core */ /* #undef HAVE_NATIVE_sha1_compress */ -/* #undef HAVE_NATIVE_sha256_compress */ +/* #undef HAVE_NATIVE_sha256_compress_n */ /* #undef HAVE_NATIVE_sha512_compress */ /* #undef HAVE_NATIVE_sha3_permute */ /* #undef HAVE_NATIVE_umac_nh */ @@ -107,14 +121,11 @@ /* #undef HAVE_OPENSSL_EVP_H */ /* Define to 1 if you have the `secure_getenv' function. */ -/* #undef HAVE_SECURE_GETENV */ +#define HAVE_SECURE_GETENV 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 -/* Define to 1 if you have the header file. */ -#define HAVE_STDIO_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 @@ -130,9 +141,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TIME_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 @@ -149,7 +157,7 @@ #define PACKAGE_NAME "nettle" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "nettle 3.8.1" +#define PACKAGE_STRING "nettle 3.9.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "nettle" @@ -158,7 +166,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "3.8.1" +#define PACKAGE_VERSION "3.9.1" /* The size of `long', as computed by sizeof. */ #define SIZEOF_LONG __SIZEOF_LONG__ @@ -174,13 +182,10 @@ STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ -/* Define to 1 if all of the C90 standard headers exist (not just the ones - required in a freestanding environment). This macro is provided for - backward compatibility; new code need not use it. */ +/* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 -/* Define to 1 if you can safely include both and . This - macro is obsolete. */ +/* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Defined if public key features are enabled */ diff --git a/app/src/main/cpp/nettle/nettle b/app/src/main/cpp/nettle/nettle deleted file mode 160000 index 990abad16..000000000 --- a/app/src/main/cpp/nettle/nettle +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 990abad16ceacd070747dcc76ed16a39c129321e diff --git a/app/src/main/cpp/nettle/version.h b/app/src/main/cpp/nettle/version.h index 1e7feb26b..6aa193c6a 100644 --- a/app/src/main/cpp/nettle/version.h +++ b/app/src/main/cpp/nettle/version.h @@ -41,7 +41,7 @@ extern "C" { /* Individual version numbers in decimal */ #define NETTLE_VERSION_MAJOR 3 -#define NETTLE_VERSION_MINOR 8 +#define NETTLE_VERSION_MINOR 9 #define NETTLE_USE_MINI_GMP 0 From dab7968ce32ce9aaff4cc8953ebd6f1f1cc001fb Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 26 Sep 2023 00:21:29 +0800 Subject: [PATCH 27/44] Update liblzma to v5.4.4 --- .../cpp/0001-Don-t-build-other-binarys.patch | 34 ------------------- app/src/main/cpp/CMakeLists.txt | 5 ++- 2 files changed, 2 insertions(+), 37 deletions(-) delete mode 100644 app/src/main/cpp/0001-Don-t-build-other-binarys.patch diff --git a/app/src/main/cpp/0001-Don-t-build-other-binarys.patch b/app/src/main/cpp/0001-Don-t-build-other-binarys.patch deleted file mode 100644 index 0efeed5a0..000000000 --- a/app/src/main/cpp/0001-Don-t-build-other-binarys.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 2bda36800a5424c44378bbc0cc8bb5d26a0f34fa Mon Sep 17 00:00:00 2001 -From: tarsin -Date: Sat, 22 Jul 2023 08:30:20 +0800 -Subject: [PATCH] Don't build other binarys - ---- - CMakeLists.txt | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 55cd358..52b57aa 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -962,7 +962,7 @@ check_symbol_exists(getopt_long getopt.h HAVE_GETOPT_LONG) - # xzdec - ############################################################################# - --if(HAVE_GETOPT_LONG AND HAVE_DECODERS) -+if(0) - add_executable(xzdec - src/common/sysdefs.h - src/common/tuklib_common.h -@@ -1008,7 +1008,7 @@ endif() - # xz - ############################################################################# - --if(NOT MSVC AND HAVE_GETOPT_LONG) -+if(0) - add_executable(xz - src/common/mythread.h - src/common/sysdefs.h --- -2.41.0 - diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 678e8a434..a6df0762b 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -23,9 +23,8 @@ set(FETCHCONTENT_BASE_DIR ${deps}) set(BUILD_TESTING 0) FetchContent_Declare(liblzma - GIT_REPOSITORY https://git.tukaani.org/xz.git - GIT_TAG v5.4.3 - PATCH_COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/0001-Don-t-build-other-binarys.patch || cd . + GIT_REPOSITORY https://github.com/FooIbar/xz.git + GIT_TAG v5.4.4 ) FetchContent_MakeAvailable(liblzma) From d674672ce270fb8847808b3afec7fa47a9ce511a Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 26 Sep 2023 00:21:53 +0800 Subject: [PATCH 28/44] Update libarchive to v3.7.2 --- app/src/main/cpp/0001-Hide-symbols.patch | 29 -------------------- app/src/main/cpp/0002-Insert-link-libs.patch | 25 ----------------- app/src/main/cpp/CMakeLists.txt | 5 ++-- 3 files changed, 2 insertions(+), 57 deletions(-) delete mode 100644 app/src/main/cpp/0001-Hide-symbols.patch delete mode 100644 app/src/main/cpp/0002-Insert-link-libs.patch diff --git a/app/src/main/cpp/0001-Hide-symbols.patch b/app/src/main/cpp/0001-Hide-symbols.patch deleted file mode 100644 index 2e61d1e09..000000000 --- a/app/src/main/cpp/0001-Hide-symbols.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 57da49f9b0ed8538573f6cfe289f835ee0078eec Mon Sep 17 00:00:00 2001 -From: tarsin -Date: Sat, 22 Jul 2023 17:50:08 +0800 -Subject: [PATCH] Hide symbols - ---- - CMakeLists.txt | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 646484b7..67a71272 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -2060,10 +2060,10 @@ SET(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fvisibility=hidden -Werror") - CHECK_C_SOURCE_COMPILES("void __attribute__((visibility(\"default\"))) foo(void); - int main() { return 0; }" HAVE_VISIBILITY_ATTR) --IF (HAVE_VISIBILITY_ATTR) -+IF (0) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") - ADD_DEFINITIONS(-D__LIBARCHIVE_ENABLE_VISIBILITY) --ENDIF(HAVE_VISIBILITY_ATTR) -+ENDIF(0) - SET(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") - - # Generate "config.h" from "build/cmake/config.h.in" --- -2.41.0 - diff --git a/app/src/main/cpp/0002-Insert-link-libs.patch b/app/src/main/cpp/0002-Insert-link-libs.patch deleted file mode 100644 index c4cf952a4..000000000 --- a/app/src/main/cpp/0002-Insert-link-libs.patch +++ /dev/null @@ -1,25 +0,0 @@ -From c9298fd6dc0a8b04dd4b2247118b9cb895c46e58 Mon Sep 17 00:00:00 2001 -From: tarsin -Date: Sat, 23 Jul 2022 16:05:36 +0800 -Subject: [PATCH 2/2] Insert link libs - ---- - CMakeLists.txt | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 713e3bc5..7247640d 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -415,7 +415,7 @@ IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}") - # # endif - ENDIF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}") - --SET(ADDITIONAL_LIBS "") -+SET(ADDITIONAL_LIBS ${LIBARCHIVE_CUSTOM_LIBS}) - # - # Find ZLIB - # --- -2.39.2 - diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index a6df0762b..1f6b6666f 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -68,9 +68,8 @@ option(ENABLE_TEST OFF) SET(LIBARCHIVE_CUSTOM_LIBS "nettle" "liblzma") FetchContent_Declare(libarchive - GIT_REPOSITORY https://github.com/libarchive/libarchive - GIT_TAG v3.7.0 - PATCH_COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/0001-Hide-symbols.patch ${CMAKE_CURRENT_LIST_DIR}/0002-Insert-link-libs.patch || cd . + GIT_REPOSITORY https://github.com/FooIbar/libarchive.git + GIT_TAG v3.7.2 ) FetchContent_MakeAvailable(libarchive) From 2fbf226ccdb41a0a3be7afbe64b81f20cd7c12ed Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 26 Sep 2023 01:23:11 +0800 Subject: [PATCH 29/44] Update author summary in about --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 689582d85..53ad01403 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -440,7 +440,7 @@ EhViewer EhViewer is not affiliated with E-Hentai.org in any way Author - <del>Hippo &lt;ehviewersu$gmail.com&gt;</del><br><del>NekoInverter</del><br>飛鳥澪 + <del>Hippo &lt;ehviewersu$gmail.com&gt;</del><br><del>NekoInverter</del><br><del>飛鳥澪</del><br>Foolbar Latest release Source Build version From a90cf3c72b161bc9fa5b5ebeeb99a5c5ff6238ba Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 26 Sep 2023 01:28:01 +0800 Subject: [PATCH 30/44] Update issue template --- .github/ISSUE_TEMPLATE/bug-report.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 7e8f9c4a6..d1f622ed6 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -6,10 +6,10 @@ body: - type: markdown attributes: value: | - 感谢您愿意为 Ehviewer-Overhauled 做出贡献! + 感谢您愿意为 EhViewer 做出贡献! 提交问题报告前,还请首先完成文末的自查步骤 - Thanks for your contribution on Ehviewer-Overhauled Project! + Thanks for your contribution on EhViewer Project! Please finish verify steps which list in the end first before create bug report - type: textarea @@ -141,5 +141,5 @@ body: - label: 您确保这个 Issue 只提及一个问题。如果您有多个问题报告,烦请发起多个 Issue / Ensure there is only one bug report in this issue. Please make mutiply issue for mutiply bugs required: true - - label: 您确保已使用最新 CI 版本测试,并且该问题在最新 CI 版本中并未解决 / This bug have not solved in latest CI version + - label: 您确保已使用最新 [CI 版本](https://github.com/FooIbar/EhViewer/actions)测试,并且该问题在最新 CI 版本中并未解决 / This bug have not solved in latest [CI version](https://github.com/FooIbar/EhViewer/actions) required: true From 58069e8925b1123887eee9fc051958a4d404ac49 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 26 Sep 2023 01:35:37 +0800 Subject: [PATCH 31/44] Fix cmake cache for CI --- .github/workflows/ci.yml | 4 +++- .github/workflows/releases.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 065bfaf7b..b4bfa13a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,9 @@ jobs: - name: CMake Cache uses: actions/cache@v3 with: - path: app/.cxx + path: | + app/.cxx + app/src/main/cpp/nettle/nettle key: ${{ runner.os }}-cmake-${{ github.run_id }} restore-keys: ${{ runner.os }}-cmake- diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 9d1498d29..396b830c7 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -32,7 +32,9 @@ jobs: - name: CMake Cache uses: actions/cache@v3 with: - path: app/.cxx + path: | + app/.cxx + app/src/main/cpp/nettle/nettle key: ${{ runner.os }}-cmake-${{ github.run_id }} restore-keys: ${{ runner.os }}-cmake- From 567875cf0094c0b01dba12ceacac3841cb6b3589 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 26 Sep 2023 16:50:07 +0800 Subject: [PATCH 32/44] Apply quick search in place if not in Popular (#30) --- .../ehviewer/ui/scene/GalleryListScene.kt | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt index 84b87aa5b..ce7cb4b57 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt @@ -285,7 +285,7 @@ class GalleryListScene : SearchBarScene() { setSearchBarHint(title) when (mode) { - MODE_NORMAL -> if (category != EhUtils.NONE || !keyword.isNullOrEmpty()) { + MODE_NORMAL, MODE_SUBSCRIPTION -> if (category != EhUtils.NONE || !keyword.isNullOrEmpty()) { mainActivity?.clearNavCheckedItem() } MODE_TAG, MODE_UPLOADER, MODE_IMAGE_SEARCH -> mainActivity?.clearNavCheckedItem() @@ -620,20 +620,22 @@ class GalleryListScene : SearchBarScene() { drawerBinding.toolbar.setTitle(R.string.toplist) } else { drawerBinding.toolbar.setTitle(R.string.quick_search) - } - if (!mIsTopList) drawerBinding.toolbar.inflateMenu(R.menu.drawer_gallery_list) - drawerBinding.toolbar.setOnMenuItemClickListener { item: MenuItem -> - val id = item.itemId - if (id == R.id.action_add) { - showAddQuickSearchDialog( - qsDrawerAdapter, - drawerBinding.recyclerViewDrawer, - drawerBinding.tip, - ) - } else if (id == R.id.action_help) { - showQuickSearchTipDialog() + if (mUrlBuilder.mode != MODE_WHATS_HOT) { + drawerBinding.toolbar.inflateMenu(R.menu.drawer_gallery_list) + drawerBinding.toolbar.setOnMenuItemClickListener { item: MenuItem -> + val id = item.itemId + if (id == R.id.action_add) { + showAddQuickSearchDialog( + qsDrawerAdapter, + drawerBinding.recyclerViewDrawer, + drawerBinding.tip, + ) + } else if (id == R.id.action_help) { + showQuickSearchTipDialog() + } + true + } } - true } return drawerBinding.root } @@ -856,13 +858,17 @@ class GalleryListScene : SearchBarScene() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QsDrawerHolder { val holder = QsDrawerHolder(ItemDrawerListBinding.inflate(mInflater, parent, false)) holder.itemView.setOnClickListener { - if (!mIsTopList) { + if (mUrlBuilder.mode == MODE_WHATS_HOT) { val q = mQuickSearchList[holder.bindingAdapterPosition] - // Navigate to galleryListScene to clear nav checked item navAnimated(R.id.galleryListScene, ListUrlBuilder().apply { set(q) }.toStartArgs()) } else { - mUrlBuilder.keyword = keywords[holder.bindingAdapterPosition].toString() - mUrlBuilder.mJumpTo = null + if (mIsTopList) { + mUrlBuilder.keyword = keywords[holder.bindingAdapterPosition].toString() + mUrlBuilder.mJumpTo = null + } else { + val q = mQuickSearchList[holder.bindingAdapterPosition] + mUrlBuilder.set(q) + } onUpdateUrlBuilder() mAdapter?.refresh() } From 1d0c76b2b2fb4f9a9b4dd534c29feaca11506e5c Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Tue, 26 Sep 2023 19:26:32 +0800 Subject: [PATCH 33/44] Fix OOB access when no results found --- .../java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt index ce7cb4b57..a5a89d91a 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt @@ -515,14 +515,15 @@ class GalleryListScene : SearchBarScene() { tip: TextView, ) { val context = context ?: return + if (mAdapter!!.itemCount == 0) return // Can't add image search as quick search if (MODE_IMAGE_SEARCH == mUrlBuilder.mode) { showTip(R.string.image_search_not_quick_search, LENGTH_LONG) return } - val gi = mAdapter?.peek(binding.recyclerView.layoutManager!!.firstVisibleItemPosition) - val next = gi?.gid?.plus(1) + val gi = mAdapter!!.peek(binding.recyclerView.layoutManager!!.firstVisibleItemPosition)!! + val next = gi.gid + 1 // Check duplicate for (q in mQuickSearchList) { @@ -557,7 +558,7 @@ class GalleryListScene : SearchBarScene() { } return@launchIO } - if (checked[0] && next != null) { + if (checked[0]) { text += "@$next" Settings.qSSaveProgress = true } else { From 198acef666cf18baa0aff8ddecab80cbdfde8089 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 21:03:06 +0000 Subject: [PATCH 34/44] Update dependency com.mikepenz:aboutlibraries-core to v10.9.1 --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index defb0fe6d..e29cae067 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -233,7 +233,7 @@ dependencies { implementation("com.squareup.okio:okio-jvm:3.5.0") - implementation("com.mikepenz:aboutlibraries-core:10.9.0") + implementation("com.mikepenz:aboutlibraries-core:10.9.1") implementation("dev.chrisbanes.insetter:insetter:0.6.1") // Dead Dependency implementation("dev.rikka.rikkax.core:core-ktx:1.4.1") From 8bf3f0f094eb615f3397f2006fa8bcbf68ced232 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 01:41:01 +0000 Subject: [PATCH 35/44] Update plugin com.mikepenz.aboutlibraries.plugin to v10.9.1 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 89a5b1634..1fe792444 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { kotlin("plugin.serialization") version "1.9.10" apply false id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false id("com.diffplug.spotless") version "6.21.0" apply false - id("com.mikepenz.aboutlibraries.plugin") version "10.9.1-debug01" apply false + id("com.mikepenz.aboutlibraries.plugin") version "10.9.1" apply false id("org.mozilla.rust-android-gradle.rust-android") version "0.9.3" apply false id("dev.shreyaspatil.compose-compiler-report-generator") version "1.1.0" apply false } From 7e4b6dbf31b1e8439ef864c94733b116858f11c1 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:47:57 +0800 Subject: [PATCH 36/44] Fix memory leak --- app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt index a9e2d55e7..ed7463132 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt @@ -140,6 +140,7 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene { override fun onDestroyView() { super.onDestroyView() mSearchViewOnBackPressedCallback.remove() + binding.root.removeAllViews() _binding = null } From 0d6fd8d7adace6beea5402afc8a025f751fae64a Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Wed, 27 Sep 2023 22:05:21 +0800 Subject: [PATCH 37/44] Workaround for SideSheetDialog (#31) --- app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.kt index 020371c7f..f33a07c03 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/BaseScene.kt @@ -156,7 +156,10 @@ abstract class BaseScene : Fragment() { } hideSoftInput() createDrawerView(savedInstanceState)?.let { - sideSheetDialog = SideSheetDialog(requireContext()).apply { + sideSheetDialog = object : SideSheetDialog(requireContext()) { + // Dirty workaround + override fun cancel() = hide() + }.apply { window?.decorView?.apply { val owner = viewLifecycleOwner setViewTreeLifecycleOwner(owner) From 9f500b85e63716e21e651de6ea81bb45475e556b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:40:08 +0000 Subject: [PATCH 38/44] Update plugin com.android.application to v8.1.2 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1fe792444..4ae5a7c5f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.android.application") version "8.1.1" apply false + id("com.android.application") version "8.1.2" apply false kotlin("android") version "1.9.10" apply false kotlin("plugin.serialization") version "1.9.10" apply false id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false From 5aaa1bb5b3541230027930878d914b7b06768627 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:20:43 +0800 Subject: [PATCH 39/44] Fix spotless --- app/build.gradle.kts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e29cae067..50290a43b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -192,10 +192,10 @@ dependencies { implementation("androidx.lifecycle:lifecycle-process:2.6.2") // https://developer.android.com/jetpack/androidx/releases/navigation - val nav_version = "2.7.3" - implementation("androidx.navigation:navigation-fragment-ktx:$nav_version") - implementation("androidx.navigation:navigation-ui-ktx:$nav_version") - implementation("androidx.navigation:navigation-compose:$nav_version") + val navigation = "2.7.3" + implementation("androidx.navigation:navigation-fragment-ktx:$navigation") + implementation("androidx.navigation:navigation-ui-ktx:$navigation") + implementation("androidx.navigation:navigation-compose:$navigation") // https://developer.android.com/jetpack/androidx/releases/paging val paging = "3.2.1" @@ -205,9 +205,9 @@ dependencies { implementation("androidx.recyclerview:recyclerview-selection:1.2.0-alpha01") // https://developer.android.com/jetpack/androidx/releases/room - val room_version = "2.6.0-rc01" - ksp("androidx.room:room-compiler:$room_version") - implementation("androidx.room:room-paging:$room_version") + val room = "2.6.0-rc01" + ksp("androidx.room:room-compiler:$room") + implementation("androidx.room:room-paging:$room") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01") implementation("androidx.work:work-runtime-ktx:2.8.1") @@ -215,9 +215,9 @@ dependencies { implementation("com.github.chrisbanes:PhotoView:2.3.0") // Dead Dependency implementation("com.github.tachiyomiorg:DirectionalViewPager:1.0.0") // Dead Dependency // https://github.com/google/accompanist/releases - val accompanist_version = "0.32.0" - implementation("com.google.accompanist:accompanist-themeadapter-material3:$accompanist_version") - implementation("com.google.accompanist:accompanist-webview:$accompanist_version") + val accompanist = "0.32.0" + implementation("com.google.accompanist:accompanist-themeadapter-material3:$accompanist") + implementation("com.google.accompanist:accompanist-webview:$accompanist") implementation("com.google.android.material:material:1.11.0-alpha03") val splitties = "3.0.0" @@ -299,7 +299,11 @@ spotless { ktlint() } kotlinGradle { - ktlint() + ktlint().editorConfigOverride( + mapOf( + "ktlint_standard_multiline-expression-wrapping" to "disabled", + ), + ) } } From 8469eac18cae8ed33c38decf00a703e93068e48b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 07:35:40 +0000 Subject: [PATCH 40/44] Update plugin com.diffplug.spotless to v6.22.0 (#33) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4ae5a7c5f..c951ed551 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ plugins { kotlin("android") version "1.9.10" apply false kotlin("plugin.serialization") version "1.9.10" apply false id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false - id("com.diffplug.spotless") version "6.21.0" apply false + id("com.diffplug.spotless") version "6.22.0" apply false id("com.mikepenz.aboutlibraries.plugin") version "10.9.1" apply false id("org.mozilla.rust-android-gradle.rust-android") version "0.9.3" apply false id("dev.shreyaspatil.compose-compiler-report-generator") version "1.1.0" apply false From 213133ab45c2fdfaf5acf9611a646b887841a826 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 30 Sep 2023 19:14:52 +0800 Subject: [PATCH 41/44] Fix SignInScreen drawing behind the system bars --- .../main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt index f79806083..73ea2bac3 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/login/SignInScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState @@ -181,7 +182,7 @@ fun SignInScreen(windowSizeClass: WindowSizeClass) { when (windowSizeClass.widthSizeClass) { WindowWidthSizeClass.Compact, WindowWidthSizeClass.Medium -> { Column( - modifier = Modifier.padding(dimensionResource(id = R.dimen.keyline_margin)).fillMaxSize().verticalScroll(rememberScrollState()), + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).systemBarsPadding().padding(dimensionResource(id = R.dimen.keyline_margin)), horizontalAlignment = Alignment.CenterHorizontally, ) { Image( @@ -266,7 +267,7 @@ fun SignInScreen(windowSizeClass: WindowSizeClass) { } WindowWidthSizeClass.Expanded -> { Row( - modifier = Modifier.padding(dimensionResource(id = R.dimen.keyline_margin)).fillMaxSize().verticalScroll(rememberScrollState()), + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).systemBarsPadding().padding(dimensionResource(id = R.dimen.keyline_margin)), verticalAlignment = Alignment.CenterVertically, ) { Column( From c0348484fe42628ea6b801c5767a57104cbbd523 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 30 Sep 2023 19:17:23 +0800 Subject: [PATCH 42/44] Fix padding for the IME --- .../main/java/com/hippo/ehviewer/ui/ConfigureActivity.kt | 3 +++ .../java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt | 8 ++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/ConfigureActivity.kt b/app/src/main/java/com/hippo/ehviewer/ui/ConfigureActivity.kt index fddd2023b..f72c7da1c 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/ConfigureActivity.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/ConfigureActivity.kt @@ -5,10 +5,12 @@ import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.foundation.layout.imePadding import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.SideEffect import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.Modifier import androidx.core.view.WindowCompat import androidx.navigation.NavController import androidx.navigation.compose.NavHost @@ -46,6 +48,7 @@ class ConfigureActivity : EhActivity() { } else { BASE_SETTINGS_SCREEN }, + modifier = Modifier.imePadding(), enterTransition = { slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Up, tween(200)) }, exitTransition = { fadeOut(tween(200)) }, popEnterTransition = { fadeIn(tween(200)) }, diff --git a/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt b/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt index ac0f7718d..2e1a29998 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt @@ -8,14 +8,11 @@ import android.util.AttributeSet import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ElevatedCard @@ -82,7 +79,7 @@ class SearchLayout @JvmOverloads constructor( } } Mdc3Theme { - Column(modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.search_layout_margin_h)).imePadding().verticalScroll(rememberScrollState())) { + Column(modifier = Modifier.imePadding().verticalScroll(rememberScrollState()).navigationBarsPadding().padding(horizontal = dimensionResource(id = R.dimen.search_layout_margin_h))) { AnimatedVisibility(visible = vm.isNormalMode) { ElevatedCard(modifier = Modifier.fillMaxWidth().padding(vertical = dimensionResource(id = R.dimen.search_layout_margin_v))) { Column(modifier = Modifier.padding(horizontal = dimensionResource(id = R.dimen.search_category_padding_h), vertical = dimensionResource(id = R.dimen.search_category_padding_v))) { @@ -143,7 +140,6 @@ class SearchLayout @JvmOverloads constructor( text = { Text(text = stringResource(id = R.string.search_image)) }, ) } - Spacer(modifier = Modifier.height(WindowInsets.systemBars.asPaddingValues().calculateBottomPadding())) } } } From 4a83829dfd0ed2cfa9b9650bbcece8a5ce2b49a5 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 30 Sep 2023 19:49:21 +0800 Subject: [PATCH 43/44] Fix padding for scrollable --- .../java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt | 4 ++-- .../java/com/hippo/ehviewer/ui/login/SelectSiteScreen.kt | 6 ++---- .../main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt | 4 +--- .../java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt | 5 +---- .../java/com/hippo/ehviewer/ui/settings/DownloadScreen.kt | 5 +---- .../main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt | 5 +---- .../java/com/hippo/ehviewer/ui/settings/MyTagsScreen.kt | 2 +- .../java/com/hippo/ehviewer/ui/settings/UConfigScreen.kt | 2 +- .../java/com/hippo/ehviewer/ui/webview/WebViewScreen.kt | 2 +- 9 files changed, 11 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt index cd9f92c59..81519e0d6 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/login/CookieSignInScreen.kt @@ -257,7 +257,7 @@ fun CookieSignInScene(windowSizeClass: WindowSizeClass) { when (windowSizeClass.widthSizeClass) { WindowWidthSizeClass.Compact, WindowWidthSizeClass.Medium -> { Column( - modifier = Modifier.padding(dimensionResource(id = R.dimen.keyline_margin)).padding(padding).fillMaxSize().verticalScroll(rememberScrollState()), + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(padding).padding(dimensionResource(id = R.dimen.keyline_margin)), horizontalAlignment = Alignment.CenterHorizontally, ) { Icon( @@ -284,7 +284,7 @@ fun CookieSignInScene(windowSizeClass: WindowSizeClass) { } WindowWidthSizeClass.Expanded -> { Row( - modifier = Modifier.padding(dimensionResource(id = R.dimen.keyline_margin)).padding(padding).verticalScroll(rememberScrollState()), + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(padding).padding(dimensionResource(id = R.dimen.keyline_margin)), verticalAlignment = Alignment.CenterVertically, ) { Column( diff --git a/app/src/main/java/com/hippo/ehviewer/ui/login/SelectSiteScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/login/SelectSiteScreen.kt index 72051539a..5189f037d 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/login/SelectSiteScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/login/SelectSiteScreen.kt @@ -5,12 +5,10 @@ import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SegmentedButton @@ -45,7 +43,7 @@ fun SelectSiteScreen() { } Column( - modifier = Modifier.padding(WindowInsets.systemBars.asPaddingValues()).padding(horizontal = dimensionResource(R.dimen.keyline_margin)).padding(top = dimensionResource(R.dimen.keyline_margin)).fillMaxSize(), + modifier = Modifier.systemBarsPadding().padding(horizontal = dimensionResource(R.dimen.keyline_margin)).padding(top = dimensionResource(R.dimen.keyline_margin)).fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { Text( diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt index 8ceb72a1e..2b64ec206 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/AboutScreen.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -84,7 +83,7 @@ fun AboutScreen() { }, snackbarHost = { SnackbarHost(snackbarHostState) }, ) { paddingValues -> - Column(modifier = Modifier.padding(top = paddingValues.calculateTopPadding()).nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState())) { + Column(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState()).padding(paddingValues)) { Preference( title = stringResource(id = R.string.settings_about_declaration), summary = stringResource(id = R.string.settings_about_declaration_summary), @@ -127,7 +126,6 @@ fun AboutScreen() { launchSnackBar(ExceptionUtils.getReadableString(it)) } } - Spacer(modifier = Modifier.size(paddingValues.calculateBottomPadding())) } } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt index f7a18d2be..ed4f71299 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/AdvancedScreen.kt @@ -7,9 +7,7 @@ import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS import android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -70,7 +68,7 @@ fun AdvancedScreen() { }, snackbarHost = { SnackbarHost(snackbarHostState) }, ) { paddingValues -> - Column(modifier = Modifier.padding(top = paddingValues.calculateTopPadding()).nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState())) { + Column(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState()).padding(paddingValues)) { SwitchPreference( title = stringResource(id = R.string.settings_advanced_save_parse_error_body), summary = stringResource(id = R.string.settings_advanced_save_parse_error_body_summary), @@ -225,7 +223,6 @@ fun AdvancedScreen() { } } } - Spacer(modifier = Modifier.size(paddingValues.calculateBottomPadding())) } } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/DownloadScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/DownloadScreen.kt index b0ed1b638..3476a2d44 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/DownloadScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/DownloadScreen.kt @@ -5,9 +5,7 @@ import android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -74,7 +72,7 @@ fun DownloadScreen() { }, snackbarHost = { SnackbarHost(snackbarHostState) }, ) { paddingValues -> - Column(modifier = Modifier.padding(top = paddingValues.calculateTopPadding()).nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState())) { + Column(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState()).padding(paddingValues)) { var downloadLocationState by ::downloadLocation.observed val cannotGetDownloadLocation = stringResource(id = R.string.settings_download_cant_get_download_location) val selectDownloadDirLauncher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocumentTree()) { treeUri -> @@ -232,7 +230,6 @@ fun DownloadScreen() { it.printStackTrace() } } - Spacer(modifier = Modifier.size(paddingValues.calculateBottomPadding())) } } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt index b29efdf84..ade09eed8 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/EhScreen.kt @@ -4,9 +4,7 @@ import android.content.DialogInterface import android.os.Build import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -90,7 +88,7 @@ fun EhScreen() { ) { paddingValues -> val touristMode = stringResource(id = R.string.settings_eh_identity_cookies_tourist) val copiedToClipboard = stringResource(id = R.string.copied_to_clipboard) - Column(modifier = Modifier.padding(top = paddingValues.calculateTopPadding()).nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState())) { + Column(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection).verticalScroll(rememberScrollState()).padding(paddingValues)) { Preference( title = stringResource(id = R.string.account_name), summary = Settings.displayName ?: touristMode, @@ -343,7 +341,6 @@ fun EhScreen() { ) } } - Spacer(modifier = Modifier.size(paddingValues.calculateBottomPadding())) } } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/MyTagsScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/MyTagsScreen.kt index 363774031..3a0d3116c 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/MyTagsScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/MyTagsScreen.kt @@ -38,7 +38,7 @@ fun MyTagsScreen() { val state = rememberWebViewState(url = url) WebView( state = state, - modifier = Modifier.padding(top = paddingValues.calculateTopPadding()).fillMaxSize(), + modifier = Modifier.padding(paddingValues).fillMaxSize(), onCreated = { it.setDefaultSettings() }, diff --git a/app/src/main/java/com/hippo/ehviewer/ui/settings/UConfigScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/settings/UConfigScreen.kt index d21fb8a14..7288369bf 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/settings/UConfigScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/settings/UConfigScreen.kt @@ -62,7 +62,7 @@ fun UConfigScreen() { val state = rememberWebViewState(url = url) WebView( state = state, - modifier = Modifier.padding(top = paddingValues.calculateTopPadding()).fillMaxSize(), + modifier = Modifier.padding(paddingValues).fillMaxSize(), onCreated = { it.setDefaultSettings() }, diff --git a/app/src/main/java/com/hippo/ehviewer/ui/webview/WebViewScreen.kt b/app/src/main/java/com/hippo/ehviewer/ui/webview/WebViewScreen.kt index 9a83c4ec0..f99686352 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/webview/WebViewScreen.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/webview/WebViewScreen.kt @@ -34,7 +34,7 @@ fun WebViewScreen(url: String, onNavigateUp: () -> Unit) { ) { paddingValues -> WebView( state = state, - modifier = Modifier.padding(top = paddingValues.calculateTopPadding()).fillMaxSize(), + modifier = Modifier.padding(paddingValues).fillMaxSize(), onCreated = { it.setDefaultSettings() }, ) DisposableEffect(Unit) { From cac65d9030b7500f236cc3039bbe7af6e0383bb0 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Sat, 30 Sep 2023 23:03:35 +0800 Subject: [PATCH 44/44] Fix insets for pre API 30 --- .../main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt | 2 ++ app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt index a5a89d91a..41b1a39a0 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.kt @@ -27,6 +27,7 @@ import android.view.ViewGroup import android.view.ViewPropertyAnimator import android.widget.TextView import androidx.activity.OnBackPressedCallback +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.material3.Text import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.stringResource @@ -332,6 +333,7 @@ class GalleryListScene : SearchBarScene() { ), ) mViewTransition = BringOutTransition(binding.contentLayout.contentView, binding.searchLayout) + binding.searchLayout.consumeWindowInsets = false binding.searchLayout.setViewTreeViewModelStoreOwner(this) binding.fastScroller.setOnDragHandlerListener(object : OnDragHandlerListener { override fun onStartDragHandler() {} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt index ed7463132..1f6dfd627 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/SearchBarScene.kt @@ -11,6 +11,7 @@ import androidx.annotation.CallSuper import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -82,6 +83,7 @@ abstract class SearchBarScene : BaseScene(), ToolBarScene { onApplySearch() true } + binding.searchBarList.consumeWindowInsets = false binding.searchBarList.setMD3Content { LazyColumn(contentPadding = WindowInsets.navigationBars.asPaddingValues()) { items(mSuggestionList) {