Merge branch 'master' into devel
This commit is contained in:
65
.idea/misc.xml
generated
65
.idea/misc.xml
generated
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="../../../../../../layout/custom_preview.xml" value="0.1" />
|
||||
<entry key="../../../../../../opt/usr/android-sdk/platforms/android-30/data/res/drawable/list_divider_material.xml" value="0.28512820512820514" />
|
||||
<entry key="../../../../../../opt/usr/android-sdk/platforms/android-30/data/res/layout/simple_dropdown_item_1line.xml" value="0.24739583333333334" />
|
||||
<entry key="../../../../.gradle/caches/transforms-3/0998d1b3fbd6b77213a827054a7dfcfd/transformed/appcompat-1.2.0/res/layout/abc_alert_dialog_material.xml" value="0.25885416666666666" />
|
||||
<entry key="../../../../.gradle/caches/transforms-3/0998d1b3fbd6b77213a827054a7dfcfd/transformed/appcompat-1.2.0/res/layout/abc_select_dialog_material.xml" value="0.25885416666666666" />
|
||||
<entry key="../../../../.gradle/caches/transforms-3/688e95ad986d2d0286c79f787589b7cb/transformed/material-1.3.0/res/layout/mtrl_alert_dialog.xml" value="0.25885416666666666" />
|
||||
<entry key="../../../../.gradle/caches/transforms-3/7bbda65156c2f797f689a169a6aaa2eb/transformed/appcompat-1.2.0/res/drawable/abc_switch_thumb_material.xml" value="0.2609375" />
|
||||
<entry key="app/src/main/res/drawable/ic_alert_outline.xml" value="0.2609375" />
|
||||
<entry key="app/src/main/res/drawable/ic_clear_all.xml" value="0.275" />
|
||||
<entry key="app/src/main/res/drawable/ic_complete.xml" value="0.275" />
|
||||
<entry key="app/src/main/res/drawable/ic_history.xml" value="0.275" />
|
||||
<entry key="app/src/main/res/drawable/ic_locale.xml" value="0.197" />
|
||||
<entry key="app/src/main/res/drawable/ic_open_external.xml" value="0.197" />
|
||||
<entry key="app/src/main/res/drawable/tab_indicator.xml" value="0.28512820512820514" />
|
||||
<entry key="app/src/main/res/drawable/tabs_background.xml" value="0.28512820512820514" />
|
||||
<entry key="app/src/main/res/layout-w600dp/activity_details.xml" value="0.18072916666666666" />
|
||||
<entry key="app/src/main/res/layout-w600dp/fragment_details.xml" value="0.14583333333333334" />
|
||||
<entry key="app/src/main/res/layout-w600dp/fragment_list.xml" value="0.14635416666666667" />
|
||||
<entry key="app/src/main/res/layout/activity_protect.xml" value="0.26927083333333335" />
|
||||
<entry key="app/src/main/res/layout/activity_setup_protect.xml" value="0.26927083333333335" />
|
||||
<entry key="app/src/main/res/layout/dialog_favorite_categories.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/dialog_list_mode.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/dialog_onboard.xml" value="0.25885416666666666" />
|
||||
<entry key="app/src/main/res/layout/fragment_chapters.xml" value="0.24739583333333334" />
|
||||
<entry key="app/src/main/res/layout/fragment_details.xml" value="0.26145833333333335" />
|
||||
<entry key="app/src/main/res/layout/fragment_favourites.xml" value="0.26296296296296295" />
|
||||
<entry key="app/src/main/res/layout/fragment_feed.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/fragment_list.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/fragment_search_suggestion.xml" value="0.25885416666666666" />
|
||||
<entry key="app/src/main/res/layout/item_branch.xml" value="0.24739583333333334" />
|
||||
<entry key="app/src/main/res/layout/item_branch_dropdown.xml" value="0.25743589743589745" />
|
||||
<entry key="app/src/main/res/layout/item_category.xml" value="0.25885416666666666" />
|
||||
<entry key="app/src/main/res/layout/item_category_checkable.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/item_manga_grid.xml" value="0.26042632066728455" />
|
||||
<entry key="app/src/main/res/layout/item_manga_list_details.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/item_page_thumb.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/item_page_webtoon.xml" value="0.13095238095238096" />
|
||||
<entry key="app/src/main/res/layout/item_recent.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/layout/item_search_suggestion_header.xml" value="0.25885416666666666" />
|
||||
<entry key="app/src/main/res/layout/item_search_suggestion_manga.xml" value="0.24479166666666666" />
|
||||
<entry key="app/src/main/res/layout/item_search_suggestion_query.xml" value="0.587248322147651" />
|
||||
<entry key="app/src/main/res/layout/item_source_config.xml" value="0.25885416666666666" />
|
||||
<entry key="app/src/main/res/layout/item_source_locale.xml" value="0.25885416666666666" />
|
||||
<entry key="app/src/main/res/layout/item_tracklog.xml" value="0.24479166666666666" />
|
||||
<entry key="app/src/main/res/layout/sheet_pages.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/menu/opt_browser.xml" value="0.24479166666666666" />
|
||||
<entry key="app/src/main/res/menu/opt_protect.xml" value="0.26927083333333335" />
|
||||
<entry key="app/src/main/res/menu/opt_sources.xml" value="0.24479166666666666" />
|
||||
<entry key="app/src/main/res/menu/popup_category.xml" value="0.2601851851851852" />
|
||||
<entry key="app/src/main/res/xml/pref_main.xml" value="0.26927083333333335" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -13,8 +13,8 @@ android {
|
||||
applicationId 'org.koitharu.kotatsu'
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode 364
|
||||
versionName '1.0.1'
|
||||
versionCode 365
|
||||
versionName '1.1'
|
||||
|
||||
kapt {
|
||||
arguments {
|
||||
@@ -93,9 +93,8 @@ dependencies {
|
||||
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.0'
|
||||
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.0'
|
||||
|
||||
implementation 'io.insert-koin:koin-android:3.0.2'
|
||||
implementation 'io.insert-koin:koin-android-ext:3.0.2'
|
||||
implementation 'io.coil-kt:coil-base:1.2.1'
|
||||
implementation 'io.insert-koin:koin-android:3.1.0'
|
||||
implementation 'io.coil-kt:coil-base:1.2.2'
|
||||
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
||||
implementation 'com.github.solkin:disk-lru-cache:1.2'
|
||||
|
||||
@@ -103,5 +102,5 @@ dependencies {
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.json:json:20210307'
|
||||
testImplementation 'io.insert-koin:koin-test-junit4:3.0.2'
|
||||
testImplementation 'io.insert-koin:koin-test-junit4:3.1.0'
|
||||
}
|
||||
@@ -35,6 +35,7 @@ class ShortcutsRepository(
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return
|
||||
val manager = context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager
|
||||
val shortcuts = historyRepository.getList(0, manager.maxShortcutCountPerActivity)
|
||||
.filter { x -> x.title.isNotEmpty() }
|
||||
.map { buildShortcutInfo(it).build().toShortcutInfo() }
|
||||
manager.dynamicShortcuts = shortcuts
|
||||
}
|
||||
|
||||
@@ -49,18 +49,17 @@ class MangareadRepository(
|
||||
id = generateUid(href),
|
||||
url = href,
|
||||
publicUrl = href.inContextOf(div),
|
||||
coverUrl = div.selectFirst("img").attr("data-srcset")
|
||||
.split(',').firstOrNull()?.substringBeforeLast(' ').orEmpty(),
|
||||
coverUrl = div.selectFirst("img").absUrl("src"),
|
||||
title = summary.selectFirst("h3").text(),
|
||||
rating = div.selectFirst("span.total_votes")?.ownText()
|
||||
?.toFloatOrNull()?.div(5f) ?: -1f,
|
||||
tags = summary.selectFirst(".mg_genres").select("a").mapToSet { a ->
|
||||
tags = summary.selectFirst(".mg_genres")?.select("a")?.mapToSet { a ->
|
||||
MangaTag(
|
||||
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
|
||||
title = a.text(),
|
||||
source = MangaSource.MANGAREAD
|
||||
)
|
||||
},
|
||||
}.orEmpty(),
|
||||
author = summary.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
|
||||
state = when (summary.selectFirst(".mg_status")?.selectFirst(".summary-content")
|
||||
?.ownText()?.trim()) {
|
||||
@@ -148,7 +147,7 @@ class MangareadRepository(
|
||||
?: throw ParseException("Root not found")
|
||||
return root.select("div.page-break").map { div ->
|
||||
val img = div.selectFirst("img")
|
||||
val url = img.relUrl("data-src")
|
||||
val url = img.relUrl("src")
|
||||
MangaPage(
|
||||
id = generateUid(url),
|
||||
url = url,
|
||||
|
||||
@@ -2,13 +2,12 @@ package org.koitharu.kotatsu.details
|
||||
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
import org.koitharu.kotatsu.details.ui.DetailsViewModel
|
||||
|
||||
val detailsModule
|
||||
get() = module {
|
||||
|
||||
viewModel { (intent: MangaIntent) ->
|
||||
DetailsViewModel(intent, get(), get(), get(), get(), get(), get())
|
||||
viewModel { intent ->
|
||||
DetailsViewModel(intent.get(), get(), get(), get(), get(), get(), get())
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.favourites
|
||||
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.MangaCategoriesViewModel
|
||||
@@ -13,11 +12,11 @@ val favouritesModule
|
||||
|
||||
single { FavouritesRepository(get()) }
|
||||
|
||||
viewModel { (categoryId: Long) ->
|
||||
FavouritesListViewModel(categoryId, get(), get())
|
||||
viewModel { categoryId ->
|
||||
FavouritesListViewModel(categoryId.get(), get(), get())
|
||||
}
|
||||
viewModel { FavouritesCategoriesViewModel(get()) }
|
||||
viewModel { (manga: Manga) ->
|
||||
MangaCategoriesViewModel(manga, get())
|
||||
viewModel { manga ->
|
||||
MangaCategoriesViewModel(manga.get(), get())
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import android.content.Context
|
||||
import com.tomclaw.cache.DiskLruCache
|
||||
import org.koitharu.kotatsu.utils.FileSizeUtils
|
||||
import org.koitharu.kotatsu.utils.ext.longHashCode
|
||||
import org.koitharu.kotatsu.utils.ext.sub
|
||||
import org.koitharu.kotatsu.utils.ext.subdir
|
||||
import org.koitharu.kotatsu.utils.ext.takeIfReadable
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
@@ -13,8 +13,10 @@ import java.io.OutputStream
|
||||
class PagesCache(context: Context) {
|
||||
|
||||
private val cacheDir = context.externalCacheDir ?: context.cacheDir
|
||||
private val lruCache =
|
||||
DiskLruCache.create(cacheDir.sub(Cache.PAGES.dir), FileSizeUtils.mbToBytes(200))
|
||||
private val lruCache = DiskLruCache.create(
|
||||
cacheDir.subdir(Cache.PAGES.dir),
|
||||
FileSizeUtils.mbToBytes(200)
|
||||
)
|
||||
|
||||
operator fun get(url: String): File? {
|
||||
return lruCache.get(url)?.takeIfReadable()
|
||||
@@ -22,7 +24,7 @@ class PagesCache(context: Context) {
|
||||
|
||||
@Deprecated("Useless lambda")
|
||||
fun put(url: String, writer: (OutputStream) -> Unit): File {
|
||||
val file = cacheDir.sub(url.longHashCode().toString())
|
||||
val file = File(cacheDir, url.longHashCode().toString())
|
||||
file.outputStream().use(writer)
|
||||
val res = lruCache.put(url, file)
|
||||
file.delete()
|
||||
@@ -30,7 +32,7 @@ class PagesCache(context: Context) {
|
||||
}
|
||||
|
||||
fun put(url: String, inputStream: InputStream): File {
|
||||
val file = cacheDir.sub(url.longHashCode().toString())
|
||||
val file = File(cacheDir, url.longHashCode().toString())
|
||||
file.outputStream().use { out ->
|
||||
inputStream.copyTo(out)
|
||||
}
|
||||
|
||||
@@ -175,10 +175,12 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
|
||||
}
|
||||
|
||||
fun getAvailableStorageDirs(context: Context): List<File> {
|
||||
val result = ArrayList<File>(5)
|
||||
result += context.filesDir.sub(DIR_NAME)
|
||||
val result = ArrayList<File?>(5)
|
||||
result += File(context.filesDir, DIR_NAME)
|
||||
result += context.getExternalFilesDirs(DIR_NAME)
|
||||
return result.distinctBy { it.canonicalPath }.filter { it.exists() || it.mkdir() }
|
||||
return result.filterNotNull()
|
||||
.distinctBy { it.canonicalPath }
|
||||
.filter { it.exists() || it.mkdir() }
|
||||
}
|
||||
|
||||
fun getFallbackStorageDir(context: Context): File? {
|
||||
|
||||
@@ -3,9 +3,7 @@ package org.koitharu.kotatsu.reader
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
import org.koitharu.kotatsu.local.data.PagesCache
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderViewModel
|
||||
|
||||
val readerModule
|
||||
@@ -14,7 +12,7 @@ val readerModule
|
||||
single { MangaDataRepository(get()) }
|
||||
single { PagesCache(get()) }
|
||||
|
||||
viewModel { (intent: MangaIntent, state: ReaderState?) ->
|
||||
ReaderViewModel(intent, state, get(), get(), get(), get())
|
||||
viewModel { params ->
|
||||
ReaderViewModel(params[0], params[1], get(), get(), get(), get())
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import org.koitharu.kotatsu.remotelist.ui.RemoteListViewModel
|
||||
val remoteListModule
|
||||
get() = module {
|
||||
|
||||
viewModel { (source: MangaSource) ->
|
||||
RemoteListViewModel(get(named(source)), get())
|
||||
viewModel { source ->
|
||||
RemoteListViewModel(get(named(source.get<MangaSource>())), get())
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
package org.koitharu.kotatsu.remotelist.ui
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaFilter
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.search.ui.SearchActivity
|
||||
import org.koitharu.kotatsu.utils.ext.parcelableArgument
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
@@ -25,7 +20,7 @@ class RemoteListFragment : MangaListFragment() {
|
||||
viewModel.loadNextPage()
|
||||
}
|
||||
|
||||
override fun getTitle(): CharSequence? {
|
||||
override fun getTitle(): CharSequence {
|
||||
return source.title
|
||||
}
|
||||
|
||||
@@ -34,19 +29,6 @@ class RemoteListFragment : MangaListFragment() {
|
||||
super.onFilterChanged(filter)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.opt_remote, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
R.id.action_search_internal -> {
|
||||
context?.startActivity(SearchActivity.newIntent(requireContext(), source, null))
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_SOURCE = "provider"
|
||||
|
||||
@@ -18,11 +18,11 @@ val searchModule
|
||||
|
||||
factory { MangaSuggestionsProvider.createSuggestions(androidContext()) }
|
||||
|
||||
viewModel { (source: MangaSource, query: String) ->
|
||||
SearchViewModel(get(named(source)), query, get())
|
||||
viewModel { params ->
|
||||
SearchViewModel(get(named(params.get<MangaSource>(0))), params[1], get())
|
||||
}
|
||||
viewModel { (query: String) ->
|
||||
GlobalSearchViewModel(query, get(), get())
|
||||
viewModel { query ->
|
||||
GlobalSearchViewModel(query.get(), get(), get())
|
||||
}
|
||||
viewModel { SearchSuggestionViewModel(get()) }
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class MangaSearchRepository(
|
||||
MangaSuggestionsProvider.QUERY_URI,
|
||||
SUGGESTION_PROJECTION,
|
||||
null,
|
||||
null,
|
||||
arrayOfNulls(1),
|
||||
null
|
||||
)?.use { cursor -> cursor.count } ?: 0
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -87,16 +88,7 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
true
|
||||
}
|
||||
AppSettings.KEY_SEARCH_HISTORY_CLEAR -> {
|
||||
viewLifecycleScope.launch {
|
||||
searchRepository.clearSearchHistory()
|
||||
preference.summary = preference.context.resources
|
||||
.getQuantityString(R.plurals.items, 0, 0)
|
||||
Snackbar.make(
|
||||
view ?: return@launch,
|
||||
R.string.search_history_cleared,
|
||||
Snackbar.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
clearSearchHistory(preference)
|
||||
true
|
||||
}
|
||||
AppSettings.KEY_UPDATES_FEED_CLEAR -> {
|
||||
@@ -133,4 +125,23 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearSearchHistory(preference: Preference) {
|
||||
AlertDialog.Builder(context ?: return)
|
||||
.setTitle(R.string.clear_search_history)
|
||||
.setMessage(R.string.text_clear_search_history_prompt)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.clear) { _, _ ->
|
||||
viewLifecycleScope.launch {
|
||||
searchRepository.clearSearchHistory()
|
||||
preference.summary = preference.context.resources
|
||||
.getQuantityString(R.plurals.items, 0, 0)
|
||||
Snackbar.make(
|
||||
view ?: return@launch,
|
||||
R.string.search_history_cleared,
|
||||
Snackbar.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,9 @@ val settingsModule
|
||||
single { AppSettings(androidContext()) }
|
||||
|
||||
viewModel { BackupViewModel(get(), androidContext()) }
|
||||
viewModel { (uri: Uri?) -> RestoreViewModel(uri, get(), androidContext()) }
|
||||
viewModel { params ->
|
||||
RestoreViewModel(params.getOrNull(Uri::class), get(), androidContext())
|
||||
}
|
||||
viewModel { ProtectSetupViewModel(get()) }
|
||||
viewModel { OnboardViewModel(get()) }
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
||||
import org.koitharu.kotatsu.utils.ext.map
|
||||
import org.koitharu.kotatsu.utils.ext.mapTo
|
||||
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||
import java.util.*
|
||||
|
||||
@@ -30,10 +29,10 @@ class OnboardViewModel(
|
||||
if (settings.isSourcesSelected) {
|
||||
selectedLocales.removeAll(settings.hiddenSources.map { x -> MangaSource.valueOf(x).locale })
|
||||
} else {
|
||||
LocaleListCompat.getDefault().mapTo(selectedLocales) { x ->
|
||||
val deviceLocales = LocaleListCompat.getDefault().map { x ->
|
||||
x.language
|
||||
}
|
||||
selectedLocales.retainAll(allSources.map { x -> x.locale })
|
||||
selectedLocales.retainAll(deviceLocales)
|
||||
if (selectedLocales.isEmpty()) {
|
||||
selectedLocales += "en"
|
||||
}
|
||||
@@ -71,7 +70,7 @@ class OnboardViewModel(
|
||||
}.sortedWith(SourceLocaleComparator())
|
||||
}
|
||||
|
||||
private class SourceLocaleComparator : Comparator<SourceLocale> {
|
||||
private class SourceLocaleComparator : Comparator<SourceLocale?> {
|
||||
|
||||
private val deviceLocales = LocaleListCompat.getAdjustedDefault()
|
||||
.map { it.language }
|
||||
|
||||
@@ -23,12 +23,12 @@ object CacheUtils {
|
||||
|
||||
@WorkerThread
|
||||
fun computeCacheSize(context: Context, name: String) = getCacheDirs(context)
|
||||
.map { it.sub(name) }
|
||||
.map { File(it, name) }
|
||||
.sumOf { x -> x.computeSize() }
|
||||
|
||||
@WorkerThread
|
||||
fun clearCache(context: Context, name: String) = getCacheDirs(context)
|
||||
.map { it.sub(name) }
|
||||
.map { File(it, name) }
|
||||
.forEach { it.deleteRecursively() }
|
||||
|
||||
// FIXME need async implementation
|
||||
|
||||
@@ -13,8 +13,13 @@ import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@Deprecated("Useless", ReplaceWith("File(this, name)", "java.io.File"))
|
||||
inline fun File.sub(name: String) = File(this, name)
|
||||
|
||||
fun File.subdir(name: String) = File(this, name).also {
|
||||
if (!it.exists()) it.mkdirs()
|
||||
}
|
||||
|
||||
fun File.takeIfReadable() = takeIf { it.exists() && it.canRead() }
|
||||
|
||||
fun ZipFile.readText(entry: ZipEntry) = getInputStream(entry).bufferedReader().use {
|
||||
|
||||
@@ -80,7 +80,7 @@ fun String.toRelativeUrl(domain: String): String {
|
||||
}
|
||||
|
||||
fun Element.relUrl(attributeKey: String): String {
|
||||
val attr = attr(attributeKey)
|
||||
val attr = attr(attributeKey).trim()
|
||||
if (attr.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -50,18 +50,22 @@ fun String.toCamelCase(): String {
|
||||
|
||||
fun String.transliterate(skipMissing: Boolean): String {
|
||||
val cyr = charArrayOf(
|
||||
'a', 'б', 'в', 'г', 'д', 'ё', 'ж', 'з', 'и', 'к', 'л', 'м', 'н',
|
||||
'п', 'р', 'с', 'т', 'у', 'ў', 'ф', 'х', 'ц', 'ш', 'щ', 'ы', 'э', 'ю', 'я'
|
||||
'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п',
|
||||
'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я', 'ё', 'ў'
|
||||
)
|
||||
val lat = arrayOf(
|
||||
"a", "b", "v", "g", "d", "jo", "zh", "z", "i", "k", "l", "m", "n",
|
||||
"p", "r", "s", "t", "u", "w", "f", "h", "ts", "sh", "sch", "", "e", "ju", "ja"
|
||||
"a", "b", "v", "g", "d", "e", "zh", "z", "i", "y", "k", "l", "m", "n", "o", "p",
|
||||
"r", "s", "t", "u", "f", "h", "ts", "ch", "sh", "sch", "", "i", "", "e", "ju", "ja", "jo", "w"
|
||||
)
|
||||
return buildString(length + 5) {
|
||||
for (c in this@transliterate) {
|
||||
val p = cyr.binarySearch(c.toLowerCase())
|
||||
val p = cyr.binarySearch(c.lowercaseChar())
|
||||
if (p in lat.indices) {
|
||||
append(lat[p])
|
||||
if (c.isUpperCase()) {
|
||||
append(lat[p].uppercase())
|
||||
} else {
|
||||
append(lat[p])
|
||||
}
|
||||
} else if (!skipMissing) {
|
||||
append(c)
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_search_internal"
|
||||
android:orderInCategory="26"
|
||||
android:title="@string/search"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
@@ -201,13 +201,13 @@
|
||||
<string name="_and_x_more">…и ещё %1$d</string>
|
||||
<string name="next">Далее</string>
|
||||
<string name="protect_application_subtitle">Введите пароль, который вам понадобится при запуске приложения</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="confirm">Подтвердить</string>
|
||||
<string name="password_length_hint">Пароль должен содержать не менее 4 символов</string>
|
||||
<string name="hide_toolbar">Прятать заголовок при прокрутке</string>
|
||||
<string name="search_only_on_s">Поиск только по %s</string>
|
||||
<string name="other">Другие</string>
|
||||
<string name="languages">Languages</string>
|
||||
<string name="welcome">Welcome</string>
|
||||
<string name="description">Описание</string>
|
||||
<string name="text_clear_search_history_prompt">Вы действительно хотите удалить все последние поисковые запросы? Это действие не может быть отменено.</string>
|
||||
<string name="languages">Языки</string>
|
||||
<string name="welcome">Добро пожаловать</string>
|
||||
<string name="text_clear_search_history_prompt">Вы действительно хотите удалить все недавние поисковые запросы? Это действие не может быть отменено.</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user