Compare commits

...
2790 Commits
Author SHA1 Message Date
FooIbar fe4ab6fdab Prepare for release 1.13.0
Releases / build (push) Has been cancelled
2024-11-01 21:03:04 +08:00
FooIbar e60b6922c3 Prevent coil from adding cache-control headers
ConnectivityChecker is not reliable when used with VPN on old platforms.
2024-11-01 19:23:14 +08:00
Re*Index. (ot_inc) d3d2c907ad Update & Fix Japanese strings 2024-11-01 17:03:25 +08:00
FooIbar 84306e0b28 Use shallow clone to fetch git dependencies 2024-11-01 12:44:47 +08:00
FooIbar f7c2148d5f Update description of "view original image" 2024-11-01 12:05:40 +08:00
FooIbar 46e5a0e121 Update renovate config 2024-11-01 11:39:34 +08:00
renovate[bot] 2f5b52f12c Update AGP to v8.8.0-alpha09 2024-10-31 22:58:11 +00:00
renovate[bot] 20f9120583 Update plugin com.android.settings to v8.8.0-alpha09 2024-10-31 22:55:48 +00:00
FooIbar e65428cae1 Use SecureTextField for password 2024-10-31 23:51:26 +08:00
Dude so hot e5862e807c Fix to not add padding manually 2024-10-31 23:08:53 +08:00
Dude so hot 911fb3cae0 Update to use bracketCase 2024-10-31 22:17:45 +08:00
d76821f6a6 Unify decode phase to PageLoader (#1848)
* Make PageLoader size RAII

* Unify decode phase to PageLoader

* Fixes

* Fixes

* Fixes

* Refine

* Refine name

* Fixes

* Refine

* Refine

* Refine

* Refine

* Refine

* Refine

* Refine

* Revert

* Fixes

* Fixes

* Fixes

* Fixes

* Fixes

* Invalidate page cache on retryPage

* Value class

* Cancel bounds takes IntRange

* SpiderQueen awaitReade spread exception

* Reorder

* Fix

* Fix

* Refine

* Split install procress

* Interface default method

* Revert

* Revert

* Fix to clear error state

* Update app/src/main/kotlin/com/hippo/ehviewer/gallery/PageLoader.kt

Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>

* Refine

* Refine

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-10-31 12:30:52 +00:00
renovate[bot] 1d5a680a5b Update dependency androidx.work:work-runtime to v2.10.0 2024-10-31 01:19:56 +00:00
renovate[bot] 2f38e17fd6 Update dependency androidx.core:core-ktx to v1.15.0 2024-10-31 01:19:11 +00:00
renovate[bot] 7de4bea5f7 Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0 2024-10-31 00:30:00 +00:00
renovate[bot] 35db8baa2a Update dependency androidx.compose:compose-bom-alpha to v2024.10.01 2024-10-31 00:29:50 +00:00
renovate[bot] e774dd3a6c Update benchmark to v1.4.0-alpha04 2024-10-30 21:13:16 +00:00
renovate[bot] f3619c6b43 Update dependency androidx.activity:activity-compose to v1.10.0-alpha03 2024-10-30 21:12:43 +00:00
renovate[bot] b807081f9d Update androidx.room to v2.7.0-alpha11 2024-10-30 19:03:46 +00:00
renovate[bot] 0807d7f1ce Update androidx.lifecycle to v2.9.0-alpha06 2024-10-30 19:03:18 +00:00
FooIbar 8b6894716b Remove fixed ktor workaround 2024-10-30 23:21:00 +08:00
Dude so hot cb733d8e38 Move ktlint to stable 2024-10-30 23:11:19 +08:00
FooIbar d9c7daebea Fix save image filename for external archives 2024-10-30 23:00:34 +08:00
FooIbar bbe8fd6b8f Use .editorconfig to disable ktlint rule (#1844) 2024-10-30 13:58:53 +00:00
Dude so hot 8f8fe513fa Cleanup ctor 2024-10-30 20:30:53 +08:00
Dude so hot 8a4df1f2ba Disable ktlint_standard_class-signature 2024-10-30 20:30:53 +08:00
Dude so hot dacbf5edb3 Fix thumb extension for webp 2024-10-30 19:08:52 +08:00
Dude so hot 4e145f46db Demagic DownloadThumbInterceptor 2024-10-30 19:08:52 +08:00
renovate[bot] 53dc622376 Update dependency io.ktor:ktor-client-okhttp to v3.0.1 2024-10-29 23:37:20 +00:00
renovate[bot] aab8fabb1f Disable SaveBodyPlugin & fix non-redirect Ktor client defaults 2024-10-29 16:21:19 +00:00
FooIbar 86bb240633 Disable Cronet on some incompatible devices 2024-10-29 23:41:40 +08:00
Dude so hot c6b3aec1af Fix build 2024-10-29 23:35:59 +08:00
Dude so hot e6c4b32a47 Use defaultRequest 2024-10-29 23:35:59 +08:00
Dude so hot b71e83047d Install UA for ktor client 2024-10-29 23:35:59 +08:00
Dude so hot 8609336240 Move to use BlackholeDecoder.Factory() 2024-10-29 23:35:59 +08:00
FooIbar ded11a81a5 Refine cache key for v2 gallery preview 2024-10-29 21:17:45 +08:00
renovate[bot]andDude so hot 0c00ea9292 Refactor PageLoader (#1830)
* Cleanup PageLoader

* Refactor ReaderScreen

* Refactor EhPageLoader

* Refine

* Refine

* Refine

* Refine

* Refine

* Don't inline

* Fix recompose

* Merge PageLoader

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-29 08:10:52 +00:00
FooIbar 672b53d8a9 Migrate to settings plugin and update NDK to r27c 2024-10-29 15:27:08 +08:00
FooIbar bc5032b2d0 Fix off-screen fetcher jobs blocking decode queue 2024-10-29 06:56:24 +08:00
renovate[bot] 4cefa439ec Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-rc02 2024-10-28 21:26:43 +00:00
FooIbar 4d2b7b3ad0 Adapt to the upcoming thumbnail changes (#1823) 2024-10-28 22:55:27 +08:00
FooIbar 58f85cc436 Clean up or parameter as it's no longer required 2024-10-28 20:14:52 +08:00
FooIbar 5c50d7622b Unify normal and small thumbnails parsing 2024-10-28 20:14:52 +08:00
renovate[bot] e90b31bf69 Update Rust crate quick-xml to 0.37 2024-10-28 00:48:23 +00:00
renovate[bot] b43d60138b Lock file maintenance 2024-10-28 00:47:49 +00:00
FooIbar 9f4faebfe6 Use ktor plugin for download timeout 2024-10-28 00:00:48 +08:00
FooIbar b6f84d8de6 Group ad utils and fix a main thread IO 2024-10-27 22:58:15 +08:00
FooIbar 230eec7c59 Revert "Block AD in Large preview (#1694)"
This reverts commit 04ee1a63

Reason for revert: Obsoleted by the upcoming changes
2024-10-27 22:58:15 +08:00
renovate[bot]andDude so hot 3b9cfefd5f Fix Small Preview CrossFade not work (#1816)
* Fix Small Preview CrossFade not work

* Abstract

* Update MergeInterceptor.kt

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-27 12:01:53 +00:00
FooIbar c1b701f1f9 Only check file integrity for images served by H@H
URLs returned by non-H@H servers may not contain file hash for resampled
images.
2024-10-27 16:10:47 +08:00
FooIbar 4744caaacc Show search warnings (if any) when no hits found 2024-10-27 15:48:46 +08:00
FooIbar b58912462a Make image limits description unambiguous 2024-10-27 12:36:56 +08:00
FooIbar f3cadf594d Fix crash on devices without WallpaperService 2024-10-27 11:30:37 +08:00
FooIbar a8834ee21c Fix menu click glitch after pager type change 2024-10-26 22:18:52 +08:00
FooIbar 0c59403e49 Add support for arrow key navigation (#1808)
* Add support for arrow key navigation

* Refactor key event handler to use Compose KeyEvent

Also removed volume key configurations.

* Fix focus requester
2024-10-26 12:54:29 +00:00
FooIbar 431a771672 Relax regex for the upcoming WebP adoption 2024-10-26 13:54:16 +08:00
Dude so hot b043b06208 Refine TagNamespace 2024-10-26 10:45:23 +08:00
renovate[bot] abccf713df Update AGP to v8.8.0-alpha08 2024-10-25 19:21:42 +00:00
renovate[bot] 4b83f6f28f Update dependency com.google.devtools.ksp to v2.1.0-Beta2-1.0.26 2024-10-25 19:19:06 +00:00
renovate[bot]andDude so hot e843a547a5 Make GalleryTagGroup immutable & non-empty (#1798)
* Make GalleryTagGroup immutable & non-empty

* Refine

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-25 15:18:12 +00:00
小白-白 40d9bfa30b Fix thumb parsing when labels are enabled 2024-10-25 22:00:53 +08:00
小白-白 69669f0a50 Fix archive download 2024-10-25 21:04:00 +08:00
Dude so hot 4c20d27d33 Optimize regex with Chatgpt 2024-10-25 18:34:00 +08:00
小白-白 06eb277b34 Fix preview parser 2024-10-25 16:18:52 +08:00
renovate[bot] 86120277c7 Update dependency androidx.work:work-runtime to v2.10.0-rc01 2024-10-24 18:16:09 +00:00
renovate[bot]andDude so hot 62927cb6a8 Kill Legacy TextView (#1786)
* Kill Legacy TextView

* Fix textStyle

* Fix color

* Add breakToTextAndUrl

* Impl breakToTextAndUrl

* Fix OOB

* Update GalleryCommentsScreen.kt

* Fix bug

* Fix color

* Refine regex

* Add undeline as well

* Refine

* Revert

* Don't break if not show image

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-24 23:38:27 +08:00
renovate[bot]andDude so hot 22f31f2ebc Remember pageloader in ViewModel (#1780)
* Remember pageloader in ViewModel

* Fix hang on

* Refine

* Move ***InVM functions to ViewModelState

* Add rememberInVM overload takes no key

* Support asyncInVM & launchInVM with key

* Move UNCHECKED_CAST code

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-23 21:57:28 +08:00
FooIbar c8cfaeecf6 Clean up java.nio APIs usage to avoid desugaring 2024-10-23 18:03:45 +08:00
FooIbar 714d334067 Misc cleanup 2024-10-23 15:20:43 +08:00
FooIbar ca324995b3 Clean up ExceptionUtils with Either.catch 2024-10-23 15:20:43 +08:00
FooIbar f301eab5b1 Fix preview list not recomposing on detail refresh 2024-10-23 11:27:04 +08:00
FooIbar 87ac60a3ab Clean up GalleryListUrlParser/Builder 2024-10-22 22:52:36 +08:00
FooIbar a2f89f07fa Use e-hentai thumbnail server by default 2024-10-22 21:40:21 +08:00
renovate[bot]andDude so hot 57d7d2b798 Kill Switch (#1778)
* Kill Switch

* Refine comment

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-21 13:32:01 +00:00
Dude so hot 6f3bc25b64 Don't apply NonCancellable to H@H large images 2024-10-21 20:54:37 +08:00
Dude so hot 62477dac87 Fix NamedSemaphore naming 2024-10-21 20:54:37 +08:00
Dude so hot 0dfee513f4 Lock concurrency for Normal previews as well 2024-10-21 20:54:37 +08:00
Dude so hot 31f97cb840 Introduce NamedSemaphore 2024-10-21 20:54:37 +08:00
Dude so hot 93e2d36dbb Share semaphore 2024-10-21 20:54:37 +08:00
Dude so hot aed3d08167 Fetch from h1 server is NonCancellable 2024-10-21 20:54:37 +08:00
Dude so hot 9c5f11dd9d Fix step 2024-10-21 20:54:37 +08:00
Dude so hot 1af7aa8a16 Allow configure thumb concurrency temporarily 2024-10-21 20:54:37 +08:00
Dude so hot cf6f793478 Limit thumb fetcher concurrency 2024-10-21 20:54:37 +08:00
Dude so hot 145948f506 Add HttpClientConfig<T>.configureCommon 2024-10-21 20:54:37 +08:00
FooIbar b068492d10 Refine caching configuration in CI 2024-10-21 12:13:03 +08:00
renovate[bot] 8c94d39ae4 Lock file maintenance 2024-10-21 01:43:19 +00:00
Dude so hot c584d72f41 Rotate hue ourselves 2024-10-20 22:31:16 +08:00
Dude so hot cfd248f818 Support WallPaper DynamicColor on O_MR1 above 2024-10-20 22:31:16 +08:00
Dude so hot b9e59ee2f8 Harmonize with Kolor functions 2024-10-20 22:31:16 +08:00
Dude so hot 439899fbdc Use Expressive MotionScheme 2024-10-20 22:31:16 +08:00
Dude so hot 177c1889fa Import material-kolor 2024-10-20 22:31:16 +08:00
FooIbar ebce847724 Update OkHttp and configure async DNS 2024-10-20 19:32:26 +08:00
renovate[bot]andDude so hot c6b6d9a310 Fallback to Okhttp instead (#1771)
* Fallback to Okhttp instead

* Drop unused proguard

* Exclude okhttp3 public suffix

* Refine

* Refine

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-20 09:21:14 +00:00
Dude so hot 6601a45472 GP divide by 1k 2024-10-19 22:53:37 +08:00
Dude so hot d66fb9a783 RollingNumber support separator 2024-10-19 22:53:37 +08:00
Dude so hot c244369875 Apply RollingNumber to quota 2024-10-19 22:53:37 +08:00
Dude so hot f9c812864e Apply RollingNumber to gp & c 2024-10-19 22:53:37 +08:00
Dude so hot 87d0cdd9e5 Fix to measure RollingNumber with +inf maxHeight 2024-10-19 22:53:37 +08:00
Dude so hot d237a18aae Refine Naming 2024-10-19 21:36:40 +08:00
Dude so hot 0159cf30ae NamedMutex shares MutexPool 2024-10-19 21:36:40 +08:00
Dude so hot 6aba1670ec Refine NamedMutex 2024-10-19 21:36:40 +08:00
Dude so hot 447a31ea00 Restore default MaxConnPerRoute 2024-10-19 21:36:40 +08:00
FooIbar 9e410a61ef Pin Rust toolchain version to 1.81.0
1.82.0 has a severe binary size regression (+36%)
2024-10-19 21:27:34 +08:00
FooIbar 4588b7eaa5 Refine resources packing options 2024-10-19 15:23:24 +08:00
FooIbar aef55c9207 Use Cargo.lock for reproducible builds 2024-10-19 15:23:24 +08:00
renovate[bot] 9a587e9dd2 Update plugin composeCompilerReportGenerator to v1.4.1 2024-10-19 06:40:15 +00:00
renovate[bot] cbe834c71d Update Kotlin & KSP 2024-10-19 08:46:37 +08:00
FooIbar 020495cebf Fix comparison with leading zeros and clean up 2024-10-19 00:31:38 +08:00
FooIbar 54d3cccb67 Fix AnchoredDraggable fling behavior 2024-10-19 00:29:47 +08:00
renovate[bot] b4adf57f39 Update compose.destinations to v2.1.0-beta14 2024-10-18 13:34:21 +00:00
b796dbcde3 Partially Reland "Use Apache5 as fallback HTTP engine" (#1755)
* Use Apache5 as fallback HTTP engine

* Fix R8

* Depolymorphism CronetEngine context

* Conditionally insert conscrypt

* Limit IO thread cnt to 1

* Don't package compose destination as well

* Refine

* Add an option for debugging HTTP engines

---------

Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-18 10:18:46 +00:00
FooIbar ba2c69690f Revert "Use Apache5 as fallback HTTP engine (#1752)"
This reverts commit c3b60f1eac.
2024-10-18 16:16:36 +08:00
FooIbarandDude so hot c3b60f1eac Use Apache5 as fallback HTTP engine (#1752)
* Use Apache5 as fallback HTTP engine

* Fix R8

* Depolymorphism CronetEngine context

* Drop Conscrypt, don't enforce anything

* Limit to 1 io thread count

* Fix H2 support below A10

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-18 15:57:42 +08:00
renovate[bot] 2bb387eeaf Update AGP to v8.8.0-alpha07 2024-10-17 22:50:11 +00:00
FooIbar fd67c733aa Always upload R8 reports 2024-10-18 00:17:44 +08:00
renovate[bot]andDude so hot eac7048360 Optimise non-fixed length RollingNumber (#1751)
* Try Optimise non-fixed length RollingNumber

* Apply RollingNumber to SliderPref

* Revert Debug

* RollingNumber handle negative value

* Fix typo

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-17 21:54:20 +08:00
renovate[bot]andDude so hot 34de943c9f Introduce RollingNumberPlaceholder (#1750)
* Introduce RollingNumberPlaceholder, sync page index double end style

* Cleanup

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-17 19:27:41 +08:00
renovate[bot] 302b43c9e8 Update dependency sh.calvin.reorderable:reorderable to v2.4.0 2024-10-17 09:02:20 +00:00
FooIbar 07b3917c4e Best effort for devices without DocumentsUI 2024-10-17 16:55:44 +08:00
FooIbar 1ace248121 Allow resetting to default download location 2024-10-17 16:55:44 +08:00
renovate[bot]andDude so hot 7a96feb049 Rolling number POC, convert page index (#1740)
* Rolling number POC, convert page index

* Refine

* Improve

* Comments

* Refine Comments

* Bigger number is from top

* Prepare to make content moveable

* Make content index reversed

* Use moveableContentOf

* Increase interval

* Fix calculation

* Fix calculation again

* Extract

* Refine

* Use zero-sized placeholder

* Fix width

* Allow RollingNumber have fixed width

* Improve comments

* Make moveableContent initialized lazily

* Reverse direction

* Avoid movableContentOf if width fixed

* Use Arrangement.spacedBy

* Improve animation

* Refine

* Fix comment

* Fix padding

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-17 06:07:49 +00:00
renovate[bot]andrenovate[bot] 5df1d099a1 Update dependency androidx.compose:compose-bom-alpha to v2024.10.00 (#1746)
* Update dependency androidx.compose:compose-bom-alpha to v2024.10.00

* Update Theme.k

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <99822064+revonateB0T@users.noreply.github.com>
2024-10-17 00:30:48 +00:00
renovate[bot] ed2db49cdb Update dependency androidx.core:core-ktx to v1.15.0-rc01 2024-10-17 00:23:24 +00:00
renovate[bot] 7b2c99357e Update androidx.lifecycle to v2.9.0-alpha05 2024-10-17 00:16:37 +00:00
renovate[bot] 4868c40795 Update androidx.room to v2.7.0-alpha10 2024-10-17 00:16:10 +00:00
renovate[bot]andrenovate[bot] 27ff17db50 Update benchmark to v1.4.0-alpha03 (#1743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <99822064+revonateB0T@users.noreply.github.com>
2024-10-17 00:15:47 +00:00
renovate[bot] c15a52eb2a Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0-rc01 2024-10-16 23:56:52 +00:00
FooIbar faa54dedb1 Migrate to BTF2
This reverts commit 8a29d46b
2024-10-16 11:14:54 +08:00
renovate[bot] 59bdb4b2f0 Update dependency io.github.pdvrieze.xmlutil:serialization to v0.90.2 2024-10-15 20:23:09 +00:00
renovate[bot] 4990d757ae Update dependency chrome to v130 2024-10-15 20:22:40 +00:00
FooIbar 5f71c3dcb4 Update Compose Material3 to 1.4 2024-10-15 23:58:56 +08:00
Dude so hot 1892a750b7 Address Code Review 2024-10-15 21:15:38 +08:00
Dude so hot 020f853bb1 MergeInterceptor use NamedMutex 2024-10-15 21:15:38 +08:00
Dude so hot 9ccddae60a Introduce Better NamedMutex 2024-10-15 21:15:38 +08:00
Dude so hot b7a2d93f03 Optimize rememberInVM allocation 2024-10-15 19:08:12 +08:00
Dude so hot 2fc8b421b0 Optimize collection access 2024-10-15 19:08:12 +08:00
Dude so hot 180466674f Optimize statesMap to use mutableIntObjectMapOf 2024-10-15 19:08:12 +08:00
Dude so hot ac23a4312d Address CR 2024-10-15 19:08:12 +08:00
Dude so hot aaea83b932 Minor cleanup GalleryDetailScreen 2024-10-15 19:08:12 +08:00
Dude so hot 8425ea0b2f Move SpiderDen file cache to use rwlock 2024-10-15 19:08:12 +08:00
Dude so hot 100a6569b7 Use rwlock 2024-10-15 13:40:02 +08:00
Dude so hot e8c4b9ab78 Ensure PageLoader cache sync 2024-10-15 13:03:18 +08:00
Dude so hot eff5467ccf Cleanup CrashHandler 2024-10-15 13:03:18 +08:00
Dude so hot 769308c9f0 Remove obsolete 2024-10-15 13:03:18 +08:00
Dude so hot e1de57c98c Ensure QrCodeInterceptor cache thread-safe 2024-10-15 13:03:18 +08:00
Dude so hot 9c6a5af87e Ensure FavouriteStatusRouter thread-safe 2024-10-15 13:03:18 +08:00
Dude so hot 9d88577108 Move to SieveCache 2024-10-15 13:03:18 +08:00
renovate[bot]andrenovate[bot] dbebc5956f Update AGP to v8.8.0-alpha06 (#1728)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <99822064+revonateB0T@users.noreply.github.com>
2024-10-15 02:30:35 +00:00
renovate[bot]andDude so hot 52ca5a7eb8 SpotlessAPply (#1729)
Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-10-15 02:19:56 +00:00
FooIbar 78b898dc5c Reduce build noise 2024-10-14 20:48:13 +08:00
Dude so hot 1e81157d5c Update VectorPainterCache to use MutableScatterMap 2024-10-14 13:27:49 +08:00
Dude so hot 5cff3db9b5 Drop unused local variable 2024-10-14 13:27:49 +08:00
Dude so hot 25fe80f252 Drop DismissDialogScope wrapper 2024-10-14 13:27:49 +08:00
Dude so hot 413bb2cd82 No longer need write permission as we copy magnet now 2024-10-14 13:27:49 +08:00
renovate[bot] b867bbc7a6 Lock file maintenance 2024-10-14 03:23:13 +00:00
Dude so hot 3bf6f763aa Optimise DialogState with value class 2024-10-13 20:48:24 +08:00
2c0d621b16 Add avatar (#1720)
* Load Avatar

* Click Avatar to show image limit

* Shared Limit among collection

* Cleanup and configure heartbeat

* Always refresh avatars

* Refine icons

* Avoid heartbeat

* Fix mistake

* No need to SharingStarted.WhileSubscribed

* Address code review

* Simply map error msg

* Convert limitFlow to stateFlow

* Fixes

* Refine retry logic

* Don't retry automatically

* Don't cache error result

* Animate quota changes

* Logout from guest mode via avatar

* No need to navigate explicitly as needSignIn is observed

* Make PostLogin not suspend

* More UX friendly

* Fix progressIndicator not disappear

* Use Either.catch.mapLeft

* Refine

* Add overload for awaitConfirmationOrCancel

* Log error with snackbar

* Refine

* Fix to use collectLatest

* Refine

* Refine

* Address cr

* Refine

* Animated loading

* Refine

* Fix

* Fix

* Refine image limits dialog

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-10-13 19:36:02 +08:00
renovate[bot] e930ebf42f Update dependency libarchive to v3.7.7 2024-10-13 10:41:48 +00:00
Dude so hot 4e3862b1c5 Move ImageSearchScreen 2024-10-12 21:21:14 +08:00
Dude so hot e3ffb9a473 Spilt ImageSearch from GalleryListScreen 2024-10-12 21:21:14 +08:00
FooIbar e485d79bb1 Drop torrent download in favor of magnet links 2024-10-12 15:26:37 +08:00
renovate[bot] 49edbb8185 Update compose.destinations to v2.1.0-beta13 2024-10-10 13:58:06 +00:00
renovate[bot] 32f7407752 Update dependency io.ktor:ktor-client-core to v3.0.0 2024-10-09 17:15:48 +00:00
renovate[bot]andFooIbar aef02d34a5 Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-rc01 (#1713)
* Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-rc01

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-10-08 11:24:43 +00:00
renovate[bot] bb2f9bb309 Lock file maintenance 2024-10-07 07:48:01 +00:00
FooIbar 140b6528a6 Fix ktlint snapshot 2024-10-07 15:40:23 +08:00
FooIbar fa3cf650ea Pin Compose Material3 version to 1.3 2024-10-05 16:11:48 +08:00
renovate[bot] cfe2cff74c Update AGP to v8.8.0-alpha05 2024-10-03 22:08:36 +00:00
renovate[bot] 1def52e41a Update dependency androidx.compose:compose-bom-alpha to v2024.09.03 2024-10-03 19:18:58 +00:00
renovate[bot] cc4eab3244 Update dependency io.ktor:ktor-client-core to v3.0.0-rc-2 2024-10-03 09:08:35 +00:00
renovate[bot] 4327e48c1f Update dependency androidx.profileinstaller:profileinstaller to v1.4.1 2024-10-03 00:25:35 +00:00
renovate[bot] c8c077c14b Update dependency androidx.work:work-runtime to v2.10.0-beta01 2024-10-03 00:25:19 +00:00
renovate[bot] f82221552b Update benchmark to v1.4.0-alpha02 2024-10-02 21:08:39 +00:00
renovate[bot] bfe0aad951 Update dependency androidx.core:core-ktx to v1.15.0-beta01 2024-10-02 21:08:05 +00:00
renovate[bot] 2f5d8edb03 Update androidx.lifecycle to v2.9.0-alpha04 2024-10-02 19:09:56 +00:00
renovate[bot] ac0acafff9 Update androidx.room to v2.7.0-alpha09 2024-10-02 19:09:27 +00:00
renovate[bot] 9333150c3b Update dependency liblzma to v5.6.3 2024-10-01 18:41:54 +00:00
renovate[bot] 0c71c6856b Update dependency chrome to v129 2024-10-01 05:59:07 +00:00
FooIbar 6a47a8a1e1 Use renovate to update Chrome version 2024-10-01 13:51:58 +08:00
renovate[bot]andDude so hot 04ee1a6362 Block AD in Large preview (#1694)
* Cleanup with `getOrPut`

* Refine `ArchivePageLoader` naming

* Move `PageLoader`

* Bump ktlint to fix when guards

* Extract `AdsPlaceholder`

* Detect QrCode for LargePreview

* Conditional detect

* Fixes

* Fixes

* Cleanup code

* Fix render

* Fixup hardware bitmap

* Original size to detect

* Log QrCode detect exception

* Don't mutate cached

* Refine ListUrlBuilder

* Move functions

* Enable preview adblocker for debug build only

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-09-30 21:09:56 +08:00
renovate[bot] 9ead29643d Lock file maintenance 2024-09-30 00:22:01 +00:00
FooIbar d8e7bd4ccc Prepare for next iteration 2024-09-28 22:57:59 +08:00
FooIbar dd2949638c Prepare for release 1.12.1
Releases / build (push) Has been cancelled
2024-09-28 22:57:17 +08:00
FooIbar f71aa4902b Prepare changelog for 1.12.1 (#1691)
[no ci]
2024-09-28 22:56:20 +08:00
FooIbar af7e411932 Refine GalleryMultiPageViewerPTokenParser 2024-09-28 00:01:21 +08:00
FooIbar c54ac1a4c0 Fix crash when download location is invalid 2024-09-27 19:57:47 +08:00
renovate[bot] 00d6a2e403 Update AGP to v8.8.0-alpha04 2024-09-27 02:08:47 +00:00
FooIbar b67d0938b0 Reapply "Add scroll bar to quick search and download label"
This reverts commit a52ab28534.
2024-09-26 19:12:46 +08:00
FooIbar 8447760cb5 Fix image download queue not respecting FIFO order 2024-09-25 22:58:36 +08:00
FooIbar 24d2072586 Use Downloads as start screen if device is offline (#1675) 2024-09-25 03:54:34 +00:00
renovate[bot] a52ab28534 Revert "Add scroll bar to quick search and download label"
This reverts commit 601713d8d7.
2024-09-25 08:25:04 +08:00
FooIbar 601713d8d7 Add scroll bar to quick search and download label 2024-09-25 07:38:20 +08:00
FooIbar 7bfa5be53c Fix concurrent creation of the same directory 2024-09-24 21:36:42 +08:00
renovate[bot] ae3a66903a Update dependency gradle to v8.10.2 2024-09-24 02:16:59 +00:00
renovate[bot] 5438fd5d9b Update AGP to v8.8.0-alpha03 2024-09-23 21:59:33 +00:00
FooIbar a74ffca03d Fix galleries with both artist and cosplayer tags
Legacy issue of E-Hentai's tag namespacing changes.
2024-09-24 00:38:24 +08:00
renovate[bot] c5a83d567e Update dependency libarchive to v3.7.6 2024-09-23 13:40:44 +00:00
FooIbar 1b1f781dd9 Update renovate config 2024-09-23 21:32:34 +08:00
renovate[bot] 988195e4fc Lock file maintenance 2024-09-23 00:49:24 +00:00
FooIbar 4d4124458d Fix reader prefetch when scroll direction changes 2024-09-22 16:19:24 +08:00
FooIbar 0ae2843676 Actually fix data import on Android V
This reverts commit 26921c8a
2024-09-21 23:10:50 +08:00
FooIbar beaddc9eeb Fix foreign key constraint violation on db import 2024-09-21 23:10:50 +08:00
FooIbar d843b3a14b Try to reduce false positives in ad detection 2024-09-21 20:05:01 +08:00
Dude so hot b9da0eda8b Cleanup 2024-09-20 20:01:49 +08:00
Dude so hot ba75cda036 Move navigation to use compose Rect 2024-09-20 20:01:49 +08:00
Dude so hot 9d59af29c5 Singleton Navigation 2024-09-20 20:01:49 +08:00
FooIbar 660d6e32f1 Cleanup 2024-09-20 19:50:13 +08:00
FooIbar c07c663105 Address deprecation 2024-09-20 19:50:13 +08:00
FooIbar 3673f6f7f9 Rename awaitPermissionOrCancel -> awaitConfirmationOrCancel 2024-09-20 19:50:13 +08:00
renovate[bot]andDude so hot e8120e12d0 ADT Page model (#1655)
* Enable when guards

* ADT Page model

* Refine

* Refine

* Remove type conversion

* Cleanup

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-09-20 16:19:59 +08:00
renovate[bot] f7459886b2 Update kotlinx.serialization to v1.7.3 2024-09-19 20:07:38 +00:00
FooIbar 6fe5319c08 Update Kotlin & KSP to 2.1.0-Beta1 2024-09-19 23:57:48 +08:00
FooIbar 3a42208a36 Merge GalleryPreviewScreen to GalleryDetailScreen (#1649) 2024-09-19 23:39:42 +08:00
FooIbar e4eacce5bf Update Compose BOM 2024-09-19 23:02:04 +08:00
FooIbar d1fdea8d3e Update libarchive to v3.7.5 2024-09-19 22:57:38 +08:00
98e452e39e Fastpath to create regioned hardware bitmap (#1647)
* kotlin side

* Impl

* Refine

* respect ahb align

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Don't copy unnecessary things

* Cleanup

* Recycle

* Revert "Disable `abortOnError` for lint in debug build"

This reverts commit cea06f0c

* Fix marshmallow build

* Fix cmake

* Address cr

* Refine

* Cleanup

* log it

---------

Signed-off-by: Dude so hot <djohn@fbi.gov>
Co-authored-by: Dude so hot <djohn@fbi.gov>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-09-19 14:25:55 +00:00
FooIbar 02e8fcc534 Fix lint
This reverts commit cea06f0c
2024-09-19 21:54:28 +08:00
renovate[bot]andDude so hot 70852c2725 Crop bitmap before draw (#1646)
* Crop bitmap before draw

* Spilt

* Refine

* Cleanup

* Address code review

* Address code review

* Address code review

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-09-19 07:56:24 +00:00
renovate[bot] ea67d6e078 Update benchmark to v1.4.0-alpha01 2024-09-18 22:15:18 +00:00
renovate[bot] d2aa3b5347 Update androidx.room to v2.7.0-alpha08 2024-09-18 22:14:40 +00:00
renovate[bot] 937792ba91 Update dependency androidx.work:work-runtime to v2.10.0-alpha04 2024-09-18 18:53:24 +00:00
renovate[bot] fcfdaf59f8 Update dependency androidx.lifecycle:lifecycle-process to v2.9.0-alpha03 2024-09-18 17:22:46 +00:00
renovate[bot] 0d4da998a1 Update dependency androidx.profileinstaller:profileinstaller to v1.4.0 2024-09-18 17:21:32 +00:00
FooIbar 0e7a32d9af [Marshmallow] Add ISRG Root X1 as a trusted root 2024-09-18 17:54:41 +08:00
FooIbar 4bb6b0baf6 Switch to rxing for QR code detection 2024-09-16 17:54:14 +08:00
renovate[bot] 0591b3224f Lock file maintenance 2024-09-16 00:10:00 +00:00
renovate[bot]andDude so hot eaf8dd21ff Crop border in Rust (#1631)
* Fix deref_mut_direct_bytebuffer lifetime

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Framework

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Add Infra

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Implement

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Refine

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Impl

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Fixes

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Implement

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Update profile code

* Remove corrent but slow code that slow for 1000x

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Revert "Remove corrent but slow code that slow for 1000x"

This reverts commit 644d093ddc20f4a129ee304157767707337d149d.

* Fix speed

Signed-off-by: Dude so hot <djohn@fbi.gov>

* refine

Signed-off-by: Dude so hot <djohn@fbi.gov>

* refine

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Refine

Signed-off-by: Dude so hot <djohn@fbi.gov>

* cleanup type conversion

Signed-off-by: Dude so hot <djohn@fbi.gov>

* cleanup

Signed-off-by: Dude so hot <djohn@fbi.gov>

* refine

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Remove C cropborder impl

* impl nth to accel

Signed-off-by: Dude so hot <djohn@fbi.gov>

* F**K

Signed-off-by: Dude so hot <djohn@fbi.gov>

---------

Signed-off-by: Dude so hot <djohn@fbi.gov>
Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-09-15 22:20:55 +08:00
Dude so hot 9bc6cccf26 buffer share same lifetime with jnienv
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot eb3b53ee5b Format
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot 731af586af Add safety hint for parse_marshal_inplace
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot 3acb70b8e1 Add safety hint for deref_mut_direct_bytebuffer
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot 836b1841e3 Add safety hint for with_bitmap_content
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot d37f4580a9 Rename to avoid clash
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot 70fc964b4d Fold get_bitmap_handle
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot c3c5fbfc79 Extract with_bitmap_content
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot 04103f9280 Extract detect_image_ad
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
Dude so hot 69370efcf5 Modularize QrCode
Signed-off-by: Dude so hot <djohn@fbi.gov>
2024-09-14 20:08:51 +08:00
renovate[bot]andDude so hot f0d3b0c8ae Misc updates (#1629)
* Respect Arch's ndk location

* Don't spam in debug build

* Cleanup

* Revert "Cleanup"

This reverts commit 45b9d76dd363aa1fd3d58b5102b68649028e313a.

* Revert "Respect Arch's ndk location"

This reverts commit 3fd773422d3ae440a6466e2fa161a45018fd8ed7.

* Respect Arch ndk location

---------

Co-authored-by: Dude so hot <djohn@fbi.gov>
2024-09-14 10:45:36 +00:00
FooIbar 370c485048 Update NDK to r27b and address deprecation 2024-09-14 17:07:04 +08:00
FooIbar 7e4c910cd7 Fix blocked image placeholder content scale 2024-09-14 16:06:09 +08:00
renovate[bot] e8c1c80ce5 Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-android to v1.9.0 2024-09-13 16:20:18 +00:00
0d55f319c9 Fuckoff External Ads (#1617)
* Add Rust implementation to detect QRCode from bitmap

* Add QRCodeInterceptor Framework

* Let image take hasQRCode info

* Keep ReaderPage index internal

* Move imageCache to use ReaderPage as key

* Make PageLoader size & pages internal

* Refine

* Kill entry if QRCode

* Rewrite request to respect index mapping

* Debug: enable by default

* Fix crash

* Fixup

* Fix identity

* Revert to lruCache to avoid crash

* Fixup

* Clippy check for android only

* Fixup

* Resolve clippy

* Switch

* Apply switch

* Restart pageloader restore pages

* Cleanup

* Cleanup

Signed-off-by: Dude so hot <djohn@fbi.gov>

* let it inference

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Don't detect border for ads

* Make coil interceptor runs in `Dispatchers.Default`

* Revert "Restart pageloader restore pages"

This reverts commit 8fd02fb7d9c677c119df72a767a6079f1899dc31.

* Revert drop page changes

* Use backGround color painter for ads

* Only check ads for tags contains extraneous ads

* Only check ads for head 5 images || tail 10 images

* Move strip ADs switch to AdvancedScreen

* Pick placeholder

* Show Placeholder

* Don't try to extract & decode

Signed-off-by: Dude so hot <djohn@fbi.gov>

* cleanup

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Naming

* Naming

* Naming

* Naming

* For ArchivePageLoader as well

* Hint

* Fix flicker

* Refine

* Naming

* QR -> Qr

* Naming

* QR -> Qr

* Naming

* Refine

* Revert

* Remove header check

* Allow show ads

* Adjust

* Refine

* Revert "Don't try to extract & decode"

This reverts commit f35ef46f6ffc81485cf0f4c646ed79e524c29d32.

Signed-off-by: Dude so hot <djohn@fbi.gov>

* be strict

Signed-off-by: Dude so hot <djohn@fbi.gov>

* Just Extract, don't decode

* Refine

* Refine placeholder

---------

Signed-off-by: Dude so hot <djohn@fbi.gov>
Co-authored-by: Dude so hot <djohn@fbi.gov>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-09-13 16:10:05 +00:00
FooIbar 42ed51094e Temporarily disable shared element transitions (#1621) 2024-09-13 12:10:26 +08:00
renovate[bot] 84c3fee5da Update dependency sh.calvin.reorderable:reorderable to v2.4.0-beta01 2024-09-13 00:33:59 +00:00
renovate[bot] b3af2c9481 Update AGP to v8.8.0-alpha02 2024-09-12 22:42:21 +00:00
renovate[bot] 33cab186fd Update dependency com.squareup.okio:okio-jvm to v3.9.1 2024-09-12 22:40:33 +00:00
FooIbar e3f52412ee Replace custom user agent with desktop site option 2024-09-12 20:22:54 +08:00
080810c707 Update dependency io.ktor:ktor-client-core to v3.0.0-rc-1 (#1424)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <99822064+revonateB0T@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-09-10 01:22:52 +00:00
renovate[bot] 964e827cbe Update AGP to v8.8.0-alpha01 2024-09-10 01:10:26 +00:00
FooIbar cae02acfc4 Fix cosplayer tag translation in download label 2024-09-10 06:11:25 +08:00
FooIbar 31ce4eac92 Update description for IP-based image limit 2024-09-09 22:13:49 +08:00
renovate[bot] bd5bd1e571 Implement Shared Element Transition Connector Framework (#1614)
undefined
2024-09-09 21:46:07 +08:00
renovate[bot] 2b4a6dc57a Update dependency gradle to v8.10.1 2024-09-09 10:25:31 +00:00
FooIbar 68932731b9 Fix gallery detail losing scroll position 2024-09-09 18:14:48 +08:00
renovate[bot] aab7ba0d53 Lock file maintenance 2024-09-09 01:22:24 +00:00
renovate[bot] 59bf4f2702 Update compose.destinations to v2.1.0-beta12 2024-09-08 22:47:54 +00:00
FooIbar e0e4b739f9 Add key and contentType for gallery detail 2024-09-08 22:04:12 +08:00
FooIbar 21d6b3bbb8 [no ci] Fix renovate config 2024-09-07 18:13:20 +08:00
FooIbar dae5d67515 [no ci] Fix renovate config 2024-09-07 17:59:56 +08:00
FooIbar a6a814bbbb [no ci] Update renovate config 2024-09-07 16:27:23 +08:00
FooIbar 0b0555af9d Use singleton empty WindowInsets 2024-09-07 16:13:54 +08:00
FooIbar 6e0d77a8ab Fix unfinished files being considered downloaded 2024-09-07 16:13:40 +08:00
FooIbar 5c06a69c8a Revert "Update agp to v8.7.0-beta01"
This reverts commit 63ec1aa217.
2024-09-06 14:25:38 +08:00
FooIbar 188a236a90 Fix reader padding and progress indicator theme 2024-09-06 10:00:21 +08:00
renovate[bot] 63ec1aa217 Update agp to v8.7.0-beta01 2024-09-05 21:38:21 +00:00
renovate[bot] 829316d8b9 Update dependency com.google.devtools.ksp to v2.0.20-1.0.25 2024-09-05 21:36:55 +00:00
renovate[bot] 337739fdad Update dependency androidx.profileinstaller:profileinstaller to v1.4.0-rc01 2024-09-05 14:44:41 +00:00
FooIbar f144ac701d Refine BitmapPainter 2024-09-05 22:36:19 +08:00
FooIbar 9c9b8b74cd Fix crash on random button click with empty list 2024-09-05 20:53:00 +08:00
renovate[bot] 154c7f3710 Update dependency com.google.accompanist:accompanist-drawablepainter to v0.36.0 2024-09-05 03:38:28 +00:00
renovate[bot] d3308bc987 Update dependency androidx.activity:activity-compose to v1.10.0-alpha02 2024-09-05 01:56:06 +00:00
renovate[bot] 04d9ee57d7 Update dependency androidx.core:core-splashscreen to v1.2.0-alpha02 2024-09-05 01:45:16 +00:00
FooIbar f3eecf18fb Switch to official Compose alpha BOM
This reverts commit c76440f167.
2024-09-05 09:45:04 +08:00
renovate[bot] 6591495d2d Update dependency androidx.work:work-runtime to v2.10.0-alpha03 2024-09-05 01:43:42 +00:00
renovate[bot] 2497835628 Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0-beta01 2024-09-04 22:35:38 +00:00
renovate[bot] 8fad9b2abe Update androidx.lifecycle to v2.9.0-alpha02 2024-09-04 22:34:46 +00:00
renovate[bot] fdd0ec9fd2 Update dependency com.android.tools:desugar_jdk_libs_nio to v2.1.2 2024-09-04 10:52:07 +00:00
FooIbar 1219ff99ff Reset page state on page loader restart 2024-09-03 19:12:01 +08:00
FooIbar c60b14998a Fix crash when drawing > 100 MB bitmaps 2024-09-03 19:03:54 +08:00
renovate[bot] 380554bd19 Lock file maintenance 2024-09-02 01:56:54 +00:00
FooIbar 2b969030da Fix recent download label can't be set to null
This reverts commit 822a461acd.
2024-09-01 20:56:01 +08:00
github-actions[bot] da917de1f4 Update Chrome version for default User-Agent 2024-09-01 13:34:46 +08:00
renovate[bot] 541f9e89f3 Update agp to v8.7.0-alpha09 2024-08-30 15:14:11 +00:00
renovate[bot] f4a987c83f Update agp to v8.7.0-alpha08 2024-08-28 19:45:33 +00:00
renovate[bot] 37474ed6ac Update kotlinx.serialization to v1.7.2 2024-08-28 19:43:12 +00:00
renovate[bot] cb69a168f3 Update dependency com.android.tools:desugar_jdk_libs_nio to v2.1.1 2024-08-28 13:34:26 +00:00
FooIbar 94366553de Fix torrent count parsing
This partially reverts commit 634269c6a4.
2024-08-27 07:37:30 +08:00
FooIbar 383332bfbb Fix account-based image limit parsing (#1565)
* Fix account-based image limit parsing

* Fix format
2024-08-27 07:37:05 +08:00
renovate[bot] 4bb1a17d39 Update dependency com.android.tools:desugar_jdk_libs_nio to v2.1.0 2024-08-26 17:43:40 +00:00
renovate[bot] 94d68fe38b Lock file maintenance 2024-08-26 00:56:27 +00:00
renovate[bot] cf6c850d2a Update aboutlibraries to v11.2.3 2024-08-23 11:06:34 +00:00
renovate[bot] c8a3a0fc20 Update dependency sh.calvin.reorderable:reorderable to v2.4.0-alpha02 2024-08-23 01:22:29 +00:00
renovate[bot] 433896b267 Update dependency com.google.devtools.ksp to v2.0.20-1.0.24 2024-08-22 23:11:02 +00:00
renovate[bot] 7e9c1f00ef Update Kotlin & KSP to v2.0.20 2024-08-22 10:56:10 +00:00
renovate[bot] 2b5b0d695a Update dependency me.saket.telephoto:zoomable to v0.13.0 2024-08-22 03:41:35 +00:00
renovate[bot] 2265b0943e Update dependency androidx.core:core-ktx to v1.15.0-alpha02 2024-08-22 01:09:20 +00:00
renovate[bot] 78f12065ab Update dependency dev.chrisbanes.compose:compose-bom to v2024.08.00-alpha02 2024-08-21 22:04:09 +00:00
renovate[bot] f28c45a13a Update dependency androidx.profileinstaller:profileinstaller to v1.4.0-beta01 2024-08-21 22:03:53 +00:00
renovate[bot] e030500917 Update benchmark to v1.3.0 2024-08-21 21:01:47 +00:00
renovate[bot] 9c042cd323 Update androidx.room to v2.7.0-alpha07 2024-08-21 21:01:30 +00:00
FooIbar 44eea7a273 Adapt status bar content color for reader theme 2024-08-21 15:20:25 +08:00
FooIbar 834cfc5e8c Support scrolling with mouse wheel in reader 2024-08-21 15:20:16 +08:00
renovate[bot] 876bb68873 Update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.6.1 2024-08-20 17:10:58 +00:00
FooIbar 40c1b7ef21 Prepare for next iteration 2024-08-19 21:02:30 +08:00
FooIbar 6191ad74d3 Prepare for release 1.12.0 2024-08-19 21:01:58 +08:00
FooIbar 5aae8f5649 Fix thumbnail resolution setting not working 2024-08-19 17:45:39 +08:00
FooIbar 6886465afb Refine reader
Fix navigation when switching from `WebtoonViewer` to `PagerViewer`.

Hide navigation overlay and reset slider to follow pager on click.
2024-08-19 17:45:26 +08:00
FooIbar 5a46fc4573 Don't recycle visible images 2024-08-19 13:49:36 +08:00
renovate[bot] a08b8e96e5 Lock file maintenance 2024-08-19 01:05:11 +00:00
FooIbar 5aeded7a24 Don't show load state indicator when no hits found 2024-08-18 17:40:48 +08:00
FooIbar 1883b82159 Fix pager unclickability when image is not loaded 2024-08-18 17:40:37 +08:00
FooIbar 302b57d4ac Fix normal preview in exhentai
Remove force e-hentai thumb option due to infeasible.
2024-08-17 00:52:44 +08:00
FooIbar c6b793923e Temporarily disable shared element transitions 2024-08-16 20:20:13 +08:00
FooIbar 058c280fd7 Avoid out-of-screen shared element transitions 2024-08-16 19:45:19 +08:00
renovate[bot] 0fa42d731b Update agp to v8.7.0-alpha07 2024-08-16 00:45:15 +00:00
FooIbar 9b54b57934 Refactor reader prefetch logic (#1523)
* Refactor reader prefetch logic

* Refine
2024-08-16 00:46:44 +08:00
FooIbar d3ab3ba61f [no ci] Update workflow 2024-08-15 18:29:41 +08:00
renovate[bot] 921f570151 Update dependency gradle to v8.10 2024-08-14 12:46:28 +00:00
FooIbar 03ab435401 Fix preload in reader (#1517)
* Fix preload in reader

* Reduce preload page count for ArchivePageLoader
2024-08-14 12:58:06 +08:00
renovate[bot] b73704ede1 Update dependency com.google.devtools.ksp to v2.0.20-RC2-1.0.24 2024-08-14 01:37:30 +00:00
renovate[bot] 97b2181ff7 Update agp to v8.7.0-alpha06 2024-08-13 19:11:16 +00:00
renovate[bot] ef5e3f7c51 Update Kotlin & KSP to v2.0.20-RC2 2024-08-13 13:41:34 +00:00
FooIbar 8a29d46b38 Revert^3 "Update Compose snapshot and migrate to BTF2 (#1474)"
This reverts commit 22b5a175f4.
2024-08-13 18:54:38 +08:00
FooIbar 75d8ff4b64 Fix ComicInfo.xml for galleries with temp tags 2024-08-13 17:46:01 +08:00
FooIbar 33258ea554 Fix read progress insert crash when exiting reader 2024-08-13 17:40:21 +08:00
renovate[bot] a723b4ecd3 Lock file maintenance 2024-08-12 00:15:22 +00:00
renovate[bot] 78a237fb0e Update agp to v8.7.0-alpha05 2024-08-09 02:18:54 +00:00
renovate[bot] 8fe60c0163 Update dependency dev.chrisbanes.compose:compose-bom to v2024.08.00-alpha01 2024-08-08 06:19:26 +00:00
renovate[bot] ffe47b2ff2 Update dependency androidx.lifecycle:lifecycle-runtime-compose to v2.9.0-alpha01 2024-08-08 03:14:46 +00:00
renovate[bot] e05fffb41c Update dependency androidx.biometric:biometric-ktx to v1.4.0-alpha02 2024-08-08 03:14:00 +00:00
renovate[bot] 1fb5de2527 Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha10 2024-08-08 00:40:20 +00:00
renovate[bot] 46790a1fbe Update dependency androidx.profileinstaller:profileinstaller to v1.4.0-alpha02 2024-08-08 00:39:56 +00:00
renovate[bot] af1316f06b Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0-alpha14 2024-08-07 22:11:39 +00:00
renovate[bot] 24564cac8d Update dependency androidx.paging:paging-compose to v3.3.2 2024-08-07 22:11:14 +00:00
renovate[bot] c4868f137b Update benchmark to v1.3.0-rc01 2024-08-07 20:38:52 +00:00
renovate[bot] 3ccfa0dd5b Update androidx.room to v2.7.0-alpha06 2024-08-07 20:38:26 +00:00
FooIbar fded0fd08d Fix GitHub authorization and clean up code 2024-08-07 18:37:51 +08:00
renovate[bot] b1afe9bcd1 Update agp to v8.7.0-alpha04 2024-08-06 22:54:54 +00:00
FooIbar 22b5a175f4 Reapply "Update Compose snapshot and migrate to BTF2 (#1474)"
This reverts commit 94b138f254.
2024-08-06 23:01:20 +08:00
FooIbar ee9e0df12e [no ci] Fix release workflow 2024-08-06 22:03:30 +08:00
FooIbar dd525baf88 Use encoded token to avoid detection & revocation (#1492) 2024-08-06 21:33:46 +08:00
FooIbar 9180603ead Fix a division by zero error in ScrollbarAdapter 2024-08-06 21:30:12 +08:00
renovate[bot] 66fe19369e Lock file maintenance 2024-08-05 00:38:20 +00:00
renovate[bot] b9db025f57 Update gradle/actions action to v4 2024-08-04 00:54:28 +00:00
FooIbar 44f6eca3aa Fix main thread IO (really) and float comparison 2024-08-03 14:55:05 +08:00
FooIbar 1ff1caf421 Fix list item container color
Also compile debug build with SDK 35 as sources for SDK 35 have been
available.
2024-08-03 08:42:33 +08:00
github-actions[bot] ec1355c0e7 Update Chrome version for default User-Agent 2024-08-01 11:21:29 +08:00
FooIbar d23a453f71 Don't let navigation overlay consume click event
So it won't take two actions to dismiss overlay & app bar.
2024-08-01 07:25:47 +08:00
FooIbar 94b138f254 Revert "Update Compose snapshot and migrate to BTF2 (#1474)"
This reverts commit abcef9a86e.
2024-08-01 03:06:53 +08:00
FooIbar c281daa4ea Update NDK to r27 2024-08-01 01:42:33 +08:00
FooIbar 4f9eba8c63 Update Kotlin and remove workaround 2024-08-01 01:08:41 +08:00
FooIbar a2547f1e8d Update page range filter limit 2024-07-31 18:54:51 +08:00
FooIbar abcef9a86e Update Compose snapshot and migrate to BTF2 (#1474)
* Update Compose snapshot and remove workaround

* Sync SearchBarInputField with upstream

* Migrate to BTF2 text fields

* Fix search page range error text container color

* Update snapshot to fix a SieveCache crash

https://r.android.com/3199791
2024-07-31 17:40:09 +08:00
FooIbar 7d6a9b10e4 Fix crash when opening archives simultaneously 2024-07-30 16:27:16 +08:00
renovate[bot] 9322b80790 Update dependency com.google.devtools.ksp to v2.0.0-1.0.24 2024-07-30 00:51:18 +00:00
FooIbar e12897bd13 Fix layout issue with comments that contain images 2024-07-29 21:59:40 +08:00
FooIbar 28279cc671 Fix page transitions when reading with volume keys 2024-07-29 18:19:43 +08:00
FooIbar 2531fa289b Update dependency sh.calvin.reorderable:reorderable to v2.4.0-alpha01 2024-07-29 10:47:13 +08:00
renovate[bot] 9673163e8f Lock file maintenance 2024-07-29 00:55:33 +00:00
renovate[bot] 3f7091f880 Update dependency sh.calvin.reorderable:reorderable to v2.3.0 2024-07-28 20:01:11 +00:00
FooIbar 5df75fd534 Don't save baseline profile in sources (#1462)
* Don't save baseline profile in sources

* Fixup
2024-07-28 17:25:36 +00:00
FooIbarandGG Bond 62061e54ee Add shared element transitions (#1049)
* Add shared element transitions

* Fixup CodeStyle

* Add a overload for `Modifier.sharedBounds`

* Add TransitionsVisibilityScope to hold multiple transition

* advance AnimatedVisibilityScope to TransitionsVisibilityScope

* composing use advance

* Correctly remember

* Convert to use `Set`

* share SharedContentState

* Refine

* Cleanup

* Cleanup

* Update snapshot

* Temporarily disable navigation transition

* Fix build

* Make `TransitionsVisibilityScope` a value class

* Naming

* Use `implicit` instead

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-07-28 14:11:47 +00:00
github-actions[bot] 436c07fb6b Update baseline profile 2024-07-28 21:34:06 +08:00
FooIbar a16f873f7d Fix crash when switching reading mode 2024-07-28 21:15:09 +08:00
FooIbar 98fdcf0588 Fix double free on closing failed-to-open archives 2024-07-28 20:48:56 +08:00
renovate[bot] 539ad1af30 Fix read encrypted archive 2024-07-28 12:05:04 +00:00
FooIbar 4370606977 [Reader] Show progress indicator & fix background 2024-07-28 19:45:18 +08:00
FooIbar 1ecdc07655 Graduate Compose Reader to stable 2024-07-28 17:29:50 +08:00
FooIbar 01a1113a07 [New Reader] Avoid initial scroll on reader start 2024-07-28 17:14:07 +08:00
renovate[bot] fd6c2977b0 Update plugin composeCompilerReportGenerator to v1.4.0 2024-07-28 08:50:51 +00:00
FooIbar 02e36e7021 [New Reader] Implement open archive intent 2024-07-28 14:00:23 +08:00
FooIbar 7f8e4aa003 [New Reader] Hide menu on scroll 2024-07-28 14:00:23 +08:00
FooIbar 8ce16bc918 [New Reader] Implement navigation overlay (#1445)
* [New Reader] Implement navigation overlay

* Fix typo

* Refine

* Reuse navigation regions
2024-07-26 23:45:41 +08:00
renovate[bot] fbe35a0fa0 Update agp to v8.7.0-alpha03 2024-07-25 23:43:05 +00:00
renovate[bot] 931f1ec514 Update dependency dev.chrisbanes.compose:compose-bom to v2024.07.00-alpha02 2024-07-25 17:31:31 +00:00
renovate[bot] 7c4a59e9a4 Update compose.destinations to v2.1.0-beta11 2024-07-25 13:33:39 +00:00
FooIbar c1c6f25763 [New Reader] Refine landscape zoom (#1442) 2024-07-25 18:53:16 +08:00
renovate[bot] e7f515c70f Update dependency androidx.paging:paging-compose to v3.3.1 2024-07-24 19:48:04 +00:00
renovate[bot] 64fecbfa52 Update dependency androidx.lifecycle:lifecycle-process to v2.8.4 2024-07-24 17:18:31 +00:00
renovate[bot] c6c181a9fa Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha09 2024-07-24 22:05:22 +08:00
FooIbar 53a1bd9959 [New Reader] Implement landscape zoom 2024-07-24 20:36:43 +08:00
FooIbar 7b1f94cf5a [New Reader] Implement custom image scale types 2024-07-24 09:02:45 +08:00
renovate[bot] 4b8ecbf6a7 Update agp to v8.7.0-alpha02 2024-07-22 21:19:13 +00:00
renovate[bot] 0e0b0519e7 Lock file maintenance 2024-07-22 02:12:22 +00:00
FooIbar 7fb3b7c785 Tweak baseline profile generation schedule
[no ci]
2024-07-21 15:00:14 +08:00
renovate[bot]andFooIbar e18ebb1feb Update compose.destinations to v2.1.0-beta10 (#1435)
* Update compose.destinations to v2.1.0-beta10

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-07-21 06:30:57 +00:00
FooIbar f76dcfc97b [New Reader] Misc improvements 2024-07-21 08:30:32 +08:00
renovate[bot] c0c630bd9f Update dependency me.saket.telephoto:zoomable to v0.12.1 2024-07-20 09:00:29 +00:00
FooIbar 04df7da5dc Remove obsolete workaround 2024-07-17 17:38:01 +08:00
FooIbar d156638a79 Fix comment screen refresh indicator padding 2024-07-17 17:33:44 +08:00
FooIbar c78fe0b72c [New Reader] Implement touch navigation 2024-07-17 17:32:08 +08:00
renovate[bot] 799c37ea71 Update dependency sh.calvin.reorderable:reorderable to v2.2.0 2024-07-17 05:42:34 +00:00
renovate[bot] 9559ca571b Update agp 2024-07-15 19:40:24 +00:00
renovate[bot] 2f5c1e11c6 Lock file maintenance 2024-07-15 01:07:35 +00:00
renovate[bot] 734c73fa4d Update dependency me.saket.telephoto:zoomable to v0.12.0 2024-07-13 19:51:02 +00:00
renovate[bot] c09173d62c Update dependency com.google.devtools.ksp to v2.0.0-1.0.23 2024-07-11 21:35:55 +00:00
renovate[bot] 533f50ed08 Update dependency gradle to v8.9 2024-07-11 18:03:51 +00:00
Dude so hot b4422fe910 Drop MAP_UNINITIALIZED
This is not available on modern MMU devices
2024-07-11 21:31:34 +08:00
Dude so hot 22e58a034f Fix memleak while do archive 2024-07-11 21:12:31 +08:00
FooIbar 784856d341 Revert "Update agp to v8.6.0-beta01"
This reverts commit b982705b2f.
2024-07-11 08:45:00 +08:00
renovate[bot] f82832ca36 Update dependency dev.chrisbanes.compose:compose-bom to v2024.07.00-alpha01 2024-07-11 00:15:30 +00:00
renovate[bot] 6a70aa792e Update benchmark to v1.3.0-beta02 2024-07-10 19:10:50 +00:00
renovate[bot] a0016dbf85 Update androidx.room to v2.7.0-alpha05 2024-07-10 19:10:30 +00:00
renovate[bot] b982705b2f Update agp to v8.6.0-beta01 2024-07-10 17:01:40 +00:00
FooIbar 4c36398bed Prepare for next iteration 2024-07-10 22:13:25 +08:00
FooIbar 7e1b3abcf6 Prepare for release 1.11.7 2024-07-10 22:12:56 +08:00
FooIbar 97bb65aa35 Fix search bar title flickering 2024-07-10 22:11:46 +08:00
FooIbar 98c1a377ca Fix main thread disk IO 2024-07-10 20:25:52 +08:00
FooIbar 2d2ce3281e Fix Path -> Uri conversion for paths contain '%'
This reverts commit ab2e4a8e2d.
2024-07-10 19:44:13 +08:00
renovate[bot] a28d3ba840 Update dependency org.jsoup:jsoup to v1.18.1 2024-07-10 08:41:55 +00:00
FooIbar ab2e4a8e2d Fix Path -> Uri conversion
No need to do it for '?' as that's not allowed in filename.
2024-07-10 12:59:29 +08:00
FooIbar 67ddba87b5 Fix workflow config
[no ci]
2024-07-09 22:29:28 +08:00
FooIbar 8164847fcb Prepare for next iteration 2024-07-09 22:03:40 +08:00
FooIbar 85b538bbd3 Prepare for release 1.11.6 2024-07-09 22:03:04 +08:00
FooIbar d00d700a4b Improve Path/Uri conversion 2024-07-09 21:51:41 +08:00
github-actions[bot] ae66318843 Update baseline profile 2024-07-09 19:15:53 +08:00
FooIbar 1b9aa6a762 Retrieve favorite notes when modifying favorites 2024-07-09 18:54:57 +08:00
renovate[bot]andFooIbar 306ce83de4 Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha08 (#1397)
* Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha08

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-07-09 07:01:49 +00:00
FooIbar 89f9735ab9 Update Rust edition to 2021 2024-07-09 11:07:10 +08:00
FooIbar 843e1cc6a0 Fix MediaStore DATE_ADDED/DATE_MODIFIED
They are in seconds not milliseconds as per the documentation.
2024-07-09 10:55:34 +08:00
FooIbar 1a53d0d207 Fix download notification not showing 2024-07-09 10:18:22 +08:00
renovate[bot] 45c02d4fd6 Update Rust crate quick-xml to 0.36 2024-07-08 20:06:06 +00:00
renovate[bot] 862dee0845 Lock file maintenance 2024-07-08 01:53:46 +00:00
FooIbar 809bbfeba7 Refine clean redundancy dialog 2024-07-08 00:12:23 +08:00
FooIbar 959c740175 AndroidFileSystem POC (#1383)
* AndroidFileSystem POC

* Cache image file paths

* Refine
2024-07-07 07:13:49 +00:00
FooIbar a718510c89 Implicitly add language filter tag
This partially reverts commit 673c1837e9.
2024-07-06 15:02:55 +08:00
FooIbar f7c2fd8af3 Renew GitHub token 2024-07-05 21:12:46 +08:00
FooIbar c76440f167 Address deprecation 2024-07-05 20:57:47 +08:00
FooIbar c3bd959ee5 Update Compose snapshot (#1381)
* Update Compose snapshot

https://issuetracker.google.com/344633766

* Fix search bar text field padding
2024-07-04 13:34:27 +00:00
FooIbar 0a25643b87 Fix native crash on archive open failures 2024-07-04 20:24:37 +08:00
FooIbar c805ca8aff Revert "Reuse the root download location UniFile object"
Reason for revert: Caused OOM.
2024-07-03 22:34:18 +08:00
FooIbar 699a1ab801 Refactor DownloadService to use flows 2024-07-03 19:59:12 +08:00
FooIbar ee091aee0f Rescan download directory when restoring downloads (#1372) 2024-07-02 05:50:20 +00:00
FooIbar 673c1837e9 Fix language filter being applied to quick search 2024-07-02 13:44:01 +08:00
FooIbar 3998913c17 Fix existing download dirname not being used (#1371)
Tweak clean redundancy logic and add a confirm dialog.
2024-07-02 13:41:31 +08:00
renovate[bot] 1e83d7128e Update androidx.lifecycle to v2.8.3 2024-07-01 17:29:06 +00:00
FooIbar 355289a576 Avoid relying on implementation details (#1357)
* Avoid relying on implementation details

* Refine

* Fixup

* Extract common logic of RawFile & TreeDocumentFile

* Reuse the root download location UniFile object
2024-07-01 20:00:13 +08:00
FooIbar ba3a41f0ee Limit search bar text to single line 2024-07-01 17:17:38 +08:00
github-actions[bot] fc6d0bd6ef Update Chrome version for default User-Agent 2024-07-01 14:26:38 +08:00
FooIbar 15ef0ae362 Exclude scrollbar area from the system gesture 2024-07-01 14:26:15 +08:00
renovate[bot] a598f8562d Lock file maintenance 2024-07-01 01:28:33 +00:00
github-actions[bot] 2860fed5ab Update baseline profile 2024-06-30 11:07:14 +08:00
FooIbar f247544439 Migrate to CMP's implementation of scrollbar 2024-06-30 11:06:12 +08:00
renovate[bot] fdc3d94d5c Update Rust crate quick-xml to 0.35 2024-06-29 20:08:16 +00:00
renovate[bot] afc2ff7478 Update dependency io.github.petertrr:kotlin-multiplatform-diff to v0.7.0 2024-06-29 15:38:04 +00:00
renovate[bot] 83072d4eee Update aboutlibraries to v11.2.2 2024-06-29 12:13:33 +00:00
renovate[bot] 7e7be8d40a Update agp to v8.6.0-alpha08 2024-06-27 21:42:03 +00:00
FooIbar 90d7555333 [no ci] Fix benchmark build type configuration 2024-06-27 14:48:55 +08:00
github-actions[bot] ba268cfe6d Update baseline profile 2024-06-27 12:37:32 +08:00
renovate[bot]andFooIbar 0a7a9beb84 Update dependency androidx.test.uiautomator:uiautomator to v2.4.0-alpha01 (#1354)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-06-27 04:09:18 +00:00
renovate[bot] b18b89db29 Update dependency androidx.test.ext:junit to v1.2.1 2024-06-27 03:54:12 +00:00
FooIbar cb2d99bdc1 Add automated baseline profile generation (#1349)
* Add automated baseline profile generation

* Create benchmark build type

And remove the `enabledRules` argument as it will be injected by
baseline profile gradle plugin.
2024-06-27 11:46:02 +08:00
renovate[bot]andFooIbar 4dd6d68163 Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha07 (#1351)
* Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha07

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-06-27 03:44:45 +00:00
renovate[bot] 28ecc9d479 Update dependency dev.chrisbanes.compose:compose-bom to v2024.06.00-alpha01 2024-06-26 23:16:46 +00:00
renovate[bot] c917117db3 Update kotlinx.serialization to v1.7.1 2024-06-25 17:19:22 +00:00
FooIbar 5c0d65dd60 Fix crop borders not working 2024-06-25 15:17:21 +08:00
FooIbar dfc59aa643 Target API 35 as it has reached platform stability
Still use 34 SDK in debug build as sources for 35 are not available yet.
2024-06-25 15:17:09 +08:00
renovate[bot] 6ab77e541f Update dependency com.android.application to v8.6.0-alpha07 2024-06-25 10:01:48 +08:00
renovate[bot] 6224f8f4ab Update Rust crate quick-xml to 0.34 2024-06-24 21:20:26 +00:00
renovate[bot] 3d269c4220 Lock file maintenance 2024-06-24 00:31:53 +00:00
FooIbar 176a802e96 Don't use Unicode ellipsis character for filename
It will be replaced by three dots.
2024-06-23 09:04:18 +08:00
renovate[bot] 417a06e140 Update dependency io.github.fornewid:material-motion-compose-core to v2.0.1 2024-06-22 21:19:47 +00:00
FooIbar 5c4f034532 Update Compose snapshot and vendor Reorderable
As `animateItemPlacement` has been removed.
2024-06-22 12:57:13 +08:00
FooIbar 1d50855f52 Workaround for displaying extremely long images (#1327)
* Workaround for displaying extremely long images

* Make hardware bitmap threshold configurable
2024-06-22 12:56:46 +08:00
renovate[bot] 0280450797 Update Rust crate quick-xml to 0.33 2024-06-21 16:58:19 +00:00
FooIbar d0c907c7ff Remove unused jitpack repo 2024-06-21 12:17:49 +08:00
FooIbar 1302e17c01 Migrate to ViewPager2 (#1335)
* Migrate to ViewPager2

* Remove code for unimplemented automatic background
2024-06-21 12:07:27 +08:00
FooIbar 33f83b7325 Switch PhotoView to active fork 2024-06-20 15:05:02 +08:00
FooIbar d2c49f5022 Upload all R8 reports 2024-06-19 12:26:32 +08:00
FooIbar 084883a308 Decouple CronetEngine 2024-06-19 12:14:20 +08:00
FooIbar 67a73da720 Revert "Update dependency com.android.application to v8.6.0-alpha06"
This reverts commit f2447fd122.
2024-06-19 01:21:01 +08:00
renovate[bot] f2447fd122 Update dependency com.android.application to v8.6.0-alpha06 2024-06-18 16:33:56 +00:00
FooIbar 8ddcb003e0 Move lint check to the check job (#1330)
* K2 lint

* Move lint check to the check job

* Fix CI
2024-06-18 16:25:38 +00:00
FooIbar 0bff011f72 Address deprecation 2024-06-18 18:15:29 +08:00
FooIbar f41d1d7306 Skip patching if the patch is already applied 2024-06-18 00:12:33 +08:00
renovate[bot] a30aa23b67 Update xmlutil to v0.90.1 2024-06-17 23:39:02 +08:00
FooIbar 583d30eb5f Update nettle to v3.10 2024-06-17 18:01:31 +08:00
FooIbar c53b0986a9 Use link options to exclude libarchive symbols 2024-06-17 18:00:56 +08:00
renovate[bot] 85703c8c47 Lock file maintenance 2024-06-17 07:57:38 +00:00
renovate[bot] 025ba0bf5b Lock file maintenance 2024-06-17 01:19:24 +00:00
renovate[bot] ac2def22d2 Update Rust crate android_logger to 0.14 2024-06-16 09:59:31 +00:00
FooIbar 895cfc7bc6 Minor refactor 2024-06-16 17:48:50 +08:00
FooIbar 49eb9d5077 Fix gid qualifier not working with language filter 2024-06-16 17:48:50 +08:00
FooIbar 5a3c165ff1 Update ktlint to 1.3.0 2024-06-16 17:48:50 +08:00
FooIbar 3946428df6 Migrate to the std implementation of OnceCell 2024-06-16 17:46:40 +08:00
FooIbar 471d9784d6 Use different schedule to avoid rate limits 2024-06-15 13:41:21 +08:00
FooIbar 0ba0afc0d0 Downgrade Compose to the last known good build 2024-06-14 20:44:18 +08:00
FooIbar 5049b791fb Fix FAB recomposing on item selected 2024-06-14 20:43:46 +08:00
renovate[bot] 9a3715c516 Update androidx.lifecycle to v2.8.2 2024-06-12 23:23:08 +00:00
renovate[bot] 4ee276f636 Update androidx.room to v2.7.0-alpha04 2024-06-12 20:27:55 +00:00
renovate[bot] d528b2d5d0 Update dependency io.github.petertrr:kotlin-multiplatform-diff to v0.6.0 2024-06-12 01:40:34 +00:00
FooIbar b3ee69d193 Clean up EhCookieStore 2024-06-11 14:21:51 +08:00
FooIbar f882b78ff6 Update NDK to r27 RC 1 2024-06-11 14:20:18 +08:00
renovate[bot] 7e58101a3f Update Rust crate quick-xml to 0.32 2024-06-10 15:25:59 +00:00
FooIbar 5450eb9b2b Revert "Update Compose snapshot"
This reverts commit 13cf42437f.
2024-06-10 13:04:40 +08:00
renovate[bot] 69695e3c99 Lock file maintenance 2024-06-10 01:02:53 +00:00
FooIbar 5b15059c04 Switch back to C implementation of sha1
Now that libnettle is built with hardware acceleration instructions
2024-06-09 23:11:57 +08:00
FooIbar f50d69cd60 Build libnettle with assembly code (#1292)
* Build libnettle with assembler code

* Add .gitattributes for shell script

* Patch nettle for CPU feature detection on Android

* Don't build libnettle at configuration time

* Fix build

* Refine
2024-06-09 13:49:36 +08:00
renovate[bot] df6f783a69 Update dependency com.android.application to v8.6.0-alpha05 2024-06-08 10:58:55 +00:00
Dude so hot f0291d94f9 Tell function return types to workaround compiler bug 2024-06-07 17:11:04 +08:00
Dude so hot 593f24b86f Refactor awaitInputTextWithCheckBox 2024-06-07 17:11:04 +08:00
Dude so hot 5bce898f99 Move goto dialog invalidator to use ensure 2024-06-07 17:11:04 +08:00
Dude so hot 2b444c262d Move archive dialog invalidator to use ensure 2024-06-07 17:11:04 +08:00
Dude so hot e40a7c75d9 Move page range invalidator to use ensure 2024-06-07 17:11:04 +08:00
Dude so hot 4a7c057260 Expr-ize 2024-06-07 17:11:04 +08:00
Dude so hot 229a00cd53 Let Dialog.awaitInputText use Raise to improve semantics 2024-06-07 17:11:04 +08:00
Dude so hot d2d0d880f1 Let Dialog.awaitResult use Raise to improve semantics 2024-06-07 17:11:04 +08:00
Dude so hot c5e17c1d5b Retry when FabLayoutState sync interrupted
Double click primary fab on select mode should "collapse to recompose secondary fabs" then immediately expand
2024-06-07 15:58:37 +08:00
Dude so hot 33ff2ebe06 Import arrow resilience 2024-06-07 15:58:37 +08:00
Dude so hot 5c13e188de Secondary fab recompose force fablayout collapse
Fix bug where fastly click primary fab twice on select mode, select state is cleared but secondary fabs not recomposed
2024-06-07 15:58:37 +08:00
FooIbar 60b03dcd0e Fix integrity check for non-H@H resampled images
Their URLs contain hashes for both original and resampled images.
2024-06-07 15:13:40 +08:00
renovate[bot] 4604a25f58 Update dependency io.github.fornewid:material-motion-compose-core to v2 2024-06-07 01:26:56 +00:00
FooIbar 99029b8b04 Prepare for next iteration 2024-06-06 22:07:52 +08:00
FooIbar 70f46442c6 Prepare for release 1.11.6-RC2 2024-06-06 22:07:23 +08:00
FooIbar 13cf42437f Update Compose snapshot
https://issuetracker.google.com/343750859
2024-06-06 21:54:22 +08:00
renovate[bot] 1e29f6dcb4 Update kotlinx.serialization to v1.7.0 2024-06-06 13:52:43 +00:00
renovate[bot] f25981792f Update dependency com.google.devtools.ksp to v2.0.0-1.0.22 2024-06-06 00:09:30 +00:00
FooIbar 934c8be3e4 Anti-tamper support 2024-06-04 15:13:09 +08:00
renovate[bot] b9994eacbc Lock file maintenance 2024-06-03 01:53:41 +00:00
FooIbar 704ab0ee7e Prepare for next iteration 2024-06-02 23:38:33 +08:00
FooIbar 6d1d737f9f Prepare for release 1.11.6-RC1 2024-06-02 23:38:02 +08:00
FooIbar bc75156232 Simplify ReadableTime.getFilenamableTime 2024-06-02 22:51:58 +08:00
FooIbar 2101ea7a36 Update mime types based on Android's mime.types 2024-06-02 22:22:42 +08:00
FooIbar 26921c8ae1 Fix data export/import on Android V
The mime type mapping for sqlite files was added in
https://r.android.com/2988915.
2024-06-02 22:22:42 +08:00
FooIbar be1eecf3b5 Use official coroutines API instead of manual cast 2024-06-02 19:49:21 +08:00
FooIbar 2d4f154c9b Prevent async failure from cancelling parent scope 2024-06-02 19:49:21 +08:00
renovate[bot] d82cbe51ba Update dependency io.github.fornewid:material-motion-compose-core to v1.2.1 2024-06-02 03:13:01 +00:00
FooIbar d13ffa93ba Workaround for navigation bars padding on API < 28 2024-06-01 22:34:30 +08:00
FooIbar 2cce55953f Fix quick search and download label reordering
This is a regression introduced by 6277d7d.
2024-06-01 22:15:44 +08:00
FooIbar 07d100fcc0 Show navigation drawer only on top-level screens (#1266)
* Show navigation drawer only on top-level screens

* Remove redundant `rememberUpdatedState`
2024-06-01 18:59:16 +08:00
FooIbar cc04371181 Fix navigation drawer overlapping side sheet 2024-06-01 13:08:49 +08:00
github-actions[bot] ee50c88765 Update Chrome version for default User-Agent 2024-06-01 09:02:43 +08:00
renovate[bot] efc5b55ea7 Update dependency gradle to v8.8 2024-05-31 23:42:12 +00:00
FooIbar 94af66156a Replace invalid/consecutive whitespaces in query 2024-06-01 01:52:03 +08:00
FooIbar 4861359f9e Make secondary FAB offset density-aware 2024-06-01 01:51:40 +08:00
renovate[bot] 5af167dab4 Update compose.destinations to v2.1.0-beta09 2024-05-31 14:19:32 +00:00
renovate[bot] db1f0bc6d7 Update dependency com.android.application to v8.6.0-alpha04 2024-05-30 23:33:55 +00:00
renovate[bot] b94a843ec5 Update aboutlibraries to v11.2.1 2024-05-30 08:27:09 +00:00
FooIbar b27d214f24 Use Non-H as default category for guest mode
Don't modify the URL builder.
2024-05-30 10:57:26 +08:00
FooIbar a81eb9d17b Fix default value 2024-05-30 10:57:26 +08:00
FooIbar ec9b85f30f Refactor to not get sign-in state from cookies 2024-05-30 10:57:26 +08:00
FooIbar 8ac2f33949 Update liblzma to v5.6.2 2024-05-30 09:32:18 +08:00
FooIbar d84198ab28 Move Compose out of snapshot 2024-05-30 09:22:20 +08:00
renovate[bot] 34d339d9f1 Update compose.destinations to v2.1.0-beta08 2024-05-30 00:26:53 +00:00
renovate[bot] bcfefc7c76 Update dependency dev.chrisbanes.compose:compose-bom to v2024.05.00-alpha03 2024-05-29 21:16:26 +00:00
renovate[bot] 62539dc48e Update dependency androidx.appcompat:appcompat to v1.7.0 2024-05-29 21:15:22 +00:00
renovate[bot] 453ab11395 Update androidx.lifecycle to v2.8.1 2024-05-29 18:36:58 +00:00
renovate[bot] b2246b980a Update androidx.room to v2.7.0-alpha03 2024-05-29 18:36:07 +00:00
FooIbar 822a461acd Use All as default recent download label 2024-05-28 22:46:18 +08:00
renovate[bot] 25e5c0ab8e Lock file maintenance 2024-05-27 01:53:10 +00:00
FooIbar 2a55db95f4 Workaround for ReaderPageSheet clipped on API < 28 2024-05-26 17:17:50 +08:00
FooIbar a144866182 Use commit time instead for reproducible builds 2024-05-25 16:56:17 +08:00
FooIbar be7a04a4cb Move kotlin options to kotlin block 2024-05-24 22:18:18 +08:00
renovate[bot] fd1b861dab Update dependency com.android.application to v8.6.0-alpha03 2024-05-24 01:09:17 +00:00
FooIbar 957ebd35aa Update Compose snapshot
https://issuetracker.google.com/333584635
2024-05-23 16:31:14 +08:00
FooIbar 29d8b11771 Fix quota exceeded exceptions being swallowed 2024-05-22 18:37:28 +08:00
renovate[bot] c87059e9d7 Update Kotlin & KSP 2024-05-22 09:51:29 +08:00
renovate[bot] 4babe2eec4 Update aboutlibraries to v11.2.0 2024-05-21 23:45:18 +00:00
FooIbar 48fdaaca0c Fix race condition of ComicInfo.xml modification 2024-05-21 19:54:41 +08:00
FooIbar f0ee88b4d6 [no ci] Fix renovate config 2024-05-21 17:32:37 +08:00
FooIbar 9210780b6b Fix renovate false positive 2024-05-21 17:26:30 +08:00
FooIbar b479e28543 Initial support for importing downloaded archives 2024-05-21 14:20:57 +08:00
FooIbar f93b98fc5e Fix user input not being used when rating gallery 2024-05-20 11:51:29 +08:00
renovate[bot] 4721d1011b Lock file maintenance 2024-05-20 00:43:28 +00:00
FooIbar 4da4443e67 [no ci] Remove unused res 2024-05-20 00:25:13 +08:00
FooIbar e5343f4360 Don't package 32-bit x86 libs into universal apk 2024-05-20 00:24:05 +08:00
FooIbar 86323220dc Prepare for next iteration 2024-05-19 23:06:35 +08:00
FooIbar ada8f3af75 Prepare for release 1.11.5 2024-05-19 23:06:00 +08:00
FooIbar fb940d3982 Group downloads by artist if no labels are defined 2024-05-19 23:02:29 +08:00
FooIbar 8e8729c25f Introduce AppConfig.isSnapshot 2024-05-19 23:01:25 +08:00
FooIbar ffdd063ca1 Revert "Update Compose snapshot"
This reverts commit e6bdaf1172.

Reason for revert: https://issuetracker.google.com/341320533
2024-05-19 20:44:51 +08:00
FooIbar dfd5c6c70e Remove unnecessary synchronization
We use thread-safe methods now.
2024-05-19 20:32:08 +08:00
FooIbar 3068aab681 Use CI update channel by default for snapshots (#1223)
* Use CI update channel by default for snapshots

And use build time as initial update time.

* Fix build time
2024-05-19 20:25:59 +08:00
renovate[bot] e402587f8f Update plugin composeCompilerReportGenerator to v1.3.1 2024-05-19 10:52:18 +00:00
FooIbar 00b1be879d Fix app language out of sync with system settings (#1221)
* Fix app language out of sync with system settings

* Manually update current language

Recomposition may not happen when current language is the same as system
 default.
2024-05-19 10:43:24 +00:00
ɴᴇᴋᴏ e63bd49a4c Update TW Translation (#1081)
* Add new TW Translation

* Fix translation

* change translate

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* change to '圖庫'

* 更新 strings.xml

* space

* fix

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml
2024-05-19 15:41:10 +08:00
renovate[bot] 8131170eb1 Update compose.destinations to v2.1.0-beta07 2024-05-18 20:13:22 +00:00
FooIbar dc1abd3806 Migrate to Compose Material3 Adaptive (#1219)
* Migrate to Compose Material3 Adaptive

* Fix R8
2024-05-18 20:56:03 +08:00
FooIbar 468fbd50da Fix tap zone overlay not following inversion 2024-05-18 18:53:26 +08:00
FooIbar f2011f9b6f Fix reader tap zone inversion not working 2024-05-18 18:53:26 +08:00
FooIbar 1e53a9b389 Make sure favorites don't have the same timestamp 2024-05-18 10:46:46 +08:00
renovate[bot] dc2504b67f Update dependency com.android.application to v8.6.0-alpha02 2024-05-17 23:06:40 +00:00
FooIbar 2ae3e3b64c Reland "Use autogenerated localeConfig"
Reland as https://issuetracker.google.com/294109810 has been fixed.
2024-05-17 23:50:48 +08:00
FooIbar e6bdaf1172 Update Compose snapshot
https://issuetracker.google.com/339188523
2024-05-17 14:34:53 +08:00
FooIbar 36a66d9199 Revert "Workaround for renovate false positive"
This reverts commit fb6fbb8df9.
2024-05-17 14:23:21 +08:00
FooIbar fb6fbb8df9 Workaround for renovate false positive 2024-05-17 12:17:12 +08:00
renovate[bot] ef8449dc02 Update compose.destinations to v2.1.0-beta06 2024-05-16 16:06:28 +00:00
FooIbar b59f8e9ade Use Non-H category as homepage in guest mode 2024-05-16 01:46:14 +08:00
FooIbar a49506f4a0 Update Compose snapshot to fix item clipping
https://issuetracker.google.com/340201510
2024-05-15 21:26:07 +08:00
FooIbar 4ce3d25eed Remove unused code 2024-05-15 17:28:42 +08:00
FooIbar 81b166bee1 Unpin dependencies 2024-05-15 10:58:53 +08:00
renovate[bot] 37a587859a Update dependency dev.chrisbanes.compose:compose-bom to v2024.05.00-alpha02 2024-05-15 10:47:04 +08:00
renovate[bot] b7544630bb Update dependency com.android.application to v8.6.0-alpha01 2024-05-15 02:43:51 +00:00
renovate[bot] 05c7a0fa39 Update dependency androidx.paging:paging-compose to v3.3.0 2024-05-15 02:43:16 +00:00
renovate[bot] eee7655f80 Update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.6.0 2024-05-15 02:42:54 +00:00
renovate[bot] 9390813c48 Update dependency androidx.lifecycle:lifecycle-runtime-compose to v2.8.0 2024-05-15 02:42:37 +00:00
renovate[bot] d032fbdd67 Update dependency androidx.annotation:annotation to v1.8.0 2024-05-14 23:15:41 +00:00
renovate[bot] adcd73a590 Update dependency androidx.appcompat:appcompat to v1.7.0-rc01 2024-05-14 23:15:00 +00:00
renovate[bot] 87b405bf1f Update androidx.room to v2.7.0-alpha02 2024-05-14 17:41:39 +00:00
renovate[bot] d8306e2c80 Update androidx.lifecycle to v2.8.0 2024-05-14 17:41:20 +00:00
FooIbar c03fe9b51e Address java.util.regex.Pattern usage 2024-05-15 01:31:54 +08:00
FooIbar 9099014d28 Remove reference of "Sign in via cookies" 2024-05-15 01:31:54 +08:00
FooIbar d7b3872486 Support autofill in SignInScreen 2024-05-15 01:31:54 +08:00
FooIbar 4ae2af0bef Adjust SignInScreen layout 2024-05-15 01:31:54 +08:00
FooIbar c9bcd46b77 Revert "Drop basic login as captcha is mandatory now"
This reverts commit e07aab4434.
2024-05-15 01:31:54 +08:00
FooIbar e531653634 Workaround for archive list crash when scrolling
It has fixed size and we don't actually expect its items to be reused.
2024-05-14 13:59:24 +08:00
renovate[bot]andFooIbar a29e4c72b1 Update Kotlin & KSP (#1171)
* Update Kotlin & KSP

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-05-14 12:14:54 +08:00
FooIbar 9e1f7ca051 Fix crash in favorites caused by duplicate items 2024-05-13 22:42:39 +08:00
renovate[bot] fbbc347411 Update dependency sh.calvin.reorderable:reorderable to v2.1.1 2024-05-13 04:11:24 +00:00
renovate[bot] ea364536a4 Lock file maintenance 2024-05-13 01:32:13 +00:00
github-actions[bot] 575fc9e94c Update Chrome version for default User-Agent 2024-05-12 14:53:50 +08:00
FooIbar 703c63125a [no ci] Don't push to main branch directly 2024-05-12 14:42:53 +08:00
FooIbar b205b5e120 Keep default User-Agent updated 2024-05-12 11:44:28 +08:00
FooIbar e27f36d2c8 Don't swallow exceptions when importing database 2024-05-12 11:39:29 +08:00
FooIbar d582eddc03 Update Corrosion to v0.5 2024-05-12 02:08:29 +08:00
FooIbar 3b83d8744c Revert "Update dependency com.android.application to v8.5.0-beta01"
This reverts commit 7c39b95025.
2024-05-11 13:18:20 +08:00
renovate[bot] 68a5217b1c Lock file maintenance 2024-05-11 04:39:15 +00:00
FooIbar c01082b822 Revert pointless bumps and check in Cargo.lock 2024-05-11 12:26:25 +08:00
FooIbar bb95c86320 Update Compose snapshot 2024-05-11 11:56:41 +08:00
FooIbar d398926aeb Simplify rating widget implementation 2024-05-11 03:23:40 +08:00
FooIbar 7b23efb0ce Fix rememberMutableStateInDataStore persistence 2024-05-11 03:22:22 +08:00
FooIbar 7818ff197c Fix R8 2024-05-11 03:21:37 +08:00
FooIbar 95bfc4f8c5 Introduce AnchoredHorizontalDraggable to prevent unintentional drags 2024-05-11 03:21:37 +08:00
FooIbar c750016034 Revert "Revert "Drop experimental touch slop factor setting" (#1162)"
This reverts commit a4619547f1.
2024-05-11 03:21:37 +08:00
FooIbar 6298e501cd Save minimum rating search option in preference (#1163) 2024-05-11 03:18:01 +08:00
renovate[bot] 7c39b95025 Update dependency com.android.application to v8.5.0-beta01 2024-05-10 18:46:00 +00:00
renovate[bot] 02c1e630d1 Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-android to v1.8.1 2024-05-10 11:36:12 +00:00
GG Bond 8f3b0cc536 Refine naming 2024-05-10 19:27:45 +08:00
GG Bond d0c5ef8e8a Refine naming 2024-05-10 19:27:45 +08:00
GG Bond d628024637 Refine 2024-05-10 19:27:45 +08:00
GG Bond fe1249630b Convert FavDialogTheta to use rememberInDataStore 2024-05-10 19:27:45 +08:00
GG Bond cdbe3cf728 Drop unused avatar pref 2024-05-10 19:27:45 +08:00
GG Bond f5e36bc0cf Initialize dataStateFlow on app start 2024-05-10 19:27:45 +08:00
GG Bond 4f9bfe13cb Move SearchCategory to use rememberInDataStore 2024-05-10 19:27:45 +08:00
GG Bond 959da21b9d Introduce rememberInDataStore 2024-05-10 19:27:45 +08:00
renovate[bot]andGG Bond fae2b1f416 Cleanup rememberInVM family (#1166)
* Update DataStore to 1.1.1 for future `rememberInDataStore` impl

* Cleanup `rememberInVM` family

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-05-10 06:15:18 +00:00
GG Bond a054633d0a Update DataStore to 1.1.1 for future rememberInDataStore impl 2024-05-10 13:49:36 +08:00
FooIbar a4619547f1 Revert "Drop experimental touch slop factor setting" (#1162)
* Revert "Drop experimental touch slop factor setting"

This reverts commit d5d8a828ef.

Reason for revert: After some more testing I think sadly we still need it.

* Read touch slop factor as state
2024-05-10 13:08:32 +08:00
FooIbar 5d53febb15 Show gallery pages in thumbnail mode (#1164) 2024-05-10 04:41:42 +00:00
FooIbar 3da1587924 Use HapticFeedback in ChapterNavigator as well 2024-05-10 12:22:09 +08:00
FooIbar 971d0307fe Inline DragHandle as it's redundant now 2024-05-10 12:22:09 +08:00
FooIbar 705d3afb78 Refactor haptic feedback on reordering 2024-05-10 12:22:09 +08:00
renovate[bot] bc34b4b9c1 Update dependency sh.calvin.reorderable:reorderable to v2.1.0 2024-05-09 09:59:57 +00:00
FooIbar a2ac01fcdc Revert "Update dependency sh.calvin.reorderable:reorderable to v2.0.4"
This reverts commit 4cea8d0090.

Reason for revert: The item being dragged becomes invisible.
2024-05-09 14:44:10 +08:00
FooIbar 645ebddd4f Fix crash when saving unloaded images 2024-05-09 14:23:11 +08:00
FooIbar d5d8a828ef Drop experimental touch slop factor setting 2024-05-09 12:18:59 +08:00
FooIbar 96d4193d2d Fix system bars insets in fullscreen on API < 30 2024-05-09 12:14:59 +08:00
FooIbar 18e4afdff9 Update Compose snapshot 2024-05-09 12:13:28 +08:00
FooIbar 19a702ffc4 Migrate to main artifact of AndroidX WorkManager
`work-runtime-ktx` is empty since 2.9.0
2024-05-08 17:55:39 +08:00
renovate[bot] cfd44c256f Update compose.destinations to v2.1.0-beta05 2024-05-07 23:13:30 +00:00
renovate[bot] 4cea8d0090 Update dependency sh.calvin.reorderable:reorderable to v2.0.4 2024-05-07 19:49:57 +00:00
FooIbar 30e166b29c Fix DownloadService state not cleared 2024-05-07 16:34:23 +08:00
FooIbar c50f3d8c5b Fix tap control area shifting after zooming out 2024-05-07 15:37:38 +08:00
FooIbar d9249eeedb Fix tap control area shifting in multi-window mode 2024-05-07 15:37:38 +08:00
FooIbar 51699cafe6 Constrain minimum width of reader bottom bar menus 2024-05-07 15:37:17 +08:00
FooIbar ce97976bdd Refactor bottom bar icon dropdown menus in reader
Avoid hard-coded width and offset.
2024-05-07 15:37:17 +08:00
renovate[bot]andFooIbar 7b8a12e3eb Update dependency sh.calvin.reorderable:reorderable to v2.0.3 (#1143)
* Update dependency sh.calvin.reorderable:reorderable to v2.0.3

* Address deprecation

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-05-07 03:49:33 +00:00
FooIbar 7276c37c54 Don't constrain menu's width 2024-05-07 01:17:55 +08:00
FooIbar 4ec7de611c Introduce DropdownFilterChip for SearchFilter 2024-05-07 01:17:55 +08:00
FooIbar 0295c40b02 Implement fullscreen mode in new reader 2024-05-06 19:53:32 +08:00
FooIbar 035fa44523 Correctly handle display cutout (#1139) 2024-05-06 14:34:22 +08:00
renovate[bot] 60c6618db1 Update compose.destinations to v2.1.0-beta04 2024-05-05 23:53:49 +00:00
FooIbar f35643b2b6 Correctly handle window insets in reader
Now it's actual edge-to-edge.
2024-05-06 07:46:15 +08:00
FooIbar b25661c436 Revert "Clarify message for no current torrents"
This reverts commit 49d4ae07

Reason for revert: We list outdated torrents as well after torrent
dialog overhaul.
2024-05-05 18:05:40 +08:00
FooIbar cea06f0c7e Disable abortOnError for lint in debug build
[no ci]
2024-05-05 17:16:16 +08:00
FooIbar 7de6a821d9 Drop 32-bit x86 support 2024-05-05 11:17:26 +08:00
FooIbar 13be4e4eb1 Remove Navigation Compose dependency
It's transitively provided by Compose Destinations, we should not
directly depend on it in case they are incompatible.
2024-05-05 07:58:46 +08:00
renovate[bot] 691e7c3ba7 Update compose.destinations to v2.1.0-beta03 2024-05-04 18:08:26 +00:00
FooIbar 31aea1cdbf Fix duplicate key in search suggestions 2024-05-05 01:59:49 +08:00
FooIbar 97d5642427 Run download item restoration in parallel 2024-05-04 18:52:05 +08:00
FooIbar c68272c1a4 Fix download item restoration not bailing on error 2024-05-04 17:59:34 +08:00
renovate[bot] a69dc994b3 Update dependency sh.calvin.reorderable:reorderable to v2.0.1 2024-05-04 09:27:19 +00:00
renovate[bot] d79a71c764 Update dependency dev.chrisbanes.compose:compose-bom to v2024.05.00-alpha01 2024-05-04 08:31:58 +00:00
renovate[bot] 35183de477 Update dependency androidx.navigation:navigation-compose to v2.8.0-alpha08 2024-05-04 16:31:41 +08:00
FooIbar 21b9fe3cb2 Update to snapshot Compose and remove workaround (#1050)
* Update to snapshot Compose

* Fix dep

* Revert "More workaround"

This reverts commit 9013778f58.

* Revert "Workaround for lazy layout lagging (#1042)"

This reverts commit b83e0fd0

* Revert "Workaround for comment list lagging at the bottom"

This reverts commit 45be957df5.

* Fix minOffset for blur radius calculation

Also use `onSizeChanged` instead of `onGloballyPositioned` as
measurement happens before placement.
2024-05-04 16:22:01 +08:00
FooIbar 5762b0bfc3 Disallow screen capture on identity cookies dialog 2024-05-04 11:30:34 +08:00
renovate[bot] 3473e91747 Update dependency com.android.application to v8.5.0-alpha08 2024-05-03 23:07:00 +00:00
renovate[bot]andFooIbar 6277d7d41d Update dependency sh.calvin.reorderable:reorderable to v2 (#1120)
* Update dependency sh.calvin.reorderable:reorderable to v2

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-05-03 09:36:56 +00:00
renovate[bot] f22da2b771 Revert androidx navigation update 2024-05-03 17:07:55 +08:00
FooIbar 3466bbd64a Disable grouping for AndroidX dependencies 2024-05-03 16:33:25 +08:00
FooIbar 49fc87621c Revert "Limit workflow concurrency"
This reverts commit e81092d42c.
2024-05-03 16:33:25 +08:00
GG Bond 7e558f4478 DialogState.bgWork doesn't show dialog if work doesn't suspend 2024-05-03 15:29:13 +08:00
FooIbar 307624ca9a Copy invalid filename handling logic from AOSP 2024-05-03 15:29:00 +08:00
FooIbar 40e66b919a Move ArchiveList and TorrentList to separate files (#1113)
* Move ArchiveList and TorrentList to separate files

GalleryDetailScreen is too long

* Refactor with deferred archive and torrent results
2024-05-03 07:27:57 +08:00
FooIbar cf2e0aadd5 [no ci] Fix renovate config 2024-05-02 13:56:25 +08:00
FooIbar 1b523f6a78 [no ci] Tweak renovate config 2024-05-02 13:48:50 +08:00
renovate[bot] 6a9f6bb645 Drop obsolete flag
Room generate kotlin by default now.
2024-05-02 07:17:16 +08:00
renovate[bot] 45602b05c6 Update aboutlibraries to v11.1.4 2024-05-01 19:09:42 +00:00
renovate[bot] 8dc842e125 Update AndroidX & Jetpack Compose 2024-05-01 19:09:18 +00:00
renovate[bot] 9dfc3a49fe Update Rust crate tl to 0.7.8 2024-05-01 17:10:59 +00:00
renovate[bot] 97d4a61140 Update Rust crate serde_cbor to 0.11.2 2024-05-01 17:10:41 +00:00
renovate[bot] 8b596e2274 Update Rust crate sha1 to 0.10.6 2024-05-01 17:10:15 +00:00
renovate[bot] 123b86830b Update Rust crate serde to 1.0.200 2024-05-01 16:40:54 +00:00
renovate[bot] e11f5615a1 Update Rust crate regex-lite to 0.1.5 2024-05-01 14:16:12 +00:00
FooIbar 31fb2ed2b1 Address renovate warning
[no ci]
2024-05-01 22:15:59 +08:00
renovate[bot] 9c12d11c85 Update Rust crate serde to 1.0.199 2024-05-01 14:14:59 +00:00
renovate[bot] aea0e885c3 Update Rust crate log to 0.4.21 2024-05-01 12:43:51 +00:00
renovate[bot] f34ff71145 Update Rust crate jni to 0.21.1 2024-05-01 12:43:29 +00:00
FooIbar 820c16e86b Tweak image limits dialog 2024-05-01 19:39:24 +08:00
renovate[bot] a335348b1a Update Rust crate android_logger to 0.13.3 2024-05-01 10:41:05 +00:00
renovate[bot] 7f134e1995 Update Rust crate anyhow to 1.0.82 2024-05-01 10:40:43 +00:00
FooIbar 9e13c1c3db Revert "Update Kotlin & KSP (#1084)"
This reverts commit 9ff74e789c.

Reason for revert: crash
2024-05-01 01:29:14 +08:00
FooIbar 61161cef0f Torrent dialog overhaul 2024-05-01 01:06:57 +08:00
renovate[bot]andFooIbar 9ff74e789c Update Kotlin & KSP (#1084)
* Update Kotlin & KSP

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-04-30 12:48:06 +00:00
FooIbar 45183df640 Avoid packing/unpacking and use pre-allocated list 2024-04-30 17:13:59 +08:00
FooIbar 22f11994f5 Remove obsolete workaround 2024-04-30 12:46:46 +08:00
renovate[bot] bc7aa832b7 Update dependency com.android.application to v8.5.0-alpha07 2024-04-29 21:37:45 +00:00
FooIbar b32f78ea9f Archive dialog overhaul 2024-04-29 23:49:40 +08:00
FooIbar 78002dac3a Use proper placeholder instead of 0 in image limit 2024-04-29 16:29:46 +08:00
renovate[bot]andGG Bond aca70354e7 Refactor FabBuilder interface & refine suspend dialog naming (#1082)
* `FabLayoutValue` is `Stable`

* FabBuilder accepts a autoClose

* Refactor control flow to pattern matching expression and avoid exception

* Close fab on DatePicker selected

* Refine naming

* Introduce `SnapshotStateMap<K, V>.takeAndClear()`

* PutAll action use `autoClose = false`

* Handle exceptions

* Cleanup

* Handle potential e

* Refine to use autoClose

* FabLayout should use parent Screen CoroutineScope

* Use implicit context

* Introduce `runSwallowingWithUI`

* log exception as well

* Refine naming

* Cleanup with `runSwallowingWithUI`

* Refine naming again

* Fixup

* Remove redundant logcat

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-04-29 04:20:37 +00:00
FooIbar d7a3471b9b Fix side drawer anchor updates during initial open 2024-04-28 23:43:55 +08:00
FooIbar e81092d42c Limit workflow concurrency
[no ci]
2024-04-28 18:51:11 +08:00
renovate[bot] d06df3c819 Update dependency me.saket.telephoto:zoomable to v0.11.2 2024-04-28 10:17:26 +00:00
FooIbar 050bfea8f2 Parse favorite categories from user config page 2024-04-28 18:09:17 +08:00
renovate[bot] 7b84c74abf Update dependency me.saket.telephoto:zoomable to v0.11.1 2024-04-28 06:46:40 +00:00
FooIbar 009c49cd89 Don't fail silently if can't install update 2024-04-28 14:37:31 +08:00
renovate[bot] ca023f73f4 Update dependency me.saket.telephoto:zoomable to v0.11.0 2024-04-28 05:53:51 +00:00
renovate[bot]andFooIbar 456dfd2aac Update compose.destinations to v2.1.0-beta02 (#1073)
* Update compose.destinations to v2.1.0-beta02

* Fix build

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-04-28 05:45:03 +00:00
renovate[bot] 0c0291127c Revert "Drop Xjvm-default=all"
This reverts commit df1efa7604.
2024-04-27 16:59:41 +08:00
FooIbar fe0c74de23 MimeTypeMap is case-sensitive prior to Android O
https://android-review.googlesource.com/251120
2024-04-27 16:54:06 +08:00
renovate[bot] df1efa7604 Drop Xjvm-default=all
We are not a library intended for Javaers nor do we have any Java code to interop so this is meaningless and safely to drop
2024-04-27 03:41:54 +08:00
FooIbar 73122fc517 Workaround for SearchBar reopen in non-touch mode 2024-04-27 03:34:27 +08:00
renovate[bot] b506ba277c Drop -Xlambdas=indy
https://kotlinlang.org/docs/whatsnew-eap.html#generate-lambda-functions-using-invokedynamic
2024-04-26 23:00:41 +08:00
dasoopsandFooIbar ea3aed8fae Reload metadata (#1058)
* Reload metadata

* Remove pages check and Refactor

* Check metadata stable

* Run in parallel

* Refactor postedTime

* Remove concurrency limit

* Update translation

* Update translate

Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>

* `parseDate` return timestamps

* Remove unused import

* Show Snackbar after the update

* Revert EndLine

* use localContext

* Extend the range of `runSuspendCatching`

---------

Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-04-26 21:05:52 +08:00
FooIbar 481bb8e7d4 Update libarchive to v3.7.4 2024-04-26 19:01:03 +08:00
FooIbar 0ed8c40dbf Improve a11y by limiting grid item's aspect ratio 2024-04-26 18:08:32 +08:00
FooIbar d267d7c3b0 [no ci] Change links in README to use https 2024-04-26 17:48:27 +08:00
FooIbar a04206f600 Refine UniFile and evict lookup cache on delete
Also add comments on functions that rely on implementation details.
2024-04-26 15:46:47 +08:00
FooIbar 8d64a6f1b2 Update ndk and support 16 KB page sizes (#1057)
* Update ndk and support 16 KB page sizes

* Fix CI

* Update graphics-path and pass linker flag to rustc
2024-04-25 14:37:01 +00:00
dasoops b3f614e150 Sort artists by gallery count (#1059)
* Sort artists by number of galleries

* Sorted in DB query
2024-04-25 11:23:11 +00:00
renovate[bot]andGG Bond 988fae56fd Add fake implicit syntax for migration (#1056)
* Add fake `implicit` syntax

* Refine

* Refine

* Refine

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-04-25 00:17:33 +08:00
FooIbar fa439fc62d Switch back to GitHub xz repo
It should be faster.
2024-04-24 22:05:35 +08:00
GG Bond c58b2d6156 Cleanup realPadding calculation 2024-04-24 19:40:30 +08:00
GG Bond 62c56b7918 Add missing lazy item key 2024-04-24 19:40:30 +08:00
GG Bond 73882ab55d Cleanup DownloadsScreen to use implicit context 2024-04-24 19:17:34 +08:00
490ea2b521 Add Option to Select Downloads Grouping Mode (#998)
* Add Option to Select Downloads Grouping Mode

* hide Drag and Edit Button when Mode is Artist

* Revert "hide Drag and Edit Button when Mode is Artist"

some changes are not filtered when pushed

This reverts commit 319812e156f61c32250d908ed5ed22720ea0c6b7.

* hide Drag and Edit Button when Mode is Artist

* declared is typo

* use ComicInfo.penciller

* remove BaseGalleryInfo.artist

* Correct invalidate key

* reImport kotlin.math.roundToInt, it was incorrectly deleted

* use movableContentOf

* optimize imports

* use remember not rememberInVM

* Get DownloadInfo.artists from Database or `ComicInfo.xml`

* refactor

* unknown artist group

* redundant parameter

* reformat code

* SearchBar title and hint

* Translation

* Fix when initially loaded, the count of DownloadLabel is zero.

* lazy invalid

* use remember not rememberInVM

* refactor

* Fix LazyColumn not updated

* refactor

* Hide some Button in Artist Mode

* Revert

* Fix update labelList not updated UI

* Revert reFormat

* use trailing lambda

* Revert rememberUpdatedState

* Translate

* use buildMap

* Move ARTIST to DOWNLOAD_ARTIST

* Revert multi-line for chained Modifier

* Generate DownloadInfo.artistInfoList after writeComicInfo and restoreDownload

* Fixed crash after download gallery

* Use a composite key for DOWNLOAD_ARTISTS

* Make artists non-null

* Refactor

* Only update artist info when writing comic info

* Separate list for pending artist info

* Remove unused

* Put download artist when import database

* Use a composite key of GID and ARTIST

* Refactor

* Cache labelList

* named lambda parameters

* Refactor to avoid `mutex`

* follow up on `Make artists non-null`

* ArtistList order by ARTIST

* Lift EhTagDatabase check

* Translate artist in download title

* Refactor

* Refactor readMetadataFromLocal

Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>

* Do not update the DB when the `artists` is empty

* Remove unused

---------

Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
Co-authored-by: GG Bond <whatever@tagkong.com>
2024-04-24 11:01:53 +00:00
GG Bond 7116871652 Avoid implement a CancellableContinuation
Let compiler do CPS transform
2024-04-24 18:43:21 +08:00
FooIbar cca374c774 Refactor UniFile.fromUri for tree uri
This reverts b39e244 ("Fix `UniFile.fromUri` for children of tree uri")
and 3978abe ("Fix UniFile.fromUri() for 2 path segments tree uri").
2024-04-24 17:48:41 +08:00
FooIbar 3e0dbf92d0 Fix search bar offset not being reset 2024-04-22 12:49:03 +08:00
renovate[bot] 2747ae674c Update dependency sh.calvin.reorderable:reorderable to v1.5.2 2024-04-21 20:20:31 +00:00
FooIbar e85ec5aaba Code cleanup 2024-04-21 23:42:55 +08:00
FooIbar d4894e066b Prepare for next iteration 2024-04-21 22:47:04 +08:00
FooIbar 71a4e84d7c Prepare for release 1.11.4 2024-04-21 22:45:54 +08:00
FooIbar d6c36146ba Fix losing reading progress on reading mode change 2024-04-21 22:35:22 +08:00
FooIbar 9013778f58 More workaround 2024-04-21 18:05:25 +08:00
renovate[bot] 1af03dd145 Update dependency sh.calvin.reorderable:reorderable to v1.5.1 2024-04-20 16:46:53 +00:00
FooIbar b83e0fd092 Workaround for lazy layout lagging (#1042) 2024-04-20 16:37:41 +00:00
GG Bond 1f8d786d05 Simplify to use Modifier.offset 2024-04-20 18:31:22 +08:00
GG Bond 5d87a4ada0 Never have a clipped shadow 2024-04-20 18:31:22 +08:00
GG Bond 4d4fb1e398 Eliminate unnecessary Column 2024-04-20 17:10:33 +08:00
GG Bond 05eea54f06 Fix primaryFab appear anim 2024-04-20 17:10:33 +08:00
GG Bond a00d9ef765 Mitigate shadow being clipped 2024-04-20 17:10:33 +08:00
GG Bond aa6ddac9c5 Avoid unnecessary zIndex 2024-04-20 17:10:33 +08:00
GG Bond 9a6f17c745 Image Search Card doesn't need to be scrollable now 2024-04-20 17:10:33 +08:00
GG Bond 980977aaf3 Ensure Image Search Card's shadow not being clipped 2024-04-20 17:10:33 +08:00
GG Bond 3ed0afaf91 Restore an alpha usage can be safely applied 2024-04-20 17:10:33 +08:00
GG Bond 250adb4b33 Fix shadow being clipped 2024-04-20 17:10:33 +08:00
GG Bond 0baf09cb53 Codestyle fix for DownloadCard 2024-04-20 17:10:33 +08:00
FooIbar d04a914b9b Tweak gallery card alignment and ensure min height 2024-04-19 19:08:21 +08:00
renovate[bot] 59775cb27c Update dependency com.android.application to v8.5.0-alpha06 2024-04-18 22:06:24 +00:00
GG Bond fb76cd7b1b Move compose out of snapshot 2024-04-18 11:25:52 +08:00
renovate[bot] 52fb5306b6 Update dependency dev.chrisbanes.compose:compose-bom to v2024.04.00-alpha02 2024-04-18 01:03:11 +00:00
renovate[bot] 74f7d95718 Update AndroidX & Jetpack Compose 2024-04-17 18:12:27 +00:00
renovate[bot] bcc1b78c7c Update compose snapshot 2024-04-18 00:00:56 +08:00
FooIbar 3978abea87 Fix UniFile.fromUri() for 2 path segments tree uri 2024-04-17 17:38:51 +08:00
FooIbar 556b726349 Update to follow the latest material slider specs
Tick size is 4 dp now.
2024-04-16 10:49:10 +08:00
FooIbar e0f16f31e6 Automatically backup data before updating 2024-04-16 00:08:30 +08:00
FooIbar b39e24467c Fix UniFile.fromUri for children of tree uri 2024-04-15 23:50:54 +08:00
FooIbar 65613f07ba Optimize DownloadCard interaction in select mode 2024-04-15 21:53:37 +08:00
FooIbar 666a7e4d77 Allow disable list item animations on API 29+ (#1024)
* Allow disable list item animations on API 29+

* Update list item animations setting description
2024-04-15 14:54:13 +08:00
renovate[bot] cf08bfdd9b Update dependency me.saket.telephoto:zoomable to v0.10.0 2024-04-14 21:58:40 +00:00
renovate[bot]andFooIbar 1f47d56c55 Update Kotlin, KSP and Compose Compiler (#1009)
* Update Kotlin, KSP and Compose Compiler

* Migrate to new compose compiler gradle plugin

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-04-14 14:38:22 +00:00
FooIbar 1a7dde848f Don't treat warnings as errors on debug build 2024-04-14 17:56:55 +08:00
GG Bond c8207308a8 Update predictive back animations to use interpolation curve of (0.1, 0.1, 0, 1) 2024-04-14 17:38:03 +08:00
renovate[bot] f23020cc6f Update dependency sh.calvin.reorderable:reorderable to v1.5.0 2024-04-12 18:46:12 +00:00
renovate[bot] 555e487f1e Update dependency com.android.application to v8.5.0-alpha05 2024-04-11 18:20:21 +00:00
renovate[bot] 107bb0b15d Update aboutlibraries to v11.1.3 2024-04-09 19:14:59 +00:00
FooIbar 87a2de393e Tweak select item dialog style 2024-04-10 03:04:49 +08:00
renovate[bot] a7e4412454 Update dependency com.mikepenz.aboutlibraries.plugin to v11.1.2 2024-04-09 14:42:54 +00:00
FooIbar 7dce4cfa8e Update Compose snapshot 2024-04-09 22:12:49 +08:00
FooIbar 2b30aca47c Update R8 and remove workaround 2024-04-09 21:44:57 +08:00
FooIbar 0073d2862b Fixed crash on deleting a label after renaming it 2024-04-09 18:39:25 +08:00
FooIbar b182c97185 Fix titleless select item dialog top padding 2024-04-09 10:46:44 +08:00
renovate[bot] a32119bada Update dependency com.android.application to v8.5.0-alpha04 2024-04-08 19:37:35 +00:00
FooIbar a928cfd066 Update libarchive to v3.7.3 2024-04-09 00:08:01 +08:00
FooIbar 8c7a371336 Highlight selected item in select item dialog 2024-04-07 23:32:47 +08:00
GG Bond 6f61eb4946 Update outdated comments 2024-04-07 21:21:37 +08:00
GG Bond 1096f05344 Move navigation out of snapshot 2024-04-07 21:21:37 +08:00
GG Bond 26f96d3e38 Move to telephoto 0.10.0-SNAPSHOT 2024-04-07 21:21:37 +08:00
FooIbar 4a02189a59 Rearrange code to move plurals resources together 2024-04-07 17:13:35 +08:00
FooIbar 7a5bab41f6 Add option to disable list item animations (#997)
It may crash on some devices.
2024-04-07 13:57:27 +08:00
FooIbar 84c32fb28d Prepare for next iteration 2024-04-06 17:10:28 +08:00
FooIbar a3cb6d2782 Prepare for release 1.11.3 2024-04-06 17:09:38 +08:00
FooIbar 45be957df5 Workaround for comment list lagging at the bottom 2024-04-06 15:25:26 +08:00
FooIbar 8e45014e3f Align load comments button and progress indicator 2024-04-06 15:24:54 +08:00
FooIbar d84e948352 Add padding for progress indicator in DetailScreen 2024-04-06 15:24:54 +08:00
FooIbar 68bd835038 Fallback to transferTo if sendfile failed 2024-04-06 10:52:25 +08:00
FooIbar c297bebea1 Fix resource leak when decode job is canceled 2024-04-05 20:29:04 +08:00
FooIbar 6c0a823216 Fix typo (#991)
* Fix typo

* Fix lint
2024-04-05 06:57:34 +00:00
renovate[bot]andFooIbar 067a701bdc Update KSP to v2.0.0-Beta5-1.0.20 (#989)
* Update Kotlin, KSP and Compose Compiler

* Fix compose compiler version

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-04-05 05:03:58 +00:00
GG Bond c3fb008c92 Introduce HttpStatement.executeSafely 2024-04-05 13:03:39 +08:00
GG Bond bc4321da2e Cleanup CronetEngine 2024-04-05 13:03:39 +08:00
FooIbar 8dec040803 Fix FileNotFoundException on saving download thumb 2024-04-05 00:04:02 +08:00
FooIbar 29e4e77c44 Open file descriptor in "wt" mode for overwriting 2024-04-05 00:04:02 +08:00
FooIbar 11429ef7fe Log image loading errors in release build 2024-04-05 00:04:02 +08:00
FooIbar f5fcd96a1e Fix DownloadService stopped during onFinish call 2024-04-04 19:17:35 +08:00
renovate[bot]andFooIbar 19120038c5 Update AndroidX & Jetpack Compose (#985)
* Update AndroidX & Jetpack Compose

* Fix nullability

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-04-04 06:19:08 +00:00
FooIbar 9021f28ead Allow update to unstable AndroidX libraries
Most of them are already transitively updated.
2024-04-04 13:52:50 +08:00
renovate[bot] 62934f72e3 Update dependency dev.chrisbanes.compose:compose-bom to v2024.04.00-alpha01 2024-04-03 23:36:15 +00:00
renovate[bot] 6c534e1049 Update dependency androidx.paging:paging-compose to v3.3.0-beta01 2024-04-03 19:00:38 +00:00
renovate[bot] f80cd90792 Update dependency androidx.core:core-splashscreen to v1.1.0-rc01 2024-04-03 19:00:00 +00:00
renovate[bot] 3999c0c114 Update dependency io.arrow-kt:arrow-stack to v1.2.4 2024-04-03 13:21:01 +00:00
FooIbar 59399453c4 Fix IP ban error message and parse error logging (#979) 2024-04-03 08:56:40 +00:00
renovate[bot] 694bb19e2a Update dependency sh.calvin.reorderable:reorderable to v1.4.0 2024-04-03 06:25:14 +00:00
FooIbar 9928ecd4d9 Refactor database export 2024-04-03 11:54:06 +08:00
renovate[bot] 2c5293af6e Update dependency com.android.application to v8.5.0-alpha03 2024-04-02 13:39:05 +00:00
FooIbar 9569ca774d Fix unable to refresh images due to resource leak 2024-04-02 00:38:38 +08:00
FooIbar 3a04460926 Abort if no image entries found in archive 2024-04-01 18:18:19 +08:00
FooIbar acb4fb6166 Don't run decode job if fetch job failed
Fix fetch error being suppressed by decode job result.
2024-03-31 20:39:27 +08:00
renovate[bot]andGG Bond 7d137bb016 Fast move to compose destinations v2.1 (#965)
* Fast move to compose destinations v2.1

* Remove default parameters

* Cleanup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-31 16:07:06 +08:00
FooIbar 8c2ed37b72 Update build script due to xz Github repo shutdown 2024-03-31 01:31:22 +08:00
FooIbar 749b230250 Fix download label not being draggable 2024-03-30 10:19:08 +08:00
renovate[bot]andGG Bond 23531cb6e0 Upstream SearchBar (#960)
* Upstream SearchBar

* Fix SearchBar label

* Fix SearchBar padding

* Use BoxWithConstraints

* Refine

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-29 10:01:42 +00:00
FooIbar 0ac11dbe0b Fix SpiderQueen not respecting FIFO order
And optimize preloading strategy.
2024-03-29 17:50:53 +08:00
FooIbar 9b0e017542 Use Compose UI implementation of parseAsHtml 2024-03-28 15:48:28 +08:00
FooIbar f2f5fcacf9 Use upstream navigation drawer 2024-03-28 15:48:16 +08:00
FooIbar 52ded265f3 Update Compose to snapshot and remove workaround 2024-03-28 08:41:01 +08:00
FooIbar e77f905c4a Revert "Downgrade to stable AGP"
This reverts commit 2d14d34d53.

Reason for revert: Workaround added
2024-03-28 08:39:15 +08:00
FooIbar 2d14d34d53 Downgrade to stable AGP 2024-03-27 13:26:34 +08:00
renovate[bot] 78facda18a Crossinline (#952) 2024-03-26 22:32:42 +08:00
renovate[bot]andrenovate[bot] 1fe1b43015 Update Kotlin, KSP and Compose Compiler (#950)
* Update Kotlin, KSP and Compose Compiler

* Update libs.versions.toml

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <99822064+revonateB0T@users.noreply.github.com>
2024-03-26 14:19:00 +00:00
FooIbar 63164dc70a Scale wide images (banners) to fit target width
And don't scale tall images (webtoons).
2024-03-26 15:50:45 +08:00
renovate[bot] 0d39092a7f Update dependency me.saket.telephoto:zoomable to v0.9.0 2024-03-26 00:34:29 +00:00
renovate[bot] c50db8a327 Update plugin composeCompilerReportGenerator to v1.2.0 2024-03-25 11:58:03 +00:00
renovate[bot] 7e107cc5e2 Update dependency com.mikepenz.aboutlibraries.plugin to v11.1.1 2024-03-23 15:15:45 +00:00
renovate[bot] 260949e3a7 Update dependency gradle to v8.7 2024-03-22 20:28:33 +00:00
renovate[bot] d9ec108721 Update dependency com.android.application to v8.5.0-alpha02 2024-03-22 20:25:51 +00:00
FooIbar 1e97407936 Fix recycled item's height being 0 in webtoon mode
Refactor reader page holder and miscellaneous cleanups
2024-03-22 22:10:00 +08:00
FooIbar 73afe05a18 Manually migrate from schema 17 to 18 for non-null 2024-03-22 20:59:45 +08:00
FooIbar 23475de932 Fix layout inspector not working 2024-03-21 20:31:10 +08:00
FooIbar 6fb2172c2c Drop obsolete snapshot 2024-03-21 19:02:34 +08:00
renovate[bot] 9226b71119 Update dependency dev.chrisbanes.compose:compose-bom to v2024.03.00-alpha02 2024-03-21 10:42:27 +00:00
FooIbar 58e38b58bf Fix renovate configuration
[no ci]
2024-03-21 18:18:29 +08:00
renovate[bot] db0d110627 Update dependency androidx.paging:paging-compose to v3.3.0-alpha05 2024-03-21 10:17:09 +00:00
FooIbar 08812bf7ff Tweak renovate configuration
[no ci]
2024-03-21 18:09:13 +08:00
renovate[bot] daf7f8ffca Update dependency com.android.application to v8.5.0-alpha01 2024-03-21 09:52:03 +00:00
FooIbar 74564fa07f Tweak renovate configuration
[no ci]
2024-03-21 17:41:35 +08:00
FooIbar fc51d3fc81 Allow update to unstable AGP and Compose BOM
[no ci]
2024-03-21 17:32:50 +08:00
renovate[bot]andFooIbar c5d5b8abd2 Update dependency androidx.navigation:navigation-compose to v2.8.0-alpha05 (#929)
* Update dependency androidx.navigation:navigation-compose to v2.8.0-alpha05

* Fix deprecated

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-03-21 17:31:54 +08:00
FooIbar 193badccb8 Fix crash when reading galleries from gallery list 2024-03-21 16:52:17 +08:00
FooIbar 2653d0568a Fix false positive update notifications 2024-03-21 16:31:48 +08:00
FooIbar adf5a65371 Group Kotlin, KSP and Compose Compiler
[no ci]
2024-03-21 15:54:08 +08:00
FooIbar 5b59dabc66 Fix generating simple language from title 2024-03-21 15:19:46 +08:00
GG Bond f7259c5b40 Individual zoomableState per pager item 2024-03-17 14:56:44 +08:00
FooIbar 6f9fceaef8 Prepare for next iteration 2024-03-17 14:45:19 +08:00
FooIbar 6a64ff51ed Prepare for release 1.11.2 2024-03-17 14:44:16 +08:00
FooIbar ea9d9cfba7 Prepare changelog for 1.11.2 2024-03-17 14:41:43 +08:00
FooIbar 75c6561896 Fix app updater getting wrong download link 2024-03-16 20:13:42 +08:00
FooIbar 8f8db82e9d Fix disowned gallery uploader parsing (#918)
* Fix disowned gallery uploader parsing

* Run rustfmt

* Refine

* Run rustfmt
2024-03-16 17:48:10 +08:00
FooIbar a114a8ac72 Minor tweak to some settings' visibility 2024-03-16 11:10:08 +08:00
FooIbar 2c6216057f Revert "Merge default and marshmallow flavors"
This reverts commit 5676de24da.

Reason for revert: Desugaring causes regression on API 26+
2024-03-15 19:55:59 +08:00
FooIbar c5cbcf7418 Reintroduce confirm dialog for swipe-to-dismiss (#914)
Observe the state changes instead of using `confirmValueChange`, which
will be called twice.
2024-03-15 18:40:51 +08:00
FooIbar 5746e3bb57 Pin compose foundation version to 1.7.0-alpha03 2024-03-14 16:05:18 +08:00
FooIbar fd3c87be22 Make reader bottom sheet scrollable and fix insets 2024-03-14 16:05:08 +08:00
FooIbar 866fff3e45 Fix favorites modification blocked by snackbar 2024-03-14 16:04:55 +08:00
FooIbar 06df7befb6 Fix tag namespace for cloud favorites search 2024-03-13 21:38:16 +08:00
FooIbar 8021f86473 Address java.util.regex.Pattern usage 2024-03-13 21:34:04 +08:00
renovate[bot]andGG Bond c9919a8b39 Cleanup CronetEngine (#901)
* Cleanup CronetEngine with UploadDataProviders

* Remove WriteChannelContent as no user now

* Cleanup

* Cleanup

* Remove unnecessary invokeOnCancellation

* Refine

* Refine

* Format

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-13 14:40:37 +08:00
renovate[bot] 386015a9ec Update dependency com.squareup.okio:okio-jvm to v3.9.0 2024-03-13 04:00:26 +00:00
FooIbar cbce98b34e Prepare for next iteration 2024-03-12 22:47:24 +08:00
FooIbar f69521fc1a Prepare for release 1.11.1 2024-03-12 22:45:48 +08:00
FooIbar 01b4054368 Prepare changelog for 1.11.1 2024-03-12 22:34:27 +08:00
FooIbar e07aab4434 Drop basic login as captcha is mandatory now 2024-03-12 21:27:01 +08:00
FooIbar 18caa87512 Implement group by download label 2024-03-12 21:26:09 +08:00
FooIbar 5676de24da Merge default and marshmallow flavors 2024-03-12 12:05:12 +08:00
FooIbar 57bbb1fe38 Embed Cronet and drop OkHttp (#895)
* Embed Cronet and drop OkHttp

* Fix updater
2024-03-11 12:22:39 +00:00
FooIbar dcbfbc2e5f Fix concurrent modification 2024-03-11 15:04:56 +08:00
FooIbar e1f473d301 Convert remaining icons to ImageVector 2024-03-11 12:43:52 +08:00
renovate[bot] a33256d29f Update dependency sh.calvin.reorderable:reorderable to v1.3.3 2024-03-10 11:12:12 +00:00
FooIbar 6a81877b09 Prepare for next iteration 2024-03-09 19:17:18 +08:00
FooIbar 6cd7b85b94 Prepare for release 1.11.0 2024-03-09 19:16:25 +08:00
FooIbar df97a9c4b9 Prepare changelog for 1.11.0 (#881)
no ci
2024-03-09 19:10:37 +08:00
FooIbar 5cb91e9b45 Update liblzma to v5.6.1 2024-03-09 19:03:37 +08:00
FooIbar 94794cb0db Address code review comments 2024-03-09 17:16:42 +08:00
FooIbar a16c021000 Fix temporary download directory cleanup 2024-03-09 16:22:57 +08:00
FooIbar 49d4ae078f Clarify message for no current torrents 2024-03-09 14:52:12 +08:00
FooIbar eb45068df3 Increase bringCursorIntoView workaround delay 2024-03-09 14:19:00 +08:00
renovate[bot] 1aa750d676 Update softprops/action-gh-release action to v2 2024-03-08 21:35:28 +00:00
FooIbar af85a68e3d Fix duplicate subscription on page state 2024-03-08 15:45:54 +08:00
FooIbar a8fc4003a3 Workaround for crash on delete text button click 2024-03-08 09:24:10 +08:00
renovate[bot] 675df44745 Update dependency com.google.devtools.ksp to v2.0.0-Beta4-1.0.19 2024-03-08 00:33:53 +00:00
renovate[bot] 7e271d7e8e Update dependency com.android.application to v8.4.0-alpha13 2024-03-07 22:07:29 +00:00
FooIbar acb2c720af Fix torrent parsing 2024-03-07 23:06:22 +08:00
GG Bond 5d0c2e3f05 Animated dim with SettingsPager 2024-03-07 22:48:33 +08:00
GG Bond 3d5e3620dd Restore dep behaviour in ReaderModeSetting 2024-03-07 22:48:33 +08:00
GG Bond 43aefeedae Restore dep behaviour of fullscreen & cutoutShort 2024-03-07 22:48:33 +08:00
GG Bond c2cbcc009d No more credits to MDC-Android 2024-03-07 21:08:55 +08:00
GG Bond 2aa494d9b7 Get rid of MDC-Android 2024-03-07 21:08:55 +08:00
GG Bond 8f3a11f374 Calculate Reader statusBarColor with Compose 2024-03-07 21:08:55 +08:00
GG Bond 76298f15e4 Rewrite harmonizeWithRole with ColorUtils 2024-03-07 21:08:55 +08:00
GG Bond 58839e0def Fix Error Text Color 2024-03-07 21:08:55 +08:00
GG Bond 6fe62db5e4 Remove ReaderButton, prepare to drop MDC 2024-03-07 21:08:55 +08:00
renovate[bot]andGG Bond 9b9f25d405 Move to Compose Reader Settings Now (#871)
* Move to Compose Reader Settings Now

* Cleanup res

* Cleanup

* Fix trans

* Fix

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-07 17:43:41 +08:00
renovate[bot]andGG Bond e47d7378ec Add remaining settings layout (#870)
* Implement ReadModeSetting

* Fix textstyle

* Fix pref color

* Fix

* Refine

* Refine style

* Remaining Pref

* Inline

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-07 08:49:13 +00:00
renovate[bot]andGG Bond 51b385408d Implement remaining of ColorFilterSetting (#867)
Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-07 13:14:58 +08:00
renovate[bot] 8e7cced8d2 Update dependencies 2024-03-07 13:12:18 +08:00
renovate[bot] affeb3e106 Update dependency androidx.browser:browser to v1.8.0 2024-03-06 21:05:15 +00:00
FooIbar a2377857e9 Fix page state update on cache entry removed 2024-03-06 22:53:41 +08:00
FooIbar 7714ff8938 Make sure slider value has single source of truth 2024-03-06 21:55:43 +08:00
FooIbar 352853b88c Implement VolumeKeysHandler 2024-03-06 20:44:49 +08:00
5idereal 23d282e354 Update strings.xml 2024-03-06 19:46:00 +08:00
FooIbar b93c12de89 Fix navigating on non-main thread 2024-03-06 16:30:37 +08:00
FooIbar e0e5a155aa Initial support for local tag search
BREAKING CHANGE: Upgrade database
2024-03-06 16:29:37 +08:00
renovate[bot]andGG Bond e1f34a7b1b Implement ColorFilterSetting (#859)
* Implement ColorFilterSetting

* Initial ColorFilterSetting

* Cleanup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-05 17:20:09 +00:00
renovate[bot] 298e80eb9d Update compose.destinations to v1.10.2 2024-03-05 16:28:14 +00:00
renovate[bot]andGG Bond 3ecfd83f1e Remaining GeneralSettings Layout (#857)
* PlaceHolder

* Implement

* ConfigureKeepScreenOn

* Implement

* Remaining general layout

* Remove zIndex

* Add ReaderContentOverlay

* Stub for ColorFilterSetting

* Implement ColorFilterSetting

* Introduce SliderChoice

* Refine naming

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-05 16:19:21 +00:00
renovate[bot]andGG Bond 1dcf4e7f46 Implement some reader settings (#856)
* Initial SpinnerChoice

* Apply bgColor

* Introduce SwitchChoice

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-05 18:32:36 +08:00
FooIbar f1a856cb45 Don't fetch metadata if source is GalleryDetail 2024-03-05 18:32:25 +08:00
renovate[bot]andGG Bond af32d7eea7 Initial Setting Pager (#854)
* Update Compose Snapshot

* Initial SettingsPager

* Cleanup

* Fix inactive color

* Sync container color with BSheet

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-05 13:32:48 +08:00
FooIbar 47be2754e5 Refactor tag namespace to use value class 2024-03-05 10:45:51 +08:00
FooIbar 39b16b6650 Fix webtoon last visible item position calculation 2024-03-04 22:13:07 +08:00
FooIbar 0a809a564c Fix general setting update on reading mode changes
Another bug introduced in DataStore migration.
2024-03-04 19:49:32 +08:00
FooIbar 07e24013c8 Workaround for prepending before the first item 2024-03-04 19:48:55 +08:00
FooIbar 8e8394985d Don't crop borders for webtoons
Webtoons are typically split across multiple pages, they require
consistent width to maintain alignment.
2024-03-04 16:56:23 +08:00
FooIbar e54b33aaaa Fix simple language generation for ComicInfo
Regression introduced in commit 4142f288
2024-03-04 15:01:16 +08:00
GG Bond e6a22d8ef4 Reader Setting PlaceHolder 2024-03-04 12:21:02 +08:00
GG Bond ae25018574 ReaderScreen saveToImage 2024-03-04 12:21:02 +08:00
GG Bond 28160608ec ReaderScreen saveImage 2024-03-04 12:21:02 +08:00
GG Bond 38651eba1d Optimize GalleryListScreen 2024-03-04 00:42:36 +08:00
GG Bond cc53fa5f1c Optimize 2024-03-04 00:42:36 +08:00
FooIbar 70f8181752 Support FTS for history and local favorites search
BREAKING CHANGE: Upgrade database
2024-03-03 23:24:08 +08:00
GG Bond 9e506f6258 Update empty hint in HistoryScreen 2024-03-03 23:23:08 +08:00
GG Bond 1304c728cf Cleanup GalleryCommentsScreen 2024-03-03 23:09:00 +08:00
GG Bond 80e11c54e7 Composing FavouritesScreen 2024-03-03 23:09:00 +08:00
GG Bond ff5d58b101 Update CopyLeft years 2024-03-03 23:09:00 +08:00
GG Bond bf550d99bc Remove credits to OkHttp as we are not directly built on it 2024-03-03 23:09:00 +08:00
FooIbar 7738b7bc29 Implement title keyword search in history (#840)
* Implement title keyword search in history

* Don't use Dispatchers.IO
2024-03-03 14:51:30 +00:00
FooIbar 01f51b1000 Decouple search FAB from SearchBarScreen 2024-03-03 18:44:40 +08:00
FooIbar 16dfacb285 Workaround incorrect fling velocity on zoom end 2024-03-03 00:42:46 +08:00
GG Bond a253ddf7e4 composing with MainActivity 2024-03-02 21:57:55 +08:00
GG Bond ffb488482c composing GalleryDetailScreen 2024-03-02 21:57:55 +08:00
GG Bond 0e29754ce9 composing GalleryCommentsScreen 2024-03-02 21:57:55 +08:00
GG Bond ee97720e1f composing GalleryPreviewScreen 2024-03-02 21:22:57 +08:00
GG Bond 29d4e6370c composing GalleryPreviewScreen 2024-03-02 21:22:57 +08:00
GG Bond 9040cb54d4 composing with CoroutineScope 2024-03-02 21:22:57 +08:00
GG Bond f082766f06 composing HistoryScreen 2024-03-02 21:22:57 +08:00
GG Bond e2372891cb composing ReaderScreen 2024-03-02 21:22:57 +08:00
GG Bond 9dc5b5c539 Introducing composing magic, pack necessary environment CompositionLocal 2024-03-02 21:22:57 +08:00
GG Bond 886e025ac8 Implement copy 2024-03-02 21:22:57 +08:00
GG Bond feb13cbd79 Fix sheet anim 2024-03-02 21:22:57 +08:00
GG Bond 66baaad86f Implement share image 2024-03-02 21:22:57 +08:00
FooIbar 4142f28822 Fix simple language generation for favorites 2024-03-02 19:40:30 +08:00
renovate[bot] c578b16e27 Update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.6.0-RC.2 2024-03-02 10:06:04 +00:00
FooIbar 32887acecd Migrate to kotlinx datetime [2/2] 2024-03-02 17:58:37 +08:00
FooIbar 5cf5cc5e34 Update page state on image extraction failure 2024-03-02 16:11:42 +08:00
GG Bond 4dc0f7e02e CropBorder use Compose IntRect 2024-03-02 16:01:08 +08:00
renovate[bot]andGG Bond 6e9c6e6269 Updates for ReaderScreen (#827)
* Retry pages

* Restore loading behaviour

* Refactor GalleryPager

* GalleryPager accepts onSelectPage

* Slot to do page select actions

* Move zoomableState in

* Refactor using EdgeApplier

* Cleanup unneeded

* Workaround Crash

* Don't scale non-image

* Reset page state when recycled

* Have pageloader restart when cropBorder changes

* Make PagerItem top-level

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-02 15:43:53 +08:00
renovate[bot]andGG Bond a22880a9b1 Fix archive memleak (#828)
* Don't lock anon pages when decode

* Log madvise fault

* Simplify

* Don't readahead unconditionally

* Refine

* Fixes

* Cleanup

* Fix sparse archive case

* Fixes

* Prefault anon pages for new kernel

* Fixes

* Fixes

* Fixes

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-03-02 14:48:35 +08:00
FooIbar 7357724392 Address GlobalScope usage and minor cleanup 2024-03-01 16:05:17 +08:00
renovate[bot] fb1b08e7e8 Update dependency com.android.application to v8.4.0-alpha12 2024-02-29 23:43:32 +00:00
renovate[bot] 1405b99ab8 Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha06 2024-02-29 23:41:13 +00:00
FooIbar f7aec69dae Avoid SAF overhead when save-as-cbz is enabled 2024-02-29 22:15:43 +08:00
renovate[bot] f15a0fc4bb Update dependency io.arrow-kt:arrow-stack to v1.2.3 2024-02-29 10:21:56 +00:00
FooIbar 6330fc3bdc Revert "Build with Android 15 preview SDK"
This reverts commit 7d2e0f7f

Reason for revert: Android SDK sources for VanillaIceCream are not
available, making it hard to debug.
2024-02-29 16:10:00 +08:00
FooIbar 01e3f3e9b7 Sort only entries in external archive files 2024-02-29 16:07:34 +08:00
FooIbar e0c614cf71 Cache display name and mime type for document file 2024-02-29 16:06:42 +08:00
renovate[bot] b34764d4c2 Update dependency com.google.devtools.ksp to v2.0.0-Beta4-1.0.18 2024-02-29 04:44:46 +00:00
FooIbar f46f84e533 Fix forbidden filename characters in gallery title 2024-02-29 12:36:40 +08:00
renovate[bot] ca0eaf2053 Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha05 2024-02-29 03:05:54 +00:00
renovate[bot] 25f283ee9c Update snapshot 2024-02-29 03:45:13 +08:00
FooIbar 8ee23ab520 Fix zero-copy branch condition for an edge case 2024-02-29 01:45:10 +08:00
renovate[bot]andrenovate[bot] 6964baf3f6 Update aboutlibraries to v11 (major) (#810)
* Update aboutlibraries to v11

* Update LicenseScreen.kt

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <99822064+revonateB0T@users.noreply.github.com>
2024-02-28 12:52:07 +00:00
FooIbar 01aa7af175 Minor fixes for new reader 2024-02-28 18:28:19 +08:00
renovate[bot]andGG Bond 5982bd2d4b Zero-copy read for 0-compression archives (#809)
* Zero-copy read for 0-compression archives

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-28 09:04:17 +00:00
FooIbar d0fbb3539f Initial save downloaded gallery as cbz archive (#808)
* Initial save downloaded gallery as cbz archive

* Make save as cbz archive opt-in
2024-02-28 08:06:08 +00:00
GG Bond 284fb4242b Compose Reader Start Page 2024-02-28 15:52:53 +08:00
GG Bond beeb4bdbd4 Crop border for Compose ReaderScreen 2024-02-28 15:52:53 +08:00
renovate[bot]andGG Bond 76a52903e5 Polymorphic pager (#804)
* Ctrl AppbarVisible

* PageIndicatorText

* Polymorphic pager

* Fixes

* Sync state for pager as well

* Refine

* Navbar Padding

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-28 04:19:29 +00:00
Vladimir Dostoyevskiy a19b8782a8 Update compose snapshot 2024-02-28 08:58:51 +08:00
Vladimir DostoyevskiyandGG Bond 31f66fd05b Reader updates (#800)
* Refine

* Bars and sliders

* Zoomable

* Refine

* Refine Slider & LazyList state sync

* Refine

* Cleanup

* Fixes

* Fix initial state

* Fixes

* Fixes

* Fixup initial state

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-27 23:14:36 +08:00
renovate[bot] bc3c4e969c Update dependency io.arrow-kt:arrow-stack to v1.2.2 2024-02-27 14:52:00 +00:00
FooIbar 4231402e54 Coroutinize DownloadManager 2024-02-27 22:44:12 +08:00
Vladimir DostoyevskiyandGG Bond ff4f76dfa5 Initial Compose ReaderScreen (#799)
* Initial Compose ReaderScreen

* Refine

* Naming

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-27 09:44:03 +00:00
FooIbar 2ff9df4c07 Show gallery pages in history 2024-02-27 17:29:35 +08:00
GG Bond 7cbc641178 Drop outdated comment 2024-02-27 13:58:33 +08:00
GG Bond 08d5621b59 Update snapshot for non-gesture systemback transition 2024-02-27 13:58:33 +08:00
GG Bond d39c2fdfa2 Update workaround 2024-02-27 13:58:33 +08:00
GG Bond 27e02ad642 Don't dup fd when calculate sha1
Signed-off-by: GG Bond <whatever@tagkong.com>
2024-02-27 12:50:32 +08:00
FooIbar 11e9faef7c Fix skip H@H key parsing
It may contain alphabets.
2024-02-26 20:55:48 +08:00
FooIbar cbb8971dd1 Implement sort downloads by page count 2024-02-26 18:04:45 +08:00
FooIbar 1077f4d8cf Show pages instead of language in downloads' badge (#793)
It is expected that most downloads will be in the same language.

BREAKING CHANGE: Upgrade db, add `PAGES` column to `GALLERIES` table
2024-02-26 17:54:21 +08:00
FooIbar 594f9412e3 Ignore leading zeros when sorting archive entries 2024-02-26 12:44:48 +08:00
Vladimir DostoyevskiyandGG Bond 7674f6a0f7 Refactor Image with coil Interceptor (#791)
* CropBorderInterceptor

* TooLargeBitmapInterceptor

* Refine

* Take Foolbar's code

* May fail if the image is too large

* Fixup

* Fixup

* Refine

* Refine

* Swap CropBorderInterceptor & HardwareBitmapInterceptor

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-26 03:49:40 +00:00
Vladimir DostoyevskiyandGG Bond aea6fbf4ab Anyhow for parser (#788)
* Use anyhow for parser

Signed-off-by: GG Bond <whatever@tagkong.com>

* Refine

Signed-off-by: GG Bond <whatever@tagkong.com>

---------

Signed-off-by: GG Bond <whatever@tagkong.com>
Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-25 23:58:33 +08:00
GG Bond 962f9bfff5 Fuck off silly error handling
Signed-off-by: GG Bond <whatever@tagkong.com>
2024-02-25 23:04:35 +08:00
GG Bond 60532e2622 Move sha1 to mod hash, use anyhow
Signed-off-by: GG Bond <whatever@tagkong.com>
2024-02-25 23:04:35 +08:00
FooIbar 5c7a834342 Treat download as finished if archive file exists 2024-02-25 21:24:08 +08:00
FooIbar ca940080a9 Move checked category filter cards to first 2024-02-25 19:39:16 +08:00
Vladimir Dostoyevskiy 2273dd541a Enable simd (#783)
* Enable simd

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update CMakeLists.txt
2024-02-25 07:34:17 +00:00
Vladimir DostoyevskiyandGG Bond 422062226d Move to rust sha1 impl (#782)
* Move to rust sha1 impl

* Use onstack buffer

Signed-off-by: GG Bond <whatever@tagkong.com>

---------

Signed-off-by: GG Bond <whatever@tagkong.com>
Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-25 14:07:32 +08:00
FooIbar 6a6da6f059 Move sha1 digest calculation to native function (#781)
`kotlinx-io` has removed hash functions API.
2024-02-25 00:15:34 +08:00
GG Bond 4cbb0eca4f launchInVM 2024-02-24 22:29:41 +08:00
GG Bond ebb3eb1ab3 Simplify EhEngine.getPreviewList 2024-02-24 22:29:41 +08:00
GG Bond ebf645acaf Refine naming 2024-02-24 22:29:41 +08:00
GG Bond ec787ebde2 Aggressively fetch in viewModelScope 2024-02-24 22:29:41 +08:00
GG Bond 4f190cb0ef Cleanup GalleryPreviewScreen 2024-02-24 22:29:41 +08:00
GG Bond 2a36868d11 CR for GalleryInfo 2024-02-24 22:29:41 +08:00
GG Bond 176d8be565 Throwable.displayString() 2024-02-24 22:29:41 +08:00
GG Bond 7b581e45e1 CodeReview for LoadStateIndicator 2024-02-24 22:29:41 +08:00
GG Bond 4888e29f79 CodeReview for EhAsyncThumb 2024-02-24 22:29:41 +08:00
GG Bond e5f6d1b1aa CodeReview for EhAsyncThumb 2024-02-24 22:29:41 +08:00
GG Bond d544bbfbeb CodeReview for GalleryPreview 2024-02-24 22:29:41 +08:00
FooIbar ed20d6022b Update liblzma to v5.6.0 2024-02-24 19:26:32 +08:00
FooIbar 4191e2091c Handle invalid UTF-8 characters in response body (#778) 2024-02-24 18:30:40 +08:00
FooIbar 1eeb5a51f6 Introduce DownloadsFilterState (#769)
* Fix default download list not updating on label delete

* Fix unexpected behavior after renaming label
2024-02-24 12:51:11 +08:00
FooIbar dd0776758f Refactor confirm remove download dialog 2024-02-24 01:42:01 +08:00
FooIbar cf3ccf6155 Update snapshot
* Remove obsolete workaround
2024-02-23 22:40:19 +08:00
GG Bond fa6e4acad6 Flatten closure
Signed-off-by: GG Bond <whatever@tagkong.com>
2024-02-23 11:13:58 +08:00
GG Bond db33a72a8e Update snapshot 2024-02-23 11:13:58 +08:00
renovate[bot] 0f8a0549b1 Update dependency com.android.application to v8.4.0-alpha11 2024-02-23 02:02:43 +00:00
renovate[bot] 26ff30af6c Update dependency sh.calvin.reorderable:reorderable to v1.3.2 2024-02-22 01:20:38 +00:00
GG Bond c2fa32f430 Workaround SlotTable modification race 2024-02-21 20:09:36 +08:00
GG Bond 2734de0588 Fix upstream RememberObserver forget order changes 2024-02-21 20:09:36 +08:00
GG Bond aa219e4b71 Fix for compose snapshot 2024-02-21 20:09:36 +08:00
GG Bond 645656b4cd Update compose snapshot 2024-02-21 20:09:36 +08:00
GG Bond ef16bdeb75 Relax GalleryList recomposition 2024-02-21 14:17:37 +08:00
FooIbar 84299b4db7 Workaround for image search (#768)
* Workaround for image search

* Cleanup
2024-02-20 15:22:51 +00:00
FooIbar 953e216dde Implement sort modes and random walk for downloads (#767)
* Implement sort modes and random walk for downloads

* Use `PrefDelegate<T>.asMutableState` instead

BREAKING CHANGE: Upgrade database.
2024-02-20 11:50:37 +00:00
FooIbar c57fd0a923 Reset progress indicator on retry 2024-02-19 17:31:20 +08:00
FooIbar f9cb3d769f Skip H@H on force retry (#762)
* Skip H@H on force retry

* Refine
2024-02-19 08:11:57 +00:00
GG Bond dd62571943 Apply padding for SearchBarScreen Fab 2024-02-19 15:55:41 +08:00
GG Bond 9edd33d88d Apply padding for GalleryCommentsScreen 2024-02-19 15:55:41 +08:00
GG Bond b2fded76d5 Extract a snackBarPadding Modifier 2024-02-19 15:55:41 +08:00
GG Bond 1761493c8e Apply padding to FabLayout 2024-02-19 15:29:33 +08:00
GG Bond 6aa6ee2810 LocalSnackbarFabPadding 2024-02-19 15:29:33 +08:00
GG Bond 84728a1490 Enable context receivers 2024-02-19 15:29:33 +08:00
GG Bond a1568467f0 Cleanup showTip usage 2024-02-19 15:29:33 +08:00
FooIbar 32e2a03c31 Make GalleryInfo.token non-null, upgrade db 2024-02-19 15:24:08 +08:00
GG Bond d4609593e2 Remove showTip usage in GalleryDetailScreen 2024-02-19 12:57:10 +08:00
GG Bond a2af7437c0 Remove showTip usage in GalleryCommentsScreen 2024-02-19 12:57:10 +08:00
FooIbar ab5af22fc3 Re-enable gradle configuration cache 2024-02-18 15:14:35 +08:00
FooIbar 39a159e5ca Optimize CI caching policy 2024-02-18 15:14:35 +08:00
FooIbar ec8a54906c Optimize CI caching policy 2024-02-18 11:59:27 +08:00
FooIbar 73c0ce02ea Separate build tasks to accelerate CI 2024-02-18 08:27:03 +08:00
FooIbar 7d2e0f7f7e Build with Android 15 preview SDK (#749)
* Build with Android 15 preview SDK

* Fix CI

* Don't set application as test-only
2024-02-17 19:05:12 +08:00
FooIbar 7515a049c2 Address cmake warning: "Policy CMP0077 is not set" 2024-02-17 15:03:28 +08:00
GG Bond a317d5303e Enable compiler nonSkippingGroupOptimization 2024-02-17 13:36:07 +08:00
Vladimir DostoyevskiyandGG Bond c4045ded70 Upstream Navigation (#744)
* Official Navigation

* Update snapshot

* Move navigation to snapshot

* Drop dead switch

* Bisect

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-17 12:16:05 +08:00
FooIbar 3cb1b1eee4 Migrate to Corrosion, rust-android-gradle is dead (#742)
* Migrate to Corrosion, rust-android-gradle is dead

This also allows us to enable gradle configuration cache.

* Disable gradle configuration cache
2024-02-17 08:04:28 +08:00
renovate[bot] 5423af46c5 Update dependency org.jetbrains.kotlinx:kotlinx-serialization-json-okio to v1.6.3 2024-02-16 19:03:24 +00:00
FooIbar a2883840e0 Fix thumbnails not updating in grid view (#741)
* Fix 7735237 ("Remember ImageRequest")

* Refine
2024-02-16 11:21:11 +00:00
GG Bond 14810b4c2c Grab some RestrictedApi to make lint happy 2024-02-16 12:25:42 +08:00
GG Bond f5a9a41790 Introduce Result<T>.foldToLoadResult 2024-02-16 12:25:42 +08:00
Vladimir Dostoyevskiy 500d00d214 Update kotlin & compose compiler 2024-02-16 10:00:17 +08:00
Vladimir Dostoyevskiy 49810f8fd1 Update compose snapshot 2024-02-16 09:47:45 +08:00
renovate[bot] 6ad3ab228f Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-android to v1.8.0 2024-02-15 16:36:08 +00:00
renovate[bot] 3a29ce291b Update compose.destinations to v1.10.1 2024-02-15 16:35:33 +00:00
Vladimir DostoyevskiyandGG Bond 1e28a4c7ab Introduce delegateSnapshotUpdate dsl (#735)
* Introduce rememberSnapshotFlowAsState dsl

* Refine naming

* Cleanup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-16 00:11:35 +08:00
FooIbar 645467d20f Implement random walk in search results 2024-02-15 18:20:42 +08:00
Vladimir Dostoyevskiy b2a5fe9f52 Update NDK 2024-02-15 09:23:38 +08:00
Vladimir Dostoyevskiy 2ea3c03360 Update compose snapshot (#731)
* Update compose snapshot

* Update
2024-02-14 04:15:24 +00:00
FooIbar 0c147967d2 Attempt to parse received keyword as URL first 2024-02-13 23:45:30 +08:00
FooIbar de1fab2595 Fix current page in goto dialog on ToplistScreen 2024-02-13 23:11:26 +08:00
FooIbar b86eebf0a7 Refactor Context.decodeBitmap to non-blocking 2024-02-13 22:07:36 +08:00
FooIbar 07345f90e6 Fix exported archive extension on older platform 2024-02-13 02:09:54 +08:00
FooIbar 5fe520e575 Cleanup Log usage and make logging configurable 2024-02-13 00:23:10 +08:00
FooIbar a9dd705ec5 Don't trim gallery detail cache, Resolve #710
It will only free about 1 MB memory
2024-02-12 23:42:01 +08:00
FooIbar e36520faad Replace printStackTrace with proper priority log (#722)
* Replace `printStackTrace` with proper priority log

* Fix
2024-02-12 14:40:45 +00:00
Vladimir DostoyevskiyandGG Bond edaf0a4275 Implement check ripple (#721)
* Implement check ripple

* Fix

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-12 14:21:18 +00:00
GG Bond 7735237ea7 Remember ImageRequest
ImageRequest is not Stable, each recompose will allocate an ImageRequest
2024-02-12 21:21:06 +08:00
FooIbar 7bbc4ea618 Fix failed to generate ComicInfo.xml on API < 33 2024-02-12 21:10:46 +08:00
GG Bond db99392082 Simplify GalleryList state a bit 2024-02-12 19:32:54 +08:00
FooIbar 7bf6a9f545 Add animation for DownloadsScreen grid view switch 2024-02-12 18:54:01 +08:00
FooIbar 51c0efebc4 Support grid view in DownloadsScreen (#714)
* Support grid view in DownloadsScreen

* Fix aspect

* Refine
2024-02-12 09:37:45 +00:00
FooIbar 7ef70aa16e Generate ComicInfo.xml on archive download 2024-02-11 21:01:16 +08:00
FooIbar c5c0c6c4bd Initial support for third-party download manager 2024-02-11 18:43:59 +08:00
GG Bond b26cba8ea9 Update compose snapshot 2024-02-10 22:46:08 +08:00
GG Bond 90b4c16166 Lock drawer on SignInScreen 2024-02-10 15:01:53 +08:00
GG Bond 9b0f6fe433 Lock drawer on all Webview Screen 2024-02-10 15:01:53 +08:00
GG Bond e24735c341 Relax GalleryCommentsScreen recompose 2024-02-10 15:01:53 +08:00
GG Bond 9680ada9ee Lift a Modifier.layout usage 2024-02-10 15:01:53 +08:00
GG Bond 028a7c2352 ListUrlBuilder.asDst 2024-02-10 15:01:53 +08:00
GG Bond 80e5f36c4e Long.asDstWith -> GalleryDetailScreenDestination 2024-02-10 15:01:53 +08:00
GG Bond e0b65184e2 BaseGalleryInfo.asDestination() 2024-02-10 15:01:53 +08:00
GG Bond 395a48ddeb Implement random walk in localFav 2024-02-10 15:01:53 +08:00
GG Bond e22a39f549 Refactor FavouritesScreen state management 2024-02-10 15:01:53 +08:00
renovate[bot] e17d934ebf Update dependency com.squareup.okio:okio-jvm to v3.8.0 2024-02-10 00:28:46 +00:00
FooIbar 10746417b6 Fix crash when visiting newer version galleries
(cherry picked from commit 9be19489a4)
2024-02-09 23:27:27 +08:00
FooIbar 3ef45ba0cc Refactor remaining dialogs to Compose 2024-02-09 14:45:26 +08:00
FooIbar a3e7b6ef43 Refactor select item dialog API to take List<T> 2024-02-08 12:39:04 +08:00
renovate[bot] c444a3b435 Update dependency androidx.compose.material3:material3 to v1.2.0 2024-02-08 00:26:23 +00:00
renovate[bot] 5161802465 Update androidx.navigation to v2.7.7 2024-02-07 21:41:33 +00:00
FooIbar 8c27feec7a Refine exporting downloaded gallery as cbz archive (#698) 2024-02-07 07:17:55 +00:00
FooIbar 37e895cdca Decouple hideHvEvents and requestNews settings (#697)
Visiting gallery page on e-hentai will show HV events as well.
2024-02-06 16:23:25 +00:00
FooIbar e1ad4e3b90 Rename .thumb to thumb.jpg so it can be previewed 2024-02-06 23:18:41 +08:00
FooIbar 5f0be5ae43 Move reading progress to database
In this way cbz archives can be read without SpiderInfo.
2024-02-06 21:33:24 +08:00
Vladimir Dostoyevskiy 9a7cabb221 Update snapshot 2024-02-06 20:33:20 +08:00
renovate[bot] 6acc552058 Update dependency sh.calvin.reorderable:reorderable to v1.3.1 2024-02-06 17:44:30 +08:00
FooIbar b4f4d442eb Ensure images use .jpg extension instead of .jpeg 2024-02-06 16:24:55 +08:00
Vladimir DostoyevskiyandGG Bond 21016dda53 Initial draft support export as cbz (#685)
* Initial draft support export as cbz

* Hint user progress

* Hint user result

* Emit comicInfo as well

* Write ComicInfo if not exist

* Use perFilename

* Print stacktrace

* Fix

* Refine

* Revert "Refine"

This reverts commit 2b368180fde00c7a8cfd4e895f1f2d5c29c3cf9f.

* Refine

* Refine

* Fix

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-02-06 06:44:11 +00:00
Vladimir Dostoyevskiy 576e5b1b58 Revert "Update dependency sh.calvin.reorderable:reorderable to v1.3.0"
This reverts commit 17437a6882.
2024-02-06 14:21:33 +08:00
renovate[bot] 17437a6882 Update dependency sh.calvin.reorderable:reorderable to v1.3.0 2024-02-05 21:49:27 +00:00
FooIbar 04f9f087da Refactor image saving to run on background thread 2024-02-05 07:10:35 +08:00
FooIbar c508947728 Lazily initialize image cache of PageLoader
`OSUtils.totalMemory` needs to read from disk
2024-02-04 23:27:54 +08:00
FooIbar ce1dc55d3c Add support for non-UTF-8 encoded archives (#682) 2024-02-04 22:24:32 +08:00
renovate[bot]andFooIbar e9f615819f Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha04 (#677)
* Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha04

* Revert "Fix delayed application of HTTP engine changes"

This reverts commit c82de0b779.

* Revert "No longer need restart to switch HC"

This reverts commit 7e8b0a58

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-02-03 21:24:59 +08:00
FooIbar 8da3546558 Add back GifDecoder as service loader is disabled 2024-02-03 20:05:56 +08:00
FooIbar d8f8dcffbd Update compose snapshot and remove workaround 2024-02-03 18:14:03 +08:00
FooIbar e79113b19e Lazily initialize image cache on background thread 2024-02-03 18:04:42 +08:00
renovate[bot] 2a7f65a1bd Update dependency gradle to v8.6 2024-02-02 20:27:41 +00:00
FooIbar e322878b95 Don't use app-specific dir as default download dir 2024-02-02 11:01:06 +08:00
FooIbar 11b09f187c Refactor some dialogs to Compose (#675)
* Refactor some dialogs to Compose

* Implement rating bar

* Cleanup
2024-02-01 06:42:39 +00:00
renovate[bot] 926309733c Update dependency io.github.fornewid:material-motion-compose-core to v1.2.0 2024-01-31 05:24:14 +00:00
FooIbar c4b2bcab66 Allow clearing igneous cookie without signing out 2024-01-30 20:16:39 +08:00
FooIbar b88c96894d Prepare to save downloaded gallery as cbz archive 2024-01-30 19:15:40 +08:00
FooIbar 8502671203 Drop CookieSignInScreen and SelectSiteScreen
Cookie-based login is useless due to new e-hentai cookie policy.

Simplify login process a bit since exhentai is preferred.
2024-01-30 10:20:22 +08:00
renovate[bot] 4a7d6f7489 Update dependency io.github.fornewid:material-motion-compose-core to v1.1.2 2024-01-29 20:42:45 +00:00
FooIbar aec34c81aa Make PageCount field optional 2024-01-27 21:22:31 +08:00
FooIbar 1d4fe30e04 Restore download from ComicInfo.xml if available 2024-01-27 20:21:11 +08:00
FooIbar a2cfecd922 Upstream SearchBar Predictive Back support 2024-01-27 20:19:59 +08:00
renovate[bot] d36aef3214 Update actions/upload-artifact action to v4 2024-01-27 09:23:06 +00:00
FooIbar c632231813 Update xz to v5.4.6 2024-01-27 17:00:01 +08:00
FooIbar d8dd68c9b6 Fix sad panda check false positive 2024-01-27 14:19:26 +08:00
FooIbar d6a58d5d34 Generate ComicInfo.xml on download 2024-01-27 13:43:08 +08:00
renovate[bot] 41f8168c28 Update gradle/gradle-build-action action to v3 2024-01-26 21:54:50 +00:00
renovate[bot] 4513ead30a Update compose.destinations to v1.10.0 2024-01-26 05:21:27 +00:00
renovate[bot] f4e23a5738 Update dependency dev.chrisbanes.compose:compose-bom to v2024.01.00-alpha03 2024-01-24 22:00:36 +00:00
FooIbar 79b167002c Use spotless's default ktlint version (#657)
* Use spotless's default ktlint version

* Suppress property naming rule for backing property
2024-01-24 08:32:01 +00:00
FooIbar a9a763ae5f Update Kotlin, KSP and Compose Compiler 2024-01-24 15:43:36 +08:00
FooIbar a5fc29bc66 Fix uploader chip not clickable in thumbnail mode 2024-01-24 14:52:51 +08:00
FooIbar 02c568fd7a Update issue template
[no ci]
2024-01-24 13:33:08 +08:00
renovate[bot] ce55891bc2 Update dependency com.android.application to v8.2.2 2024-01-23 18:58:25 +00:00
renovate[bot] 87b1160c72 Update plugin spotless to v6.25.0 2024-01-23 11:18:25 +00:00
GG Bond ccc6d004de Refactor FilterScreen dialog to Compose, animateItemPlacement 2024-01-23 12:49:12 +08:00
renovate[bot]andFooIbar 20b145bee5 Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha03 (#648)
* Update dependency io.coil-kt.coil3:coil-bom to v3.0.0-alpha03

* Adapt coil3 changes

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2024-01-21 06:11:13 +00:00
renovate[bot] a37cc59a56 Update dependency org.chromium.net:cronet-api to v119 2024-01-17 18:54:41 +00:00
renovate[bot] 7cbffff12c Update compose.destinations to v1.9.62 2024-01-17 17:47:56 +00:00
renovate[bot] 4e5ae53775 Update actions/cache action to v4 2024-01-17 17:43:46 +00:00
renovate[bot] a53de63695 Update compose.destinations to v1.9.61 2024-01-17 14:54:53 +00:00
renovate[bot] 8020c139ec Update dependency io.github.fornewid:material-motion-compose-core to v1.1.1 2024-01-16 20:29:51 +00:00
FooIbar 3c5375a9a6 Prepare for next iteration 2024-01-15 23:41:08 +08:00
FooIbar 1d9008a1a6 Prepare for release 1.10.3 2024-01-15 23:39:56 +08:00
FooIbar fb577dc026 Update compose snapshot and r8 2024-01-15 20:01:11 +08:00
FooIbar 675eb1b7e2 Update compose-bom to v2024.01.00-alpha01 2024-01-15 17:41:46 +08:00
renovate[bot] 6a3d522dfa Update plugin spotless to v6.24.0 2024-01-15 02:54:24 +00:00
renovate[bot] 47aa5c64e7 Update compose.destinations to v1.9.60 2024-01-14 19:25:34 +00:00
FooIbar 5ecf5c41ca Don't use password type keyboard for number input
Some devices will use secure keyboard for password input.
2024-01-14 16:40:50 +08:00
FooIbar bc6d12a873 Fix typo 2024-01-13 18:26:42 +08:00
FooIbar 4d983830df Refine exception translation 2024-01-13 12:27:52 +08:00
FooIbar 2f1e0d030e Revert "Reduce image target size since we are using fill"
This reverts commit c07d9da7

Reason for revert: Coil provides more precise target size control
compared to `ImageDecoder.setTargetSampleSize`.
2024-01-12 15:03:38 +08:00
FooIbar b7c873a172 Minor cleanup 2024-01-12 14:16:38 +08:00
renovate[bot] 9d5eb55290 Update compose.destinations to v1.9.59 2024-01-11 12:08:16 +00:00
renovate[bot] 78ffb1c4fe Update dependency com.google.android.material:material to v1.12.0-alpha03 2024-01-11 00:37:42 +00:00
renovate[bot] 031d622d5d Update androidx.lifecycle to v2.7.0 2024-01-10 19:49:20 +00:00
renovate[bot] 34da120a43 Update compose.destinations to v1.9.58 2024-01-10 19:46:27 +00:00
FooIbar 5285e1ccf2 Update coil to 3.0.0-alpha02 2024-01-10 21:10:40 +08:00
FooIbar e28efc1f50 Fix request news 2024-01-09 22:52:21 +08:00
FooIbar 1c043a81a6 Adapt coil3 changes 2024-01-09 22:09:39 +08:00
Vladimir DostoyevskiyandGG Bond 9a769cc7b6 Rust refactor (#617)
* Introduce deref_direct_bytebuffer

* Cleanup

* Cleanup

* Cleanup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-01-07 17:56:49 +00:00
FooIbar 045c6abe40 Revert "Always enable predictive nav" (#616)
* Revert "Always enable predictive nav"

This reverts commit 0333a8c679.

* Disable predictive nav animations by default
2024-01-07 13:45:28 +00:00
FooIbar 4ad5cef412 Fix unable to move to first page on first attempt 2024-01-07 14:24:31 +08:00
GG Bond c3ffab3c79 Move to official aboutlibraries m3 widget 2024-01-07 13:36:53 +08:00
FooIbar c82de0b779 Fix delayed application of HTTP engine changes 2024-01-07 13:36:41 +08:00
FooIbar 4e36cbabc0 Fix crash on get 509 and mDownloadReference > 1 2024-01-06 23:49:26 +08:00
FooIbar 94f87b14b7 Fix download state not updating 2024-01-06 23:49:26 +08:00
FooIbar 6bc80d1afa [Marshmallow] Archive support 2024-01-06 22:02:00 +08:00
FooIbar fe4d004083 Fix request news 2024-01-06 20:41:30 +08:00
FooIbar 28410befa3 Java 21 2024-01-05 17:36:03 +08:00
Vladimir Dostoyevskiy 515f7deb7e Update compose snapshot 2024-01-04 09:18:07 +08:00
renovate[bot] 800e66261e Update dependency com.android.application to v8.2.1 2024-01-03 19:15:18 +00:00
renovate[bot] 65658c4a02 Update dependency io.github.raamcosta.compose-destinations:core to v1.9.57 2024-01-03 17:09:11 +00:00
FooIbar 0488c7ebf4 Fix restartGalleryProvider being called on start 2024-01-03 22:09:53 +08:00
FooIbar c30c1b29ef Workaround loading images from file uri 2024-01-03 19:49:47 +08:00
GG Bond 876001ad99 Adapt coil3 changes 2024-01-03 19:13:55 +08:00
FooIbar 60dc59adbc Fix concurrent modification 2024-01-03 17:17:19 +08:00
FooIbar c994890f28 Don't retry too many times on the same request 2024-01-03 17:16:10 +08:00
FooIbar 76223a2cd2 Drop fixed workaround 2024-01-03 15:10:37 +08:00
FooIbar 6274b39b68 Kotlin 2.0.0-Beta2 2024-01-03 11:24:26 +08:00
FooIbar cca3a3e350 Lower crop border threshold
Some images have white edges on both left and right.
2024-01-02 21:39:59 +08:00
FooIbar 86ef8f2b48 Ensure cropped images meet minimum width/height 2024-01-02 18:41:53 +08:00
Vladimir DostoyevskiyandGG Bond 5d116d9477 Image wrap a CoilImage (#588)
* Image wrap a CoilImage

* Make ImageSource sealed

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-01-02 07:43:31 +00:00
Vladimir DostoyevskiyandGG Bond 6e73fcc8c9 Cleanup Image decode (#587)
* Move to coil snapshot

* Unify decode with coil

* Unify decode with coil

* Add AnimatedImageDecoderDecoder

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2024-01-02 06:48:15 +00:00
FooIbar 3bd12a3047 Fix typo 2024-01-01 22:40:27 +08:00
FooIbar c99d8e8275 [Marshmallow] Support crop image borders 2024-01-01 20:18:00 +08:00
FooIbar 4a12e71877 Fix crash in comment screen after leaving the app 2024-01-01 17:36:53 +08:00
GG Bond 3043901b5a Resolve #579, Resolve #581 2024-01-01 15:25:49 +08:00
renovate[bot] 7cc28955d6 Update dependency com.mikepenz.aboutlibraries.plugin to v10.10.0 2023-12-31 13:20:37 +00:00
FooIbar ef44bb4857 Prepare for next iteration 2023-12-31 19:50:55 +08:00
FooIbar 37660ef697 Prepare for release 1.10.2 2023-12-31 19:50:11 +08:00
FooIbar 9821b3aaab Fix lint 2023-12-31 18:55:48 +08:00
FooIbar 1f5331af5a Update lint plugin and fix some issues 2023-12-31 18:55:48 +08:00
Vladimir DostoyevskiyandGG Bond 3ea6c82a6d Don't unwind (#574)
* Don't unwind

* Fixes

* Abort in panic

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-31 09:39:29 +00:00
FooIbar ba53d01fa1 Show tip if move favorites failed 2023-12-31 17:29:58 +08:00
FooIbar df8ae8d11a Refine crop border (#573)
* Refresh adapter instead of recreate viewer

* Convert crop broder icons to ImageVector

* Cleanup res
2023-12-31 07:42:01 +00:00
Vladimir DostoyevskiyandGG Bond c817726ab3 Use Cbor (#572)
* Track marshal/unmarshal performance

* Use Cbor

* Refine

* Drop logging

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-31 07:36:42 +00:00
FooIbar 9eb606810f Avoid detecting gallery URL copied from share menu 2023-12-31 14:10:16 +08:00
Vladimir DostoyevskiyandGG Bond fbb030ec8e Drop custom PtrCursor (#569)
* Drop custom PtrCursor

* Drop unused crate

* Fixup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-31 05:51:14 +00:00
FooIbar 28afebefb1 Follow coil 3 API changes (#570)
* Follow coil 3 API changes

* Use coil 3.0.0-alpha01
2023-12-31 05:14:25 +00:00
FooIbar da2610657c Fix typo 2023-12-31 12:37:17 +08:00
Vladimir DostoyevskiyandGG Bond 6e3471ba1b Refactor Rust parser, decouple with JNI for better further KMP support (#568)
* Use serde & kotlinx serialization to marshal jni data

* Introduce unmarshalParsingAs

* Comments

* Introduce parse_marshal_inplace

* Convert parseLimit

* Aha, convert parseGalleryInfoList

* Drop cache_unwind

* Unwind manually

* Fixes

* Drop jnix, update jni

* Data class

* Cleanups

* Cleanups

* Optimize a copy

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-30 20:45:11 +00:00
FooIbar 5a9ab6c4eb Fix snackbar dismiss action color 2023-12-31 01:25:47 +08:00
1fe553d039 Initial crop Border using cpu (#530)
* Initial get crop rect for bitmap

* Adapt for RGBA8888

* Support crop with rect in SubsamplingScaleImageView

* Settings to control crop border

* BottomBar to control crop border

* Fix rgb detect

* Update border.c

* Update Image.kt

* Fix webtoon

* Don't copy if not isAtLeastQ

* Refine

* Avoid too large bitmap

* Fix grey calculation

* Revert "Avoid too large bitmap"

This reverts commit d58dbe12062586ffe4ce4b872aace48b23ad9fde.

* Use matrix to draw bitmap to bypass the size limit

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2023-12-30 13:04:58 +00:00
GG Bond 42e0b0aeab Drop explicitly fabbuilder reallocation, buildFab within snapshotFlow 2023-12-30 11:44:27 +08:00
GG Bond 9e0ea32296 Update snapshot 2023-12-29 23:59:09 +08:00
FooIbar d3f5274b7e Hide comment button in guest mode 2023-12-29 22:37:10 +08:00
FooIbar faff0733e9 Fix unintended spaces in comments 2023-12-29 22:11:47 +08:00
FooIbar 7b32cde7dd Reword current image limits to reduce confusion 2023-12-29 21:14:12 +08:00
FooIbar 648d1d10b3 Always retrieve gallery detail from cache
Serialization & deserialization will create a new copy
2023-12-29 21:10:34 +08:00
Vladimir DostoyevskiyandGG Bond 52727100a0 Use ParcelFileDescriptor.open for RawFile, SAF sucks! (#561)
* Use ParcelFileDescriptor.open for RawFile, SAF sucks!

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-29 20:09:45 +08:00
FooIbar 8a2dbb99f0 Fix comments not showing after commenting 2023-12-29 13:22:36 +08:00
Vladimir DostoyevskiyandGG Bond d880b30ea9 Move to coil NetworkFetcher (#558)
* Move to coil NetworkFetcher

* Fixup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-29 04:15:24 +00:00
renovate[bot] 0e2ca4e150 Update dependency org.jsoup:jsoup to v1.17.2 2023-12-29 03:48:18 +00:00
FooIbar e0eef82ed8 Fix crash when suggestions have the same keyword 2023-12-29 09:51:00 +08:00
FooIbar 09839086a2 Refactor drag reordering 2023-12-29 09:17:46 +08:00
renovate[bot] 3ca3ab7273 Update compose.destinations to v1.9.56 2023-12-28 05:09:40 +00:00
GG Bond 8386bf9c69 Fix regression again 2023-12-28 00:39:06 +08:00
GG Bond 99b8ee1f78 Adjust anim specs 2023-12-28 00:39:06 +08:00
GG Bond 0333a8c679 Always enable predictive nav 2023-12-28 00:39:06 +08:00
GG Bond e0bb09e902 Update compose snapshot, Resolve #413 2023-12-28 00:39:06 +08:00
GG Bond 77677cead3 Fix regression 2023-12-27 22:39:35 +08:00
GG Bond d4b2ff7de9 New nav anim motion 2023-12-27 22:39:35 +08:00
GG Bond b81bae09d1 Update Predictive Back for NavHost, use SeekableTransitionState 2023-12-27 22:39:35 +08:00
Vladimir DostoyevskiyandGG Bond 846e66a56c UniFile Refactors (#546)
* Use DocumentsContractCompat

* Make UniFile.imageSource a extension

* Make UniFile.openFileDescriptor a extension

* Use appCtx

* Use appCtx

* Use appCtx

* Use appCtx

* Drop saveImageToLauncher

* Cleanup

* Use operator resolve

* Simplify

* Fix Toast

* Fixup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-27 08:00:32 +00:00
FooIbar 5cec635e52 Update lock-threads.yml
[no ci]
2023-12-27 15:45:35 +08:00
Vladimir DostoyevskiyandGG Bond 8d0dc88125 Implement lookup cache for UniFile (#545)
* Implement lookup cache for RawFile

* Implement lookup cache for TreeDocumentFile

* Drop unused UriHandler

* UniFile.subFile never return null

* Nonnull UniFile.fromFile

* SingleDocumentFile use appCtx

* TreeDocumentFile use appCtx

* MediaFile use appCtx

* Refine

* Refine

* Refine

* optimize TreeDocumentFile cache

* optimize RawFile cache

* Take care of dir lookup cache cause memleak

* Fixup

* Fixup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-27 04:30:20 +00:00
FooIbar 51b58bb797 Convert MainActivity dialogs to use DialogState (#544)
* Convert MainActivity dialogs to use DialogState

* Always open settings if the button is clicked
2023-12-26 14:58:00 +00:00
Vladimir DostoyevskiyandGG Bond f79aa2350c Refactor UniFile, allow all image format, Resolve #529 (#543)
* Refactor UniFile, allow all image format, Resolve #529

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-26 14:50:28 +00:00
FooIbar 719dddeab9 Fix search bar hint not updating 2023-12-26 21:12:32 +08:00
FooIbar c1522568fd Cleanup legacy code 2023-12-26 20:50:31 +08:00
FooIbar 3ad6b9106b Merge ConfigureActivity into MainActivity 2023-12-26 20:45:22 +08:00
FooIbar 549387ac91 Strip okhttp's public suffix database (#539)
As cookies are handled by ktor now
2023-12-25 20:24:42 +08:00
Vladimir DostoyevskiyandGG Bond 7d2f985ffa Introduce DownloadThumbInterceptor (#538)
* Introduce DownloadThumbInterceptor

* Fixup

* Update DownloadInfoMagics.kt

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-25 09:27:49 +00:00
GG Bond 7e8b0a5800 No longer need restart to switch HC 2023-12-23 15:23:45 +08:00
FooIbar 69252ae8a4 Fix old download label not displayed when renaming 2023-12-22 14:53:45 +08:00
FooIbar eeed56b211 Fix crash when suggestions have the same keyword 2023-12-22 14:44:06 +08:00
renovate[bot] 8aaad071ea Update dependency com.google.devtools.ksp to v2.0.0-Beta2-1.0.16 2023-12-20 00:51:14 +00:00
FooIbar 7ef67e1bf9 Update CHANGELOG.zh-CN.MD
[no ci]
2023-12-19 19:05:16 +08:00
FooIbar 1c15d9a956 Prepare for next iteration 2023-12-19 18:36:49 +08:00
FooIbar 70082090a1 Prepare for release 1.10.1 2023-12-19 18:34:50 +08:00
FooIbar dbc1a32496 Update changelog for 1.10.1 (#526)
[no ci]
2023-12-19 18:34:04 +08:00
FooIbar e8c9ee5dd0 Cleanup obsolete logs 2023-12-19 16:41:33 +08:00
FooIbar 5c3657736b Dump heap on OOM 2023-12-19 16:41:33 +08:00
FooIbar 5191408d06 Provide dismiss action for snackbars with actions 2023-12-19 14:09:33 +08:00
FooIbar 347ce6854d Fix missing content warning cookie in guest mode 2023-12-19 11:17:58 +08:00
FooIbar f86dec9b2e Workaround unable to exit search field on API < 28 2023-12-19 09:46:24 +08:00
FooIbar c74b128b1a Debounce slider value changes 2023-12-19 09:46:13 +08:00
FooIbar 8ee28a4b4f Update history regardless of availability
In case the gallery is taken down by DMCA.
2023-12-18 13:56:01 +08:00
renovate[bot] 3b07b6997d Update dependency com.squareup.okhttp3:okhttp-bom to v5.0.0-alpha.12 2023-12-17 16:15:10 +00:00
FooIbar f59023ed03 Disable some unnecessary logging 2023-12-17 23:05:47 +08:00
FooIbar 3fc13e61c3 Refine download delay 2023-12-17 22:52:04 +08:00
FooIbar ae22f448a8 Revert to use OkHttp as fallback engine
This partially reverts commit 7b67210876

Reason for revert: `setApplicationProtocols` used by Apache 5 HC is not
available until API 29.
2023-12-17 19:12:56 +08:00
renovate[bot] 450c15d51e Update dependency com.squareup.okio:okio-jvm to v3.7.0 2023-12-17 01:17:50 +00:00
FooIbar d9e5bb4399 Fix unreleased lock 2023-12-17 01:03:57 +08:00
FooIbar 369904f659 Don't update page state on force retry 2023-12-16 16:35:49 +08:00
FooIbar 96302b2344 Log before making requests instead of after 2023-12-16 16:26:13 +08:00
FooIbar eeffb12e3b Cleanup code 2023-12-15 15:42:03 +08:00
FooIbar 57c12f7df0 Prepare for next iteration 2023-12-14 22:54:08 +08:00
FooIbar 37eb2f1aed Prepare for release 1.10.0 2023-12-14 22:50:41 +08:00
renovate[bot] c70ec5f354 Update dependency dev.chrisbanes.compose:compose-bom to v2023.12.00-alpha04 2023-12-14 14:42:27 +00:00
FooIbar 7139af4629 Update renovate.json
[no ci]
2023-12-14 22:25:27 +08:00
FooIbar a2bac029f5 Update renovate.json
[no ci]
2023-12-14 22:21:04 +08:00
FooIbar 6c68074e8b Update CHANGELOG.zh-CN.MD (#503)
[no ci]
2023-12-14 22:12:55 +08:00
FooIbar 991caf73f4 Fix ReaderPageSheet padding and ripple 2023-12-14 20:18:40 +08:00
FooIbar 0ba11641fa Update compose compiler 2023-12-14 19:45:32 +08:00
FooIbar b51120e914 Drop deprecated Accompanist libraries (#500)
* Migrate XML themes to Compose

* Vendor Accompanist WebView
2023-12-14 18:04:51 +08:00
GG Bond b02fb2d1d7 PagingSourceFactory capture mutableState only, Resolve #491 2023-12-14 12:46:42 +08:00
renovate[bot] c6247230da Update androidx.navigation to v2.7.6 2023-12-14 04:43:19 +00:00
renovate[bot] d64be78b4e Update dependency androidx.activity:activity-compose to v1.8.2 2023-12-14 04:19:48 +00:00
renovate[bot] e75f633165 Update androidx.lifecycle to v2.7.0-rc02 2023-12-14 04:18:36 +00:00
GG Bond 27c5598133 Fix build 2023-12-14 12:00:02 +08:00
renovate[bot] a9449bfbc7 Update dependency sh.calvin.reorderable:reorderable to v1.2.0 2023-12-13 07:32:39 +00:00
GG Bond 4fecbe259b Update compose snapshot, drop outdated workaround 2023-12-13 11:51:12 +08:00
GG Bond 81d72edbf0 Update compose snapshot 2023-12-12 16:04:32 +08:00
GG Bond ea7e6e4624 Support OutgoingContent.WriteChannelContent in CronetEngine 2023-12-10 21:40:27 +08:00
GG Bond 6335d5bca4 Fix search image 2023-12-10 21:40:27 +08:00
GG Bond 227b430dbb Animate comments update, Resolve #450 2023-12-10 11:36:14 +08:00
GG Bond 0bba56a29f Let GalleryList aware of favSlot update 2023-12-10 11:21:16 +08:00
FooIbar c07d9da7b0 Reduce image target size since we are using fill 2023-12-09 17:04:54 +08:00
Vladimir DostoyevskiyandGG Bond 900c5ed007 Remove unnecessary Image -> Drawable (#484)
* Remove unnecessary Image -> Drawable

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-09 08:11:22 +00:00
Vladimir DostoyevskiyandGG Bond ba0788f6df Move to Coil 3 (#482)
* Move to Coil 3

* Fix R8

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-09 07:37:44 +00:00
Vladimir DostoyevskiyandGG Bond c517856e89 Convert ReaderPageSheet to Compose (#481)
* Convert ReaderPageSheet to Compose

* Cleanup unused

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-09 06:39:46 +00:00
Vladimir DostoyevskiyandGG Bond 791ee0ddbf Drop icon recompose fix (#480)
* Update snapshot and drop unused workaround

* Drop unnecessary fix

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-09 02:27:28 +00:00
Vladimir DostoyevskiyandGG Bond 0746938cb9 Compose bottom reader menu (#479)
* Migrate bottom reader menu to Compose

* Use Compose to animate bottom reader menu bars

* Cleanup unused

* Refine

* Cleanup to use DropdownMenu

* Cleanup unused

* Refine BottomReaderBar layout

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-08 17:23:51 +00:00
FooIbar bbae24aba9 Follow API rate limit to avoid IP ban (#478)
* Follow API rate limit to avoid IP ban

* Delay for bulk favorite adding to prevent flooding

* Revert "Delay for bulk favorite adding to prevent flooding"

This reverts commit 0c175453101aab2d6d200a661259906291ceac36.

* Make requests in parallel
2023-12-08 16:09:40 +00:00
FooIbar 677edb0e02 Make blur radius discrete to reduce overhead (#476)
* Make blur radius discrete to reduce overhead

* Refine
2023-12-08 14:22:51 +00:00
GG Bond a4328c5111 Workaround rating icon 2023-12-08 21:46:06 +08:00
GG Bond 27cf341fef Drop paging runtime 2023-12-08 21:46:06 +08:00
GG Bond bc654e98b8 Drop explicitly coordinatorlayout usage 2023-12-08 21:46:06 +08:00
FooIbar 588f78e598 Fix search bar padding in landscape mode 2023-12-08 16:40:42 +08:00
FooIbar 70f952285a Don't scroll to top on refresh in local favorites 2023-12-08 16:08:55 +08:00
GG Bond a6f5e4f98d Make sure computeIfAbsent inlined 2023-12-08 13:27:01 +08:00
FooIbar 6fe5c1d666 Use commit author name instead of login name
Fix parse error caused by invalid GitHub account
2023-12-08 13:08:31 +08:00
GG Bond 1dba12ec94 Cache VectorPainter for MetaRatingWidget 2023-12-08 12:50:19 +08:00
GG Bond aeb3f689d1 Fix to provide it with setMD3Content 2023-12-08 12:50:19 +08:00
GG Bond 0a2268d4de Allow VectorPainter to be cached 2023-12-08 12:50:19 +08:00
GG Bond 9a32b020cf Let GalleryTags prefer next column not multiple lines 2023-12-08 00:35:20 +08:00
GG Bond c5b01a7089 Update compose snapshot for lazygrid performance 2023-12-08 00:00:28 +08:00
GG Bond 0634fbb724 Optimize to use constant ConstraintSet 2023-12-07 22:48:06 +08:00
FooIbar 445e9511a0 Flatten layout 2023-12-07 20:20:10 +08:00
renovate[bot] ac532acb5b Update Rust crate once_cell to 1.19 2023-12-07 12:03:34 +00:00
FooIbar 7a8e21fbef Keep search bar state across configuration changes 2023-12-07 15:09:59 +08:00
GG Bond 58b0f3a41e Avoid graphicsLayer overhead 2023-12-07 13:24:31 +08:00
GG Bond ab373990cd Following tachiyomi 4146c4c31d069ce9fb7ab36d72f1f8fa2be1e050 2023-12-07 12:48:50 +08:00
GG Bond 272c157fe0 Compose PageIndicatorText, revert 3744018af8 2023-12-07 12:48:50 +08:00
GG Bond e5e047ee10 Move to Compose ReaderContentOverlay 2023-12-07 12:48:50 +08:00
renovate[bot] bf0b529018 Update dependency com.google.android.material:material to v1.12.0-alpha02 2023-12-06 19:19:11 +00:00
FooIbar acf2392406 Avoid progress indicator recomposing in background 2023-12-07 00:05:50 +08:00
FooIbar cecd6fb359 [no ci] Remove deprecated JCenter repository 2023-12-06 13:31:00 +08:00
Vladimir DostoyevskiyandGG Bond 7b67210876 Fallback engine should be Apache5 HC (#456)
* Drop explicitly okhttp dependency

* Move to Apache5 HC instead

* Fix build

* Credit to Ktor instead

* Refactor Cronet Preference

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-06 04:42:17 +00:00
Vladimir DostoyevskiyandGG Bond e40c4f2c71 Save body for ByteBuffer as well (#455)
* Save parseErrorBody for ByteBuffer as well

* Fix

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-05 13:52:08 +00:00
GG Bond b0717b38b1 Cleanup okhttp urlbuilder usage 2023-12-05 18:17:33 +08:00
GG Bond 18c9b95b9b Convert FavListUrlBuilder to use ktor UrlBuilder 2023-12-05 18:17:33 +08:00
GG Bond fc63c41ab0 Cleanup okhttp usage 2023-12-04 20:30:24 +08:00
GG Bond d1c7434993 Drop CloudflareInterceptor to synchronize behaviour 2023-12-04 20:30:24 +08:00
GG Bond da15ba8b9a Always use KtorHttpUriFetcher 2023-12-04 20:30:24 +08:00
GG Bond 1d2a2a3608 Fix to copy to FileChannel directly 2023-12-04 20:30:24 +08:00
renovate[bot] 145cd7a7c0 Update plugin spotless to v6.23.3 2023-12-04 08:06:29 +00:00
FooIbar 048415f3e0 Readd QUIC hints as cronet engine is now preferred 2023-12-04 12:41:39 +08:00
GG Bond 95ccabc756 Fix download origin image 2023-12-04 01:18:25 +08:00
FooIbar 1f08c0e08c Fix ProgressScreen layout 2023-12-04 01:09:49 +08:00
GG Bond b036aeef23 Refine 2023-12-04 00:46:58 +08:00
GG Bond d469a8404c Refine 2023-12-04 00:46:58 +08:00
GG Bond 5b16b6aed9 Hint the scheduler that we are mostly non-blocking 2023-12-04 00:46:58 +08:00
GG Bond 151949aecf Move SpiderDen to use ktor directly
Should have no performance regression, though benchmark is unavailable

Cache should be managed on ktor layer anyway
2023-12-04 00:46:58 +08:00
FooIbar de2c4ca3f5 Move category filters below search bar 2023-12-03 23:03:52 +08:00
FooIbar e5bebcfe80 [no ci] Update renovate.json 2023-12-03 21:50:00 +08:00
FooIbar 0080a482e4 [no ci] Don't update to SNAPSHOTs 2023-12-03 21:48:41 +08:00
FooIbar 756867416b Fix crash on clicking gallery link with page number 2023-12-03 21:43:05 +08:00
FooIbar 124ff2f190 Fix intent emitted before collection being missed 2023-12-03 21:16:16 +08:00
FooIbar 828a3d09b6 Move advanced options below search bar 2023-12-03 19:39:58 +08:00
FooIbar fc3b9d73ec Add language filter for search (#428)
* Add language filter for search

* Refine

* Refine
2023-12-03 06:44:00 +00:00
FooIbar ba943a31d4 [no ci] Update ci.yml 2023-12-03 13:35:29 +08:00
renovate[bot] 8ee1ac7617 Update dependency sh.calvin.reorderable:reorderable to v1.1.0 2023-12-03 05:30:30 +00:00
FooIbar 113f2a1794 Fix NPE (#433)
* Fix NPE

* Enable strict mode in debug environment
2023-12-03 05:14:09 +00:00
GG Bond f6028813e2 Limit CronetEngine to use 1 thread since we are totally async & non-blocking 2023-12-03 11:57:40 +08:00
GG Bond b094a32d12 Convert to use async Channel for reuse of CancellableContinuation 2023-12-03 11:57:40 +08:00
FooIbar fd3e4bdc60 Fix search bar offset on label change 2023-12-02 22:10:06 +08:00
FooIbarandVladimir Dostoyevskiy 142092d930 Add missing inline modifier (#426)
* Add missing inline modifier

* Update EhRequestBuilder.kt

* Update EhRequestBuilder.kt

---------

Co-authored-by: Vladimir Dostoyevskiy <99822064+VDostoyevskiy@users.noreply.github.com>
2023-12-02 12:15:30 +00:00
FooIbar 75e3e78ecb Update history when viewing downloaded galleries 2023-12-02 17:11:16 +08:00
FooIbar 053832681f Add search suggestion item placement animation 2023-12-02 15:54:20 +08:00
Vladimir DostoyevskiyandGG Bond 29e33d6e69 Initial CronetEngine (#421)
* Initial CronetEngine without UploadDataProvider support

* Support ByteArrayContent

* Cleanup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-02 07:50:47 +00:00
FooIbar 2d878e2f1c Migrate to kotlinx datetime [1/2] 2023-12-02 15:34:51 +08:00
Vladimir DostoyevskiyandGG Bond 0fdbfbb1ae Move to Ktor Cookie handle, Part 2 (#419)
* Migration

* Migration

* Migration

* Migration

* Make EhCookieStore a CookiesStorage

* Drop CookieDB migration

* Drop one Okhttp cookie usage

* Drop one Okhttp cookie usage

* Remove typealias

* Move EhTagDatabase to use ktor

* Make cronet just use Dispatchers.IO

* Make all okhttpClient internally used

* Cleanup

* Refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-02 05:42:02 +00:00
Vladimir DostoyevskiyandGG Bond 52f314f6b0 Move to Ktor, Part 1 (#415)
* Ktor 3.0.0-beta-1

* Drop chunker since we no more se okhttp

* Move getGalleryDetail to ktor

* Migration

* Migration

* Migration

* Migration

* Migration

* Migration

* Migration

* Migration

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-02 09:33:46 +08:00
renovate[bot] ff8d8916aa Update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.5.0 2023-12-01 19:02:36 +00:00
FooIbar b2368b312f Prepare for next iteration 2023-12-01 22:41:12 +08:00
FooIbar 3cade906d6 Prepare for release 1.9.0 (#406)
* Prepare for release 1.9.0

* Add known issues

* Bump version

* [no ci] Rename CHANGELOG.MD
2023-12-01 22:35:47 +08:00
FooIbar e7cb33ef6f Fix calling Activity.recreate from IO thread 2023-12-01 22:25:12 +08:00
Vladimir DostoyevskiyandGG Bond 8c331c9577 Fix BottomSheet (#414)
* Fix BottomSheet

* Predictive Back for ModelBottomSheet

* Naming

* Naming

* Naming

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-12-01 22:13:03 +08:00
FooIbar 8560a050ba Make CheckBox/RadioButton text clickable and refine layout (#416)
* Make CheckBox/RadioButton text clickable

* Introduce LabeledCheckbox and refine layout
2023-12-01 13:59:28 +00:00
FooIbar 583637b692 Fix IME not hiding after performing search (#412)
* Fix IME not hiding after performing search

Regression of https://android.googlesource.com/platform/frameworks/support/+/8f81d46e2c3f37564d0b7515ec9411314645e187

* Add comment
2023-12-01 06:31:02 +00:00
FooIbar 791359e949 Fix last item placement animation 2023-12-01 13:30:17 +08:00
FooIbar e238b6aec0 Fix touch slop 2023-12-01 12:27:16 +08:00
renovate[bot] 17a143c4de Update dependency com.android.application to v8.2.0 2023-11-30 19:36:10 +00:00
FooIbar dfb0aa823e Fix crash when deleting downloads 2023-12-01 01:57:18 +08:00
renovate[bot] b5cad36967 Update kotlinx.serialization to v1.6.2 2023-11-30 15:53:13 +00:00
tehcneko 86378630bb Fix searchLayout close icon (#404)
* Fix searchLayout close icon

* Update GalleryListScreen.kt
2023-11-30 12:35:43 +00:00
Vladimir DostoyevskiyandGG Bond 730035aff7 Refine Fablayout (#403)
* Fix read page

* Refine FabLayout

* Let Fablayout have consistent animation state, walk consistently

* Let Fablayout collapse when secondaryFab updated

* Move animation delay out of FabLayout, should not handle that within FabLayout

* Refine predictive back

* Refine predictive back

* Introduce waitCollapse

* Refine

* Simplify

* Simplify

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-30 11:02:58 +00:00
renovate[bot] 64ac770c56 Update dependency dev.chrisbanes.compose:compose-bom to v2023.12.00-alpha03 2023-11-30 09:04:05 +00:00
FooIbar 557a5599e2 Make release build profileable 2023-11-30 16:47:41 +08:00
FooIbar ffd24015ac Update renovate.json
skip-checks: true
2023-11-30 13:19:25 +08:00
renovate[bot] 5eb1f12113 Update dependency androidx.work:work-runtime-ktx to v2.9.0 2023-11-30 04:48:06 +00:00
renovate[bot] 8425fed5a7 Update plugin spotless to v6.23.2 2023-11-30 03:01:33 +00:00
GG Bond 1e34aa4d9a Enable picker mode
Seems fixed by https://github.com/androidx/androidx/commit/4cf31c1a2c2a1f65fcb842490391c8a91fe44a84
2023-11-30 11:01:11 +08:00
GG Bond f383594050 Update snapshot 2023-11-30 11:01:11 +08:00
FooIbar 086db7572d Fix FAB not collapsing with no selected items 2023-11-30 09:28:26 +08:00
FooIbar 082e05584a Fix FAB animation 2023-11-30 09:28:14 +08:00
renovate[bot] fb20f899e2 Update dependency androidx.compose.ui:ui-text-android to v1.6.0-beta02 2023-11-29 22:58:17 +00:00
renovate[bot] c0c07ff2cf Update androidx.room to v2.6.1 2023-11-29 18:15:46 +00:00
renovate[bot] 2f67b741ff Update actions/setup-java action to v4 2023-11-29 16:26:11 +00:00
renovate[bot] 5a96048051 Update dependency gradle to v8.5 2023-11-29 14:58:30 +00:00
FooIbar 5d8b38ecf9 Fix HistoryScreen tip padding 2023-11-29 22:56:38 +08:00
FooIbar 2941ac8285 Add error tip for local favorites 2023-11-29 22:48:55 +08:00
FooIbar 07e316d9a9 Refine DownloadsScreen (#392)
* Fix downloads reorder and delete

* Fix download label edit and delete

* Fix changing download label
2023-11-29 14:15:37 +00:00
GG Bond 5bd9fa3a62 Drop compose viewbinding dependency 2023-11-29 18:25:23 +08:00
GG Bond 0b5da2b2dd Drop explicitly fragment dependency 2023-11-29 18:25:23 +08:00
GG Bond 714a8ccf65 Drop swiperefreshlayout dependency 2023-11-29 18:25:23 +08:00
GG Bond 5c731cc6b2 Drop rv selection dependency 2023-11-29 18:25:23 +08:00
GG Bond eda8115fe5 Revert "Drop fixed workaround"
Revert reason: BTF2 still not fixed
This reverts commit 3c988c63f244f0ec1bf027cc84d49c3e1c404aba.
2023-11-29 18:25:23 +08:00
GG Bond cf0a408b90 Drop fixed workaround 2023-11-29 18:25:23 +08:00
GG Bond f9786377a5 Update compose snapshot, new PullToRefreshContainer style 2023-11-29 18:25:23 +08:00
renovate[bot] 93f234b16d Update dependency com.google.devtools.ksp to v2.0.0-Beta1-1.0.15 2023-11-29 03:39:16 +00:00
GG Bond afb986937b Defer searchBarOffsetY read to minimize recompose scope 2023-11-29 11:38:54 +08:00
Vladimir DostoyevskiyandGG Bond 61fecaffe1 Workaround Infinity recompose (#387)
* Workaround Infinity recompose

* Observe all Snapshot apply that may trigger recompose when debug mode

* Continue to fix things up

* Fix things up

* Fix things up

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-28 17:03:37 +00:00
FooIbar 6f87afc1bf Fix navigation drawer padding 2023-11-28 23:35:43 +08:00
FooIbar 2e5950a1a8 Disable haptic feedback if ticks are too dense 2023-11-28 18:01:44 +08:00
FooIbar 4bf0c4ecec Minimize unnecessary network requests 2023-11-28 17:41:45 +08:00
FooIbar 3a8dbcdb32 Disallow empty gallery list result
It has to be a parse error
2023-11-28 16:10:22 +08:00
GG Bond 1f3546f3cc Fix remove fav 2023-11-28 15:12:17 +08:00
GG Bond f864d65d98 Don't collect If isInFavScene 2023-11-28 15:12:17 +08:00
GG Bond 3479498c6c optimize detailScreen state collect 2023-11-28 14:53:26 +08:00
GG Bond ac319330be Reduce allocation 2023-11-28 14:53:26 +08:00
GG Bond 9b3595e45f Reduce allocation 2023-11-28 14:53:26 +08:00
GG Bond d855858543 Refactor DownloadManager NotifyFlow 2023-11-28 14:53:26 +08:00
GG Bond ada52f1687 Reduce allocation 2023-11-28 13:42:59 +08:00
GG Bond ef68374f52 Reduce allocation on anim path 2023-11-28 13:42:59 +08:00
Vladimir DostoyevskiyandGG Bond 0bf8049021 Reduce allocation for getCategoryColor (#379)
* Reduce allocation for getCategoryColor

* refine

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-28 05:09:12 +00:00
GG Bond 3cff3f837a Reduce allocation in NavDrawer 2023-11-28 12:25:22 +08:00
GG Bond ca94a63762 Drop unused SimpleRatingView 2023-11-28 12:25:22 +08:00
GG Bond 81b8bc9029 Fixup 2023-11-28 12:25:22 +08:00
GG Bond 9d38520b85 Rename to *Screen 2023-11-28 12:25:22 +08:00
FooIbar 800e09adad Use relative links in READMEs 2023-11-28 11:40:30 +08:00
FooIbar 30d6c11220 Move showDatePicker to CommonOperations.kt 2023-11-28 01:36:55 +08:00
FooIbar e465356df8 Use large heap on API < 26 2023-11-28 00:52:18 +08:00
FooIbar ff8e1b7d28 Fix downloads and favorites selection 2023-11-27 23:34:01 +08:00
GG Bond 175e1d7df9 Convert TimePicker to use a dialogState 2023-11-27 23:05:00 +08:00
FooIbar 271c1b1390 Fix downloads filter and search 2023-11-27 23:02:24 +08:00
GG Bond a128356fc4 Cleanup unused 2023-11-27 22:33:16 +08:00
FooIbar 2ed957b5f2 Compose DatePicker 2023-11-27 22:12:01 +08:00
FooIbar 85bb9b9f97 Fix crash when TextField with focus is scaled to 0 2023-11-27 21:18:03 +08:00
GG Bond 050b5c0451 Kill EditTextDialogBuilder 2023-11-27 21:10:41 +08:00
GG Bond a14df3fc0c Fix bigicon tint in nightmode 2023-11-27 21:01:17 +08:00
GG Bond 939136476e Fix tip 2023-11-27 20:19:59 +08:00
GG Bond 7e2af653ee Cleanup unused 2023-11-27 20:19:59 +08:00
GG Bond d357a55307 Cleanup unused 2023-11-27 20:19:59 +08:00
GG Bond 23509ac2c9 Fix activity transition style 2023-11-27 20:19:59 +08:00
FooIbar 118a4f75c0 Fix crash info collector 2023-11-27 19:56:47 +08:00
renovate[bot] 2b8a7fafe6 Update plugin spotless to v6.23.0 2023-11-27 08:09:14 +00:00
Vladimir DostoyevskiyandGG Bond 10eda7e5f3 Introduce LockDrawerHandle (#360)
* Introduce LockDrawerHandle

* refine

* Ensure SearchBar PredictiveBackHandler is latest when enabled

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-27 08:08:54 +00:00
FooIbar c23cadec8a Cleanup snackbar usage
`SnackbarDuration.Short` is already longer than `Snackbar.LENGTH_LONG`
2023-11-27 15:16:11 +08:00
FooIbar 0114081a2b Fix search bar scroll-away offset 2023-11-27 14:14:59 +08:00
GG Bond 2611601fb9 Optional Predictive NavAnim 2023-11-27 13:56:36 +08:00
FooIbar 4194087f0b Fix GalleryInfoBottomSheet content padding 2023-11-27 13:27:42 +08:00
renovate[bot] 673adc41ba Update dependency org.jsoup:jsoup to v1.17.1 2023-11-27 03:09:59 +00:00
FooIbar b195ae25a8 Fix LazyList items jumping during scroll
https://issuetracker.google.com/issues/312025159
2023-11-27 02:19:22 +08:00
GG Bond 556c49fbfd Check meteredNetworkWaring 2023-11-27 00:37:19 +08:00
GG Bond 358a5249a4 Cleanup 2023-11-27 00:37:19 +08:00
GG Bond d5b837e6af CheckClipboard within Composables 2023-11-27 00:37:19 +08:00
GG Bond 61100d0c83 Upgrade lifecycle for new compose utils 2023-11-27 00:37:19 +08:00
GG Bond 8473ca9fff Observe Intent within Composables 2023-11-27 00:37:19 +08:00
FooIbar 37a2227c5c Fix OOB in DownloadsScreen 2023-11-27 00:16:05 +08:00
Vladimir DostoyevskiyandGG Bond d6a4ab7471 CompositionLocal Sheet State (#351)
* CompositionLocal Sheet State

* Fix typo

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-26 15:43:30 +00:00
GG Bond 6291288c42 Lowering default navAnim duration to 500ms 2023-11-26 23:25:22 +08:00
Vladimir DostoyevskiyandGG Bond 6c926419e9 Compose Era!!! (#346)
* Initial Kill Fragment!

* Cleanup

* Cleanup

* Convert to use Compose ModalBottomSheet

* Ignore insets

* Navigate

* Fixes

* Cleanup

* Fix navToWebview

* Fix navToWebview

* showtip

* Refine

* Fixes

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-26 15:02:03 +00:00
FooIbar f292f31ac1 Refine DownloadsScreen icons (#349)
* Convert big download icon to ImageVector

* Tweak download label icons
2023-11-26 14:54:29 +00:00
FooIbar 86a49f764e Add haptic feedback for drag and drop in Downloads 2023-11-26 22:32:04 +08:00
FooIbar 5dad21f4ea Fix download label drag and drop 2023-11-26 21:57:21 +08:00
FooIbar a4e9291bf9 Implement LoadStateIndicator 2023-11-26 21:08:18 +08:00
Vladimir DostoyevskiyandGG Bond 2a667e62f4 Compose DownloadScreen (#343)
* Initial Compose DownloadScreen

* Cleanup namespace

* Reorderable

* Reorderable

* Fixes

* Fix layout

* Fixes

* State labelList

* Fixes

* SwipeToDismiss

* RenameLabel

* Rewrite renameLabel to notify

* Fix name shadow

* Fixes

* Fixes

* SelectMode

* Drop unused

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-26 20:12:01 +08:00
FooIbar 6bd8063976 Replace thumb size setting with thumb column count 2023-11-26 15:09:43 +08:00
FooIbar 0aba5907b0 Fix title overflow 2023-11-26 01:05:57 +08:00
FooIbar 32182a7791 Fix keyword and title not updating 2023-11-26 01:05:57 +08:00
Vladimir DostoyevskiyandGG Bond 198960f93c Compose DownloadCard (#339)
* Cleanup res

* Compose DownloadCard

* Refine

* Fix CI

* Fixes

* Fix recompose

* Fix textStyle

* Fixes

* Fixes

* Restore design specs and clean up

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-25 16:46:07 +00:00
FooIbar 618f14a732 Reset search bar offset on loading 2023-11-26 00:09:44 +08:00
FooIbar fec2c39364 Extract common part of GalleryList and Favorites (#338)
* Extract common part of GalleryList and Favorites

* Scroll to top after refreshing
2023-11-25 15:15:28 +00:00
FooIbar dd06d82cd9 Refine side sheet layout 2023-11-25 16:38:30 +08:00
GG Bond 4c98ee5350 Refine CheckBox dialog design 2023-11-25 15:53:36 +08:00
GG Bond 2800a7bc15 Kill CheckBoxDialogBuilder 2023-11-25 15:53:36 +08:00
FooIbar 04818e5afb Fix IME won't pop up after dismissing dialog (#334)
* Fix IME won't pop up after dismissing dialog

* Add keep rule for reflection
2023-11-25 14:17:21 +08:00
Vladimir DostoyevskiyandGG Bond 122089eb1e Predictive Back for NavHost (#335)
* Grab navigation-compose

* Initial SeekableTransitions

* Refine

* Fixes

* Fix anim again

* Easeout Predictive Back

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
2023-11-25 14:11:00 +08:00
GG Bond b991e5d70a Cleanup ActionBuilder 2023-11-24 22:21:03 +08:00
GG Bond 0d00ae207a Drawer blurs behind 2023-11-24 21:51:22 +08:00
GG Bond 9e451c18d9 Simplify GalleryInfoListItem placeholder 2023-11-24 21:32:36 +08:00
GG Bond 71ebd99115 Stateful listThumbSize 2023-11-24 21:22:08 +08:00
GG Bond 116dbead4b Stateful thumbSizeDp 2023-11-24 21:22:08 +08:00
FooIbar ef8adb00f4 Fix invisible FAB being clickable 2023-11-24 20:47:20 +08:00
FooIbar 7d74781f96 Collect debug info when dumping logs 2023-11-24 20:17:12 +08:00
Vladimir Dostoyevskiyandskymkmk b7627dc576 Fix GalleryList to use FastScrollLazyVerticalGrid when listMode (#324)
* Fix GalleryList to use FastScrollLazyVerticalGrid when listMode

* Fix recompose

* Initial PrefDelegate -> State<T>, MutableState<T>

* Migrate

* Optimize

---------

Co-authored-by: skymkmk <whatever@tagkong.com>
2023-11-24 10:44:38 +00:00
FooIbar cf42acd65c Lock side drawer as well 2023-11-24 18:31:34 +08:00
skymkmk 4163c895df Tweak SearchTab Design 2023-11-24 17:44:06 +08:00
FooIbar 63ddd5ea89 Fix side sheet padding 2023-11-24 17:17:33 +08:00
FooIbar 216dfded4b Fix downloads FAB animation 2023-11-24 16:50:29 +08:00
FooIbar 08b5eac6bd Restore history item delete animation 2023-11-24 16:14:53 +08:00
FooIbar 6e541be6ca Restore quick search item drag and drop animation 2023-11-24 15:48:47 +08:00
FooIbar 17a9c02f96 [Marshmallow] Fix OOM when decoding images 2023-11-24 13:22:23 +08:00
Vladimir Dostoyevskiyandskymkmk ed640ab00e Enhanced swipe-edge-oriented PredictiveBack (#317)
* Enhanced swipe-edge-oriented PredictiveBack

Following MDC NavigationDrawer design specs

* Cleanups

---------

Co-authored-by: skymkmk <whatever@tagkong.com>
2023-11-23 18:01:58 +00:00
skymkmk d69df5f7ab PredictiveBack for ModalNavigationDrawer, SideDrawer 2023-11-24 00:47:36 +08:00
FooIbar 6f6461e855 Fix disowned gallery uploader parsing 2023-11-24 00:06:59 +08:00
skymkmk 682d959688 All Easing for animateFloatMergePredictiveBackAsState 2023-11-23 23:31:02 +08:00
skymkmk 179686de16 Reimplement animateFloatMergePredictiveBackAsState 2023-11-23 23:31:02 +08:00
FooIbar 32e35622bd Kotlin 2.0.0-Beta1 (#312)
* Kotlin 2.0.0-Beta1

* Cleanup
2023-11-23 14:21:43 +00:00
c9c06202bb Compose GalleryListScene (#301)
* Initial Migrate

* Cleanup

* Search

* Refine

* Initial searchLayout

* Cleanup

* Margins

* Animated State

* Animated State

* Fixes

* ShowSearchFab

* Refine

* Log

* Refine naming

* Update

* Scroll to hide FAB

* Cleanups

* Initial side sheet

* Refine side sheet

* Refine layout

* Refine transition

* Refine padding

* Refine ProvideSideSheetContent to handle multiple screen on composition

* Let sidesheet container padding vec insets

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
Co-authored-by: skymkmk <admin@skymkmk.com>
2023-11-23 14:14:02 +00:00
FooIbar 42d17621f9 Fix advanced search not working 2023-11-23 21:42:55 +08:00
renovate[bot] 629044c241 Update dependency dev.chrisbanes.compose:compose-bom to v2023.12.00-alpha02 2023-11-23 12:48:58 +00:00
FooIbar 9be19489a4 Fix crash when visiting newer version galleries 2023-11-23 20:48:32 +08:00
FooIbar cde4f9e405 Fix refresh state 2023-11-23 20:48:21 +08:00
FooIbar 16fddcb377 Refine 2023-11-23 20:48:21 +08:00
FooIbar 35cff4647a Fix favorites refresh 2023-11-23 20:48:21 +08:00
renovate[bot] 80ad749fc2 Update compose.destinations to v1.9.55 2023-11-21 14:00:36 +00:00
FooIbar 1a1d444b20 Restore common actions in comment field 2023-11-21 22:00:18 +08:00
FooIbar bb2d500067 Refine FavouritesScreen layout 2023-11-21 21:53:44 +08:00
FooIbar c3c7e88c15 Fix pull request builds being pushed to users 2023-11-21 17:17:07 +08:00
FooIbar 8dc3b1f376 Restore secondary FAB fade 2023-11-21 16:53:49 +08:00
Lokesh Gidra b49a80bb35 Cleanup unused res 2023-11-20 21:45:40 +08:00
Lokesh Gidra 21bfd4dd2d Cleanup unused res 2023-11-20 21:45:40 +08:00
Lokesh Gidra 3551ed7c7a Refine ActionBuilder dsl 2023-11-20 21:45:40 +08:00
FooIbar 5f8ab98e9e Tweak settings transition animations 2023-11-20 17:48:56 +08:00
FooIbar 8c6b2f5366 Fix side sheet padding 2023-11-20 16:10:57 +08:00
Vladimir DostoyevskiyandLokesh Gidra bac60fbec8 Compose FavouriteScreen (#295)
* Restore FavouriteScene SideSheet dragToOpen

* Initial move to Compose FavScene

* Refine state

* Refine state

* Introduce ProvideSideSheetContent with extra checkers

* Make sideSheet activity private

* Dont allow provide a null AssistContent

* Restore trailingIcon to openSideSheet

* Refine

* Cleanup

* Implement searchBarConnection

* Reduce allocation for animation

* Initial compose FabLayout API

* Restore showGoToDialog

* Refine

* Refine

* Refine

* PullTORefresh

* PullTORefresh

* Refine Dsl

* Insetless placeholder

* let pullToRefresh use insetless padding as well

* Support drawer gestures

* Fix tip color and ripple

* Make pullToRefresh optional

* Composite container color

* Fix padding

* Fix misadd

* Fix gesture

* Fixes

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-20 07:09:35 +00:00
FooIbar 4eed03ebed Add configuration for lock bot 2023-11-20 11:37:38 +08:00
Lokesh Gidra e33295d0a6 Don't allow RecyclerView intercept ACTION_CANCEL TouchEvent as well 2023-11-19 16:22:21 +08:00
Vladimir DostoyevskiyandLokesh Gidra 07a495c499 Reimplement ModalNavigationDrawer to allow HistoryScreen gesture (#293)
* Reimplement ModalNavigationDrawer to allow HistoryScreen gesture

* Fix RTL, fix gesture disabled

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-19 07:53:54 +00:00
e69eba6023 Compose FabLayout (#290)
* ComposeFabLayout with Predictive Back

* Refine

* Fix padding

* Fix anim

* Fix scrim

* Cleanup

* Convert FavoritesScene to use ComposeFabLayout

* Convert DownloadsScene to use ComposeFabLayout

* Cleanup unused code

* Rename ComposeFabLayout to FabLayout

* Refine

* Refine

* Intercept MotionEvent.ACTION_CANCEL for rv have SelectionTracker attached

* Revert to old icons

* Revert FAB orders

* Cleanup resources

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
2023-11-19 09:21:52 +08:00
Lokesh Gidra 8be6ad84fc Get rid of IntList, LongList 2023-11-17 23:54:19 +08:00
Lokesh Gidra 59e46aeeea Navigate with GalleryDetailScreenArgs directly 2023-11-17 23:54:19 +08:00
renovate[bot] 4404531171 Update dependency com.android.application to v8.1.4 2023-11-16 19:51:03 +00:00
FooIbar 99db84fdd0 Cleanup code 2023-11-17 00:10:44 +08:00
FooIbar aa50b69754 Add rotate inertia for favSelectDialog 2023-11-16 23:15:02 +08:00
FooIbar fa2933df7c Workaround for BTF2 cursor not showing 2023-11-16 23:07:29 +08:00
FooIbar c51a26b9b7 Close drawer before navigating to another activity
Fix crash caused by activity recreate when it's invisible
2023-11-16 19:00:58 +08:00
FooIbar 9859a1eaac Fix amoled dark mode 2023-11-16 19:00:43 +08:00
Lokesh Gidra cd3858ace8 Rotatable fav select dialog 2023-11-16 14:27:51 +08:00
FooIbar 0c54e8b0b3 Allow setting search bar title 2023-11-16 12:47:33 +08:00
Lokesh Gidra e32a7b61b6 Workaround IME won't show again once hidden 2023-11-16 11:58:23 +08:00
FooIbar ea2977268b Follow upstream API changes 2023-11-16 11:21:20 +08:00
Vladimir Dostoyevskiy 6b529bcb18 Upgrade compose bom (#277)
* Upgrade compose bom

* Update settings.gradle.kts
2023-11-16 02:32:14 +00:00
FooIbar 941e7d18f3 Implement pull to refresh in GalleryCommentsScreen (#272)
* Use AndroidX snapshot builds

* Implement pull to refresh in GalleryCommentsScreen

* Don't use snapshot builds for other libraries
2023-11-16 09:34:29 +08:00
FooIbar d0fe9fac8c Fix crash when applying style to comment 2023-11-16 09:33:58 +08:00
FooIbar 8f37c5ba25 Fix favButton text not updating in gallery detail 2023-11-16 09:33:24 +08:00
renovate[bot] b63b36e6d2 Update dependency androidx.browser:browser to v1.7.0 2023-11-15 21:52:38 +00:00
renovate[bot] 081357cbb4 Update dependency androidx.activity:activity-compose to v1.8.1 2023-11-15 18:15:44 +00:00
renovate[bot] 0f7aa5f9ea Update kotlinx.serialization to v1.6.1 2023-11-15 16:07:25 +00:00
Lokesh Gidra a565b428e8 Apply blur to Compose Dialog 2023-11-15 21:05:45 +08:00
FooIbar 71f4df6f05 Fix download dialog checkbox ripple 2023-11-15 20:41:56 +08:00
FooIbar 5da2f91e6a Fix comment EditText height 2023-11-15 20:32:52 +08:00
FooIbar a6e9867596 Clear previous comment if it was in edit mode 2023-11-15 20:32:52 +08:00
FooIbar 9e1cff014d Minor cleanup 2023-11-15 20:32:52 +08:00
Lokesh Gidra 9c06f10d43 Drop explicitly androidx collection dependency
Since compose runtime depends 1.4.0a1 now
2023-11-15 20:11:56 +08:00
Lokesh Gidra 3f11df1dc6 Cleanup unused 2023-11-15 20:11:56 +08:00
Lokesh Gidra 6dd4505cec Convert download dialog to coroutine dialog 2023-11-15 20:11:56 +08:00
Lokesh Gidra 8faabd7759 Cleanup unused res 2023-11-15 19:03:40 +08:00
FooIbar 288e56d7e0 Fix search bar width 2023-11-15 15:23:15 +08:00
Vladimir DostoyevskiyandLokesh Gidra 7bcddb5f51 Initial limited support for BBCode editor (#260)
* Initial support edit

* Override LocalTextToolbar to reimpl BBCode editor: groundwork

* Impl

* Hacky

* Keep spans when editing

* Fix bold

* Fixes

* Initial AnnoStr to BBCode

* Implement edit with annotatedString

* Cleanup

* Cleanup

* Hack

* Some necessary comment

* Make url span a noop now

* Cleanup

* Cleanup

* Fix annotatedStr concat

* Fix toBBCode

* Clear focus as well

* Support Overlapped SpanStyle to BBCode

* Refine

* Cleanup code

* Fix algo

* Fix conflict

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-15 13:03:18 +08:00
FooIbar 7b0bd309e4 Fix light splash screen in dark theme on API >= 31 2023-11-15 01:19:53 +08:00
FooIbar 237938b1f0 Check temporary IP ban and refine error translation (#262)
* Check temporary IP ban and refine error translation

* Fix lint
2023-11-14 10:27:45 +00:00
FooIbar 07009f8bd6 Expose searchFieldState as workaround
Until we migrate GalleryListScene to compose
2023-11-14 16:09:23 +08:00
FooIbar f7ef768c8f Set default filter mode 2023-11-14 00:37:15 +08:00
FooIbar d1c3c9a37a Refine modifyFavorites 2023-11-13 18:23:58 +08:00
Lokesh Gidra 78f15860e0 Check sadpanda in cronet path 2023-11-13 18:23:58 +08:00
Lokesh Gidra 6b11773da9 ModifyFavoritesRange concurrently
Order?
2023-11-13 18:23:58 +08:00
Lokesh Gidra ed26cb8f35 Move modifyFavorites to use cronet 2023-11-13 18:23:58 +08:00
Lokesh Gidra 337f27dc38 Convert ghRequest to use stdlib Base64 impl 2023-11-13 18:23:58 +08:00
FooIbar 97fab45877 Avoid unnecessary overhead 2023-11-13 16:49:01 +08:00
FooIbar 8e8749ed6e Fix crash when initial composition hasn't been performed 2023-11-13 15:04:02 +08:00
Lokesh Gidra a0e999576e Fix comment textfield cursor color 2023-11-13 12:07:44 +08:00
Lokesh Gidra b29802c260 Keep GalleryDetail comments in sync 2023-11-13 11:32:24 +08:00
Lokesh Gidra 665e5a3d39 Immutable GalleryComment 2023-11-13 11:32:24 +08:00
Lokesh Gidra c2a2dafb47 Resolve #251 2023-11-13 11:32:24 +08:00
Lokesh Gidra 1d12a16e3d Resolve #250 2023-11-13 11:32:24 +08:00
Vladimir DostoyevskiyandLokesh Gidra f3fe5f0a75 Support cronetRequest with body (#248)
* Initial Add RequestBody support for cronetRequest

* Convert modifyFavorites to use cronet

* Code refactor

* Avoid some unnecessary copy

* Suppress NewApi for all managed usage

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-12 15:45:02 +00:00
Vladimir DostoyevskiyandLokesh Gidra 3bad1d06f4 Migrate more to cronet directly (#247)
* Convert GalleryListParser to parse a DirectByteBuffer

* Convert FavoritesParser to parse a DirectByteBuffer

* Limit buffer size

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-12 19:29:31 +08:00
FooIbar 70f2bfb760 Fix fab animation 2023-11-12 16:06:36 +08:00
Lokesh Gidra 9e86d42972 Predictive Back for Compose SearchBar
https://android-review.googlesource.com/c/platform/frameworks/support/+/2721593
2023-11-12 15:41:41 +08:00
FooIbar c8ade4d750 Fix recyclerview item disappearing 2023-11-12 01:39:16 +08:00
FooIbar 11b7bbd7ef Fix search bar text missing 2023-11-11 23:51:48 +08:00
Lokesh Gidra 513bce51ea Avoid unnecessary recompose in ReaderProgressIndicator 2023-11-11 22:57:04 +08:00
FooIbar f2c8c5d66d Mitigate OOM for API < 26 2023-11-11 22:44:55 +08:00
4e08f4f962 Compose Searchbar (#237)
* Migrate to Compose SearchBar

* Fix searchbar padding

* Fix content padding

* Implement scroll away behaviour

* Reset searchBarOffsetY when expand

* Fix multiple listener

* Fix cursor position

* Fix spotless

---------

Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-11 13:03:11 +00:00
FooIbar a9bd55dff5 Restore fab rotation when showing and hiding (#235)
* Restore fab rotation when showing and hiding

* Make it rotate in the same direction
2023-11-10 12:29:01 +00:00
FooIbar 5cec825dbe Clean up duplicate imports 2023-11-10 18:05:20 +08:00
FooIbar 14c5b28cdc Refactor visibility animation for FabLayout 2023-11-10 16:41:42 +08:00
nullArrayListandLokesh Gidra 7693b11e0a Fix wrong SideSheetDialog usage (#231)
* Fix wrong SideSheetDialog usage

* Do not assume fragmentView first composition earlier than drawerView's

Use MainActivity composition instead

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-10 05:47:14 +00:00
FooIbar f9cb49e4d3 Only show commit subjects in changelog 2023-11-10 02:14:56 +08:00
Lokesh Gidra 892a614246 Drop overloadaggressively
https://r8.googlesource.com/r8/+/04d49b152b624a437db46e17410bb1cb1e4dd809
2023-11-09 22:34:31 +08:00
FooIbar 4a482d996e Reduce category min width for small screen devices
Tested-on: 4.65" 720x1280
2023-11-09 20:19:41 +08:00
Lokesh Gidra af9baa8ce4 Convert to use enableEdgeToEdge 2023-11-09 19:39:48 +08:00
Lokesh Gidra 39a11525a9 Rename EMPTY_GALLERY_COMMENT_LIST 2023-11-09 18:20:00 +08:00
Lokesh Gidra 2337dda4eb Remove EMPTY_GALLERY_TAG_GROUP_ARRAY
There is no reason to keep it
emptyList() always return a singleton
2023-11-09 18:20:00 +08:00
Lokesh Gidra c0a610a02b Remove GalleryApiInfo
No user now
2023-11-09 18:20:00 +08:00
Lokesh Gidra 85f7b54719 Convert GalleryComment to data class
Generate equals method for compose
2023-11-09 18:20:00 +08:00
Lokesh Gidra e0aea2fedf Convert GalleryTagGroup to data class
Generate equals method for compose
2023-11-09 18:20:00 +08:00
Lokesh Gidra ee83dbb877 Convert GalleryDetail to data class
Generate equals method for compose
2023-11-09 18:20:00 +08:00
Lokesh Gidra 1de4bc11eb Keep primary constructor only 2023-11-09 18:20:00 +08:00
FooIbar 04a7656afa Fix gallery detail refresh 2023-11-09 16:36:14 +08:00
nullArrayListandLokesh Gidra 77ec7e76e9 Refactor out animateFloatMergePredictiveBackAsState (#221)
* Refactor out animateFloatMergePredictiveBackAsState

* Revert EditTextHeight to 80dp

* Fix

* Fix animation when content too long

* Fix double navbar padding

* Fix lazycolumn jumpping

* Fix padding

* Fix padding again

* Refine

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-09 05:24:42 +00:00
FooIbar 9ca7be081a Built-in proguard rules are obsolete, use our own
Fix regression of #216
2023-11-09 10:30:27 +08:00
FooIbar fb36346f0b Fix variable shadowing (regression of #218) 2023-11-09 09:35:46 +08:00
FooIbar 95679f3fb9 Append skip H@H key to original image url on retry
Since original images may be served by H@H now
2023-11-09 01:04:49 +08:00
nullArrayListandLokesh Gidra addd4124c1 Initial Predictive back animation support for commentFragment Edittext (#217)
* Initial Predictive back animation support for commentFragment Edittext

* Fix

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-08 14:47:24 +00:00
FooIbar 74b79d9faa Use built-in proguard rules and @Keep annotation
`-keepattributes LineNumberTable,SourceFile` is not needed since R8 v8.2
APK size is increased by 1.7% though
2023-11-08 22:45:24 +08:00
nullArrayListandLokesh Gidra 9daa05ef02 Enable Predictive Back (#214)
* Enable Predictive Back

Tested with UP1A.231005.007, no bugs

* Fix Wrong SDK behaviour

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-08 19:06:41 +08:00
FooIbar 5ee884e0a2 Update thanks and Traditional Chinese README (#213)
* Update thanks and Traditional Chinese README

* Credit to Compose Destinations
2023-11-08 10:12:33 +00:00
FooIbar dba7f4e6c0 Fix inconsistent refresh state
Don't save it as `onRestoreInstanceState` will be called after loading
state has settled
2023-11-08 16:55:30 +08:00
FooIbar 8221514805 Update README.md 2023-11-08 16:54:00 +08:00
FooIbar 2ae3effc0e Move updates check to MainActivity 2023-11-08 16:09:45 +08:00
Lokesh Gidra 5b450ff18f Fix not filter all comments 2023-11-08 12:33:26 +08:00
Lokesh Gidra 92be6e9340 Explicitly reallocate lambda by key, fix download not work due to composer skip local fun reallocation 2023-11-08 12:33:26 +08:00
Lokesh Gidra 8884aeec11 Fix filter comment 2023-11-08 12:33:26 +08:00
Lokesh Gidra 8e15eda4e3 Fix navigate on IO thread crash 2023-11-08 12:33:26 +08:00
Lokesh Gidra 0dbf220655 Enable some compose compiler optimization 2023-11-08 12:33:26 +08:00
renovate[bot] fe69d59ef1 Update dependency com.android.application to v8.1.3 2023-11-07 23:30:33 +00:00
renovate[bot] 1e1f8350b5 Update dependency androidx.compose.compiler:compiler to v1.5.4 2023-11-07 19:07:38 +00:00
FooIbar afa2d03b56 Fix local favorites list jumping (#206)
* Revert "Fix local favorites scroll state loss"

This reverts commit c4be269f

* Enable placeholders as workaround

* Remove TODO

* Bump minimum fast scroller handler height to 48 dp

Make it consistent with `VerticalFastScroller`
2023-11-07 14:56:46 +00:00
FooIbar 1293d7fe28 Fix history not updated 2023-11-07 18:22:31 +08:00
renovate[bot] 62e879f2de Update dependency io.ktor:ktor-io-jvm to v2.3.6 2023-11-07 09:13:33 +00:00
Lokesh Gidra a771994f6f Introduce ActionBuilder 2023-11-07 17:13:15 +08:00
Lokesh Gidra 8c2ba051a0 Various cleanup for GalleryDetailScene 2023-11-07 17:13:15 +08:00
FooIbar ae2f289122 Make TorrentResult immutable and do some cleanup 2023-11-07 16:35:05 +08:00
nullArrayListandLokesh Gidra 703d63d106 Fragmentless GalleryDetailScene (#202)
* Initial fragmentless port

* Compile it

* Refine

* Refine

* All

* Fix

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-07 15:39:59 +08:00
FooIbar 2d7b024293 Fix unused resources inspection not working in AS (#200)
* Fix unused resources inspection not working in AS

* Remove unused resources

* Update CI

* Fix CI

* Add baseline for lint

* Test CI
2023-11-06 22:18:56 +08:00
Lokesh Gidra 26906f6709 Fix GalleryDetailScene comment ellipsize 2023-11-06 18:29:48 +08:00
Lokesh Gidra e9ec97403f Fix with missing ComposeWithMD3 2023-11-06 18:29:48 +08:00
Lokesh Gidra 34fb72707b Drop BaseToolbarScene since no user now 2023-11-06 18:29:48 +08:00
Lokesh Gidra fb7eb64c3a Drop unused xml layout 2023-11-06 18:29:48 +08:00
Lokesh Gidra ef65720999 Drop leakcanary since we will totally migrate to compose 2023-11-06 18:29:48 +08:00
Lokesh Gidra 3bc71d6798 Fix comment display limits 2023-11-06 18:29:48 +08:00
FooIbar c4be269fb7 Fix local favorites scroll state loss 2023-11-06 16:18:25 +08:00
nullArrayListandLokesh Gidra 1238edfe2b Compose GalleryCommentsScreen (#187)
* Initial Stub Compose GalleryCommentsScreen

* Initial Fab and edittext

* Refine comment edittext

* Support load more comments

* Animated loading state

* Refine, cleanup migrated things

* Initial comment dialog

* Refine

* Introduce buildAction dsl

* Impl voteComment

* Refine and cleanup migrated things

* Impl check vote status

* Refine

* Refine

* Padding a ime

* Support send commnet

* Cleanup all the code

* Let edittext and sendButton padding a navbar

* Let LazyColumn padding a ime

* Let LazyColumn contentPadding a edittext and fab

* Handle unresolved span with onCardClick

* Modify how LinkifyTextView works

* Adjust padding

* Adjust comment textstyle

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-06 03:19:59 +00:00
FooIbar 747fd23b96 Add experimental option to tweak swipe sensitivity 2023-11-05 10:57:20 +08:00
FooIbar 022f7a3ef1 Fix crash when clicking retry button in favorites 2023-11-04 23:59:40 +08:00
FooIbar e0cad8600c Fix crash caused by drawer state deserialization 2023-11-04 18:50:52 +08:00
renovate[bot] 9510ebbc31 Update dependency com.mikepenz.aboutlibraries.plugin to v10.9.2 2023-11-04 09:31:51 +00:00
FooIbar b63f2fd393 Limit request concurrency 2023-11-04 15:32:08 +08:00
FooIbar 95a0e9f03b Cleanup crash info collector 2023-11-04 14:25:01 +08:00
renovate[bot] 8265dd7f02 Update dependency com.google.devtools.ksp to v1.9.20-1.0.14 2023-11-03 03:58:14 +00:00
FooIbar 67feb19cab Fix unable to open drawer after double clicked 2023-11-03 00:46:10 +08:00
FooIbar 614e847de0 Fix incorrect favorite states in search results 2023-11-02 23:29:41 +08:00
renovate[bot] c2ff4b6a0b Update dependency com.android.tools:desugar_jdk_libs_nio to v2.0.4 2023-11-02 10:08:47 +00:00
FooIbar b273f1039c [Reader] Hide slider ticks if they are too dense 2023-11-02 18:08:31 +08:00
Lokesh Gidra bea0c6a1f0 Simplify with Fragment.ComposeWithMD3 2023-11-02 16:46:35 +08:00
Lokesh Gidra dcfaa361ec Extract a fragmentless ProgressScreen
ProgressScene.KEY_ACTION is always ProgressScene.ACTION_GALLERY_TOKEN, thus remove it
2023-11-02 16:03:03 +08:00
Lokesh Gidra 9904e166d2 Extract a fragmentless HistoryScreen 2023-11-02 15:13:52 +08:00
Lokesh Gidra 5f02769012 Extract a fragmentless GalleryPreviewScreen 2023-11-02 13:42:21 +08:00
nullArrayListandLokesh Gidra 19e5636dd2 Migrate ConfigureActivity to compose-destinations (#178)
* Add compose-destinations lib, prepare to drop fragment

* Move ConfigureActivity to compose destinations

* Restore navAnims

---------

Co-authored-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-02 11:40:13 +08:00
renovate[bot] 9a220f89d9 Update androidx.navigation to v2.7.5 2023-11-01 18:01:33 +00:00
FooIbar 1c76ec813c Fix crash when clicking download notification 2023-11-02 02:01:16 +08:00
FooIbar d36c189430 Update xz to v5.4.5 2023-11-01 23:29:48 +08:00
FooIbar 61e2ace5c8 Fix insets on API < 29 2023-11-01 23:17:46 +08:00
Lokesh Gidra d6a3f21754 Fix a weird NPE 2023-11-01 22:12:07 +08:00
Lokesh Gidra 4e54d7f66f Refine FavouriteStatusRouter observable stateFlow 2023-11-01 22:12:07 +08:00
Lokesh Gidra f2dff038cd Global, CompositionLocal DialogState
Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-01 19:37:22 +08:00
Lokesh Gidra a7b30640e0 Drop DrawerView
Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
2023-11-01 19:37:22 +08:00
FooIbar 45048b1f46 [Marshmallow] Fix crash when saving images 2023-11-01 16:26:06 +08:00
FooIbar 498129314a Refine storage permission request 2023-11-01 15:42:55 +08:00
Officer 3ee4b4a61e Cleanup ReaderActivity & Fix activity not finish when no archive passwd available 2023-11-01 15:41:23 +08:00
FooIbar ee59c0f22e Convert ReaderActivity dialog to use a DialogState 2023-11-01 12:30:36 +08:00
FooIbar c56134cd92 Fix API results parsing error on certain galleries 2023-11-01 12:17:48 +08:00
renovate[bot] b3d1b66a06 Update dependency com.google.devtools.ksp to v1.9.20-1.0.13 2023-11-01 03:49:48 +00:00
renovate[bot] c9bb81bf63 Update kotlin to v1.9.20 2023-11-01 02:41:28 +00:00
FooIbar d176810dae Update compose compiler for kotlin 1.9.20 2023-11-01 10:38:36 +08:00
FooIbar 17bdca71b1 Reduce drawer and history item gesture sensitivity 2023-11-01 09:50:25 +08:00
FooIbar 22fd3730df Sync with upstream changes and cleanup code 2023-11-01 02:37:34 +08:00
FooIbar 23d1271949 Prepare for next iteration 2023-10-31 13:30:29 +08:00
FooIbar bf6aa3e8ae Release 1.8.11.0 2023-10-31 12:49:53 +08:00
FooIbar 75fcfde892 Always enable gestures if drawer is open 2023-10-31 11:58:13 +08:00
FooIbar 89be27995e Fix #154 regression (#158)
* Revert "Fix crash when deleting filters"

This reverts commit 717d3717ba.

* Revert "Update dependency dev.chrisbanes.compose:compose-bom to v2023.11.00-alpha02"

This reverts commit 38c18149

Reason for revert: https://issuetracker.google.com/issues/295745063#comment57
2023-10-31 03:45:25 +00:00
FooIbar 6738dc6cdc Partially enable drawer gestures for now 2023-10-31 11:34:14 +08:00
renovate[bot] 9ff0decb98 Update dependency io.coil-kt:coil-bom to v2.5.0 2023-10-30 23:02:14 +00:00
FooIbar 717d3717ba Fix crash when deleting filters 2023-10-31 03:25:25 +08:00
FooIbar fdbca869a8 Allow hiding comments below custom threshold 2023-10-31 00:44:32 +08:00
Astesia aafa750ca3 change runnable to coroutine job, and fix fragment compose memory leak (#152) 2023-10-30 22:39:29 +08:00
Astesia afe2bac672 Fix fragment compose view memory leak (#151)
* fix fragment compose view memory leak

* chang wildcard import
2023-10-30 20:07:37 +08:00
FooIbar b6f5d72db5 Fix NPE when evicting cache but Image was recycled
But why was it recycled?
2023-10-30 18:00:37 +08:00
FooIbar f0021a7601 Fix tag filters not working in thumbnail mode 2023-10-30 17:22:31 +08:00
FooIbar ea5bfbb346 Fix ViewModel memory leak 2023-10-30 12:32:11 +08:00
FooIbar 38fbcf4457 Update issue template 2023-10-30 00:48:24 +08:00
FooIbar 7c43e8f349 Avoid uncaught exceptions crashing entire app 2023-10-30 00:30:01 +08:00
FooIbar 93df4e3dd9 Revert "Scroll to top after refreshing" (#139)
* Revert "Fix progress not showing after clicking error tip"

This reverts commit bc914566dd.

* Revert "Try to fix recyclerview disappearing after refresh (#61)"

This reverts commit f9a3c3d266.

* Revert "Scroll to top after refreshing"

This reverts commit b0896ea465.
2023-10-29 14:44:42 +00:00
fricyo f7d45a52a7 Fix a strange word 2023-10-29 21:01:21 +08:00
FooIbar 328f96d115 Fix GalleryPreviewScreen insets 2023-10-29 20:57:01 +08:00
fricyo 22338a72d8 Complete the missing translations (#131)
* Complete the missing translations

* Remove the duplicate

* Update ""settings_eh_force_eh_thumb_summary""
2023-10-29 17:18:03 +08:00
FooIbar 256dedcb7c Add note for forceEhThumb 2023-10-29 16:36:49 +08:00
FooIbar 95d2438b84 Fix state recalculation after recompose 2023-10-29 16:19:59 +08:00
FooIbar f8d27e165e Update UI state on main thread and fix weight 2023-10-29 16:19:59 +08:00
FooIbar e2f024ae29 Fix reader not loading under certain circumstances (#128)
* Revert "Fix reader bug on certain orientation settings"

This reverts commit 6e59583dea.

* Revert "Skip `buildProvider` if the activity will restart"

This reverts commit a880f801fb.

* Preserve gallery provider in view model
2023-10-29 03:24:24 +08:00
FooIbar 9c28fbeaf8 Allow custom user agent string 2023-10-28 22:34:00 +08:00
FooIbar 6458eb090a Add missing color filter modes 2023-10-28 20:39:16 +08:00
FooIbar f1ca2b6958 Add animations for category chips 2023-10-28 19:34:32 +08:00
FooIbar 60f031e7e3 Fix crash when navController is not initialized 2023-10-28 13:43:32 +08:00
FooIbar e6a44ee0e1 Clarify system requirement for Marshmallow flavor 2023-10-28 02:49:27 +08:00
FooIbar 7a3a641a07 Fix crash when copying cookies 2023-10-28 02:10:13 +08:00
FooIbar 1021efb239 Fix NPE caused by coroutine cancellation 2023-10-27 23:35:23 +08:00
FooIbar edbe6509e1 Remember last viewed toplist 2023-10-27 20:37:20 +08:00
FooIbar 44a6253bfc Sync with upstream API changes 2023-10-27 19:40:41 +08:00
FooIbar 3d6e5df71e Leave 56 dp minimum edge gap for navigation drawer 2023-10-27 13:09:11 +08:00
FooIbar 2733d2e58c Convert more icons to ImageVector 2023-10-27 11:43:47 +08:00
FooIbar 0c78673870 Fix unexpected touch scale behavior in PageViewer 2023-10-27 03:11:00 +08:00
FooIbar d618948429 Set min width and max items in each row (#99)
* Set category chip to fixed width

* Set min width and max items in each row
2023-10-26 17:54:56 +00:00
FooIbar 7584704d22 Avoid race condition when updating tag database
`updateInternal` and `issueUpdateInMemoryData` will try to create tag
database directory at the same time on first launch and one of them will
fail, causing app crash
2023-10-27 00:10:59 +08:00
FooIbar 4a4658cc54 Dispatch and apply system bars insets separately 2023-10-26 22:43:43 +08:00
FooIbar e9875f1a24 Use lazy initialization instead 2023-10-26 21:01:01 +08:00
FooIbar cc11257d80 Suppress lint 2023-10-26 20:17:28 +08:00
FooIbar 4fd64601ef Use ImageVector icons 2023-10-26 19:45:29 +08:00
FooIbar 7eea490adf Drop RikkaX 2023-10-26 19:29:57 +08:00
FooIbar b2b12f7b93 Migrate from RikkaX Insets to Insetter 2023-10-26 13:22:23 +08:00
renovate[bot] 66d026cffa Update kotlin to v1.9.20-RC2 2023-10-26 04:12:31 +00:00
FooIbar 5a15a20dd6 Update compose compiler for kotlin 1.9.20-RC2 2023-10-26 12:09:43 +08:00
renovate[bot] 70450a9725 Update dependency com.google.devtools.ksp to v1.9.20-RC2-1.0.13 2023-10-26 00:43:46 +00:00
FooIbar 470a3c6a09 Move search fab to GalleryListScene 2023-10-26 00:03:04 +08:00
FooIbar 15f8b2f15d Cleanup code 2023-10-26 00:02:20 +08:00
FooIbar 717cbe7630 Request recomposition after view gets created 2023-10-25 23:51:09 +08:00
FooIbar d34075d29d Apply ime padding to suggestion list 2023-10-25 23:51:09 +08:00
FooIbar 80d4d66fb5 Dispatch insets from compose to android view 2023-10-25 23:51:09 +08:00
FooIbar 6b20b46761 Revert "Set bar style correctly"
This reverts 216a043094.

Reason for revert: Incorrect status bar color when app's night mode
setting is different from system's
2023-10-25 21:29:26 +08:00
FooIbar cd764a4a3c Fix spotless 2023-10-25 18:29:44 +08:00
FooIbar 5422b3d8bd Disable edge to edge temporarily 2023-10-25 17:42:32 +08:00
FooIbar 0273390d79 Flatten layout 2023-10-25 15:36:30 +08:00
FooIbar 8f7242b939 Bring search fab in front of search layout 2023-10-25 15:26:43 +08:00
FooIbar 246dee63b4 Move Context.findActivity to separated file 2023-10-25 13:24:28 +08:00
FooIbar 697918a73a Move navItems to top level 2023-10-25 13:11:21 +08:00
FooIbar 67e480220e Refine navigation drawer 2023-10-25 12:58:44 +08:00
FooIbar 5784eb008e Migrate navigation drawer to compose (#80)
* Drop AboveSnackerLayout

* Migrate navigation drawer to compose

* Suspend until logged in before loading

* Use AndroidViewBinding

* fixup! Migrate navigation drawer to compose

* Cleanup AboveSnackView usage

* Cleanup res

* Cleanup dependencies
2023-10-25 01:53:44 +08:00
FooIbar 82d66c4d57 Prepare for next iteration 2023-10-25 01:53:13 +08:00
FooIbar ab8671cc3b Revert "Exclude some libraries from aboutLibraries"
This reverts commit bc34f25a3c.

Reason for revert: Licenses should be included as per Apache 2.0
2023-10-24 23:53:25 +08:00
FooIbar 2e52dda208 Downgrade AGP to stable version but use newer lint (#81)
* Downgrade AGP to stable version but use newer lint

* Downgrade Java to 17 and use newer r8
2023-10-24 13:08:23 +00:00
renovate[bot] 1ab08d0ae1 Update Rust crate quick-xml to 0.31 2023-10-23 20:22:16 +00:00
FooIbar 702be0ed43 Use eh API as well if forceEhThumb is enabled 2023-10-23 22:37:55 +08:00
FooIbar 4067543701 Cleanup code 2023-10-23 16:03:01 +08:00
FooIbar 074689c60e Fall back if failed to retrieve data from API 2023-10-23 15:10:18 +08:00
FooIbar 2beb715df3 Cleanup code 2023-10-23 14:36:28 +08:00
FooIbar 7ea2597899 Fix large torrent list parsing 2023-10-23 02:25:17 +08:00
FooIbar 34a8f92865 Show meaningful error message if it's available 2023-10-23 02:25:17 +08:00
FooIbar 6e2a2de13f Reformat imports alphabetically
https://developer.android.com/kotlin/style-guide#import_statements
2023-10-22 22:13:45 +08:00
FooIbar e073232352 Fix cronet support detection 2023-10-22 17:52:16 +08:00
FooIbar 6f49b4d23e Fix deprecated 2023-10-21 18:22:45 +08:00
FooIbar 97cad20ab1 It's affected by AGP and NDK versions as well 2023-10-21 17:38:29 +08:00
FooIbar 9300a3d9ce Don't write cmake cache every time 2023-10-21 16:26:14 +08:00
FooIbar 28b7f80a8f Fix content behind navigation bar 2023-10-21 16:13:27 +08:00
FooIbar a06d23753a Lock navi drawer on where doesn't have navi icon 2023-10-21 13:10:46 +08:00
FooIbar 98d66b3e6c Release 1.8.10.1 2023-10-21 00:14:03 +08:00
FooIbar 6e59583dea Fix reader bug on certain orientation settings
Resolve #68
2023-10-21 00:12:52 +08:00
FooIbar 2f0571e384 Implement splash screen 2023-10-20 17:36:59 +08:00
renovate[bot] 64a6074e02 Update dependency org.jsoup:jsoup to v1.16.2 2023-10-20 06:11:31 +00:00
renovate[bot] 0b7cb4cf41 Update dependency com.android.application to v8.3.0-alpha09 2023-10-20 01:48:36 +00:00
renovate[bot] e620832e33 Update dependency com.google.android.material:material to v1.11.0-beta01 2023-10-19 23:03:41 +00:00
renovate[bot] f82e4af0e3 Update dependency com.android.application to v8.3.0-alpha08 2023-10-19 20:36:34 +00:00
FooIbar 02baa793f8 Release 1.8.10.0 2023-10-19 21:31:08 +08:00
FooIbar 9311a9e7f9 Implement download timeout 2023-10-19 21:15:55 +08:00
renovate[bot] 00a60ad6ab Update actions/checkout digest to b4ffde6 2023-10-19 11:51:36 +00:00
FooIbar e740c25211 Implement LoadStateAdapter for append/prepend load 2023-10-19 19:51:19 +08:00
FooIbar 79c6b63c56 Refactor image download and improve retry strategy 2023-10-19 14:50:22 +08:00
FooIbar bc914566dd Fix progress not showing after clicking error tip 2023-10-19 14:50:22 +08:00
FooIbar 2c6ccfb23d Enable showGalleryPages by default 2023-10-19 14:50:22 +08:00
FooIbar 646767e712 Add back cronet option for debugging 2023-10-19 14:50:22 +08:00
FooIbar 754b14d349 Simplify Java toolchain configuration 2023-10-19 14:50:22 +08:00
renovate[bot] 38c18149aa Update dependency dev.chrisbanes.compose:compose-bom to v2023.11.00-alpha02 2023-10-19 00:42:42 +00:00
renovate[bot] 35b448a274 Update dependency androidx.recyclerview:recyclerview to v1.3.2 2023-10-18 22:25:52 +00:00
renovate[bot] c1e63b5a5d Update androidx.room to v2.6.0 2023-10-18 18:31:20 +00:00
FooIbar 37f984829a Update docs to explain flavors (#64)
* Update README.md

* Update zh-cn.md
2023-10-18 09:45:33 +00:00
FooIbar 65942021d0 Kotlin 1.9.20-RC and Java 21 2023-10-18 02:06:09 +08:00
FooIbar ecef20d52b Use stable version of ktlint since 1.0.1 is out 2023-10-18 00:31:19 +08:00
FooIbar 1a092bb200 Fix total pages not updating for new archives 2023-10-18 00:22:37 +08:00
FooIbar a880f801fb Skip buildProvider if the activity will restart 2023-10-18 00:22:37 +08:00
FooIbar f00360e81c Fix stable channel update check 2023-10-18 00:06:10 +08:00
FooIbar 1737163364 Use product flavors for OSS and GMS variants (#62)
* Use product flavors for OSS and GMS variants

* Move code to kotlin directory

* Temporarily disable lint

* Fix CI

* Fix release

* Tweak release asset names
2023-10-17 10:11:59 +00:00
FooIbar f9a3c3d266 Try to fix recyclerview disappearing after refresh (#61)
* Try to fix recyclerview disappearing after refresh

* Another attempt

* Workaround: Use RefreshLayout's progress indicator
2023-10-17 04:49:20 +00:00
FooIbar 7db04e4359 Fix unable to show content in cutout area 2023-10-16 00:28:24 +08:00
FooIbar 934629d829 Add lint check for marshmallow (#58)
* Add lint check for marshmallow

* Treat some warnings as errors

* Fix attribute unused on older versions
2023-10-15 09:16:50 +00:00
FooIbar cd65bb057d Fix inlined constants on older versions 2023-10-15 15:45:00 +08:00
FooIbar f2d94f1ed6 Use product flavors to provide marshmallow support (#57)
* Use product flavors to provide marshmallow support

Fix crashing when opening archives

* Fix artifacts upload

* Change artifact names

* Fix app updater
2023-10-14 19:14:19 +00:00
FooIbar e29281ce39 Generate and upload native debug symbols 2023-10-15 01:09:44 +08:00
FooIbar 1e719a8738 Use local variable instead 2023-10-15 00:05:43 +08:00
FooIbar 92926487b6 Check if the image is GIF before doing mmap 2023-10-14 21:30:10 +08:00
FooIbar 69f744131a Use custom decoder factory instead
`ImageDecoderDecoder.Factory` is only applicable for animated images.
2023-10-14 19:59:17 +08:00
FooIbar 83cd9bdd00 Revert "Remove coil-gif library"
This reverts commit 1130f4f114.
2023-10-14 19:59:17 +08:00
FooIbar 1130f4f114 Remove coil-gif library
We only use coil for thumbnails, which are all static, and
`ImageDecoderDecoder` is only applicable for animated images.
2023-10-14 15:25:33 +08:00
FooIbar d99d9008dd Do not modify the original file when rewriting GIF
Make it a decode-time thing.
2023-10-14 15:25:33 +08:00
FooIbar 78f61b2396 Tweak the error message of getting a blank page 2023-10-14 14:48:47 +08:00
FooIbar 32829bbf15 Implement image subsampling on API < 28 2023-10-13 15:36:28 +08:00
FooIbar a2d3046070 Fix unable to hide hentaiverse notification
Resolve #51
2023-10-13 00:10:29 +08:00
FooIbar 95641e398a Refactor download delay to mitigate request flood 2023-10-12 22:30:53 +08:00
FooIbar 97c39d07e8 Update e-hentai / exhentai API URLs 2023-10-12 21:16:10 +08:00
FooIbar 14fa2fab71 Remove GIF support on API < 28 2023-10-12 19:29:57 +08:00
FooIbar ef8c31ae52 Upgrade ndk to 26.1.10909125
Fix ndk-stack
2023-10-12 15:04:29 +08:00
FooIbar 353080867a Build x86_64 apk for emulator 2023-10-12 14:29:39 +08:00
FooIbar 4d09b895d4 Refactor areContentsTheSame to compare entire objects 2023-10-11 01:08:46 +08:00
FooIbar 6c00d66334 Cleanup sad panda check 2023-10-10 22:43:35 +08:00
FooIbar 77de187207 Refine GalleryPageApiParser exception handling 2023-10-10 22:38:35 +08:00
FooIbar 79eec13856 Wrap exceptions thrown by native methods 2023-10-10 21:59:37 +08:00
FooIbar 562c6fa9a4 Fix tag database download on API < 24 2023-10-10 19:06:58 +08:00
FooIbar 9fa3ddd254 Downgrade minSdk to 23 (#48)
* Revert "Drop webp icon since minSdk is 28"

This reverts commit 9f77a4ce0a.

* Upgrade AGP and use K2 lint

* Enable core library desugaring and minSdk 23

* Fix some new API usage

* Add fallback image decoder for API < 28
2023-10-08 10:04:40 +00:00
FooIbar d11a0b9b8a Move AGP version to version section 2023-10-06 23:15:47 +08:00
FooIbar 41cf3fbe89 Cleanup version catalog 2023-10-06 15:54:43 +08:00
FooIbar ac12ab93e5 Add compose compiler to version catalog for renovate 2023-10-06 15:02:20 +08:00
FooIbar 8b4e978cf4 Migrate to version catalog 2023-10-06 14:39:47 +08:00
FooIbar c15f22400e Migrate to auto-mirrored icons 2023-10-05 23:36:07 +08:00
FooIbar 1773116313 Fix spotless not working 2023-10-05 23:23:39 +08:00
renovate[bot] 62424fbad1 Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0-alpha13 2023-10-05 11:39:49 +00:00
renovate[bot] d07bd1aa29 Update ktor to v2.3.5 2023-10-05 10:25:27 +00:00
FooIbar 8433df09e3 Update compose-bom to v2023.11.00-alpha01 2023-10-05 15:11:35 +08:00
FooIbar 0634898cb6 Update gradle wrapper 2023-10-05 15:11:01 +08:00
renovate[bot] 2ebafc3eeb Update dependency gradle to v8.4 2023-10-05 05:59:33 +00:00
FooIbar 8288559e44 Drop GIF workaround on API 34 and above
https://android.googlesource.com/platform/frameworks/base/+/2be87bb707e2c6d75f668c4aff6697b85fbf5b15
2023-10-05 13:30:33 +08:00
renovate[bot] 2caf3f0174 Update navigation to v2.7.4 2023-10-05 04:36:23 +00:00
renovate[bot] e88e48906d Update dependency androidx.fragment:fragment-ktx to v1.7.0-alpha06 2023-10-05 00:53:42 +00:00
renovate[bot] 8fb5153983 Update dependency androidx.collection:collection-ktx to v1.3.0 2023-10-04 23:43:31 +00:00
renovate[bot] 03725b0ab4 Update dependency androidx.activity:activity-compose to v1.8.0 2023-10-04 19:07:04 +00:00
FooIbar b0896ea465 Scroll to top after refreshing 2023-10-04 21:24:28 +08:00
FooIbar 654e9a79c5 Don't append when all results were filtered out 2023-10-04 21:04:20 +08:00
FooIbar 7f541e2623 Fix side sheet not showing after swiped off 2023-10-04 15:43:26 +08:00
FooIbar 198e905050 Change block uploader icon 2023-10-03 22:42:31 +08:00
FooIbar 3744018af8 Revert "Move PageIndicatorText to Compose"
This reverts commit 7c987ec8
2023-10-03 18:41:16 +08:00
FooIbar a21ba04e95 Initialize Settings as early as possible 2023-10-02 19:50:13 +08:00
FooIbar bf4d39421b Cleanup code 2023-10-02 16:29:04 +08:00
renovate[bot] 2e4935715f Update dependency com.squareup.okio:okio-jvm to v3.6.0 2023-10-02 03:15:22 +00:00
FooIbar cf8ce9642a Make changelog scrollable 2023-10-02 00:02:48 +08:00
FooIbar cac65d9030 Fix insets for pre API 30 2023-09-30 23:19:52 +08:00
FooIbar 4a83829dfd Fix padding for scrollable 2023-09-30 23:19:52 +08:00
FooIbar c0348484fe Fix padding for the IME 2023-09-30 23:19:52 +08:00
FooIbar 213133ab45 Fix SignInScreen drawing behind the system bars 2023-09-30 23:19:52 +08:00
renovate[bot] 8469eac18c Update plugin com.diffplug.spotless to v6.22.0 (#33)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-29 07:35:40 +00:00
FooIbar 5aaa1bb5b3 Fix spotless 2023-09-29 15:20:43 +08:00
renovate[bot] 9f500b85e6 Update plugin com.android.application to v8.1.2 2023-09-28 18:40:08 +00:00
FooIbar 0d6fd8d7ad Workaround for SideSheetDialog (#31) 2023-09-27 14:05:21 +00:00
FooIbar 7e4b6dbf31 Fix memory leak 2023-09-27 19:47:57 +08:00
renovate[bot] 8bf3f0f094 Update plugin com.mikepenz.aboutlibraries.plugin to v10.9.1 2023-09-27 01:41:01 +00:00
renovate[bot] 198acef666 Update dependency com.mikepenz:aboutlibraries-core to v10.9.1 2023-09-26 21:03:06 +00:00
FooIbar 1d0c76b2b2 Fix OOB access when no results found 2023-09-26 19:26:32 +08:00
FooIbar 567875cf00 Apply quick search in place if not in Popular (#30) 2023-09-26 08:50:07 +00:00
FooIbar 58069e8925 Fix cmake cache for CI 2023-09-26 01:35:37 +08:00
FooIbar a90cf3c72b Update issue template 2023-09-26 01:28:01 +08:00
FooIbar 2fbf226ccd Update author summary in about 2023-09-26 01:23:11 +08:00
FooIbar d674672ce2 Update libarchive to v3.7.2 2023-09-26 00:28:54 +08:00
FooIbar dab7968ce3 Update liblzma to v5.4.4 2023-09-26 00:28:54 +08:00
FooIbar 510719f890 Convert libnettle build to FetchContent 2023-09-26 00:27:48 +08:00
renovate[bot] 96b92239b0 Update plugin com.mikepenz.aboutlibraries.plugin to v10.9.1-debug01 2023-09-25 08:06:51 +00:00
FooIbar 363029cbdd Upgrade r8 (#27) 2023-09-24 15:55:51 +00:00
FooIbar 7783a8de15 Cleanup build cache for CI 2023-09-24 17:52:06 +08:00
FooIbar 26a589fc1d 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
2023-09-24 08:10:17 +00:00
FooIbar 4c467c304f NDK will be installed automatically 2023-09-24 03:17:12 +08:00
FooIbar 9496b9396a Upgrade ndk to 26.0.10792818 (#24) 2023-09-23 18:52:46 +00:00
FooIbar 669a9ee1e3 Use spotless for ktlint integration 2023-09-24 02:12:39 +08:00
FooIbar d08b7c2d94 Update README 2023-09-23 22:32:54 +08:00
FooIbar 534f6aa22c Merge pull request workflow to CI 2023-09-23 19:13:43 +08:00
FooIbar 8ea731159f Prevent unnecessary regeneration of BuildConfig 2023-09-23 18:59:29 +08:00
renovate[bot] 7704fa9318 Update plugin com.mikepenz.aboutlibraries.plugin to v10.9.0 2023-09-23 09:34:12 +00:00
renovate[bot] d0e3de7121 Update dependency com.mikepenz:aboutlibraries-core to v10.9.0 2023-09-23 07:37:51 +00:00
renovate[bot] 40af1862a0 Update actions/checkout digest to 8ade135 2023-09-23 05:50:16 +00:00
FooIbar 33e24aa46c Fix CI for renovate 2023-09-23 13:49:34 +08:00
FooIbar 5a97561389 Upgrade gradle wrapper 2023-09-22 16:24:48 +08:00
FooIbar 26701d84f7 Cleanup redundant .gitignore 2023-09-22 15:56:27 +08:00
FooIbar d13b09aaf3 Fix swipe-to-refresh 2023-09-22 15:46:57 +08:00
FooIbar 6a65b61785 Store SearchLayout state in ViewModel 2023-09-22 15:02:18 +08:00
FooIbar 2b8bfab44b Fix minRating advanced search 2023-09-22 13:41:22 +08:00
FooIbar b9e1d79be6 Switch to branch automerging 2023-09-21 21:33:21 +08:00
renovate[bot] 0f9e1819c1 Update room_version to v2.6.0-rc01 2023-09-21 10:23:31 +00:00
renovate[bot] eda97347fc Update nav_version to v2.7.3 2023-09-21 08:09:21 +00:00
renovate[bot] 2bd24b6a8b Update dependency com.google.android.material:material to v1.11.0-alpha03 2023-09-21 04:56:54 +00:00
renovate[bot] 8306342ab6 Update dependency androidx.fragment:fragment-ktx to v1.7.0-alpha05 2023-09-21 00:45:03 +00:00
renovate[bot] 6b6ba91721 Update dependency androidx.activity:activity-compose to v1.8.0-rc01 2023-09-20 22:32:00 +00:00
FooIbar 68155e6a6b Refine modify favorites dialog layout 2023-09-16 18:36:44 +08:00
FooIbar bfbceefef2 Fix respectDefaultWidth not working 2023-09-16 17:08:13 +08:00
FooIbar 21b39135fe Tweak modify favorites dialog layout 2023-09-15 21:10:51 +08:00
FooIbar 6adc7f7221 Add option to disable category color harmonization 2023-09-13 20:21:06 +08:00
FooIbar 6bfa8d1ea4 Fix crashing when reordering downloads 2023-09-10 21:18:23 +08:00
FooIbar 6f22269d93 Disable swiping and dragging when in selection mode 2023-09-10 21:18:05 +08:00
FooIbar b68dc98ae0 Fix drawer lock states saving 2023-09-10 19:58:12 +08:00
FooIbar f9ad1f724b Don't show search fab when search view is expanded 2023-09-10 18:30:46 +08:00
FooIbar afd22635bd Update releases.yml 2023-09-10 16:41:46 +08:00
FooIbar a9f9706be3 Migrate from intFromStrPref to intPref 2023-09-09 17:39:29 +08:00
FooIbar 41f35498fe Update syn to v2.0 2023-09-09 16:06:46 +08:00
FooIbar 58628b6556 Update jni_fn to v0.1.2 2023-09-09 16:05:17 +08:00
FooIbar 875858618e Maintenance mode 2023-09-08 21:39:56 +08:00
FooIbar 70b7bf390a Sync with 1.8.9.x versionCode 2023-09-08 18:24:00 +08:00
FooIbar de3d6de4cf Revert "Sync rootProjName with repo name"
This reverts commit de9fa5be5a.
2023-09-08 18:01:58 +08:00
FooIbar e3b4caa37d Ignore expunged torrents 2023-09-08 17:15:46 +08:00
renovate[bot] f8e19f7772 Update paging to v3.2.1 2023-09-08 16:52:03 +08:00
renovate[bot] ea5dd8b1bf Update nav_version to v2.7.2 2023-09-08 16:51:29 +08:00
renovate[bot] bd7db1a016 Update dependency io.arrow-kt:arrow-stack to v1.2.1 2023-09-08 15:30:07 +08:00
renovate[bot] 02ac048d74 Update dependency androidx.lifecycle:lifecycle-process to v2.6.2 2023-09-08 15:26:41 +08:00
renovate[bot] 9a3c9b9cbd Update dependency androidx.fragment:fragment-ktx to v1.7.0-alpha04 2023-09-08 14:55:29 +08:00
renovate[bot] 80c77c740e Update dependency androidx.core:core-ktx to v1.12.0 2023-09-08 14:55:05 +08:00
renovate[bot] 0f62662963 Update dependency androidx.collection:collection-ktx to v1.3.0-rc01 2023-09-08 14:54:23 +08:00
renovate[bot] 576d6515db Update dependency androidx.activity:activity-compose to v1.8.0-beta01 2023-09-08 14:53:55 +08:00
FooIbar 30d29bfa80 Fix torrent parsing 2023-09-08 14:52:04 +08:00
FooIbar c7c0446f23 Tweak ParseException 2023-09-08 14:49:28 +08:00
FooIbar 134777584d Merge branch 'Ehviewer-Overhauled:1.8.x.x' into 1.8.x.x 2023-09-06 16:52:10 +08:00
renovate[bot] 0b64eadb0c Update actions/checkout action to v4 2023-09-04 16:52:00 +00:00
FooIbar ea93960bf4 Fix pages fields in AdvancedSearch 2023-09-01 19:30:21 +08:00
renovate[bot] 71032e3010 Update ktor to v2.3.4 2023-08-31 21:07:43 +00:00
FooIbar d6a3a351f5 Fix UI not updating after download state changed 2023-08-30 16:37:37 +08:00
FooIbar a574bca48e Kotlin 1.9.10 2023-08-30 16:22:18 +08:00
FooIbar 785faf1bf4 Upgrade ndk to r26 RC 1 2023-08-30 16:20:32 +08:00
FooIbar fbcc32b3ee Merge remote-tracking branch 'upstream/1.8.x.x' into 1.8.x.x
# Conflicts:
#	app/build.gradle.kts
2023-08-25 13:28:07 +08:00
renovate[bot] 46b19a9de5 Update room_version to v2.6.0-beta01 2023-08-24 15:49:05 +00:00
renovate[bot] d2f47d51f9 Update plugin com.google.devtools.ksp to v1.9.10-1.0.13 2023-08-24 10:15:46 +00:00
renovate[bot] db380507f5 Update nav_version to v2.7.1 2023-08-24 07:03:27 +00:00
renovate[bot] 84cf67d21a Update dependency composeOptions to v1.5.2 2023-08-24 03:49:47 +00:00
renovate[bot] 8f53591800 Update dependency androidx.fragment:fragment-ktx to v1.7.0-alpha03 2023-08-24 01:47:24 +00:00
renovate[bot] 65ffd78844 Update dependency androidx.activity:activity-compose to v1.8.0-alpha07 2023-08-23 23:18:25 +00:00
renovate[bot] c00b5e6635 Update serialization to v1.6.0 2023-08-22 23:06:02 +00:00
FooIbar 8160991086 Don't respond to touch events when scrolling 2023-08-22 19:27:44 +08:00
FooIbar f0c933d97a Replace deprecated method 2023-08-22 18:55:39 +08:00
renovate[bot] 3fb8d3e73b Update plugin com.android.application to v8.1.1 2023-08-22 06:12:17 +00:00
renovate[bot] d8efff9921 Update accompanist_version to v0.32.0 2023-08-21 14:07:10 +00:00
FooIbar 32170688b6 Support clearing image cache for specific gallery 2023-08-21 18:39:35 +08:00
FooIbar ca74bfe2e4 Merge branch 'Ehviewer-Overhauled:1.8.x.x' into 1.8.x.x 2023-08-17 22:52:55 +08:00
renovate[bot] 41767f0fd7 Update dependency gradle to v8.3 2023-08-17 14:50:21 +00:00
FooIbar c62ca4dd23 Fix DownloadsScene crash
java.lang.LinkageError: Method com.hippo.ehviewer.databinding.ActivityMainBinding com.hippo.ehviewer.ui.scene.DownloadsScene.getBinding() overrides final method in class Lcom/hippo/ehviewer/ui/scene/SearchBarScene
2023-08-17 20:24:34 +08:00
FooIbar 9c5eddb903 Remove embedded Cronet library 2023-08-17 17:51:44 +08:00
FooIbar 4a0df07805 Set User-Agent in CronetEngine.Builder 2023-08-17 00:03:13 +08:00
FooIbar 37a3edd44b Revert "Add quichint"
This reverts commit 4e427f27
2023-08-16 23:50:20 +08:00
FooIbar f117abd483 Revert "Add option for QUIC support"
This reverts commit 861c05db
2023-08-16 23:27:38 +08:00
FooIbar 4593714298 Cleanup DownloadManager 2023-08-16 23:12:18 +08:00
FooIbar a148fd6ec3 Use flow for DownloadsScene UI updates 2023-08-16 23:12:18 +08:00
FooIbar 23a44e2f3b Migrate DownloadAdapter to ListAdapter 2023-08-16 20:23:57 +08:00
FooIbar 01e03ec0f0 Support search in DownloadsScene 2023-08-15 23:03:52 +08:00
FooIbar 4594ac592c Merge branch 'Ehviewer-Overhauled:1.8.x.x' into 1.8.x.x 2023-08-15 17:44:38 +08:00
FooIbar eee0f2dded Fix FavoritesScene crash 2023-08-15 17:24:21 +08:00
FooIbar b4080302c3 Refine GalleryListParser 2023-08-15 16:22:55 +08:00
renovate[bot] 337e210b5b Update dependency com.google.android.material:material to v1.11.0-alpha02 2023-08-15 05:08:26 +00:00
FooIbar a05b9174d4 Tweak EhScreen layout 2023-08-14 23:12:39 +08:00
FooIbar aa8adfb6f7 Use LazyColumn in showSelectItem() 2023-08-14 23:10:32 +08:00
FooIbar 1034fcd7b0 Fix favorite button color 2023-08-14 21:11:55 +08:00
FooIbar 69a26aeedb Implement swipe-to-remove in Downloads and Favorites 2023-08-14 21:11:55 +08:00
FooIbar dd607b41e9 Show search fab in FavoritesScene 2023-08-13 19:13:08 +08:00
FooIbar fd45319715 Fix toplist 2023-08-13 00:14:44 +08:00
FooIbar c34ba56896 Start a new fragment if search was performed from Popular or Toplist 2023-08-12 22:47:20 +08:00
FooIbar 6e00a4133c Fix nav checked item 2023-08-12 17:51:52 +08:00
FooIbar 9924b6ec0b Cleanup layout 2023-08-11 13:49:16 +08:00
FooIbar 4d09504abc Fix swipe-to-refresh 2023-08-11 13:49:15 +08:00
FooIbar f901bd2336 Fix navigation transitions 2023-08-11 13:49:13 +08:00
FooIbar 187c35fe88 Fix "Copied to clipboard" message not showing in API 32 and lower 2023-08-11 13:48:51 +08:00
FooIbar cc94bed772 Fix error message when no hits found 2023-08-11 13:48:51 +08:00
FooIbar 8c9cdf46db Remove predictive back support
Reland after #1322 resolved
2023-08-11 13:48:51 +08:00
FooIbar 09dd200655 Migrate right drawer to side sheet 2023-08-11 13:38:17 +08:00
FooIbar 38294e8cfc Fix deprecated function 2023-08-11 13:38:17 +08:00
FooIbar 87a42cf53d Revert obsolete Workaround
This reverts commit 576ff1b0

Reason for revert: Fixed in `androidx.core:core:1.12.0-beta01`.
https://android.googlesource.com/platform/frameworks/support/+/8f7e02550620919fafb4c7fef8743f8c20562945
2023-08-11 13:38:15 +08:00
renovate[bot] 2adf2c15fa Update dependency androidx.browser:browser to v1.6.0 2023-08-10 15:31:44 +00:00
renovate[bot] 99ac2a287e Update room_version to v2.6.0-alpha03 2023-08-10 13:08:56 +00:00
renovate[bot] 371ccab596 Update nav_version to v2.7.0 2023-08-10 11:39:12 +00:00
renovate[bot] 590c505f33 Update dependency androidx.fragment:fragment-ktx to v1.7.0-alpha02 2023-08-10 06:27:27 +00:00
renovate[bot] 01c2f3ea69 Update dependency androidx.core:core-ktx to v1.12.0-rc01 2023-08-10 04:29:43 +00:00
renovate[bot] 4c4eec118d Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0-alpha12 2023-08-10 01:27:55 +00:00
renovate[bot] 310be050d8 Update dependency androidx.collection:collection-ktx to v1.3.0-beta01 2023-08-09 22:24:00 +00:00
FooIbar 181e0301aa Fix onBackPressed callbacks order 2023-08-07 08:48:21 +08:00
FooIbar a86ca2e82c Move favorite button below header 2023-08-06 22:38:34 +08:00
FooIbar 85c911cf35 Tweak GalleryDetailScene button layout 2023-08-06 22:38:34 +08:00
FooIbar db57e2dde6 Use mobile UA for Cloudflare bypass
Allow custom UA in the future?
2023-08-05 18:25:39 +08:00
FooIbar c163ad42a6 Remove experimental status of Cloudflare bypass 2023-08-05 17:14:06 +08:00
FooIbar a2af3a4652 Manually resolve Cloudflare challenge if failed to bypass 2023-08-05 17:14:06 +08:00
FooIbar 59a9448d70 Restore default favorite slot 2023-08-04 17:37:26 +08:00
FooIbar 22b87de29d Don't show cloud favorites when not logged in 2023-08-04 17:37:26 +08:00
FooIbar d98292da1d Refine Cloudflare challenges detection 2023-08-04 05:46:51 +08:00
renovate[bot] 5422c04c53 Update plugin com.android.application to v8.1.0 2023-08-03 21:39:26 +08:00
FooIbar 0a5783de89 Fix compatibility with AGP 8.1.0 2023-08-03 21:39:14 +08:00
renovate[bot] 717e2191b0 Update plugin com.google.devtools.ksp to v1.9.0-1.0.13 2023-08-03 10:20:10 +08:00
FooIbar eedc3ba5eb Drop CheckableComposeView
It was required by EasyRecyclerView
2023-08-03 10:18:22 +08:00
renovate[bot] 30ee1816df Update dependency com.squareup.okio:okio-jvm to v3.5.0 2023-08-02 18:03:57 +00:00
FooIbar 940047de11 Refine Cloudflare challenge detection 2023-08-02 17:21:40 +08:00
tarsin c0e2041efe Cleanup code 2023-08-02 10:25:09 +08:00
tarsin 8f9d2adcfe Fixup to use compose FontFamily 2023-08-02 10:19:39 +08:00
tarsin 1bfda83665 Introduce DialogState.awaitInputText 2023-08-02 10:14:41 +08:00
tarsin 39b896e1b9 Cleanup dialog api 2023-08-02 09:18:27 +08:00
tarsin cfe7ee7f9c Convert to use tachiyomi fastscroller impl 2023-08-02 08:42:55 +08:00
FooIbar 2a95d6707a Implement Context.createReaderThemeContext() 2023-08-02 07:07:30 +08:00
renovate[bot] f4fe5f1783 Update ktor to v2.3.3 2023-08-01 18:57:09 +00:00
FooIbar 10040b2923 Minor tweaks 2023-08-01 21:04:22 +08:00
tarsin 42c56616fb Apply compose compiler report plugin 2023-08-01 09:55:35 +08:00
tarsin f8c926e1cd Cleanup unused res 2023-08-01 09:38:08 +08:00
tarsin 2adf620059 Let suggestion content padding a navbar 2023-08-01 09:30:31 +08:00
tarsin 4bdc182520 Revert "Optimize suggestion data fetch"
Revert reason: Fix OOB
This reverts commit bc4c7f62a0.
2023-08-01 09:23:40 +08:00
tarsin bc4c7f62a0 Optimize suggestion data fetch 2023-08-01 09:17:41 +08:00
tarsin b2d0c59913 Fixup suggestion color 2023-08-01 09:03:58 +08:00
tarsin ceb5424772 Cleanup SuggestionProvider 2023-08-01 08:54:46 +08:00
tarsin 5a5a5da2d9 Convert SearchBarScene SuggestRV to LazyColumn 2023-08-01 08:42:15 +08:00
tarsin 0ff9b03596 Convert TaskPreferenceDialog to compose 2023-08-01 07:37:30 +08:00
FooIbar acbe4eafa9 Support clearing search history 2023-08-01 06:36:00 +08:00
FooIbar 0a5600d949 Cleanup code 2023-08-01 06:36:00 +08:00
tarsin 63a83257fe Revert category text color to onSurface 2023-07-31 13:07:37 +08:00
tarsin d115e28403 Fix DownloadsScene category 2023-07-31 12:52:08 +08:00
tarsin 3d1ae0acfc Introduce harmonizeWithRole to keep target role chroma and tone 2023-07-31 12:35:38 +08:00
tarsin a3a01065c0 Harmonize category color 2023-07-31 11:13:16 +08:00
tarsin ae33d692bf Clip category a small corner 2023-07-31 10:46:54 +08:00
tarsin 39f55d7db1 Upgrade r8 2023-07-29 20:27:03 +08:00
tarsin a86f8d6096 Upgrade accompanist to v0.31.6rc (#1301)
* Upgrade accompanist to v0.31.6rc

* Update build.gradle.kts
2023-07-29 19:14:39 +08:00
tarsin b28fc3ffc4 Make cronetRequest.execute(..., () -> R): R 2023-07-28 18:28:07 +08:00
tarsin 5d4f544b94 No more content length validation 2023-07-28 18:18:01 +08:00
tarsin b0f0686821 Convert HomeParser to use a bytebuffer 2023-07-28 17:49:41 +08:00
tarsin b7c8afe7d2 Initial fetchCompat okhttp layer 2023-07-28 17:42:17 +08:00
tarsin 02855b68e6 Initial let parser use bytebuffer 2023-07-28 17:24:42 +08:00
tarsin cf8097babc Don't truncate fc, receivedByteCount is unreliable 2023-07-28 16:54:46 +08:00
tarsin 2d5a2022b4 Convert all GalleryListParser to rust 2023-07-28 15:30:57 +08:00
tarsin 2fac22970e Fixup! Cleanup TorrentParser 2023-07-28 12:31:44 +08:00
tarsin 8c10836e6e Cleanup TorrentParser 2023-07-28 12:30:43 +08:00
tarsin 69bba560f0 Convert to use regex-lite 2023-07-28 11:56:16 +08:00
tarsin a9d5c15bd9 Fixup codestyle 2023-07-28 11:37:59 +08:00
tarsin 1d0812ddaf Fixup codestyle 2023-07-28 11:15:48 +08:00
tarsin 02bdc9c1a3 Refine rust glist parser, do not allocate subhtml 2023-07-28 10:41:44 +08:00
tarsin 6a08460e8e Fix thumbnail mode parser 2023-07-28 10:02:04 +08:00
tarsin 091ad5cf0f Cleanup GalleryListParser 2023-07-28 09:25:56 +08:00
tarsin f911e4629c Drop jnix net extension 2023-07-28 07:18:28 +08:00
tarsin 0265ddc6e1 Introduce CronetRequest.copyToChannel 2023-07-27 12:02:30 +08:00
tarsin ead2300d90 Refactor package layout 2023-07-27 11:56:22 +08:00
tarsin b3a8547527 Drop okhttptransport since most file download job use cronet directly now 2023-07-27 11:52:31 +08:00
tarsin 37a5dbd20d Fix animated CoilImageGetter 2023-07-27 11:31:54 +08:00
tarsin c20dc66db3 Fix GalleryDetailScene comment ripple 2023-07-27 10:43:46 +08:00
tarsin 31c32123c9 Drop URLImageGetter 2023-07-27 10:25:08 +08:00
tarsin 14faa38de3 Fix SegmentedButton shape 2023-07-27 07:59:02 +08:00
tarsin 4827b7e077 Convert to use SingleChoiceSegmentedButtonRow 2023-07-27 07:53:55 +08:00
renovate[bot] 2d9a17bd25 Update dependency androidx.core:core-ktx to v1.12.0-beta01 2023-07-27 07:38:36 +08:00
renovate[bot] ce3ad45c09 Update dependency dev.chrisbanes.compose:compose-bom to v2023.07.00-alpha02 2023-07-27 07:38:27 +08:00
renovate[bot] 44fcc21d9c Update paging to v3.2.0 2023-07-27 07:38:17 +08:00
renovate[bot] 5c1a6808d7 Update dependency androidx.recyclerview:recyclerview to v1.3.1 2023-07-27 07:24:58 +08:00
renovate[bot] d461b1b8b6 Update dependency composeOptions to v1.5.1 2023-07-27 07:24:44 +08:00
renovate[bot] d74b0448d5 Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0-alpha11 2023-07-26 21:24:28 +00:00
renovate[bot] ed2a37c615 Update dependency androidx.navigation:navigation-compose to v2.7.0-rc01 2023-07-26 19:49:59 +00:00
tarsin 34c51d3115 Cleanup CronetHttpUriFetcher 2023-07-26 17:25:41 +08:00
tarsin f85d36d14d Cleanup CronetHttpUriFetcher 2023-07-26 17:17:31 +08:00
tarsin 9818f227d7 Initial Jvmheapless IO for Coil 2023-07-26 17:01:15 +08:00
tarsin 01353e05cc Cleanup CronetRequest 2023-07-26 16:16:32 +08:00
tarsin 02eaedd6a0 Lazy borrow cronet bytebuffer 2023-07-26 15:52:55 +08:00
renovate[bot] c71c872aa2 Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-android to v1.7.3 2023-07-25 21:52:29 +00:00
renovate[bot] d79dc0c630 Update Rust crate quick-xml to 0.30 2023-07-24 07:30:53 +08:00
FooIbar 46cf695bde Fix gallery detail error tip not showing 2023-07-22 21:45:44 +08:00
FooIbar c913a7eb9e Fix NPE in H@H archive download 2023-07-22 18:07:22 +08:00
tarsin 887c46c87f Hide LA symbols 2023-07-22 17:53:00 +08:00
tarsin e4d3501f93 Use fat lto 2023-07-22 17:18:45 +08:00
FooIbar add98bb630 Unescape gallery info fetched from API 2023-07-22 16:36:59 +08:00
tarsin 05651584dc Fixup install ndk 2023-07-22 10:56:00 +08:00
tarsin 37171840d3 Fixup install ndk 2023-07-22 10:55:06 +08:00
tarsin 4ee8fbedbf Fixup install ndk 2023-07-22 10:52:48 +08:00
tarsin 274e6a0666 Switch to ndk r26b1 2023-07-22 10:48:01 +08:00
tarsin b26686823e Do not build libarchive test 2023-07-22 10:27:50 +08:00
tarsin 64354ea511 Xz 5.4.3 2023-07-22 10:16:27 +08:00
tarsin 07cce5bbad Libarchive 3.7.0 2023-07-22 09:59:33 +08:00
FooIbar bbab9522df Fix category badge not showing 2023-07-22 06:28:51 +08:00
FooIbar 1a6d839ca0 Partly revert 0d666a6 to reduce network requests 2023-07-22 06:27:09 +08:00
FooIbar 0d666a633f Add dirname field for DownloadInfo 2023-07-21 20:36:19 +08:00
tarsin b24679adbd Update r8 2023-07-21 09:12:55 +08:00
tarsin 90b4d643d4 Cleanup dependencies 2023-07-21 08:59:18 +08:00
tarsin 469f2871f7 Revert to use quick-xml for url unescape 2023-07-21 08:54:06 +08:00
tarsin c7766de766 Strip unused features 2023-07-21 08:22:28 +08:00
tarsin 314de6a6a7 Set opt-level to 's', we need vectorize html parser 2023-07-21 07:48:01 +08:00
tarsin 9c148dd58d Set rust codegen units to 1 for release profile 2023-07-21 07:34:31 +08:00
tarsin 1ae469facc Drop obsolete workaround (#1274)
* Drop obsolete workaround

* Update build.gradle.kts
2023-07-21 07:05:51 +08:00
renovate[bot] eada6641e4 Update plugin com.google.devtools.ksp to v1.9.0-1.0.12 2023-07-21 06:19:24 +08:00
FooIbar 2eb50803b5 Fix downloads import order 2023-07-21 06:19:10 +08:00
FooIbar 29e3e876c7 Upgrade db, add foreign key for download label 2023-07-21 06:19:10 +08:00
FooIbar 1c38dbaa0b Upgrade db, add unique index for download label 2023-07-21 06:19:10 +08:00
FooIbar 31dcd349df Fix delete download not working 2023-07-20 19:00:57 +08:00
FooIbar ee504e3361 Upgrade db, extract common gallery info 2023-07-20 19:00:57 +08:00
FooIbar 11426e1c4c Upgrade db, add galleries table 2023-07-20 19:00:57 +08:00
tarsin 13346f1124 Drop explicitly copy constructor 2023-07-19 17:28:27 +08:00
FooIbar f38f3989e7 Tweak db migration, cleanup code
Keep the time field in DownloadInfo for future sort by start / complete time function
2023-07-19 07:17:21 +08:00
FooIbar 5c33ca1c9a [DO NOT USE] Refine drag and drop reordering, part 3/3 2023-07-19 07:17:21 +08:00
FooIbar 3599ffb805 [DO NOT USE] Refine drag and drop reordering, part 2/3 2023-07-19 07:17:21 +08:00
FooIbar 344cd1305c [DO NOT USE] Refine drag and drop reordering, part 1/3 2023-07-19 07:17:21 +08:00
renovate[bot] 84fe0b9cb7 Update dependency composeOptions to v1.5.0 2023-07-18 21:56:53 +00:00
tarsin e5963208b1 Fixup codestyle 2023-07-18 18:28:27 +08:00
tarsin 8bc84b404d Reimplement groupByToObserved 2023-07-18 18:23:40 +08:00
tarsin 80d75661c1 Fixup! Refactor EhFilter to fix concurrency modification 2023-07-18 18:14:58 +08:00
tarsin 1c74a422bc Refactor EhFilter to fix concurrency modification 2023-07-18 17:34:51 +08:00
FooIbar f06c2d6805 Adjust default aspect in grid mode 2023-07-18 14:22:41 +08:00
FooIbar fdbe06e8c5 Use handle instead of long press for drag 2023-07-18 07:05:13 +08:00
FooIbar 15a9c4ee45 Move to recyclerview-selection, part 2/2 2023-07-18 07:05:13 +08:00
FooIbar 38c90f35f2 Move to recyclerview-selection, part 1/2 2023-07-18 07:05:13 +08:00
renovate[bot] bf3ee4cce2 Update plugin com.mikepenz.aboutlibraries.plugin to v10.8.3 2023-07-17 15:52:59 +00:00
renovate[bot] 9553491040 Update dependency com.mikepenz:aboutlibraries-core to v10.8.3 2023-07-17 13:29:54 +00:00
tarsin 0253d92c7f Cleanup code 2023-07-16 22:28:07 +08:00
tarsin e2ac340b6f Refine SelectableGalleryInfoRecyclerView 2023-07-16 22:22:29 +08:00
tarsin 44b60185cc Refine SelectableGalleryInfoRecyclerView 2023-07-16 22:12:15 +08:00
tarsin 9b3ffd1f2c Refactor EasyRecyclerView 2023-07-16 21:59:48 +08:00
tarsin 935c8e7d15 Remove easyrv usage in GalleryCommentsScene 2023-07-16 21:15:58 +08:00
tarsin 8f5094efef Cleanup EasyRv 2023-07-16 18:45:12 +08:00
tarsin 91accb6655 Cleanup all unnecessary easyrv usage, prepare to drop easyrv 2023-07-16 18:38:54 +08:00
FooIbar 4f23cf5d8d Fix local favorite count not updating 2023-07-16 16:33:29 +08:00
FooIbar 39f76246c8 Fix favorites move from local to cloud 2023-07-16 16:33:29 +08:00
FooIbar 8ac2b027ec Remove deprecated hosts 2023-07-16 16:33:29 +08:00
FooIbar 919d22ebf1 Gradle configuration cache compatibility 2023-07-16 16:33:29 +08:00
FooIbar 14a28c681a Do db migration, drop history favorite slot trick 2023-07-15 17:39:43 +08:00
FooIbar 388bccc468 Make QuickSearch name non-null 2023-07-15 17:39:43 +08:00
FooIbar 639d94795c Check initialization of mSpiderQueen 2023-07-15 14:20:38 +08:00
FooIbar 51e2f44868 Fix swipe refresh and error tip click refresh 2023-07-15 06:44:59 +08:00
FooIbar 92b9b9879c Fix sad panda check on login 2023-07-14 18:18:58 +08:00
FooIbar c867a74aea Tweak original image download 2023-07-14 18:18:45 +08:00
FooIbar e9a1bf22b1 Tweak archive download and image limit reset 2023-07-14 18:18:45 +08:00
FooIbar 46271fb0d2 Subscribe reading mode and orientation type changes 2023-07-13 07:00:18 +08:00
renovate[bot] 7438b17366 Update dependency io.arrow-kt:arrow-stack to v1.2.0 2023-07-12 18:38:41 +00:00
FooIbar 8306640ed6 Don't intercept on Varnish errors 2023-07-12 18:33:01 +08:00
tarsin 39b7623688 Flatten layout 2023-07-12 17:21:22 +08:00
tarsin 41b46035e4 Fix DownloadsScene leak 2023-07-12 16:22:20 +08:00
tarsin 10045494b8 Fix GalleryCommentsScene binding leak 2023-07-12 16:11:28 +08:00
tarsin ea67a022d8 Fix leaking 2023-07-12 15:56:20 +08:00
tarsin 203c89e3a8 Fixup! Fix a itemTouchHelper rv leak 2023-07-12 15:51:07 +08:00
tarsin 1c88be6f82 Fix a itemTouchHelper rv leak 2023-07-12 15:47:40 +08:00
tarsin 2a19bcd73b Fix a rv adapter leak 2023-07-12 15:34:07 +08:00
tarsin 9f29594ad6 Fix paging3 dependency 2023-07-12 15:22:27 +08:00
tarsin 9677e6ac80 Add leakcanary debug impl 2023-07-12 15:20:43 +08:00
tarsin 1590ca4b80 Convert DownloadService to use a deferred DownloadManager 2023-07-12 15:04:40 +08:00
tarsin effe7530ed Fixup! suspend db query 2023-07-12 12:24:31 +08:00
tarsin 19f270e320 Fixup! suspend db query 2023-07-12 12:22:55 +08:00
tarsin 25d876f8b9 Initial suspend all db query
TODO: Cleanup DownloadManager
2023-07-12 12:21:05 +08:00
tarsin 179e470154 Make DownloadScreen scrollable 2023-07-12 11:08:02 +08:00
tarsin 5cf122c30c Suspend more db 2023-07-12 10:41:56 +08:00
tarsin 36895de83b Introduce runAssertingNotMainThread as workaround 2023-07-12 10:37:00 +08:00
tarsin fed5285a31 Suspend more db query 2023-07-12 10:30:46 +08:00
tarsin b1fbefc09e Cleanup DownloadManager 2023-07-12 10:20:41 +08:00
tarsin 2fd9982c37 Cleanup EHDB nullability 2023-07-12 10:07:26 +08:00
tarsin 89a108574a Suspend DownloadLabelDao delete 2023-07-12 10:05:24 +08:00
tarsin 28ce6ee13e Suspend DownloadDirnameDao 2023-07-12 10:01:26 +08:00
tarsin 4441ea2c5d Suspend DownloadDirnameDao load 2023-07-12 09:58:31 +08:00
tarsin 02489893ec Suspend DownloadDirnameDao update insert 2023-07-12 09:46:09 +08:00
tarsin 62c3e9290e Suspend DownloadDirnameDao deleteByKey 2023-07-12 09:35:32 +08:00
tarsin 3f53710c5b Restore allowMainThreadQueries, prepare to suspendize DownloadManager 2023-07-12 09:31:16 +08:00
tarsin 389f27dfa1 Cleanup unused dao method 2023-07-12 09:30:13 +08:00
tarsin e2d03eb928 Purify SearchDao 2023-07-12 09:26:20 +08:00
tarsin 37ec49ed69 Suspend parser 2023-07-12 09:22:24 +08:00
tarsin 4694245b51 Suspend more db queries, part of #629 2023-07-12 09:15:01 +08:00
tarsin 60b77145a9 Prepare to drop allowMainThreadQueries 2023-07-12 08:37:46 +08:00
tarsin 28a6f8cd2b Refine package layout 2023-07-12 08:34:55 +08:00
tarsin 02a3c1c54b Cleanup kt style builder 2023-07-12 08:32:43 +08:00
tarsin 09df7cc39b Cleanup kt style builder 2023-07-12 08:27:33 +08:00
tarsin a4ce60c849 Refactor package layout 2023-07-12 08:03:45 +08:00
tarsin d74f18012b Refactor package layout 2023-07-12 07:55:54 +08:00
tarsin 3609379284 Refactor package layout 2023-07-12 07:48:21 +08:00
tarsin 19f9105640 Fixup AboutScreen edgeToEdge 2023-07-11 19:43:05 +08:00
tarsin 24664d4e83 Merge EhPreviewItem and its placeholder 2023-07-11 17:42:32 +08:00
tarsin e16b5b0437 Cleanup layout 2023-07-11 16:29:02 +08:00
FooIbar 94747da3d0 Tweak the layout of the favorite dialog 2023-07-11 14:43:37 +08:00
tarsin df8c70d8e6 Move GalleryListScene to paging3 (#1245)
* Initial WIP move GalleryListScene to paging3

* Refine

* Refine

* Refine

* Refine

* Refine

* Refine

* Typesafe State

* Refine

* Refine

* Refine

* Refine

* Cleanup code

* Cleanup code
2023-07-11 10:40:03 +08:00
tarsin 7fd3361608 Refine FavoritesScene 2023-07-11 07:35:13 +08:00
FooIbar d9522e4e89 Implement automatic update checks 2023-07-11 06:53:09 +08:00
FooIbar a8c96fa7df Introduce AppUpdater 2023-07-11 06:53:09 +08:00
renovate[bot] 5570933be4 Update dependency gradle to v8.2.1 2023-07-10 15:27:02 +00:00
FooIbar fb6cb8d3fb Generate repo name at build time 2023-07-10 22:13:55 +08:00
FooIbar 4ca7b6b11c Show changelog for CI build 2023-07-10 22:13:55 +08:00
renovate[bot] 5c377d346e Update dependency com.mikepenz:aboutlibraries-core to v10.8.2 2023-07-10 19:34:30 +08:00
tarsin 1dd0eeb2ed Rename rememberMemorized to rememberInVM 2023-07-10 19:28:42 +08:00
tarsin 3f6abd6380 Cleanup rememberMemorized 2023-07-10 19:27:44 +08:00
tarsin 407c55dbdc Properly store GalleryPreviewScreen data 2023-07-10 18:36:38 +08:00
tarsin 74afa6c764 Cleanup FavoritesScene 2023-07-10 18:27:31 +08:00
tarsin 60ccd988cb Introduce lazyMut 2023-07-10 18:26:15 +08:00
tarsin 505ba6e4e3 Move some persistent data to VM as in-memory storage 2023-07-10 18:02:40 +08:00
tarsin d4d6fe56a9 Move FavouriteScene to paging3 (#1238)
* Initial move favScene to paging3

* Refine

* Refine

* Refine

* Refine

* Implement goto bottom

* Refine

* Implement Jumpto

* Refine

* Refine

* Refine

* Refine

* Refine

* Cleanup code

* Cleanup code

* Refine

* Refine

* Do load in IOContext
2023-07-10 14:00:45 +08:00
tarsin 740fff2178 Add paging3 runtime dependency 2023-07-10 08:34:47 +08:00
tarsin 54a2ea64bc Cleanup GalleryAdapter, prepare migrate to paging3 2023-07-10 08:30:38 +08:00
FooIbar 200882e13c Log details of bad response code error 2023-07-10 06:43:44 +08:00
FooIbar dac28b9b6a Refactor e-hentai API response parsing 2023-07-10 06:43:44 +08:00
renovate[bot] 7a8ae183da Update plugin com.mikepenz.aboutlibraries.plugin to v10.8.2 2023-07-09 18:32:08 +00:00
tarsin c163e24434 Refine ComposeFavScene 2023-07-09 17:14:04 +08:00
tarsin eed30084bc Refine ComposeFavScene 2023-07-09 16:55:39 +08:00
tarsin 137a51dad0 Refine ComposeFavScene SearchBar 2023-07-09 16:29:31 +08:00
tarsin b71d326620 Refine ComposeFavScene 2023-07-09 16:21:57 +08:00
tarsin 371622770b Refine ComposeFavScene 2023-07-09 16:18:23 +08:00
tarsin 2b6bcf6698 Refactor ComposeFavScene 2023-07-09 16:05:45 +08:00
tarsin bc33ea84f2 Initial load Fav source 2023-07-09 16:00:57 +08:00
tarsin 3d7210ec08 Prepare to rewrite FavScene with Compose 2023-07-09 15:40:37 +08:00
tarsin e7bed5f5eb Remove redundant TODO 2023-07-09 15:29:03 +08:00
tarsin a3237a024e Cleanup ComposeFragment 2023-07-09 15:28:29 +08:00
tarsin 662fc6859b Fix GalleryPreviewScreen page load 2023-07-09 13:27:20 +08:00
tarsin 5bb61959bd Add jumping support 2023-07-09 12:52:57 +08:00
tarsin 8ae75101ef Add LazyGridScrollbar for preview jump 2023-07-09 11:54:13 +08:00
tarsin 95fcab0980 Inline LazyColumnScrollbar 2023-07-09 11:36:37 +08:00
tarsin d2b141e218 Fix jump crash 2023-07-09 11:21:10 +08:00
tarsin 73eb91f4b4 Cleanup GalleryPreviewScreen 2023-07-09 10:49:43 +08:00
tarsin 61c51f8882 Fix MergeInterceptor 2023-07-09 10:49:00 +08:00
tarsin cb9f36dd52 Rewrite GalleryPreviewScreen Pager, Resolve #1152 2023-07-09 10:14:13 +08:00
tarsin 80b0203af2 Fix ci failed 2023-07-09 08:16:48 +08:00
tarsin 66155eed1c Fix crash when r8 shrink aboutlibraries json 2023-07-09 07:36:39 +08:00
renovate[bot] 144e8a2951 Update dependency com.mikepenz:aboutlibraries-core to v10.8.1 2023-07-09 06:48:37 +08:00
renovate[bot] 7c1f521960 Update plugin com.mikepenz.aboutlibraries.plugin to v10.8.1 2023-07-08 22:01:29 +00:00
tarsin dbe528269d Fix FavoritesScene crash again 2023-07-08 20:25:33 +08:00
tarsin 9b843e84b2 Fix FavoritesScene crash 2023-07-08 19:49:22 +08:00
tarsin c9ef0e5406 Fix read download button text maxline 2023-07-08 18:49:23 +08:00
tarsin 1a49b3d00b Cleanup unused field 2023-07-08 18:41:08 +08:00
tarsin 33502c88db Fix FavDrawer ListItem style 2023-07-08 18:32:41 +08:00
tarsin 6554735c63 Make Favscene drawer aware of Settings fav changes 2023-07-08 18:07:53 +08:00
tarsin 2360e6376e Convert FavSceneDrawer to Compose 2023-07-08 17:22:20 +08:00
tarsin b1e186a5f1 Bump MCA 2023-07-08 16:24:17 +08:00
tarsin ffd2b5a342 Fixup GalleryInfoBottomSheet impl 2023-07-08 16:21:28 +08:00
tarsin d5a16f50c5 Revert GalleryInfoBottomSheet to BottomSheetDialogFragment impl for predictive back 2023-07-08 16:12:03 +08:00
tarsin 5b03e67108 Drop unused code 2023-07-08 15:39:52 +08:00
tarsin eac5b2641b Fix galleryProvider init crash 2023-07-08 15:36:03 +08:00
tarsin e46008df55 Cleanup: Move ReaderProgressIndicator to compose 2023-07-08 14:36:42 +08:00
tarsin 07b1f39796 Move ReaderProgressIndicator to compose 2023-07-08 14:34:12 +08:00
tarsin 64d3849b62 Fixup PageSlider haptic feedback 2023-07-08 14:22:53 +08:00
tarsin 9d766f47c5 Fixup PageSlider theme 2023-07-08 14:20:22 +08:00
tarsin 64841e6e3b Move PageSlider to Compose 2023-07-08 14:11:47 +08:00
tarsin 571fbabf4f Restore PageIndicator padding 2023-07-08 13:54:38 +08:00
tarsin 12c3ad6d5f Fixup tachiyomi theme 2023-07-08 13:53:21 +08:00
tarsin 7c987ec868 Move PageIndicatorText to Compose 2023-07-08 13:47:39 +08:00
tarsin 27686e952a Resolve #1227 2023-07-08 06:58:24 +08:00
renovate[bot] de06c24924 Update dependency com.squareup.okio:okio-jvm to v3.4.0 2023-07-07 20:11:02 +00:00
tarsin 4e1b4ddf28 Kotlin 1.9.0 2023-07-07 07:12:07 +08:00
FooIbar ca21b5e713 Introduce <T> Request.executeAndParseAs() 2023-07-06 06:22:46 +08:00
FooIbar 5a6a01f813 Use kotlinx.serialization for json handling 2023-07-06 06:22:46 +08:00
FooIbar 16c6353459 Show changelog for release 2023-07-05 19:31:28 +08:00
FooIbar d1623d411a Show confirm dialog before downloading updates 2023-07-05 19:31:28 +08:00
tarsin 4e4b072c16 No more UIContext needed to modifyFav 2023-07-05 11:01:35 +08:00
tarsin f2601fb672 Refine check updates 2023-07-05 10:53:36 +08:00
tarsin 125c467c1b Fixup! Support install CI apk 2023-07-05 10:48:44 +08:00
tarsin 0b95c340d6 Support install CI apk 2023-07-05 10:47:36 +08:00
tarsin 79e0b33aad Extract the apk 2023-07-05 10:19:22 +08:00
tarsin f1f7b8dc88 Add no-op token to download CI 2023-07-05 10:04:47 +08:00
tarsin e97e539f92 Get CI archive url 2023-07-05 09:22:42 +08:00
tarsin 4b562f98f0 Get workflow url 2023-07-05 09:07:04 +08:00
tarsin bd06d76656 Cleanup code 2023-07-05 08:43:02 +08:00
tarsin 38ddca2342 Initial get latest version using github restful api 2023-07-05 08:39:22 +08:00
tarsin 1119798ce8 Initial get latest commitSha using github restful api 2023-07-05 08:32:21 +08:00
tarsin 1eeab2f03d Introduce preference to use CI update channel 2023-07-05 07:51:29 +08:00
FooIbar bfbe6b8e6a Translate tags when saving to quick search 2023-07-05 07:20:50 +08:00
FooIbar 4905c955bc Max characters limit is for ASCII characters 2023-07-05 07:20:36 +08:00
FooIbar 4cf698a10a Cleanup unused res 2023-07-04 21:20:24 +08:00
FooIbar 4b66f58fd3 Support adding favorite notes 2023-07-04 21:20:24 +08:00
FooIbar 325909401c Use named constant instead of magic number 2023-07-04 21:20:24 +08:00
FooIbar 652d6a2f28 Support displaying favorite notes 2023-07-04 21:20:24 +08:00
tarsin 7672a82260 Convert non-close callbackFlow to MutableSharedFlow 2023-07-04 11:22:01 +08:00
tarsin 0f37d17bf3 Cleanup HistoryScene 2023-07-04 10:54:56 +08:00
tarsin c923d74fec Drop explicated recompose 2023-07-04 10:49:30 +08:00
tarsin 2ba8640996 Let FavouriteStatusRouter handle historyDB as well 2023-07-04 10:39:03 +08:00
tarsin 0b1a0cade8 Cleanup FavouriteStatusRouter implementation 2023-07-04 10:24:08 +08:00
tarsin 78aab4f6c7 Cleanup FavouriteStatusRouter stateFlow 2023-07-04 10:18:14 +08:00
tarsin 77502e1a7c No need to query local db fav info 2023-07-04 10:14:30 +08:00
tarsin b90f221ede Drop isFavorited field 2023-07-04 10:11:54 +08:00
tarsin ee68b421d6 Cleanup FavouriteStatusRouter 2023-07-04 10:06:10 +08:00
tarsin 88be232e70 Drop a notifyDataSetChanged 2023-07-04 09:08:29 +08:00
FooIbar da9de7a823 Truncate file to the size actually written 2023-07-04 07:08:18 +08:00
FooIbar f08e124df6 Support downloading original images in reader 2023-07-03 22:55:05 +08:00
FooIbar ce888a0982 Unwrap IOException in getReadableString() 2023-07-03 22:55:05 +08:00
tarsin f59789a11e Fixup! Only emit info being add 2023-07-03 21:04:29 +08:00
tarsin c8a3db8a3e Fixup! Workaround ComposeView in RVView 2023-07-03 20:45:01 +08:00
tarsin 23366c8ea1 Workaround ComposeView in RVView 2023-07-03 20:35:04 +08:00
tarsin 6e65afa7e2 Share DownloadManager callback flow 2023-07-03 20:24:22 +08:00
tarsin 29b81aa90e Fix GalleryInfoListItem to use produceState 2023-07-03 20:13:25 +08:00
tarsin d85090787f Fix GalleryDetailScene DownloadInfoListener callbackFlow 2023-07-03 20:09:42 +08:00
tarsin 0eb3cc9073 Cleanup DownloadInfoListener callbackFlow 2023-07-03 20:03:48 +08:00
tarsin dfd9af8ee3 Convert DownloadInfoListener to callbackFlow 2023-07-03 19:57:28 +08:00
tarsin 1120c23709 Do db migration, make DownloadLabel nonnull 2023-07-03 18:46:43 +08:00
tarsin 975421044c Cleanup toMutable* usage 2023-07-03 18:37:50 +08:00
tarsin 802b63ed5a Cleanup DownloadManager nullability 2023-07-03 18:33:13 +08:00
tarsin d32a0d6b7f Cleanup DownloadManager 2023-07-03 18:32:20 +08:00
tarsin 0c5a1a6533 Cleanup DownloadManager 2023-07-03 18:30:35 +08:00
tarsin 61796f4cd3 Cleanup DownloadManager init code 2023-07-03 18:22:06 +08:00
tarsin 80726a7ff0 Cleanup DownloadManager 2023-07-03 18:04:34 +08:00
tarsin a2fdcc57f8 Cleanup DownloadManager 2023-07-03 17:57:05 +08:00
tarsin bffb32eafd Reduce allocation 2023-07-03 17:40:44 +08:00
tarsin 2c452d236c Cleanup mAllInfoMap init code 2023-07-03 17:37:58 +08:00
tarsin e7e036f7c6 Convert mAllInfoMap to LinkedHashMap and do query in composer thread 2023-07-03 17:25:28 +08:00
tarsin fbb702cacd Fix Deferred implementation, Resolve #1213 2023-07-03 17:13:12 +08:00
FooIbar 598438a5f9 Avoid rust jni log spam 2023-07-03 16:34:05 +08:00
FooIbar 24a1c94f04 Wrap exception as IOException in CloudflareInterceptor 2023-07-03 15:51:51 +08:00
tarsin e4e053a49b Clip CircularLayout item ripple 2023-07-03 10:29:43 +08:00
tarsin 8c0e217117 Refactor showSelectItemWithIcon layout 2023-07-03 10:24:31 +08:00
tarsin 174e899ead Fix cannot remove localFav 2023-07-03 09:23:28 +08:00
tarsin 84cc915d95 Avoid cascade column 2023-07-03 09:01:57 +08:00
tarsin 7668f568f0 Refactor to use ListItem 2023-07-03 08:38:40 +08:00
tarsin 35a7cc2067 Unify isCronetSupported 2023-07-03 08:09:37 +08:00
tarsin efa0823293 Don't respect cache headers, Resolve #1211 2023-07-03 07:56:28 +08:00
FooIbar 1473f6326d Refactor addToFavorites() 2023-07-03 07:16:44 +08:00
FooIbar 861c05db44 Add option for QUIC support 2023-07-03 07:16:44 +08:00
tarsin 09b92cc709 Reduce allocations 2023-07-02 12:46:18 +08:00
tarsin a2d9113be2 Remove unused defensive code 2023-07-02 12:42:02 +08:00
tarsin a64c7d9f22 Make GalleryTagGroup groupName immutable and nonnull 2023-07-02 12:09:09 +08:00
tarsin 97090a4dc6 Refactor out GalleryTag 2023-07-02 12:01:21 +08:00
tarsin cf2c5b7e82 Drop snapshot maven 2023-07-02 11:25:02 +08:00
tarsin 6ee5b636c2 Upgrade dependencies 2023-07-02 11:04:08 +08:00
tarsin de9fa5be5a Sync rootProjName with repo name 2023-07-02 10:51:29 +08:00
FooIbar ffc3693674 Use the same UA for ehRequest and cronetRequest 2023-07-02 07:20:46 +08:00
FooIbar a3abd224e8 Use interceptor to handle cookies instead 2023-07-02 07:20:46 +08:00
FooIbar ac680afad3 Add cookie header and handle redirect for cronetRequest 2023-07-02 07:20:46 +08:00
FooIbar 52c21319d6 Move error tip below header in gallery detail 2023-07-01 20:00:24 +08:00
FooIbar 7b38171a9d Replace cascade if with when 2023-07-01 20:00:24 +08:00
tarsin c9ef60db67 Regen gradle wrapper 2023-07-01 16:28:20 +08:00
FooIbar aff75c2dec Add option for bypassing Cloudflare 2023-07-01 14:56:27 +08:00
FooIbar 63fcca3c7d Bypass Cloudflare with webview 2023-07-01 14:56:27 +08:00
tarsin 2e3a148c7a Convert to typesafe FilterMode 2023-07-01 12:46:03 +08:00
tarsin a7b239f0b9 Drop unused coroutineScope 2023-07-01 12:21:46 +08:00
tarsin 227cbd6fba Cleanup EhDB nullability 2023-07-01 12:08:18 +08:00
tarsin 8d19dffa01 Ensure Filter DB modification never on main thread 2023-07-01 12:07:23 +08:00
tarsin f3e1400d4c Refine EhFilter API 2023-07-01 11:37:00 +08:00
tarsin ef891ea23d Cleanup EhFilter 2023-07-01 11:29:10 +08:00
tarsin 043a1d8fe7 Cleanup with HtmlCompat.parseAsHtml 2023-07-01 11:21:24 +08:00
tarsin e428695052 Cleanup filter 2023-07-01 11:07:29 +08:00
tarsin 459dd50e91 Cleanup filter 2023-07-01 10:58:36 +08:00
tarsin 4c286a279f Fix FilterScreen nullability 2023-07-01 10:53:36 +08:00
tarsin 88c394480e Upgrade DB, Filter nullability changes 2023-07-01 10:51:13 +08:00
tarsin cdd5585124 Cleanup EhFilter 2023-07-01 10:46:34 +08:00
tarsin b0346b4e9d Revert guava 2023-07-01 10:30:09 +08:00
tarsin beecd6b109 Update r8 2023-07-01 10:08:58 +08:00
tarsin 54d7abd880 Update guava 2023-07-01 10:08:14 +08:00
FooIbar 9f77a4ce0a Drop webp icon since minSdk is 28 2023-07-01 07:12:49 +08:00
renovate[bot] 754a20ee3c Update dependency gradle to v8.2 2023-06-30 22:45:38 +00:00
FooIbar b5b096aeae Add option to force e-hentai thumb server 2023-06-30 17:42:30 +08:00
FooIbar d0ecac07aa Lofi domain is deprecated 2023-06-30 17:42:30 +08:00
FooIbar 67e6387fa8 Fix settings profile cookie since 55b3753 2023-06-30 15:47:17 +08:00
FooIbar bc34f25a3c Exclude some libraries from aboutLibraries 2023-06-30 15:47:17 +08:00
FooIbar afc38c2de8 Add back press handler in select site screen 2023-06-30 15:47:17 +08:00
renovate[bot] c020af3083 Update dependency com.pinterest:ktlint to v0.50.0 2023-06-30 00:41:16 +00:00
renovate[bot] 3f509f8c11 Update dependency com.google.android.material:material to v1.10.0-alpha05 2023-06-29 22:14:41 +00:00
renovate[bot] 75eb25db18 Update chunker to v4 2023-06-30 00:24:09 +08:00
renovate[bot] 79d173cb0d Update dependency org.jetbrains.kotlinx:kotlinx-coroutines-android to v1.7.2 2023-06-29 21:43:44 +08:00
tarsin f3eb2c8c17 Optimize GalleryInfo composer path calculation 2023-06-29 19:02:24 +08:00
FooIbar d15685e1ca Add rustfmt and clippy check to CI 2023-06-29 16:06:54 +08:00
renovate[bot] 11535f7d7b Update nav_version to v2.7.0-beta02 2023-06-29 07:53:43 +08:00
FooIbar 0b526040a3 Add interceptor to store cookies for cronet 2023-06-29 07:11:57 +08:00
FooIbar 15696f4e6e Fix duplicate getUConfig() call 2023-06-29 07:11:57 +08:00
FooIbar 0c560518c8 Clean remaining code from 2d20da7 2023-06-29 07:11:57 +08:00
renovate[bot] 302cba9f61 Update ktor to v2.3.2 2023-06-28 19:41:46 +00:00
tarsin 3a33a2425f Cargo fmt 2023-06-28 18:27:22 +08:00
tarsin a5df907bbe Cargo clippy fix 2023-06-28 18:26:29 +08:00
tarsin 6879a02a63 Fix AdvancedSearch pages behaviour 2023-06-28 13:31:35 +08:00
tarsin d86d72212f Fix AdvancedSearch minrating textfield behaviour 2023-06-28 13:21:00 +08:00
tarsin de528ec277 Fix AdvancedSearch minrating textfield style 2023-06-28 12:43:47 +08:00
FooIbar 6f41ddda51 Don't retry on unrecoverable errors 2023-06-27 23:09:57 +08:00
tarsin ffaf8b9c46 Fix SearchLayout insetPadding 2023-06-27 22:18:49 +08:00
tarsin aab1c12aed Fix SearchLayout padding 2023-06-27 22:10:01 +08:00
tarsin 4e427f2761 Add quichint 2023-06-27 22:04:37 +08:00
tarsin 2a6247a89d Cleanup unused res 2023-06-27 22:04:00 +08:00
tarsin 62c3e9fd99 Restore pageRange advanced options 2023-06-27 22:00:17 +08:00
tarsin 1690651428 Restore three more advanced options 2023-06-27 21:44:05 +08:00
tarsin ea95b1c525 Fixup! Restore minRating advanced search 2023-06-27 19:58:29 +08:00
tarsin f67c80a3a3 Restore minRating advanced search 2023-06-27 19:55:15 +08:00
tarsin 6c1ffeacb2 Fixup! Initial compose advanced search 2023-06-27 19:07:26 +08:00
tarsin 753206c2fb Initial compose advanced search 2023-06-27 19:05:59 +08:00
tarsin 2ae8265d05 Fix SearchLayout title font 2023-06-27 18:37:45 +08:00
tarsin 7df7a783f6 Initial migrate SearchLayout to Compose
TODO: advanced options
2023-06-27 18:33:08 +08:00
tarsin 2829d081cc Cleanup with bundleOf ext 2023-06-27 12:20:05 +08:00
tarsin bb3a88813b Cleanup BaseScene 2023-06-27 12:00:27 +08:00
tarsin 2da8cfde01 Unify MainActivity nav behaviour 2023-06-27 11:54:09 +08:00
tarsin 2e23167e94 Enable httpcache for cronet 2023-06-24 19:03:16 +08:00
tarsin 9131f6f8cb Cleanup ListUrlBuilder 2023-06-24 16:48:19 +08:00
tarsin a77a1fd3e1 Drop UrlBuilder 2023-06-24 16:15:52 +08:00
tarsin 9dfc1324ad Flush cookies after signin 2023-06-24 16:05:35 +08:00
tarsin c84e86a5a1 Cleanup HttpUrl usage 2023-06-24 16:02:18 +08:00
tarsin be867d5d07 Cleanup HttpUrl usage 2023-06-24 15:49:00 +08:00
tarsin 5457044dd5 Cleanup a HttpUrl usage 2023-06-24 15:44:29 +08:00
tarsin be2330f1b6 Prepare to drop UrlBuilder 2023-06-24 15:36:31 +08:00
tarsin eb18e74884 Prepare to drop UrlBuilder 2023-06-24 15:28:37 +08:00
renovate[bot] fd05d03bca Update plugin com.mikepenz.aboutlibraries.plugin to v10.8.0 2023-06-24 07:02:05 +08:00
renovate[bot] 69db5bd400 Update dependency com.mikepenz:aboutlibraries-core to v10.8.0 2023-06-23 22:00:15 +00:00
FooIbar a87d720ae3 Support tag suggestion under operators and qualifiers 2023-06-22 18:51:27 +08:00
FooIbar 7b81a9aa50 Cleanup code 2023-06-22 15:40:20 +08:00
FooIbar b07fd2bc4f Remove all unnecessary jvm annotations 2023-06-22 15:40:20 +08:00
FooIbar 3c64486c3b Convert all unifile classes to kotlin 2023-06-22 15:40:20 +08:00
FooIbar 8cb4045589 Rename .java to .kt 2023-06-22 15:40:20 +08:00
FooIbar 7edac11d53 Rename UniFile.kt to UniFileExtensions.kt 2023-06-22 15:40:20 +08:00
tarsin 838f8ac98c Fix galleryTag layout 2023-06-22 11:39:27 +08:00
tarsin 3a57d43aa4 Fixup! Kotlin 1.9.0-RC 2023-06-22 10:26:42 +08:00
tarsin 69870803f7 Kotlin 1.9.0-RC 2023-06-22 10:23:27 +08:00
renovate[bot] eef5e5485a Update dependency androidx.paging:paging-compose to v3.2.0-rc01 2023-06-22 10:03:31 +08:00
renovate[bot] ebbe26e5e6 Update room_version to v2.6.0-alpha02 2023-06-22 10:01:56 +08:00
FooIbar 0cd83d3e4c Convert all legacy view classes to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 1c07c61307 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar b602fa1204 Convert AddDeleteDrawable, HandlerDrawable and WrapDrawable to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 273bed9ba1 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 028405ecce Convert MarginItemDecoration, SimpleSmoothScroller and WindowInsetsAnimationHelper to kotlin 2023-06-22 10:01:41 +08:00
FooIbar ada4158c8e Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar fc99c611a6 Convert ViewTransition and BringOutTransition to kotlin 2023-06-22 10:01:41 +08:00
FooIbar fce4a2751a Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 557818e59f Drop DialogWebChromeClient and SimpleHolder 2023-06-22 10:01:41 +08:00
FooIbar a85f3cbe0b Do ktlint format 2023-06-22 10:01:41 +08:00
FooIbar 5d8acd9577 Drop ViewUtils 2023-06-22 10:01:41 +08:00
FooIbar e2bf887b94 Convert RadioGridGroup to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 4a0893c573 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 839d074df1 Drop NumberUtils 2023-06-22 10:01:41 +08:00
FooIbar 9be7705050 Convert EasyRecyclerView to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 470a2baa6a Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar fb8de517a0 Drop LayoutUtils 2023-06-22 10:01:41 +08:00
FooIbar 635de44299 Convert AboveSnackerLayout to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 1d4bd9a294 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar a0b48a5cc7 Drop MathUtils 2023-06-22 10:01:41 +08:00
FooIbar eb726ccbf4 Convert SimpleGridLayout to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 3f484a49e8 Drop StringUtils and Utilities 2023-06-22 10:01:41 +08:00
FooIbar 09cd08bfaa Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar e6312a37c7 Convert LayoutManagerUtils to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 862b3e5e46 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 0042482107 Convert SimpleHandler to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 85bc215e00 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 2db5a749a0 Drop IOUtils 2023-06-22 10:01:41 +08:00
FooIbar 8c439b1167 Convert OSUtils to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 4eb1a4141f Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 4f47febc06 Convert AnimationUtils, ConcurrentPool, IntIdGenerator and SimpleAnimatorListener to kotlin 2023-06-22 10:01:41 +08:00
FooIbar c61afc7a04 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar b59966e8a4 Convert FastScroller to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 457cf2e856 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 4a7626c6f6 Convert FileUtils to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 947452e3f1 Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar b6de84c369 Drop ObjectUtils 2023-06-22 10:01:41 +08:00
FooIbar 0adc43b243 Convert ReadableTime and TextUrl to kotlin 2023-06-22 10:01:41 +08:00
FooIbar 0c9a8624bc Rename .java to .kt 2023-06-22 10:01:41 +08:00
FooIbar 09e9d3ff5a Drop JsoupUtils and LogCat 2023-06-22 10:01:41 +08:00
renovate[bot] 7240ca4eba Update dependency androidx.activity:activity-compose to v1.8.0-alpha06 2023-06-22 00:41:41 +00:00
tarsin 0a2c29a693 Adjust GalleryInfo layout 2023-06-21 10:37:05 +08:00
tarsin bba875238c Rewrite GalleryInfo layout with ConstraintLayout dsl 2023-06-21 10:28:16 +08:00
FooIbar c33248b1bf Use file hash for cover search 2023-06-21 00:52:28 +08:00
FooIbar 24431051ae Make HV event notification clickable 2023-06-20 23:03:59 +08:00
FooIbar 1758e25388 Cleanup code 2023-06-20 23:03:59 +08:00
tarsin a27e8b99d9 Fix parse e-hentai failed 2023-06-20 22:18:19 +08:00
tarsin a06e76e934 Fix proguard and do cargo fmt 2023-06-20 21:53:48 +08:00
FooIbar 14609583b5 Show favorite name in gallery list 2023-06-20 21:49:28 +08:00
FooIbar 751a89c107 Refine rust gallery list parser 2023-06-20 21:49:28 +08:00
tarsin 619c8f6deb Update r8 2023-06-20 19:54:12 +08:00
tarsin c3835b8a65 Drop unused field in GalleryInfo 2023-06-20 19:43:42 +08:00
tarsin 5fd890cf9b Cleanup code 2023-06-20 19:40:32 +08:00
tarsin 40c6135214 Cleanup code 2023-06-20 19:37:06 +08:00
tarsin cfa1ce8ab6 Cleanup code 2023-06-20 19:34:38 +08:00
tarsin 260dafcd79 Fixup bytebuffer usage 2023-06-20 19:27:12 +08:00
tarsin 73b3cd4625 Add annotations 2023-06-20 17:36:44 +08:00
tarsin d895a07583 Cleanup code 2023-06-20 17:33:48 +08:00
tarsin b84872aca2 Format code 2023-06-20 17:16:41 +08:00
tarsin 0ef4bccb7c Intercept okhttp request to cronet 2023-06-20 17:15:48 +08:00
tarsin dfc6c6a030 Let okhttp cronet converter handle cookies 2023-06-20 17:15:26 +08:00
tarsin b62f1d0c9f Add copy of okhttp cronet converter 2023-06-20 17:02:02 +08:00
tarsin 8abb5d9fb4 Add SwitchPref switch padding 2023-06-20 12:24:33 +08:00
tarsin 5f13725173 Handle #1157 [2/2] 2023-06-20 11:55:25 +08:00
tarsin 7f8b41f998 Handle #1157 [1/2] 2023-06-20 11:51:46 +08:00
FooIbar 1319060311 Drop some ViewUtils methods 2023-06-20 00:51:49 +08:00
FooIbar d1f914c2fa Convert SearchLayout to view binding 2023-06-20 00:51:49 +08:00
FooIbar 46cd1013fb Convert GalleryDetailScene to view binding 2023-06-20 00:51:49 +08:00
FooIbar 2ed516cf85 Convert SuggestionHolder to view binding 2023-06-20 00:51:49 +08:00
FooIbar 2ce55b4aef Convert GalleryCommentsScene to view binding 2023-06-20 00:51:49 +08:00
FooIbar df7071a22c Convert FavoritesScene to view binding 2023-06-20 00:51:49 +08:00
tarsin 707529972e Cleanup code 2023-06-19 11:28:54 +08:00
tarsin cf2796ebaa Add cronet temporarily for testing usage
We temporarily add cronet implementation to test the wrapper stability
Drop it when Android 14 release
2023-06-19 10:38:36 +08:00
tarsin 9611d81969 Include ktor proguard file 2023-06-19 01:37:58 +08:00
tarsin fb31f627a1 Update build.gradle.kts 2023-06-18 17:51:15 +08:00
tarsin 4741e4f858 Validate content length 2023-06-18 16:39:04 +08:00
tarsin b44ddf980b Cleanup code 2023-06-18 16:35:55 +08:00
tarsin 47b97243c3 Refine polling recycle 2023-06-18 16:33:54 +08:00
tarsin b695b06507 Pooling the bytebuffer 2023-06-18 16:30:18 +08:00
tarsin 110fb9fb59 Refine HttpEngineCoroutinizer 2023-06-18 16:13:54 +08:00
tarsin fe7c979d78 Cleanup HttpEngineCoroutinizer 2023-06-18 15:25:19 +08:00
tarsin 0d10899417 Initial support Android14 HttpEngine 2023-06-18 15:09:50 +08:00
tarsin ff89afb8c1 Fix fragment predictive back 2023-06-17 23:40:10 +08:00
tarsin 188248c634 Fix searchview predictive back 2023-06-17 23:30:01 +08:00
tarsin 0d3c942984 Fix navigation drawer predictive back 2023-06-17 23:26:22 +08:00
tarsin 2b520be693 Upgrade androidx activity 2023-06-17 23:22:34 +08:00
tarsin 4b831a2ee1 Support fragment predictive back 2023-06-17 23:19:32 +08:00
tarsin 59037d60e2 Revert "Revert "Revert "Update README.md"""
This reverts commit 61917285d5.
2023-06-17 22:01:57 +08:00
tarsin 61917285d5 Revert "Revert "Update README.md""
This reverts commit 6ccb59957d.
2023-06-17 17:56:45 +08:00
tarsin 453f77dd3e Upgrade androidx fragment 2023-06-17 17:42:18 +08:00
tarsin b40004d9ba Fix download crash on Android 14 2023-06-17 17:37:03 +08:00
tarsin f8f2d020eb Upgrade mdc for searchbar predictive back 2023-06-17 17:32:08 +08:00
tarsin 4f09de8a69 Refine warning 2023-06-17 16:51:37 +08:00
tarsin 2d20da70b8 Drop domain fronting and other network hacks since #1147 2023-06-17 16:37:51 +08:00
tarsin cf95e7b034 Upgrade compileSdk to 34 2023-06-17 15:01:33 +08:00
tarsin b5709a49f4 Fix padding 2023-06-16 20:59:46 +08:00
tarsin 75a7143442 Tweak GalleryDetailScene button layout 2023-06-16 20:57:52 +08:00
tarsin 3e47d82713 Spilt galleryList parser 2023-06-16 16:58:03 +08:00
tarsin 62f9361d25 Cleanup code 2023-06-16 16:52:19 +08:00
tarsin 3a97b93b6d Parse gid and token 2023-06-16 16:48:24 +08:00
tarsin 3b9850b90d Trim title 2023-06-16 16:26:30 +08:00
tarsin c0636e93c6 Refine rust gd parser 2023-06-16 16:22:55 +08:00
tarsin 5ff1131dee Improve home parser, avoid iter over whole text 2023-06-16 15:35:34 +08:00
tarsin 8aca589b0f Cleanup rust gd parser 2023-06-16 15:07:00 +08:00
tarsin 10f6bd4bf6 Refine rust gd parser 2023-06-16 15:01:11 +08:00
tarsin dbe84e8bda Refine rust gd parser 2023-06-16 14:29:44 +08:00
tarsin f4de403cdd Refresh libraries 2023-06-16 12:34:03 +08:00
tarsin 9024afed19 Strip unused regex feature 2023-06-16 12:21:51 +08:00
tarsin d8921377b3 Cleanup rust implementation 2023-06-16 01:35:16 +08:00
tarsin b80deafaa8 Cleanup home.rs 2023-06-16 00:22:54 +08:00
tarsin 506c63380a Spilt home.rs 2023-06-16 00:19:22 +08:00
tarsin 9e4fc2e7af Spilt torrent.rs 2023-06-16 00:16:58 +08:00
tarsin 0a8df26549 Add stub rust BaseGalleryInfo binding 2023-06-16 00:09:35 +08:00
tarsin d2bbd1b842 Tweak BaseGalleryInfo layout 2023-06-16 00:07:38 +08:00
tarsin 5974ce11a1 Build arm64 only if debug 2023-06-15 22:47:28 +08:00
tarsin 3ec700da56 Add f32 jni binding support 2023-06-15 20:33:14 +08:00
tarsin cb7b601f58 Revert "Drop fromJava impl and unused std impl"
This reverts commit 8e08a4881f.
2023-06-15 18:25:18 +08:00
tarsin 8e08a4881f Drop fromJava impl and unused std impl 2023-06-15 17:41:43 +08:00
tarsin 2fac1c8e4c Step to globally update to jni-rs 0.20.0 2023-06-15 15:43:37 +08:00
tarsin d240fb7e05 Add jnix for jni 0.21 upgrade 2023-06-15 14:43:50 +08:00
tarsin 326d378979 Cleanup package 2023-06-15 14:36:47 +08:00
tarsin 71f91bf054 Obtain jni_fn locally 2023-06-15 13:50:25 +08:00
tarsin 40e4d40683 Fix dependencies 2023-06-15 13:44:58 +08:00
tarsin c9d439e748 Obtain catch_panic, catch_panic_macros locally 2023-06-15 13:32:33 +08:00
tarsin 0ec90655c0 Specific jni-rs version 2023-06-15 13:13:47 +08:00
tarsin c6949cd09b Update rustup before compile 2023-06-15 13:00:32 +08:00
tarsin 1e47170c3b Refine rust jni parseLimit 2023-06-15 12:22:30 +08:00
tarsin b7d2e4e5da Cleanup code 2023-06-15 12:04:37 +08:00
tarsin 28c7a701ca Use jni signature generator 2023-06-15 11:56:57 +08:00
tarsin 52560b6b95 Catch rust panic 2023-06-15 11:52:02 +08:00
tarsin 1c2c18bff1 Cleanup rust binding 2023-06-15 05:06:12 +08:00
tarsin ed1603eec4 Update proguard-rules.pro 2023-06-15 04:25:36 +08:00
tarsin 2206dd85bc Use jnix 2023-06-15 04:13:01 +08:00
tarsin 62509e1500 Use lazy regex! marco 2023-06-14 20:59:11 +08:00
tarsin 56cad66aec Tweak cargo profile 2023-06-14 16:52:54 +08:00
tarsin 660d917f97 Unescape xml for favcat name 2023-06-14 16:34:10 +08:00
tarsin 0ca5572684 Do rustfmt, unescape xml 2023-06-14 16:29:39 +08:00
tarsin cbebdb542d Move torrent parser to rust 2023-06-14 16:20:18 +08:00
tarsin 84d13fe9c5 Cleanup rust code 2023-06-14 13:05:01 +08:00
tarsin c6919c39c6 Move favParser to rust 2023-06-14 12:41:44 +08:00
tarsin 92b6069654 Cleanup rust parser 2023-06-14 11:36:36 +08:00
tarsin 804dffc81a Cleanup rust parser 2023-06-14 10:30:07 +08:00
tarsin 5831761fc0 Drop logger for now 2023-06-12 15:42:42 +08:00
tarsin c887379b8b Ignore Cargo.lock as well 2023-06-12 15:39:35 +08:00
tarsin 82c92203b6 Initial refactor HomeParser with rust 2023-06-12 15:36:58 +08:00
tarsin 881948554e Cleanup buildscript 2023-06-12 12:05:05 +08:00
tarsin b0357201a5 Downgrade AGP to stable version 2023-06-12 11:58:48 +08:00
tarsin 7ddeaf6d16 Use cdylib and release profile for now 2023-06-12 11:07:11 +08:00
tarsin 942abd7dbb Add support for build rust dylib 2023-06-12 11:01:18 +08:00
tarsin 9f78b69390 Resolve #1136 2023-06-11 12:36:11 +08:00
tarsin 6e561ca9a9 Update r8 2023-06-10 17:15:55 +08:00
tarsin cec86576c1 Singletonize ReaderPreferences 2023-06-10 13:56:18 +08:00
tarsin 9eb8e984b6 Add chunker http inspector for debug usage 2023-06-09 19:00:03 +08:00
renovate[bot] 20798b5d25 Update plugin com.android.application to v8.1.0-beta05 2023-06-09 01:45:54 +00:00
tarsin 29fafdf216 Upgrade paging 2023-06-08 16:53:32 +08:00
tarsin 2fbda42e53 Cleanup CookiesDao 2023-06-08 16:26:49 +08:00
tarsin 285feb5f5b Cleanup EhCookieStore 2023-06-08 16:22:36 +08:00
tarsin cfdb8793c6 Cleanup EhCookieStore 2023-06-08 16:18:32 +08:00
tarsin 55b3753e66 Migrate cookies store to CookieManager backend 2023-06-08 16:11:48 +08:00
renovate[bot] ad04681460 Update dependency androidx.paging:paging-common-ktx to v3.2.0-beta01 2023-06-08 04:07:38 +00:00
renovate[bot] 2e132f06b7 Update nav_version to v2.7.0-beta01 2023-06-08 09:30:00 +08:00
renovate[bot] dc74266927 Update dependency androidx.core:core-ktx to v1.11.0-beta02 2023-06-07 21:39:55 +00:00
tarsin e002e15a66 Fix imagelimits dialog crash 2023-06-07 16:14:10 +08:00
tarsin e149c7065e Upgrade r8 2023-06-07 15:46:50 +08:00
tarsin 107a5ce626 Tweak package layout 2023-06-07 15:39:35 +08:00
tarsin b6d69f7a02 Tweak package layout 2023-06-07 15:36:56 +08:00
tarsin 6de6c89439 Tweak package layout 2023-06-07 15:35:16 +08:00
tarsin c1ca6dcd5d Tweak package layout 2023-06-07 15:31:33 +08:00
tarsin 223ebd6acd Flatten legacy view package 2023-06-07 15:28:47 +08:00
tarsin cc8311e116 Opt-in DataStorePreferencesPreview 2023-06-07 15:18:58 +08:00
tarsin a66f53e562 Trick to fix amoled mode 2023-06-07 15:13:08 +08:00
tarsin de699dacfe Subscribe show_tag_translations changes 2023-06-07 15:04:36 +08:00
tarsin 431007a731 Subscribe gallerysite changes 2023-06-07 15:02:24 +08:00
tarsin 797d511c2c Protect preferences need certain locales 2023-06-07 14:58:22 +08:00
tarsin 0c40be5da8 Protect preferences need signin 2023-06-07 14:55:33 +08:00
tarsin 2fc04caa05 Drop unused res 2023-06-07 14:48:23 +08:00
tarsin 78ffe38f54 Fix securityDelay pref summary 2023-06-07 14:45:19 +08:00
tarsin 8152a04155 Fix thumbResolution pref summary 2023-06-07 14:38:07 +08:00
tarsin 64b39275e2 Restore UConfigScreen applyTip 2023-06-07 14:33:21 +08:00
tarsin 23c6291cc8 Use mutableStateListOf, remove some recompose trigger 2023-06-07 14:29:22 +08:00
tarsin 60fe67b97a Restore filter tip 2023-06-07 14:22:28 +08:00
tarsin 96264a28a6 Fixup! Restore dialog to add filter 2023-06-07 13:51:47 +08:00
tarsin b86cb676d6 Restore dialog to add filter 2023-06-07 13:43:57 +08:00
tarsin a05fc8447d Restore dialog to delete filter 2023-06-07 13:28:45 +08:00
tarsin 68a617b952 FilterScreen optimize recompose 2023-06-06 23:48:14 +08:00
tarsin f18bfab35f FilterScreen appbar liftonScroll 2023-06-06 23:45:11 +08:00
tarsin c04f30a5b7 FilterScreen implementation part 4 2023-06-06 23:43:51 +08:00
tarsin 7a35d60b71 FilterScreen implementation part 3 2023-06-06 23:40:42 +08:00
tarsin cd3fa38161 FilterScreen implementation part 2 2023-06-06 23:34:33 +08:00
tarsin 6a65eabf28 FilterScreen implementation part 1 2023-06-06 23:29:55 +08:00
tarsin 0905a4dfba FilterScreen help message 2023-06-06 23:08:42 +08:00
tarsin c68c011e69 FilterScreen stub 2023-06-06 23:05:51 +08:00
tarsin a57066b6db Implement MyTagsScreen 2023-06-06 23:01:24 +08:00
tarsin 0b19cc71c9 Cleanup UConfigScreen 2023-06-06 22:48:55 +08:00
tarsin 38e6b60005 Cleanup UConfigScreen 2023-06-06 22:36:34 +08:00
tarsin 35a18ecc0f Navback after settings applied 2023-06-06 22:34:12 +08:00
tarsin 5fb2ec2fda Cleanup js apply 2023-06-06 22:31:27 +08:00
tarsin 61a2ae9431 Implement UConfigScreen 2023-06-06 22:23:36 +08:00
tarsin cba05171af Convert to use accompanist Webview 2023-06-06 21:54:25 +08:00
renovate[bot] 816d63e432 Update accompanist_version to v0.31.3-SNAPSHOT 2023-06-06 21:41:40 +08:00
tarsin 56c2e6fcde Import accompanist webview 2023-06-06 21:39:34 +08:00
tarsin d6aee24295 Remove Activity ref 2023-06-06 19:49:42 +08:00
tarsin 13b28c0f38 Introduce FINISH_ROUTE_NAME 2023-06-06 19:47:08 +08:00
tarsin 2f69b942d9 Cleanup SelectSiteScreen 2023-06-06 19:11:07 +08:00
tarsin 5977d77381 Navigate to SIGN_IN_ROUTE directly when signout 2023-06-06 19:04:01 +08:00
tarsin fe336ebf6a Fixup merge 2023-06-06 19:00:12 +08:00
tarsin c44776870e Merge LoginActivity & SettingsActivity 2023-06-06 18:54:29 +08:00
tarsin 67d5942aff Observe updateWhenRequestNewsChanges 2023-06-06 16:36:00 +08:00
tarsin 48e3b44658 Implement compose TimePickerDialog 2023-06-06 16:30:59 +08:00
tarsin 89347768b3 Fix codestyle 2023-06-06 15:50:33 +08:00
tarsin 2ed726427f Add AnimatedVisibility for preference dependency 2023-06-06 15:49:37 +08:00
tarsin 8ee20070b6 Add FilterScreen stub 2023-06-06 15:45:35 +08:00
tarsin ca9e1e93d9 Add MyTagsScreen stub 2023-06-06 15:43:28 +08:00
tarsin d9ea549b51 Add UConfigScreen stub 2023-06-06 15:38:48 +08:00
tarsin 0860bb488f [DO NOT USE] Restore ability to reset image limits 2023-06-06 15:23:53 +08:00
tarsin 8efc5401cb [DO NOT USE] Show Integer in slider 2023-06-06 14:36:29 +08:00
tarsin 13e5649948 [DO NOT USE] Add 2 missing preference 2023-06-06 14:33:08 +08:00
tarsin bb77c4ecfc [DO NOT USE] Introduce LauncherPreference 2023-06-06 14:06:07 +08:00
tarsin 3d16151bd2 [DO NOT USE] Fixup codestyle 2023-06-06 13:40:58 +08:00
tarsin 9053b200b2 [DO NOT USE] Restore copy notify 2023-06-06 01:24:31 +08:00
tarsin a450dd29f9 [DO NOT USE] Cleanup AccountPreference 2023-06-06 01:18:04 +08:00
tarsin 2f309fe9bb [DO NOT USE] Cleanup AccountPreference 2023-06-06 01:16:34 +08:00
tarsin 5f9f7d0ba7 [DO NOT USE] Restore AccountPreference 2023-06-06 01:13:59 +08:00
tarsin 6f1a08f2c7 [DO NOT USE] Introduce WorkPreference 2023-06-06 00:46:33 +08:00
tarsin 563f6810be [DO NOT USE] Merge object PreferenceTokens 2023-06-06 00:39:14 +08:00
tarsin 66ed7a04a4 [DO NOT USE] Cleanup preference default args 2023-06-06 00:38:04 +08:00
tarsin 626475a91f [DO NOT USE] Restore ability to clear redundancy 2023-06-06 00:34:11 +08:00
tarsin f99575771c [DO NOT USE] Restore ability to restore downloads 2023-06-06 00:28:21 +08:00
tarsin bc5a0f9140 [DO NOT USE] Fix to use Transition.None 2023-06-05 23:52:35 +08:00
tarsin 40958179ca [DO NOT USE] Use new navigation anim 2023-06-05 23:45:54 +08:00
tarsin d98006c2cd [DO NOT USE] Upgrade androidx navigation to 2.7.0-alpha01 2023-06-05 21:28:43 +08:00
tarsin 5134c9b378 [DO NOT USE] Observe theme changed 2023-06-05 19:04:31 +08:00
tarsin 1379953a9c [DO NOT USE] Inline setting keys 2023-06-05 18:45:14 +08:00
tarsin cc02b69020 [DO NOT USE] EhScreen implementation part 1 2023-06-05 18:42:16 +08:00
tarsin 55b4edac4d [DO NOT USE] Cleanup unused res and code 2023-06-05 18:18:27 +08:00
tarsin b56f136da0 [DO NOT USE] Introduce MutableState<T>.rememberedAccessor 2023-06-05 17:49:49 +08:00
tarsin d2b5e5ec01 [DO NOT USE] Tweak SimpleMenuPreferenceInt to receive a MutableState 2023-06-05 17:10:39 +08:00
tarsin 623ab63d8d [DO NOT USE] Introduce KMutableProperty0<T>.observed 2023-06-05 16:58:38 +08:00
tarsin 3b1beba570 [DO NOT USE] Implement DownloadScreen part 4 2023-06-05 16:05:38 +08:00
tarsin 4e6210c1f8 [DO NOT USE] Implement DownloadScreen part 3 2023-06-05 16:00:50 +08:00
tarsin 281154be7a [DO NOT USE] Implement DownloadScreen part 2 2023-06-05 15:55:07 +08:00
tarsin 9b4477766c [DO NOT USE] Implement DownloadScreen part 1 2023-06-05 15:45:02 +08:00
tarsin 53bbabab75 [DO NOT USE] Drop in-app proxy support 2023-06-05 15:32:51 +08:00
tarsin b1671eacb7 [DO NOT USE] Restore DOH support 2023-06-05 15:28:00 +08:00
tarsin b41e564411 [DO NOT USE] Import backupFav 2023-06-05 15:23:24 +08:00
tarsin 48e12154c3 [DO NOT USE] Fix db import 2023-06-05 15:17:05 +08:00
tarsin 5c25e2801c [DO NOT USE] Implement DB import 2023-06-05 14:51:12 +08:00
tarsin c2d2c1c4f6 [DO NOT USE] Implement DB export 2023-06-05 14:45:34 +08:00
tarsin 59959bb9ee [DO NOT USE] Migrate to datastore backend 2023-06-05 12:24:08 +08:00
tarsin 3664ca846c [DO NOT USE] Drop androidx preference, drop rikkax preference 2023-06-05 12:17:55 +08:00
tarsin 8c6d28d6e2 Make AndroidPreferenceStore use Settings backend 2023-06-05 12:09:36 +08:00
tarsin b3acd1d603 Implement openByDefault 2023-06-05 11:57:53 +08:00
tarsin d76e056b91 Implement dumpLogcatLauncher 2023-06-05 11:50:16 +08:00
tarsin 5de5dbabef AdvancedScreen placeholder 2023-06-05 11:19:09 +08:00
tarsin 866ea6369e Refine observed usage 2023-06-05 01:14:53 +08:00
tarsin ae2f7204fa Implement Compose SimpleMenuPreference 2 2023-06-05 01:09:41 +08:00
tarsin 5be2b77e42 Implement Compose SimpleMenuPreference 2023-06-05 00:55:49 +08:00
tarsin 8f1f76c3d1 Import DropDownPref 2023-06-05 00:31:56 +08:00
tarsin 6f488c1d00 Implement part of AdvancedScreen 2023-06-05 00:27:00 +08:00
tarsin ee7724e754 Create EhScreen, DownloadScreen stub 2023-06-05 00:19:18 +08:00
tarsin 6c4848b6f9 Apply applyPopAnimationsToPendingTransition globally 2023-06-05 00:15:31 +08:00
tarsin b6c36c20b6 Add stub AdvancedScreen 2023-06-05 00:13:21 +08:00
tarsin a29fc4ce94 Fix SliderPref enable status 2023-06-05 00:10:30 +08:00
tarsin 6490598fc3 Add IntSliderPreference 2023-06-05 00:05:25 +08:00
tarsin f3519f6f8a Import SliderPref 2023-06-04 23:53:42 +08:00
tarsin d44192079d Properly implement Preference 2023-06-04 23:39:33 +08:00
tarsin 140fac4f3b Stupid implementation of SwitchPreference 2023-06-04 17:33:01 +08:00
tarsin 802db256c1 Cleanup LicenseScreen 2023-06-04 16:58:10 +08:00
tarsin c8a9cfa8a3 Add SecurityScreen stub 2023-06-04 16:56:39 +08:00
tarsin 2213969c6e Fixup LicenseScreen padding 2023-06-04 16:51:45 +08:00
tarsin 524a3a94c4 Cleanup AboutScreen 2023-06-04 16:49:16 +08:00
tarsin 4ec58a0f62 Add standalone SpannedHelper 2023-06-04 16:43:01 +08:00
tarsin e25227e39d Add nestedScrollConnection 2023-06-04 16:38:28 +08:00
tarsin 7efaa64562 Implement AboutScreen 2023-06-04 16:30:49 +08:00
tarsin a2b95f6c61 AboutScreen stub 2023-06-04 15:32:32 +08:00
tarsin 9a6aa1a591 Cleanup PreferenceHeader implementation 2023-06-04 15:28:36 +08:00
tarsin de780635e4 Implement BaseScreen 2023-06-04 15:25:30 +08:00
tarsin 3dbb40967f Introduce BaseScreen 2023-06-04 14:54:59 +08:00
tarsin f39d17abc0 Introduce new compose SettingsActivity stub 2023-06-04 14:42:56 +08:00
tarsin a015e54569 Revert "Introduce KTLS based http downoader API stub"
This reverts commit a256864c84.
2023-06-03 22:16:51 +08:00
tarsin a256864c84 Introduce KTLS based http downoader API stub 2023-06-03 17:37:53 +08:00
tarsin d74b5bff7b Konvert AppConfig 2023-06-03 15:40:01 +08:00
tarsin 31e7943d22 Rename .java to .kt 2023-06-03 15:40:01 +08:00
tarsin b2d1660e95 Drop GetText 2023-06-03 15:06:42 +08:00
tarsin 5d13e29300 Cleanup unused res 2023-06-03 15:00:06 +08:00
tarsin aaf9ef06dd Rewrite ProgressScene with Jetpack Compose 2023-06-02 21:23:30 +08:00
tarsin 6725ef992a Drop Settings.initialize 2023-06-02 18:14:00 +08:00
tarsin b5baecf8d0 Singletonize EhProxySelector 2023-06-02 17:58:35 +08:00
tarsin 58d1ace612 Singletonize FavouriteStatusRouter 2023-06-02 17:55:40 +08:00
tarsin a4eca58275 Don't opt-in InternalCoroutinesApi 2023-06-02 15:53:18 +08:00
tarsin c97974eb72 Purify Settings 2023-06-02 15:47:11 +08:00
tarsin c46c386fea Move downloadLocation getter setter companion of DownloadManager 2023-06-02 15:43:10 +08:00
tarsin 3f4ca1bcbf Cleanup Settings code style 2023-06-02 15:35:34 +08:00
tarsin e4e04a4508 Cleanup Settings 2023-06-02 15:34:01 +08:00
tarsin 6d87dc0b1c Continue to cleanup Settings 2023-06-02 15:21:58 +08:00
tarsin db16a0c17c Cleanup Settings 2023-06-02 15:20:41 +08:00
tarsin 8fc411a30b Make Delegate private interface 2023-06-02 15:13:37 +08:00
tarsin c4a15f8e00 Optin ExperimentalSplittiesApi 2023-06-02 15:12:18 +08:00
tarsin 90e6918db0 Cleanup Settings 2023-06-02 15:09:40 +08:00
tarsin 62d7d09886 Inline launchPageGalleryListSceneAction 2023-06-02 15:03:34 +08:00
tarsin d9c933bd0a Inline thumbSize 2023-06-02 14:59:46 +08:00
tarsin 06c3e3c8a0 Fix downloadLocation scheme 2023-06-02 14:54:15 +08:00
tarsin f284ac71b5 Introduce stringArrayPref 2023-06-02 14:47:56 +08:00
tarsin cd969ac33b Introduce intArrayPref 2023-06-02 14:38:20 +08:00
tarsin ac43df5e03 Refine saveFromHttpResponse, avoid a buffer allocation 2023-06-02 14:14:21 +08:00
tarsin 8ea6417ea6 Refactor out interceptSecurityOrReturn 2023-06-02 13:49:49 +08:00
tarsin 19295e1d30 Refactor out lockObserver 2023-06-02 13:46:15 +08:00
tarsin f84b10f2eb Resolve #1124 2023-06-02 12:31:11 +08:00
tarsin 184edf9d4c Use splitties roomDb builder 2023-06-02 12:19:04 +08:00
tarsin 257e247e23 Inline listThumbSize 2023-06-01 21:10:47 +08:00
tarsin a2f0b4a64f Inline putPasswdToArchivePasswds 2023-06-01 21:08:26 +08:00
tarsin 9f1ec2be7e Inline intFrom 2023-06-01 21:05:22 +08:00
tarsin 046ba62256 Introduce intFromStrPref 2023-06-01 21:04:03 +08:00
tarsin c9f18b0b71 Convert to use intFromStrPref 2023-06-01 19:34:05 +08:00
tarsin b61e1bdbe3 Introduce intFromStrPref 2023-06-01 19:17:23 +08:00
tarsin 1a01caee2c Cleanup archivePasswds pref 2023-06-01 18:48:33 +08:00
tarsin 2fed610470 Cleanup listThumbSize pref 2023-06-01 18:39:36 +08:00
tarsin 2026843628 Inline some preference keys 2023-06-01 17:49:27 +08:00
tarsin 9997d31421 Inline some preference keys 2023-06-01 17:46:36 +08:00
tarsin 1079e4a759 Sort preferences by type 2023-06-01 17:40:44 +08:00
tarsin ce5c258cf9 Move some property to delegate 2023-06-01 17:36:06 +08:00
tarsin c1b76b35ec Move some property to delegate 2023-06-01 17:28:22 +08:00
tarsin e9cb083672 Move some property to delegate 2023-06-01 17:16:23 +08:00
tarsin 034a5c2071 Move some property to delegate 2023-06-01 17:07:57 +08:00
tarsin 6c7e3019ff Import splitties preferences 2023-06-01 16:56:23 +08:00
tarsin fc02902ccb Restore LongClick HapticFeedback 2023-06-01 16:17:59 +08:00
tarsin f33ff6d380 Use Splitties systemServices 2023-06-01 16:13:37 +08:00
tarsin 2c30deb298 Use Splitties appCtx 2023-06-01 15:48:45 +08:00
tarsin 6ea635a1e9 Resolve #1122 2023-05-31 23:21:59 +08:00
tarsin 858134927a Resolve #1122 2023-05-31 21:38:52 +08:00
tarsin 0eec51ef8e Revert "Resolve #1122"
This reverts commit de065076df.
2023-05-31 21:28:45 +08:00
tarsin de065076df Resolve #1122 2023-05-31 18:51:22 +08:00
tarsin ad4c418736 Resolve #1121 2023-05-31 18:37:45 +08:00
tarsin 9ab368a760 Workaround download in UIContext 2023-05-31 18:00:50 +08:00
tarsin 59f3cf20a5 Introduce DialogState.doGalleryInfoAction 2023-05-31 17:57:24 +08:00
tarsin 8a58b6ee0f Move to DialogState.showMoveDownloadLabel impl 2023-05-31 17:45:28 +08:00
tarsin d6816c89e5 Refactor compose dialog 2023-05-31 17:02:32 +08:00
tarsin 7ca37ee54a Tweak prefetchDistance 2023-05-31 14:46:32 +08:00
tarsin 4b4304629f Fix previewScene jump 2023-05-31 14:36:32 +08:00
tarsin dba557b942 Fix codestyle 2023-05-31 13:50:37 +08:00
tarsin fe158e7f62 Tweak DialogScope 2023-05-31 13:47:53 +08:00
tarsin ac7fed649a Implement dialogState.confirmRemoveDownload 2023-05-31 13:25:23 +08:00
tarsin cb67a51686 Move DialogState.selectGalleryInfoAction to CommonOperations 2023-05-31 12:42:50 +08:00
tarsin 4d85a2aa41 Resolve #1120 2023-05-31 12:29:29 +08:00
tarsin 0df875d65a Upgrade AGP 2023-05-31 12:17:06 +08:00
tarsin fff1ec0947 Downgrade AGP to stable version 2023-05-31 12:06:14 +08:00
tarsin 250a7ef25e Update build.gradle.kts 2023-05-31 02:16:30 +08:00
tarsin 805d22802c Update build.gradle.kts 2023-05-31 02:14:20 +08:00
tarsin 9745ce7d34 Update build.gradle.kts 2023-05-31 01:55:27 +08:00
tarsin c165c15099 Upgrade AGP 2023-05-31 01:28:03 +08:00
tarsin 351231aab9 Delegate all reader call to Context.navToReader 2023-05-31 01:10:08 +08:00
tarsin 0e78494f39 Cleanup code 2023-05-31 00:52:13 +08:00
tarsin 886ce38543 Drop SelectItemWithIconAdapter 2023-05-31 00:46:52 +08:00
tarsin f542c8a12e Inline NoHistory 2023-05-31 00:27:07 +08:00
tarsin c35cac860f Cleanup showSelectItemWithIcon implementation 2023-05-31 00:25:24 +08:00
tarsin afcdc5ec5b Fix typo 2023-05-30 23:58:04 +08:00
tarsin b9f24001ed Move to showSelectItemWithIcon impl 2023-05-30 23:55:40 +08:00
tarsin 1f0319c242 Tweak showSelectItemWithIcon style 2023-05-30 23:49:29 +08:00
tarsin 5e8e95f716 Introduce DialogScope.showSelectItemWithIcon 2023-05-30 23:41:19 +08:00
tarsin dd73b20b3f Konvert ShortcutsActivity 2023-05-30 21:41:59 +08:00
tarsin c6a83ac6b2 Rename .java to .kt 2023-05-30 21:41:59 +08:00
tarsin 6ea7a1405f Cleanup unused code 2023-05-30 21:37:47 +08:00
tarsin 774db8d3a4 Always merge requests when preloadThumbAggressively 2023-05-30 21:26:19 +08:00
tarsin a7187d62d3 Konvert ImageLoader.Builder 2023-05-30 21:24:36 +08:00
tarsin e5788b9ec5 Cleanup EhApplication 2023-05-30 21:20:36 +08:00
tarsin be96491091 Introduce idiomatic OkHttp builders 2023-05-30 21:17:36 +08:00
tarsin ea0b83476f Konvert FavouriteStatusRouter 2023-05-30 20:41:14 +08:00
tarsin 187f77d32f Rename .java to .kt 2023-05-30 20:41:14 +08:00
tarsin 46655e3326 Move builtInHosts to Standalone EhHostsConfig 2023-05-30 20:35:32 +08:00
tarsin 4f1615b736 Cleanup EhRequestBuilder 2023-05-30 20:30:50 +08:00
tarsin 8b3ab44c1c Cleanup EhSSLSocketFactory 2023-05-30 20:27:45 +08:00
tarsin 10b6258175 Only make large blob downloading sensitive for cancelling 2023-05-30 20:17:40 +08:00
tarsin 13b532c12a Revert "Fix usingCancellable with null ret value"
This reverts commit d464d00067.
2023-05-30 20:16:02 +08:00
tarsin 126f4238d6 Fix DownloadsScene lag 2023-05-30 18:18:30 +08:00
tarsin 9666feac57 Cleanup downloadManager ref in DownloadsScene 2023-05-30 17:43:57 +08:00
tarsin d464d00067 Fix usingCancellable with null ret value 2023-05-29 20:04:15 +08:00
tarsin 6e96571cc8 Cleanup UrlBuilder with HttpUrl 2023-05-29 19:58:56 +08:00
tarsin 2b70c983bf Document Call.usingCancellable 2023-05-29 17:41:59 +08:00
tarsin 3a2c18d8a9 Refine saveFromHttpResponse 2023-05-29 17:24:34 +08:00
tarsin 29fb40eecc Introduce Call.usingCancellable 2023-05-29 17:02:46 +08:00
tarsin 684d25780e Introduce runInterruptibleOkio 2023-05-29 16:03:41 +08:00
tarsin 51a292e5d0 Use runInterruptible for more sensitive cancellation 2023-05-29 15:36:35 +08:00
tarsin 4f99107ac5 Tweak DF configs 2023-05-28 20:33:44 +08:00
tarsin e4685c7018 Log DoH lookup failure 2023-05-28 19:26:17 +08:00
tarsin 6a42793a59 Fixup! Implement custom DoH 2023-05-28 19:08:02 +08:00
tarsin 4a81df4174 Implement custom DoH 2023-05-28 19:04:28 +08:00
tarsin 512e961820 Add DohPreference 2023-05-28 18:37:50 +08:00
tarsin cbccf7e7fa Add dohUrl settings entry 2023-05-28 17:54:26 +08:00
tarsin f1890c2d3e Cleanup Settings 2023-05-28 17:48:56 +08:00
tarsin 0c30b20a66 Add doh module 2023-05-28 17:43:36 +08:00
tarsin 14b3f13338 Use AndroidAsyncDns 2023-05-28 17:34:00 +08:00
tarsin 0f75f5ec69 Tweak hosts config 2023-05-28 13:57:39 +08:00
tarsin bdbc5438aa Fixup code style 2023-05-28 13:56:51 +08:00
tarsin 525131dbaf Update EhDns.kt 2023-05-28 01:29:08 +08:00
tarsin f8938a46bb Fix naming 2023-05-28 01:18:58 +08:00
tarsin 50ce18d201 Fix codestyle 2023-05-28 01:14:56 +08:00
tarsin bba06321c8 Introduce hostDSL 2023-05-28 01:13:22 +08:00
tarsin 3439b684e1 Drop ip parser 2023-05-28 00:37:30 +08:00
tarsin 0ffba596e5 Cleanup Obsolete db 2023-05-27 23:52:25 +08:00
tarsin c112322daf Drop custom hosts 2023-05-27 23:46:00 +08:00
tarsin a942a487a0 Drop buildMainDB 2023-05-27 22:53:24 +08:00
tarsin 7f02c27a3a Rename EhDatabase to Database 2023-05-27 22:51:37 +08:00
tarsin a69edd5c55 Move CookiesDatabase out of EhDatabase 2023-05-27 22:50:52 +08:00
tarsin f8a0d8b9c5 Move searchDatabase out of EhDatabase 2023-05-27 22:49:12 +08:00
tarsin a7214740ec Avoid mainthread db query 2023-05-27 20:01:26 +08:00
tarsin 17fb0f724c Fix SearchDatabase query 2023-05-27 19:56:38 +08:00
tarsin 5e14dad961 Initial migrate SearchDatabase to ROOM 2023-05-27 19:27:01 +08:00
tarsin dc48363398 Dedup dependencies 2023-05-27 13:02:46 +08:00
tarsin df4a8ec15e Cleanup codestyle 2023-05-27 12:53:03 +08:00
tarsin 810e3ff5fe Use suggestion chip 2023-05-27 12:49:54 +08:00
tarsin aef065a057 Allow open license dialog when badge clicked 2023-05-27 12:41:36 +08:00
tarsin 1824786a80 Open website by default when library item clicked 2023-05-27 01:26:34 +08:00
tarsin c8b7fed168 Drop autogenerated json 2023-05-27 01:19:40 +08:00
tarsin 4118390283 Use tertiaryContainer for badge container 2023-05-27 01:09:59 +08:00
tarsin 13a9fd36d3 Sort libraries by name 2023-05-27 01:03:11 +08:00
tarsin 9ad933934f Add LicenseFragment 2023-05-27 00:55:03 +08:00
tarsin 92240c6c2c Improve MergeInterceptor, only merge normal preview requests 2023-05-26 18:43:40 +08:00
tarsin 689a78d2ee Improve MergeInterceptor 2023-05-26 18:01:45 +08:00
tarsin 7ed0b93faa Cleanup code 2023-05-26 17:37:55 +08:00
tarsin 3a004c41f8 Refactor db export with resourceDSL 2023-05-26 17:15:11 +08:00
tarsin 90ed83efd5 Refactor db import with resourceDSL 2023-05-26 16:58:18 +08:00
tarsin 3a2ccf86fd Fix database import 2023-05-26 16:36:39 +08:00
tarsin 4e6f906903 Convert ThumbKeyMigration to AutoMigrationSpec 2023-05-26 16:27:22 +08:00
tarsin c73ca48e35 Add db v4 schemas 2023-05-26 16:12:55 +08:00
tarsin e1d7b3132d Drop BookmarksDao, upgrade db 2023-05-26 16:02:32 +08:00
tarsin 1f4f99079b Sync with 1.8.8.3 VC 2023-05-26 15:48:03 +08:00
tarsin bf495336d9 Fixup aa1e2102fc 2023-05-26 15:44:55 +08:00
tarsin cc636bcae0 Nonnullize and Immutablize DownloadDirname, upgrade db 2023-05-26 15:44:00 +08:00
tarsin cf185a6148 Export dao schemas 2023-05-26 15:29:16 +08:00
tarsin f92ce637bf Fixup unsafe Composable behaviour 2023-05-26 15:22:50 +08:00
tarsin 2a34d6eb8b Workaround aspect is NaN, Resolve #1116 2023-05-26 15:13:45 +08:00
tarsin a8e3f67371 Fix wrong thumb crop behaviour 2023-05-26 14:59:03 +08:00
tarsin 4a7d4dedd0 Sync with 1.8.8.2 VC 2023-05-26 14:36:55 +08:00
tarsin 7d3178015b Fixup! Resolve #1113 2023-05-26 14:34:58 +08:00
tarsin 54079990d0 Sync with 1.8.8.1 versionCode 2023-05-26 13:48:41 +08:00
tarsin a379391862 Resolve #1113 2023-05-26 13:43:07 +08:00
tarsin dfb2fbf88b Hello, K2! 2023-05-25 16:23:05 +08:00
tarsin 68f201980a Upgrade Kotlin 1.9.0-Beta 2023-05-25 16:14:35 +08:00
tarsin 9a079083e9 Prepare next development iteration 2023-05-25 15:39:16 +08:00
renovate[bot] 1ee1b122fe Update dependency dev.chrisbanes.compose:compose-bom to v2023.04.00-SNAPSHOT 2023-05-25 15:37:48 +08:00
tarsin 25d4d5e393 Bump to 1.8.8.0
Releases / Build (push) Has been cancelled
2023-05-25 15:33:07 +08:00
tarsin 1743caa869 Remove unused padding 2023-05-25 15:13:27 +08:00
tarsin 958fdb19b4 Revert "Decode cf protected email, step 1"
This reverts commit d44981a70c.
2023-05-25 15:02:14 +08:00
tarsin 4b63648a79 Revert "Decode cf protected email, step 2, Resolve #1102"
This reverts commit 74c6bfa479.
2023-05-25 15:02:00 +08:00
tarsin 498b84df37 Revert "Optimize code"
This reverts commit 6ed3fb29d9.
2023-05-25 15:01:49 +08:00
tarsin 7a4e65259d Revert "Uniform html parse behaviour"
This reverts commit c5c1170383.
2023-05-25 15:01:38 +08:00
tarsin 8cb8dcbe0f Resolve #1067 2023-05-25 14:16:13 +08:00
tarsin da37b3cdff Upgrade compose bom 2023-05-25 13:44:10 +08:00
renovate[bot] 0a1768e481 Update dependency androidx.core:core-ktx to v1.11.0-beta01 2023-05-25 13:41:57 +08:00
renovate[bot] 818d16a32d Update dependency androidx.paging:paging-common-ktx to v3.2.0-alpha06 2023-05-25 13:41:03 +08:00
renovate[bot] e9a5d1cc7c Update dependency androidx.paging:paging-compose to v1.0.0-alpha20 2023-05-25 13:40:19 +08:00
renovate[bot] dac56f3e32 Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.0-alpha10 2023-05-25 03:55:42 +00:00
renovate[bot] d6cbcdc6cd Update dependency androidx.activity:activity-compose to v1.7.2 2023-05-25 01:29:39 +00:00
tarsin c5c1170383 Uniform html parse behaviour 2023-05-24 20:12:24 +08:00
tarsin 6ed3fb29d9 Optimize code 2023-05-24 19:28:55 +08:00
tarsin 74c6bfa479 Decode cf protected email, step 2, Resolve #1102 2023-05-24 19:19:47 +08:00
tarsin d44981a70c Decode cf protected email, step 1 2023-05-24 18:51:22 +08:00
tarsin 06e411d332 Fixup! Rewrite LauncherUtils 2023-05-23 13:44:32 +08:00
tarsin f419189749 Rewrite LauncherUtils 2023-05-23 13:11:57 +08:00
tarsin aa1e2102fc Fix deprecated coil API 2023-05-22 21:53:59 +08:00
tarsin 306ce9ed21 Always use ImageDecoderDecoder for better performance 2023-05-22 12:33:12 +08:00
renovate[bot] 544fcb2e88 Update dependency io.coil-kt:coil-compose to v2.4.0 2023-05-21 21:44:29 +00:00
tarsin cb01df4071 Revert "Update dependency dev.chrisbanes.compose:compose-bom to v2023.04.00-SNAPSHOT"
This reverts commit 38310b7c5a.
2023-05-21 10:42:08 +08:00
renovate[bot] 38310b7c5a Update dependency dev.chrisbanes.compose:compose-bom to v2023.04.00-SNAPSHOT 2023-05-20 19:21:10 +00:00
tarsin fcd56ff4e9 Use compose-bom 2023.04.00-alpha04 for reproducible artifact 2023-05-21 00:16:58 +08:00
tarsin 41300a9fd4 Fix okhttp dependency 2023-05-21 00:12:28 +08:00
tarsin 0bd5f9dc31 Downgrade ArrowKt to stable release for reproducible artifacts 2023-05-21 00:11:10 +08:00
tarsin 004ecd0dd3 Resolve #1095 2023-05-21 00:06:56 +08:00
871 changed files with 46277 additions and 55611 deletions

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
[*.{kt,kts}]
ij_kotlin_imports_layout = *
ktlint_code_style = intellij_idea
ktlint_function_naming_ignore_when_annotated_with = Composable
ktlint_standard_class-signature = disabled
+1
View File
@@ -0,0 +1 @@
*.sh eol=lf
+14 -11
View File
@@ -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
@@ -64,7 +64,7 @@ body:
description: 您可以通过设置-高级-导出日志来获得日志文件 / You can get logs file in Settings - Advanced - Dump logcat
placeholder: 06-15 17:44:53.704 23382 23382 E ...
validations:
required: false
required: true
- type: textarea
id: more
@@ -79,6 +79,15 @@ body:
validations:
required: false
- type: input
id: site
attributes:
label: 浏览站点 / Browsing site
description: E-Hentai / ExHentai
placeholder: E-Hentai
validations:
required: true
- type: input
id: version
attributes:
@@ -132,17 +141,11 @@ body:
请确认您已经遵守所有必选项
Please ensure you have obtained all needed options
options:
- label: 如果您有足够的时间和能力,并愿意为此提交 PR ,请勾上此复选框 / Pull request is welcome. Check this if you want to start a pull request
required: false
- label: 您已仔细查看并知情 [Q&A](https://github.com/Ehviewer-Overhauled/Ehviewer/issues/61) 中的内容 / You have checked [Q&A](https://github.com/Ehviewer-Overhauled/Ehviewer/issues/61) carefully
required: true
- label: 您已搜索过 [Issue Tracker](https://github.com/Ehviewer-Overhauled/Ehviewer/issues),没有找到类似内容 / I have searched on [Issue Tracker](https://github.com/Ehviewer-Overhauled/Ehviewer/issues), No duplicate or related open issue has been found
- label: 您已搜索过 [Issue Tracker](https://github.com/FooIbar/EhViewer/issues),没有找到类似内容 / I have searched on [Issue Tracker](https://github.com/FooIbar/EhViewer/issues), No duplicate or related open issue has been found
required: true
- 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
+1 -5
View File
@@ -1,5 +1 @@
blank_issues_enabled: false
contact_links:
- name: 所有其他问题 / All other questions
url: https://github.com/Ehviewer-Overhauled/Ehviewer/discussions
about: 转到 Discussions / Turn to discussions
blank_issues_enabled: false
@@ -1,94 +0,0 @@
name: 功能请求 / Feature request
description: 提出一个功能建议 / Suggest an idea
labels:
- "enhancement"
body:
- type: markdown
attributes:
value: |
感谢您愿意为 Ehviewer-Overhauled 做出贡献!
提交功能建议前,还请首先完成文末的自查步骤
Thanks for your contribution on Ehviewer-Overhauled Project!
Please finish verify steps which list in the end first before suggest an idea
- type: textarea
id: request
attributes:
label: 需求 / Requirement
description: |
在此处描述您的需求。这通常会是一个您想要的功能
Ddescribe what you need here.
placeholder: |
我需要 XXX 功能 ...
I want ABC feature ...
validations:
required: true
- type: textarea
id: impl
attributes:
label: 建议实现 / Suggested implements
description: |
在此处表述您建议的实现方式。如有可能,UI 类功能请求还请尽量附上图示
Describe your suggested implements here, It's recommend to add a photo if you are making a UI feature request.
placeholder: |
建议在 XX 处添加 XX ...
I recommend add ABC feature to DEF...
图片(如果有)/ Photos (if exists)
validations:
required: true
- type: textarea
id: more
attributes:
label: 备注 / Addition details
description: |
在此处写下其他您想说的内容
Describe addition details here
placeholder: |
其他有用的信息与附件
Additional details and attachments
validations:
required: false
- type: input
id: version
attributes:
label: EhViewer 版本号 / EhViewer version code
description: 您可以在设置 - 关于处找到版本号 / You can get version code in Settings - About
placeholder: 1.6.9.13
validations:
required: true
- type: input
id: ci
attributes:
label: EhViewer CI 版本 / EhViewer CI Version
description: 位于设置 - 关于中的版本号后 / Next to the version code in Settings - About
placeholder: 26f05a0
validations:
required: true
- type: checkboxes
id: check
attributes:
label: 自查步骤 / Verify steps
description: |
请确认您已经遵守所有必选项
Please ensure you have obtained all needed options
options:
- label: 如果您有足够的时间和能力,并愿意为此提交 PR ,请勾上此复选框 / Pull request is welcome. Check this if you want to start a pull request
required: false
- label: 您已仔细查看并知情 [Q&A](https://github.com/Ehviewer-Overhauled/Ehviewer/issues/61) 中的内容 / You have checked [Q&A](https://github.com/Ehviewer-Overhauled/Ehviewer/issues/61) carefully
required: true
- label: 您已搜索过 [Issue Tracker](https://github.com/Ehviewer-Overhauled/Ehviewer/issues),没有找到类似内容 / I have searched on [Issue Tracker](https://github.com/Ehviewer-Overhauled/Ehviewer/issues), No duplicate or related open issue has been found
required: true
- label: 您确保这个 Issue 只提及一个功能。如果您有多个功能请求,烦请发起多个 Issue / Ensure there is only one feature request in this issue. Please make mutiply issue for mutiply feature request
required: true
- label: 您确保已使用最新 CI 版本测试,并且该功能在最新 CI 版本中并未按照预期实现 / This feature don't implement correctly in latest CI version
required: true
+161 -44
View File
@@ -4,65 +4,182 @@ on:
push:
branches:
- '*'
tags-ignore:
- "*"
pull_request:
workflow_dispatch:
jobs:
linux:
name: Build
check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'recursive'
uses: actions/checkout@v4
- name: Setup Java 17
uses: actions/setup-java@v3
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
java-version: 21
- name: Install NDK
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;25.2.9519653" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- name: Install Rust Toolchain
run: rustup default 1.81.0 && rustup target add armv7-linux-androideabi aarch64-linux-android x86_64-linux-android && rustup component add rustfmt clippy
- name: Ktlint Check
run: ./gradlew ktlintCheck
- name: Gradle Build
uses: gradle/gradle-build-action@v2
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
gradle-home-cache-cleanup: true
arguments: assembleRelease
workspaces: "./app/src/main/rust"
shared-key: ${{ runner.os }}
- 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: Rustfmt Check
working-directory: ./app/src/main/rust
run: cargo fmt --all -- --check
- 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: Clippy Check
working-directory: ./app/src/main/rust
run: cargo clippy --target aarch64-linux-android --all-features -- -D warnings
- name: Update ARM32
uses: actions/upload-artifact@v3
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
name: armeabi-v7a-${{ github.sha }}
path: app/build/outputs/apk/release/app-armeabi-v7a-release.apk
cache-read-only: true
- name: Update x86
uses: actions/upload-artifact@v3
with:
name: x86-${{ github.sha }}
path: app/build/outputs/apk/release/app-x86-release.apk
- name: Spotless Check
run: ./gradlew spotlessCheck
- name: Update mapping
uses: actions/upload-artifact@v3
- name: Lint Check
run: ./gradlew lintMarshmallowRelease
default:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
name: mapping-${{ github.sha }}
path: app/build/outputs/mapping/release/mapping.txt
retention-days: 5
distribution: temurin
java-version: 21
- name: Install Rust Toolchain
run: rustup default 1.81.0 && rustup target add armv7-linux-androideabi aarch64-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"
shared-key: ${{ runner.os }}
save-if: "false"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GradleEncryptionKey }}
- name: CMake Cache
uses: actions/cache@v4
with:
path: app/.cxx
key: cmake-default-${{ hashFiles('settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
restore-keys: cmake-default-
- name: Build
run: ./gradlew assembleDefaultRelease
- name: Upload ARM64
uses: actions/upload-artifact@v4
with:
name: default-arm64-v8a-${{ github.sha }}
path: app/build/outputs/apk/default/release/app-default-arm64-v8a-release.apk
- name: Upload x86_64
uses: actions/upload-artifact@v4
with:
name: default-x86_64-${{ github.sha }}
path: app/build/outputs/apk/default/release/app-default-x86_64-release.apk
- name: Upload ARM32
uses: actions/upload-artifact@v4
with:
name: default-armeabi-v7a-${{ github.sha }}
path: app/build/outputs/apk/default/release/app-default-armeabi-v7a-release.apk
- name: Upload mapping
if: always()
uses: actions/upload-artifact@v4
with:
name: default-mapping-${{ github.sha }}
path: app/build/outputs/mapping/defaultRelease
- name: Upload native debug symbols
uses: actions/upload-artifact@v4
with:
name: default-native-debug-symbols-${{ github.sha }}
path: app/build/outputs/native-debug-symbols/defaultRelease/native-debug-symbols.zip
marshmallow:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Install Rust Toolchain
run: rustup default 1.81.0 && rustup target add armv7-linux-androideabi aarch64-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"
shared-key: ${{ runner.os }}
save-if: "false"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GradleEncryptionKey }}
- name: CMake Cache
uses: actions/cache@v4
with:
path: app/.cxx
key: cmake-marshmallow-${{ hashFiles('settings.gradle.kts', 'app/src/main/cpp/CMakeLists.txt', 'app/src/main/rust/Cargo.lock') }}
restore-keys: cmake-marshmallow-
- name: Build
run: ./gradlew assembleMarshmallowRelease
- name: Upload ARM64
uses: actions/upload-artifact@v4
with:
name: marshmallow-arm64-v8a-${{ github.sha }}
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-arm64-v8a-release.apk
- name: Upload x86_64
uses: actions/upload-artifact@v4
with:
name: marshmallow-x86_64-${{ github.sha }}
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-x86_64-release.apk
- name: Upload ARM32
uses: actions/upload-artifact@v4
with:
name: marshmallow-armeabi-v7a-${{ github.sha }}
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-armeabi-v7a-release.apk
- name: Upload mapping
if: always()
uses: actions/upload-artifact@v4
with:
name: marshmallow-mapping-${{ github.sha }}
path: app/build/outputs/mapping/marshmallowRelease
- name: Upload native debug symbols
uses: actions/upload-artifact@v4
with:
name: marshmallow-native-debug-symbols-${{ github.sha }}
path: app/build/outputs/native-debug-symbols/marshmallowRelease/native-debug-symbols.zip
+21
View File
@@ -0,0 +1,21 @@
name: 'Lock Threads'
on:
schedule:
- cron: '0 8 * * *'
workflow_dispatch:
permissions:
issues: write
concurrency:
group: lock-threads
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
with:
issue-inactive-days: '1'
process-only: 'issues'
-55
View File
@@ -1,55 +0,0 @@
name: Pull Request Check
on: [pull_request]
jobs:
linux:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
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;25.2.9519653" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- 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
+65 -48
View File
@@ -6,68 +6,85 @@ on:
- "*"
jobs:
linux:
name: Build
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Free disk space
run: rm -rf $AGENT_TOOLSDIRECTORY
- name: Setup Java 17
uses: actions/setup-java@v3
- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
java-version: 21
- name: Install NDK
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;25.2.9519653" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
- name: Install Rust Toolchain
run: rustup default 1.81.0 && rustup target add armv7-linux-androideabi aarch64-linux-android x86_64-linux-android
- name: Gradle Build
uses: gradle/gradle-build-action@v2
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
arguments: assembleRelease
workspaces: "./app/src/main/rust"
- name: CMake Cache
uses: actions/cache/restore@v4
with:
path: app/.cxx
key: cmake-
restore-keys: cmake-
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
cache-encryption-key: ${{ secrets.GradleEncryptionKey }}
- name: Generate Baseline Profile
run: ./gradlew generateBaselineProfile
-Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
- name: Build
run: ./gradlew assembleRelease
- name: Rename Apks
run: |
cp app/build/outputs/apk/release/app-universal-release.apk app/build/outputs/apk/release/EhViewer-universal.apk
cp app/build/outputs/apk/release/app-arm64-v8a-release.apk app/build/outputs/apk/release/EhViewer-arm64-v8a.apk
cp app/build/outputs/apk/release/app-x86_64-release.apk app/build/outputs/apk/release/EhViewer-x86_64.apk
cp app/build/outputs/apk/release/app-x86-release.apk app/build/outputs/apk/release/EhViewer-x86.apk
cp app/build/outputs/apk/release/app-armeabi-v7a-release.apk app/build/outputs/apk/release/EhViewer-armeabi-v7a.apk
mv app/build/outputs/apk/default/release/app-default-universal-release.apk EhViewer-${{ github.ref_name }}-default-universal.apk
mv app/build/outputs/apk/default/release/app-default-arm64-v8a-release.apk EhViewer-${{ github.ref_name }}-default-arm64-v8a.apk
mv app/build/outputs/apk/default/release/app-default-x86_64-release.apk EhViewer-${{ github.ref_name }}-default-x86_64.apk
mv app/build/outputs/apk/default/release/app-default-armeabi-v7a-release.apk EhViewer-${{ github.ref_name }}-default-armeabi-v7a.apk
mv app/build/outputs/mapping/defaultRelease/mapping.txt EhViewer-${{ github.ref_name }}-default-mapping.txt
mv app/build/outputs/native-debug-symbols/defaultRelease/native-debug-symbols.zip EhViewer-${{ github.ref_name }}-default-native-debug-symbols.zip
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-universal-release.apk EhViewer-${{ github.ref_name }}-marshmallow-universal.apk
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-arm64-v8a-release.apk EhViewer-${{ github.ref_name }}-marshmallow-arm64-v8a.apk
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-x86_64-release.apk EhViewer-${{ github.ref_name }}-marshmallow-x86_64.apk
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-armeabi-v7a-release.apk EhViewer-${{ github.ref_name }}-marshmallow-armeabi-v7a.apk
mv app/build/outputs/mapping/marshmallowRelease/mapping.txt EhViewer-${{ github.ref_name }}-marshmallow-mapping.txt
mv app/build/outputs/native-debug-symbols/marshmallowRelease/native-debug-symbols.zip EhViewer-${{ github.ref_name }}-marshmallow-native-debug-symbols.zip
- name: Releases
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
body: Bump Version
discussion_category_name: Announcements
files: |
app/build/outputs/apk/release/EhViewer-universal.apk
app/build/outputs/apk/release/EhViewer-arm64-v8a.apk
app/build/outputs/apk/release/EhViewer-x86_64.apk
app/build/outputs/apk/release/EhViewer-x86.apk
app/build/outputs/apk/release/EhViewer-armeabi-v7a.apk
app/build/outputs/mapping/release/mapping.txt
EhViewer-${{ github.ref_name }}-default-universal.apk
EhViewer-${{ github.ref_name }}-default-arm64-v8a.apk
EhViewer-${{ github.ref_name }}-default-x86_64.apk
EhViewer-${{ github.ref_name }}-default-armeabi-v7a.apk
EhViewer-${{ github.ref_name }}-default-mapping.txt
EhViewer-${{ github.ref_name }}-default-native-debug-symbols.zip
- name: Collect Apks
run: |
mkdir app/build/outputs/apk/release/fdroid
cp app/build/outputs/apk/release/app-arm64-v8a-release.apk app/build/outputs/apk/release/fdroid/EhViewer-v$GITHUB_REF_NAME.apk
cp app/build/outputs/apk/release/app-armeabi-v7a-release.apk app/build/outputs/apk/release/fdroid/EhViewer-v$GITHUB_REF_NAME-armv7.apk
- name: Push Apks
uses: Ehviewer-Overhauled/github-action-push-to-another-repository@main
env:
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
with:
source-directory: app/build/outputs/apk/release/fdroid
destination-github-username: Ehviewer-Overhauled
destination-repository-name: fdroid-repo
user-name: 'github-actions[bot]'
user-email: 'github-actions[bot]@users.noreply.github.com'
target-branch: deploy
create-target-branch: true
commit-message: Add apks from $GITHUB_REF
target-directory: fdroid/tmp-apks
EhViewer-${{ github.ref_name }}-marshmallow-universal.apk
EhViewer-${{ github.ref_name }}-marshmallow-arm64-v8a.apk
EhViewer-${{ github.ref_name }}-marshmallow-x86_64.apk
EhViewer-${{ github.ref_name }}-marshmallow-armeabi-v7a.apk
EhViewer-${{ github.ref_name }}-marshmallow-mapping.txt
EhViewer-${{ github.ref_name }}-marshmallow-native-debug-symbols.zip
+1 -3
View File
@@ -2,9 +2,7 @@
/local.properties
.DS_Store
/build
/src
/.kotlin
*.iml
.idea
/captures
release
google-services.json
-3
View File
@@ -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
+431
View File
@@ -0,0 +1,431 @@
# 变更日志
## [1.13.0] - 2024-11-01
### 重大变更
* 不再捆绑 Cronet 库,在不支持 HttpEngine 的设备上回退到 OkHttp
* 适配 E 站缩略图和 WebP 等相关变更
### 改进
* 使用磁力链接代替种子下载
* 在搜索栏右侧显示论坛头像
* 支持重置下载路径
* 为 Android 10 以下且没有 DocumentsUI 的设备创建默认下载目录 [#1735](https://github.com/FooIbar/EhViewer/issues/1735)
* 重新添加了强制使用 e-hentai 缩略图服务器的选项
* 阅读器支持 PageUp/PageDown 和方向键上/下翻页 [#1801](https://github.com/FooIbar/EhViewer/issues/1801)
* 未找到搜索结果时显示可能存在的警告 [#1787](https://github.com/FooIbar/EhViewer/issues/1787)
* 更新了日本语翻译
* 杂项优化
### Bug 修复
* 阅读器屏幕方向与手机屏幕方向不同时闪退 [#1779](https://github.com/FooIbar/EhViewer/issues/1779)
* 下载文件哈希不匹配导致下载失败 [#1811](https://github.com/FooIbar/EhViewer/issues/1811)
* 无法同时下载和查看 [#1822](https://github.com/FooIbar/EhViewer/issues/1822)
* 杂项修复
## [1.12.1] - 2024-09-28
### 新功能
* 屏蔽含有二维码的图片(位于高级设置)
### 改进
* 移除高级设置中的自定义 User Agent,改为桌面版网站选项
* 画廊预览与画廊详情页面合并
* 为快速搜索和下载标签列表添加了滚动条
* 无网络条件下启动时自动转到下载页面
* 杂项优化
### Bug 修复
* 从左到右或右到左模式观看使用鼠标滚轮无法翻页 [#1541](https://github.com/FooIbar/EhViewer/issues/1541)
* 状态栏颜色未跟随阅读器主题变化 [#1542](https://github.com/FooIbar/EhViewer/issues/1542)
* 打开 EH 设置时闪退 [#1563](https://github.com/FooIbar/EhViewer/issues/1563)
* 画廊种子过多时显示没有种子 [#1561](https://github.com/FooIbar/EhViewer/issues/1561)
* 加载大于 100 MB 的位图时崩溃
* 阅读器加载小圆圈在黑色背景下不自动变色 [#1579](https://github.com/FooIbar/EhViewer/issues/1579)
* 因闪退造成的无法挽回的下载失败 [#1602](https://github.com/FooIbar/EhViewer/issues/1602)
* 某些情况下闪退 [#1548](https://github.com/FooIbar/EhViewer/issues/1548) [#1555](https://github.com/FooIbar/EhViewer/issues/1555) [#1568](https://github.com/FooIbar/EhViewer/issues/1568)
* Android 7.0 及以下的设备无法加载图片 [#1633](https://github.com/FooIbar/EhViewer/issues/1633)
* 某些情况下导入数据失败 [#1634](https://github.com/FooIbar/EhViewer/issues/1634)
* 下载时创建重复文件夹 [#1619](https://github.com/FooIbar/EhViewer/issues/1619)
* 滚动方向改变后预载图片不生效 [#1560](https://github.com/FooIbar/EhViewer/issues/1560)
* 选择无效的下载位置后闪退
* 杂项修复
## [1.12.0] - 2024-08-19
### 重大变更
* Compose 阅读器已稳定,移除了旧阅读器实现 [#847](https://github.com/FooIbar/EhViewer/issues/847)
* 由于 E 站缩略图服务器变更,移除了强制使用 e-hentai 缩略图服务器的选项
### 改进
* 更新高级搜索选项中页数过滤器的范围限制以遵循 E 站变更
### Bug 修复
* 评论页面刷新指示器边距不正确 [#1428](https://github.com/FooIbar/EhViewer/issues/1428)
* 关闭打开失败的压缩包时崩溃
* 无法打开带密码的压缩包 [#1454](https://github.com/FooIbar/EhViewer/issues/1454)
* 使用音量键翻页时无法关闭过渡动画 [#1467](https://github.com/FooIbar/EhViewer/issues/1467)
* 带有图片的评论显示错位 [#1468](https://github.com/FooIbar/EhViewer/issues/1468)
* 在包含相同项目的页面间切换时崩溃 [#1490](https://github.com/FooIbar/EhViewer/issues/1490)
* 无法检查更新 [#1512](https://github.com/FooIbar/EhViewer/issues/1512)
* 画廊详情未加载完成时退出阅读器导致崩溃 [#1507](https://github.com/FooIbar/EhViewer/issues/1507)
* 无法为带有临时标签的画廊生成 ComicInfo.xml [#1509](https://github.com/FooIbar/EhViewer/issues/1509)
* 已下载的画廊翻页时出现加载动画 [#1510](https://github.com/FooIbar/EhViewer/issues/1510)
* 画廊详情页面的缩略图无法加载 [#1529](https://github.com/FooIbar/EhViewer/issues/1529)
* 图片未加载完成时无法通过点击翻页
* 搜索结果为空时解析失败 [#1418](https://github.com/FooIbar/EhViewer/issues/1418)
* 缩略图分辨率设置不起作用
## [1.11.7] - 2024-07-10
### Bug 修复
* 无法下载标题包含 # 或 % 的画廊
* 下载页数较多的画廊时应用无响应
* 退出搜索栏时文本闪烁
## [1.11.6] - 2024-07-09 [YANKED]
### 改进
* 某些设备上无法加载长图时可尝试减小 设置-高级 中的硬件位图阈值 [#1321](https://github.com/FooIbar/EhViewer/issues/1321)
* 清理下载冗余时显示确认对话框 [#1369](https://github.com/FooIbar/EhViewer/issues/1369)
* 修改收藏时显示收藏备注 [#1392](https://github.com/FooIbar/EhViewer/issues/1392)
### Bug 修复
* 图片完整性校验误报 [#1286](https://github.com/FooIbar/EhViewer/issues/1286)
* 某些情况下应用崩溃 [#1290](https://github.com/FooIbar/EhViewer/issues/1290) [#1302](https://github.com/FooIbar/EhViewer/issues/1302)
* 某些情况下渲染问题 [#1284](https://github.com/FooIbar/EhViewer/issues/1284)
* 无法下载标题过长的画廊 [#1340](https://github.com/FooIbar/EhViewer/issues/1340)
* 某些界面拖动滚动条时黑屏 [#1329](https://github.com/FooIbar/EhViewer/issues/1329)
* 搜索栏多行文本遮挡其他内容 [#1365](https://github.com/FooIbar/EhViewer/issues/1365)
* CIFS Documents Provider 兼容问题 [#1356](https://github.com/FooIbar/EhViewer/issues/1356)
* 清理下载冗余未按预期运行 [#1369](https://github.com/FooIbar/EhViewer/issues/1369)
* 读取压缩包失败时崩溃
* 某些设备上崩溃 [#1276](https://github.com/FooIbar/EhViewer/issues/1276)
* 检查更新失效
## [1.11.6-RC2] - 2024-06-06
### 改进
* 下载图片时执行完整性校验以防止文件损坏/被篡改
## [1.11.6-RC1] - 2024-06-02
### 改进
* 下载列表默认显示全部下载项目
* 替换搜索文本中的换行符为空格 [#1258](https://github.com/FooIbar/EhViewer/issues/1258)
### Bug 修复
* 评价画廊时未使用输入的评分
* 搜索时意外选择 Non-H 类别 [#1246](https://github.com/FooIbar/EhViewer/issues/1246)
* 侧边栏与导航抽屉重叠 [#1262](https://github.com/FooIbar/EhViewer/issues/1262)
* 快速搜索/下载标签排序失效 [#1267](https://github.com/FooIbar/EhViewer/issues/1267)
* 加载压缩包/种子列表出错时 UI 冻结
* 低版本 Android 上某些 UI 被遮挡
## [1.11.5] - 2024-05-19
### 重大变更
* 不再支持 32 位 x86
### 新功能
* 支持按作者对下载分组
* 由于 E 站不再强制要求人机验证,重新支持账号密码登录
### 改进
* 在登录时加载收藏名称 [#1077](https://github.com/FooIbar/EhViewer/issues/1077)
* 优化归档和种子界面 UI
* 禁止在 cookie 界面截图以防止泄露
* 在缩略图模式下显示画廊页数
* 记住最低评分和页数搜索参数
* 更新 User-Agent 以缓解 IP 封禁 [#1182](https://github.com/FooIbar/EhViewer/issues/1182)
* 账号密码登录支持自动填充
* 更新中文(台灣)翻译
### Bug 修复
* 非触摸模式下无法退出搜索界面 [#1060](https://github.com/FooIbar/EhViewer/issues/1060)
* 某些设备上无法安装更新 [#1067](https://github.com/FooIbar/EhViewer/issues/1067)
* 某些设备上崩溃/卡顿 [#996](https://github.com/FooIbar/EhViewer/issues/996) [#1023](https://github.com/FooIbar/EhViewer/issues/1023)
* 搜索记录中存在重复条目时崩溃 [#1130](https://github.com/FooIbar/EhViewer/issues/1130)
* 条漫模式下缩小后点按区域偏移 [#127](https://github.com/FooIbar/EhViewer/issues/127)
* 多窗口模式下点按区域偏移
* 点击下载通知时未清除状态
* 保存未完成加载的图片时崩溃 [#1154](https://github.com/FooIbar/EhViewer/issues/1154)
* 历史记录界面无法在项目上滑动打开抽屉 [#464](https://github.com/FooIbar/EhViewer/issues/464)
* 导入数据失败时显示导入成功 [#1174](https://github.com/FooIbar/EhViewer/issues/1174)
* 某些条件下收藏界面崩溃 [#1190](https://github.com/FooIbar/EhViewer/issues/1190)
* 反转点按区域功能失效 [#1217](https://github.com/FooIbar/EhViewer/issues/1217)
### 已知问题
* 某些设备上从后台返回时某些 UI 消失,可通过关闭列表项目动画部分缓解 [#1184](https://github.com/FooIbar/EhViewer/issues/1184)
## [1.11.4] - 2024-04-21
### 新功能
* 更新前自动备份数据
### 改进
* 在 设置-高级 中加入了禁用列表项目动画的选项,该功能在部分设备上导致崩溃/卡顿 [#996](https://github.com/FooIbar/EhViewer/issues/996) [#1023](https://github.com/FooIbar/EhViewer/issues/1023)
* 下载列表多选模式下避免误触 [#1016](https://github.com/FooIbar/EhViewer/issues/1016)
* 杂项 UI 优化
### Bug 修复
* 重命名下载标签后删除该标签时崩溃 [#1008](https://github.com/FooIbar/EhViewer/issues/1008)
* 搜索栏中某些输入法长按退格无法连续删除 [#606](https://github.com/FooIbar/EhViewer/issues/606)
* 评论/屏蔽/搜索建议/下载标签/快速搜索列表卡顿 [#1041](https://github.com/FooIbar/EhViewer/issues/1041)
## [1.11.3] - 2024-04-06
### 改进
* 优化预加载逻辑和图片加载顺序
* 优化画廊详情和评论页面 UI
### Bug 修复
* 某些模式下搜索结果不显示画廊语言 [#923](https://github.com/FooIbar/EhViewer/issues/923)
* 某些情况下在搜索结果中直接阅读画廊后崩溃 [#927](https://github.com/FooIbar/EhViewer/issues/927)
* 更新至最新版本后仍提示有新版本 [#927](https://github.com/FooIbar/EhViewer/issues/927)
* 从旧版本升级时包含不兼容数据导致崩溃/无法导出数据 [#940](https://github.com/FooIbar/EhViewer/issues/940) [#974](https://github.com/FooIbar/EhViewer/issues/974)
* Android 10 以下的设备打开 设置-隐私 时崩溃 [#953](https://github.com/FooIbar/EhViewer/issues/953)
* 下载标签无法拖动
* 刷新 和 刷新(原图) 无法在已下载的图片上使用
* 临时 IP 封禁错误显示为解析失败
* 某些情况下下载时闪退 [#980](https://github.com/FooIbar/EhViewer/issues/980)
* 某些设备上下载列表中的缩略图无法显示 [#977](https://github.com/FooIbar/EhViewer/issues/977)
## [1.11.2] - 2024-03-17
### 重大变更
* Default 变种最低支持版本更改为 Android 8.0,重新添加了最低支持 Android 6.0 的 Marshmallow 变种
### 改进
* 重新添加了删除快速搜索/下载标签时的确认对话框
### Bug 修复
* 收藏页面 搜索栏中文标签转英文异常 [#902](https://github.com/FooIbar/EhViewer/issues/902)
* 在收藏或者取消收藏之后,收藏按钮会无反应 [#908](https://github.com/FooIbar/EhViewer/issues/908)
* 横屏页面下阅读设置UI重合 [#909](https://github.com/FooIbar/EhViewer/issues/909)
* Search bar does not work properly in Japanese [#906](https://github.com/FooIbar/EhViewer/issues/906)
* 搜索结果中的 Disowned 画廊不显示上传者
* 使用 CI 频道更新时,有时会获取到错误的更新链接
## [1.11.1] - 2024-03-12
### 重大变更
* 由于 E 站强制要求人机验证,仅支持通过网页登录
* 默认支持 Android 6,不再提供 Marshmallow 变种
* 集成 Cronet 库,不再提供 GMS 变种
### 改进
* 支持在排序下载列表前按下载标签分组
### Bug 修复
* 下载画廊时崩溃 [#893](https://github.com/FooIbar/EhViewer/issues/893)
## [1.11.0] - 2024-03-09
### 重大变更
* 由于 E 站 Cookie 策略变更,不再支持 Cookie 登录
* 登录时自动选择 exhentai (如果可用)
* 不再提供默认下载路径
* 手动排序更改为以添加时间/上传时间/标题/下载标签/页数对下载列表排序
* 由于数据库结构变更,此版本导出的数据将无法被旧版本导入
### 新功能
* 下载画廊时生成 ComicInfo.xml 格式元数据
* 归档下载时生成 ComicInfo.xml 格式元数据 [#711](https://github.com/FooIbar/EhViewer/issues/711)
* 归档下载支持第三方下载管理器 [#79](https://github.com/FooIbar/EhViewer/issues/79)
* 保存下载结果为 CBZ 压缩包 [#660](https://github.com/FooIbar/EhViewer/issues/660)
* 清除 `igneous` Cookie (将于下次搜索时重新获取)
* 随机打开本地收藏/下载中的画廊 [#695](https://github.com/FooIbar/EhViewer/issues/695)
* 随机在搜索结果中跳转
* 以网格模式查看下载列表
* 本地收藏/历史/下载中的标签搜索 [#860](https://github.com/FooIbar/EhViewer/issues/860)
### 改进
* 搜索时优先显示已选择的类别卡片
* 多处性能优化
### Bug 修复
* 显示模式为 Thumbnail 时无法点击上传者卡片 [#653](https://github.com/FooIbar/EhViewer/issues/653)
* [Marshmallow] GIF 只显示第一帧
* 无法在 `定时请求新闻页面` 关闭时开启 `隐藏 HV 事件通知`
* 响应正文含有无效 UTF-8 字符导致解码失败 [#643](https://github.com/FooIbar/EhViewer/issues/643)
* 某些情况下应用崩溃 [#710](https://github.com/FooIbar/EhViewer/issues/710)
* 画廊名称包含非法路径字符时无法保存图片 [#815](https://github.com/FooIbar/EhViewer/issues/815)
* 无法解码超长图片 [#732](https://github.com/FooIbar/EhViewer/issues/732)
* E 站变更导致种子解析失败 [#880](https://github.com/FooIbar/EhViewer/issues/880)
* E 站不再支持相似扫描导致图片搜索无法使用
* 杂项修复
### 已知问题
* Android 14 上使用手势导航返回时过渡动画过早结束 [#775](https://github.com/FooIbar/EhViewer/issues/775)
## [1.10.3] - 2024-01-15
### 新功能
* [Marshmallow] 支持裁剪边缘、打开压缩包和 GIF
### 改进
* 由于部分设备上的非预期行为 [#578](https://github.com/FooIbar/EhViewer/issues/578) [#596](https://github.com/FooIbar/EhViewer/issues/596),默认禁用预见式返回导航动画,可于 设置-高级 中开启
* 杂项优化
### Bug 修复
* 刷新后页面无响应 [#579](https://github.com/FooIbar/EhViewer/issues/579)
* 浏览中保存图片后点击操作被阻挡 [#581](https://github.com/FooIbar/EhViewer/issues/581)
* 在画廊详情页面切换至后台后点击评论闪退 [#580](https://github.com/FooIbar/EhViewer/issues/580)
* 已下载的画廊中未阅读缓存过的图片解码失败 [#592](https://github.com/FooIbar/EhViewer/issues/592)
* 在收藏页多选并下载会使得下载状态出现问题 [#603](https://github.com/FooIbar/EhViewer/issues/603)
* 未能在不重启情况下切换 Http 引擎 [#610](https://github.com/FooIbar/EhViewer/issues/610)
* 在有进度的画廊阅读界面无法直接回到第一页 [#614](https://github.com/FooIbar/EhViewer/issues/614)
* 请求新闻界面失效 [#605](https://github.com/FooIbar/EhViewer/issues/605)
* 收藏夹为空解析失败 [#630](https://github.com/FooIbar/EhViewer/issues/630)
## [1.10.2] - 2023-12-31
### 新功能
* [阅读器] 支持裁剪图片黑色/白色边缘
### 改进
* 切换 HTTP 引擎无需重启
* 优化过渡动画
* 杂项性能优化
### Bug 修复
* 修复搜索建议中出现关键词相同的条目时崩溃 [#533](https://github.com/FooIbar/EhViewer/issues/533) [#555](https://github.com/FooIbar/EhViewer/issues/555)
* 修复重命名下载标签时不显示原标签 [#534](https://github.com/FooIbar/EhViewer/issues/534)
* 修复调整下载项目顺序时卡顿 [#552](https://github.com/FooIbar/EhViewer/issues/552)
* 修复新增或修改评论后黑屏 [#554](https://github.com/FooIbar/EhViewer/issues/554)
* 修复剪贴板读取bug [#566](https://github.com/FooIbar/EhViewer/issues/566)
* 修复画廊信息对话框无法通过返回按钮/手势关闭 [#413](https://github.com/FooIbar/EhViewer/issues/413)
## [1.10.1] - 2023-12-19
### 重大变更
* 由于 Apache HttpClient 5 在 Android 10 以下无法使用,后备 HTTP 引擎恢复为 OkHttp [#514](https://github.com/FooIbar/EhViewer/issues/514)
### Bug 修复
* 修复获取 pToken 失败导致无限加载 [#508](https://github.com/FooIbar/EhViewer/issues/508)
* 修复阅读页快速滑动滑块导致下载延时过多累计 [#512](https://github.com/FooIbar/EhViewer/issues/512)
* 修复 Android 9 以下的设备上无法退出搜索栏 [#513](https://github.com/FooIbar/EhViewer/issues/513)
## [1.10.0] - 2023-12-14 [YANKED]
### 重大变更
* 后备 HTTP 引擎变更为 Apache HttpClient 5
* 类别和高级搜索选项移至搜索栏下方
### 新功能
* 支持在搜索时指定画廊语言
### 改进
* 在下载中阅读画廊时会更新历史记录
* 多处性能改进
### Bug 修复
* 修复无法由外部应用进入画廊页面 [#436](https://github.com/FooIbar/EhViewer/issues/436)
* 修复点击精确到页的画廊链接闪退 [#430](https://github.com/FooIbar/EhViewer/issues/430)
* 修复无法搜索本地收藏 [#491](https://github.com/FooIbar/EhViewer/issues/491)
* 修复 CI 版本不显示变更日志
## [1.9.0] - 2023-12-01
### 重大变更
* 除阅读器外全部迁移至 Compose
### 新功能
* 设置-高级 中增加实验性滑动手势敏感度设置
* 支持通过滑动手势打开右侧抽屉
* 支持预见式返回动画,相关设置位于 设置-高级
### 改进
* [阅读器] 画廊页数过多时隐藏进度条刻度并禁用触感反馈
* 优化原图下载重试策略
* 优化小屏设备上的搜索类别布局
* 优化过渡动画
* 优化历史记录删除动画
* 设置-EH 中的缩略图大小设置改为缩略图列数
### Bug 修复
* 修复点击通知栏的下载通知闪退 [#175](https://github.com/FooIbar/EhViewer/issues/175)
* 修复收藏状态显示错误 [#189](https://github.com/FooIbar/EhViewer/issues/189)
* 修复双击导航按钮后无法打开导航抽屉
* 修复某些情况下闪退 [#142](https://github.com/FooIbar/EhViewer/issues/142) [#208](https://github.com/FooIbar/EhViewer/issues/208)
* 修复收藏界面点击重试崩溃 [#193](https://github.com/FooIbar/EhViewer/issues/193)
* 修复本地收藏滚动位置丢失 [#192](https://github.com/FooIbar/EhViewer/issues/192)
* 修复手速过快页面切换过快使加载圈圈不自动消失 [#209](https://github.com/FooIbar/EhViewer/issues/209)
* 修复打开并关闭右侧抽屉后,状态栏一片白色 [#101](https://github.com/FooIbar/EhViewer/issues/101)
* 修复使用深色主题时,切换界面会闪过亮色界面 [#121](https://github.com/FooIbar/EhViewer/issues/121)
* [Marshmallow] 修复小内存设备上图片解码失败 [#229](https://github.com/FooIbar/EhViewer/issues/229) [#372](https://github.com/FooIbar/EhViewer/issues/372)
* 修复已舍弃画廊上传者解析
### 已知问题
* 画廊信息对话框无法通过返回关闭 [#413](https://github.com/FooIbar/EhViewer/issues/413)
+33 -32
View File
@@ -1,60 +1,57 @@
<p align="right">
<strong>English</strong>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-cn.md">
<a href="/docs/README/zh-cn.md">
简体中文
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/docs/README/zh-tw.md">
<a href="/docs/README/zh-tw.md">
正體中文
</a>
</p>
<h1 align="center">
<img src="https://github.com/Ehviewer-Overhauled/Art/blob/master/launcher_icon-web.svg" width="200">
<img src="https://github.com/Ehviewer-Overhauled/Art/blob/master/launcher_icon-web.svg" width="200" alt="EhViewer">
<br>EhViewer<br>
</h1>
<p align="center">
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml">
<img src="https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml/badge.svg" alt="Github Actions">
<a href="https://github.com/FooIbar/EhViewer/actions/workflows/ci.yml">
<img src="https://github.com/FooIbar/EhViewer/actions/workflows/ci.yml/badge.svg" alt="Github Actions">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/blob/1.8.x.x/LICENSE">
<img src="https://img.shields.io/github/license/Ehviewer-Overhauled/Ehviewer" alt="LICENSE">
<a href="/LICENSE">
<img src="https://img.shields.io/github/license/FooIbar/EhViewer" alt="LICENSE">
</a>
<a href="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer">
<img src="https://www.codefactor.io/repository/github/Ehviewer-Overhauled/ehviewer/badge" alt="CodeFactor">
<a href="https://www.codefactor.io/repository/github/FooIbar/EhViewer">
<img src="https://www.codefactor.io/repository/github/FooIbar/EhViewer/badge" alt="CodeFactor">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases">
<img src="https://img.shields.io/github/downloads/Ehviewer-Overhauled/EhViewer/total.svg" alt="Downloads">
<a href="https://github.com/FooIbar/EhViewer/releases">
<img src="https://img.shields.io/github/v/release/FooIbar/EhViewer" alt="Release">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases">
<img src="https://img.shields.io/github/v/release/Ehviewer-Overhauled/ehviewer?include_prereleases" alt="Release">
</a>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/issues">
<img src="https://img.shields.io/github/issues/Ehviewer-Overhauled/ehviewer" alt="Issues">
<a href="https://github.com/FooIbar/EhViewer/issues">
<img src="https://img.shields.io/github/issues/FooIbar/EhViewer" alt="Issues">
</a>
</p>
<div align="center">
<h3>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#description">
<a href="#description">
Description
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#download">
<a href="#download">
Download
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#screenshot">
<a href="#screenshot">
Screenshot
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#thanks">
<a href="#thanks">
Thanks
</a>
<span> | </span>
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer#license">
<a href="#license">
License
</a>
</h3>
@@ -69,7 +66,14 @@ and [Dynamic Color](https://m3.material.io/styles/color/dynamic-color/overview)
# Download
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases"><img alt="Get it on GitHub" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-github.svg" width="200px"/></a> <a href="https://github.com/Ehviewer-Overhauled/fdroid-repo"><img alt="Get it on F-Droid" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-fdroid.svg" width="200px"/></a>
| Flavor | Feature |
|-------------|----------------------------------|
| Default | Android 8.0+, full support |
| Marshmallow | Android 6.0-7.1, limited support |
<a href="https://github.com/FooIbar/EhViewer/releases">
<img alt="Get it on GitHub" src="https://github.com/Ehviewer-Overhauled/Art/blob/master/get-it-on-github.svg" width="200px"/>
</a>
# Screenshot
@@ -81,24 +85,21 @@ and [Dynamic Color](https://m3.material.io/styles/color/dynamic-color/overview)
Here is the libraries
- [Arrow](https://arrow-kt.io/)
- [AOSP & AndroidX](http://source.android.com/)
- [AOSP & AndroidX](https://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/)
- [Material Icons](https://github.com/google/material-design-icons)
- [Ktor](https://ktor.io/)
- [Coil](https://coil-kt.github.io/coil/)
- [Jsoup](https://jsoup.org/)
Specially thanks [Tachiyomi](https://tachiyomi.org/) for its reader implementation!
- [Compose Destinations](https://composedestinations.rafaelcosta.xyz/)
- [libarchive](https://www.libarchive.org/)
- [jsoup](https://jsoup.org/)
# License
Copyright 2014-2019 Hippo Seven
Copyright 2020-2022 NekoInverter
Copyright 2022-2023 Tarsin Norbin
Copyright 2023-2024 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.
-6
View File
@@ -1,8 +1,2 @@
/build
/src/main/java-gen
manifest-merger-release-report.txt
/src/main/libs
/src/main/obj
# Intellij
*.iml
/.cxx
+239 -162
View File
@@ -1,31 +1,53 @@
import java.io.ByteArrayOutputStream
import java.time.Instant
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE
import com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeFeatureFlag
val isRelease: Boolean
get() = gradle.startParameter.taskNames.any { it.contains("Release") }
plugins {
id("com.android.application")
kotlin("android")
id("kotlin-parcelize")
kotlin("plugin.serialization")
id("com.google.devtools.ksp")
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp)
alias(libs.plugins.spotless)
alias(libs.plugins.aboutlibrariesPlugin)
alias(libs.plugins.composeCompilerReportGenerator)
alias(libs.plugins.baselineprofile)
}
val supportedAbis = arrayOf("arm64-v8a", "x86_64", "armeabi-v7a")
android {
compileSdk = 33
buildToolsVersion = "33.0.2"
ndkVersion = "25.2.9519653"
androidResources.generateLocaleConfig = true
androidResources {
generateLocaleConfig = true
localeFilters += listOf(
"zh",
"zh-rCN",
"zh-rHK",
"zh-rTW",
"es",
"ja",
"ko",
"fr",
"de",
"th",
"tr",
"nb-rNO",
)
}
splits {
abi {
isEnable = true
reset()
if (gradle.startParameter.taskNames.any { it.contains("Release") }) {
include("arm64-v8a", "x86_64", "armeabi-v7a", "x86")
if (isRelease) {
include(*supportedAbis)
isUniversalApk = true
} else {
include("arm64-v8a")
include("arm64-v8a", "x86_64")
}
}
}
@@ -39,44 +61,53 @@ android {
enableV4Signing = true
}
val commitSha by lazy {
val stdout = ByteArrayOutputStream()
exec {
commandLine = "git rev-parse --short=7 HEAD".split(' ')
standardOutput = stdout
}
stdout.toString().trim()
}
val commitSha = providers.exec {
commandLine = "git rev-parse --short=7 HEAD".split(' ')
}.standardOutput.asText.get().trim()
val buildTime by lazy {
val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm").withZone(ZoneOffset.UTC)
formatter.format(Instant.now())
}
val commitTime = providers.exec {
commandLine = "git log -1 --format=%ct".split(' ')
}.standardOutput.asText.get().trim()
val repoName = providers.exec {
commandLine = "git remote get-url origin".split(' ')
}.standardOutput.asText.get().trim().removePrefix("https://github.com/").removePrefix("git@github.com:")
.removeSuffix(".git")
val chromeVersion = rootProject.layout.projectDirectory.file("chrome.version").asFile.readText().trim()
defaultConfig {
applicationId = "moe.tarsin.ehviewer"
minSdk = 28
targetSdk = 33
versionCode = 180038
versionName = "1.8.8.0-beta"
resourceConfigurations.addAll(
listOf(
"zh",
"zh-rCN",
"zh-rHK",
"zh-rTW",
"es",
"ja",
"ko",
"fr",
"de",
"th",
"tr",
"nb-rNO",
),
)
versionCode = 180061
versionName = "1.13.0"
// versionNameSuffix = "-SNAPSHOT"
buildConfigField("String", "RAW_VERSION_NAME", "\"$versionName${versionNameSuffix.orEmpty()}\"")
buildConfigField("String", "COMMIT_SHA", "\"$commitSha\"")
buildConfigField("String", "BUILD_TIME", "\"$buildTime\"")
buildConfigField("long", "COMMIT_TIME", commitTime)
buildConfigField("String", "REPO_NAME", "\"$repoName\"")
buildConfigField("String", "CHROME_VERSION", "\"$chromeVersion\"")
ndk {
if (isRelease) {
abiFilters.addAll(supportedAbis)
}
debugSymbolLevel = "FULL"
}
externalNativeBuild {
cmake {
arguments += "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
}
}
}
flavorDimensions += "api"
productFlavors {
create("default")
create("marshmallow") {
minSdk = 23
applicationIdSuffix = ".m"
versionNameSuffix = "-M"
}
}
externalNativeBuild {
@@ -86,46 +117,31 @@ android {
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = listOf(
// https://kotlinlang.org/docs/compiler-reference.html#progressive
"-progressive",
"-Xjvm-default=all",
"-Xlambdas=indy",
"-opt-in=coil.annotation.ExperimentalCoilApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi",
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.paging.ExperimentalPagingApi",
"-opt-in=kotlin.contracts.ExperimentalContracts",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlinx.coroutines.InternalCoroutinesApi",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
)
isCoreLibraryDesugaringEnabled = true
}
lint {
abortOnError = true
checkReleaseBuilds = false
disable.add("MissingTranslation")
disable += setOf("MissingTranslation", "MissingQuantity")
error += setOf("InlinedApi")
}
packaging {
dex {
useLegacyPackaging = false
}
resources {
excludes += "/META-INF/**"
excludes += "/kotlin/**"
excludes += "**.txt"
excludes += "**.bin"
// Required by Layout Inspector
pickFirsts += "/META-INF/androidx.compose.ui_ui.version"
excludes += listOf(
"/META-INF/**",
"/kotlin/**",
"**.txt",
"**.bin",
"**.{html,mmd}", // Compose Destination
"/okhttp3/**", // Okhttp public suffix
)
}
}
@@ -141,101 +157,162 @@ android {
debug {
applicationIdSuffix = ".debug"
}
create("benchmarkRelease") {
initWith(buildTypes.getByName("release"))
matchingFallbacks += listOf("release")
applicationIdSuffix = ".benchmark"
signingConfig = signingConfigs.getByName("debug")
isDebuggable = false
}
}
buildFeatures {
buildConfig = true
compose = true
viewBinding = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.7"
}
namespace = "com.hippo.ehviewer"
}
dependencies {
// https://developer.android.com/jetpack/androidx/releases/activity
implementation("androidx.activity:activity-compose:1.7.1")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.biometric:biometric-ktx:1.2.0-alpha05")
implementation("androidx.browser:browser:1.5.0")
implementation("androidx.collection:collection-ktx:1.3.0-alpha04")
// https://developer.android.com/jetpack/androidx/releases/compose-material3
// api(platform("androidx.compose:compose-bom:2023.03.00"))
api(platform("dev.chrisbanes.compose:compose-bom:2023.04.00-SNAPSHOT"))
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.material3:material3-window-size-class")
implementation("androidx.core:core-ktx:1.11.0-alpha04")
implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha09")
implementation("androidx.coordinatorlayout:coordinatorlayout:1.2.0")
implementation("androidx.drawerlayout:drawerlayout:1.2.0")
// https://developer.android.com/jetpack/androidx/releases/lifecycle
implementation("androidx.lifecycle:lifecycle-process:2.6.1")
// https://developer.android.com/jetpack/androidx/releases/navigation
val nav_version = "2.5.3"
implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
implementation("androidx.navigation:navigation-compose:$nav_version")
// https://developer.android.com/jetpack/androidx/releases/paging
implementation("androidx.paging:paging-common-ktx:3.2.0-alpha05")
implementation("androidx.paging:paging-compose:1.0.0-alpha19")
implementation("androidx.preference:preference-ktx:1.2.0")
implementation("androidx.recyclerview:recyclerview:1.3.0")
// https://developer.android.com/jetpack/androidx/releases/room
val room_version = "2.6.0-alpha01"
ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-paging:$room_version")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01")
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation("com.drakeet.drawer:drawer:1.0.3")
implementation("com.github.chrisbanes:PhotoView:2.3.0") // Dead Dependency
implementation("com.github.tachiyomiorg:DirectionalViewPager:1.0.0") // Dead Dependency
implementation("com.github.nanihadesuka:LazyColumnScrollbar:1.6.3")
// https://github.com/google/accompanist/releases
implementation("com.google.accompanist:accompanist-themeadapter-material3:0.30.1")
implementation("com.google.android.material:material:1.9.0")
// https://square.github.io/okhttp/changelogs/changelog/
implementation("com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.11")
implementation("com.squareup.okhttp3:okhttp-coroutines")
implementation("com.squareup.okio:okio-jvm:3.3.0")
implementation("dev.chrisbanes.insetter:insetter:0.6.1") // Dead Dependency
implementation("dev.rikka.rikkax.core:core-ktx:1.4.1")
implementation("dev.rikka.rikkax.insets:insets:1.3.0")
implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.3.0")
implementation("dev.rikka.rikkax.preference:simplemenu-preference:1.0.3")
implementation("dev.rikka.rikkax.material:material-preference:2.0.0")
implementation(platform("io.arrow-kt:arrow-stack:2.0.0-SNAPSHOT"))
implementation("io.arrow-kt:arrow-functions")
implementation("io.arrow-kt:arrow-fx-coroutines")
// https://coil-kt.github.io/coil/changelog/
implementation("io.coil-kt:coil-compose:2.3.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.5.1")
implementation("org.jsoup:jsoup:1.16.1")
composeCompiler {
featureFlags = setOf(ComposeFeatureFlag.OptimizeNonSkippingGroups)
}
configurations.all {
exclude("dev.rikka.rikkax.appcompat", "appcompat")
exclude("dev.rikka.rikkax.material", "material")
baselineProfile {
mergeIntoMain = true
}
dependencies {
// https://developer.android.com/jetpack/androidx/releases/activity
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.biometric)
implementation(libs.androidx.browser)
// https://developer.android.com/jetpack/androidx/releases/compose-material3
api(platform(libs.compose.bom))
implementation(libs.bundles.compose)
implementation(libs.compose.destinations.core)
ksp(libs.compose.destinations.compiler)
implementation(libs.androidx.core)
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.constraintlayout.compose)
implementation(libs.androidx.datastore)
implementation(libs.androidx.graphics.path)
// https://developer.android.com/jetpack/androidx/releases/lifecycle
implementation(libs.androidx.lifecycle.process)
implementation(libs.androidx.lifecycle.compose)
// https://developer.android.com/jetpack/androidx/releases/paging
implementation(libs.androidx.paging.compose)
// https://developer.android.com/jetpack/androidx/releases/room
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.room.paging)
implementation(libs.androidx.work.runtime)
implementation(libs.material.motion.core)
implementation(libs.material.kolor)
implementation(libs.bundles.splitties)
// https://square.github.io/okhttp/changelogs/changelog/
implementation(platform(libs.okhttp.bom))
implementation(libs.okhttp.android)
implementation(libs.okio.jvm)
implementation(libs.logcat)
implementation(libs.diff)
implementation(libs.aboutlibraries.core)
implementation(libs.aboutlibraries.compose.m3)
implementation(libs.accompanist.drawable.painter)
implementation(libs.reorderable)
implementation(platform(libs.arrow.stack))
implementation(libs.arrow.fx.coroutines)
implementation(libs.arrow.resilience)
// https://coil-kt.github.io/coil/changelog/
implementation(platform(libs.coil.bom))
implementation(libs.bundles.coil)
implementation(libs.telephoto.zoomable)
implementation(libs.ktor.client.okhttp)
implementation(libs.bundles.kotlinx.serialization)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.datetime)
implementation(libs.jsoup)
coreLibraryDesugaring(libs.desugar)
implementation(libs.androidx.profileinstaller)
"baselineProfile"(project(":benchmark"))
debugImplementation(libs.compose.ui.tooling)
implementation(libs.compose.ui.tooling.preview)
}
kotlin {
jvmToolchain(21)
compilerOptions {
freeCompilerArgs = listOf(
// https://kotlinlang.org/docs/compiler-reference.html#progressive
"-progressive",
"-Xjvm-default=all",
"-Xcontext-receivers",
"-Xwhen-guards",
"-Xsuppress-warning=CONTEXT_RECEIVERS_DEPRECATED",
"-opt-in=coil3.annotation.ExperimentalCoilApi",
"-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3ExpressiveApi",
"-opt-in=androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi",
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
"-opt-in=androidx.compose.animation.ExperimentalSharedTransitionApi",
"-opt-in=androidx.paging.ExperimentalPagingApi",
"-opt-in=kotlin.contracts.ExperimentalContracts",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
"-opt-in=splitties.experimental.ExperimentalSplittiesApi",
"-opt-in=splitties.preferences.DataStorePreferencesPreview",
)
}
}
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
arg("room.generateKotlin", "true")
arg("compose-destinations.codeGenPackageName", "com.hippo.ehviewer.ui")
}
aboutLibraries {
duplicationMode = MERGE
duplicationRule = GROUP
}
val ktlintVersion = libs.ktlint.get().version
spotless {
kotlin {
// https://github.com/diffplug/spotless/issues/111
target("src/**/*.kt")
ktlint(ktlintVersion)
}
kotlinGradle {
ktlint(ktlintVersion)
}
}
+15 -12
View File
@@ -1,21 +1,24 @@
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# https://issuetracker.google.com/issues/190382641
-keepclassmembers class kotlin.SafePublicationLazyImpl {
java.lang.Object _value;
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class androidx.viewpager.widget.ViewPager$LayoutParams { int position; }
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
-keepattributes LineNumberTable,SourceFile
-renamesourcefileattribute SourceFile
# Ktor logger
-dontwarn org.slf4j.impl.StaticLoggerBinder
# https://issuetracker.google.com/222232895
-dontwarn androidx.window.extensions.**
-dontwarn androidx.window.sidecar.Sidecar*
-keepattributes LineNumberTable
-repackageclasses
-allowaccessmodification
-overloadaggressively
-repackageclasses
@@ -1,88 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "c801ee62729ba20a203b150211234d5c",
"entities": [
{
"tableName": "OK_HTTP_3_COOKIE",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`NAME` TEXT, `VALUE` TEXT, `EXPIRES_AT` INTEGER NOT NULL, `DOMAIN` TEXT, `PATH` TEXT, `SECURE` INTEGER NOT NULL, `HTTP_ONLY` INTEGER NOT NULL, `PERSISTENT` INTEGER NOT NULL, `HOST_ONLY` INTEGER NOT NULL, `_id` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value",
"columnName": "VALUE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "expiresAt",
"columnName": "EXPIRES_AT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "domain",
"columnName": "DOMAIN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "path",
"columnName": "PATH",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "secure",
"columnName": "SECURE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "httpOnly",
"columnName": "HTTP_ONLY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "persistent",
"columnName": "PERSISTENT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "hostOnly",
"columnName": "HOST_ONLY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c801ee62729ba20a203b150211234d5c')"
]
}
}
@@ -1,88 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "1b80cd29939b0f43934721f1289ba94d",
"entities": [
{
"tableName": "OK_HTTP_3_COOKIE",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`NAME` TEXT NOT NULL, `VALUE` TEXT NOT NULL, `EXPIRES_AT` INTEGER NOT NULL, `DOMAIN` TEXT NOT NULL, `PATH` TEXT NOT NULL, `SECURE` INTEGER NOT NULL, `HTTP_ONLY` INTEGER NOT NULL, `PERSISTENT` INTEGER NOT NULL, `HOST_ONLY` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "VALUE",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "expiresAt",
"columnName": "EXPIRES_AT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "domain",
"columnName": "DOMAIN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "path",
"columnName": "PATH",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "secure",
"columnName": "SECURE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "httpOnly",
"columnName": "HTTP_ONLY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "persistent",
"columnName": "PERSISTENT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "hostOnly",
"columnName": "HOST_ONLY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1b80cd29939b0f43934721f1289ba94d')"
]
}
}
@@ -0,0 +1,448 @@
{
"formatVersion": 1,
"database": {
"version": 10,
"identityHash": "613604f93bf815adeb87f03e2166e983",
"entities": [
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `TIME` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `FAVORITE_SLOT` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '613604f93bf815adeb87f03e2166e983')"
]
}
}
@@ -0,0 +1,469 @@
{
"formatVersion": 1,
"database": {
"version": 11,
"identityHash": "92915e937cb7ccc536d352fda5cf287f",
"entities": [
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL DEFAULT 0, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `TIME` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL DEFAULT 0, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `FAVORITE_SLOT` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '92915e937cb7ccc536d352fda5cf287f')"
]
}
}
@@ -0,0 +1,454 @@
{
"formatVersion": 1,
"database": {
"version": 12,
"identityHash": "d40b38b0ba3b1c53b773728cdee328c8",
"entities": [
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `FAVORITE_SLOT` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd40b38b0ba3b1c53b773728cdee328c8')"
]
}
}
@@ -0,0 +1,534 @@
{
"formatVersion": 1,
"database": {
"version": 13,
"identityHash": "df15d8f70f45047a738c8911212ea73c",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `FAVORITE_SLOT` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'df15d8f70f45047a738c8911212ea73c')"
]
}
}
@@ -0,0 +1,402 @@
{
"formatVersion": 1,
"database": {
"version": 14,
"identityHash": "54e4f2704cc47c5a6a2f4b96de978cce",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '54e4f2704cc47c5a6a2f4b96de978cce')"
]
}
}
@@ -0,0 +1,412 @@
{
"formatVersion": 1,
"database": {
"version": 15,
"identityHash": "991a3a3ddc4fe8d4dbcb39b975ab73b8",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '991a3a3ddc4fe8d4dbcb39b975ab73b8')"
]
}
}
@@ -0,0 +1,433 @@
{
"formatVersion": 1,
"database": {
"version": 16,
"identityHash": "06e5ff8fd6797d5801e86753fa5831b2",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '06e5ff8fd6797d5801e86753fa5831b2')"
]
}
}
@@ -0,0 +1,471 @@
{
"formatVersion": 1,
"database": {
"version": 17,
"identityHash": "d6375317a9298b7feae5925a23272bb9",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "PROGRESS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `PAGE` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd6375317a9298b7feae5925a23272bb9')"
]
}
}
@@ -0,0 +1,471 @@
{
"formatVersion": 1,
"database": {
"version": 18,
"identityHash": "bc90acf4ffb4e7cce9a16cd5a0f662f3",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT NOT NULL, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "PROGRESS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `PAGE` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bc90acf4ffb4e7cce9a16cd5a0f662f3')"
]
}
}
@@ -0,0 +1,465 @@
{
"formatVersion": 1,
"database": {
"version": 19,
"identityHash": "edd2f8e628072889f7702b50eb2c44a1",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT NOT NULL, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "PROGRESS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `PAGE` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'edd2f8e628072889f7702b50eb2c44a1')"
]
}
}
@@ -0,0 +1,472 @@
{
"formatVersion": 1,
"database": {
"version": 20,
"identityHash": "a8dd0226b286cc57a8c99ba7ad416730",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT NOT NULL, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `PAGES` INTEGER NOT NULL DEFAULT 0, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "pages",
"columnName": "PAGES",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "PROGRESS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `PAGE` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a8dd0226b286cc57a8c99ba7ad416730')"
]
}
}
@@ -0,0 +1,513 @@
{
"formatVersion": 1,
"database": {
"version": 21,
"identityHash": "6a9926f6722f8fc6f9c4426b31260e33",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT NOT NULL, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `PAGES` INTEGER NOT NULL DEFAULT 0, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "pages",
"columnName": "PAGES",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "PROGRESS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `PAGE` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"ftsVersion": "FTS4",
"ftsOptions": {
"tokenizer": "simple",
"tokenizerArgs": [],
"contentTable": "GALLERIES",
"languageIdColumnName": "",
"matchInfo": "FTS4",
"notIndexedColumns": [],
"prefixSizes": [],
"preferredOrder": "ASC"
},
"contentSyncTriggers": [
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GalleryFts_BEFORE_UPDATE BEFORE UPDATE ON `GALLERIES` BEGIN DELETE FROM `GalleryFts` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GalleryFts_BEFORE_DELETE BEFORE DELETE ON `GALLERIES` BEGIN DELETE FROM `GalleryFts` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GalleryFts_AFTER_UPDATE AFTER UPDATE ON `GALLERIES` BEGIN INSERT INTO `GalleryFts`(`docid`, `TITLE`, `TITLE_JPN`) VALUES (NEW.`rowid`, NEW.`TITLE`, NEW.`TITLE_JPN`); END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GalleryFts_AFTER_INSERT AFTER INSERT ON `GALLERIES` BEGIN INSERT INTO `GalleryFts`(`docid`, `TITLE`, `TITLE_JPN`) VALUES (NEW.`rowid`, NEW.`TITLE`, NEW.`TITLE_JPN`); END"
],
"tableName": "GalleryFts",
"createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`TITLE` TEXT NOT NULL, `TITLE_JPN` TEXT NOT NULL, content=`GALLERIES`)",
"fields": [
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": []
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6a9926f6722f8fc6f9c4426b31260e33')"
]
}
}
@@ -0,0 +1,525 @@
{
"formatVersion": 1,
"database": {
"version": 22,
"identityHash": "f61ae3beef3739c0de7db945d2c9a4a4",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT NOT NULL, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_TAGS` TEXT, `PAGES` INTEGER NOT NULL DEFAULT 0, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleTags",
"columnName": "SIMPLE_TAGS",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "pages",
"columnName": "PAGES",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "PROGRESS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `PAGE` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"ftsVersion": "FTS4",
"ftsOptions": {
"tokenizer": "simple",
"tokenizerArgs": [],
"contentTable": "GALLERIES",
"languageIdColumnName": "",
"matchInfo": "FTS4",
"notIndexedColumns": [],
"prefixSizes": [],
"preferredOrder": "ASC"
},
"contentSyncTriggers": [
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_BEFORE_UPDATE BEFORE UPDATE ON `GALLERIES` BEGIN DELETE FROM `GALLERIES_FTS` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_BEFORE_DELETE BEFORE DELETE ON `GALLERIES` BEGIN DELETE FROM `GALLERIES_FTS` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_AFTER_UPDATE AFTER UPDATE ON `GALLERIES` BEGIN INSERT INTO `GALLERIES_FTS`(`docid`, `TITLE`, `TITLE_JPN`, `SIMPLE_TAGS`) VALUES (NEW.`rowid`, NEW.`TITLE`, NEW.`TITLE_JPN`, NEW.`SIMPLE_TAGS`); END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_AFTER_INSERT AFTER INSERT ON `GALLERIES` BEGIN INSERT INTO `GALLERIES_FTS`(`docid`, `TITLE`, `TITLE_JPN`, `SIMPLE_TAGS`) VALUES (NEW.`rowid`, NEW.`TITLE`, NEW.`TITLE_JPN`, NEW.`SIMPLE_TAGS`); END"
],
"tableName": "GALLERIES_FTS",
"createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`TITLE` TEXT NOT NULL, `TITLE_JPN` TEXT NOT NULL, `SIMPLE_TAGS` TEXT, content=`GALLERIES`)",
"fields": [
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "simpleTags",
"columnName": "SIMPLE_TAGS",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": []
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f61ae3beef3739c0de7db945d2c9a4a4')"
]
}
}
@@ -0,0 +1,564 @@
{
"formatVersion": 1,
"database": {
"version": 23,
"identityHash": "7d1cfc4e9a9d506a73eb0520ae414d25",
"entities": [
{
"tableName": "GALLERIES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TOKEN` TEXT NOT NULL, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_TAGS` TEXT, `PAGES` INTEGER NOT NULL DEFAULT 0, `SIMPLE_LANGUAGE` TEXT, `FAVORITE_SLOT` INTEGER NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleTags",
"columnName": "SIMPLE_TAGS",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "pages",
"columnName": "PAGES",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "favoriteSlot",
"columnName": "FAVORITE_SLOT",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `POSITION` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_DOWNLOAD_LABELS_LABEL",
"unique": true,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_DOWNLOAD_LABELS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`LABEL`) REFERENCES `DOWNLOAD_LABELS`(`LABEL`) ON UPDATE CASCADE ON DELETE SET NULL )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [
{
"name": "index_DOWNLOADS_LABEL",
"unique": false,
"columnNames": [
"LABEL"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_DOWNLOADS_LABEL` ON `${TABLE_NAME}` (`LABEL`)"
}
],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
},
{
"table": "DOWNLOAD_LABELS",
"onDelete": "SET NULL",
"onUpdate": "CASCADE",
"columns": [
"LABEL"
],
"referencedColumns": [
"LABEL"
]
}
]
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_ARTISTS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `ARTIST` TEXT NOT NULL, PRIMARY KEY(`GID`, `ARTIST`), FOREIGN KEY(`GID`) REFERENCES `DOWNLOADS`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "artist",
"columnName": "ARTIST",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID",
"ARTIST"
]
},
"indices": [],
"foreignKeys": [
{
"table": "DOWNLOADS",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "PROGRESS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `PAGE` INTEGER NOT NULL, PRIMARY KEY(`GID`), FOREIGN KEY(`GID`) REFERENCES `GALLERIES`(`GID`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": [
{
"table": "GALLERIES",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"GID"
],
"referencedColumns": [
"GID"
]
}
]
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT NOT NULL, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `POSITION` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "POSITION",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"ftsVersion": "FTS4",
"ftsOptions": {
"tokenizer": "simple",
"tokenizerArgs": [],
"contentTable": "GALLERIES",
"languageIdColumnName": "",
"matchInfo": "FTS4",
"notIndexedColumns": [],
"prefixSizes": [],
"preferredOrder": "ASC"
},
"contentSyncTriggers": [
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_BEFORE_UPDATE BEFORE UPDATE ON `GALLERIES` BEGIN DELETE FROM `GALLERIES_FTS` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_BEFORE_DELETE BEFORE DELETE ON `GALLERIES` BEGIN DELETE FROM `GALLERIES_FTS` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_AFTER_UPDATE AFTER UPDATE ON `GALLERIES` BEGIN INSERT INTO `GALLERIES_FTS`(`docid`, `TITLE`, `TITLE_JPN`, `SIMPLE_TAGS`) VALUES (NEW.`rowid`, NEW.`TITLE`, NEW.`TITLE_JPN`, NEW.`SIMPLE_TAGS`); END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_GALLERIES_FTS_AFTER_INSERT AFTER INSERT ON `GALLERIES` BEGIN INSERT INTO `GALLERIES_FTS`(`docid`, `TITLE`, `TITLE_JPN`, `SIMPLE_TAGS`) VALUES (NEW.`rowid`, NEW.`TITLE`, NEW.`TITLE_JPN`, NEW.`SIMPLE_TAGS`); END"
],
"tableName": "GALLERIES_FTS",
"createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`TITLE` TEXT NOT NULL, `TITLE_JPN` TEXT NOT NULL, `SIMPLE_TAGS` TEXT, content=`GALLERIES`)",
"fields": [
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "simpleTags",
"columnName": "SIMPLE_TAGS",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": []
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7d1cfc4e9a9d506a73eb0520ae414d25')"
]
}
}
@@ -0,0 +1,534 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "f5752deda842dccabded1cdbf1c78384",
"entities": [
{
"tableName": "BOOKMARKS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`PAGE` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumb",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumb",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `LABEL` TEXT, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT, `ENABLE` INTEGER, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `MODE` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlotBackingField",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumb",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumb",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f5752deda842dccabded1cdbf1c78384')"
]
}
}
@@ -0,0 +1,534 @@
{
"formatVersion": 1,
"database": {
"version": 5,
"identityHash": "f5752deda842dccabded1cdbf1c78384",
"entities": [
{
"tableName": "BOOKMARKS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`PAGE` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `LABEL` TEXT, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT, `ENABLE` INTEGER, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `MODE` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlotBackingField",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f5752deda842dccabded1cdbf1c78384')"
]
}
}
@@ -0,0 +1,534 @@
{
"formatVersion": 1,
"database": {
"version": 6,
"identityHash": "e45f4380ef769c127604cb2a502a942b",
"entities": [
{
"tableName": "BOOKMARKS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`PAGE` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "page",
"columnName": "PAGE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `LABEL` TEXT, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT, `ENABLE` INTEGER, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `MODE` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlotBackingField",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e45f4380ef769c127604cb2a502a942b')"
]
}
}
@@ -0,0 +1,448 @@
{
"formatVersion": 1,
"database": {
"version": 7,
"identityHash": "9563c2017be4341dc1bada115426df77",
"entities": [
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `LABEL` TEXT, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT, `ENABLE` INTEGER, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `MODE` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlotBackingField",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9563c2017be4341dc1bada115426df77')"
]
}
}
@@ -0,0 +1,448 @@
{
"formatVersion": 1,
"database": {
"version": 8,
"identityHash": "f09bae277bbdab54ecbb0d698c83e734",
"entities": [
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `LABEL` TEXT, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `MODE` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlotBackingField",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f09bae277bbdab54ecbb0d698c83e734')"
]
}
}
@@ -0,0 +1,448 @@
{
"formatVersion": 1,
"database": {
"version": 9,
"identityHash": "64f51a531e13d2b0b971f3d8da0876b0",
"entities": [
{
"tableName": "DOWNLOADS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`STATE` INTEGER NOT NULL, `LEGACY` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, `LABEL` TEXT, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "state",
"columnName": "STATE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "legacy",
"columnName": "LEGACY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_LABELS",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LABEL` TEXT NOT NULL, `TIME` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "label",
"columnName": "LABEL",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "DOWNLOAD_DIRNAME",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GID` INTEGER NOT NULL, `DIRNAME` TEXT NOT NULL, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dirname",
"columnName": "DIRNAME",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "FILTER",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`MODE` INTEGER NOT NULL, `TEXT` TEXT NOT NULL, `ENABLE` INTEGER NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "TEXT",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "enable",
"columnName": "ENABLE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "HISTORY",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `MODE` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favoriteSlotBackingField",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LOCAL_FAVORITES",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`TIME` INTEGER NOT NULL, `GID` INTEGER NOT NULL, `TOKEN` TEXT, `TITLE` TEXT, `TITLE_JPN` TEXT, `THUMB` TEXT, `CATEGORY` INTEGER NOT NULL, `POSTED` TEXT, `UPLOADER` TEXT, `RATING` REAL NOT NULL, `SIMPLE_LANGUAGE` TEXT, PRIMARY KEY(`GID`))",
"fields": [
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "gid",
"columnName": "GID",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "token",
"columnName": "TOKEN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "TITLE",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "titleJpn",
"columnName": "TITLE_JPN",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbKey",
"columnName": "THUMB",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "posted",
"columnName": "POSTED",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "UPLOADER",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "rating",
"columnName": "RATING",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "simpleLanguage",
"columnName": "SIMPLE_LANGUAGE",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"GID"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "QUICK_SEARCH",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `NAME` TEXT, `MODE` INTEGER NOT NULL, `CATEGORY` INTEGER NOT NULL, `KEYWORD` TEXT, `ADVANCE_SEARCH` INTEGER NOT NULL, `MIN_RATING` INTEGER NOT NULL, `PAGE_FROM` INTEGER NOT NULL, `PAGE_TO` INTEGER NOT NULL, `TIME` INTEGER NOT NULL, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "NAME",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mode",
"columnName": "MODE",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "category",
"columnName": "CATEGORY",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "keyword",
"columnName": "KEYWORD",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "advanceSearch",
"columnName": "ADVANCE_SEARCH",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "minRating",
"columnName": "MIN_RATING",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageFrom",
"columnName": "PAGE_FROM",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pageTo",
"columnName": "PAGE_TO",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "TIME",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '64f51a531e13d2b0b971f3d8da0876b0')"
]
}
}
@@ -0,0 +1,46 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "69230710633494b4b331e10dae436fb7",
"entities": [
{
"tableName": "suggestions",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER, `date` LONG, `query` TEXT, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "date",
"columnName": "date",
"affinity": "LONG",
"notNull": false
},
{
"fieldPath": "query",
"columnName": "query",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '69230710633494b4b331e10dae436fb7')"
]
}
}
@@ -0,0 +1,46 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "bf4a5b5f3cb9bc7383488bae14f5d4bd",
"entities": [
{
"tableName": "suggestions",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`date` INTEGER NOT NULL, `query` TEXT NOT NULL, `_id` INTEGER, PRIMARY KEY(`_id`))",
"fields": [
{
"fieldPath": "date",
"columnName": "date",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "query",
"columnName": "query",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"_id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bf4a5b5f3cb9bc7383488bae14f5d4bd')"
]
}
}
+40 -53
View File
@@ -12,7 +12,8 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
@@ -27,22 +28,21 @@
android:hasFragileUserData="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="@bool/large_heap"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:targetApi="tiramisu">
<activity
android:name=".ui.login.LoginActivity"
android:exported="false"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"/>
<profileable android:shell="true" />
<activity
android:name=".ui.MainActivity"
android:banner="@mipmap/ic_leanback_banner"
android:configChanges="screenSize"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/AppTheme.Splash"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -69,8 +69,39 @@
<data android:scheme="https" />
<data android:host="exhentai.org" />
<data android:host="e-hentai.org" />
<data android:host="g.e-hentai.org" />
<data android:host="lofi.e-hentai.org" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:host="*" />
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/zip" />
<data android:mimeType="application/x-7z-compressed" />
<data android:mimeType="application/x-tar" />
<data android:mimeType="application/x-xz" />
<data android:mimeType="application/gzip" />
<data android:mimeType="application/vnd.rar" />
<data android:mimeType="application/vnd.comicbook+zip" />
<data android:mimeType="application/vnd.comicbook-rar" />
<!-- unofficial -->
<data android:mimeType="application/7z" />
<data android:mimeType="application/rar" />
<data android:mimeType="application/x-cbz" />
<data android:mimeType="application/x-cbr" />
<data android:mimeType="application/x-cbt" />
<data android:mimeType="application/x-cb7" />
<data android:mimeType="application/x-zip-compressed" />
<data android:mimeType="application/x-rar-compressed" />
<data android:mimeType="application/x-compressed-tar" />
<data android:mimeType="application/x-bzip-compressed-tar" />
<data android:mimeType="application/x-lzma-compressed-tar" />
<data android:mimeType="application/x-xz-compressed-tar" />
</intent-filter>
<intent-filter android:label="@string/keyword_search">
<action android:name="android.intent.action.SEND" />
@@ -87,54 +118,10 @@
<data android:mimeType="image/*" />
</intent-filter>
</activity>
<activity
android:name="eu.kanade.tachiyomi.ui.reader.ReaderActivity"
android:configChanges="screenSize"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:host="*" />
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/7z" />
<data android:mimeType="application/rar" />
<data android:mimeType="application/zip" />
<data android:mimeType="application/x-7z-compressed" />
<data android:mimeType="application/x-rar-compressed" />
<data android:mimeType="application/x-zip-compressed" />
<data android:mimeType="application/x-tar" />
<data android:mimeType="application/x-xz" />
<data android:mimeType="application/gzip" />
<data android:mimeType="application/x-cbz" />
<data android:mimeType="application/x-cbr" />
<data android:mimeType="application/x-cbt" />
<data android:mimeType="application/x-cb7" />
<!-- untested -->
<data android:mimeType="application/vnd.comicbook+zip" />
<data android:mimeType="application/vnd.comicbook-rar" />
<data android:mimeType="application/x-compressed-tar" />
<data android:mimeType="application/x-bzip-compressed-tar" />
<data android:mimeType="application/x-lzma-compressed-tar" />
<data android:mimeType="application/x-xz-compressed-tar" />
</intent-filter>
</activity>
<activity
android:name=".ui.SettingsActivity"
android:configChanges="screenSize"
android:label="@string/settings"
android:theme="@style/AppTheme" />
<activity
android:name=".ui.SecurityActivity"
android:configChanges="screenSize"
android:label="@string/settings"
android:theme="@style/AppTheme" />
android:label="@string/settings" />
<activity
android:name=".shortcuts.ShortcutsActivity"
android:excludeFromRecents="true"
@@ -0,0 +1,52 @@
From d1db03ebd9989d10a5a905b792b712c6487a0057 Mon Sep 17 00:00:00 2001
From: FooIbar <118464521+FooIbar@users.noreply.github.com>
Date: Sat, 24 Feb 2024 12:03:15 +0000
Subject: [PATCH] Don't build other binaries
---
CMakeLists.txt | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a346dd02..52b5d0d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1567,7 +1567,7 @@ endif()
# xzdec and lzmadec
#############################################################################
-if(HAVE_DECODERS AND (NOT MSVC OR MSVC_VERSION GREATER_EQUAL 1900))
+if(0)
foreach(XZDEC xzdec lzmadec)
add_executable("${XZDEC}"
src/common/sysdefs.h
@@ -1624,7 +1624,7 @@ endif()
# lzmainfo
#############################################################################
-if(HAVE_DECODERS AND (NOT MSVC OR MSVC_VERSION GREATER_EQUAL 1900))
+if(0)
add_executable(lzmainfo
src/common/sysdefs.h
src/common/tuklib_common.h
@@ -1680,7 +1680,7 @@ endif()
# xz
#############################################################################
-if(NOT MSVC OR MSVC_VERSION GREATER_EQUAL 1900)
+if(0)
add_executable(xz
src/common/mythread.h
src/common/sysdefs.h
@@ -1914,7 +1914,7 @@ endif()
# Scripts
#############################################################################
-if(UNIX)
+if(0)
# NOTE: This isn't as sophisticated as in the Autotools build which
# uses posix-shell.m4 but hopefully this doesn't need to be either.
# CMake likely won't be used on as many (old) obscure systems as the
--
2.34.1
@@ -1,34 +0,0 @@
From fc9fb0ea245259e346ab46c334f03b557fe63b6b Mon Sep 17 00:00:00 2001
From: tarsin <yuanqingxiang233@163.com>
Date: Tue, 22 Nov 2022 12:37:12 +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 01c73cd..b461e68 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -592,7 +592,7 @@ check_symbol_exists(getopt_long getopt.h HAVE_GETOPT_LONG)
# xzdec
#############################################################################
-if(HAVE_GETOPT_LONG)
+if(0)
add_executable(xzdec
src/common/sysdefs.h
src/common/tuklib_common.h
@@ -630,7 +630,7 @@ endif()
# xz
#############################################################################
-if(NOT MSVC AND HAVE_GETOPT_LONG)
+if(0)
add_executable(xz
src/common/mythread.h
src/common/sysdefs.h
--
2.39.2
@@ -1,38 +0,0 @@
From 2a67861e6f06794f3671c4988bac12330d8422e3 Mon Sep 17 00:00:00 2001
From: tarsin <yuanqingxiang233@163.com>
Date: Fri, 27 May 2022 23:21:20 +0800
Subject: [PATCH 1/2] Don't build shared lib
---
libarchive/CMakeLists.txt | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt
index ff7ade00..00c2e170 100644
--- a/libarchive/CMakeLists.txt
+++ b/libarchive/CMakeLists.txt
@@ -242,12 +242,6 @@ ELSEIF(ARCHIVE_ACL_SUNOS)
LIST(APPEND libarchive_SOURCES archive_disk_acl_sunos.c)
ENDIF()
-# Libarchive is a shared library
-ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
-TARGET_INCLUDE_DIRECTORIES(archive PUBLIC .)
-TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS})
-SET_TARGET_PROPERTIES(archive PROPERTIES SOVERSION ${SOVERSION})
-
# archive_static is a static library
ADD_LIBRARY(archive_static STATIC ${libarchive_SOURCES} ${include_HEADERS})
TARGET_LINK_LIBRARIES(archive_static ${ADDITIONAL_LIBS})
@@ -260,7 +254,7 @@ ENDIF(NOT WIN32 OR CYGWIN)
IF(ENABLE_INSTALL)
# How to install the libraries
- INSTALL(TARGETS archive archive_static
+ INSTALL(TARGETS archive_static
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
--
2.39.2
@@ -1,17 +1,17 @@
From c9298fd6dc0a8b04dd4b2247118b9cb895c46e58 Mon Sep 17 00:00:00 2001
From: tarsin <yuanqingxiang233@163.com>
Date: Sat, 23 Jul 2022 16:05:36 +0800
Subject: [PATCH 2/2] Insert link libs
From aee8f7147ddb262fd9e5feee8d5b17094cf3470f Mon Sep 17 00:00:00 2001
From: FooIbar <118464521+FooIbar@users.noreply.github.com>
Date: Tue, 26 Sep 2023 00:09:25 +0800
Subject: [PATCH] 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
index ec97e4c7..420f204c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -415,7 +415,7 @@ IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
@@ -438,7 +438,7 @@ IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
# # endif
ENDIF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
@@ -21,5 +21,5 @@ index 713e3bc5..7247640d 100644
# Find ZLIB
#
--
2.39.2
2.34.1
+74 -22
View File
@@ -1,9 +1,10 @@
cmake_minimum_required(VERSION 3.14)
project(ehviewer C ASM)
project(ehviewer C)
include(ExternalProject)
include(FetchContent)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -fvisibility=hidden -fvisibility-inlines-hidden -funroll-loops -flto=thin \
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -fvisibility=hidden -fvisibility-inlines-hidden -funroll-loops -flto \
-mllvm -polly \
-mllvm -polly-run-dce \
-mllvm -polly-run-inliner \
@@ -16,25 +17,52 @@ if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
-mllvm -polly-invariant-load-hoisting")
endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# Change the default path of fetch content to avoid downloading the same dependencies per architecture
get_filename_component(deps "../_deps" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
set(FETCHCONTENT_BASE_DIR ${deps})
option(BUILD_TESTING OFF)
FetchContent_Declare(liblzma
GIT_REPOSITORY https://git.tukaani.org/xz.git
GIT_TAG v5.4.1
PATCH_COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/0001-Don-t-build-other-binarys.patch || cd .
)
set(XZ_PATCH ${CMAKE_CURRENT_LIST_DIR}/0001-Don-t-build-other-binaries.patch)
FetchContent_Declare(
liblzma
GIT_REPOSITORY https://github.com/tukaani-project/xz.git
GIT_TAG v5.6.3
GIT_SHALLOW 1
PATCH_COMMAND git apply --check -R ${XZ_PATCH} || git apply ${XZ_PATCH}
)
FetchContent_MakeAvailable(liblzma)
include_directories(${liblzma_SOURCE_DIR}/src/liblzma/api)
# Build GNUTLS libnettle
add_subdirectory(nettle)
if (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
execute_process(
COMMAND wsl wslpath ${CMAKE_CURRENT_LIST_DIR}
OUTPUT_VARIABLE CURRENT_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else ()
set(CURRENT_DIR ${CMAKE_CURRENT_LIST_DIR})
endif ()
set(NDK_VERSION "${ANDROID_NDK_MAJOR}.${ANDROID_NDK_MINOR}.${ANDROID_NDK_BUILD}")
ExternalProject_Add(
nettle
PREFIX nettle
GIT_REPOSITORY https://gitlab.com/gnutls/nettle.git
GIT_TAG nettle_3.10_release_20240616
GIT_SHALLOW 1
GIT_CONFIG core.autocrlf=input
CONFIGURE_COMMAND bash ${CURRENT_DIR}/configure_nettle.sh ${NDK_VERSION} ${CMAKE_C_COMPILER_TARGET}
BUILD_COMMAND bash -c "make libnettle.a CFLAGS='${CMAKE_C_FLAGS} -Qunused-arguments'"
INSTALL_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_BYPRODUCTS nettle/src/nettle/libnettle.a
)
ExternalProject_Get_Property(nettle SOURCE_DIR)
include_directories(${SOURCE_DIR}/..)
add_library(libnettle STATIC IMPORTED)
set_property(TARGET libnettle PROPERTY IMPORTED_LOCATION ${SOURCE_DIR}/libnettle.a)
add_dependencies(libnettle nettle)
# Configure libnettle support for libarchive
include_directories(nettle)
include_directories(.)
set(HAVE_LIBNETTLE 1)
set(HAVE_NETTLE_AES_H 1)
set(HAVE_NETTLE_HMAC_H 1)
@@ -50,18 +78,42 @@ SET(HAVE_LZMA_STREAM_ENCODER_MT 1)
SET(HAVE_LZMADEC_H 1)
SET(HAVE_LIBLZMADEC 1)
# Configure libarchive link's static lib
SET(LIBARCHIVE_CUSTOM_LIBS "nettle" "liblzma")
option(ENABLE_OPENSSL OFF)
option(ENABLE_TAR OFF)
option(ENABLE_CPIO OFF)
option(ENABLE_CAT OFF)
option(ENABLE_UNZIP OFF)
option(ENABLE_TEST OFF)
FetchContent_Declare(libarchive
GIT_REPOSITORY https://github.com/libarchive/libarchive
GIT_TAG v3.6.2
PATCH_COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/0001-Don-t-build-shared-lib.patch ${CMAKE_CURRENT_LIST_DIR}/0002-Insert-link-libs.patch || cd .
)
# Configure libarchive link's static lib
SET(LIBARCHIVE_CUSTOM_LIBS "libnettle" "liblzma")
set(LIBARCHIVE_PATCH ${CMAKE_CURRENT_LIST_DIR}/0001-Insert-link-libs.patch)
FetchContent_Declare(
libarchive
GIT_REPOSITORY https://github.com/libarchive/libarchive.git
GIT_TAG v3.7.7
GIT_SHALLOW 1
PATCH_COMMAND git apply --check -R ${LIBARCHIVE_PATCH} || git apply ${LIBARCHIVE_PATCH}
)
FetchContent_MakeAvailable(libarchive)
include_directories(${libarchive_SOURCE_DIR}/libarchive)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.5
GIT_SHALLOW 1
)
FetchContent_MakeAvailable(Corrosion)
corrosion_import_crate(MANIFEST_PATH ../rust/Cargo.toml LOCKED)
corrosion_add_target_local_rustflags(ehviewer_rust "-Clink-args=-Wl,-z,max-page-size=16384")
if (ANDROID_NATIVE_API_LEVEL GREATER_EQUAL 26)
corrosion_set_features(ehviewer_rust FEATURES api-level-26)
endif ()
# Build and link our app's native lib
add_library(${PROJECT_NAME} SHARED archive.c gifutils.c natsort/strnatcmp.c)
target_link_libraries(${PROJECT_NAME} archive_static log)
add_library(${PROJECT_NAME} SHARED archive.c gifutils.c hash.c natsort/strnatcmp.c)
target_link_libraries(${PROJECT_NAME} ehviewer_rust archive_static log jnigraphics -Wl,--exclude-libs,ALL)
+162 -119
View File
@@ -34,7 +34,6 @@
#include "natsort/strnatcmp.h"
#include "ehviewer.h"
#include "spinlock.h"
typedef struct {
int using;
@@ -49,25 +48,25 @@ typedef struct {
size_t size;
} entry;
_Atomic mcs_lock ctx_lock;
static archive_ctx **ctx_pool;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static archive_ctx **ctx_pool = NULL;
#define CTX_POOL_SIZE 20
static void *mempool = NULL;
static void *mempool = MAP_FAILED;
static size_t *mempoolofs = NULL;
static int page_size = 0;
#define PAGE_ALIGN(x) ((x + ~PAGE_MASK) & PAGE_MASK)
#define PAGE_ALIGN(x) ((x + page_size - 1) & ~(page_size - 1))
#define MEMPOOL_ADDR_BY_SORTED_IDX(x) (mempool + (index ? mempoolofs[index - 1] : 0))
#define MEMPOOL_SIZE (mempoolofs[entryCount - 1])
#define MEMPOOL_ENTITY_SIZE(x) PAGE_ALIGN(entries[x].size)
#define PROT_RW (PROT_WRITE | PROT_READ)
#define MAP_ANON_POOL (MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE | MAP_UNINITIALIZED)
#define MAP_ANON_POOL (MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE)
static bool need_encrypt = false;
static char *passwd = NULL;
static void *archiveAddr = NULL;
static void *archiveAddr = MAP_FAILED;
static size_t archiveSize = 0;
static entry *entries = NULL;
static size_t entryCount = 0;
@@ -86,6 +85,8 @@ const char supportExt[10][6] = {
};
static inline int filename_is_playable_file(const char *name) {
if (!name)
return false;
const char *dotptr = strrchr(name, '.');
if (!dotptr++)
return false;
@@ -96,26 +97,39 @@ static inline int filename_is_playable_file(const char *name) {
return false;
}
static inline const char *archive_entry_pathname2(struct archive_entry *entry) {
const char *name = archive_entry_pathname_utf8(entry);
return name ? name : archive_entry_pathname(entry);
}
static inline bool archive_entry_is_file(struct archive_entry *entry) {
return archive_entry_filetype(entry) == AE_IFREG;
}
static inline bool archive_entry_is_playable(struct archive_entry *entry) {
return archive_entry_is_file(entry) &&
filename_is_playable_file(archive_entry_pathname2(entry));
}
static inline int compare_entries(const void *a, const void *b) {
const char *fa = ((entry *) a)->filename;
const char *fb = ((entry *) b)->filename;
return strnatcmp(fa, fb);
}
static long archive_map_entries_index(archive_ctx *ctx) {
long count = 0;
static int archive_map_entries_index(archive_ctx *ctx, bool sort) {
int count = 0;
while (archive_read_next_header(ctx->arc, &ctx->entry) == ARCHIVE_OK) {
const char *name = archive_entry_pathname(ctx->entry);
if (filename_is_playable_file(name)) {
const char *name = archive_entry_pathname2(ctx->entry);
if (archive_entry_is_file(ctx->entry) && filename_is_playable_file(name)) {
entries[count].filename = strdup(name);
entries[count].index = count;
entries[count].size = archive_entry_size(ctx->entry);
count++;
}
}
if (!count)
LOGE("%s", archive_error_string(ctx->arc));
qsort(entries, entryCount, sizeof(entry), compare_entries);
if (sort)
qsort(entries, entryCount, sizeof(entry), compare_entries);
return count;
}
@@ -135,39 +149,27 @@ static bool archive_prealloc_mempool() {
return true;
}
// Mincore does not support anon mapping yet
// Now that we use MADV_FREE, how can we detect whether pages is reclaimed?
static bool is_mempool_pages_present_and_lock(int index) {
void *addr = MEMPOOL_ADDR_BY_SORTED_IDX(index);
size_t size = MEMPOOL_ENTITY_SIZE(index);
mlock(addr, size);
#if 0
unsigned char vec[size / PAGE_SIZE];
unsigned char r = 1;
mincore(addr, size, vec);
for (int i = 0; i < size / PAGE_SIZE; ++i) r &= vec[i];
return r;
#endif
return false;
}
#define MEMPOOL_IN_CORE_AND_LOCK(x) is_mempool_pages_present_and_lock(x)
#define ADDR_IN_FILE_MAPPING(addr) (addr >= archiveAddr && addr < archiveAddr + archiveSize)
static void mempool_release_pages(void *addr, size_t size) {
size = PAGE_ALIGN(size);
munlock(addr, size);
int ret = madvise(addr, size, MADV_FREE);
if (ret == -EINVAL) madvise(addr, size, MADV_DONTNEED);
madvise_log_if_error(addr, size, MADV_DONTNEED);
}
static long archive_list_all_entries(archive_ctx *ctx) {
long count = 0;
static bool kernel_can_prefault = true;
static void mempool_prefault_pages(void *addr, size_t size) {
size = PAGE_ALIGN(size);
if (kernel_can_prefault) {
if (madvise(addr, size, MADV_POPULATE_WRITE)) kernel_can_prefault = false;
}
}
static int archive_list_all_entries(archive_ctx *ctx) {
int count = 0;
while (archive_read_next_header(ctx->arc, &ctx->entry) == ARCHIVE_OK)
if (filename_is_playable_file(archive_entry_pathname(ctx->entry)))
if (archive_entry_is_playable(ctx->entry))
count++;
if (!count)
LOGE("%s", archive_error_string(ctx->arc));
return count;
}
@@ -212,7 +214,7 @@ static int archive_alloc_ctx(archive_ctx **ctxptr) {
static int archive_skip_to_index(archive_ctx *ctx, int index) {
while (archive_read_next_header(ctx->arc, &ctx->entry) == ARCHIVE_OK) {
if (!filename_is_playable_file(archive_entry_pathname(ctx->entry)))
if (!archive_entry_is_playable(ctx->entry))
continue;
if (ctx->next_index++ == index) {
return ctx->next_index - 1;
@@ -224,8 +226,7 @@ static int archive_skip_to_index(archive_ctx *ctx, int index) {
static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
int ret;
archive_ctx *ctx = NULL;
mcs_lock_t local_lock;
lock_mcs(&ctx_lock, &local_lock);
pthread_mutex_lock(&mutex);
for (int i = 0; i < CTX_POOL_SIZE; i++) {
if (!ctx_pool[i])
continue;
@@ -240,7 +241,7 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
}
if (ctx)
ctx->using = 1;
unlock_mcs(&ctx_lock, &local_lock);
pthread_mutex_unlock(&mutex);
if (!ctx) {
archive_ctx *victimCtx = NULL;
@@ -249,7 +250,7 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
ret = archive_alloc_ctx(&ctx);
if (ret)
return ret;
lock_mcs(&ctx_lock, &local_lock);
pthread_mutex_lock(&mutex);
for (int i = 0; i < CTX_POOL_SIZE; i++) {
if (!ctx_pool[i]) {
ctx_pool[i] = ctx;
@@ -264,7 +265,7 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
}
}
if (replace) ctx_pool[victimIdx] = ctx;
unlock_mcs(&ctx_lock, &local_lock);
pthread_mutex_unlock(&mutex);
if (replace) archive_release_ctx(victimCtx);
}
ret = archive_skip_to_index(ctx, idx);
@@ -279,32 +280,36 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
}
JNIEXPORT jint JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_openArchive(JNIEnv *env, jclass thiz, jint fd,
jlong size) {
Java_com_hippo_ehviewer_jni_ArchiveKt_openArchive(JNIEnv *env, jclass thiz, jint fd, jlong size, jboolean sort_entries) {
EH_UNUSED(env);
EH_UNUSED(thiz);
page_size = getpagesize();
archive_ctx *ctx = NULL;
int mmap_flags = MAP_PRIVATE;
archiveAddr = mmap64(0, size, PROT_READ, mmap_flags, fd, 0);
archiveAddr = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (archiveAddr == MAP_FAILED) {
LOGE("%s%s", "mmap64 failed with error ", strerror(errno));
LOGE("%s%s", "mmap failed with error ", strerror(errno));
return 0;
}
archiveSize = size;
madvise_log_if_error(archiveAddr, archiveSize, MADV_WILLNEED);
ctx_pool = calloc(CTX_POOL_SIZE, sizeof(archive_ctx **));
if (!ctx_pool) {
LOGE("Allocate archive ctx pool failed:ENOMEM");
return 0;
}
long r = archive_alloc_ctx(&ctx);
int r = archive_alloc_ctx(&ctx);
if (r) {
if (r == -ENOMEM)
LOGE("%s", "Mem alloc failed");
LOGE("%s%s", "Archive open failed:", archive_error_string(ctx->arc));
return 0;
} else {
entryCount = archive_list_all_entries(ctx);
LOGI("%s%zu%s", "Found ", entryCount, " image entries in archive");
if (!entryCount) {
LOGE("%s%s", "Archive open failed:", archive_error_string(ctx->arc));
archive_release_ctx(ctx);
return 0;
}
// We must read through the file|vm then we can know whether it is encrypted
int encryptRet = archive_read_has_encrypted_entries(ctx->arc);
@@ -340,13 +345,9 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_openArchive(JNIEnv *env, jcl
LOGE("%s%s", "Archive open failed:", archive_error_string(ctx->arc));
} else {
entries = calloc(entryCount, sizeof(entry));
r = archive_map_entries_index(ctx);
r = archive_map_entries_index(ctx, sort_entries);
if (!archive_prealloc_mempool()) {
r = 0;
for (int i = 0; i < entryCount; ++i) {
free((void *) entries[i].filename);
}
free(entries);
}
}
@@ -354,84 +355,100 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_openArchive(JNIEnv *env, jcl
return r;
}
#pragma clang diagnostic push
#pragma ide diagnostic ignored "ConstantConditionsOC"
#pragma ide diagnostic ignored "UnreachableCode"
JNIEXPORT jobject JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_extractToByteBuffer(JNIEnv *env, jclass thiz,
jint index) {
Java_com_hippo_ehviewer_jni_ArchiveKt_extractToByteBuffer(JNIEnv *env, jclass thiz, jint index) {
EH_UNUSED(env);
EH_UNUSED(thiz);
void *addr = MEMPOOL_ADDR_BY_SORTED_IDX(index);
size_t size = entries[index].size;
if (!MEMPOOL_IN_CORE_AND_LOCK(index)) {
index = entries[index].index;
archive_ctx *ctx = NULL;
int ret;
ret = archive_get_ctx(&ctx, index);
if (ret) return 0;
ret = archive_read_data(ctx->arc, addr, size);
index = entries[index].index;
archive_ctx *ctx = NULL;
int ret = archive_get_ctx(&ctx, index);
if (ret) return 0;
void *buffer = NULL;
size_t buffer_size = 0;
la_int64_t output_ofs = 0;
archive_read_data_block(ctx->arc, (const void **) &buffer, &buffer_size, &output_ofs);
bool zero_copy = ADDR_IN_FILE_MAPPING(buffer) && !output_ofs && buffer_size == size;
if (zero_copy) {
ctx->using = 0;
if (ret == size)
return (*env)->NewDirectByteBuffer(env, addr, size);
if (ret != size)
LOGE("%s", "No enough data read, WTF?");
if (ret < 0)
LOGE("%s%s", "Archive read failed:", archive_error_string(ctx->arc));
mempool_release_pages(addr, size);
return (*env)->NewDirectByteBuffer(env, buffer, buffer_size);
} else {
return (*env)->NewDirectByteBuffer(env, addr, size);
size_t bytes = 0;
mempool_prefault_pages(addr, size);
do {
memcpy(addr + output_ofs, buffer, buffer_size);
bytes += buffer_size;
ret = archive_read_data_block(ctx->arc, (const void **) &buffer, &buffer_size, &output_ofs);
} while (bytes != size && !ret);
ctx->using = 0;
if (bytes == size) {
return (*env)->NewDirectByteBuffer(env, addr, size);
} else {
if (ret < 0) {
LOGE("%s%s", "Archive read failed:", archive_error_string(ctx->arc));
} else {
LOGE("%s", "No enough data read, WTF?");
}
}
mempool_release_pages(addr, size);
}
return 0;
}
#pragma clang diagnostic pop
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_closeArchive(JNIEnv *env, jclass thiz) {
Java_com_hippo_ehviewer_jni_ArchiveKt_closeArchive(JNIEnv *env, jclass thiz) {
EH_UNUSED(env);
EH_UNUSED(thiz);
for (int i = 0; i < CTX_POOL_SIZE; i++)
archive_release_ctx(ctx_pool[i]);
if (ctx_pool) {
for (int i = 0; i < CTX_POOL_SIZE; i++)
archive_release_ctx(ctx_pool[i]);
free(ctx_pool);
ctx_pool = NULL;
}
free(passwd);
free(ctx_pool);
passwd = NULL;
need_encrypt = false;
munmap(archiveAddr, archiveSize);
munmap(mempool, MEMPOOL_SIZE);
if (archiveAddr != MAP_FAILED) {
munmap(archiveAddr, archiveSize);
archiveAddr = MAP_FAILED;
}
if (mempool != MAP_FAILED) {
munmap(mempool, MEMPOOL_SIZE);
mempool = MAP_FAILED;
}
free(mempoolofs);
for (int i = 0; i < entryCount; ++i) {
free((void *) entries[i].filename);
mempoolofs = NULL;
if (entries) {
for (int i = 0; i < entryCount; ++i) {
free((void *) entries[i].filename);
}
free(entries);
entries = NULL;
}
free(entries);
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_needPassword(JNIEnv *env, jclass thiz) {
Java_com_hippo_ehviewer_jni_ArchiveKt_needPassword(JNIEnv *env, jclass thiz) {
EH_UNUSED(env);
EH_UNUSED(thiz);
return need_encrypt;
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_providePassword(JNIEnv *env, jclass thiz,
jstring str) {
Java_com_hippo_ehviewer_jni_ArchiveKt_providePassword(JNIEnv *env, jclass thiz, jstring str) {
EH_UNUSED(thiz);
struct archive_entry *entry;
archive_ctx *ctx;
jboolean ret = true;
int len = (*env)->GetStringUTFLength(env, str);
passwd = realloc(passwd, len * sizeof(char));
if (!passwd) {
LOGE("Allocate passwd buffer failed");
return false;
}
strcpy(passwd, (*env)->GetStringUTFChars(env, str, NULL));
passwd = realloc(passwd, len + 1);
(*env)->GetStringUTFRegion(env, str, 0, len, passwd);
passwd[len] = 0;
archive_alloc_ctx(&ctx);
void *tmpBuf = alloca(4096);
while (archive_read_next_header(ctx->arc, &entry) == ARCHIVE_OK) {
if (!filename_is_playable_file(archive_entry_pathname(entry)))
if (!archive_entry_is_playable(entry))
continue;
if (!archive_entry_is_encrypted(entry))
continue;
@@ -446,24 +463,15 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_providePassword(JNIEnv *env,
}
JNIEXPORT jstring JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_getFilename(JNIEnv *env, jclass thiz,
jint index) {
Java_com_hippo_ehviewer_jni_ArchiveKt_getExtension(JNIEnv *env, jclass thiz, jint index) {
EH_UNUSED(env);
EH_UNUSED(thiz);
index = entries[index].index;
archive_ctx *ctx = NULL;
int ret;
ret = archive_get_ctx(&ctx, index);
if (ret)
return NULL;
jstring str = (*env)->NewStringUTF(env, archive_entry_pathname(ctx->entry));
ctx->using = 0;
return str;
const char *ext = strrchr(entries[index].filename, '.') + 1;
return (*env)->NewStringUTF(env, ext);
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_extractToFd(JNIEnv *env, jclass thiz,
jint index, jint fd) {
JNIEXPORT jboolean JNICALL
Java_com_hippo_ehviewer_jni_ArchiveKt_extractToFd(JNIEnv *env, jclass thiz, jint index, jint fd) {
EH_UNUSED(env);
EH_UNUSED(thiz);
index = entries[index].index;
@@ -471,16 +479,51 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_extractToFd(JNIEnv *env, jcl
int ret;
ret = archive_get_ctx(&ctx, index);
if (!ret) {
archive_read_data_into_fd(ctx->arc, fd);
ret = archive_read_data_into_fd(ctx->arc, fd);
ctx->using = 0;
}
return ret == ARCHIVE_OK;
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_releaseByteBuffer(JNIEnv *env, jclass thiz,
jobject buffer) {
Java_com_hippo_ehviewer_jni_ArchiveKt_releaseByteBuffer(JNIEnv *env, jclass thiz, jobject buffer) {
EH_UNUSED(thiz);
void *addr = (*env)->GetDirectBufferAddress(env, buffer);
size_t size = (*env)->GetDirectBufferCapacity(env, buffer);
mempool_release_pages(addr, size);
if (!ADDR_IN_FILE_MAPPING(addr)) mempool_release_pages(addr, size);
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_jni_ArchiveKt_archiveFdBatch(JNIEnv *env, jclass clazz, jintArray fd_batch, jobjectArray names, jint arc_fd, jint size) {
EH_UNUSED(clazz);
struct archive *arc = archive_write_new();
struct stat st;
char buff[8192];
jint fdBatch[size];
(*env)->GetIntArrayRegion(env, fd_batch, 0, size, fdBatch);
archive_write_set_format_zip(arc);
archive_write_zip_set_compression_store(arc);
archive_write_open_fd(arc, arc_fd);
struct archive_entry *entry = archive_entry_new();
for (int i = 0; i < size; i++) {
int fd = fdBatch[i];
jobject name = (*env)->GetObjectArrayElement(env, names, i);
const char *cname = (*env)->GetStringUTFChars(env, name, false);
archive_entry_set_pathname(entry, cname);
(*env)->ReleaseStringUTFChars(env, name, cname);
fstat(fd, &st);
archive_entry_copy_stat(entry, &st);
archive_entry_set_perm(entry, 0644);
archive_write_header(arc, entry);
int len;
do {
len = read(fd, buff, sizeof(buff));
archive_write_data(arc, buff, len);
} while (len > 0);
archive_write_finish_entry(arc);
archive_entry_clear(entry);
}
archive_entry_free(entry);
archive_write_close(arc);
archive_write_free(arc);
}
+13
View File
@@ -0,0 +1,13 @@
SUFFIX=toolchains/llvm/prebuilt/$(uname -s | tr '[:upper:]' '[:lower:]')-x86_64/bin
CI_NDK_LOCATION=$ANDROID_HOME/ndk/$1/$SUFFIX
ARCH_NDK_LOCATION=$ANDROID_HOME/ndk-bundle/$SUFFIX
if test -e $CI_NDK_LOCATION ;then
TOOLCHAIN=$CI_NDK_LOCATION
else
TOOLCHAIN=$ARCH_NDK_LOCATION
fi
TARGET=$2
./.bootstrap && ./configure --host=$TARGET --disable-public-key --disable-dependency-tracking \
AR=$TOOLCHAIN/llvm-ar \
CC="$TOOLCHAIN/clang -target $TARGET" \
RANLIB=$TOOLCHAIN/llvm-ranlib
+23 -7
View File
@@ -1,6 +1,7 @@
#include <jni.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <android/log.h>
#include <sys/stat.h>
#include <sys/mman.h>
@@ -11,6 +12,7 @@
#define GIF_HEADER_87A "GIF87a"
#define GIF_HEADER_89A "GIF89a"
#define GIF_HEADER_LENGTH 6
static int FRAME_DELAY_START_MARKER = 0x0021F904;
@@ -21,7 +23,8 @@ typedef signed char byte;
#define DEFAULT_FRAME_DELAY 10
static inline bool isGif(void *addr) {
return !memcmp(addr, GIF_HEADER_87A, 6) || !memcmp(addr, GIF_HEADER_89A, 6);
return !memcmp(addr, GIF_HEADER_87A, GIF_HEADER_LENGTH) ||
!memcmp(addr, GIF_HEADER_89A, GIF_HEADER_LENGTH);
}
static void doRewrite(byte *addr, size_t size) {
@@ -42,20 +45,33 @@ static void doRewrite(byte *addr, size_t size) {
}
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_ehviewer_jni_GifUtilsKt_isGif(JNIEnv *env, jclass clazz, jint fd) {
byte buffer[GIF_HEADER_LENGTH];
return read(fd, buffer, GIF_HEADER_LENGTH) == GIF_HEADER_LENGTH &&
isGif(buffer);
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_image_ImageKt_rewriteGifSource(JNIEnv *env, jclass clazz, jobject buffer) {
Java_com_hippo_ehviewer_jni_GifUtilsKt_rewriteGifSource(JNIEnv *env, jclass clazz, jobject buffer) {
byte *addr = (*env)->GetDirectBufferAddress(env, buffer);
size_t size = (*env)->GetDirectBufferCapacity(env, buffer);
doRewrite(addr, size);
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_image_ImageKt_rewriteGifSource2(JNIEnv *env, jclass clazz, jint fd) {
JNIEXPORT jobject JNICALL
Java_com_hippo_ehviewer_jni_GifUtilsKt_mmap(JNIEnv *env, jclass clazz, jint fd) {
struct stat64 st;
fstat64(fd, &st);
size_t size = st.st_size;
byte *addr = mmap64(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) return;
doRewrite(addr, size);
byte *addr = mmap64(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED) return NULL;
return (*env)->NewDirectByteBuffer(env, addr, size);
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_jni_GifUtilsKt_munmap(JNIEnv *env, jclass clazz, jobject buffer) {
byte *addr = (*env)->GetDirectBufferAddress(env, buffer);
size_t size = (*env)->GetDirectBufferCapacity(env, buffer);
munmap(addr, size);
}
+39
View File
@@ -0,0 +1,39 @@
#include <unistd.h>
#include <jni.h>
#include <nettle/sha1.h>
#include "ehviewer.h"
#define BUFFER_SIZE 8192
typedef uint8_t byte;
const char hex_digits[] = "0123456789abcdef";
JNIEXPORT jstring JNICALL
Java_com_hippo_ehviewer_jni_HashKt_sha1(JNIEnv *env, jclass clazz, jint fd) {
EH_UNUSED(clazz);
struct sha1_ctx ctx;
sha1_init(&ctx);
size_t bytes_read;
byte buffer[BUFFER_SIZE];
while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) {
sha1_update(&ctx, bytes_read, buffer);
}
byte digest[SHA1_DIGEST_SIZE];
sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
byte byte;
char hex_digest[2 * SHA1_DIGEST_SIZE + 1];
for (int i = 0; i < SHA1_DIGEST_SIZE; i++) {
byte = digest[i];
hex_digest[2 * i] = hex_digits[byte >> 4 & 0xF];
hex_digest[2 * i + 1] = hex_digits[byte & 0xF];
}
hex_digest[2 * SHA1_DIGEST_SIZE] = '\0';
return (*env)->NewStringUTF(env, hex_digest);
}
+24 -85
View File
@@ -30,7 +30,6 @@
* negative chars in their default char type.
*/
#include <stddef.h> /* size_t */
#include <ctype.h>
#include "strnatcmp.h"
@@ -39,28 +38,21 @@
/* These are defined as macros to make it easier to adapt this code to
* different characters types or comparison functions. */
static inline int
nat_isdigit(nat_char a)
nat_isdigit(const char *a)
{
return isdigit((unsigned char) a);
return isdigit((unsigned char) *a);
}
static inline int
nat_isspace(nat_char a)
nat_isspace(const char *a)
{
return isspace((unsigned char) a);
}
static inline nat_char
nat_toupper(nat_char a)
{
return toupper((unsigned char) a);
return isspace((unsigned char) *a) || *a == '0' && nat_isdigit(a + 1);
}
static int
compare_right(nat_char const *a, nat_char const *b)
compare_right(const char *a, const char *b)
{
int bias = 0;
@@ -69,11 +61,11 @@ compare_right(nat_char const *a, nat_char const *b)
both numbers to know that they have the same magnitude, so we
remember it in BIAS. */
for (;; a++, b++) {
if (!nat_isdigit(*a) && !nat_isdigit(*b))
if (!nat_isdigit(a) && !nat_isdigit(b))
return bias;
if (!nat_isdigit(*a))
if (!nat_isdigit(a))
return -1;
if (!nat_isdigit(*b))
if (!nat_isdigit(b))
return +1;
if (*a < *b) {
if (!bias)
@@ -84,94 +76,41 @@ compare_right(nat_char const *a, nat_char const *b)
} else if (!*a && !*b)
return bias;
}
return 0;
}
static int
compare_left(nat_char const *a, nat_char const *b)
int
strnatcmp(const char *a, const char *b)
{
/* Compare two left-aligned numbers: the first to have a
different value wins. */
for (;; a++, b++) {
if (!nat_isdigit(*a) && !nat_isdigit(*b))
return 0;
if (!nat_isdigit(*a))
return -1;
if (!nat_isdigit(*b))
return +1;
if (*a < *b)
return -1;
if (*a > *b)
return +1;
}
int result;
return 0;
}
while (1) {
/* skip over leading spaces or zeros */
while (nat_isspace(a))
a++;
static int
strnatcmp0(nat_char const *a, nat_char const *b, int fold_case)
{
int ai, bi;
nat_char ca, cb;
int fractional, result;
ai = bi = 0;
while (1) {
ca = a[ai]; cb = b[bi];
/* skip over leading spaces or zeros */
while (nat_isspace(ca))
ca = a[++ai];
while (nat_isspace(cb))
cb = b[++bi];
while (nat_isspace(b))
b++;
/* process run of digits */
if (nat_isdigit(ca) && nat_isdigit(cb)) {
fractional = (ca == '0' || cb == '0');
if (fractional) {
if ((result = compare_left(a+ai, b+bi)) != 0)
return result;
} else {
if ((result = compare_right(a+ai, b+bi)) != 0)
return result;
}
if (nat_isdigit(a) && nat_isdigit(b)) {
if ((result = compare_right(a, b)) != 0)
return result;
}
if (!ca && !cb) {
if (!*a && !*b) {
/* The strings compare the same. Perhaps the caller
will want to call strcmp to break the tie. */
return 0;
}
if (fold_case) {
ca = nat_toupper(ca);
cb = nat_toupper(cb);
}
if (ca < cb)
if (*a < *b)
return -1;
if (ca > cb)
if (*a > *b)
return +1;
++ai; ++bi;
a++; b++;
}
}
int
strnatcmp(nat_char const *a, nat_char const *b) {
return strnatcmp0(a, b, 0);
}
/* Compare, recognizing numeric string and ignoring case. */
int
strnatcasecmp(nat_char const *a, nat_char const *b) {
return strnatcmp0(a, b, 1);
}
+1 -8
View File
@@ -24,14 +24,7 @@
extern "C" {
#endif
/* CUSTOMIZATION SECTION
*
* You can change this typedef, but must then also change the inline
* functions in strnatcmp.c */
typedef char nat_char;
int strnatcmp(nat_char const *a, nat_char const *b);
int strnatcasecmp(nat_char const *a, nat_char const *b);
int strnatcmp(const char *a, const char *b);
#ifdef __cplusplus
}
-239
View File
@@ -1,239 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
project(nettle C)
set(LIBNETTLE_DEFINITIONS
-DHAVE_CONFIG_H)
set(LIBNETTLE_SOURCES
nettle/aes-decrypt-internal.c
nettle/aes-decrypt.c
nettle/aes-decrypt-table.c
nettle/aes128-decrypt.c
nettle/aes192-decrypt.c
nettle/aes256-decrypt.c
nettle/aes-encrypt-internal.c
nettle/aes-encrypt.c
nettle/aes-encrypt-table.c
nettle/aes128-encrypt.c
nettle/aes192-encrypt.c
nettle/aes256-encrypt.c
nettle/aes-invert-internal.c
nettle/aes-set-key-internal.c
nettle/aes-set-encrypt-key.c
nettle/aes-set-decrypt-key.c
nettle/aes128-set-encrypt-key.c
nettle/aes128-set-decrypt-key.c
nettle/aes128-meta.c
nettle/aes192-set-encrypt-key.c
nettle/aes192-set-decrypt-key.c
nettle/aes192-meta.c
nettle/aes256-set-encrypt-key.c
nettle/aes256-set-decrypt-key.c
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
nettle/blowfish-bcrypt.c
nettle/base16-encode.c
nettle/base16-decode.c
nettle/base16-meta.c
nettle/base64-encode.c
nettle/base64-decode.c
nettle/base64-meta.c
nettle/base64url-encode.c
nettle/base64url-decode.c
nettle/base64url-meta.c
nettle/buffer.c
nettle/buffer-init.c
nettle/camellia-crypt-internal.c
nettle/camellia-table.c
nettle/camellia-absorb.c
nettle/camellia-invert-key.c
nettle/camellia128-set-encrypt-key.c
nettle/camellia128-crypt.c
nettle/camellia128-set-decrypt-key.c
nettle/camellia128-meta.c
nettle/camellia192-meta.c
nettle/camellia256-set-encrypt-key.c
nettle/camellia256-crypt.c
nettle/camellia256-set-decrypt-key.c
nettle/camellia256-meta.c
nettle/cast128.c
nettle/cast128-meta.c
nettle/cbc.c
nettle/cbc-aes128-encrypt.c
nettle/cbc-aes192-encrypt.c
nettle/cbc-aes256-encrypt.c
nettle/ccm.c
nettle/ccm-aes128.c
nettle/ccm-aes192.c
nettle/ccm-aes256.c
nettle/cfb.c
nettle/siv-cmac.c
nettle/siv-cmac-aes128.c
nettle/siv-cmac-aes256.c
nettle/cnd-memcpy.c
nettle/chacha-crypt.c
nettle/chacha-core-internal.c
nettle/chacha-poly1305.c
nettle/chacha-poly1305-meta.c
nettle/chacha-set-key.c
nettle/chacha-set-nonce.c
nettle/ctr.c
nettle/ctr16.c
nettle/des.c
nettle/des3.c
nettle/eax.c
nettle/eax-aes128.c
nettle/eax-aes128-meta.c
nettle/ghash-set-key.c
nettle/ghash-update.c
nettle/gcm.c
nettle/gcm-aes.c
nettle/gcm-aes128.c
nettle/gcm-aes128-meta.c
nettle/gcm-aes192.c
nettle/gcm-aes192-meta.c
nettle/gcm-aes256.c
nettle/gcm-aes256-meta.c
nettle/gcm-camellia128.c
nettle/gcm-camellia128-meta.c
nettle/gcm-camellia256.c
nettle/gcm-camellia256-meta.c
nettle/cmac.c
nettle/cmac64.c
nettle/cmac-aes128.c
nettle/cmac-aes256.c
nettle/cmac-des3.c
nettle/cmac-aes128-meta.c
nettle/cmac-aes256-meta.c
nettle/cmac-des3-meta.c
nettle/gost28147.c
nettle/gosthash94.c
nettle/gosthash94-meta.c
nettle/hmac.c
nettle/hmac-gosthash94.c
nettle/hmac-md5.c
nettle/hmac-ripemd160.c
nettle/hmac-sha1.c
nettle/hmac-sha224.c
nettle/hmac-sha256.c
nettle/hmac-sha384.c
nettle/hmac-sha512.c
nettle/hmac-streebog.c
nettle/hmac-sm3.c
nettle/hmac-md5-meta.c
nettle/hmac-ripemd160-meta.c
nettle/hmac-sha1-meta.c
nettle/hmac-sha224-meta.c
nettle/hmac-sha256-meta.c
nettle/hmac-sha384-meta.c
nettle/hmac-sha512-meta.c
nettle/hmac-streebog-meta.c
nettle/hmac-sm3-meta.c
nettle/knuth-lfib.c
nettle/hkdf.c
nettle/md2.c
nettle/md2-meta.c
nettle/md4.c
nettle/md4-meta.c
nettle/md5.c
nettle/md5-compress.c
nettle/md5-compat.c
nettle/md5-meta.c
nettle/memeql-sec.c
nettle/memxor.c
nettle/memxor3.c
nettle/nettle-lookup-hash.c
nettle/nettle-meta-aeads.c
nettle/nettle-meta-armors.c
nettle/nettle-meta-ciphers.c
nettle/nettle-meta-hashes.c
nettle/nettle-meta-macs.c
nettle/pbkdf2.c
nettle/pbkdf2-hmac-gosthash94.c
nettle/pbkdf2-hmac-sha1.c
nettle/pbkdf2-hmac-sha256.c
nettle/pbkdf2-hmac-sha384.c
nettle/pbkdf2-hmac-sha512.c
nettle/poly1305-aes.c
nettle/poly1305-internal.c
nettle/realloc.c
nettle/ripemd160.c
nettle/ripemd160-compress.c
nettle/ripemd160-meta.c
nettle/salsa20-core-internal.c
nettle/salsa20-crypt-internal.c
nettle/salsa20-crypt.c
nettle/salsa20r12-crypt.c
nettle/salsa20-set-key.c
nettle/salsa20-set-nonce.c
nettle/salsa20-128-set-key.c
nettle/salsa20-256-set-key.c
nettle/sha1.c
nettle/sha1-compress.c
nettle/sha1-meta.c
nettle/sha256.c
nettle/sha256-compress.c
nettle/sha224-meta.c
nettle/sha256-meta.c
nettle/sha512.c
nettle/sha512-compress.c
nettle/sha384-meta.c
nettle/sha512-meta.c
nettle/sha512-224-meta.c
nettle/sha512-256-meta.c
nettle/sha3.c
nettle/sha3-permute.c
nettle/sha3-224.c
nettle/sha3-224-meta.c
nettle/sha3-256.c
nettle/sha3-256-meta.c
nettle/sha3-384.c
nettle/sha3-384-meta.c
nettle/sha3-512.c
nettle/sha3-512-meta.c
nettle/shake256.c
nettle/sm3.c
nettle/sm3-meta.c
nettle/serpent-set-key.c
nettle/serpent-encrypt.c
nettle/serpent-decrypt.c
nettle/serpent-meta.c
nettle/streebog.c
nettle/streebog-meta.c
nettle/twofish.c
nettle/twofish-meta.c
nettle/umac-nh.c
nettle/umac-nh-n.c
nettle/umac-l2.c
nettle/umac-l3.c
nettle/umac-poly64.c
nettle/umac-poly128.c
nettle/umac-set-key.c
nettle/umac32.c
nettle/umac64.c
nettle/umac96.c
nettle/umac128.c
nettle/version.c
nettle/write-be32.c
nettle/write-le32.c
nettle/write-le64.c
nettle/yarrow256.c
nettle/yarrow_key_event.c
nettle/xts.c
nettle/xts-aes128.c
nettle/xts-aes256.c
)
set(LIBNETTLE_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/nettle
)
add_library(nettle STATIC ${LIBNETTLE_SOURCES})
target_include_directories(nettle PUBLIC ${LIBNETTLE_INCLUDES})
target_compile_definitions(nettle PRIVATE ${LIBNETTLE_DEFINITIONS})
-275
View File
@@ -1,275 +0,0 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
/* Define to 1 if using 'alloca.c'. */
/* #undef C_ALLOCA */
/* Define to 1 if you have 'alloca', as a function or macro. */
#define HAVE_ALLOCA 1
/* Define to 1 if <alloca.h> works. */
#define HAVE_ALLOCA_H 1
/* Define if __builtin_bswap64 is available */
#define HAVE_BUILTIN_BSWAP64 1
/* Define if clock_gettime is available */
#define HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define if fcntl file locking is available */
#define HAVE_FCNTL_LOCKING 1
/* Define if the compiler understands __attribute__ */
#define HAVE_GCC_ATTRIBUTE 1
/* Define to 1 if you have the `getline' function. */
#define HAVE_GETLINE 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have dlopen (with -ldl). */
#define HAVE_LIBDL 1
/* Define to 1 if you have the `gmp' library (-lgmp). */
/* #undef HAVE_LIBGMP */
/* Define if compiler and linker supports __attribute__ ifunc */
#define HAVE_LINK_IFUNC 1
/* Define to 1 if you have the <malloc.h> header file. */
#define HAVE_MALLOC_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 */
/* #undef HAVE_NATIVE_aes_decrypt */
/* #undef HAVE_NATIVE_aes_encrypt */
/* #undef HAVE_NATIVE_aes128_decrypt */
/* #undef HAVE_NATIVE_aes128_encrypt */
/* #undef HAVE_NATIVE_aes128_invert_key */
/* #undef HAVE_NATIVE_aes128_set_decrypt_key */
/* #undef HAVE_NATIVE_aes128_set_encrypt_key */
/* #undef HAVE_NATIVE_aes192_decrypt */
/* #undef HAVE_NATIVE_aes192_encrypt */
/* #undef HAVE_NATIVE_aes192_invert_key */
/* #undef HAVE_NATIVE_aes192_set_decrypt_key */
/* #undef HAVE_NATIVE_aes192_set_encrypt_key */
/* #undef HAVE_NATIVE_aes256_decrypt */
/* #undef HAVE_NATIVE_aes256_encrypt */
/* #undef HAVE_NATIVE_aes256_invert_key */
/* #undef HAVE_NATIVE_aes256_set_decrypt_key */
/* #undef HAVE_NATIVE_aes256_set_encrypt_key */
/* #undef HAVE_NATIVE_cbc_aes128_encrypt */
/* #undef HAVE_NATIVE_cbc_aes192_encrypt */
/* #undef HAVE_NATIVE_cbc_aes256_encrypt */
/* #undef HAVE_NATIVE_chacha_core */
/* #undef HAVE_NATIVE_chacha_2core */
/* #undef HAVE_NATIVE_chacha_3core */
/* #undef HAVE_NATIVE_chacha_4core */
/* #undef HAVE_NATIVE_fat_chacha_2core */
/* #undef HAVE_NATIVE_fat_chacha_3core */
/* #undef HAVE_NATIVE_fat_chacha_4core */
/* #undef HAVE_NATIVE_ecc_curve25519_modp */
/* #undef HAVE_NATIVE_ecc_curve448_modp */
/* #undef HAVE_NATIVE_ecc_secp192r1_modp */
/* #undef HAVE_NATIVE_ecc_secp192r1_redc */
/* #undef HAVE_NATIVE_ecc_secp224r1_modp */
/* #undef HAVE_NATIVE_ecc_secp224r1_redc */
/* #undef HAVE_NATIVE_ecc_secp256r1_modp */
/* #undef HAVE_NATIVE_ecc_secp256r1_redc */
/* #undef HAVE_NATIVE_ecc_secp384r1_modp */
/* #undef HAVE_NATIVE_ecc_secp384r1_redc */
/* #undef HAVE_NATIVE_ecc_secp521r1_modp */
/* #undef HAVE_NATIVE_ecc_secp521r1_redc */
/* #undef HAVE_NATIVE_ghash_set_key */
/* #undef HAVE_NATIVE_ghash_update */
/* #undef HAVE_NATIVE_salsa20_core */
/* #undef HAVE_NATIVE_salsa20_2core */
/* #undef HAVE_NATIVE_fat_salsa20_2core */
/* #undef HAVE_NATIVE_sha1_compress */
/* #undef HAVE_NATIVE_sha256_compress */
/* #undef HAVE_NATIVE_sha512_compress */
/* #undef HAVE_NATIVE_sha3_permute */
/* #undef HAVE_NATIVE_umac_nh */
/* #undef HAVE_NATIVE_umac_nh_n */
/* Define to 1 if you have the <openssl/ecdsa.h> header file. */
/* #undef HAVE_OPENSSL_ECDSA_H */
/* Define to 1 if you have the <openssl/evp.h> header file. */
/* #undef HAVE_OPENSSL_EVP_H */
/* Define to 1 if you have the `secure_getenv' function. */
/* #undef HAVE_SECURE_GETENV */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <valgrind/memcheck.h> header file. */
/* #undef HAVE_VALGRIND_MEMCHECK_H */
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "nettle-bugs@lists.lysator.liu.se"
/* Define to the full name of this package. */
#define PACKAGE_NAME "nettle"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "nettle 3.8.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "nettle"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "3.8.1"
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG __SIZEOF_LONG__
/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T __SIZEOF_SIZE_T__
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at runtime.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
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 STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. This
macro is obsolete. */
#define TIME_WITH_SYS_TIME 1
/* Defined if public key features are enabled */
/* #undef WITH_HOGWEED */
/* Define if you have openssl's libcrypto (used for benchmarking) */
/* #undef WITH_OPENSSL */
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef gid_t */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef uid_t */
/* AIX requires this to be the first thing in the file. */
#ifndef __GNUC__
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
char *alloca ();
# endif
# endif
/* Needed for alloca on windows */
# if HAVE_MALLOC_H
# include <malloc.h>
# endif
# endif
#else /* defined __GNUC__ */
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
/* Needed for alloca on windows, also with gcc */
# if HAVE_MALLOC_H
# include <malloc.h>
# endif
# endif
#endif
#if HAVE_STRERROR
#define STRERROR strerror
#else
#define STRERROR(x) (sys_errlist[x])
#endif
#if __GNUC__ && HAVE_GCC_ATTRIBUTE
# define NORETURN __attribute__ ((__noreturn__))
# define PRINTF_STYLE(f, a) __attribute__ ((__format__ (__printf__, f, a)))
# define UNUSED __attribute__ ((__unused__))
#else
# define NORETURN
# define PRINTF_STYLE(f, a)
# define UNUSED
#endif
#if defined(__x86_64__) || defined(__arch64__)
# define HAVE_NATIVE_64_BIT 1
#else
/* Needs include of <limits.h> before use. */
# define HAVE_NATIVE_64_BIT (SIZEOF_LONG * CHAR_BIT >= 64)
#endif
-1
View File
@@ -1 +0,0 @@
-1
View File
@@ -1 +0,0 @@
-64
View File
@@ -1,64 +0,0 @@
/* version.h
Information about library version.
Copyright (C) 2015 Red Hat, Inc.
Copyright (C) 2015 Niels Möller
This file is part of GNU Nettle.
GNU Nettle is free software: you can redistribute it and/or
modify it under the terms of either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version.
or both in parallel, as here.
GNU Nettle 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 copies of the GNU General Public License and
the GNU Lesser General Public License along with this program. If
not, see http://www.gnu.org/licenses/.
*/
#ifndef NETTLE_VERSION_H_INCLUDED
#define NETTLE_VERSION_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
/* Individual version numbers in decimal */
#define NETTLE_VERSION_MAJOR 3
#define NETTLE_VERSION_MINOR 8
#define NETTLE_USE_MINI_GMP 0
/* We need a preprocessor constant for GMP_NUMB_BITS, simply using
sizeof(mp_limb_t) * CHAR_BIT is not good enough. */
#if NETTLE_USE_MINI_GMP
# define GMP_NUMB_BITS n/a
#endif
int
nettle_version_major (void);
int
nettle_version_minor (void);
#ifdef __cplusplus
}
#endif
#endif /* NETTLE_VERSION_H_INCLUDED */
-44
View File
@@ -1,44 +0,0 @@
#ifndef EHVIEWER_SPINLOCK_H
#define EHVIEWER_SPINLOCK_H
#include <stddef.h>
#include <stdatomic.h>
#define cmpxchg(P, O, N) __sync_val_compare_and_swap((P), (O), (N))
#define barrier() __asm__ __volatile__("":::"memory")
#if defined(__aarch64__) || defined(__arm__)
#define cpu_relax() __asm__ volatile ("wfe");
#else
#define cpu_relax() __asm__ volatile ("pause" ::: "memory");
#endif
typedef struct mcs_lock_t mcs_lock_t;
struct mcs_lock_t {
mcs_lock_t *next;
int spin;
};
typedef struct mcs_lock_t *mcs_lock;
static inline void lock_mcs(_Atomic mcs_lock *m, mcs_lock_t *me) {
mcs_lock_t *tail;
me->next = NULL;
me->spin = 0;
tail = atomic_exchange(m, me);
if (!tail) return;
tail->next = me;
barrier();
while (!me->spin) cpu_relax();
return;
}
static inline void unlock_mcs(mcs_lock *m, mcs_lock_t *me) {
if (!me->next) {
if (cmpxchg(m, me, NULL) == me) return;
while (!me->next) cpu_relax();
}
me->next->spin = 1;
}
#endif //EHVIEWER_SPINLOCK_H
@@ -1,40 +0,0 @@
package androidx.navigation.ui
import android.view.MenuItem
import androidx.annotation.IdRes
import androidx.navigation.ActivityNavigator
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavOptions
fun onNavDestinationSelected2(item: MenuItem, navController: NavController): Boolean {
if (navController.currentDestination?.matchDestination(item.itemId) == true) return true
val builder = NavOptions.Builder().setLaunchSingleTop(true)
if (
navController.currentDestination!!.parent!!.findNode(item.itemId)
is ActivityNavigator.Destination
) {
builder.setEnterAnim(R.anim.nav_default_enter_anim)
.setExitAnim(R.anim.nav_default_exit_anim)
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
.setPopExitAnim(R.anim.nav_default_pop_exit_anim)
} else {
builder.setEnterAnim(com.hippo.ehviewer.R.anim.scene_open_enter)
.setExitAnim(com.hippo.ehviewer.R.anim.scene_open_exit)
.setPopEnterAnim(com.hippo.ehviewer.R.anim.scene_close_enter)
.setPopExitAnim(com.hippo.ehviewer.R.anim.scene_close_exit)
}
val options = builder.build()
return try {
// TODO provide proper API instead of using Exceptions as Control-Flow.
navController.navigate(item.itemId, null, options)
// Return true only if the destination we've navigated to matches the MenuItem
navController.currentDestination?.matchDestination(item.itemId) == true
} catch (e: IllegalArgumentException) {
false
}
}
fun NavDestination.matchDestination(@IdRes destId: Int): Boolean =
hierarchy.any { it.id == destId }
@@ -1,25 +0,0 @@
package androidx.swiperefreshlayout.widget
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.ShapeDrawable
import android.util.AttributeSet
import androidx.core.graphics.ColorUtils
import rikka.core.res.resolveColor
@SuppressLint("PrivateResource")
class ThemedSwipeRefreshLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : SwipeRefreshLayout(context, attrs) {
init {
val surfaceColor =
context.theme.resolveColor(com.google.android.material.R.attr.colorSurface)
val overlayColor =
context.getColor(com.google.android.material.R.color.m3_popupmenu_overlay_color)
val backgroundColor = ColorUtils.compositeColors(overlayColor, surfaceColor)
(mCircleView.background as ShapeDrawable).paint.color = backgroundColor
setColorSchemeColors(context.theme.resolveColor(com.google.android.material.R.attr.colorAccent))
}
}
@@ -1,111 +0,0 @@
package com.davemorrissey.labs.subscaleview
import android.graphics.Bitmap
import android.graphics.Rect
import com.davemorrissey.labs.subscaleview.provider.InputProvider
/**
* Helper class used to set the source and additional attributes from a variety of sources. Supports
* use of a bitmap, asset, resource, external file or any other URI.
*
*
* When you are using a preview image, you must set the dimensions of the full size image on the
* ImageSource object for the full size image using the [.dimensions] method.
*/
class ImageSource {
val bitmap: Bitmap?
val provider: InputProvider?
private var sWidth = 0
private var sHeight = 0
var sRegion = Rect(0, 0, 0, 0)
private set
var isCached = false
private set
private constructor(bitmap: Bitmap, cached: Boolean) {
this.bitmap = bitmap
provider = null
sWidth = bitmap.width
sHeight = bitmap.height
isCached = cached
}
private constructor(provider: InputProvider) {
bitmap = null
this.provider = provider
}
/**
* Use a region of the source image. Region must be set independently for the full size image and the preview if
* you are using one.
*
* @param sRegion the region of the source image to be displayed.
* @return this instance for chaining.
*/
fun region(sRegion: Rect): ImageSource {
this.sRegion = sRegion
setInvariants()
return this
}
/**
* Declare the dimensions of the image. This is only required for a full size image, when you are specifying a URI
* and also a preview image. When displaying a bitmap object, or not using a preview, you do not need to declare
* the image dimensions. Note if the declared dimensions are found to be incorrect, the view will reset.
*
* @param sWidth width of the source image.
* @param sHeight height of the source image.
* @return this instance for chaining.
*/
fun dimensions(sWidth: Int, sHeight: Int): ImageSource {
if (bitmap == null) {
this.sWidth = sWidth
this.sHeight = sHeight
}
setInvariants()
return this
}
private fun setInvariants() {
if (!sRegion.isEmpty) {
sWidth = sRegion.width()
sHeight = sRegion.height()
}
}
companion object {
/**
* Create an instance from an input provider.
*
* @param provider input stream provider.
* @return an [ImageSource] instance.
*/
fun provider(provider: InputProvider): ImageSource {
return ImageSource(provider)
}
/**
* Provide a loaded bitmap for display.
*
* @param bitmap bitmap to be displayed.
* @return an [ImageSource] instance.
*/
fun bitmap(bitmap: Bitmap): ImageSource {
return ImageSource(bitmap, false)
}
/**
* Provide a loaded and cached bitmap for display. This bitmap will not be recycled when it is no
* longer needed. Use this method if you loaded the bitmap with an image loader such as Picasso
* or Volley.
*
* @param bitmap bitmap to be displayed.
* @return an [ImageSource] instance.
*/
fun cachedBitmap(bitmap: Bitmap): ImageSource {
return ImageSource(bitmap, true)
}
}
}
@@ -1,15 +0,0 @@
package com.davemorrissey.labs.subscaleview
import android.graphics.PointF
import java.io.Serializable
/**
* Wraps the scale, center and orientation of a displayed image for easy restoration on screen rotate.
*/
class ImageViewState(val scale: Float, center: PointF) : Serializable {
private val centerX: Float = center.x
private val centerY: Float = center.y
val center: PointF
get() = PointF(centerX, centerY)
}
File diff suppressed because it is too large. Load diff
@@ -1,53 +0,0 @@
package com.davemorrissey.labs.subscaleview.decoder
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Point
import android.graphics.Rect
import com.davemorrissey.labs.subscaleview.provider.InputProvider
import java.lang.Exception
import kotlin.Throws
/**
* Interface for image decoding classes.
*/
interface Decoder {
/**
* Initialise the decoder. When possible, perform initial setup work once in this method. The
* dimensions of the image must be returned.
*
* @param context Application context. A reference may be held, but must be cleared on recycle.
* @param provider Provider of the image.
* @return Dimensions of the image.
* @throws Exception if initialisation fails.
*/
@Throws(Exception::class)
fun init(context: Context, provider: InputProvider): Point
/**
* Decode a region of the image with the given sample size. This method is called off the UI
* thread so it can safely load the image on the current thread. It is called from
* [android.os.AsyncTask]s running in an executor that may have multiple threads, so
* implementations must be thread safe. Adding `synchronized` to the method signature
* is the simplest way to achieve this, but bear in mind the [.recycle] method can be
* called concurrently.
*
* @param sRect Source image rectangle to decode.
* @param sampleSize Sample size.
* @return The decoded region. It is safe to return null if decoding fails.
*/
fun decodeRegion(sRect: Rect, sampleSize: Int): Bitmap
/**
* Status check. Should return false before initialisation and after recycle.
*
* @return true if the decoder is ready to be used.
*/
val isReady: Boolean
/**
* This method will be called when the decoder is no longer required. It should clean up any
* resources still in use.
*/
fun recycle()
}
@@ -1,62 +0,0 @@
package com.davemorrissey.labs.subscaleview.decoder
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Point
import android.graphics.Rect
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.davemorrissey.labs.subscaleview.provider.InputProvider
class ImageDecoder @JvmOverloads constructor(
private val cropBorders: Boolean,
bitmapConfig: Bitmap.Config? = null,
) : Decoder {
init {
val globalBitmapConfig = SubsamplingScaleImageView.preferredBitmapConfig
}
/**
* Initialise the decoder. When possible, perform initial setup work once in this method. The
* dimensions of the image must be returned.
*
* @param context Application context. A reference may be held, but must be cleared on recycle.
* @param provider Provider of the image.
* @return Dimensions of the image.
* @throws Exception if initialisation fails.
*/
@Throws(Exception::class)
override fun init(context: Context, provider: InputProvider): Point {
TODO()
}
/**
* Decode a region of the image with the given sample size. This method is called off the UI
* thread so it can safely load the image on the current thread. It is called from
* [android.os.AsyncTask]s running in an executor that may have multiple threads, so
* implementations must be thread safe. Adding `synchronized` to the method signature
* is the simplest way to achieve this, but bear in mind the [.recycle] method can be
* called concurrently.
*
* @param sRect Source image rectangle to decode.
* @param sampleSize Sample size.
* @return The decoded region. It is safe to return null if decoding fails.
*/
override fun decodeRegion(sRect: Rect, sampleSize: Int): Bitmap {
TODO()
}
/**
* Status check. Should return false before initialisation and after recycle.
*
* @return true if the decoder is ready to be used.
*/
override val isReady: Boolean = TODO()
/**
* This method will be called when the decoder is no longer required. It should clean up any
* resources still in use.
*/
override fun recycle() {
TODO()
}
}
@@ -1,3 +0,0 @@
package com.davemorrissey.labs.subscaleview.provider
interface InputProvider
@@ -1,177 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Environment;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hippo.ehviewer.client.exception.ParseException;
import com.hippo.ehviewer.util.ReadableTime;
import com.hippo.ehviewer.yorozuya.FileUtils;
import com.hippo.ehviewer.yorozuya.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
public class AppConfig {
public static final String APP_DIRNAME = "EhViewer";
private static final String DOWNLOAD = "download";
private static final String TEMP = "temp";
private static final String PARSE_ERROR = "parse_error";
private static final String CRASH = "crash";
@SuppressLint("StaticFieldLeak")
private static Context sContext;
public static void initialize(Context context) {
sContext = context.getApplicationContext();
}
@Nullable
public static File getExternalAppDir() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File dir = sContext.getExternalFilesDir(null);
return FileUtils.ensureDirectory(dir) ? dir : null;
}
return null;
}
/**
* mkdirs and get
*/
@Nullable
public static File getDirInExternalAppDir(String filename) {
File appFolder = getExternalAppDir();
if (appFolder != null) {
File dir = new File(appFolder, filename);
return FileUtils.ensureDirectory(dir) ? dir : null;
}
return null;
}
@Nullable
public static File getFileInExternalAppDir(String filename) {
File appFolder = getExternalAppDir();
if (appFolder != null) {
File file = new File(appFolder, filename);
return FileUtils.ensureFile(file) ? file : null;
}
return null;
}
@Nullable
public static File getDefaultDownloadDir() {
return getDirInExternalAppDir(DOWNLOAD);
}
@Nullable
public static File getExternalTempDir() {
File dir = sContext.getExternalCacheDir();
File file;
if (null != dir && FileUtils.ensureDirectory(file = new File(dir, TEMP))) {
return file;
} else {
return null;
}
}
@Nullable
public static File getExternalCopyTempDir() {
File dir = sContext.getExternalCacheDir();
File file;
if (null != dir && FileUtils.ensureDirectory(file = new File(dir, "copy"))) {
return file;
} else {
return null;
}
}
@Nullable
public static File getExternalParseErrorDir() {
return getDirInExternalAppDir(PARSE_ERROR);
}
@Nullable
public static File getExternalCrashDir() {
return getDirInExternalAppDir(CRASH);
}
@Nullable
public static File getTempDir() {
File dir = sContext.getCacheDir();
File file;
if (null != dir && FileUtils.ensureDirectory(file = new File(dir, TEMP))) {
return file;
} else {
return null;
}
}
@Nullable
public static File createTempFile() {
return FileUtils.createTempFile(getTempDir(), null);
}
public static void saveParseErrorBody(@NonNull ParseException e) {
File dir = getExternalParseErrorDir();
if (null == dir) {
return;
}
File file = new File(dir, ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt");
OutputStream os = null;
try {
os = new FileOutputStream(file);
String message = e.getMessage();
String body = e.getBody();
if (null != message) {
os.write(message.getBytes(StandardCharsets.UTF_8));
os.write('\n');
}
os.write(body.getBytes(StandardCharsets.UTF_8));
os.flush();
} catch (IOException e1) {
// Ignore
} finally {
IOUtils.closeQuietly(os);
}
}
@Nullable
public static File getFilesDir(String name) {
File dir = sContext.getFilesDir();
if (dir == null) {
return null;
}
dir = new File(dir, name);
if (dir.isDirectory() || dir.mkdirs()) {
return dir;
} else {
return null;
}
}
}
@@ -1,96 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer
import android.os.Build
import android.os.Debug
import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.yorozuya.FileUtils
import com.hippo.ehviewer.yorozuya.OSUtils
import java.io.File
import java.io.FileWriter
import java.io.PrintWriter
private fun joinIfStringArray(any: Any?): String {
return if (any is Array<*>) any.joinToString() else any.toString()
}
private fun collectClassStaticInfo(clazz: Class<*>): String {
return clazz.declaredFields.joinToString("\n") {
"${it.name}=${joinIfStringArray(it.get(null))}"
}
}
object Crash {
private fun collectInfo(fw: FileWriter) {
fw.write("======== PackageInfo ========\n")
fw.write("PackageName=${BuildConfig.APPLICATION_ID}\n")
fw.write("VersionName=${BuildConfig.VERSION_NAME}\n")
fw.write("VersionCode=${BuildConfig.VERSION_CODE}\n")
fw.write("CommitSha=${BuildConfig.COMMIT_SHA}\n")
fw.write("BuildTime=${BuildConfig.BUILD_TIME}\n")
fw.write("\n")
// Device info
fw.write("======== DeviceInfo ========\n")
fw.write("${collectClassStaticInfo(Build::class.java)}\n")
fw.write("${collectClassStaticInfo(Build.VERSION::class.java)}\n")
fw.write("MEMORY=")
fw.write(FileUtils.humanReadableByteCount(OSUtils.getAppAllocatedMemory(), false))
fw.write("\n")
fw.write("MEMORY_NATIVE=")
fw.write(FileUtils.humanReadableByteCount(Debug.getNativeHeapAllocatedSize(), false))
fw.write("\n")
fw.write("MEMORY_MAX=")
fw.write(FileUtils.humanReadableByteCount(OSUtils.getAppMaxMemory(), false))
fw.write("\n")
fw.write("MEMORY_TOTAL=")
fw.write(FileUtils.humanReadableByteCount(OSUtils.getTotalMemory(), false))
fw.write("\n")
fw.write("\n")
}
private fun getThrowableInfo(t: Throwable, fw: FileWriter) {
val printWriter = PrintWriter(fw)
t.printStackTrace(printWriter)
var cause = t.cause
while (cause != null) {
cause.printStackTrace(printWriter)
cause = cause.cause
}
}
fun saveCrashLog(t: Throwable) {
val dir = AppConfig.getExternalCrashDir() ?: return
val nowString = ReadableTime.getFilenamableTime(System.currentTimeMillis())
val fileName = "crash-$nowString.log"
val file = File(dir, fileName)
runCatching {
FileWriter(file).use { fw ->
fw.write("TIME=${nowString}\n")
fw.write("\n")
collectInfo(fw)
fw.write("======== CrashInfo ========\n")
getThrowableInfo(t, fw)
fw.write("\n")
fw.flush()
}
}.onFailure {
it.printStackTrace()
file.delete()
}
}
}
@@ -1,208 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer
import android.app.Application
import android.content.ComponentCallbacks2
import androidx.appcompat.app.AppCompatDelegate
import androidx.collection.LruCache
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.util.DebugLogger
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhDns
import com.hippo.ehviewer.client.EhSSLSocketFactory
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.data.GalleryDetail
import com.hippo.ehviewer.coil.MergeInterceptor
import com.hippo.ehviewer.coil.diskCache
import com.hippo.ehviewer.dailycheck.checkDawn
import com.hippo.ehviewer.dao.buildMainDB
import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.legacy.cleanObsoleteCache
import com.hippo.ehviewer.ui.keepNoMediaFileStatus
import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.yorozuya.FileUtils
import eu.kanade.tachiyomi.core.preference.AndroidPreferenceStore
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.util.lang.launchIO
import kotlinx.coroutines.DelicateCoroutinesApi
import okhttp3.Cache
import okhttp3.OkHttpClient
import okio.FileSystem
import okio.Path.Companion.toOkioPath
import java.net.Proxy
import java.security.KeyStore
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
class EhApplication : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
@OptIn(DelicateCoroutinesApi::class)
override fun onCreate() {
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
application = this
val handler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { t, e ->
try {
if (Settings.saveCrashLog) {
Crash.saveCrashLog(e)
}
} catch (ignored: Throwable) {
}
handler?.uncaughtException(t, e)
}
super<Application>.onCreate()
System.loadLibrary("ehviewer")
Settings.initialize()
ReadableTime.initialize(this)
AppConfig.initialize(this)
AppCompatDelegate.setDefaultNightMode(Settings.theme)
launchIO {
launchIO {
EhTagDatabase.update()
}
launchIO {
ehDatabase
}
launchIO {
DownloadManager.isIdle
}
launchIO {
cleanupDownload()
}
if (Settings.requestNews) {
launchIO {
checkDawn()
}
}
}
cleanObsoleteCache(this)
}
private suspend fun cleanupDownload() {
runCatching {
keepNoMediaFileStatus()
}.onFailure {
it.printStackTrace()
}
runCatching {
clearTempDir()
}.onFailure {
it.printStackTrace()
}
}
private fun clearTempDir() {
var dir = AppConfig.getTempDir()
if (null != dir) {
FileUtils.deleteContent(dir)
}
dir = AppConfig.getExternalTempDir()
if (null != dir) {
FileUtils.deleteContent(dir)
}
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) {
galleryDetailCache.evictAll()
}
}
override fun onPause(owner: LifecycleOwner) {
if (!locked) {
locked_last_leave_time = System.currentTimeMillis() / 1000
}
locked = true
}
override fun newImageLoader(): ImageLoader {
return ImageLoader.Builder(this).apply {
okHttpClient(nonCacheOkHttpClient)
components { add(MergeInterceptor) }
diskCache(imageCache)
crossfade(300)
error(R.drawable.image_failed)
if (BuildConfig.DEBUG) logger(DebugLogger())
}.build()
}
companion object {
var locked = true
var locked_last_leave_time: Long = 0
lateinit var application: EhApplication
private set
val ehProxySelector by lazy { EhProxySelector() }
val nonCacheOkHttpClient by lazy {
OkHttpClient.Builder().apply {
cookieJar(EhCookieStore)
dns(EhDns)
proxySelector(ehProxySelector)
if (Settings.dF) {
val factory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())!!
factory.init(null as KeyStore?)
val manager = factory.trustManagers!!
val trustManager = manager.filterIsInstance<X509TrustManager>().first()
sslSocketFactory(EhSSLSocketFactory, trustManager)
proxy(Proxy.NO_PROXY)
}
}.build()
}
// Never use this okhttp client to download large blobs!!!
val okHttpClient by lazy {
nonCacheOkHttpClient.newBuilder().cache(
Cache(
application.cacheDir.toOkioPath() / "http_cache",
20L * 1024L * 1024L,
FileSystem.SYSTEM,
),
).build()
}
val galleryDetailCache by lazy {
LruCache<Long, GalleryDetail>(25).also {
favouriteStatusRouter.addListener { gid, slot ->
it[gid]?.favoriteSlot = slot
}
}
}
val hosts by lazy { Hosts(application, "hosts.db") }
val favouriteStatusRouter by lazy { FavouriteStatusRouter() }
val readerPreferences by lazy { ReaderPreferences(AndroidPreferenceStore(application)) }
val ehDatabase by lazy { buildMainDB(application) }
val imageCache by lazy {
diskCache {
directory(application.cacheDir.toOkioPath() / "image_cache")
maxSizeBytes(Settings.readCacheSize.coerceIn(320, 5120).toLong() * 1024 * 1024)
}
}
}
}
@@ -1,465 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer
import android.content.Context
import android.net.Uri
import android.os.ParcelFileDescriptor
import android.os.ParcelFileDescriptor.MODE_READ_ONLY
import androidx.paging.PagingSource
import androidx.room.Room.databaseBuilder
import com.hippo.ehviewer.EhApplication.Companion.ehDatabase
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.dao.BasicDao
import com.hippo.ehviewer.dao.DownloadDirname
import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.dao.DownloadLabel
import com.hippo.ehviewer.dao.EHDB_MIGRATION_4_5
import com.hippo.ehviewer.dao.EhDatabase
import com.hippo.ehviewer.dao.Filter
import com.hippo.ehviewer.dao.HistoryInfo
import com.hippo.ehviewer.dao.LocalFavoriteInfo
import com.hippo.ehviewer.dao.QuickSearch
import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.util.sendTo
object EhDB {
private const val CUR_DB_VER = 4
private val db = ehDatabase
// Fix state
@get:Synchronized
val allDownloadInfo: List<DownloadInfo>
get() = db.downloadsDao().list().onEach {
if (it.state == DownloadInfo.STATE_WAIT || it.state == DownloadInfo.STATE_DOWNLOAD) {
it.state = DownloadInfo.STATE_NONE
}
}
@Synchronized
fun updateDownloadInfo(downloadInfos: List<DownloadInfo>) {
val dao = db.downloadsDao()
dao.update(downloadInfos)
}
@Synchronized
fun putDownloadInfo(downloadInfo: DownloadInfo) {
db.downloadsDao().run {
if (load(downloadInfo.gid) != null) {
update(downloadInfo)
} else {
insert(downloadInfo)
}
}
}
@Synchronized
fun removeDownloadInfo(downloadInfo: DownloadInfo) {
db.downloadsDao().delete(downloadInfo)
}
@Synchronized
fun getDownloadDirname(gid: Long): String? {
val dao = db.downloadDirnameDao()
val raw = dao.load(gid)
return raw?.dirname
}
@Synchronized
fun putDownloadDirname(gid: Long, dirname: String?) {
val dao = db.downloadDirnameDao()
var raw = dao.load(gid)
if (raw != null) {
raw.dirname = dirname
dao.update(raw)
} else {
raw = DownloadDirname(gid, dirname)
dao.insert(raw)
}
}
@Synchronized
fun removeDownloadDirname(gid: Long) {
val dao = db.downloadDirnameDao()
dao.deleteByKey(gid)
}
@Synchronized
fun clearDownloadDirname() {
val dao = db.downloadDirnameDao()
dao.deleteAll()
}
@get:Synchronized
val allDownloadLabelList: List<DownloadLabel>
get() = db.downloadLabelDao().list()
@Synchronized
fun addDownloadLabel(label: String): DownloadLabel {
val dao = db.downloadLabelDao()
val raw = DownloadLabel()
raw.label = label
raw.time = System.currentTimeMillis()
raw.id = dao.insert(raw)
return raw
}
@Synchronized
fun addDownloadLabel(raw: DownloadLabel): DownloadLabel {
// Reset id
raw.id = null
val dao = db.downloadLabelDao()
raw.id = dao.insert(raw)
return raw
}
@Synchronized
fun updateDownloadLabel(raw: DownloadLabel?) {
val dao = db.downloadLabelDao()
dao.update(raw!!)
}
@Synchronized
fun moveDownloadLabel(fromPosition: Int, toPosition: Int) {
if (fromPosition == toPosition) {
return
}
val reverse = fromPosition > toPosition
val offset = if (reverse) toPosition else fromPosition
val limit = if (reverse) fromPosition - toPosition + 1 else toPosition - fromPosition + 1
val dao = db.downloadLabelDao()
val list = dao.list(offset, limit)
val step = if (reverse) 1 else -1
val start = if (reverse) limit - 1 else 0
val end = if (reverse) 0 else limit - 1
val toTime = list[end].time
var i = end
while (if (reverse) i < start else i > start) {
list[i].time = list[i + step].time
i += step
}
list[start].time = toTime
dao.update(list)
}
@Synchronized
fun removeDownloadLabel(raw: DownloadLabel?) {
val dao = db.downloadLabelDao()
dao.delete(raw!!)
}
@get:Synchronized
val allLocalFavorites: List<GalleryInfo>
get() {
val dao = db.localFavoritesDao()
val list = dao.list()
return ArrayList<GalleryInfo>(list)
}
@Synchronized
fun searchLocalFavorites(query: String): List<GalleryInfo> {
val dao = db.localFavoritesDao()
val list = dao.list("%$query%")
return ArrayList<GalleryInfo>(list)
}
@Synchronized
fun removeLocalFavorites(gid: Long) {
db.localFavoritesDao().deleteByKey(gid)
}
@Synchronized
fun removeLocalFavorites(gidArray: LongArray) {
val dao = db.localFavoritesDao()
for (gid in gidArray) {
dao.deleteByKey(gid)
}
}
@JvmStatic
@Synchronized
fun containLocalFavorites(gid: Long): Boolean {
val dao = db.localFavoritesDao()
return dao.contains(gid)
}
@Synchronized
fun putLocalFavorites(galleryInfo: GalleryInfo) {
val dao = db.localFavoritesDao()
if (null == dao.load(galleryInfo.gid)) {
val info: LocalFavoriteInfo
if (galleryInfo is LocalFavoriteInfo) {
info = galleryInfo
} else {
info = LocalFavoriteInfo(galleryInfo)
info.time = System.currentTimeMillis()
}
dao.insert(info)
}
}
@Synchronized
fun putLocalFavorites(galleryInfoList: List<GalleryInfo>) {
for (gi in galleryInfoList) {
putLocalFavorites(gi)
}
}
@get:Synchronized
val allQuickSearch: List<QuickSearch>
get() {
val dao = db.quickSearchDao()
return dao.list()
}
@Synchronized
fun insertQuickSearch(quickSearch: QuickSearch) {
val dao = db.quickSearchDao()
quickSearch.id = null
quickSearch.time = System.currentTimeMillis()
quickSearch.id = dao.insert(quickSearch)
}
@Synchronized
fun importQuickSearch(quickSearchList: List<QuickSearch?>) {
val dao = db.quickSearchDao()
for (quickSearch in quickSearchList) {
dao.insert(quickSearch!!)
}
}
@Synchronized
fun deleteQuickSearch(quickSearch: QuickSearch?) {
val dao = db.quickSearchDao()
if (quickSearch != null) {
dao.delete(quickSearch)
}
}
@Synchronized
fun moveQuickSearch(fromPosition: Int, toPosition: Int) {
if (fromPosition == toPosition) {
return
}
val reverse = fromPosition > toPosition
val offset = if (reverse) toPosition else fromPosition
val limit = if (reverse) fromPosition - toPosition + 1 else toPosition - fromPosition + 1
val dao = db.quickSearchDao()
val list = dao.list(offset, limit)
val step = if (reverse) 1 else -1
val start = if (reverse) limit - 1 else 0
val end = if (reverse) 0 else limit - 1
val toTime = list[end].time
var i = end
while (if (reverse) i < start else i > start) {
list[i].time = list[i + step].time
i += step
}
list[start].time = toTime
dao.update(list)
}
@get:Synchronized
val historyLazyList: PagingSource<Int, HistoryInfo>
get() = db.historyDao().listLazy()
@Synchronized
fun putHistoryInfo(galleryInfo: GalleryInfo?) {
val dao = db.historyDao()
val info: HistoryInfo = if (galleryInfo is HistoryInfo) {
galleryInfo
} else {
HistoryInfo(galleryInfo!!)
}
info.time = System.currentTimeMillis()
if (null != dao.load(info.gid)) {
dao.update(info)
} else {
dao.insert(info)
}
}
@Synchronized
fun putHistoryInfoNonRefresh(info: GalleryInfo) {
val dao = db.historyDao()
val i = dao.load(info.gid)
if (null != i) {
val historyInfo: HistoryInfo
if (info is HistoryInfo) {
historyInfo = info
} else {
historyInfo = HistoryInfo(info)
historyInfo.time = i.time
}
dao.update(historyInfo)
}
}
@Synchronized
fun putHistoryInfo(historyInfoList: List<HistoryInfo>) {
val dao = db.historyDao()
for (info in historyInfoList) {
if (null == dao.load(info.gid)) {
dao.insert(info)
}
}
}
@Synchronized
fun deleteHistoryInfo(info: HistoryInfo?) {
val dao = db.historyDao()
dao.delete(info!!)
}
@Synchronized
fun clearHistoryInfo() {
val dao = db.historyDao()
dao.deleteAll()
}
@get:Synchronized
val allFilter: List<Filter>
get() = db.filterDao().list()
@Synchronized
fun addFilter(filter: Filter): Boolean {
val existFilter: Filter? = try {
db.filterDao().load(filter.text!!, filter.mode)
} catch (e: Exception) {
null
}
return if (existFilter == null) {
filter.id = null
filter.id = db.filterDao().insert(filter)
true
} else {
false
}
}
@Synchronized
fun deleteFilter(filter: Filter) {
db.filterDao().delete(filter)
}
@Synchronized
fun triggerFilter(filter: Filter) {
filter.enable = filter.enable?.not() ?: false
db.filterDao().update(filter)
}
private fun <T> copyDao(from: BasicDao<T>, to: BasicDao<T>) {
val list = from.list()
for (item in list) to.insert(item)
}
@Synchronized
fun exportDB(context: Context, uri: Uri): Boolean {
val ehExportName = "eh.export.db"
runCatching {
context.deleteDatabase(ehExportName)
val newDb = databaseBuilder(context, EhDatabase::class.java, ehExportName).build()
copyDao(db.downloadsDao(), newDb.downloadsDao())
copyDao(db.downloadLabelDao(), newDb.downloadLabelDao())
copyDao(db.downloadDirnameDao(), newDb.downloadDirnameDao())
copyDao(db.historyDao(), newDb.historyDao())
copyDao(db.quickSearchDao(), newDb.quickSearchDao())
copyDao(db.localFavoritesDao(), newDb.localFavoritesDao())
copyDao(db.filterDao(), newDb.filterDao())
newDb.close()
val dbFile = context.getDatabasePath(ehExportName)
context.contentResolver.openFileDescriptor(uri, "rw")!!.use { toFd ->
ParcelFileDescriptor.open(dbFile, MODE_READ_ONLY).use { fromFd ->
fromFd sendTo toFd
}
}
return true
}.onFailure {
it.printStackTrace()
}
return false
}
/**
* @return error string, null for no error
*/
@Synchronized
fun importDB(context: Context, uri: Uri): String? {
runCatching {
val oldDB = databaseBuilder(context, EhDatabase::class.java, "tmp.db")
.createFromInputStream { context.contentResolver.openInputStream(uri) }
.addMigrations(EHDB_MIGRATION_4_5)
.build()
// Download label
val manager = DownloadManager
runCatching {
val downloadLabelList = oldDB.downloadLabelDao().list()
manager.addDownloadLabel(downloadLabelList)
}
// Downloads
runCatching {
val downloadInfoList = oldDB.downloadsDao().list()
manager.addDownload(downloadInfoList, false)
}
// Download dirname
runCatching {
oldDB.downloadDirnameDao().list().forEach {
putDownloadDirname(it.gid, it.dirname)
}
}
// History
runCatching {
val historyInfoList = oldDB.historyDao().list()
putHistoryInfo(historyInfoList)
}
// QuickSearch
runCatching {
val quickSearchList = oldDB.quickSearchDao().list()
val currentQuickSearchList = db.quickSearchDao().list()
val importList = quickSearchList.mapNotNull { newQS ->
newQS.takeIf { currentQuickSearchList.find { it.name == newQS.name } == null }
}
importQuickSearch(importList)
}
// LocalFavorites
runCatching {
oldDB.localFavoritesDao().list().forEach {
putLocalFavorites(it)
}
}
// Filter
runCatching {
val filterList = oldDB.filterDao().list()
val currentFilterList = db.filterDao().list()
filterList.forEach {
if (it !in currentFilterList) addFilter(it)
}
}
oldDB.close()
}.onFailure {
it.printStackTrace()
return context.getString(R.string.cant_read_the_file)
}
return null
}
}
@@ -1,92 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer
import android.text.TextUtils
import com.hippo.ehviewer.Settings.proxyIp
import com.hippo.ehviewer.Settings.proxyPort
import com.hippo.ehviewer.Settings.proxyType
import com.hippo.ehviewer.network.InetValidator.isValidInetPort
import com.hippo.ehviewer.util.ExceptionUtils
import java.io.IOException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Proxy
import java.net.ProxySelector
import java.net.SocketAddress
import java.net.URI
class EhProxySelector internal constructor() : ProxySelector() {
private var delegation: ProxySelector? = null
private var alternative: ProxySelector?
init {
alternative = getDefault() ?: NullProxySelector()
updateProxy()
}
fun updateProxy() {
delegation = when (proxyType) {
TYPE_DIRECT -> NullProxySelector()
TYPE_SYSTEM -> alternative
TYPE_HTTP, TYPE_SOCKS -> null
else -> alternative
}
}
override fun select(uri: URI): List<Proxy> {
val type = proxyType
if (type == TYPE_HTTP || type == TYPE_SOCKS) {
runCatching {
val ip = proxyIp
val port = proxyPort
if (!TextUtils.isEmpty(ip) && isValidInetPort(port)) {
val inetAddress = InetAddress.getByName(ip)
val socketAddress = InetSocketAddress(inetAddress, port)
return listOf(
Proxy(
if (type == TYPE_HTTP) Proxy.Type.HTTP else Proxy.Type.SOCKS,
socketAddress,
),
)
}
}.onFailure {
ExceptionUtils.throwIfFatal(it)
it.printStackTrace()
}
}
return delegation?.select(uri) ?: alternative!!.select(uri)
}
override fun connectFailed(uri: URI, sa: SocketAddress, ioe: IOException) {
delegation?.select(uri)
}
private class NullProxySelector : ProxySelector() {
override fun select(uri: URI): List<Proxy> {
return listOf(Proxy.NO_PROXY)
}
override fun connectFailed(uri: URI, sa: SocketAddress, ioe: IOException) {}
}
companion object {
const val TYPE_DIRECT = 0
const val TYPE_SYSTEM = 1
const val TYPE_HTTP = 2
const val TYPE_SOCKS = 3
}
}
@@ -1,74 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer;
import android.annotation.SuppressLint;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.yorozuya.IntIdGenerator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FavouriteStatusRouter {
private static final String KEY_DATA_MAP_NEXT_ID = "data_map_next_id";
private final IntIdGenerator idGenerator = new IntIdGenerator(Settings.getInt(KEY_DATA_MAP_NEXT_ID, 0));
@SuppressLint("UseSparseArrays")
private final HashMap<Integer, Map<Long, GalleryInfo>> maps = new HashMap<>();
private final List<Listener> listeners = new ArrayList<>();
public int saveDataMap(Map<Long, GalleryInfo> map) {
int id = idGenerator.nextId();
maps.put(id, map);
Settings.putInt(KEY_DATA_MAP_NEXT_ID, idGenerator.nextId());
return id;
}
public Map<Long, GalleryInfo> restoreDataMap(int id) {
return maps.remove(id);
}
public void modifyFavourites(long gid, int slot) {
for (Map<Long, GalleryInfo> map : maps.values()) {
GalleryInfo info = map.get(gid);
if (info != null) {
info.setFavoriteSlot(slot);
}
}
for (Listener listener : listeners) {
listener.onModifyFavourites(gid, slot);
}
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void removeListener(Listener listener) {
listeners.remove(listener);
}
public interface Listener {
void onModifyFavourites(long gid, int slot);
}
}
@@ -1,343 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer;
/*
* Created by Hippo on 2018/3/21.
*/
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Pair;
import androidx.annotation.Nullable;
import com.hippo.ehviewer.database.MSQLiteBuilder;
import com.hippo.ehviewer.util.SqlUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class Hosts {
private static final int VERSION_1 = 1;
private static final String TABLE_HOSTS = "HOSTS";
private static final String COLUMN_HOST = "HOST";
private static final String COLUMN_IP = "IP";
private static final int DB_VERSION = VERSION_1;
private final SQLiteDatabase db;
public Hosts(Context context, String name) {
SQLiteOpenHelper helper = new MSQLiteBuilder()
.version(VERSION_1)
.createTable(TABLE_HOSTS)
.insertColumn(TABLE_HOSTS, COLUMN_HOST, String.class)
.insertColumn(TABLE_HOSTS, COLUMN_IP, String.class)
.build(context, name, DB_VERSION);
db = helper.getWritableDatabase();
}
@Nullable
public static InetAddress toInetAddress(String host, String ip) {
if (!isValidHost(host)) {
return null;
}
if (ip == null) {
return null;
}
byte[] bytes = parseV4(ip);
if (bytes == null) {
bytes = parseV6(ip);
}
if (bytes == null) {
return null;
}
try {
return InetAddress.getByAddress(host, bytes);
} catch (UnknownHostException e) {
return null;
}
}
/**
* Returns true if the host is valid.
*/
public static boolean isValidHost(String host) {
if (host == null) {
return false;
}
if (host.length() > 253) {
return false;
}
int labelLength = 0;
for (int i = 0, n = host.length(); i < n; i++) {
char ch = host.charAt(i);
if (ch == '.') {
if (labelLength < 1 || labelLength > 63) {
return false;
}
labelLength = 0;
} else {
labelLength++;
}
if ((ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '-' && ch != '.') {
return false;
}
}
return labelLength >= 1 && labelLength <= 63;
}
/**
* Returns true if ips are valid.
*/
public static boolean isValidIp(String ips) {
if (ips == null) {
return false;
}
String[] list = ips.split("\\+");
for (String ip : list) {
if (parseV4(ip) == null && parseV6(ip) == null) {
return false;
}
}
return true;
}
// org.xbill.DNS.Address.parseV4
@Nullable
private static byte[] parseV4(String s) {
int numDigits;
int currentOctet;
byte[] values = new byte[4];
int currentValue;
int length = s.length();
currentOctet = 0;
currentValue = 0;
numDigits = 0;
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c >= '0' && c <= '9') {
/* Can't have more than 3 digits per octet. */
if (numDigits == 3)
return null;
/* Octets shouldn't start with 0, unless they are 0. */
if (numDigits > 0 && currentValue == 0)
return null;
numDigits++;
currentValue *= 10;
currentValue += (c - '0');
/* 255 is the maximum value for an octet. */
if (currentValue > 255)
return null;
} else if (c == '.') {
/* Can't have more than 3 dots. */
if (currentOctet == 3)
return null;
/* Two consecutive dots are bad. */
if (numDigits == 0)
return null;
values[currentOctet++] = (byte) currentValue;
currentValue = 0;
numDigits = 0;
} else
return null;
}
/* Must have 4 octets. */
if (currentOctet != 3)
return null;
/* The fourth octet can't be empty. */
if (numDigits == 0)
return null;
values[currentOctet] = (byte) currentValue;
return values;
}
// org.xbill.DNS.Address.parseV6
@Nullable
private static byte[] parseV6(String s) {
int range = -1;
byte[] data = new byte[16];
String[] tokens = s.split(":", -1);
int first = 0;
int last = tokens.length - 1;
if (tokens[0].length() == 0) {
// If the first two tokens are empty, it means the string
// started with ::, which is fine. If only the first is
// empty, the string started with :, which is bad.
if (last - first > 0 && tokens[1].length() == 0)
first++;
else
return null;
}
if (tokens[last].length() == 0) {
// If the last two tokens are empty, it means the string
// ended with ::, which is fine. If only the last is
// empty, the string ended with :, which is bad.
if (last - first > 0 && tokens[last - 1].length() == 0)
last--;
else
return null;
}
if (last - first + 1 > 8)
return null;
int i, j;
for (i = first, j = 0; i <= last; i++) {
if (tokens[i].length() == 0) {
if (range >= 0)
return null;
range = j;
continue;
}
if (tokens[i].indexOf('.') >= 0) {
// An IPv4 address must be the last component
if (i < last)
return null;
// There can't have been more than 6 components.
if (i > 6)
return null;
byte[] v4addr = parseV4(tokens[i]);
if (v4addr == null)
return null;
for (int k = 0; k < 4; k++)
data[j++] = v4addr[k];
break;
}
try {
for (int k = 0; k < tokens[i].length(); k++) {
char c = tokens[i].charAt(k);
if (Character.digit(c, 16) < 0)
return null;
}
int x = Integer.parseInt(tokens[i], 16);
if (x > 0xFFFF || x < 0)
return null;
data[j++] = (byte) (x >>> 8);
data[j++] = (byte) (x & 0xFF);
} catch (NumberFormatException e) {
return null;
}
}
if (j < 16 && range < 0)
return null;
if (range >= 0) {
int empty = 16 - j;
System.arraycopy(data, range, data, range + empty, j - range);
for (i = range; i < range + empty; i++)
data[i] = 0;
}
return data;
}
/**
* Gets a InetAddress with the host.
*/
@Nullable
public List<InetAddress> get(String host) {
if (!isValidHost(host)) {
return null;
}
try (Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_HOSTS + " WHERE " + COLUMN_HOST + " = ?;", new String[]{host})) {
if (cursor.moveToNext()) {
String[] ips = SqlUtils.getString(cursor, COLUMN_IP, null).split("\\+");
List<InetAddress> addresses = new ArrayList<>();
for (String ip : ips) {
addresses.add(toInetAddress(host, ip));
}
return addresses;
} else {
return null;
}
}
}
public boolean contains(String host) {
try (Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_HOSTS + " WHERE " + COLUMN_HOST + " = ?;", new String[]{host})) {
return cursor.moveToNext();
}
}
/**
* Puts the host-ip pair into this hosts.
*/
public boolean put(String host, String ip) {
if (!isValidHost(host) || !isValidIp(ip)) {
return false;
}
ContentValues values = new ContentValues();
values.put(COLUMN_HOST, host);
values.put(COLUMN_IP, ip);
if (contains(host)) {
db.update(TABLE_HOSTS, values, COLUMN_HOST + " = ?", new String[]{host});
} else {
db.insert(TABLE_HOSTS, null, values);
}
return true;
}
/**
* Puts delete the entry with the host.
*/
public void delete(String host) {
db.delete(TABLE_HOSTS, COLUMN_HOST + " = ?", new String[]{host});
}
/**
* Get all data from this host.
*/
public List<Pair<String, String>> getAll() {
List<Pair<String, String>> result = new ArrayList<>();
try (Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_HOSTS + ";", null)) {
while (cursor.moveToNext()) {
String host = SqlUtils.getString(cursor, COLUMN_HOST, null);
String ip = SqlUtils.getString(cursor, COLUMN_IP, null);
result.add(new Pair<>(host, ip));
}
}
return result;
}
}
@@ -1,641 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer
import android.content.SharedPreferences
import android.net.Uri
import android.util.Log
import androidx.annotation.DimenRes
import androidx.preference.PreferenceManager
import com.hippo.ehviewer.EhApplication.Companion.application
import com.hippo.ehviewer.client.data.FavListUrlBuilder
import com.hippo.ehviewer.ui.scene.GalleryListScene
import com.hippo.ehviewer.yorozuya.LayoutUtils.dp2pix
import com.hippo.ehviewer.yorozuya.NumberUtils
import com.hippo.unifile.UniFile
import java.util.Locale
object Settings {
/********************
* Eh
*/
const val KEY_THEME = "theme"
const val KEY_ACCOUNT = "account"
const val KEY_IMAGE_LIMITS = "image_limits"
const val KEY_U_CONFIG = "uconfig"
const val KEY_MY_TAGS = "mytags"
const val KEY_BLACK_DARK_THEME = "black_dark_theme"
const val DEFAULT_BLACK_DARK_THEME = false
const val THEME_SYSTEM = -1
const val KEY_GALLERY_SITE = "gallery_site"
const val KEY_LIST_MODE = "list_mode"
const val KEY_DETAIL_SIZE = "detail_size"
const val KEY_THUMB_SIZE = "thumb_size_"
const val KEY_THUMB_RESOLUTION = "thumb_resolution"
const val KEY_SHOW_JPN_TITLE = "show_jpn_title"
const val KEY_SHOW_TAG_TRANSLATIONS = "show_tag_translations"
const val KEY_TAG_TRANSLATIONS_SOURCE = "tag_translations_source"
const val KEY_REQUEST_NEWS = "request_news"
const val KEY_REQUEST_NEWS_TIMER = "request_news_timer"
const val KEY_REQUEST_NEWS_TIMER_HOUR = "request_news_timer_hour"
const val KEY_REQUEST_NEWS_TIMER_MINUTE = "request_news_timer_minute"
const val KEY_HIDE_HV_EVENTS = "hide_hv_events"
val SIGN_IN_REQUIRED = arrayOf(
KEY_IMAGE_LIMITS,
KEY_GALLERY_SITE,
KEY_U_CONFIG,
KEY_MY_TAGS,
KEY_SHOW_JPN_TITLE,
KEY_REQUEST_NEWS,
KEY_REQUEST_NEWS_TIMER,
KEY_HIDE_HV_EVENTS,
)
/********************
* Privacy and Security
*/
const val KEY_SEC_SECURITY = "enable_secure"
const val VALUE_SEC_SECURITY = false
/********************
* Download
*/
const val KEY_DOWNLOAD_SAVE_SCHEME = "image_scheme"
const val KEY_DOWNLOAD_SAVE_AUTHORITY = "image_authority"
const val KEY_DOWNLOAD_SAVE_PATH = "image_path"
const val KEY_NOTIFICATION_REQUIRED = "notification_required"
const val KEY_DOWNLOAD_SAVE_QUERY = "image_query"
const val KEY_DOWNLOAD_SAVE_FRAGMENT = "image_fragment"
const val KEY_MEDIA_SCAN = "media_scan"
const val INVALID_DEFAULT_FAV_SLOT = -2
/********************
* Advanced
*/
const val KEY_SAVE_PARSE_ERROR_BODY = "save_parse_error_body"
const val KEY_SECURITY = "require_unlock"
const val KEY_SECURITY_DELAY = "require_unlock_delay"
const val KEY_READ_CACHE_SIZE = "read_cache_size"
const val DEFAULT_READ_CACHE_SIZE = 640
const val KEY_BUILT_IN_HOSTS = "built_in_hosts_2"
const val KEY_DOMAIN_FRONTING = "domain_fronting"
const val KEY_BYPASS_VPN = "bypass_vpn"
const val KEY_LIST_THUMB_SIZE = "list_tile_size"
private const val KEY_LAST_DAWN_DAY = "last_dawn_day"
private const val DEFAULT_HIDE_HV_EVENTS = false
private const val KEY_SHOW_COMMENTS = "show_gallery_comments"
private const val DEFAULT_SHOW_COMMENTS = true
private val TAG = Settings::class.java.simpleName
private const val KEY_DISPLAY_NAME = "display_name"
private val DEFAULT_DISPLAY_NAME: String? = null
private const val DEFAULT_LIST_THUMB_SIZE = 40
private const val KEY_AVATAR = "avatar"
private const val KEY_REMOVE_IMAGE_FILES = "include_pic"
private const val DEFAULT_REMOVE_IMAGE_FILES = true
private const val KEY_NEED_SIGN_IN = "need_sign_in"
private const val DEFAULT_NEED_SIGN_IN = true
private const val KEY_SELECT_SITE = "select_site"
private const val DEFAULT_SELECT_SITE = true
private const val DEFAULT_THEME = THEME_SYSTEM
private const val DEFAULT_GALLERY_SITE = 0
private const val KEY_LAUNCH_PAGE = "launch_page"
private const val DEFAULT_LAUNCH_PAGE = 0
private const val DEFAULT_LIST_MODE = 0
private const val DEFAULT_DETAIL_SIZE = 0
private const val DEFAULT_THUMB_SIZE = 120
private const val DEFAULT_THUMB_RESOLUTION = 0
private const val DEFAULT_SHOW_JPN_TITLE = false
private const val KEY_SHOW_GALLERY_PAGES = "show_gallery_pages"
private const val DEFAULT_SHOW_GALLERY_PAGES = false
private const val DEFAULT_SHOW_TAG_TRANSLATIONS = false
private const val KEY_METERED_NETWORK_WARNING = "cellular_network_warning"
private const val DEFAULT_METERED_NETWORK_WARNING = false
private const val KEY_APP_LINK_VERIFY_TIP = "app_link_verify_tip"
private const val DEFAULT_APP_LINK_VERIFY_TIP = false
private const val DEFAULT_MEDIA_SCAN = false
private const val KEY_RECENT_DOWNLOAD_LABEL = "recent_download_label"
private val DEFAULT_RECENT_DOWNLOAD_LABEL: String? = null
private const val KEY_HAS_DEFAULT_DOWNLOAD_LABEL = "has_default_download_label"
private const val DEFAULT_HAS_DOWNLOAD_LABEL = false
private const val KEY_DEFAULT_DOWNLOAD_LABEL = "default_download_label"
private val DEFAULT_DOWNLOAD_LABEL: String? = null
private const val KEY_MULTI_THREAD_DOWNLOAD = "download_thread"
private const val DEFAULT_MULTI_THREAD_DOWNLOAD = 3
private const val KEY_PRELOAD_IMAGE = "preload_image"
private const val DEFAULT_PRELOAD_IMAGE = 5
private const val KEY_DOWNLOAD_ORIGIN_IMAGE = "download_origin_image"
private const val DEFAULT_DOWNLOAD_ORIGIN_IMAGE = false
/********************
* Favorites
*/
private const val KEY_FAV_CAT_0 = "fav_cat_0"
private const val KEY_FAV_CAT_1 = "fav_cat_1"
private const val KEY_FAV_CAT_2 = "fav_cat_2"
private const val KEY_FAV_CAT_3 = "fav_cat_3"
private const val KEY_FAV_CAT_4 = "fav_cat_4"
private const val KEY_FAV_CAT_5 = "fav_cat_5"
private const val KEY_FAV_CAT_6 = "fav_cat_6"
private const val KEY_FAV_CAT_7 = "fav_cat_7"
private const val KEY_FAV_CAT_8 = "fav_cat_8"
private const val KEY_FAV_CAT_9 = "fav_cat_9"
private const val DEFAULT_FAV_CAT_0 = "Favorites 0"
private const val DEFAULT_FAV_CAT_1 = "Favorites 1"
private const val DEFAULT_FAV_CAT_2 = "Favorites 2"
private const val DEFAULT_FAV_CAT_3 = "Favorites 3"
private const val DEFAULT_FAV_CAT_4 = "Favorites 4"
private const val DEFAULT_FAV_CAT_5 = "Favorites 5"
private const val DEFAULT_FAV_CAT_6 = "Favorites 6"
private const val DEFAULT_FAV_CAT_7 = "Favorites 7"
private const val DEFAULT_FAV_CAT_8 = "Favorites 8"
private const val DEFAULT_FAV_CAT_9 = "Favorites 9"
private const val KEY_FAV_COUNT_0 = "fav_count_0"
private const val KEY_FAV_COUNT_1 = "fav_count_1"
private const val KEY_FAV_COUNT_2 = "fav_count_2"
private const val KEY_FAV_COUNT_3 = "fav_count_3"
private const val KEY_FAV_COUNT_4 = "fav_count_4"
private const val KEY_FAV_COUNT_5 = "fav_count_5"
private const val KEY_FAV_COUNT_6 = "fav_count_6"
private const val KEY_FAV_COUNT_7 = "fav_count_7"
private const val KEY_FAV_COUNT_8 = "fav_count_8"
private const val KEY_FAV_COUNT_9 = "fav_count_9"
private const val KEY_FAV_LOCAL = "fav_local"
private const val KEY_FAV_CLOUD = "fav_cloud"
private const val DEFAULT_FAV_COUNT = 0
private const val KEY_RECENT_FAV_CAT = "recent_fav_cat"
private const val DEFAULT_RECENT_FAV_CAT = FavListUrlBuilder.FAV_CAT_ALL
// -1 for local, 0 - 9 for cloud favorite, other for no default fav slot
private const val KEY_DEFAULT_FAV_SLOT = "default_favorite_2"
private const val DEFAULT_DEFAULT_FAV_SLOT = INVALID_DEFAULT_FAV_SLOT
private const val DEFAULT_SAVE_PARSE_ERROR_BODY = true
private const val KEY_SAVE_CRASH_LOG = "save_crash_log"
private const val DEFAULT_SAVE_CRASH_LOG = true
private const val DEFAULT_BUILT_IN_HOSTS = false
private const val DEFAULT_FRONTING = false
private const val DEFAULT_BYPASS_VPN = true
private const val KEY_PROXY_TYPE = "proxy_type"
private const val DEFAULT_PROXY_TYPE = EhProxySelector.TYPE_SYSTEM
private const val KEY_PROXY_IP = "proxy_ip"
private val DEFAULT_PROXY_IP: String? = null
private const val KEY_PROXY_PORT = "proxy_port"
private const val DEFAULT_PROXY_PORT = -1
private const val KEY_CLIPBOARD_TEXT_HASH_CODE = "clipboard_text_hash_code"
private const val DEFAULT_CLIPBOARD_TEXT_HASH_CODE = 0
private const val KEY_DOWNLOAD_DELAY = "download_delay"
private const val DEFAULT_DOWNLOAD_DELAY = 0
private const val DEFAULT_REQUEST_NEWS = false
private const val KEY_ARCHIVE_PASSWDS = "archive_passwds"
private const val KEY_QS_SAVE_PROGRESS = "qs_save_progress"
private const val DEFAULT_QS_SAVE_PROGRESS = true
private const val KEY_PRELOAD_THUMB_AGGRESIVELY = "preload_thumb_aggressively"
private const val DEFAULT_PRELOAD_THUMB_AGGRESIVELY = false
var LIST_THUMB_SIZE_INITED = false
private lateinit var sSettingsPre: SharedPreferences
private var LIST_THUMB_SIZE = 40
fun initialize() {
sSettingsPre = PreferenceManager.getDefaultSharedPreferences(application)
fixDefaultValue()
}
private fun fixDefaultValue() {
if ("CN" == Locale.getDefault().country) {
// Enable domain fronting if the country is CN
if (!sSettingsPre.contains(KEY_BUILT_IN_HOSTS)) {
putBuiltInHosts(true)
}
if (!sSettingsPre.contains(KEY_DOMAIN_FRONTING)) {
putDF(true)
}
// Enable show tag translations if the country is CN
if (!sSettingsPre.contains(KEY_SHOW_TAG_TRANSLATIONS)) {
putShowTagTranslations(true)
}
}
}
private fun getBoolean(key: String, defValue: Boolean): Boolean {
return try {
sSettingsPre.getBoolean(key, defValue)
} catch (e: ClassCastException) {
Log.d(TAG, "Get ClassCastException when get $key value", e)
defValue
}
}
private fun putBoolean(key: String, value: Boolean) {
sSettingsPre.edit().putBoolean(key, value).apply()
}
@JvmStatic
fun getInt(key: String, defValue: Int): Int {
return try {
sSettingsPre.getInt(key, defValue)
} catch (e: ClassCastException) {
Log.d(TAG, "Get ClassCastException when get $key value", e)
defValue
}
}
@JvmStatic
fun putInt(key: String, value: Int) {
sSettingsPre.edit().putInt(key, value).apply()
}
private fun getString(key: String, defValue: String?): String? {
return try {
sSettingsPre.getString(key, defValue)
} catch (e: ClassCastException) {
Log.d(TAG, "Get ClassCastException when get $key value", e)
defValue
}
}
private fun putString(key: String, value: String?) {
sSettingsPre.edit().putString(key, value).apply()
}
private fun getStringSet(key: String): MutableSet<String>? {
return sSettingsPre.getStringSet(key, null)
}
private fun putStringToStringSet(key: String, value: String) {
var set = getStringSet(key)
if (set == null) {
set =
mutableSetOf(value)
} else if (set.contains(value)) return else set.add(value)
sSettingsPre.edit().putStringSet(key, set).apply()
}
private fun getIntFromStr(key: String, defValue: Int): Int {
return try {
NumberUtils.parseIntSafely(
sSettingsPre.getString(key, defValue.toString()),
defValue,
)
} catch (e: ClassCastException) {
Log.d(TAG, "Get ClassCastException when get $key value", e)
defValue
}
}
private fun putIntToStr(key: String, value: Int) {
sSettingsPre.edit().putString(key, value.toString()).apply()
}
var lastDawnDay: Long
get() = sSettingsPre.getLong(KEY_LAST_DAWN_DAY, 0)
set(value) = sSettingsPre.edit().putLong(KEY_LAST_DAWN_DAY, value).apply()
val displayName: String?
get() = getString(KEY_DISPLAY_NAME, DEFAULT_DISPLAY_NAME)
fun putDisplayName(value: String?) {
putString(KEY_DISPLAY_NAME, value)
}
fun putAvatar(value: String?) {
putString(KEY_AVATAR, value)
}
val removeImageFiles: Boolean
get() = getBoolean(KEY_REMOVE_IMAGE_FILES, DEFAULT_REMOVE_IMAGE_FILES)
fun putRemoveImageFiles(value: Boolean) {
putBoolean(KEY_REMOVE_IMAGE_FILES, value)
}
val needSignIn: Boolean
get() = getBoolean(KEY_NEED_SIGN_IN, DEFAULT_NEED_SIGN_IN)
fun putNeedSignIn(value: Boolean) {
putBoolean(KEY_NEED_SIGN_IN, value)
}
val selectSite: Boolean
get() = getBoolean(KEY_SELECT_SITE, DEFAULT_SELECT_SITE)
fun putSelectSite(value: Boolean) {
putBoolean(KEY_SELECT_SITE, value)
}
val theme: Int
get() = getIntFromStr(KEY_THEME, DEFAULT_THEME)
val blackDarkTheme
get() = getBoolean(KEY_BLACK_DARK_THEME, DEFAULT_BLACK_DARK_THEME)
val gallerySite: Int
get() = getIntFromStr(KEY_GALLERY_SITE, DEFAULT_GALLERY_SITE)
fun putGallerySite(value: Int) {
putIntToStr(KEY_GALLERY_SITE, value)
}
val launchPageGalleryListSceneAction: String
get() {
return when (val value = getIntFromStr(KEY_LAUNCH_PAGE, DEFAULT_LAUNCH_PAGE)) {
0 -> GalleryListScene.ACTION_HOMEPAGE
1 -> GalleryListScene.ACTION_SUBSCRIPTION
2 -> GalleryListScene.ACTION_WHATS_HOT
3 -> GalleryListScene.ACTION_TOP_LIST
else -> throw IllegalStateException("Unexpected value: $value")
}
}
val listMode: Int
get() = getIntFromStr(KEY_LIST_MODE, DEFAULT_LIST_MODE)
private val detailSize: Int
get() = getIntFromStr(KEY_DETAIL_SIZE, DEFAULT_DETAIL_SIZE)
@get:DimenRes
val detailSizeResId: Int
get() = when (detailSize) {
0 -> R.dimen.gallery_list_column_width_long
1 -> R.dimen.gallery_list_column_width_short
else -> throw IllegalStateException("Unexpected value: $detailSize")
}
val thumbSize: Int
get() = dp2pix(application, thumbSizeDp.toFloat())
val thumbSizeDp: Int
get() = getInt(KEY_THUMB_SIZE, DEFAULT_THUMB_SIZE)
val thumbResolution: Int
get() = getIntFromStr(KEY_THUMB_RESOLUTION, DEFAULT_THUMB_RESOLUTION)
val showComments: Boolean
get() = getBoolean(KEY_SHOW_COMMENTS, DEFAULT_SHOW_COMMENTS)
val requestNews: Boolean
get() = getBoolean(KEY_REQUEST_NEWS, DEFAULT_REQUEST_NEWS)
val hideHvEvents: Boolean
get() = getBoolean(KEY_HIDE_HV_EVENTS, DEFAULT_HIDE_HV_EVENTS)
val showJpnTitle: Boolean
get() = getBoolean(KEY_SHOW_JPN_TITLE, DEFAULT_SHOW_JPN_TITLE)
val showGalleryPages: Boolean
get() = getBoolean(KEY_SHOW_GALLERY_PAGES, DEFAULT_SHOW_GALLERY_PAGES)
val showTagTranslations: Boolean
get() = getBoolean(KEY_SHOW_TAG_TRANSLATIONS, DEFAULT_SHOW_TAG_TRANSLATIONS)
private fun putShowTagTranslations(value: Boolean) {
putBoolean(KEY_SHOW_TAG_TRANSLATIONS, value)
}
val meteredNetworkWarning: Boolean
get() = getBoolean(KEY_METERED_NETWORK_WARNING, DEFAULT_METERED_NETWORK_WARNING)
val appLinkVerifyTip: Boolean
get() = getBoolean(KEY_APP_LINK_VERIFY_TIP, DEFAULT_APP_LINK_VERIFY_TIP)
fun putAppLinkVerifyTip(value: Boolean) {
putBoolean(KEY_APP_LINK_VERIFY_TIP, value)
}
val enabledSecurity: Boolean
get() = getBoolean(KEY_SEC_SECURITY, VALUE_SEC_SECURITY)
val downloadLocation: UniFile?
get() {
val dir: UniFile?
val builder = Uri.Builder()
builder.scheme(getString(KEY_DOWNLOAD_SAVE_SCHEME, null))
builder.encodedAuthority(getString(KEY_DOWNLOAD_SAVE_AUTHORITY, null))
builder.encodedPath(getString(KEY_DOWNLOAD_SAVE_PATH, null))
builder.encodedQuery(getString(KEY_DOWNLOAD_SAVE_QUERY, null))
builder.encodedFragment(getString(KEY_DOWNLOAD_SAVE_FRAGMENT, null))
dir = UniFile.fromUri(application, builder.build())
return dir ?: UniFile.fromFile(AppConfig.getDefaultDownloadDir())
}
fun putDownloadLocation(location: UniFile) {
val uri = location.uri
putString(KEY_DOWNLOAD_SAVE_SCHEME, uri.scheme)
putString(KEY_DOWNLOAD_SAVE_AUTHORITY, uri.encodedAuthority)
putString(KEY_DOWNLOAD_SAVE_PATH, uri.encodedPath)
putString(KEY_DOWNLOAD_SAVE_QUERY, uri.encodedQuery)
putString(KEY_DOWNLOAD_SAVE_FRAGMENT, uri.encodedFragment)
}
val mediaScan: Boolean
get() = getBoolean(KEY_MEDIA_SCAN, DEFAULT_MEDIA_SCAN)
val recentDownloadLabel: String?
get() = getString(KEY_RECENT_DOWNLOAD_LABEL, DEFAULT_RECENT_DOWNLOAD_LABEL)
fun putRecentDownloadLabel(value: String?) {
putString(KEY_RECENT_DOWNLOAD_LABEL, value)
}
val hasDefaultDownloadLabel: Boolean
get() = getBoolean(KEY_HAS_DEFAULT_DOWNLOAD_LABEL, DEFAULT_HAS_DOWNLOAD_LABEL)
fun putHasDefaultDownloadLabel(hasDefaultDownloadLabel: Boolean) {
putBoolean(KEY_HAS_DEFAULT_DOWNLOAD_LABEL, hasDefaultDownloadLabel)
}
val defaultDownloadLabel: String?
get() = getString(KEY_DEFAULT_DOWNLOAD_LABEL, DEFAULT_DOWNLOAD_LABEL)
fun putDefaultDownloadLabel(value: String?) {
putString(KEY_DEFAULT_DOWNLOAD_LABEL, value)
}
val multiThreadDownload: Int
get() = getIntFromStr(KEY_MULTI_THREAD_DOWNLOAD, DEFAULT_MULTI_THREAD_DOWNLOAD)
val downloadDelay: Int
get() = getIntFromStr(KEY_DOWNLOAD_DELAY, DEFAULT_DOWNLOAD_DELAY)
val preloadImage: Int
get() = getIntFromStr(KEY_PRELOAD_IMAGE, DEFAULT_PRELOAD_IMAGE)
val downloadOriginImage: Boolean
get() = getBoolean(KEY_DOWNLOAD_ORIGIN_IMAGE, DEFAULT_DOWNLOAD_ORIGIN_IMAGE)
val favCat: Array<String>
get() = arrayOf(
sSettingsPre.getString(KEY_FAV_CAT_0, DEFAULT_FAV_CAT_0)!!,
sSettingsPre.getString(KEY_FAV_CAT_1, DEFAULT_FAV_CAT_1)!!,
sSettingsPre.getString(KEY_FAV_CAT_2, DEFAULT_FAV_CAT_2)!!,
sSettingsPre.getString(KEY_FAV_CAT_3, DEFAULT_FAV_CAT_3)!!,
sSettingsPre.getString(KEY_FAV_CAT_4, DEFAULT_FAV_CAT_4)!!,
sSettingsPre.getString(KEY_FAV_CAT_5, DEFAULT_FAV_CAT_5)!!,
sSettingsPre.getString(KEY_FAV_CAT_6, DEFAULT_FAV_CAT_6)!!,
sSettingsPre.getString(KEY_FAV_CAT_7, DEFAULT_FAV_CAT_7)!!,
sSettingsPre.getString(KEY_FAV_CAT_8, DEFAULT_FAV_CAT_8)!!,
sSettingsPre.getString(KEY_FAV_CAT_9, DEFAULT_FAV_CAT_9)!!,
)
fun putFavCat(value: Array<String?>) {
check(value.size == 10)
sSettingsPre.edit()
.putString(KEY_FAV_CAT_0, value[0])
.putString(KEY_FAV_CAT_1, value[1])
.putString(KEY_FAV_CAT_2, value[2])
.putString(KEY_FAV_CAT_3, value[3])
.putString(KEY_FAV_CAT_4, value[4])
.putString(KEY_FAV_CAT_5, value[5])
.putString(KEY_FAV_CAT_6, value[6])
.putString(KEY_FAV_CAT_7, value[7])
.putString(KEY_FAV_CAT_8, value[8])
.putString(KEY_FAV_CAT_9, value[9])
.apply()
}
val favCount: IntArray
get() = intArrayOf(
sSettingsPre.getInt(KEY_FAV_COUNT_0, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_1, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_2, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_3, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_4, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_5, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_6, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_7, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_8, DEFAULT_FAV_COUNT),
sSettingsPre.getInt(KEY_FAV_COUNT_9, DEFAULT_FAV_COUNT),
)
fun putFavCount(count: IntArray) {
check(count.size == 10)
sSettingsPre.edit()
.putInt(KEY_FAV_COUNT_0, count[0])
.putInt(KEY_FAV_COUNT_1, count[1])
.putInt(KEY_FAV_COUNT_2, count[2])
.putInt(KEY_FAV_COUNT_3, count[3])
.putInt(KEY_FAV_COUNT_4, count[4])
.putInt(KEY_FAV_COUNT_5, count[5])
.putInt(KEY_FAV_COUNT_6, count[6])
.putInt(KEY_FAV_COUNT_7, count[7])
.putInt(KEY_FAV_COUNT_8, count[8])
.putInt(KEY_FAV_COUNT_9, count[9])
.apply()
}
val favLocalCount: Int
get() = sSettingsPre.getInt(KEY_FAV_LOCAL, DEFAULT_FAV_COUNT)
fun putFavLocalCount(count: Int) {
sSettingsPre.edit().putInt(KEY_FAV_LOCAL, count).apply()
}
val favCloudCount: Int
get() = sSettingsPre.getInt(KEY_FAV_CLOUD, DEFAULT_FAV_COUNT)
fun putFavCloudCount(count: Int) {
sSettingsPre.edit().putInt(KEY_FAV_CLOUD, count).apply()
}
val recentFavCat: Int
get() = getInt(KEY_RECENT_FAV_CAT, DEFAULT_RECENT_FAV_CAT)
fun putRecentFavCat(value: Int) {
putInt(KEY_RECENT_FAV_CAT, value)
}
val defaultFavSlot: Int
get() = getInt(KEY_DEFAULT_FAV_SLOT, DEFAULT_DEFAULT_FAV_SLOT)
fun putDefaultFavSlot(value: Int) {
putInt(KEY_DEFAULT_FAV_SLOT, value)
}
val qSSaveProgress: Boolean
get() = getBoolean(KEY_QS_SAVE_PROGRESS, DEFAULT_QS_SAVE_PROGRESS)
fun putQSSaveProgress(value: Boolean) {
putBoolean(KEY_QS_SAVE_PROGRESS, value)
}
val saveParseErrorBody: Boolean
get() = getBoolean(KEY_SAVE_PARSE_ERROR_BODY, DEFAULT_SAVE_PARSE_ERROR_BODY)
val saveCrashLog: Boolean
get() = getBoolean(KEY_SAVE_CRASH_LOG, DEFAULT_SAVE_CRASH_LOG)
val security: Boolean
get() = getBoolean(KEY_SECURITY, false)
fun putSecurity(value: Boolean) {
putBoolean(KEY_SECURITY, value)
}
val securityDelay: Int
get() = getInt(KEY_SECURITY_DELAY, 0)
val readCacheSize: Int
get() = getIntFromStr(KEY_READ_CACHE_SIZE, DEFAULT_READ_CACHE_SIZE)
val builtInHosts: Boolean
get() = getBoolean(KEY_BUILT_IN_HOSTS, DEFAULT_BUILT_IN_HOSTS)
private fun putBuiltInHosts(value: Boolean) {
putBoolean(KEY_BUILT_IN_HOSTS, value)
}
val dF: Boolean
get() = getBoolean(KEY_DOMAIN_FRONTING, DEFAULT_FRONTING)
private fun putDF(value: Boolean) {
putBoolean(KEY_DOMAIN_FRONTING, value)
}
val bypassVpn: Boolean
get() = getBoolean(KEY_BYPASS_VPN, DEFAULT_BYPASS_VPN)
@JvmStatic
val proxyType: Int
get() = getInt(KEY_PROXY_TYPE, DEFAULT_PROXY_TYPE)
fun putProxyType(value: Int) {
putInt(KEY_PROXY_TYPE, value)
}
@JvmStatic
val proxyIp: String?
get() = getString(KEY_PROXY_IP, DEFAULT_PROXY_IP)
fun putProxyIp(value: String?) {
putString(KEY_PROXY_IP, value)
}
@JvmStatic
val proxyPort: Int
get() = getInt(KEY_PROXY_PORT, DEFAULT_PROXY_PORT)
fun putProxyPort(value: Int) {
putInt(KEY_PROXY_PORT, value)
}
val clipboardTextHashCode: Int
get() = getInt(KEY_CLIPBOARD_TEXT_HASH_CODE, DEFAULT_CLIPBOARD_TEXT_HASH_CODE)
fun putClipboardTextHashCode(value: Int) {
putInt(KEY_CLIPBOARD_TEXT_HASH_CODE, value)
}
val archivePasswds: Set<String>?
get() = getStringSet(KEY_ARCHIVE_PASSWDS)
fun putPasswdToArchivePasswds(value: String) {
putStringToStringSet(KEY_ARCHIVE_PASSWDS, value)
}
val listThumbSize: Int
get() {
if (LIST_THUMB_SIZE_INITED) {
return LIST_THUMB_SIZE
}
val size = 3 * getInt(KEY_LIST_THUMB_SIZE, DEFAULT_LIST_THUMB_SIZE)
LIST_THUMB_SIZE = size
LIST_THUMB_SIZE_INITED = true
return size
}
val notificationRequired: Boolean
get() = getBoolean(KEY_NOTIFICATION_REQUIRED, false)
fun putNotificationRequired() {
putBoolean(KEY_NOTIFICATION_REQUIRED, true)
}
val preloadThumbAggressively: Boolean
get() = getBoolean(KEY_PRELOAD_THUMB_AGGRESIVELY, DEFAULT_PRELOAD_THUMB_AGGRESIVELY)
}
@@ -1,46 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.data.GalleryPreview
import com.hippo.ehviewer.client.data.NormalGalleryPreview
// ExHentai Large Preview: https://s.exhentai.org/t/***
// ExHentai Normal Preview: https://s.exhentai.org/m/***
// EHentai Normal Preview: https://ehgt.org/m/***
// EHentai Large Preview: https://ehgt.org/***
private const val URL_PREFIX_THUMB_E = "https://ehgt.org/"
private const val URL_PREFIX_THUMB_EX = "https://s.exhentai.org/"
fun getImageKey(gid: Long, index: Int): String {
return "image:$gid:$index"
}
fun getThumbKey(url: String): String {
return url.removePrefix(URL_PREFIX_THUMB_E).removePrefix(URL_PREFIX_THUMB_EX).removePrefix("t/")
}
val GalleryPreview.url
get() = if (this is NormalGalleryPreview) {
if (EhUtils.isExHentai) URL_PREFIX_THUMB_EX + imageKey else URL_PREFIX_THUMB_E + imageKey
} else {
if (EhUtils.isExHentai) URL_PREFIX_THUMB_EX + "t/" + imageKey else URL_PREFIX_THUMB_E + imageKey
}
val GalleryInfo.thumbUrl
get() = if (EhUtils.isExHentai) URL_PREFIX_THUMB_EX + "t/" + thumbKey!! else URL_PREFIX_THUMB_E + thumbKey!!
@@ -1,269 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import com.hippo.ehviewer.EhApplication
import com.hippo.ehviewer.network.CookieDatabase
import com.hippo.ehviewer.network.CookieSet
import eu.kanade.tachiyomi.util.lang.launchIO
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import java.util.Collections
import java.util.regex.Pattern
object EhCookieStore : CookieJar {
private val db: CookieDatabase = CookieDatabase(EhApplication.application)
private val map: MutableMap<String, CookieSet> = db.allCookies
fun signOut() {
clear()
}
fun hasSignedIn(): Boolean {
val url = EhUrl.HOST_E.toHttpUrl()
return contains(url, KEY_IPB_MEMBER_ID) &&
contains(url, KEY_IPB_PASS_HASH)
}
const val KEY_IPB_MEMBER_ID = "ipb_member_id"
const val KEY_IPB_PASS_HASH = "ipb_pass_hash"
const val KEY_IGNEOUS = "igneous"
const val KEY_SETTINGS_PROFILE = "sp"
const val KEY_STAR = "star"
private const val KEY_CONTENT_WARNING = "nw"
private const val CONTENT_WARNING_NOT_SHOW = "1"
private val sTipsCookie: Cookie = Cookie.Builder()
.name(KEY_CONTENT_WARNING)
.value(CONTENT_WARNING_NOT_SHOW)
.domain(EhUrl.DOMAIN_E)
.path("/")
.expiresAt(Long.MAX_VALUE)
.build()
fun newCookie(
cookie: Cookie,
newDomain: String,
forcePersistent: Boolean = false,
forceLongLive: Boolean = false,
forceNotHostOnly: Boolean = false,
): Cookie {
val builder = Cookie.Builder()
builder.name(cookie.name)
builder.value(cookie.value)
if (forceLongLive) {
builder.expiresAt(Long.MAX_VALUE)
} else if (cookie.persistent) {
builder.expiresAt(cookie.expiresAt)
} else if (forcePersistent) {
builder.expiresAt(Long.MAX_VALUE)
}
if (cookie.hostOnly && !forceNotHostOnly) {
builder.hostOnlyDomain(newDomain)
} else {
builder.domain(newDomain)
}
builder.path(cookie.path)
if (cookie.secure) {
builder.secure()
}
if (cookie.httpOnly) {
builder.httpOnly()
}
return builder.build()
}
fun copyCookie(domain: String, newDomain: String, name: String, path: String = "/") {
val cookie = map[domain]?.get(name, domain, path)
cookie?.let { addCookie(newCookie(it, newDomain)) }
}
fun deleteCookie(url: HttpUrl, name: String) {
val deletedCookie = Cookie.Builder()
.name(name)
.value("deleted")
.domain(url.host)
.expiresAt(0)
.build()
addCookie(deletedCookie)
}
@Synchronized
fun addCookie(cookie: Cookie) {
// For cookie database
var toAdd: Cookie? = null
var toUpdate: Cookie? = null
var toRemove: Cookie? = null
var set = map[cookie.domain]
if (set == null) {
set = CookieSet()
map[cookie.domain] = set
}
if (cookie.expiresAt <= System.currentTimeMillis()) {
toRemove = set.remove(cookie)
// If the cookie is not persistent, it's not in database
if (toRemove != null && !toRemove.persistent) {
toRemove = null
}
} else {
toAdd = cookie
toUpdate = set.add(cookie)
// If the cookie is not persistent, it's not in database
if (!toAdd.persistent) toAdd = null
if (toUpdate != null && !toUpdate.persistent) toUpdate = null
// Remove the cookie if it updates to null
if (toAdd == null && toUpdate != null) {
toRemove = toUpdate
toUpdate = null
}
}
if (toRemove != null) {
db.remove(toRemove)
}
if (toAdd != null) {
if (toUpdate != null) {
db.update(toUpdate, toAdd)
} else {
db.add(toAdd)
}
}
}
fun getCookieHeader(url: HttpUrl): String {
val cookies = getCookies(url)
val cookieHeader = StringBuilder()
var i = 0
val size = cookies.size
while (i < size) {
if (i > 0) {
cookieHeader.append("; ")
}
val cookie = cookies[i]
cookieHeader.append(cookie.name).append('=').append(cookie.value)
i++
}
return cookieHeader.toString()
}
@Synchronized
fun getCookies(url: HttpUrl): List<Cookie> {
val accepted: MutableList<Cookie> = ArrayList()
val expired: MutableList<Cookie> = ArrayList()
for ((domain, cookieSet) in map) {
if (domainMatch(url, domain)) {
cookieSet[url, accepted, expired]
}
}
for (cookie in expired) {
if (cookie.persistent) {
db.remove(cookie)
}
}
// RFC 6265 Section-5.4 step 2, sort the cookie-list
// Cookies with longer paths are listed before cookies with shorter paths.
// Ignore creation-time, we don't store them.
accepted.sortWith { o1: Cookie, o2: Cookie -> o2.path.length - o1.path.length }
return accepted
}
fun contains(url: HttpUrl, name: String?): Boolean {
for (cookie in getCookies(url)) {
if (cookie.name == name) {
return true
}
}
return false
}
/**
* Remove all cookies in this `CookieRepository`.
*/
@Synchronized
fun clear() {
map.clear()
launchIO {
db.clear()
}
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
for (cookie in cookies) {
// See https://github.com/Ehviewer-Overhauled/Ehviewer/issues/873
if (cookie.name != "__utmp") {
addCookie(cookie)
}
}
}
/**
* Quick and dirty pattern to differentiate IP addresses from hostnames. This is an approximation
* of Android's private InetAddress#isNumeric API.
*
*
* This matches IPv6 addresses as a hex string containing at least one colon, and possibly
* including dots after the first colon. It matches IPv4 addresses as strings containing only
* decimal digits and dots. This pattern matches strings like "a:.23" and "54" that are neither IP
* addresses nor hostnames; they will be verified as IP addresses (which is a more strict
* verification).
*/
private val VERIFY_AS_IP_ADDRESS =
Pattern.compile("([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)")
/**
* Returns true if `host` is not a host name and might be an IP address.
*/
private fun verifyAsIpAddress(host: String): Boolean {
return VERIFY_AS_IP_ADDRESS.matcher(host).matches()
}
// okhttp3.Cookie.domainMatch(HttpUrl, String)
@JvmStatic
fun domainMatch(url: HttpUrl, domain: String?): Boolean {
val urlHost = url.host
return if (urlHost == domain) {
true // As in 'example.com' matching 'example.com'.
} else {
urlHost.endsWith(domain!!) &&
urlHost[urlHost.length - domain.length - 1] == '.' && !verifyAsIpAddress(
urlHost,
)
}
// As in 'example.com' matching 'www.example.com'.
}
override fun loadForRequest(url: HttpUrl): List<Cookie> {
val cookies = getCookies(url)
val checkTips = domainMatch(url, EhUrl.DOMAIN_E)
return if (checkTips) {
val result: MutableList<Cookie> = ArrayList(cookies.size + 1)
// Add all but skip some
for (cookie in cookies) {
val name = cookie.name
if (KEY_CONTENT_WARNING == name) {
continue
}
result.add(cookie)
}
// Add some
result.add(sTipsCookie)
Collections.unmodifiableList(result)
} else {
cookies
}
}
}
@@ -1,137 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import com.hippo.ehviewer.EhApplication
import com.hippo.ehviewer.Hosts
import com.hippo.ehviewer.Settings
import okhttp3.Dns
import java.net.InetAddress
import java.net.UnknownHostException
object EhDns : Dns {
private val hosts = EhApplication.hosts
private val builtInHosts: MutableMap<String, List<InetAddress>> = mutableMapOf()
init {
// Pair(ip: String!, blockedByCCP: Boolean!)
val ehgtHosts = arrayOf(
Pair("37.48.89.44", false),
Pair("81.171.10.48", false),
Pair("178.162.139.24", false),
Pair("178.162.140.212", false),
Pair("2001:1af8:4700:a062:8::47de", false),
Pair("2001:1af8:4700:a062:9::47de", true),
Pair("2001:1af8:4700:a0c9:4::47de", false),
Pair("2001:1af8:4700:a0c9:3::47de", true),
)
put(
builtInHosts,
"e-hentai.org",
Pair("104.20.134.21", false),
Pair("104.20.135.21", false),
Pair("172.67.0.127", false),
)
put(
builtInHosts,
"exhentai.org",
Pair("178.175.128.252", false),
Pair("178.175.129.252", false),
Pair("178.175.129.254", false),
Pair("178.175.128.254", false),
Pair("178.175.132.20", false),
Pair("178.175.132.22", false),
)
put(
builtInHosts,
"s.exhentai.org",
Pair("178.175.129.254", false),
Pair("178.175.128.254", false),
Pair("178.175.132.22", false),
)
put(
builtInHosts,
"repo.e-hentai.org",
Pair("94.100.28.57", true),
Pair("94.100.29.73", true),
)
put(
builtInHosts,
"forums.e-hentai.org",
Pair("94.100.18.243", false),
)
put(
builtInHosts,
"ehgt.org",
*ehgtHosts,
)
put(
builtInHosts,
"gt0.ehgt.org",
*ehgtHosts,
)
put(
builtInHosts,
"gt1.ehgt.org",
*ehgtHosts,
)
put(
builtInHosts,
"gt2.ehgt.org",
*ehgtHosts,
)
put(
builtInHosts,
"gt3.ehgt.org",
*ehgtHosts,
)
put(
builtInHosts,
"ul.ehgt.org",
Pair("94.100.24.82", true),
Pair("94.100.24.72", true),
)
put(
builtInHosts,
"raw.githubusercontent.com",
Pair("151.101.0.133", false),
Pair("151.101.64.133", false),
Pair("151.101.128.133", false),
Pair("151.101.192.133", false),
)
}
private fun put(
map: MutableMap<String, List<InetAddress>>,
host: String,
vararg ips: Pair<String, Boolean>,
) {
map[host] = ips.mapNotNull { pair ->
Hosts.toInetAddress(host, pair.first).takeUnless { Settings.dF && pair.second }
}
}
@Throws(UnknownHostException::class)
override fun lookup(hostname: String): List<InetAddress> {
return hosts[hostname] ?: builtInHosts[hostname].takeIf { Settings.builtInHosts }
?: Dns.SYSTEM.lookup(hostname)
}
fun isInHosts(hostname: String): Boolean {
return hosts.contains(hostname) || (builtInHosts.contains(hostname) && Settings.builtInHosts)
}
}
@@ -1,454 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import android.util.Log
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.parZip
import com.hippo.ehviewer.AppConfig
import com.hippo.ehviewer.GetText
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.exception.EhException
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.client.parser.ArchiveParser
import com.hippo.ehviewer.client.parser.EventPaneParser
import com.hippo.ehviewer.client.parser.FavoritesParser
import com.hippo.ehviewer.client.parser.ForumsParser
import com.hippo.ehviewer.client.parser.GalleryApiParser
import com.hippo.ehviewer.client.parser.GalleryDetailParser
import com.hippo.ehviewer.client.parser.GalleryListParser
import com.hippo.ehviewer.client.parser.GalleryNotAvailableParser
import com.hippo.ehviewer.client.parser.GalleryPageApiParser
import com.hippo.ehviewer.client.parser.GalleryPageParser
import com.hippo.ehviewer.client.parser.GalleryTokenApiParser
import com.hippo.ehviewer.client.parser.HomeParser
import com.hippo.ehviewer.client.parser.ProfileParser
import com.hippo.ehviewer.client.parser.RateGalleryParser
import com.hippo.ehviewer.client.parser.SignInParser
import com.hippo.ehviewer.client.parser.TorrentParser
import com.hippo.ehviewer.client.parser.VoteCommentParser
import com.hippo.ehviewer.client.parser.VoteTagParser
import com.hippo.ehviewer.dailycheck.showEventNotification
import com.hippo.ehviewer.dailycheck.today
import com.hippo.ehviewer.network.StatusCodeException
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay
import moe.tarsin.coroutines.runSuspendCatching
import okhttp3.Headers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.Request
import okhttp3.RequestBody.Companion.asRequestBody
import org.json.JSONArray
import org.jsoup.Jsoup
import java.io.File
import kotlin.math.ceil
private const val TAG = "EhEngine"
private const val MAX_REQUEST_SIZE = 25
private const val SAD_PANDA_DISPOSITION = "inline; filename=\"sadpanda.jpg\""
private const val SAD_PANDA_TYPE = "image/gif"
private const val SAD_PANDA_LENGTH = "9615"
private const val KOKOMADE_URL = "https://exhentai.org/img/kokomade.jpg"
private const val U_CONFIG_TEXT = "Selected Profile"
private val MEDIA_TYPE_JPEG: MediaType = "image/jpeg".toMediaType()
private fun rethrowExactly(code: Int, headers: Headers, body: String, e: Throwable): Nothing {
// Don't translate coroutine cancellation
if (e is CancellationException) throw e
// Check sad panda
if (SAD_PANDA_DISPOSITION == headers["Content-Disposition"] && SAD_PANDA_TYPE == headers["Content-Type"] && SAD_PANDA_LENGTH == headers["Content-Length"]) {
throw EhException("Sad Panda")
}
// Check sad panda(without panda)
if ("text/html; charset=UTF-8" == headers["Content-Type"] && "0" == headers["Content-Length"] && EhUtils.isExHentai) {
throw EhException("Sad Panda\n(without panda)")
}
// Check kokomade
if (body.contains(KOKOMADE_URL)) {
throw EhException("今回はここまで ${GetText.getString(R.string.kokomade_tip)}".trimIndent())
}
// Check Gallery Not Available
if (body.contains("Gallery Not Available - ")) {
val error = GalleryNotAvailableParser.parse(body)
if (!error.isNullOrBlank()) {
throw EhException(error)
}
}
// Check bad response code
if (code >= 400) {
throw StatusCodeException(code)
}
if (e is ParseException) {
if (body.isEmpty()) {
throw EhException(GetText.getString(R.string.error_empty_html))
} else if ("<" !in body) {
throw EhException(body)
} else {
if (Settings.saveParseErrorBody) AppConfig.saveParseErrorBody(e)
throw EhException(GetText.getString(R.string.error_parse_error))
}
}
// We can't translate it, rethrow it anyway
throw e
}
private suspend inline fun <T> Request.executeAndParsingWith(block: String.() -> T): T {
Log.d(TAG, url.toString())
return execute {
val body = body.string()
try {
block(body)
} catch (e: Exception) {
rethrowExactly(code, headers, body, e)
}
}
}
object EhEngine {
suspend fun getTorrentList(url: String, gid: Long, token: String?): List<TorrentParser.Result> {
val referer = EhUrl.getGalleryDetailUrl(gid, token)
return ehRequest(url, referer).executeAndParsingWith(TorrentParser::parse)
}
suspend fun getArchiveList(url: String, gid: Long, token: String?) = ehRequest(url, EhUrl.getGalleryDetailUrl(gid, token))
.executeAndParsingWith(ArchiveParser::parse)
.apply { funds = funds ?: ehRequest(EhUrl.URL_FUNDS).executeAndParsingWith(HomeParser::parseFunds) }
suspend fun getImageLimits() = parZip(
{ ehRequest(EhUrl.URL_HOME).executeAndParsingWith(HomeParser::parse) },
{ ehRequest(EhUrl.URL_FUNDS).executeAndParsingWith(HomeParser::parseFunds) },
{ limits, funds -> HomeParser.Result(limits, funds) },
)
suspend fun getNews(parse: Boolean) = ehRequest(EhUrl.URL_NEWS, EhUrl.REFERER_E)
.executeAndParsingWith { if (parse) EventPaneParser.parse(this) else null }
suspend fun getProfile(): ProfileParser.Result {
val url = ehRequest(EhUrl.URL_FORUMS).executeAndParsingWith(ForumsParser::parse)
return ehRequest(url, EhUrl.URL_FORUMS).executeAndParsingWith(ProfileParser::parse)
}
suspend fun getUConfig(url: String = EhUrl.uConfigUrl) {
runSuspendCatching {
ehRequest(url).executeAndParsingWith { check(contains(U_CONFIG_TEXT)) { "U_CONFIG_TEXT not found!" } }
}.onFailure {
// It may get redirected when accessing ex for the first time
if (EhUtils.isExHentai) {
it.printStackTrace()
ehRequest(url).executeAndParsingWith { check(contains(U_CONFIG_TEXT)) { "U_CONFIG_TEXT not found!" } }
} else {
throw it
}
}
}
suspend fun getGalleryPage(
url: String,
gid: Long,
token: String?,
): GalleryPageParser.Result {
val referer = EhUrl.getGalleryDetailUrl(gid, token)
return ehRequest(url, referer).executeAndParsingWith(GalleryPageParser::parse)
}
suspend fun getGalleryList(url: String) = ehRequest(url, EhUrl.referer)
.executeAndParsingWith(GalleryListParser::parse)
.apply { fillGalleryList(galleryInfoList, url, true) }
suspend fun getGalleryDetail(url: String) = ehRequest(url, EhUrl.referer).executeAndParsingWith {
EventPaneParser.parse(this)?.let {
Settings.lastDawnDay = today
showEventNotification(it)
}
GalleryDetailParser.parse(this)
}
suspend fun getPreviewList(url: String) = ehRequest(url, EhUrl.referer).executeAndParsingWith {
GalleryDetailParser.parsePreviewList(this) to GalleryDetailParser.parsePreviewPages(this)
}
suspend fun getFavorites(url: String) = ehRequest(url, EhUrl.referer)
.executeAndParsingWith(FavoritesParser::parse)
.apply { fillGalleryList(galleryInfoList, url, false) }
suspend fun signIn(username: String, password: String): String {
val referer = "https://forums.e-hentai.org/index.php?act=Login&CODE=00"
val url = EhUrl.API_SIGN_IN
val origin = "https://forums.e-hentai.org"
return ehRequest(url, referer, origin) {
formBody {
add("referer", referer)
add("b", "")
add("bt", "")
add("UserName", username)
add("PassWord", password)
add("CookieDate", "1")
}
}.executeAndParsingWith(SignInParser::parse)
}
suspend fun commentGallery(url: String, comment: String, id: String?) = ehRequest(url, url, EhUrl.origin) {
formBody {
if (id == null) {
add("commenttext_new", comment)
} else {
add("commenttext_edit", comment)
add("edit_comment", id)
}
}
}.executeAndParsingWith {
val document = Jsoup.parse(this)
val elements = document.select("#chd + p")
if (elements.size > 0) {
throw EhException(elements[0].text())
}
GalleryDetailParser.parseComments(document)
}
/**
* @param dstCat -1 for delete, 0 - 9 for cloud favorite, others throw Exception
* @param note max 250 characters
*/
suspend fun addFavorites(
gid: Long,
token: String?,
dstCat: Int,
note: String?,
) {
val catStr: String = when (dstCat) {
-1 -> "favdel"
in 0..9 -> dstCat.toString()
else -> throw EhException("Invalid dstCat: $dstCat")
}
val url = EhUrl.getAddFavorites(gid, token)
return ehRequest(url, url, EhUrl.origin) {
formBody {
add("favcat", catStr)
add("favnote", note ?: "")
// submit=Add+to+Favorites is not necessary, just use submit=Apply+Changes all the time
add("submit", "Apply Changes")
add("update", "1")
}
}.executeAndParsingWith { }
}
suspend fun downloadArchive(
gid: Long,
token: String?,
or: String?,
res: String?,
isHAtH: Boolean,
): String? {
if (or.isNullOrEmpty()) {
throw EhException("Invalid form param or: $or")
}
if (res.isNullOrEmpty()) {
throw EhException("Invalid res: $res")
}
val url = EhUrl.getDownloadArchive(gid, token, or)
val referer = EhUrl.getGalleryDetailUrl(gid, token)
val request = ehRequest(url, referer, EhUrl.origin) {
formBody {
if (isHAtH) {
add("hathdl_xres", res)
} else {
add("dltype", res)
if (res == "org") {
add("dlcheck", "Download Original Archive")
} else {
add("dlcheck", "Download Resample Archive")
}
}
}
}
var result = request.executeAndParsingWith(ArchiveParser::parseArchiveUrl)
if (!isHAtH) {
if (result == null) {
// Wait for the server to prepare archives
delay(1000)
result = request.executeAndParsingWith(ArchiveParser::parseArchiveUrl)
if (result == null) {
throw EhException("Archive unavailable")
}
}
return result
}
return null
}
suspend fun resetImageLimits(): HomeParser.Limits? {
return ehRequest(EhUrl.URL_HOME) {
formBody {
add("act", "limits")
add("reset", "Reset Limit")
}
}.executeAndParsingWith(HomeParser::parseResetLimits)
}
suspend fun modifyFavorites(url: String, gidArray: LongArray, dstCat: Int): FavoritesParser.Result {
val catStr: String = when (dstCat) {
-1 -> "delete"
in 0..9 -> "fav$dstCat"
else -> throw EhException("Invalid dstCat: $dstCat")
}
return ehRequest(url, url, EhUrl.origin) {
formBody {
add("ddact", catStr)
gidArray.forEach { add("modifygids[]", it.toString()) }
add("apply", "Apply")
}
}.executeAndParsingWith(FavoritesParser::parse).apply { fillGalleryList(galleryInfoList, url, false) }
}
suspend fun getGalleryPageApi(
gid: Long,
index: Int,
pToken: String,
showKey: String?,
previousPToken: String?,
): GalleryPageApiParser.Result {
val referer = if (index > 0 && previousPToken != null) EhUrl.getPageUrl(gid, index - 1, previousPToken) else null
return ehRequest(EhUrl.apiUrl, referer, EhUrl.origin) {
jsonBody {
put("method", "showpage")
put("gid", gid)
put("page", index + 1)
put("imgkey", pToken)
put("showkey", showKey)
}
}.executeAndParsingWith(GalleryPageApiParser::parse)
}
suspend fun rateGallery(apiUid: Long, apiKey: String?, gid: Long, token: String?, rating: Float) = ehRequest(EhUrl.apiUrl, EhUrl.getGalleryDetailUrl(gid, token), EhUrl.origin) {
jsonBody {
put("method", "rategallery")
put("apiuid", apiUid)
put("apikey", apiKey)
put("gid", gid)
put("token", token)
put("rating", ceil((rating * 2).toDouble()).toInt())
}
}.executeAndParsingWith(RateGalleryParser::parse)
suspend fun fillGalleryListByApi(galleryInfoList: List<GalleryInfo>, referer: String) = galleryInfoList.chunked(MAX_REQUEST_SIZE).parMap {
ehRequest(EhUrl.apiUrl, referer, EhUrl.origin) {
jsonBody {
put("method", "gdata")
array("gidlist") { it.forEach { put(jsonArrayOf(it.gid, it.token)) } }
put("namespace", 1)
}
}.executeAndParsingWith { GalleryApiParser.parse(this, it) }
}
suspend fun voteComment(
apiUid: Long,
apiKey: String?,
gid: Long,
token: String?,
commentId: Long,
commentVote: Int,
) = ehRequest(EhUrl.apiUrl, EhUrl.referer, EhUrl.origin) {
jsonBody {
put("method", "votecomment")
put("apiuid", apiUid)
put("apikey", apiKey)
put("gid", gid)
put("token", token)
put("comment_id", commentId)
put("comment_vote", commentVote)
}
}.executeAndParsingWith { VoteCommentParser.parse(this, commentVote) }
suspend fun voteTag(
apiUid: Long,
apiKey: String?,
gid: Long,
token: String?,
tags: String?,
vote: Int,
) = ehRequest(EhUrl.apiUrl, EhUrl.referer, EhUrl.origin) {
jsonBody {
put("method", "taggallery")
put("apiuid", apiUid)
put("apikey", apiKey)
put("gid", gid)
put("token", token)
put("tags", tags)
put("vote", vote)
}
}.executeAndParsingWith(VoteTagParser::parse)
suspend fun getGalleryToken(gid: Long, gtoken: String?, page: Int) = ehRequest(EhUrl.apiUrl, EhUrl.referer, EhUrl.origin) {
jsonBody {
put("method", "gtoken")
put("pagelist", JSONArray().put(JSONArray().put(gid).put(gtoken).put(page + 1)))
}
}.executeAndParsingWith(GalleryTokenApiParser::parse)
/**
* @param image Must be jpeg
*/
suspend fun imageSearch(image: File, uss: Boolean, osc: Boolean) = ehRequest(EhUrl.imageSearchUrl, EhUrl.referer, EhUrl.origin) {
multipartBody {
setType(MultipartBody.FORM)
addFormDataPart("sfile", "a.jpg", image.asRequestBody(MEDIA_TYPE_JPEG))
if (uss) addFormDataPart("fs_similar", "on")
if (osc) addFormDataPart("fs_covers", "on")
addFormDataPart("f_sfile", "File Search")
}
}.executeAndParsingWith(GalleryListParser::parse).apply { fillGalleryList(galleryInfoList, EhUrl.imageSearchUrl, true) }
private suspend fun fillGalleryList(list: MutableList<GalleryInfo>, url: String, filter: Boolean) {
// Filter title and uploader
if (filter) list.removeAll { EhFilter.filterTitle(it) || EhFilter.filterUploader(it) }
var hasTags = false
var hasPages = false
var hasRated = false
for (gi in list) {
if (gi.simpleTags != null) {
hasTags = true
}
if (gi.pages != 0) {
hasPages = true
}
if (gi.rated) {
hasRated = true
}
}
val needApi = filter && EhFilter.needTags() && !hasTags || Settings.showGalleryPages && !hasPages || hasRated
if (needApi) fillGalleryListByApi(list, url)
// Filter tag, thumbnail mode need filter uploader again
if (filter) list.removeAll { EhFilter.filterUploader(it) || EhFilter.filterTag(it) || EhFilter.filterTagNamespace(it) }
}
suspend fun addFavoritesRange(gidArray: LongArray, tokenArray: Array<String?>, dstCat: Int) {
require(gidArray.size == tokenArray.size)
gidArray.forEachIndexed { index, gid -> addFavorites(gid, tokenArray[index], dstCat, null) }
}
}
@@ -1,153 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import android.util.Log
import arrow.core.memoize
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.dao.Filter
private val regex = { p: Filter -> Regex(p.text!!) }.memoize()
object EhFilter {
val titleFilterList = mutableListOf<Filter>()
val uploaderFilterList = mutableListOf<Filter>()
val tagFilterList = mutableListOf<Filter>()
val tagNamespaceFilterList = mutableListOf<Filter>()
val commenterFilterList = mutableListOf<Filter>()
val commentFilterList = mutableListOf<Filter>()
const val MODE_TITLE = 0
const val MODE_UPLOADER = 1
const val MODE_TAG = 2
const val MODE_TAG_NAMESPACE = 3
const val MODE_COMMENTER = 4
const val MODE_COMMENT = 5
private const val TAG = "EhFilter"
init { EhDB.allFilter.forEach(::memorizeFilter) }
private fun memorizeFilter(filter: Filter) {
when (filter.mode) {
MODE_TITLE -> {
filter.text = filter.text!!.lowercase()
titleFilterList.add(filter)
}
MODE_TAG -> {
filter.text = filter.text!!.lowercase()
tagFilterList.add(filter)
}
MODE_TAG_NAMESPACE -> {
filter.text = filter.text!!.lowercase()
tagNamespaceFilterList.add(filter)
}
MODE_UPLOADER -> uploaderFilterList.add(filter)
MODE_COMMENTER -> commenterFilterList.add(filter)
MODE_COMMENT -> commentFilterList.add(filter)
else -> Log.d(TAG, "Unknown mode: " + filter.mode)
}
}
@Synchronized
fun addFilter(filter: Filter): Boolean {
filter.enable = true
if (!EhDB.addFilter(filter)) return false
memorizeFilter(filter)
return true
}
@Synchronized
fun triggerFilter(filter: Filter) {
EhDB.triggerFilter(filter)
}
@Synchronized
fun deleteFilter(filter: Filter) {
EhDB.deleteFilter(filter)
when (filter.mode) {
MODE_TITLE -> titleFilterList.remove(filter)
MODE_TAG -> tagFilterList.remove(filter)
MODE_TAG_NAMESPACE -> tagNamespaceFilterList.remove(filter)
MODE_UPLOADER -> uploaderFilterList.remove(filter)
MODE_COMMENTER -> commenterFilterList.remove(filter)
MODE_COMMENT -> commentFilterList.remove(filter)
else -> Log.d(TAG, "Unknown mode: " + filter.mode)
}
}
@Synchronized
fun needTags(): Boolean {
return 0 != tagFilterList.size || 0 != tagNamespaceFilterList.size
}
@Synchronized
fun filterTitle(info: GalleryInfo): Boolean {
val title = info.title ?: return false
return titleFilterList.any { it.enable!! && it.text!! in title.lowercase() }
}
@Synchronized
fun filterUploader(info: GalleryInfo): Boolean {
val uploader = info.uploader ?: return false
return uploaderFilterList.any { it.enable!! && it.text == uploader }
}
private fun spiltTag(tag: String) = tag.run {
val index = indexOf(':')
if (index < 0) null to this else substring(0, index) to substring(index + 1)
}
private fun matchTag(tag: String, filter: String): Boolean {
val (tagNamespace, tagName) = spiltTag(tag)
val (filterNamespace, filterName) = spiltTag(filter)
return if (null != tagNamespace && null != filterNamespace && tagNamespace != filterNamespace) {
false
} else {
tagName == filterName
}
}
@Synchronized
fun filterTag(info: GalleryInfo): Boolean {
val tags = info.simpleTags ?: return false
return tags.any { tag -> tagFilterList.any { it.enable!! && matchTag(tag, it.text!!) } }
}
private fun matchTagNamespace(tag: String, filter: String): Boolean {
val (nameSpace, _) = spiltTag(tag)
return nameSpace == filter
}
@Synchronized
fun filterTagNamespace(info: GalleryInfo): Boolean {
val tags = info.simpleTags ?: return false
return tags.any { tag -> tagNamespaceFilterList.any { it.enable!! && matchTagNamespace(tag, it.text!!) } }
}
@Synchronized
fun filterCommenter(commenter: String): Boolean {
return commenterFilterList.any { it.enable!! && it.text == commenter }
}
@Synchronized
fun filterComment(comment: String): Boolean {
return commentFilterList.any { it.enable!! && regex(it).containsMatchIn(comment) }
}
}
@@ -1,69 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import com.hippo.ehviewer.EhApplication.Companion.nonCacheOkHttpClient
import com.hippo.ehviewer.EhApplication.Companion.okHttpClient
import okhttp3.FormBody
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.executeAsync
import org.json.JSONArray
import org.json.JSONObject
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
inline fun ehRequest(url: String, referer: String? = null, origin: String? = null, builder: Request.Builder.() -> Unit = {}) = Request.Builder().url(url).apply {
addHeader("User-Agent", CHROME_USER_AGENT)
addHeader("Accept", CHROME_ACCEPT)
addHeader("Accept-Language", CHROME_ACCEPT_LANGUAGE)
referer?.let { addHeader("Referer", it) }
origin?.let { addHeader("Origin", it) }
}.apply(builder).build()
inline fun Request.Builder.formBody(builder: FormBody.Builder.() -> Unit) = post(FormBody.Builder().apply(builder).build())
inline fun Request.Builder.multipartBody(builder: MultipartBody.Builder.() -> Unit) = post(MultipartBody.Builder().apply(builder).build())
val MEDIA_TYPE_JSON: MediaType = "application/json; charset=utf-8".toMediaType()
inline fun JSONObject.array(name: String, builder: JSONArray.() -> Unit): JSONObject = put(name, JSONArray().apply(builder))
fun jsonArrayOf(vararg element: Any?) = JSONArray().apply { element.forEach { put(it) } } // Should ensure it is inlined
inline fun Request.Builder.jsonBody(builder: JSONObject.() -> Unit) = post(JSONObject().apply(builder).toString().toRequestBody(MEDIA_TYPE_JSON))
suspend inline fun <R> Request.execute(block: Response.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return okHttpClient.newCall(this).executeAsync().use(block)
}
suspend inline fun <R> Request.executeNonCache(block: Response.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return nonCacheOkHttpClient.newCall(this).executeAsync().use(block)
}
const val CHROME_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
const val CHROME_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
const val CHROME_ACCEPT_LANGUAGE = "en-US,en;q=0.5"
@@ -1,72 +0,0 @@
/*
* Copyright 2022 Tarsin Norbin
*
* This file is part of EhViewer
*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.hippo.ehviewer.client
import android.util.Log
import java.net.InetAddress
import java.net.Socket
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
object EhSSLSocketFactory : SSLSocketFactory() {
private val sslSocketFactory = getDefault() as SSLSocketFactory
override fun getDefaultCipherSuites(): Array<String> {
return sslSocketFactory.defaultCipherSuites
}
override fun getSupportedCipherSuites(): Array<String> {
return sslSocketFactory.supportedCipherSuites
}
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
val address = s.inetAddress.hostAddress.takeIf { EhDns.isInHosts(host) }
val socket = sslSocketFactory.createSocket(s, address ?: host, port, autoClose) as SSLSocket
val sslSession = socket.session
Log.d(
"EhSSLSocketFactory",
"Host: " + host + " Address: " + address + " Protocol:" + sslSession.protocol + " CipherSuite:" + sslSession.cipherSuite,
)
return socket
}
override fun createSocket(host: String, port: Int): Socket {
return sslSocketFactory.createSocket(host, port)
}
override fun createSocket(
host: String,
port: Int,
localHost: InetAddress,
localPort: Int,
): Socket {
return sslSocketFactory.createSocket(host, port, localHost, localPort)
}
override fun createSocket(host: InetAddress, port: Int): Socket {
return sslSocketFactory.createSocket(host, port)
}
override fun createSocket(
address: InetAddress,
port: Int,
localAddress: InetAddress,
localPort: Int,
): Socket {
return sslSocketFactory.createSocket(address, port, localAddress, localPort)
}
}
@@ -1,285 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import android.content.Context
import com.hippo.ehviewer.AppConfig
import com.hippo.ehviewer.EhApplication
import com.hippo.ehviewer.EhApplication.Companion.nonCacheOkHttpClient
import com.hippo.ehviewer.R
import com.hippo.ehviewer.yorozuya.FileUtils
import com.hippo.ehviewer.yorozuya.copyToFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import moe.tarsin.coroutines.runSuspendCatching
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.executeAsync
import okio.HashingSink.Companion.sha1
import okio.blackholeSink
import okio.buffer
import okio.source
import org.json.JSONObject
import java.io.File
import java.nio.charset.StandardCharsets
private typealias TagGroup = Map<String, String>
private typealias TagGroups = Map<String, TagGroup>
object EhTagDatabase : CoroutineScope {
private const val NAMESPACE_PREFIX = "n"
private lateinit var tagGroups: TagGroups
private val updateLock = Mutex()
private val dbLock = Mutex()
override val coroutineContext = Dispatchers.IO + Job()
fun isInitialized(): Boolean {
return this::tagGroups.isInitialized
}
private fun JSONObject.toTagGroups(): TagGroups =
keys().asSequence().associateWith { getJSONObject(it).toTagGroup() }
private fun JSONObject.toTagGroup(): TagGroup =
keys().asSequence().associateWith { getString(it) }
fun getTranslation(prefix: String? = NAMESPACE_PREFIX, tag: String?): String? {
return tagGroups[prefix]?.get(tag)?.trim()?.takeIf { it.isNotEmpty() }
}
private fun internalSuggestFlow(
tags: Map<String, String>,
keyword: String,
translate: Boolean,
exactly: Boolean,
): Flow<Pair<String?, String>> = flow {
if (exactly) {
tags[keyword]?.let {
emit(Pair(it.takeIf { translate }, keyword))
}
} else {
if (translate) {
tags.forEach { (tag, hint) ->
if (tag != keyword &&
(tag.containsIgnoreSpace(keyword) || hint.containsIgnoreSpace(keyword))
) {
emit(Pair(hint, tag))
}
}
} else {
tags.keys.forEach { tag ->
if (tag != keyword && tag.containsIgnoreSpace(keyword)) {
emit(Pair(null, tag))
}
}
}
}
}
// Construct a cold flow for tag database suggestions
fun suggestFlow(
keyword: String,
translate: Boolean,
exactly: Boolean = false,
): Flow<Pair<String?, String>> = flow {
val keywordPrefix = keyword.substringBefore(':')
val keywordTag = keyword.drop(keywordPrefix.length + 1)
val prefix = namespaceToPrefix(keywordPrefix) ?: keywordPrefix
val tags = tagGroups[prefix.takeIf { keywordTag.isNotEmpty() && it != NAMESPACE_PREFIX }]
tags?.let {
internalSuggestFlow(it, keywordTag, translate, exactly).collect { (hint, tag) ->
emit(Pair(hint, "$prefix:$tag"))
}
} ?: tagGroups.forEach { (prefix, tags) ->
if (prefix != NAMESPACE_PREFIX) {
internalSuggestFlow(tags, keyword, translate, exactly).collect { (hint, tag) ->
emit(Pair(hint, "$prefix:$tag"))
}
} else {
internalSuggestFlow(tags, keyword, translate, exactly).collect { (hint, tag) ->
emit(Pair(hint, "$tag:"))
}
}
}
}
private fun String.removeSpace(): String = replace(" ", "")
private fun String.containsIgnoreSpace(other: String, ignoreCase: Boolean = true): Boolean =
removeSpace().contains(other.removeSpace(), ignoreCase)
private val NAMESPACE_TO_PREFIX = HashMap<String, String>().also {
it["artist"] = "a"
it["cosplayer"] = "cos"
it["character"] = "c"
it["female"] = "f"
it["group"] = "g"
it["language"] = "l"
it["male"] = "m"
it["mixed"] = "x"
it["other"] = "o"
it["parody"] = "p"
it["reclass"] = "r"
}
@JvmStatic
fun namespaceToPrefix(namespace: String): String? {
return NAMESPACE_TO_PREFIX[namespace]
}
private fun getMetadata(context: Context): Array<String>? {
return context.resources.getStringArray(R.array.tag_translation_metadata)
.takeIf { it.size == 4 }
}
fun isTranslatable(context: Context): Boolean {
return context.resources.getBoolean(R.bool.tag_translatable)
}
private fun getFileContent(file: File): String? {
return runCatching {
file.source().buffer().use { it.readString(StandardCharsets.UTF_8) }
}.getOrNull()
}
private fun getFileSha1(file: File): String? {
return runCatching {
file.source().buffer().use { source ->
sha1(blackholeSink()).use {
source.readAll(it)
it.hash.hex()
}
}
}.getOrNull()
}
private fun checkData(sha1: String?, data: File): Boolean {
return sha1 != null && sha1 == getFileSha1(data)
}
private suspend fun save(client: OkHttpClient, url: String, file: File): Boolean {
val request: Request = Request.Builder().url(url).build()
val call = client.newCall(request)
runCatching {
call.executeAsync().use { response ->
if (!response.isSuccessful) {
return false
}
response.body.use {
it.copyToFile(file)
}
return true
}
}.onFailure {
file.delete()
it.printStackTrace()
}
return false
}
suspend fun update() {
updateLock.withLock {
updateInternal()
}
}
private suspend fun issueUpdateInMemoryData() {
dbLock.withLock {
getMetadata(EhApplication.application)?.let { urls ->
val dataName = urls[2]
val dir = AppConfig.getFilesDir("tag-translations")
val dataFile = File(dir, dataName).takeIf { it.exists() } ?: return
runSuspendCatching {
tagGroups = JSONObject(dataFile.source().buffer().readString(StandardCharsets.UTF_8)).toTagGroups()
}.onFailure {
it.printStackTrace()
}
}
}
}
init {
launch {
issueUpdateInMemoryData()
}
}
private suspend fun updateInternal() {
val urls = getMetadata(EhApplication.application)
urls?.let {
val sha1Name = urls[0]
val sha1Url = urls[1]
val dataName = urls[2]
val dataUrl = urls[3]
val dir = AppConfig.getFilesDir("tag-translations")
checkNotNull(dir)
val sha1File = File(dir, sha1Name)
val dataFile = File(dir, dataName)
runCatching {
// Check current sha1 and current data
val sha1 = getFileContent(sha1File)
if (!checkData(sha1, dataFile)) {
FileUtils.delete(sha1File)
FileUtils.delete(dataFile)
}
val client = nonCacheOkHttpClient
// Save new sha1
val tempSha1File = File(dir, "$sha1Name.tmp")
check(save(client, sha1Url, tempSha1File))
val tempSha1 = getFileContent(tempSha1File)
// Check new sha1 and current sha1
if (tempSha1 == sha1) {
// The data is the same
FileUtils.delete(tempSha1File)
return@runCatching
}
// Save new data
val tempDataFile = File(dir, "$dataName.tmp")
check(save(client, dataUrl, tempDataFile))
// Check new sha1 and new data
if (!checkData(tempSha1, tempDataFile)) {
FileUtils.delete(tempSha1File)
FileUtils.delete(tempDataFile)
return@runCatching
}
// Replace current sha1 and current data with new sha1 and new data
FileUtils.delete(sha1File)
FileUtils.delete(dataFile)
tempSha1File.renameTo(sha1File)
tempDataFile.renameTo(dataFile)
// Read new EhTagDatabase
issueUpdateInMemoryData()
}.onFailure {
it.printStackTrace()
}
}
}
}
@@ -1,168 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client
import android.text.TextUtils
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.GalleryInfo
import java.util.regex.Pattern
object EhUtils {
const val NONE = -1 // Use it for homepage
const val MISC = 0x1
const val DOUJINSHI = 0x2
const val MANGA = 0x4
const val ARTIST_CG = 0x8
const val GAME_CG = 0x10
const val IMAGE_SET = 0x20
const val COSPLAY = 0x40
const val ASIAN_PORN = 0x80
const val NON_H = 0x100
const val WESTERN = 0x200
const val ALL_CATEGORY = 0x3ff
const val PRIVATE = 0x400
const val UNKNOWN = 0x800
// https://youtrack.jetbrains.com/issue/KT-4749
private const val BG_COLOR_DOUJINSHI = 0xfff44336u
private const val BG_COLOR_MANGA = 0xffff9800u
private const val BG_COLOR_ARTIST_CG = 0xfffbc02du
private const val BG_COLOR_GAME_CG = 0xff4caf50u
private const val BG_COLOR_WESTERN = 0xff8bc34au
private const val BG_COLOR_NON_H = 0xff2196f3u
private const val BG_COLOR_IMAGE_SET = 0xff3f51b5u
private const val BG_COLOR_COSPLAY = 0xff9c27b0u
private const val BG_COLOR_ASIAN_PORN = 0xff9575cdu
private const val BG_COLOR_MISC = 0xfff06292u
private const val BG_COLOR_UNKNOWN = 0xff000000u
// Remove [XXX], (XXX), {XXX}, ~XXX~ stuff
private val PATTERN_TITLE_PREFIX = Pattern.compile(
"^(?:\\([^)]*\\)|\\[[^]]*]|\\{[^}]*\\}|~[^~]*~|\\s+)*",
)
// Remove [XXX], (XXX), {XXX}, ~XXX~ stuff and something like ch. 1-23
private val PATTERN_TITLE_SUFFIX = Pattern.compile(
"(?:\\s+ch.[\\s\\d-]+)?(?:\\([^)]*\\)|\\[[^]]*]|\\{[^}]*\\}|~[^~]*~|\\s+)*$",
Pattern.CASE_INSENSITIVE,
)
private val CATEGORY_VALUES = hashMapOf(
MISC to arrayOf("misc"),
DOUJINSHI to arrayOf("doujinshi"),
MANGA to arrayOf("manga"),
ARTIST_CG to arrayOf("artistcg", "Artist CG Sets", "Artist CG"),
GAME_CG to arrayOf("gamecg", "Game CG Sets", "Game CG"),
IMAGE_SET to arrayOf("imageset", "Image Sets", "Image Set"),
COSPLAY to arrayOf("cosplay"),
ASIAN_PORN to arrayOf("asianporn", "Asian Porn"),
NON_H to arrayOf("non-h"),
WESTERN to arrayOf("western"),
PRIVATE to arrayOf("private"),
UNKNOWN to arrayOf("unknown"),
)
private val CATEGORY_STRINGS = CATEGORY_VALUES.entries.map { (k, v) -> v to k }
val isExHentai: Boolean
get() = Settings.gallerySite == EhUrl.SITE_EX
@JvmStatic
fun getCategory(type: String?): Int {
for (entry in CATEGORY_STRINGS) {
for (str in entry.first)
if (str.equals(type, ignoreCase = true)) {
return entry.second
}
}
return UNKNOWN
}
fun getCategory(type: Int): String {
return CATEGORY_VALUES.getOrDefault(type, CATEGORY_VALUES[UNKNOWN])!![0]
}
fun getCategoryColor(category: Int): Int {
return when (category) {
DOUJINSHI -> BG_COLOR_DOUJINSHI
MANGA -> BG_COLOR_MANGA
ARTIST_CG -> BG_COLOR_ARTIST_CG
GAME_CG -> BG_COLOR_GAME_CG
WESTERN -> BG_COLOR_WESTERN
NON_H -> BG_COLOR_NON_H
IMAGE_SET -> BG_COLOR_IMAGE_SET
COSPLAY -> BG_COLOR_COSPLAY
ASIAN_PORN -> BG_COLOR_ASIAN_PORN
MISC -> BG_COLOR_MISC
else -> BG_COLOR_UNKNOWN
}.toInt()
}
fun signOut() {
EhCookieStore.signOut()
Settings.putAvatar(null)
Settings.putDisplayName(null)
Settings.putGallerySite(EhUrl.SITE_E)
Settings.putNeedSignIn(true)
Settings.putSelectSite(true)
}
fun needSignedIn(): Boolean {
return Settings.needSignIn
}
@JvmStatic
fun getSuitableTitle(gi: GalleryInfo): String {
return if (Settings.showJpnTitle) {
if (TextUtils.isEmpty(gi.titleJpn)) gi.title else gi.titleJpn
} else {
if (TextUtils.isEmpty(gi.title)) gi.titleJpn else gi.title
}.orEmpty()
}
fun extractTitle(fullTitle: String?): String? {
var title: String = fullTitle ?: return null
title = PATTERN_TITLE_PREFIX.matcher(title).replaceFirst("")
title = PATTERN_TITLE_SUFFIX.matcher(title).replaceFirst("")
// Sometimes title is combined by romaji and english translation.
// Only need romaji.
// TODO But not sure every '|' means that
val index = title.indexOf('|')
if (index >= 0) {
title = title.substring(0, index)
}
return title.ifEmpty { null }
}
@JvmStatic
fun handleThumbUrlResolution(url: String?): String? {
if (null == url) {
return null
}
val resolution = when (Settings.thumbResolution) {
0 -> return url
1 -> "250"
2 -> "300"
else -> return url
}
val index1 = url.lastIndexOf('_')
val index2 = url.lastIndexOf('.')
return if (index1 >= 0 && index2 >= 0 && index1 < index2) {
url.substring(0, index1 + 1) + resolution + url.substring(index2)
} else {
url
}
}
}
@@ -1,25 +0,0 @@
package com.hippo.ehviewer.client.data
interface AbstractGalleryInfo {
var gid: Long
var token: String?
var title: String?
var titleJpn: String?
var thumbKey: String?
var category: Int
var posted: String?
var uploader: String?
var disowned: Boolean
var rating: Float
var rated: Boolean
var simpleTags: Array<String>?
var pages: Int
var thumbWidth: Int
var thumbHeight: Int
var spanSize: Int
var spanIndex: Int
var spanGroupIndex: Int
var simpleLanguage: String?
var favoriteSlot: Int
var favoriteName: String?
}
@@ -1,58 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.data
import android.os.Parcelable
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.network.UrlBuilder
import com.hippo.ehviewer.util.encodeUTF8
import kotlinx.parcelize.Parcelize
@Parcelize
class FavListUrlBuilder(
private var mPrev: String? = null,
private var mNext: String? = null,
var jumpTo: String? = null,
var keyword: String? = null,
var favCat: Int = FAV_CAT_ALL,
) : Parcelable {
fun setIndex(index: String?, isNext: Boolean) {
mNext = index.takeIf { isNext }
mPrev = index.takeUnless { isNext }
}
fun build(): String {
val ub = UrlBuilder(EhUrl.favoritesUrl)
if (isValidFavCat(favCat)) {
ub.addQuery("favcat", favCat.toString())
} else if (favCat == FAV_CAT_ALL) {
ub.addQuery("favcat", "all")
}
keyword?.takeIf { it.isNotBlank() }?.let { ub.addQuery("f_search", encodeUTF8(it)) }
mPrev?.takeIf { it.isNotEmpty() }?.let { ub.addQuery("prev", it) }
mNext?.takeIf { it.isNotEmpty() }?.let { ub.addQuery("next", it) }
jumpTo?.takeIf { it.isNotEmpty() }?.let { ub.addQuery("seek", it) }
return ub.build()
}
companion object {
const val FAV_CAT_ALL = -1
const val FAV_CAT_LOCAL = -2
fun isValidFavCat(favCat: Int): Boolean {
return favCat in 0..9
}
}
}
@@ -1,50 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.data
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
class GalleryComment(
// 0 for uploader comment. can't vote
@JvmField
var id: Long = 0,
@JvmField
var score: Int = 0,
@JvmField
var editable: Boolean = false,
@JvmField
var voteUpAble: Boolean = false,
@JvmField
var voteUpEd: Boolean = false,
@JvmField
var voteDownAble: Boolean = false,
@JvmField
var voteDownEd: Boolean = false,
@JvmField
var uploader: Boolean = false,
@JvmField
var voteState: String? = null,
@JvmField
var time: Long = 0,
@JvmField
var user: String? = null,
@JvmField
var comment: String? = null,
@JvmField
var lastEdited: Long = 0,
) : Parcelable
@@ -1,131 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.data
import android.os.Parcelable
import java.util.regex.Pattern
interface GalleryInfo : AbstractGalleryInfo, Parcelable {
fun generateSLang() {
simpleLanguage = simpleTags?.let { generateSLangFromTags(it) }
?: title?.let { generateSLangFromTitle(it) }
}
private fun generateSLangFromTags(simpleTags: Array<String>): String? {
for (tag in simpleTags) {
for (i in S_LANGS.indices) {
if (S_LANG_TAGS[i] == tag) {
return S_LANGS[i]
}
}
}
return null
}
private fun generateSLangFromTitle(title: String): String? {
for (i in S_LANGS.indices) {
if (S_LANG_PATTERNS[i].matcher(title).find()) {
return S_LANGS[i]
}
}
return null
}
companion object {
/**
* ISO 639-1
*/
const val S_LANG_JA = "JA"
const val S_LANG_EN = "EN"
const val S_LANG_ZH = "ZH"
const val S_LANG_NL = "NL"
const val S_LANG_FR = "FR"
const val S_LANG_DE = "DE"
const val S_LANG_HU = "HU"
const val S_LANG_IT = "IT"
const val S_LANG_KO = "KO"
const val S_LANG_PL = "PL"
const val S_LANG_PT = "PT"
const val S_LANG_RU = "RU"
const val S_LANG_ES = "ES"
const val S_LANG_TH = "TH"
const val S_LANG_VI = "VI"
val S_LANGS = arrayOf(
S_LANG_EN,
S_LANG_ZH,
S_LANG_ES,
S_LANG_KO,
S_LANG_RU,
S_LANG_FR,
S_LANG_PT,
S_LANG_TH,
S_LANG_DE,
S_LANG_IT,
S_LANG_VI,
S_LANG_PL,
S_LANG_HU,
S_LANG_NL,
)
val S_LANG_PATTERNS = arrayOf(
Pattern.compile(
"[(\\[]eng(?:lish)?[)\\]]|英訳",
Pattern.CASE_INSENSITIVE,
), // [((\[]ch(?:inese)?[))\]]|[汉漢]化|中[国國][语語]|中文|中国翻訳
Pattern.compile(
"[(\uFF08\\[]ch(?:inese)?[)\uFF09\\]]|[汉漢]化|中[国國][语語]|中文|中国翻訳",
Pattern.CASE_INSENSITIVE,
),
Pattern.compile(
"[(\\[]spanish[)\\]]|[(\\[]Español[)\\]]|スペイン翻訳",
Pattern.CASE_INSENSITIVE,
),
Pattern.compile("[(\\[]korean?[)\\]]|韓国翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile("[(\\[]rus(?:sian)?[)\\]]|ロシア翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile("[(\\[]fr(?:ench)?[)\\]]|フランス翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile("[(\\[]portuguese|ポルトガル翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile(
"[(\\[]thai(?: ภาษาไทย)?[)\\]]|แปลไทย|タイ翻訳",
Pattern.CASE_INSENSITIVE,
),
Pattern.compile("[(\\[]german[)\\]]|ドイツ翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile("[(\\[]italiano?[)\\]]|イタリア翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile(
"[(\\[]vietnamese(?: Tiếng Việt)?[)\\]]|ベトナム翻訳",
Pattern.CASE_INSENSITIVE,
),
Pattern.compile("[(\\[]polish[)\\]]|ポーランド翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile("[(\\[]hun(?:garian)?[)\\]]|ハンガリー翻訳", Pattern.CASE_INSENSITIVE),
Pattern.compile("[(\\[]dutch[)\\]]|オランダ翻訳", Pattern.CASE_INSENSITIVE),
)
val S_LANG_TAGS = arrayOf(
"language:english",
"language:chinese",
"language:spanish",
"language:korean",
"language:russian",
"language:french",
"language:portuguese",
"language:thai",
"language:german",
"language:italian",
"language:vietnamese",
"language:polish",
"language:hungarian",
"language:dutch",
)
}
}
@@ -1,407 +0,0 @@
/*
* Copyright (C) 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.data
import android.os.Parcelable
import android.text.TextUtils
import androidx.annotation.IntDef
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.dao.QuickSearch
import com.hippo.ehviewer.network.UrlBuilder
import com.hippo.ehviewer.ui.legacy.AdvanceSearchTable
import com.hippo.ehviewer.util.encodeUTF8
import com.hippo.ehviewer.yorozuya.NumberUtils
import com.hippo.ehviewer.yorozuya.StringUtils
import kotlinx.parcelize.Parcelize
import java.io.UnsupportedEncodingException
import java.net.URLDecoder
@Parcelize
data class ListUrlBuilder(
@get:Mode @Mode
var mode: Int = MODE_NORMAL,
private var mPrev: String? = null,
private var mNext: String? = null,
private var mJumpTo: String? = null,
var category: Int = EhUtils.NONE,
private var mKeyword: String? = null,
private var mSHash: String? = null,
var advanceSearch: Int = -1,
var minRating: Int = -1,
var pageFrom: Int = -1,
var pageTo: Int = -1,
var imagePath: String? = null,
var isUseSimilarityScan: Boolean = false,
var isOnlySearchCovers: Boolean = false,
) : Parcelable {
fun reset() {
mode = MODE_NORMAL
mPrev = null
mNext = null
mJumpTo = null
this.category = EhUtils.NONE
mKeyword = null
advanceSearch = -1
minRating = -1
pageFrom = -1
pageTo = -1
imagePath = null
isUseSimilarityScan = false
isOnlySearchCovers = false
mSHash = null
}
fun setIndex(index: String?, isNext: Boolean = true) {
mNext = index?.takeIf { isNext }
mPrev = index?.takeUnless { isNext }
}
fun setJumpTo(jumpTo: String?) {
mJumpTo = jumpTo
}
var keyword: String?
get() = if (MODE_UPLOADER == mode) "uploader:$mKeyword" else mKeyword
set(keyword) {
mKeyword = keyword
}
fun set(q: QuickSearch) {
mode = q.mode
this.category = q.category
mKeyword = q.keyword
advanceSearch = q.advanceSearch
minRating = q.minRating
pageFrom = q.pageFrom
pageTo = q.pageTo
imagePath = null
isUseSimilarityScan = false
isOnlySearchCovers = false
}
fun toQuickSearch(): QuickSearch {
val q = QuickSearch()
q.mode = mode
q.category = this.category
q.keyword = mKeyword
q.advanceSearch = advanceSearch
q.minRating = minRating
q.pageFrom = pageFrom
q.pageTo = pageTo
return q
}
fun equalsQuickSearch(q: QuickSearch?): Boolean {
if (null == q) {
return false
}
if (q.mode != mode) {
return false
}
if (q.category != this.category) {
return false
}
if (!StringUtils.equals(q.keyword, mKeyword)) {
return false
}
if (q.advanceSearch != advanceSearch) {
return false
}
if (q.minRating != minRating) {
return false
}
return if (q.pageFrom != pageFrom) {
false
} else {
q.pageTo == pageTo
}
}
/**
* @param query xxx=yyy&mmm=nnn
*/
// TODO page
fun setQuery(query: String?) {
reset()
if (TextUtils.isEmpty(query)) {
return
}
val queries = StringUtils.split(query, '&')
var category = 0
var keyword: String? = null
var enableAdvanceSearch = false
var advanceSearch = 0
var enableMinRating = false
var minRating = -1
var enablePage = false
var pageFrom = -1
var pageTo = -1
for (str in queries) {
val index = str.indexOf('=')
if (index < 0) {
continue
}
val key = str.substring(0, index)
val value = str.substring(index + 1)
when (key) {
"f_cats" -> {
val cats = NumberUtils.parseIntSafely(value, EhUtils.ALL_CATEGORY)
category = category or (cats.inv() and EhUtils.ALL_CATEGORY)
}
"f_doujinshi" -> if ("1" == value) {
category = category or EhUtils.DOUJINSHI
}
"f_manga" -> if ("1" == value) {
category = category or EhUtils.MANGA
}
"f_artistcg" -> if ("1" == value) {
category = category or EhUtils.ARTIST_CG
}
"f_gamecg" -> if ("1" == value) {
category = category or EhUtils.GAME_CG
}
"f_western" -> if ("1" == value) {
category = category or EhUtils.WESTERN
}
"f_non-h" -> if ("1" == value) {
category = category or EhUtils.NON_H
}
"f_imageset" -> if ("1" == value) {
category = category or EhUtils.IMAGE_SET
}
"f_cosplay" -> if ("1" == value) {
category = category or EhUtils.COSPLAY
}
"f_asianporn" -> if ("1" == value) {
category = category or EhUtils.ASIAN_PORN
}
"f_misc" -> if ("1" == value) {
category = category or EhUtils.MISC
}
"f_search" -> try {
keyword = URLDecoder.decode(value, "utf-8")
} catch (e: UnsupportedEncodingException) {
// Ignore
} catch (_: IllegalArgumentException) {
}
"advsearch" -> if ("1" == value) {
enableAdvanceSearch = true
}
"f_sh" -> if ("on" == value) {
advanceSearch = advanceSearch or AdvanceSearchTable.SH
}
"f_sto" -> if ("on" == value) {
advanceSearch = advanceSearch or AdvanceSearchTable.STO
}
"f_sfl" -> if ("on" == value) {
advanceSearch = advanceSearch or AdvanceSearchTable.SFL
}
"f_sfu" -> if ("on" == value) {
advanceSearch = advanceSearch or AdvanceSearchTable.SFU
}
"f_sft" -> if ("on" == value) {
advanceSearch = advanceSearch or AdvanceSearchTable.SFT
}
"f_sr" -> if ("on" == value) {
enableMinRating = true
}
"f_srdd" -> minRating = NumberUtils.parseIntSafely(value, -1)
"f_sp" -> if ("on" == value) {
enablePage = true
}
"f_spf" -> pageFrom = NumberUtils.parseIntSafely(value, -1)
"f_spt" -> pageTo = NumberUtils.parseIntSafely(value, -1)
"f_shash" -> mSHash = value
}
}
this.category = category
mKeyword = keyword
if (enableAdvanceSearch) {
this.advanceSearch = advanceSearch
if (enableMinRating) {
this.minRating = minRating
} else {
this.minRating = -1
}
if (enablePage) {
this.pageFrom = pageFrom
this.pageTo = pageTo
} else {
this.pageFrom = -1
this.pageTo = -1
}
} else {
this.advanceSearch = -1
}
}
fun build(): String {
return when (mode) {
MODE_NORMAL, MODE_SUBSCRIPTION -> {
val url: String = if (mode == MODE_NORMAL) {
EhUrl.host
} else {
EhUrl.watchedUrl
}
val ub = UrlBuilder(url)
if (this.category != EhUtils.NONE) {
ub.addQuery("f_cats", category.inv() and EhUtils.ALL_CATEGORY)
}
mSHash?.let {
ub.addQuery("f_shash", it)
}
mJumpTo?.let {
ub.addQuery("seek", it)
}
mPrev?.let {
ub.addQuery("prev", it)
}
mNext?.let {
ub.addQuery("next", it)
}
// Search key
// the settings of ub:UrlBuilder may be overwritten by following Advance search
StringUtils.split(mKeyword, '|')?.forEachIndexed { idx, keyword ->
val keyword = keyword.trim { it <= ' ' }
when (idx) {
0 -> keyword.takeIf { it.isNotEmpty() }?.let { ub.addQuery("f_search", encodeUTF8(it)) }
else -> keyword.indexOf(':').takeIf { it >= 0 }?.run {
val key = keyword.substring(0, this).trim { it <= ' ' }
val value = keyword.substring(this + 1).trim { it <= ' ' }
ub.addQuery(key, encodeUTF8(value))
}
}
}
// Advance search
if (advanceSearch != -1) {
ub.addQuery("advsearch", "1")
if (advanceSearch and AdvanceSearchTable.SH != 0) ub.addQuery("f_sh", "on")
if (advanceSearch and AdvanceSearchTable.STO != 0) ub.addQuery("f_sto", "on")
if (advanceSearch and AdvanceSearchTable.SFL != 0) ub.addQuery("f_sfl", "on")
if (advanceSearch and AdvanceSearchTable.SFU != 0) ub.addQuery("f_sfu", "on")
if (advanceSearch and AdvanceSearchTable.SFT != 0) ub.addQuery("f_sft", "on")
// Set min star
if (minRating != -1) {
ub.addQuery("f_sr", "on")
ub.addQuery("f_srdd", minRating)
}
// Pages
if (pageFrom != -1 || pageTo != -1) {
ub.addQuery("f_sp", "on")
ub.addQuery("f_spf", if (pageFrom != -1) pageFrom.toString() else "")
ub.addQuery("f_spt", if (pageTo != -1) pageTo.toString() else "")
}
}
ub.build()
}
MODE_UPLOADER -> {
val sb = StringBuilder(EhUrl.host)
mKeyword?.let {
sb.append("uploader/")
sb.append(encodeUTF8(it))
}
mPrev?.let {
sb.append("?prev=").append(it)
}
mNext?.let {
sb.append("?next=").append(it)
}
mJumpTo?.let {
sb.append("&seek=").append(it)
}
sb.toString()
}
MODE_TAG -> {
val sb = StringBuilder(EhUrl.host)
mKeyword?.let {
sb.append("tag/")
sb.append(encodeUTF8(it))
}
mPrev?.let {
sb.append("?prev=").append(it)
}
mNext?.let {
sb.append("?next=").append(it)
}
mJumpTo?.let {
sb.append("&seek=").append(it)
}
sb.toString()
}
MODE_WHATS_HOT -> EhUrl.popularUrl
MODE_IMAGE_SEARCH -> EhUrl.imageSearchUrl
MODE_TOPLIST -> {
val sb = StringBuilder(EhUrl.HOST_E)
sb.append("toplist.php?tl=")
mKeyword.orEmpty().let {
sb.append(encodeUTF8(it))
}
mJumpTo?.let {
sb.append("&p=").append(it)
}
sb.toString()
}
else -> throw IllegalStateException("Unexpected value: $mode")
}
}
@IntDef(
MODE_NORMAL,
MODE_UPLOADER,
MODE_TAG,
MODE_WHATS_HOT,
MODE_IMAGE_SEARCH,
MODE_SUBSCRIPTION,
MODE_TOPLIST,
)
@Retention(AnnotationRetention.SOURCE)
private annotation class Mode
companion object {
const val MODE_NORMAL = 0x0
const val MODE_UPLOADER = 0x1
const val MODE_TAG = 0x2
const val MODE_WHATS_HOT = 0x3
const val MODE_IMAGE_SEARCH = 0x4
const val MODE_SUBSCRIPTION = 0x5
const val MODE_TOPLIST = 0x6
}
}
@@ -1,62 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.GetText.getString
import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.exception.EhException
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.util.ExceptionUtils
import com.hippo.ehviewer.util.JsoupUtils
import org.jsoup.Jsoup
object FavoritesParser {
fun parse(body: String): Result {
if (body.contains("This page requires you to log on.</p>")) {
throw EhException(getString(R.string.need_sign_in))
}
val catArray = arrayOfNulls<String>(10)
val countArray = IntArray(10)
val d = Jsoup.parse(body)
runCatching {
val ido = JsoupUtils.getElementByClass(d, "ido")
val fps = ido!!.getElementsByClass("fp")
// Last one is "fp fps"
check(fps.size == 11)
for (i in 0..9) {
val fp = fps[i]
countArray[i] = ParserUtils.parseInt(fp.child(0).text(), 0)
catArray[i] = ParserUtils.trim(fp.child(2).text())
}
}.onFailure {
ExceptionUtils.throwIfFatal(it)
it.printStackTrace()
throw ParseException("Parse favorites error", body)
}
val result = GalleryListParser.parse(d, body)
return Result(catArray, countArray, result)
}
class Result(
val catArray: Array<String?>,
val countArray: IntArray,
galleryListResult: GalleryListParser.Result,
) {
val prev = galleryListResult.prev
val next = galleryListResult.next
val galleryInfoList = galleryListResult.galleryInfoList
}
}
@@ -1,48 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.client.EhUtils.getCategory
import com.hippo.ehviewer.client.EhUtils.handleThumbUrlResolution
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.getThumbKey
import com.hippo.ehviewer.yorozuya.NumberUtils
import org.json.JSONObject
object GalleryApiParser {
fun parse(body: String, galleryInfoList: List<GalleryInfo>) {
val jo = JSONObject(body)
val ja = jo.getJSONArray("gmetadata")
for (i in 0 until ja.length()) {
val g = ja.getJSONObject(i)
val gid = g.getLong("gid")
val gi = galleryInfoList.find { it.gid == gid } ?: continue
gi.title = ParserUtils.trim(g.getString("title"))
gi.titleJpn = ParserUtils.trim(g.getString("title_jpn"))
gi.category = getCategory(g.getString("category"))
gi.thumbKey = getThumbKey(handleThumbUrlResolution(g.getString("thumb"))!!)
gi.uploader = g.getString("uploader")
gi.posted =
ParserUtils.formatDate(ParserUtils.parseLong(g.getString("posted"), 0) * 1000)
gi.rating = NumberUtils.parseFloatSafely(g.getString("rating"), 0.0f)
// tags
val tagJa = g.getJSONArray("tags")
gi.simpleTags = (0 until tagJa.length()).map { tagJa.getString(it) }.toTypedArray()
gi.pages = NumberUtils.parseIntSafely(g.getString("filecount"), 0)
gi.generateSLang()
}
}
}
@@ -1,508 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import arrow.core.unzip
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.client.EhFilter
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.EhUtils.getCategory
import com.hippo.ehviewer.client.EhUtils.handleThumbUrlResolution
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.client.data.GalleryComment
import com.hippo.ehviewer.client.data.GalleryCommentList
import com.hippo.ehviewer.client.data.GalleryDetail
import com.hippo.ehviewer.client.data.GalleryPreview
import com.hippo.ehviewer.client.data.GalleryTagGroup
import com.hippo.ehviewer.client.data.LargeGalleryPreview
import com.hippo.ehviewer.client.data.NormalGalleryPreview
import com.hippo.ehviewer.client.exception.EhException
import com.hippo.ehviewer.client.exception.OffensiveException
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.client.exception.PiningException
import com.hippo.ehviewer.client.getThumbKey
import com.hippo.ehviewer.util.ExceptionUtils
import com.hippo.ehviewer.util.JsoupUtils
import com.hippo.ehviewer.yorozuya.NumberUtils
import com.hippo.ehviewer.yorozuya.StringUtils
import com.hippo.ehviewer.yorozuya.trimAnd
import com.hippo.ehviewer.yorozuya.unescapeXml
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.nodes.Node
import org.jsoup.select.Elements
import org.jsoup.select.NodeTraversor
import org.jsoup.select.NodeVisitor
import java.time.Instant
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.Locale
object GalleryDetailParser {
private val PATTERN_ERROR = Regex("<div class=\"d\">\n<p>([^<]+)</p>")
private val PATTERN_DETAIL = Regex(
"var gid = (\\d+);.+?var token = \"([a-f0-9]+)\";.+?var apiuid = ([\\-\\d]+);.+?var apikey = \"([a-f0-9]+)\";",
RegexOption.DOT_MATCHES_ALL,
)
private val PATTERN_TORRENT =
Regex("<a[^<>]*onclick=\"return popUp\\('([^']+)'[^)]+\\)\">Torrent Download[^<]+(\\d+)[^<]+</a")
private val PATTERN_ARCHIVE =
Regex("<a[^<>]*onclick=\"return popUp\\('([^']+)'[^)]+\\)\">Archive Download</a>")
private val PATTERN_COVER = Regex("width:(\\d+)px; height:(\\d+)px.+?url\\((.+?)\\)")
private val PATTERN_PAGES =
Regex("<tr><td[^<>]*>Length:</td><td[^<>]*>([\\d,]+) pages</td></tr>")
private val PATTERN_PREVIEW_PAGES =
Regex("<td[^>]+><a[^>]+>([\\d,]+)</a></td><td[^>]+>(?:<a[^>]+>)?&gt;(?:</a>)?</td>")
private val PATTERN_NORMAL_PREVIEW =
Regex("<div class=\"gdtm\"[^<>]*><div[^<>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*><a[^<>]*href=\"(.+?)\"[^<>]*><img alt=\"([\\d,]+)\"")
private val PATTERN_LARGE_PREVIEW =
Regex("<div class=\"gdtl\".+?<a href=\"(.+?)\"><img alt=\"([\\d,]+)\".+?src=\"(.+?)\"")
private val PATTERN_NEWER_DATE = Regex(", added (.+?)<br />")
private val PATTERN_FAVORITE_SLOT =
Regex("/fav.png\\); background-position:0px -(\\d+)px")
private val EMPTY_GALLERY_TAG_GROUP_ARRAY = arrayOf<GalleryTagGroup>()
private val EMPTY_GALLERY_COMMENT_ARRAY = GalleryCommentList(arrayOf(), false)
private val WEB_COMMENT_DATE_FORMAT = DateTimeFormatter
.ofPattern("dd MMMM yyyy, HH:mm", Locale.US).withZone(ZoneOffset.UTC)
private const val OFFENSIVE_STRING =
"<p>(And if you choose to ignore this warning, you lose all rights to complain about it in the future.)</p>"
private const val PINING_STRING = "<p>This gallery is pining for the fjords.</p>"
@Throws(EhException::class)
fun parse(body: String): GalleryDetail {
if (body.contains(OFFENSIVE_STRING)) {
throw OffensiveException()
}
if (body.contains(PINING_STRING)) {
throw PiningException()
}
// Error info
PATTERN_ERROR.find(body)?.run { throw EhException(groupValues[1]) }
// Temporary workaround, see https://github.com/jhy/jsoup/issues/1850
val document = Jsoup.parse(body.replace("del>", "s>"))
val galleryDetail = GalleryDetail(
tags = parseTagGroups(document),
comments = parseComments(document),
previewPages = parsePreviewPages(body),
previewList = parsePreviewList(body).first,
)
parseDetail(galleryDetail, document, body)
// Generate simpleLanguage for local favorites
galleryDetail.generateSLang()
return galleryDetail
}
@Throws(ParseException::class)
private fun parseDetail(gd: GalleryDetail, d: Document, body: String) {
PATTERN_DETAIL.find(body)?.apply {
gd.gid = groupValues[1].toLongOrNull() ?: -1L
gd.token = groupValues[2]
gd.apiUid = groupValues[3].toLongOrNull() ?: -1L
gd.apiKey = groupValues[4]
} ?: throw ParseException("Can't parse gallery detail", body)
if (gd.gid == -1L) {
throw ParseException("Can't parse gallery detail", body)
}
PATTERN_TORRENT.find(body)?.run {
gd.torrentUrl = groupValues[1].trim().unescapeXml()
gd.torrentCount = groupValues[2].toIntOrNull() ?: 0
}
PATTERN_ARCHIVE.find(body)?.run {
gd.archiveUrl = groupValues[1].trim().unescapeXml()
}
try {
val gm = d.getElementsByClass("gm")[0]
// Thumb url
gm.getElementById("gd1")?.child(0)?.attr("style")?.trim()?.let {
gd.thumbKey = getThumbKey(
PATTERN_COVER.find(it)?.run {
handleThumbUrlResolution(groupValues[3])
}!!,
)
}
gd.title = gm.getElementById("gn")?.text()?.trim()
gd.titleJpn = gm.getElementById("gj")?.text()?.trim()
// Category
val gdc = gm.getElementById("gdc")
try {
var ce = JsoupUtils.getElementByClass(gdc, "cn")
if (ce == null) {
ce = JsoupUtils.getElementByClass(gdc, "cs")
}
gd.category = getCategory(ce!!.text())
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
gd.category = EhUtils.UNKNOWN
}
// Uploader
val gdn = gm.getElementById("gdn")
if (null != gdn) {
gd.disowned = gdn.attr("style").contains("opacity:0.5")
gd.uploader = StringUtils.trim(gdn.text())
} else {
gd.uploader = ""
}
val gdd = gm.getElementById("gdd")
gd.posted = ""
gd.parent = ""
gd.visible = ""
gd.size = ""
gd.pages = 0
gd.favoriteCount = 0
val es = gdd!!.child(0).child(0).children()
es.forEach {
parseDetailInfo(gd, it)
}
// Rating count
val ratingCount = gm.getElementById("rating_count")
if (null != ratingCount) {
gd.ratingCount = NumberUtils.parseIntSafely(
StringUtils.trim(ratingCount.text()),
0,
)
} else {
gd.ratingCount = 0
}
// Rating
val ratingLabel = gm.getElementById("rating_label")
if (null != ratingLabel) {
val ratingStr = StringUtils.trim(ratingLabel.text())
if ("Not Yet Rated" == ratingStr) {
gd.rating = -1.0f
} else {
val index = ratingStr.indexOf(' ')
if (index == -1 || index >= ratingStr.length) {
gd.rating = 0f
} else {
gd.rating = NumberUtils.parseFloatSafely(ratingStr.substring(index + 1), 0f)
}
}
} else {
gd.rating = -1.0f
}
// isFavorited
val gdf = gm.getElementById("gdf")
gd.isFavorited = false
if (gdf != null) {
val favoriteName = StringUtils.trim(gdf.text())
if (favoriteName == "Add to Favorites") {
gd.favoriteName = null
} else {
gd.isFavorited = true
gd.favoriteName = StringUtils.trim(gdf.text())
PATTERN_FAVORITE_SLOT.find(body)?.run {
gd.favoriteSlot = ((groupValues[1].toIntOrNull() ?: 2) - 2) / 19
}
}
}
if (gd.favoriteSlot == -2 && EhDB.containLocalFavorites(gd.gid)) {
gd.favoriteSlot = -1
}
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
throw ParseException("Can't parse gallery detail", body)
}
// newer version
d.getElementById("gnd")?.run {
val dates = PATTERN_NEWER_DATE.findAll(body).map { it.groupValues[1] }.toList()
select("a").forEachIndexed { index, element ->
val gi = BaseGalleryInfo()
val result = GalleryDetailUrlParser.parse(element.attr("href"))
if (result != null) {
gi.gid = result.gid
gi.token = result.token
gi.title = StringUtils.trim(element.text())
gi.posted = dates[index]
gd.newerVersions.add(gi)
}
}
}
}
private fun parseDetailInfo(gd: GalleryDetail, e: Element) {
val es = e.children()
if (es.size < 2) {
return
}
val key = StringUtils.trim(es[0].text())
val value = StringUtils.trim(es[1].ownText())
if (key.startsWith("Posted")) {
gd.posted = value
} else if (key.startsWith("Parent")) {
val a = es[1].children().first()
if (a != null) {
gd.parent = a.attr("href")
}
} else if (key.startsWith("Visible")) {
gd.visible = value
} else if (key.startsWith("Language")) {
gd.language = value
} else if (key.startsWith("File Size")) {
gd.size = value
} else if (key.startsWith("Length")) {
val index = value.indexOf(' ')
if (index >= 0) {
gd.pages = NumberUtils.parseIntSafely(value.substring(0, index), 1)
} else {
gd.pages = 1
}
} else if (key.startsWith("Favorited")) {
when (value) {
"Never" -> gd.favoriteCount = 0
"Once" -> gd.favoriteCount = 1
else -> {
val index = value.indexOf(' ')
if (index == -1) {
gd.favoriteCount = 0
} else {
gd.favoriteCount = NumberUtils.parseIntSafely(value.substring(0, index), 0)
}
}
}
}
}
private fun parseTagGroup(element: Element): GalleryTagGroup? {
return try {
val group = GalleryTagGroup()
var nameSpace = element.child(0).text()
// Remove last ':'
nameSpace = nameSpace.substring(0, nameSpace.length - 1)
group.groupName = nameSpace
val tags = element.child(1).children()
tags.forEach {
var tag = it.text()
// Sometimes parody tag is followed with '|' and english translate, just remove them
val index = tag.indexOf('|')
if (index >= 0) {
tag = tag.substring(0, index).trim()
}
if (it.className() == "gtw") {
tag = "_$tag" // weak tag
}
group.add(tag)
}
if (group.size > 0) group else null
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
e.printStackTrace()
null
}
}
/**
* Parse tag groups with html parser
*/
private fun parseTagGroups(document: Document): Array<GalleryTagGroup> {
return try {
val taglist = document.getElementById("taglist")!!
val tagGroups = taglist.child(0).child(0).children()
parseTagGroups(tagGroups)
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
e.printStackTrace()
EMPTY_GALLERY_TAG_GROUP_ARRAY
}
}
private fun parseTagGroups(trs: Elements): Array<GalleryTagGroup> {
return try {
trs.mapNotNull { parseTagGroup(it) }.toTypedArray()
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
e.printStackTrace()
EMPTY_GALLERY_TAG_GROUP_ARRAY
}
}
private fun parseComment(element: Element): GalleryComment? {
return try {
val comment = GalleryComment()
// Id
val a = element.previousElementSibling()
val name = a!!.attr("name")
comment.id = name trimAnd { substring(1).toInt().toLong() }
// Editable, vote up and vote down
val c4 = JsoupUtils.getElementByClass(element, "c4")
if (null != c4) {
if ("Uploader Comment" == c4.text()) {
comment.uploader = true
}
for (e in c4.children()) {
when (e.text()) {
"Vote+" -> {
comment.voteUpAble = true
comment.voteUpEd = StringUtils.trim(e.attr("style")).isNotEmpty()
}
"Vote-" -> {
comment.voteDownAble = true
comment.voteDownEd = StringUtils.trim(e.attr("style")).isNotEmpty()
}
"Edit" -> comment.editable = true
}
}
}
// Vote state
val c7 = JsoupUtils.getElementByClass(element, "c7")
if (null != c7) {
comment.voteState = StringUtils.trim(c7.text())
}
// Score
val c5 = JsoupUtils.getElementByClass(element, "c5")
if (null != c5) {
val es = c5.children()
if (!es.isEmpty()) {
comment.score = NumberUtils.parseIntSafely(
StringUtils.trim(es[0].text()),
0,
)
}
}
// time
val c3 = JsoupUtils.getElementByClass(element, "c3")
val temp = c3!!.ownText()
val time = if (temp.endsWith(':')) {
// user
comment.user = c3.child(0).text()
temp.substring("Posted on ".length, temp.length - " by:".length)
} else {
temp.substring("Posted on ".length)
}
comment.time = Instant.from(WEB_COMMENT_DATE_FORMAT.parse(time)).toEpochMilli()
// comment
val c6 = JsoupUtils.getElementByClass(element, "c6")
// fix underline support
for (e in c6!!.children()) {
if ("span" == e.tagName() && "text-decoration:underline;" == e.attr("style")) {
e.tagName("u")
}
}
comment.comment = c6.html()
// filter comment
if (!comment.uploader) {
val sEhFilter = EhFilter
if (sEhFilter.filterCommenter(comment.user!!) || sEhFilter.filterComment(comment.comment!!)) {
return null
}
}
// last edited
val c8 = JsoupUtils.getElementByClass(element, "c8")
if (c8 != null) {
val e = c8.children().first()
if (e != null) {
comment.lastEdited =
Instant.from(WEB_COMMENT_DATE_FORMAT.parse(e.text())).toEpochMilli()
}
}
comment
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
e.printStackTrace()
null
}
}
/**
* Parse comments with html parser
*/
fun parseComments(document: Document): GalleryCommentList {
return try {
val cdiv = document.getElementById("cdiv")!!
val c1s = cdiv.getElementsByClass("c1")
val list = c1s.mapNotNull { parseComment(it) }
val chd = cdiv.getElementById("chd")
var hasMore = false
NodeTraversor.traverse(
object : NodeVisitor {
override fun head(node: Node, depth: Int) {
if (node is Element && node.text() == "click to show all") {
hasMore = true
}
}
override fun tail(node: Node, depth: Int) {}
},
chd!!,
)
GalleryCommentList(list.toTypedArray(), hasMore)
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
e.printStackTrace()
EMPTY_GALLERY_COMMENT_ARRAY
}
}
/**
* Parse preview pages with regular expressions
*/
@Throws(ParseException::class)
fun parsePreviewPages(body: String): Int {
return PATTERN_PREVIEW_PAGES.find(body)?.groupValues?.get(1)?.toIntOrNull()
?: throw ParseException("Parse preview page count error", body)
}
/**
* Parse pages with regular expressions
*/
@Throws(ParseException::class)
fun parsePages(body: String): Int {
return PATTERN_PAGES.find(body)?.groupValues?.get(1)?.toIntOrNull()
?: throw ParseException("Parse pages error", body)
}
fun parsePreviewList(body: String): Pair<List<GalleryPreview>, List<String>> {
return runCatching { parseNormalPreview(body) }.getOrElse { parseLargePreview(body) }
}
private fun parseLargePreview(body: String): Pair<List<GalleryPreview>, List<String>> {
check(PATTERN_LARGE_PREVIEW.containsMatchIn(body))
return PATTERN_LARGE_PREVIEW.findAll(body).unzip {
val position = it.groupValues[2].toInt() - 1
val imageKey = getThumbKey(it.groupValues[3].trim())
val pageUrl = it.groupValues[1].trim()
LargeGalleryPreview(imageKey, position) to pageUrl
}.run {
first.toList() to second.toList()
}
}
private fun parseNormalPreview(body: String): Pair<List<GalleryPreview>, List<String>> {
check(PATTERN_NORMAL_PREVIEW.containsMatchIn(body))
return PATTERN_NORMAL_PREVIEW.findAll(body).unzip {
val position = it.groupValues[6].toInt() - 1
val imageKey = getThumbKey(it.groupValues[3].trim())
val xOffset = it.groupValues[4].toIntOrNull() ?: 0
val width = it.groupValues[1].toInt()
val height = it.groupValues[2].toInt()
val pageUrl = it.groupValues[5].trim()
NormalGalleryPreview(imageKey, position, xOffset, width, height) to pageUrl
}.run {
first.toList() to second.toList()
}
}
}
@@ -1,343 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import android.util.Log
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.client.getThumbKey
import com.hippo.ehviewer.util.ExceptionUtils
import com.hippo.ehviewer.util.JsoupUtils
import com.hippo.ehviewer.yorozuya.NumberUtils
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.regex.Pattern
object GalleryListParser {
private val TAG = GalleryListParser::class.java.simpleName
private const val NO_UNFILTERED_TEXT =
"No unfiltered results in this page range. You either requested an invalid page or used too aggressive filters."
private val PATTERN_RATING = Pattern.compile("\\d+px")
private val PATTERN_THUMB_SIZE = Pattern.compile("height:(\\d+)px;width:(\\d+)px")
private val PATTERN_FAVORITE_SLOT =
Pattern.compile("background-color:rgba\\((\\d+),(\\d+),(\\d+),")
private val PATTERN_PAGES = Pattern.compile("(\\d+) page")
private val PATTERN_NEXT_PAGE = Pattern.compile("p=(\\d+)")
private val PATTERN_PREV = Pattern.compile("prev=(\\d+(-\\d+)?)")
private val PATTERN_NEXT = Pattern.compile("next=(\\d+(-\\d+)?)")
private val FAVORITE_SLOT_RGB = arrayOf(
Triple("0", "0", "0"),
Triple("240", "0", "0"),
Triple("240", "160", "0"),
Triple("208", "208", "0"),
Triple("0", "128", "0"),
Triple("144", "240", "64"),
Triple("64", "176", "240"),
Triple("0", "0", "240"),
Triple("80", "0", "128"),
Triple("224", "128", "224"),
)
private fun parseRating(ratingStyle: String): String? {
val m = PATTERN_RATING.matcher(ratingStyle)
var num1 = Int.MIN_VALUE
var num2 = Int.MIN_VALUE
var rate = 5
if (m.find()) {
num1 = ParserUtils.parseInt(m.group().replace("px", ""), Int.MIN_VALUE)
}
if (m.find()) {
num2 = ParserUtils.parseInt(m.group().replace("px", ""), Int.MIN_VALUE)
}
if (num1 == Int.MIN_VALUE || num2 == Int.MIN_VALUE) {
return null
}
rate -= num1 / 16
return if (num2 == 21) {
"${rate - 1}.5"
} else {
rate.toString()
}
}
private fun parseFavoriteSlot(style: String): Int {
val m = PATTERN_FAVORITE_SLOT.matcher(style)
if (m.find()) {
val r = m.group(1)!!
val g = m.group(2)!!
val b = m.group(3)!!
return FAVORITE_SLOT_RGB.indexOf(Triple(r, g, b))
}
return -2
}
private fun parseGalleryInfo(e: Element): GalleryInfo? {
val gi: GalleryInfo = BaseGalleryInfo()
// Title, gid, token (required), tags
val glname = JsoupUtils.getElementByClass(e, "glname")
if (glname != null) {
var a = JsoupUtils.getElementByTag(glname, "a")
if (a == null) {
val parent = glname.parent()
if (parent != null && "a" == parent.tagName()) {
a = parent
}
}
if (a != null) {
val result = GalleryDetailUrlParser.parse(a.attr("href"))
if (result != null) {
gi.gid = result.gid
gi.token = result.token
}
}
var child: Element = glname
var children = glname.children()
while (children.size != 0) {
child = children[0]
children = child.children()
}
gi.title = child.text().trim { it <= ' ' }
}
if (gi.title == null) {
return null
}
// Tags
val gts = e.select(".gt, .gtl")
if (gts.size != 0) {
val tags = ArrayList<String>()
for (gt in gts) {
tags.add(gt.attr("title"))
}
gi.simpleTags = tags.toTypedArray()
}
// Category
gi.category = EhUtils.UNKNOWN
var ce = JsoupUtils.getElementByClass(e, "cn")
if (ce == null) {
ce = JsoupUtils.getElementByClass(e, "cs")
}
if (ce != null) {
gi.category = EhUtils.getCategory(ce.text())
}
// Thumb
var thumbUrl: String? = null
val glthumb = JsoupUtils.getElementByClass(e, "glthumb")
if (glthumb != null) {
val img = glthumb.select("div:nth-child(1)>img").first()
if (img != null) {
// Thumb size
val m = PATTERN_THUMB_SIZE.matcher(img.attr("style"))
if (m.find()) {
gi.thumbWidth = NumberUtils.parseIntSafely(m.group(2), 0)
gi.thumbHeight = NumberUtils.parseIntSafely(m.group(1), 0)
} else {
Log.w(TAG, "Can't parse gallery info thumb size")
gi.thumbWidth = 0
gi.thumbHeight = 0
}
// Thumb url
var url = img.attr("data-src")
if (url.isEmpty()) {
url = img.attr("src")
}
if (url.isNotEmpty()) {
thumbUrl = EhUtils.handleThumbUrlResolution(url)!!
}
}
// Pages
val div = glthumb.select("div:nth-child(2)>div:nth-child(2)>div:nth-child(2)").first()
if (div != null) {
val matcher = PATTERN_PAGES.matcher(div.text())
if (matcher.find()) {
gi.pages = NumberUtils.parseIntSafely(matcher.group(1), 0)
}
}
}
// Try extended and thumbnail version
if (thumbUrl == null) {
var gl = JsoupUtils.getElementByClass(e, "gl1e")
if (gl == null) {
gl = JsoupUtils.getElementByClass(e, "gl3t")
}
if (gl != null) {
val img = JsoupUtils.getElementByTag(gl, "img")
if (img != null) {
// Thumb size
val m = PATTERN_THUMB_SIZE.matcher(img.attr("style"))
if (m.find()) {
gi.thumbWidth = NumberUtils.parseIntSafely(m.group(2), 0)
gi.thumbHeight = NumberUtils.parseIntSafely(m.group(1), 0)
} else {
Log.w(TAG, "Can't parse gallery info thumb size")
gi.thumbWidth = 0
gi.thumbHeight = 0
}
thumbUrl = EhUtils.handleThumbUrlResolution(img.attr("src"))
}
}
}
gi.thumbKey = getThumbKey(thumbUrl!!)
// Posted
val posted = e.getElementById("posted_" + gi.gid)
if (posted != null) {
gi.posted = posted.text().trim { it <= ' ' }
gi.favoriteSlot = parseFavoriteSlot(posted.attr("style"))
}
if (gi.favoriteSlot < 0) {
gi.favoriteSlot = if (EhDB.containLocalFavorites(gi.gid)) -1 else -2
}
// Rating
val ir = JsoupUtils.getElementByClass(e, "ir")
if (ir != null) {
gi.rating = NumberUtils.parseFloatSafely(parseRating(ir.attr("style")), -1.0f)
// TODO The gallery may be rated even if it doesn't has one of these classes
gi.rated = ir.hasClass("irr") || ir.hasClass("irg") || ir.hasClass("irb")
}
// Uploader and pages
var gl = JsoupUtils.getElementByClass(e, "glhide")
var uploaderIndex = 0
var pagesIndex = 1
if (gl == null) {
// For extended
gl = JsoupUtils.getElementByClass(e, "gl3e")
uploaderIndex = 3
pagesIndex = 4
}
if (gl != null) {
val children = gl.children()
if (children.size > uploaderIndex) {
val div = children[uploaderIndex]
if (div != null) {
gi.disowned = div.attr("style").contains("opacity:0.5")
val a = div.children().first()
gi.uploader = a?.text()?.trim { it <= ' ' } ?: div.text().trim { it <= ' ' }
}
}
if (children.size > pagesIndex) {
val matcher = PATTERN_PAGES.matcher(children[pagesIndex].text())
if (matcher.find()) {
gi.pages = NumberUtils.parseIntSafely(matcher.group(1), 0)
}
}
}
// For thumbnail
val gl5t = JsoupUtils.getElementByClass(e, "gl5t")
if (gl5t != null) {
val div = gl5t.select("div:nth-child(2)>div:nth-child(2)").first()
if (div != null) {
val matcher = PATTERN_PAGES.matcher(div.text())
if (matcher.find()) {
gi.pages = NumberUtils.parseIntSafely(matcher.group(1), 0)
}
}
}
gi.generateSLang()
return gi
}
fun parse(body: String): Result {
val d = Jsoup.parse(body)
return parse(d, body)
}
fun parse(d: Document, body: String): Result {
val result = Result()
try {
val prev = d.getElementById("uprev")
val next = d.getElementById("unext")
assert(prev != null)
assert(next != null)
val matcherPrev = PATTERN_PREV.matcher(prev!!.attr("href"))
val matcherNext = PATTERN_NEXT.matcher(next!!.attr("href"))
if (matcherPrev.find()) result.prev = matcherPrev.group(1)
if (matcherNext.find()) result.next = matcherNext.group(1)
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
result.noWatchedTags = body.contains("<p>You do not have any watched tags")
if (body.contains("No hits found</p>")) {
return result
}
}
try { // For toplists
val ptt = d.getElementsByClass("ptt").first()
if (ptt != null) {
val es = ptt.child(0).child(0).children()
result.pages = es[es.size - 2].text().trim { it <= ' ' }.toInt()
var e = es[es.size - 1]
if (e != null) {
e = e.children().first()
if (e != null) {
val href = e.attr("href")
val matcher = PATTERN_NEXT_PAGE.matcher(href)
if (matcher.find()) {
result.nextPage = NumberUtils.parseIntSafely(matcher.group(1), 0)
}
}
}
}
} catch (e: Throwable) {
e.printStackTrace()
}
try {
val itg = d.getElementsByClass("itg").first()
val es = if ("table".equals(itg!!.tagName(), ignoreCase = true)) {
itg.child(0).children()
} else {
itg.children()
}
val list = result.galleryInfoList
// First one is table header, skip it
for (i in es.indices) {
val gi = parseGalleryInfo(es[i])
if (null != gi) {
list.add(gi)
}
}
if (list.isEmpty()) {
if (es.size < 2 || NO_UNFILTERED_TEXT != es[1].text()) {
Log.d(TAG, "No gallery found")
}
}
} catch (e: Throwable) {
ExceptionUtils.throwIfFatal(e)
e.printStackTrace()
throw ParseException("Can't parse gallery list", body)
}
return result
}
class Result {
var pages = 0
var nextPage = 0
var prev: String? = null
var next: String? = null
var noWatchedTags = false
val galleryInfoList = mutableListOf<GalleryInfo>()
}
}
@@ -1,144 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import android.net.Uri
import android.os.Build
import android.text.TextUtils
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.hippo.ehviewer.yorozuya.Utilities
import java.io.UnsupportedEncodingException
import java.net.MalformedURLException
import java.net.URL
import java.net.URLDecoder
import java.nio.charset.StandardCharsets
object GalleryListUrlParser {
private val VALID_HOSTS = arrayOf(EhUrl.DOMAIN_EX, EhUrl.DOMAIN_E, EhUrl.DOMAIN_LOFI)
private const val PATH_NORMAL = "/"
private const val PATH_UPLOADER = "/uploader/"
private const val PATH_TAG = "/tag/"
private const val PATH_TOPLIST = "/toplist.php"
fun parse(urlStr: String): ListUrlBuilder? {
val url = try {
URL(urlStr)
} catch (e: MalformedURLException) {
return null
}
if (!Utilities.contain(VALID_HOSTS, url.host)) {
return null
}
val path = url.path ?: return null
return if (PATH_NORMAL == path || path.isEmpty()) {
val builder = ListUrlBuilder()
builder.setQuery(url.query)
builder
} else if (path.startsWith(PATH_UPLOADER)) {
parseUploader(path)
} else if (path.startsWith(PATH_TAG)) {
parseTag(path)
} else if (path.startsWith(PATH_TOPLIST)) {
parseToplist(urlStr)
} else if (path.startsWith("/")) {
val category = try {
path.substring(1).toInt()
} catch (e: NumberFormatException) {
return null
}
val builder = ListUrlBuilder()
builder.setQuery(url.query)
builder.category = category
builder
} else {
null
}
}
// TODO get page
private fun parseUploader(path: String): ListUrlBuilder? {
var uploader: String?
val prefixLength = PATH_UPLOADER.length
val index = path.indexOf('/', prefixLength)
uploader = if (index < 0) {
path.substring(prefixLength)
} else {
path.substring(prefixLength, index)
}
uploader = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
URLDecoder.decode(uploader, StandardCharsets.UTF_8)
} else {
try {
URLDecoder.decode(uploader, StandardCharsets.UTF_8.displayName())
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
return null
}
}
if (TextUtils.isEmpty(uploader)) {
return null
}
val builder = ListUrlBuilder()
builder.mode = ListUrlBuilder.MODE_UPLOADER
builder.keyword = uploader
return builder
}
// TODO get page
private fun parseTag(path: String): ListUrlBuilder? {
var tag: String?
val prefixLength = PATH_TAG.length
val index = path.indexOf('/', prefixLength)
tag = if (index < 0) {
path.substring(prefixLength)
} else {
path.substring(prefixLength, index)
}
tag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
URLDecoder.decode(tag, StandardCharsets.UTF_8)
} else {
try {
URLDecoder.decode(tag, StandardCharsets.UTF_8.displayName())
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
return null
}
}
if (TextUtils.isEmpty(tag)) {
return null
}
val builder = ListUrlBuilder()
builder.mode = ListUrlBuilder.MODE_TAG
builder.keyword = tag
return builder
}
// TODO get page
private fun parseToplist(path: String): ListUrlBuilder? {
val uri = Uri.parse(path)
if (uri == null || TextUtils.isEmpty(uri.getQueryParameter("tl"))) {
return null
}
val tl = uri.getQueryParameter("tl")!!.toInt()
if (tl > 15 || tl < 11) {
return null
}
val builder = ListUrlBuilder()
builder.mode = ListUrlBuilder.MODE_TOPLIST
builder.keyword = tl.toString()
return builder
}
}
@@ -1,71 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.yorozuya.StringUtils
import org.json.JSONException
import org.json.JSONObject
import java.util.regex.Matcher
import java.util.regex.Pattern
object GalleryPageApiParser {
private val PATTERN_IMAGE_URL = Pattern.compile("<img[^>]*src=\"([^\"]+)\" style")
private val PATTERN_SKIP_HATH_KEY = Pattern.compile("onclick=\"return nl\\('([^)]+)'\\)")
private val PATTERN_ORIGIN_IMAGE_URL =
Pattern.compile("<a href=\"([^\"]+)fullimg.php([^\"]+)\">")
fun parse(body: String): Result {
return try {
var m: Matcher
val jo = JSONObject(body)
if (jo.has("error")) {
throw ParseException(jo.getString("error"), body)
}
val i3 = jo.getString("i3")
m = PATTERN_IMAGE_URL.matcher(i3)
val imageUrl = if (m.find()) {
StringUtils.unescapeXml(StringUtils.trim(m.group(1)))
} else {
null
}
val i6 = jo.getString("i6")
m = PATTERN_SKIP_HATH_KEY.matcher(i6)
val skipHathKey = if (m.find()) {
StringUtils.unescapeXml(StringUtils.trim(m.group(1)))
} else {
null
}
val i7 = jo.getString("i7")
m = PATTERN_ORIGIN_IMAGE_URL.matcher(i7)
val originImageUrl = if (m.find()) {
StringUtils.unescapeXml(m.group(1)) + "fullimg.php" +
StringUtils.unescapeXml(m.group(2))
} else {
null
}
if (!imageUrl.isNullOrEmpty()) {
Result(imageUrl, skipHathKey, originImageUrl)
} else {
throw ParseException("Parse image url and skip hath key error", body)
}
} catch (e: JSONException) {
throw ParseException("Can't parse json", body, e)
}
}
class Result(val imageUrl: String, val skipHathKey: String?, val originImageUrl: String?)
}
@@ -1,70 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.yorozuya.StringUtils
import java.util.regex.Pattern
object GalleryPageParser {
private val PATTERN_IMAGE_URL = Pattern.compile("<img[^>]*src=\"([^\"]+)\" style")
private val PATTERN_SKIP_HATH_KEY = Pattern.compile("onclick=\"return nl\\('([^)]+)'\\)")
private val PATTERN_ORIGIN_IMAGE_URL =
Pattern.compile("<a href=\"([^\"]+)fullimg.php([^\"]+)\">")
// TODO Not sure about the size of show keys
private val PATTERN_SHOW_KEY = Pattern.compile("var showkey=\"([0-9a-z]+)\";")
fun parse(body: String): Result {
var m = PATTERN_IMAGE_URL.matcher(body)
val imageUrl = if (m.find()) {
StringUtils.unescapeXml(StringUtils.trim(m.group(1)))
} else {
null
}
m = PATTERN_SKIP_HATH_KEY.matcher(body)
val skipHathKey = if (m.find()) {
StringUtils.unescapeXml(StringUtils.trim(m.group(1)))
} else {
null
}
m = PATTERN_ORIGIN_IMAGE_URL.matcher(body)
val originImageUrl = if (m.find()) {
StringUtils.unescapeXml(m.group(1)) + "fullimg.php" +
StringUtils.unescapeXml(m.group(2))
} else {
null
}
m = PATTERN_SHOW_KEY.matcher(body)
val showKey = if (m.find()) {
m.group(1)
} else {
null
}
return if (!imageUrl.isNullOrEmpty() && !showKey.isNullOrEmpty()) {
Result(imageUrl, skipHathKey, originImageUrl, showKey)
} else {
throw ParseException("Parse image url and show error", body)
}
}
class Result(
val imageUrl: String,
val skipHathKey: String?,
val originImageUrl: String?,
val showKey: String,
)
}
@@ -1,44 +0,0 @@
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.client.exception.ParseException
import org.jsoup.Jsoup
object HomeParser {
private val PATTERN_FUNDS =
Regex("Available: ([\\d,]+) Credits.*Available: ([\\d,]+) kGP", RegexOption.DOT_MATCHES_ALL)
private const val RESET_SUCCEED = "Image limit was successfully reset."
fun parse(body: String): Limits {
Jsoup.parse(body).selectFirst("div.homebox")?.let {
val es = it.select("p > strong")
if (es.size == 3) {
val current = ParserUtils.parseInt(es[0].text(), 0)
val maximum = ParserUtils.parseInt(es[1].text(), 0)
val resetCost = ParserUtils.parseInt(es[2].text(), 0)
return Limits(current, maximum, resetCost)
}
}
throw ParseException("Parse image limits error", body)
}
fun parseResetLimits(body: String): Limits? {
return if (body.contains(RESET_SUCCEED)) {
null
} else {
parse(body)
}
}
fun parseFunds(body: String): Funds {
PATTERN_FUNDS.find(body)?.groupValues?.run {
val fundsC = ParserUtils.parseInt(get(1), 0)
val fundsGP = ParserUtils.parseInt(get(2), 0) * 1000
return Funds(fundsGP, fundsC)
}
throw ParseException("Parse funds error", body)
}
data class Limits(val current: Int = 0, val maximum: Int, val resetCost: Int = 0)
data class Funds(val fundsGP: Int, val fundsC: Int)
class Result(val limits: Limits, val funds: Funds)
}
@@ -1,45 +0,0 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.yorozuya.NumberUtils
import com.hippo.ehviewer.yorozuya.StringUtils
import java.time.Instant
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.Locale
object ParserUtils {
private val formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm", Locale.US).withZone(ZoneOffset.UTC)
@Synchronized
fun formatDate(time: Long): String {
return formatter.format(Instant.ofEpochMilli(time))
}
fun trim(str: String?): String {
return str?.let { StringUtils.unescapeXml(it).trim() } ?: ""
}
fun parseInt(str: String?, defValue: Int): Int {
return NumberUtils.parseIntSafely(trim(str).replace(",", ""), defValue)
}
fun parseLong(str: String?, defValue: Long): Long {
return NumberUtils.parseLongSafely(trim(str).replace(",", ""), defValue)
}
}
@@ -1,54 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import android.util.Log
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.util.ExceptionUtils
import org.jsoup.Jsoup
object ProfileParser {
private val TAG = ProfileParser::class.java.simpleName
fun parse(body: String): Result {
return runCatching {
val d = Jsoup.parse(body)
val profilename = d.getElementById("profilename")
val displayName = profilename!!.child(0).text()
val avatar = runCatching {
val avatar =
profilename.nextElementSibling()!!.nextElementSibling()!!.child(0).attr("src")
if (avatar.isNullOrEmpty()) {
null
} else if (!avatar.startsWith("http")) {
EhUrl.URL_FORUMS + avatar
} else {
avatar
}
}.getOrElse {
ExceptionUtils.throwIfFatal(it)
Log.i(TAG, "No avatar")
null
}
Result(displayName, avatar)
}.getOrElse {
ExceptionUtils.throwIfFatal(it)
throw ParseException("Parse forums error", body)
}
}
class Result(val displayName: String?, val avatar: String?)
}
@@ -1,35 +0,0 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.client.exception.ParseException
import org.json.JSONException
import org.json.JSONObject
object RateGalleryParser {
fun parse(body: String): Result {
return try {
val jsonObject = JSONObject(body)
val rating = jsonObject.getDouble("rating_avg").toFloat()
val ratingCount = jsonObject.getInt("rating_cnt")
Result(rating, ratingCount)
} catch (e: JSONException) {
throw ParseException("Can't parse rate gallery", body, e)
}
}
class Result(val rating: Float, val ratingCount: Int)
}
Loaded 100 of 871 files, more files were not shown because too many files have changed in this diff. Show more