Code Refactor / Dependency Update
5
.idea/misc.xml
generated
@@ -32,8 +32,13 @@
|
||||
<entry key="../../../../layout/compose-model-1639629588722.xml" value="0.3472222222222222" />
|
||||
<entry key="../../../../layout/custom_preview.xml" value="0.518974358974359" />
|
||||
<entry key="app/src/main/res/drawable/avd_star.xml" value="0.2722222222222222" />
|
||||
<entry key="app/src/main/res/drawable/close.xml" value="0.31614583333333335" />
|
||||
<entry key="app/src/main/res/drawable/history.xml" value="0.3055555555555556" />
|
||||
<entry key="app/src/main/res/drawable/ic_star_empty.xml" value="0.31614583333333335" />
|
||||
<entry key="app/src/main/res/drawable/numeric.xml" value="0.31614583333333335" />
|
||||
<entry key="app/src/main/res/drawable/swap_horizontal.xml" value="0.31614583333333335" />
|
||||
<entry key="app/src/main/res/layout/gallery_dialog.xml" value="0.30052083333333335" />
|
||||
<entry key="app/src/main/res/layout/gallery_dialog_dotindicator.xml" value="0.2859375" />
|
||||
<entry key="app/src/main/res/layout/main_activity.xml" value="0.2953125" />
|
||||
<entry key="app/src/main/res/layout/main_activity_content.xml" value="0.2953125" />
|
||||
<entry key="app/src/main/res/layout/progress_card_view.xml" value="0.2953125" />
|
||||
|
||||
@@ -43,8 +43,6 @@ android {
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
dataBinding = true
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
@@ -91,11 +89,11 @@ dependencies {
|
||||
implementation("com.google.accompanist:accompanist-drawablepainter:0.20.3")
|
||||
implementation("com.google.accompanist:accompanist-systemuicontroller:0.20.3")
|
||||
|
||||
implementation("io.coil-kt:coil-compose:1.3.2")
|
||||
implementation("io.coil-kt:coil-compose:1.4.0")
|
||||
|
||||
implementation("io.ktor:ktor-client-core:1.6.5")
|
||||
implementation("io.ktor:ktor-client-okhttp:1.6.5")
|
||||
implementation("io.ktor:ktor-client-serialization:1.6.5")
|
||||
implementation("io.ktor:ktor-client-core:1.6.7")
|
||||
implementation("io.ktor:ktor-client-okhttp:1.6.7")
|
||||
implementation("io.ktor:ktor-client-serialization:1.6.7")
|
||||
|
||||
implementation("androidx.appcompat:appcompat:1.4.0")
|
||||
implementation("androidx.activity:activity-ktx:1.4.0")
|
||||
@@ -115,10 +113,8 @@ dependencies {
|
||||
|
||||
implementation("org.kodein.di:kodein-di-framework-compose:7.9.0")
|
||||
|
||||
implementation("com.daimajia.swipelayout:library:1.2.0@aar")
|
||||
|
||||
implementation("com.google.android.material:material:1.4.0")
|
||||
|
||||
0
|
||||
implementation(platform("com.google.firebase:firebase-bom:28.3.0"))
|
||||
implementation("com.google.firebase:firebase-analytics-ktx")
|
||||
implementation("com.google.firebase:firebase-crashlytics")
|
||||
@@ -126,26 +122,16 @@ dependencies {
|
||||
|
||||
implementation("com.google.android.gms:play-services-oss-licenses:17.0.0")
|
||||
|
||||
implementation("com.github.clans:fab:1.6.4")
|
||||
|
||||
//implementation("com.quiph.ui:recyclerviewfastscroller:0.2.1")
|
||||
|
||||
implementation("org.jsoup:jsoup:1.14.3")
|
||||
|
||||
implementation("com.tbuonomo:dotsindicator:4.2")
|
||||
|
||||
//implementation("com.andrognito.patternlockview:patternlockview:1.0.0")
|
||||
//implementation("com.andrognito.pinlockview:pinlockview:2.1.0")
|
||||
|
||||
implementation("ru.noties.markwon:core:3.1.0")
|
||||
|
||||
implementation("xyz.quaver:libpupil:2.1.11")
|
||||
implementation("xyz.quaver:documentfilex:0.7.1")
|
||||
implementation("xyz.quaver:floatingsearchview:1.1.7")
|
||||
implementation("xyz.quaver:subsampledimage:0.0.1-alpha09-SNAPSHOT")
|
||||
implementation("xyz.quaver:subsampledimage:0.0.1-alpha10-SNAPSHOT")
|
||||
|
||||
implementation("org.kodein.log:kodein-log:0.11.1")
|
||||
//debugImplementation("com.squareup.leakcanary:leakcanary-android:2.7")
|
||||
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.7")
|
||||
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("org.mockito:mockito-inline:4.1.0")
|
||||
|
||||
@@ -26,10 +26,6 @@
|
||||
tools:replace="android:theme"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="face" />
|
||||
|
||||
<provider
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
@@ -50,7 +46,6 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name=".ui.LockActivity" />
|
||||
<activity
|
||||
android:name=".ui.ReaderActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
@@ -211,11 +206,6 @@
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.SettingsActivity"
|
||||
android:label="@string/settings_title">
|
||||
<tools:validation testUrl="http://ix.io/eer" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
|
||||
@@ -23,11 +23,7 @@ import android.os.Parcelable
|
||||
import androidx.compose.runtime.Composable
|
||||
import io.ktor.http.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.kodein.di.*
|
||||
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.pupil.R
|
||||
|
||||
interface ItemInfo : Parcelable {
|
||||
val source: String
|
||||
@@ -35,9 +31,6 @@ interface ItemInfo : Parcelable {
|
||||
val title: String
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
class DefaultSearchSuggestion(override val body: String) : SearchSuggestion
|
||||
|
||||
data class SearchResultEvent(val type: Type, val itemID: String, val payload: Parcelable? = null) {
|
||||
enum class Type {
|
||||
OPEN_READER,
|
||||
@@ -54,7 +47,6 @@ abstract class Source {
|
||||
abstract val availableSortMode: List<String>
|
||||
|
||||
abstract suspend fun search(query: String, range: IntRange, sortMode: Int): Pair<Channel<ItemInfo>, Int>
|
||||
abstract suspend fun suggestion(query: String): List<SearchSuggestion>
|
||||
abstract suspend fun images(itemID: String): List<String>
|
||||
abstract suspend fun info(itemID: String): ItemInfo
|
||||
|
||||
@@ -62,10 +54,6 @@ abstract class Source {
|
||||
open fun SearchResult(itemInfo: ItemInfo, onEvent: (SearchResultEvent) -> Unit = { }) { }
|
||||
|
||||
open fun getHeadersBuilderForImage(itemID: String, url: String): HeadersBuilder.() -> Unit = { }
|
||||
|
||||
open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
|
||||
binding.leftIcon.setImageResource(R.drawable.tag)
|
||||
}
|
||||
}
|
||||
|
||||
typealias SourceEntry = Pair<String, Source>
|
||||
|
||||
@@ -26,7 +26,6 @@ import kotlinx.serialization.json.Json
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.instance
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.io.util.getChild
|
||||
import xyz.quaver.pupil.R
|
||||
|
||||
@@ -26,7 +26,6 @@ import kotlinx.coroutines.launch
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.direct
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.pupil.util.database
|
||||
|
||||
class History(override val di: DI) : Source(), DIAware {
|
||||
@@ -56,10 +55,6 @@ class History(override val di: DI) : Source(), DIAware {
|
||||
//return Pair(channel, histories.map.size)
|
||||
}
|
||||
|
||||
override suspend fun suggestion(query: String): List<SearchSuggestion> {
|
||||
throw NotImplementedError("")
|
||||
}
|
||||
|
||||
override suspend fun images(itemID: String): List<String> {
|
||||
throw NotImplementedError("")
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
package xyz.quaver.pupil.sources
|
||||
|
||||
import android.app.Application
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -59,8 +57,6 @@ import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
import org.kodein.log.LoggerFactory
|
||||
import org.kodein.log.newLogger
|
||||
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.hitomi.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.db.AppDatabase
|
||||
@@ -124,21 +120,6 @@ class Hitomi(app: Application) : Source(), DIAware {
|
||||
|
||||
private val bookmarkDao = database.bookmarkDao()
|
||||
|
||||
@Parcelize
|
||||
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion {
|
||||
constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n)
|
||||
|
||||
@IgnoredOnParcel
|
||||
override val body = s
|
||||
/*
|
||||
TODO
|
||||
if (translations[s] != null)
|
||||
"${translations[s]} ($s)"
|
||||
else
|
||||
s
|
||||
*/
|
||||
}
|
||||
|
||||
override val name: String = "hitomi.la"
|
||||
override val iconResID: Int = R.drawable.hitomi
|
||||
override val preferenceID: Int = R.xml.hitomi_preferences
|
||||
@@ -178,12 +159,6 @@ class Hitomi(app: Application) : Source(), DIAware {
|
||||
channel to cache.size
|
||||
}
|
||||
|
||||
override suspend fun suggestion(query: String) : List<TagSuggestion> {
|
||||
return getSuggestionsForQuery(query.takeLastWhile { !it.isWhitespace() }).map {
|
||||
TagSuggestion(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun images(itemID: String): List<String> {
|
||||
val galleryID = itemID.toInt()
|
||||
|
||||
@@ -229,40 +204,6 @@ class Hitomi(app: Application) : Source(), DIAware {
|
||||
append("Referer", getReferer(itemID.toInt()))
|
||||
}
|
||||
|
||||
override fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
|
||||
item as TagSuggestion
|
||||
|
||||
binding.leftIcon.setImageResource(
|
||||
when(item.n) {
|
||||
"female" -> R.drawable.gender_female
|
||||
"male" -> R.drawable.gender_male
|
||||
"language" -> R.drawable.translate
|
||||
"group" -> R.drawable.account_group
|
||||
"character" -> R.drawable.account_star
|
||||
"series" -> R.drawable.book_open
|
||||
"artist" -> R.drawable.brush
|
||||
else -> R.drawable.tag
|
||||
}
|
||||
)
|
||||
|
||||
if (item.t > 0) {
|
||||
with (binding.root) {
|
||||
val count = findViewById<TextView>(R.id.count)
|
||||
if (count == null)
|
||||
addView(
|
||||
LayoutInflater.from(context).inflate(R.layout.suggestion_count, binding.root, false)
|
||||
.apply {
|
||||
this as TextView
|
||||
|
||||
text = item.t.toString()
|
||||
}, 2
|
||||
)
|
||||
else
|
||||
count.text = item.t.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val languageMap = mapOf(
|
||||
"indonesian" to "Bahasa Indonesia",
|
||||
|
||||
@@ -60,7 +60,6 @@ import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
import org.kodein.log.LoggerFactory
|
||||
import org.kodein.log.newLogger
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.db.AppDatabase
|
||||
import xyz.quaver.pupil.db.Bookmark
|
||||
@@ -207,10 +206,6 @@ class Hiyobi_io(app: Application): Source(), DIAware {
|
||||
channel to totalCount(tags)
|
||||
}
|
||||
|
||||
override suspend fun suggestion(query: String): List<SearchSuggestion> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun images(itemID: String): List<String> = withContext(Dispatchers.IO) {
|
||||
val query = "{getManga(mangaId:$itemID){urls}}"
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2019 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.types
|
||||
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
|
||||
@Parcelize
|
||||
class HistorySuggestion(override val body: String) : SearchSuggestion
|
||||
|
||||
@Parcelize
|
||||
class NoResultSuggestion(override val body: String) : SearchSuggestion
|
||||
|
||||
@Parcelize
|
||||
class LoadingSuggestion(override val body: String) : SearchSuggestion
|
||||
|
||||
@Parcelize
|
||||
@Suppress("PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY")
|
||||
class FavoriteHistorySwitch(override val body: String) : SearchSuggestion
|
||||
@@ -65,7 +65,7 @@ import xyz.quaver.pupil.ui.composable.MultipleFloatingActionButton
|
||||
import xyz.quaver.pupil.ui.composable.SubFabItem
|
||||
import xyz.quaver.pupil.ui.dialog.SourceSelectDialog
|
||||
import xyz.quaver.pupil.ui.theme.PupilTheme
|
||||
import xyz.quaver.pupil.ui.view.ProgressCardView
|
||||
import xyz.quaver.pupil.ui.composable.ProgressCard
|
||||
import xyz.quaver.pupil.ui.viewmodel.MainViewModel
|
||||
import xyz.quaver.pupil.util.*
|
||||
import kotlin.math.*
|
||||
@@ -175,7 +175,7 @@ class MainActivity : ComponentActivity(), DIAware {
|
||||
contentPadding = PaddingValues(0.dp, 56.dp, 0.dp, 0.dp)
|
||||
) {
|
||||
items(model.searchResults, key = { it.itemID }) { itemInfo ->
|
||||
ProgressCardView(
|
||||
ProgressCard(
|
||||
progress = 0.5f
|
||||
) {
|
||||
model.source.SearchResult(itemInfo = itemInfo) { event ->
|
||||
|
||||
@@ -198,12 +198,13 @@ class ReaderActivity : ComponentActivity(), DIAware {
|
||||
Text((i + 1).toString())
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
SubSampledImage(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
imageSource = imageSource,
|
||||
state = states[i]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2019 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.ui.fragment.SettingsFragment
|
||||
import xyz.quaver.pupil.ui.fragment.SourceSettingsFragment
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
companion object {
|
||||
const val SETTINGS_EXTRA = "xyz.quaver.pupil.ui.SettingsActivity.SETTINGS_EXTRA"
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.settings_activity)
|
||||
|
||||
val fragment = intent.getStringExtra(SETTINGS_EXTRA)?.run {
|
||||
SourceSettingsFragment(this)
|
||||
} ?: SettingsFragment()
|
||||
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, fragment)
|
||||
.commit()
|
||||
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> onBackPressed()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,19 @@
|
||||
package xyz.quaver.pupil.ui.view
|
||||
package xyz.quaver.pupil.ui.composable
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ProgressCardView(progress: Float? = null, content: @Composable () -> Unit) {
|
||||
fun ProgressCard(progress: Float? = null, content: @Composable () -> Unit) {
|
||||
Card(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.databinding.DefaultQueryDialogBinding
|
||||
import xyz.quaver.pupil.sources.Hitomi
|
||||
import xyz.quaver.pupil.types.Tags
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
|
||||
class DefaultQueryDialogFragment : DialogFragment() {
|
||||
// TODO languageMap
|
||||
private val languages = Hitomi.languageMap
|
||||
private val reverseLanguages = languages.entries.associate { (k, v) -> v to k }
|
||||
|
||||
private val excludeBL = "-male:yaoi"
|
||||
private val excludeGuro = listOf("-female:guro", "-male:guro")
|
||||
private val excludeLoli = listOf("-female:loli", "-male:shota")
|
||||
|
||||
var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null
|
||||
|
||||
private var _binding: DefaultQueryDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = DefaultQueryDialogBinding.inflate(layoutInflater)
|
||||
|
||||
initView()
|
||||
|
||||
return AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.default_query_dialog_title)
|
||||
.setView(binding.root)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
val newTags = Tags.parse(binding.edittext.text.toString())
|
||||
|
||||
with (binding.languageSelector) {
|
||||
if (selectedItemPosition != 0)
|
||||
newTags.add("language:${reverseLanguages[selectedItem]}")
|
||||
}
|
||||
|
||||
if (binding.BLCheckbox.isChecked)
|
||||
newTags.add(excludeBL)
|
||||
|
||||
if (binding.guroCheckbox.isChecked)
|
||||
excludeGuro.forEach { tag ->
|
||||
newTags.add(tag)
|
||||
}
|
||||
|
||||
if (binding.loliCheckbox.isChecked)
|
||||
excludeLoli.forEach { tag ->
|
||||
newTags.add(tag)
|
||||
}
|
||||
|
||||
onPositiveButtonClickListener?.invoke(newTags)
|
||||
}.create()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
val tags = Tags.parse(
|
||||
Preferences["hitomi.default_query"]
|
||||
)
|
||||
|
||||
with (binding.languageSelector) {
|
||||
adapter =
|
||||
ArrayAdapter(
|
||||
context,
|
||||
android.R.layout.simple_spinner_dropdown_item,
|
||||
arrayListOf(
|
||||
context.getString(R.string.default_query_dialog_language_selector_none)
|
||||
).apply {
|
||||
addAll(languages.values)
|
||||
}
|
||||
)
|
||||
if (tags.any { it.area == "language" && !it.isNegative }) {
|
||||
val tag = languages[tags.first { it.area == "language" }.tag]
|
||||
if (tag != null) {
|
||||
setSelection(
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(adapter as ArrayAdapter<String>).getPosition(tag)
|
||||
)
|
||||
tags.removeByArea("language", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with (binding.BLCheckbox) {
|
||||
isChecked = tags.contains(excludeBL)
|
||||
if (tags.contains(excludeBL))
|
||||
tags.remove(excludeBL)
|
||||
}
|
||||
|
||||
with (binding.guroCheckbox) {
|
||||
isChecked = excludeGuro.all { tags.contains(it) }
|
||||
if (excludeGuro.all { tags.contains(it) })
|
||||
excludeGuro.forEach {
|
||||
tags.remove(it)
|
||||
}
|
||||
}
|
||||
|
||||
with (binding.loliCheckbox) {
|
||||
isChecked = excludeLoli.all { tags.contains(it) }
|
||||
if (excludeLoli.all { tags.contains(it) })
|
||||
excludeLoli.forEach {
|
||||
tags.remove(it)
|
||||
}
|
||||
}
|
||||
|
||||
with (binding.edittext) {
|
||||
setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE)
|
||||
addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(
|
||||
s: CharSequence?,
|
||||
start: Int,
|
||||
count: Int,
|
||||
after: Int
|
||||
) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
s ?: return
|
||||
|
||||
if (s.any { it.isUpperCase() })
|
||||
s.replace(
|
||||
0,
|
||||
s.length,
|
||||
s.toString().lowercase()
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.databinding.DownloadFolderNameDialogBinding
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
|
||||
class DownloadFolderNameDialogFragment : DialogFragment() {
|
||||
|
||||
private var _binding: DownloadFolderNameDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = DownloadFolderNameDialogBinding.inflate(layoutInflater)
|
||||
|
||||
initView()
|
||||
|
||||
return Dialog(requireContext()).apply {
|
||||
setContentView(binding.root)
|
||||
window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
binding.okButton.setOnClickListener {
|
||||
val newValue = binding.edittext.text.toString()
|
||||
|
||||
if ((newValue as? String)?.contains("/") != false) {
|
||||
Snackbar.make(binding.root, R.string.settings_invalid_download_folder_name, Snackbar.LENGTH_SHORT).show()
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
Preferences["download_folder_name"] = binding.edittext.text.toString()
|
||||
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.dialog
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.instance
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.io.util.toFile
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.databinding.DownloadLocationDialogBinding
|
||||
import xyz.quaver.pupil.databinding.DownloadLocationItemBinding
|
||||
import xyz.quaver.pupil.util.DownloadManager
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import xyz.quaver.pupil.util.byteToString
|
||||
import java.io.File
|
||||
|
||||
class DownloadLocationDialogFragment : DialogFragment(), DIAware {
|
||||
|
||||
override val di by closestDI()
|
||||
|
||||
private val downloadManager: DownloadManager by instance()
|
||||
|
||||
private var _binding: DownloadLocationDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val entries = mutableMapOf<File?, DownloadLocationItemBinding>()
|
||||
|
||||
private val requestDownloadFolderLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
val context = context ?: return@registerForActivityResult
|
||||
val dialog = dialog ?: return@registerForActivityResult
|
||||
|
||||
it.data?.data?.let { uri ->
|
||||
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
|
||||
context.contentResolver.takePersistableUriPermission(uri, takeFlags)
|
||||
|
||||
if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false)) {
|
||||
entries[null]?.locationAvailable?.text = uri.toFile(context)?.canonicalPath
|
||||
Preferences["download_folder"] = uri.toString()
|
||||
} else {
|
||||
Snackbar.make(
|
||||
dialog.window!!.decorView.rootView,
|
||||
R.string.settings_download_folder_not_writable,
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
val downloadFolder = downloadManager.downloadFolder.canonicalPath
|
||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||
entries[key]!!.button.isChecked = true
|
||||
if (key == null) entries[key]!!.locationAvailable.text = downloadFolder
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val downloadFolder = downloadManager.downloadFolder.canonicalPath
|
||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||
if (key == null)
|
||||
entries[key]!!.locationAvailable.text = downloadFolder
|
||||
else {
|
||||
entries[null]!!.button.isChecked = false
|
||||
entries[key]!!.button.isChecked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
val externalFilesDirs = ContextCompat.getExternalFilesDirs(requireContext(), null)
|
||||
|
||||
externalFilesDirs.forEachIndexed { index, dir ->
|
||||
dir ?: return@forEachIndexed
|
||||
|
||||
DownloadLocationItemBinding.inflate(layoutInflater, binding.root, true).apply {
|
||||
locationType.text = requireContext().getString(when (index) {
|
||||
0 -> R.string.settings_download_folder_internal
|
||||
else -> R.string.settings_download_folder_removable
|
||||
})
|
||||
locationAvailable.text = requireContext().getString(
|
||||
R.string.settings_download_folder_available,
|
||||
byteToString(dir.freeSpace)
|
||||
)
|
||||
root.setOnClickListener {
|
||||
entries.values.forEach { entry ->
|
||||
entry.button.isChecked = false
|
||||
}
|
||||
button.performClick()
|
||||
Preferences["download_folder"] = dir.toUri().toString()
|
||||
}
|
||||
entries[dir] = this
|
||||
}
|
||||
}
|
||||
|
||||
DownloadLocationItemBinding.inflate(layoutInflater, binding.root, true).apply {
|
||||
locationType.text = requireContext().getString(R.string.settings_download_folder_custom)
|
||||
root.setOnClickListener {
|
||||
entries.values.forEach { entry ->
|
||||
entry.button.isChecked = false
|
||||
}
|
||||
button.performClick()
|
||||
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
|
||||
addFlags(
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
|
||||
)
|
||||
putExtra("android.content.extra.SHOW_ADVANCED", true)
|
||||
}
|
||||
|
||||
requestDownloadFolderLauncher.launch(intent)
|
||||
}
|
||||
entries[null] = this
|
||||
}
|
||||
|
||||
val downloadFolder = downloadManager.downloadFolder.canonicalPath
|
||||
val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder }
|
||||
entries[key]!!.button.isChecked = true
|
||||
if (key == null) entries[key]!!.locationAvailable.text = downloadFolder
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = DownloadLocationDialogBinding.inflate(layoutInflater)
|
||||
|
||||
initView()
|
||||
|
||||
return AlertDialog.Builder(requireContext()).apply {
|
||||
setTitle(R.string.settings_download_folder)
|
||||
setView(binding.root)
|
||||
setPositiveButton(requireContext().getText(android.R.string.ok)) { _, _ ->
|
||||
if (Preferences["download_folder", ""].isEmpty())
|
||||
Preferences["download_folder"] = context.getExternalFilesDir(null)?.toUri()?.toString() ?: ""
|
||||
}
|
||||
|
||||
isCancelable = false
|
||||
}.create()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.dialog
|
||||
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
|
||||
class GalleryDialogFragment(private val source: String, private val itemID: String) : DialogFragment(), DIAware {
|
||||
|
||||
override val di by closestDI()
|
||||
/*
|
||||
private val favoriteTags: SavedSourceSet by instance(tag = "favoriteTags")
|
||||
|
||||
val onChipClickedHandler = ArrayList<((Tag) -> (Unit))>()
|
||||
|
||||
private var _binding: GalleryDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val viewModel: GalleryDialogViewModel by viewModels()
|
||||
|
||||
private val controllerListener = object: BaseControllerListener<ImageInfo>() {
|
||||
override fun onIntermediateImageSet(id: String?, imageInfo: ImageInfo?) {
|
||||
imageInfo?.let {
|
||||
binding.cover.aspectRatio = it.width / it.height.toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
|
||||
imageInfo?.let {
|
||||
binding.cover.aspectRatio = it.width / it.height.toFloat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = GalleryDialogBinding.inflate(layoutInflater)
|
||||
|
||||
with (binding.fab) {
|
||||
setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.arrow_right))
|
||||
setOnClickListener {
|
||||
context?.startActivity(Intent(requireContext(), ReaderActivity::class.java).apply {
|
||||
putExtra("source", source)
|
||||
putExtra("id", itemID)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val lilMutex = Mutex(true)
|
||||
viewModel.info.observe(this) {
|
||||
binding.progressbar.visibility = View.GONE
|
||||
binding.title.text = it.title
|
||||
binding.artist.text = it.artists
|
||||
|
||||
binding.cover.controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(it.thumbnail)
|
||||
.setControllerListener(controllerListener)
|
||||
.setOldController(binding.cover.controller)
|
||||
.build()
|
||||
|
||||
MainScope().launch {
|
||||
binding.type.text = it.extra[ItemInfo.ExtraType.TYPE]?.wordCapitalize()
|
||||
addDetails(it)
|
||||
addPreviews(it)
|
||||
|
||||
lilMutex.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.related.observe(this) {
|
||||
if (it != null) {
|
||||
MainScope().launch {
|
||||
lilMutex.withLock {
|
||||
addRelated(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.load(source, itemID)
|
||||
|
||||
return AlertDialog.Builder(requireContext())
|
||||
.setView(binding.root)
|
||||
.create()
|
||||
}
|
||||
|
||||
private suspend fun addDetails(info: ItemInfo) {
|
||||
GalleryDialogDetailsBinding.inflate(layoutInflater, binding.contents, true).apply {
|
||||
type.setText(R.string.gallery_details)
|
||||
|
||||
listOf(
|
||||
R.string.gallery_artists,
|
||||
R.string.gallery_groups,
|
||||
R.string.gallery_language,
|
||||
R.string.gallery_series,
|
||||
R.string.gallery_characters,
|
||||
R.string.gallery_tags
|
||||
).zip(
|
||||
listOf(
|
||||
info.artists.split(", ").map { Tag("artist", it) },
|
||||
info.extra[ItemInfo.ExtraType.GROUP]?.split(", ")?.filterNot { it.isEmpty() }?.map { Tag("group", it) },
|
||||
info.extra[ItemInfo.ExtraType.LANGUAGE]?.split(", ")?.filterNot { it.isEmpty() }?.map { Tag("language", it) },
|
||||
info.extra[ItemInfo.ExtraType.SERIES]?.split(", ")?.filterNot { it.isEmpty() }?.map { Tag("series", it) },
|
||||
info.extra[ItemInfo.ExtraType.CHARACTER]?.split(", ")?.filterNot { it.isEmpty() }?.map { Tag("character", it) },
|
||||
info.extra[ItemInfo.ExtraType.TAGS]?.split(", ")?.filterNot { it.isEmpty() }?.sortedBy {
|
||||
val tag = Tag.parse(it)
|
||||
|
||||
if (favoriteTags.map[source]?.contains(tag.toString()) == true)
|
||||
-1
|
||||
else
|
||||
when(Tag.parse(it).area) {
|
||||
"female" -> 0
|
||||
"male" -> 1
|
||||
else -> 2
|
||||
}
|
||||
}?.map {
|
||||
Tag.parse(it).let { tag ->
|
||||
when {
|
||||
tag.area != null -> tag
|
||||
else -> Tag("tag", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
).filterNot { (_, content) ->
|
||||
content.isNullOrEmpty()
|
||||
}.forEach { (title, content) ->
|
||||
GalleryDialogTagsBinding.inflate(layoutInflater, contents, true).apply {
|
||||
type.setText(title)
|
||||
|
||||
content!!.forEach { tag ->
|
||||
tags.addView(
|
||||
TagChip(requireContext(), source, tag).apply {
|
||||
setOnClickListener {
|
||||
onChipClickedHandler.forEach { handler ->
|
||||
handler.invoke(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun addPreviews(info: ItemInfo) {
|
||||
val previews = info.extra[ItemInfo.ExtraType.PREVIEW]?.split(", ") ?: return
|
||||
|
||||
GalleryDialogDetailsBinding.inflate(layoutInflater, binding.contents, true).apply {
|
||||
type.setText(R.string.gallery_thumbnails)
|
||||
|
||||
val pager = ViewPager2(requireContext()).apply {
|
||||
adapter = ThumbnailPageAdapter(previews)
|
||||
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
|
||||
contents.addView(pager)
|
||||
|
||||
// TODO: Change to direct allocation
|
||||
GalleryDialogDotindicatorBinding.inflate(layoutInflater, contents, true).apply {
|
||||
dotindicator.setViewPager2(pager)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addRelated(relatedItems: List<ItemInfo>) {
|
||||
val adapter = SearchResultsAdapter(MutableLiveData(relatedItems)).apply {
|
||||
onChipClickedHandler = { tag ->
|
||||
this@GalleryDialogFragment.onChipClickedHandler.forEach { handler ->
|
||||
handler.invoke(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GalleryDialogDetailsBinding.inflate(layoutInflater, binding.contents, true).apply {
|
||||
type.setText(R.string.gallery_related)
|
||||
|
||||
contents.addView(RecyclerView(requireContext()).apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
this.adapter = adapter
|
||||
|
||||
ItemClickSupport.addTo(this).apply {
|
||||
onItemClickListener = { _, position, _ ->
|
||||
requireContext().startActivity(Intent(requireContext(), ReaderActivity::class.java).apply {
|
||||
putExtra("source", source)
|
||||
putExtra("id", relatedItems[position].id)
|
||||
})
|
||||
}
|
||||
onItemLongClickListener = { _, position, _ ->
|
||||
GalleryDialogFragment(source, relatedItems[position].id).apply {
|
||||
onChipClickedHandler.add { tag ->
|
||||
this@GalleryDialogFragment.onChipClickedHandler.forEach { it.invoke(tag) }
|
||||
}
|
||||
}.show(parentFragmentManager, "")
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
binding.contents.forEach { if (it is RecyclerView) ItemClickSupport.removeFrom(it) }
|
||||
super.onDestroyView()
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.instance
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.databinding.ProxyDialogBinding
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import xyz.quaver.pupil.util.ProxyInfo
|
||||
import xyz.quaver.pupil.util.getProxyInfo
|
||||
import java.net.Proxy
|
||||
|
||||
class ProxyDialogFragment : DialogFragment(), DIAware {
|
||||
|
||||
override val di: DI by closestDI()
|
||||
|
||||
private var _binding: ProxyDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = ProxyDialogBinding.inflate(layoutInflater)
|
||||
|
||||
initView()
|
||||
|
||||
return AlertDialog.Builder(requireContext()).apply {
|
||||
setView(binding.root)
|
||||
}.create()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
val proxyInfo = getProxyInfo()
|
||||
|
||||
val enabler = { enable: Boolean ->
|
||||
binding.addr.isEnabled = enable
|
||||
binding.port.isEnabled = enable
|
||||
binding.username.isEnabled = enable
|
||||
binding.password.isEnabled = enable
|
||||
|
||||
if (!enable) {
|
||||
binding.addr.text = null
|
||||
binding.port.text = null
|
||||
binding.username.text = null
|
||||
binding.password.text = null
|
||||
}
|
||||
}
|
||||
|
||||
with(binding.typeSelector) {
|
||||
adapter = ArrayAdapter(
|
||||
context,
|
||||
android.R.layout.simple_spinner_dropdown_item,
|
||||
context.resources.getStringArray(R.array.proxy_type)
|
||||
)
|
||||
|
||||
setSelection(proxyInfo.type.ordinal)
|
||||
|
||||
onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
enabler.invoke(position != 0)
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||
}
|
||||
}
|
||||
|
||||
binding.addr.setText(proxyInfo.host)
|
||||
binding.port.setText(proxyInfo.port?.toString())
|
||||
binding.username.setText(proxyInfo.username)
|
||||
binding.password.setText(proxyInfo.password)
|
||||
|
||||
enabler.invoke(proxyInfo.type != Proxy.Type.DIRECT)
|
||||
|
||||
binding.cancelButton.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.okButton.setOnClickListener {
|
||||
val type = Proxy.Type.values()[binding.typeSelector.selectedItemPosition]
|
||||
val addr = binding.addr.text?.toString()
|
||||
val port = binding.port.text?.toString()?.toIntOrNull()
|
||||
val username = binding.username.text?.toString()
|
||||
val password = binding.password.text?.toString()
|
||||
|
||||
if (type != Proxy.Type.DIRECT) {
|
||||
if (addr == null || addr.isEmpty())
|
||||
binding.addr.error = requireContext().getText(R.string.proxy_dialog_error)
|
||||
if (port == null)
|
||||
binding.port.error = requireContext().getText(R.string.proxy_dialog_error)
|
||||
|
||||
if (addr == null || addr.isEmpty() || port == null)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
ProxyInfo(type, addr, port, username, password).let {
|
||||
Preferences["proxy"] = Json.encodeToString(it)
|
||||
// TODO
|
||||
}
|
||||
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.fragment
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.webkit.URLUtil
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.direct
|
||||
import org.kodein.di.instance
|
||||
import xyz.quaver.pupil.Pupil
|
||||
import xyz.quaver.pupil.R
|
||||
import java.io.IOException
|
||||
/*
|
||||
class ManageFavoritesFragment : PreferenceFragmentCompat(), DIAware {
|
||||
|
||||
private lateinit var progressDrawable: CircularProgressDrawable
|
||||
|
||||
override val di by closestDI()
|
||||
|
||||
private val applicationContext: Pupil by instance()
|
||||
private val client: HttpClient by instance()
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.manage_favorites_preferences, rootKey)
|
||||
|
||||
val context = requireContext()
|
||||
|
||||
val iconSize = context.resources.getDimensionPixelSize(R.dimen.settings_progressbar_icon_size)
|
||||
progressDrawable = object: CircularProgressDrawable(context) {
|
||||
override fun getIntrinsicHeight() = iconSize
|
||||
override fun getIntrinsicWidth() = iconSize
|
||||
}.apply {
|
||||
setStyle(CircularProgressDrawable.DEFAULT)
|
||||
setColorSchemeColors(ContextCompat.getColor(context, R.color.colorAccent))
|
||||
}
|
||||
|
||||
initPreferences()
|
||||
}
|
||||
|
||||
private fun initPreferences() {
|
||||
findPreference<Preference>("backup")?.setOnPreferenceClickListener { preference ->
|
||||
|
||||
MainScope().launch {
|
||||
preference.icon = progressDrawable
|
||||
progressDrawable.start()
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
kotlin.runCatching {
|
||||
requireContext().openFileInput("favorites.json").use { favorites ->
|
||||
val httpResponse: HttpResponse = client.submitForm(
|
||||
url = "http://ix.io/",
|
||||
formParameters = Parameters.build {
|
||||
append("F:1", favorites.bufferedReader().readText())
|
||||
}
|
||||
)
|
||||
|
||||
if (httpResponse.status.value != 200) throw IOException("Response code ${httpResponse.status.value}")
|
||||
|
||||
Intent(Intent.ACTION_SEND).apply {
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, httpResponse.receive<String>().replace("\n", ""))
|
||||
}.let {
|
||||
applicationContext.startActivity(Intent.createChooser(it, getString(R.string.settings_backup_share)))
|
||||
}
|
||||
}
|
||||
}.onSuccess {
|
||||
MainScope().launch {
|
||||
progressDrawable.stop()
|
||||
preference.icon = null
|
||||
}
|
||||
}.onFailure {
|
||||
view?.let {
|
||||
Snackbar.make(it, R.string.settings_backup_failed, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
findPreference<Preference>("restore")?.setOnPreferenceClickListener {
|
||||
val editText = EditText(context).apply {
|
||||
setText(context.getString(R.string.backup_url), TextView.BufferType.EDITABLE)
|
||||
}
|
||||
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.settings_restore_title)
|
||||
.setView(editText)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
kotlin.runCatching {
|
||||
val url = editText.text.toString()
|
||||
|
||||
if (!URLUtil.isValidUrl(url)) throw IllegalArgumentException()
|
||||
|
||||
client.get<Set<String>>(url).also {
|
||||
direct.instance<SavedSourceSet>(tag = "favorites.json").addAll(mapOf("hitomi.la" to it))
|
||||
}
|
||||
}.onSuccess {
|
||||
MainScope().launch {
|
||||
view?.run {
|
||||
Snackbar.make(this, context.getString(R.string.settings_restore_success, it.size), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
MainScope().launch {
|
||||
view?.run {
|
||||
Snackbar.make(this, R.string.settings_restore_failed, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
// Do Nothing
|
||||
}.show()
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
}*/
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import kotlinx.coroutines.*
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.instance
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.util.*
|
||||
|
||||
class ManageStorageFragment : PreferenceFragmentCompat(), DIAware, Preference.OnPreferenceClickListener {
|
||||
|
||||
override val di by closestDI()
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
private val downloadManager: DownloadManager by instance()
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.manage_storage_preferences, rootKey)
|
||||
|
||||
initPreferences()
|
||||
}
|
||||
|
||||
override fun onPreferenceClick(preference: Preference?): Boolean {
|
||||
val context = context ?: return false
|
||||
|
||||
with (preference) {
|
||||
this ?: return false
|
||||
|
||||
when (key) {
|
||||
"delete_cache" -> {/*
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.warning)
|
||||
setMessage(R.string.settings_clear_cache_alert_message)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
summary = context.getString(R.string.settings_storage_usage_loading)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
cache.clear()
|
||||
|
||||
MainScope().launch {
|
||||
summary = context.getString(R.string.settings_storage_usage, byteToString(cache.cacheFolder.size()))
|
||||
}
|
||||
}
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
}.show()*/
|
||||
}
|
||||
"delete_downloads" -> {
|
||||
val dir = downloadManager.downloadFolder
|
||||
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.warning)
|
||||
setMessage(R.string.settings_clear_downloads_alert_message)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
job?.cancel()
|
||||
launch(Dispatchers.Main) {
|
||||
summary = context.getString(R.string.settings_storage_usage_loading)
|
||||
}
|
||||
|
||||
if (dir.exists())
|
||||
dir.listFiles()?.forEach {
|
||||
when (it) {
|
||||
is FileX -> it.deleteRecursively()
|
||||
else -> it.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
job = launch {
|
||||
var size = 0L
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
summary = context.getString(R.string.settings_storage_usage, byteToString(size))
|
||||
}
|
||||
dir.walk().forEach {
|
||||
size += it.length()
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
summary = context.getString(R.string.settings_storage_usage, byteToString(size))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
}.show()
|
||||
}
|
||||
/*
|
||||
"clear_history" -> {
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.warning)
|
||||
setMessage(R.string.settings_clear_history_alert_message)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
histories.clear()
|
||||
summary = context.getString(R.string.settings_clear_history_summary, histories.map.values.sumOf { it.size })
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
}.show()
|
||||
}*/
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun initPreferences() {
|
||||
val context = context ?: return
|
||||
|
||||
with (findPreference<Preference>("delete_cache")) {/*
|
||||
this ?: return@with
|
||||
summary = context.getString(R.string.settings_storage_usage, byteToString(cache.cacheFolder.size()))
|
||||
|
||||
onPreferenceClickListener = this@ManageStorageFragment
|
||||
*/}
|
||||
|
||||
with (findPreference<Preference>("delete_downloads")) {
|
||||
this ?: return@with
|
||||
|
||||
val dir = downloadManager.downloadFolder
|
||||
|
||||
summary = context.getString(R.string.settings_storage_usage, byteToString(0))
|
||||
job?.cancel()
|
||||
job = CoroutineScope(Dispatchers.IO).launch {
|
||||
var size = 0L
|
||||
|
||||
dir.walk().forEach {
|
||||
launch(Dispatchers.Main) {
|
||||
summary = context.getString(R.string.settings_storage_usage, byteToString(size))
|
||||
}
|
||||
|
||||
size += it.length()
|
||||
}
|
||||
}
|
||||
|
||||
onPreferenceClickListener = this@ManageStorageFragment
|
||||
}
|
||||
/*
|
||||
with (findPreference<Preference>("clear_history")) {
|
||||
this ?: return@with
|
||||
|
||||
summary = context.getString(R.string.settings_clear_history_summary, histories.map.values.sumOf { it.size })
|
||||
|
||||
onPreferenceClickListener = this@ManageStorageFragment
|
||||
}*/
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
job?.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.andrognito.pinlockview.PinLockListener
|
||||
import xyz.quaver.pupil.databinding.PinLockFragmentBinding
|
||||
|
||||
class PINLockFragment : Fragment() {
|
||||
|
||||
private var _binding: PinLockFragmentBinding? = null
|
||||
val binding get() = _binding!!
|
||||
|
||||
var onPINEntered: ((String) -> Unit)? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = PinLockFragmentBinding.inflate(inflater, container, false)
|
||||
|
||||
binding.pinLockView.attachIndicatorDots(binding.indicatorDots)
|
||||
binding.pinLockView.setPinLockListener(object: PinLockListener {
|
||||
override fun onComplete(p0: String?) {
|
||||
onPINEntered?.invoke(p0 ?: "")
|
||||
}
|
||||
|
||||
override fun onEmpty() {}
|
||||
override fun onPinChange(p0: Int, p1: String?) {}
|
||||
})
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2019 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.andrognito.patternlockview.PatternLockView
|
||||
import com.andrognito.patternlockview.listener.PatternLockViewListener
|
||||
import com.andrognito.patternlockview.utils.PatternLockUtils
|
||||
import xyz.quaver.pupil.databinding.PatternLockFragmentBinding
|
||||
|
||||
class PatternLockFragment : Fragment() {
|
||||
|
||||
private var _binding: PatternLockFragmentBinding? = null
|
||||
val binding get() = _binding!!
|
||||
|
||||
var onPatternDrawn: ((String) -> Unit)? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = PatternLockFragmentBinding.inflate(inflater, container, false)
|
||||
binding.patternLockView.addPatternLockListener(object: PatternLockViewListener {
|
||||
override fun onComplete(pattern: MutableList<PatternLockView.Dot>?) {
|
||||
val password = PatternLockUtils.patternToMD5(binding.patternLockView, pattern)
|
||||
onPatternDrawn?.invoke(password)
|
||||
}
|
||||
|
||||
override fun onCleared() {}
|
||||
override fun onProgress(progressPattern: MutableList<PatternLockView.Dot>?) {}
|
||||
override fun onStarted() {}
|
||||
})
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.preference.*
|
||||
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.instance
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.io.util.getChild
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.ui.SettingsActivity
|
||||
import xyz.quaver.pupil.ui.dialog.*
|
||||
import xyz.quaver.pupil.util.*
|
||||
import java.util.*
|
||||
|
||||
class SettingsFragment :
|
||||
PreferenceFragmentCompat(),
|
||||
Preference.OnPreferenceClickListener,
|
||||
Preference.OnPreferenceChangeListener,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||
DIAware {
|
||||
|
||||
override val di by closestDI()
|
||||
|
||||
private val downloadManager: DownloadManager by instance()
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
val lockManager = LockManager(requireContext())
|
||||
|
||||
findPreference<Preference>("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) {
|
||||
getString(R.string.settings_lock_none)
|
||||
} else {
|
||||
lockManager.locks?.joinToString(", ") {
|
||||
when(it.type) {
|
||||
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
||||
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
||||
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreferenceClick(preference: Preference?): Boolean {
|
||||
with (preference) {
|
||||
this ?: return false
|
||||
|
||||
when (key) {
|
||||
"app_version" -> {
|
||||
checkUpdate(activity as SettingsActivity, true)
|
||||
}
|
||||
"download_folder" -> {
|
||||
DownloadLocationDialogFragment().show(parentFragmentManager, "Download Location Dialog")
|
||||
}
|
||||
"proxy" -> {
|
||||
ProxyDialogFragment().show(parentFragmentManager, "Proxy Dialog")
|
||||
}
|
||||
"user_id" -> {
|
||||
(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip(
|
||||
ClipData.newPlainText("user_id", Preferences.get<String>("user_id"))
|
||||
)
|
||||
Toast.makeText(context, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
|
||||
with (preference) {
|
||||
this ?: return false
|
||||
|
||||
when (key) {
|
||||
"nomedia" -> {
|
||||
val create = (newValue as? Boolean) ?: return false
|
||||
|
||||
return kotlin.runCatching {
|
||||
val nomedia = downloadManager.downloadFolder.getChild(".nomedia")
|
||||
|
||||
if (create)
|
||||
nomedia.createNewFile()
|
||||
else
|
||||
nomedia.delete()
|
||||
}.getOrDefault(false)
|
||||
}
|
||||
"dark_mode" -> {
|
||||
AppCompatDelegate.setDefaultNightMode(when (newValue as Boolean) {
|
||||
true -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
false -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
})
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
key ?: return
|
||||
|
||||
with (findPreference<Preference>(key)) {
|
||||
this ?: return
|
||||
|
||||
when (key) {
|
||||
"proxy" -> {
|
||||
summary = context?.let { getProxyInfo().type.name }
|
||||
}
|
||||
"download_folder" -> {
|
||||
summary = FileX(context, Preferences.get<String>("download_folder")).canonicalPath
|
||||
}
|
||||
"download_folder_name" -> {
|
||||
summary = Preferences["download_folder_name", "[-id-] -title-"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||
|
||||
Preferences.registerOnSharedPreferenceChangeListener(this)
|
||||
|
||||
initPreferences()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Preferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun initPreferences() {
|
||||
for (i in 0 until preferenceScreen.preferenceCount) {
|
||||
|
||||
preferenceScreen.getPreference(i).run {
|
||||
if (this is PreferenceCategory)
|
||||
(0 until preferenceCount).map { getPreference(it) }
|
||||
else
|
||||
listOf(this)
|
||||
}.forEach { preference ->
|
||||
with (preference) with@{
|
||||
|
||||
when (key) {
|
||||
"app_version" -> {
|
||||
val manager = requireContext().packageManager
|
||||
val info = manager.getPackageInfo(requireContext().packageName, 0)
|
||||
summary = requireContext().getString(R.string.settings_app_version_description, info.versionName)
|
||||
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"download_folder_name" -> {
|
||||
summary = Preferences["download_folder_name", "[-id-] -title-"]
|
||||
|
||||
setOnPreferenceClickListener {
|
||||
DownloadFolderNameDialogFragment().show(requireActivity().supportFragmentManager, "Download Location Dialog")
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
"download_folder" -> {
|
||||
summary = FileX(context, Preferences.get<String>("download_folder")).canonicalPath
|
||||
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"nomedia" -> {
|
||||
(this as SwitchPreferenceCompat).isChecked = kotlin.runCatching {
|
||||
downloadManager.downloadFolder.getChild(".nomedia").exists()
|
||||
}.getOrDefault(false)
|
||||
|
||||
onPreferenceChangeListener = this@SettingsFragment
|
||||
}
|
||||
"app_lock" -> {
|
||||
val lockManager = LockManager(requireContext())
|
||||
summary =
|
||||
if (lockManager.locks.isNullOrEmpty()) {
|
||||
getString(R.string.settings_lock_none)
|
||||
} else {
|
||||
lockManager.locks?.joinToString(", ") {
|
||||
when (it.type) {
|
||||
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
||||
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
||||
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"proxy" -> {
|
||||
summary = getProxyInfo().type.name
|
||||
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"dark_mode" -> {
|
||||
onPreferenceChangeListener = this@SettingsFragment
|
||||
}
|
||||
"old_import_galleries" -> {
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"user_id" -> {
|
||||
summary = Preferences.get<String>("user_id")
|
||||
onPreferenceClickListener = this@SettingsFragment
|
||||
}
|
||||
"oss" -> {
|
||||
setOnPreferenceClickListener {
|
||||
context?.startActivity(Intent(context, OssLicensesMenuActivity::class.java))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2021 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import io.ktor.client.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.x.closestDI
|
||||
import org.kodein.di.direct
|
||||
import org.kodein.di.instance
|
||||
import xyz.quaver.pupil.ui.dialog.DefaultQueryDialogFragment
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import xyz.quaver.pupil.util.getAvailableLanguages
|
||||
import xyz.quaver.pupil.util.updateTranslations
|
||||
import java.util.*
|
||||
|
||||
class SourceSettingsFragment(private val source: String) :
|
||||
PreferenceFragmentCompat(),
|
||||
Preference.OnPreferenceClickListener,
|
||||
Preference.OnPreferenceChangeListener,
|
||||
DIAware {
|
||||
|
||||
override val di by closestDI()
|
||||
|
||||
private val client: HttpClient by instance()
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
/*setPreferencesFromResource(direct.instance<SourcePreferenceIDs>().toMap()[source]!!, rootKey)*/
|
||||
|
||||
initPreferences()
|
||||
}
|
||||
|
||||
override fun onPreferenceClick(preference: Preference?): Boolean {
|
||||
with (preference) {
|
||||
this ?: return false
|
||||
|
||||
when (key) {
|
||||
"hitomi.default_query" -> {
|
||||
DefaultQueryDialogFragment().apply {
|
||||
onPositiveButtonClickListener = { newTags ->
|
||||
Preferences["hitomi.default_query"] = newTags.toString()
|
||||
summary = newTags.toString()
|
||||
}
|
||||
}.show(parentFragmentManager, "Default Query Dialog")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
|
||||
with (preference) {
|
||||
this ?: return false
|
||||
|
||||
when (key) {
|
||||
"hitomi.tag_translation" -> {
|
||||
updateTranslations(client)
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun initPreferences() {
|
||||
for (i in 0 until preferenceScreen.preferenceCount) {
|
||||
|
||||
preferenceScreen.getPreference(i).run {
|
||||
if (this is PreferenceCategory)
|
||||
(0 until preferenceCount).map { getPreference(it) }
|
||||
else
|
||||
listOf(this)
|
||||
}.forEach { preference ->
|
||||
with (preference) {
|
||||
when (key) {
|
||||
"hitomi.default_query" -> {
|
||||
summary = Preferences.get<String>(key)
|
||||
|
||||
onPreferenceClickListener = this@SourceSettingsFragment
|
||||
}
|
||||
|
||||
"hitomi.tag_translation" -> {
|
||||
this as ListPreference
|
||||
|
||||
isEnabled = false
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
kotlin.runCatching {
|
||||
val languages = getAvailableLanguages(client).distinct().toTypedArray()
|
||||
|
||||
entries = languages.map { Locale(it).let { loc -> loc.getDisplayLanguage(loc) } }.toTypedArray()
|
||||
entryValues = languages
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPreferenceChangeListener = this@SourceSettingsFragment
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.AttributeSet
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.sources.Hitomi
|
||||
import xyz.quaver.pupil.types.FavoriteHistorySwitch
|
||||
import xyz.quaver.pupil.types.HistorySuggestion
|
||||
import xyz.quaver.pupil.types.LoadingSuggestion
|
||||
import xyz.quaver.pupil.types.NoResultSuggestion
|
||||
|
||||
class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
xyz.quaver.floatingsearchview.FloatingSearchView(context, attrs),
|
||||
FloatingSearchView.OnSearchListener,
|
||||
TextWatcher
|
||||
{
|
||||
private val searchInputView = findViewById<SearchInputView>(R.id.search_bar_text)
|
||||
|
||||
var onHistoryDeleteClickedListener: ((String) -> Unit)? = null
|
||||
var onFavoriteHistorySwitchClickListener: (() -> Unit)? = null
|
||||
|
||||
var onSuggestionBinding: ((SearchSuggestionItemBinding, SearchSuggestion) -> Unit)? = null
|
||||
|
||||
init {
|
||||
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI or searchInputView.imeOptions
|
||||
|
||||
searchInputView.addTextChangedListener(this)
|
||||
onSearchListener = this
|
||||
onBindSuggestionCallback = { binding, item, _ ->
|
||||
onBindSuggestion(binding, item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
s ?: return
|
||||
|
||||
if (s.any { it.isUpperCase() })
|
||||
s.replace(0, s.length, s.toString().lowercase())
|
||||
}
|
||||
|
||||
override fun onSuggestionClicked(searchSuggestion: SearchSuggestion?) {
|
||||
when (searchSuggestion) {
|
||||
is Hitomi.TagSuggestion -> {
|
||||
val tag = "${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")}"
|
||||
with (searchInputView.text!!) {
|
||||
delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ') + 1, length)
|
||||
|
||||
if (!this.contains(tag))
|
||||
append("$tag ")
|
||||
}
|
||||
}
|
||||
is HistorySuggestion -> {
|
||||
with (searchInputView.text!!) {
|
||||
clear()
|
||||
append(searchSuggestion.body)
|
||||
}
|
||||
}
|
||||
is FavoriteHistorySwitch -> onFavoriteHistorySwitchClickListener?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSearchAction(currentQuery: String?) {}
|
||||
|
||||
private fun onBindSuggestion(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
|
||||
when(item) {
|
||||
is FavoriteHistorySwitch -> {
|
||||
binding.leftIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.swap_horizontal, context.theme))
|
||||
}
|
||||
is LoadingSuggestion -> {
|
||||
binding.leftIcon.setImageDrawable(CircularProgressDrawable(context).also {
|
||||
it.setStyle(CircularProgressDrawable.DEFAULT)
|
||||
it.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(context, R.color.colorAccent), PorterDuff.Mode.SRC_IN)
|
||||
it.start()
|
||||
})
|
||||
}
|
||||
is NoResultSuggestion -> {
|
||||
binding.leftIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.close, context.theme))
|
||||
}
|
||||
else -> {
|
||||
onSuggestionBinding?.invoke(binding, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,471 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.ui.view;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Vibrator;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.NestedScrollingChild;
|
||||
import androidx.core.view.NestedScrollingChildHelper;
|
||||
import androidx.core.view.NestedScrollingParent;
|
||||
import androidx.core.view.NestedScrollingParentHelper;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.widget.TextViewCompat;
|
||||
|
||||
import xyz.quaver.pupil.R;
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public class SwipePageTurnView extends ViewGroup implements NestedScrollingChild, NestedScrollingParent {
|
||||
|
||||
private static final int PAGE_TURN_LAYOUT_SIZE = 48;
|
||||
private static final int PAGE_TURN_ANIM_DURATION = 500;
|
||||
private static final int PREV_OFFSET = 64;
|
||||
private static final int RIPPLE_GIVE = 4;
|
||||
|
||||
private final float adjustedPageTurnLayoutSize;
|
||||
private final float adjustedPrevOffset;
|
||||
private final float adjustedRippleGive;
|
||||
|
||||
final private NestedScrollingParentHelper mNestedScrollingParentHelper;
|
||||
final private NestedScrollingChildHelper mNestedScrollingChildHelper;
|
||||
|
||||
final private Vibrator mVibrator;
|
||||
|
||||
private View mTarget;
|
||||
|
||||
private TextView mPrev;
|
||||
private TextView mNext;
|
||||
|
||||
private final Paint mRipplePaint = new Paint();
|
||||
private final Rect mRippleBound = new Rect();
|
||||
|
||||
private int mRippleSize = 0;
|
||||
private final int mRippleTargetSize;
|
||||
private final ValueAnimator mRippleAnimator = new ValueAnimator();
|
||||
|
||||
private int mCurrentOverScroll = 0;
|
||||
|
||||
private int mCurrentPage = 1;
|
||||
private boolean mShowPrev;
|
||||
private boolean mShowNext;
|
||||
|
||||
private OnPageTurnListener mOnPageTurnListener;
|
||||
|
||||
public SwipePageTurnView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SwipePageTurnView(@NonNull Context context, AttributeSet attr) {
|
||||
this(context, attr, 0);
|
||||
}
|
||||
|
||||
public SwipePageTurnView(@NonNull Context context, AttributeSet attr, int defStyle) {
|
||||
super(context, attr, defStyle);
|
||||
|
||||
setWillNotDraw(false);
|
||||
|
||||
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
|
||||
adjustedPageTurnLayoutSize = PAGE_TURN_LAYOUT_SIZE * metrics.density;
|
||||
adjustedPrevOffset = PREV_OFFSET * metrics.density;
|
||||
adjustedRippleGive = RIPPLE_GIVE * metrics.density;
|
||||
|
||||
mRippleTargetSize = metrics.widthPixels;
|
||||
|
||||
mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
|
||||
mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
|
||||
|
||||
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
|
||||
mRippleAnimator.addUpdateListener(animation -> {
|
||||
mRippleSize = (int) animation.getAnimatedValue();
|
||||
invalidate();
|
||||
});
|
||||
mRippleAnimator.setDuration(PAGE_TURN_ANIM_DURATION);
|
||||
|
||||
initPageTurnView();
|
||||
}
|
||||
|
||||
public void setCurrentPage(int currentPage, boolean showNext) {
|
||||
mCurrentPage = currentPage;
|
||||
|
||||
mShowPrev = currentPage > 1;
|
||||
mShowNext = showNext;
|
||||
|
||||
mPrev.setText(getContext().getString(R.string.main_move_to_page, mCurrentPage-1));
|
||||
mNext.setText(getContext().getString(R.string.main_move_to_page, mCurrentPage+1));
|
||||
}
|
||||
|
||||
public void setOnPageTurnListener(OnPageTurnListener listener) {
|
||||
mOnPageTurnListener = listener;
|
||||
}
|
||||
|
||||
private void initPageTurnView() {
|
||||
TextView prev = new TextView(getContext());
|
||||
TextView next = new TextView(getContext());
|
||||
|
||||
prev.setGravity(Gravity.CENTER_VERTICAL);
|
||||
next.setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
prev.setCompoundDrawablesWithIntrinsicBounds(R.drawable.navigate_prev, 0, 0, 0);
|
||||
next.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.navigate_next, 0);
|
||||
|
||||
TextViewCompat.setCompoundDrawableTintList(prev, AppCompatResources.getColorStateList(getContext(), R.color.colorAccent));
|
||||
TextViewCompat.setCompoundDrawableTintList(next, AppCompatResources.getColorStateList(getContext(), R.color.colorAccent));
|
||||
|
||||
prev.setVisibility(View.INVISIBLE);
|
||||
next.setVisibility(View.INVISIBLE);
|
||||
|
||||
mPrev = prev;
|
||||
mNext = next;
|
||||
|
||||
addView(mPrev);
|
||||
addView(mNext);
|
||||
|
||||
setCurrentPage(1, false);
|
||||
}
|
||||
|
||||
private void ensureTarget() {
|
||||
if (mTarget == null) {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
View child = getChildAt(i);
|
||||
|
||||
if (!child.equals(mNext) && !child.equals(mPrev)) {
|
||||
mTarget = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
final int width = getMeasuredWidth();
|
||||
final int height = getMeasuredHeight();
|
||||
|
||||
if (getChildCount() == 0)
|
||||
return;
|
||||
if (mTarget == null)
|
||||
ensureTarget();
|
||||
if (mTarget == null)
|
||||
return;
|
||||
|
||||
mTarget.layout(
|
||||
getPaddingLeft(),
|
||||
getPaddingTop(),
|
||||
width - getPaddingRight(),
|
||||
height - getPaddingBottom()
|
||||
);
|
||||
|
||||
final int prevWidth = mPrev.getMeasuredWidth();
|
||||
mPrev.layout(
|
||||
width / 2 - prevWidth / 2,
|
||||
getPaddingTop() + (int) adjustedPrevOffset,
|
||||
width / 2 + prevWidth / 2,
|
||||
getPaddingTop() + (int) adjustedPrevOffset + mPrev.getMeasuredHeight()
|
||||
);
|
||||
|
||||
final int nextWidth = mNext.getMeasuredWidth();
|
||||
mNext.layout(
|
||||
width / 2 - nextWidth / 2,
|
||||
height - getPaddingBottom() - mNext.getMeasuredHeight(),
|
||||
width / 2 + nextWidth / 2,
|
||||
height - getPaddingBottom()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (mTarget == null)
|
||||
ensureTarget();
|
||||
if (mTarget == null)
|
||||
return;
|
||||
|
||||
mTarget.measure(
|
||||
MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY)
|
||||
);
|
||||
|
||||
mPrev.measure(
|
||||
MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec((int) adjustedPageTurnLayoutSize, MeasureSpec.EXACTLY)
|
||||
);
|
||||
|
||||
mNext.measure(
|
||||
MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec((int) adjustedPageTurnLayoutSize, MeasureSpec.EXACTLY)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (mCurrentOverScroll == 0)
|
||||
return;
|
||||
|
||||
if (mCurrentOverScroll > 0) {
|
||||
mRippleBound.set(
|
||||
getPaddingLeft(),
|
||||
(int) (getPaddingTop() - adjustedRippleGive),
|
||||
getMeasuredWidth() - getPaddingRight(),
|
||||
(int) (getPaddingTop() + adjustedPrevOffset + mPrev.getMeasuredHeight() + adjustedRippleGive)
|
||||
);
|
||||
}
|
||||
|
||||
if (mCurrentOverScroll < 0) {
|
||||
final int height = getMeasuredHeight();
|
||||
mRippleBound.set(
|
||||
getPaddingLeft(),
|
||||
(int) (height - getPaddingBottom() - mNext.getMeasuredHeight() - adjustedRippleGive),
|
||||
getMeasuredWidth() - getPaddingRight(),
|
||||
height - getPaddingBottom()
|
||||
);
|
||||
}
|
||||
|
||||
mRipplePaint.reset();
|
||||
mRipplePaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
|
||||
switch (currentNightMode) {
|
||||
case Configuration.UI_MODE_NIGHT_YES:
|
||||
mRipplePaint.setColor(ContextCompat.getColor(getContext(), R.color.material_light_blue_700));
|
||||
break;
|
||||
case Configuration.UI_MODE_NIGHT_NO:
|
||||
mRipplePaint.setColor(ContextCompat.getColor(getContext(), R.color.material_light_blue_300));
|
||||
break;
|
||||
}
|
||||
|
||||
canvas.drawCircle(
|
||||
(mRippleBound.left + mRippleBound.right) / 2F,
|
||||
mCurrentOverScroll > 0 ? mRippleBound.bottom : mRippleBound.top,
|
||||
mRippleSize,
|
||||
mRipplePaint
|
||||
);
|
||||
}
|
||||
|
||||
private void onOverscroll(int overscroll) {
|
||||
if (mTarget == null)
|
||||
ensureTarget();
|
||||
if (mTarget == null)
|
||||
return;
|
||||
|
||||
mCurrentOverScroll = overscroll;
|
||||
|
||||
if (overscroll > 0) {
|
||||
mPrev.setVisibility(View.VISIBLE);
|
||||
mNext.setVisibility(View.INVISIBLE);
|
||||
} else if (overscroll < 0) {
|
||||
mPrev.setVisibility(View.INVISIBLE);
|
||||
mNext.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mPrev.setVisibility(View.INVISIBLE);
|
||||
mNext.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (Math.abs(overscroll) >= adjustedPageTurnLayoutSize) {
|
||||
if (!mRippleAnimator.isStarted() && mRippleSize != mRippleTargetSize) {
|
||||
mVibrator.vibrate(10);
|
||||
|
||||
mRippleAnimator.setIntValues(mRippleSize, mRippleTargetSize);
|
||||
mRippleAnimator.start();
|
||||
}
|
||||
} else {
|
||||
if (!mRippleAnimator.isStarted() && mRippleSize != 0) {
|
||||
mRippleAnimator.setIntValues(mRippleSize, 0);
|
||||
mRippleAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
float clippedOverScrollTop = (overscroll > 0 ? 1 : -1) * Math.min(Math.abs(overscroll), adjustedPageTurnLayoutSize);
|
||||
mTarget.setTranslationY(clippedOverScrollTop);
|
||||
}
|
||||
|
||||
private void onOverscrollEnd(int overscroll) {
|
||||
if (mTarget == null)
|
||||
ensureTarget();
|
||||
if (mTarget == null)
|
||||
return;
|
||||
|
||||
mRippleAnimator.cancel();
|
||||
mRippleAnimator.setIntValues(mRippleSize, 0);
|
||||
mRippleAnimator.start();
|
||||
|
||||
mPrev.setVisibility(View.INVISIBLE);
|
||||
mNext.setVisibility(View.INVISIBLE);
|
||||
|
||||
ViewCompat.animate(mTarget)
|
||||
.setDuration(PAGE_TURN_ANIM_DURATION)
|
||||
.setInterpolator(new DecelerateInterpolator())
|
||||
.translationY(0);
|
||||
|
||||
if (Math.abs(overscroll) > adjustedPageTurnLayoutSize && mOnPageTurnListener != null) {
|
||||
if (overscroll > 0)
|
||||
mOnPageTurnListener.onPrev(mCurrentPage-1);
|
||||
if (overscroll < 0)
|
||||
mOnPageTurnListener.onNext(mCurrentPage+1);
|
||||
}
|
||||
}
|
||||
|
||||
// NestedScrollingParent
|
||||
|
||||
private int mTotalUnconsumed = 0;
|
||||
|
||||
@Override
|
||||
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
|
||||
return isEnabled() && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedScrollAccepted(View child, View target, int axes) {
|
||||
mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
|
||||
startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
|
||||
|
||||
mTotalUnconsumed = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
|
||||
if (mTotalUnconsumed != 0 && dy > 0 == mTotalUnconsumed > 0) {
|
||||
if (Math.abs(dy) > Math.abs(mTotalUnconsumed)) {
|
||||
consumed[1] = dy - mTotalUnconsumed;
|
||||
mTotalUnconsumed = 0;
|
||||
} else {
|
||||
mTotalUnconsumed -= dy;
|
||||
consumed[1] = dy;
|
||||
}
|
||||
|
||||
onOverscroll(mTotalUnconsumed);
|
||||
}
|
||||
|
||||
final int[] parentConsumed = new int[2];
|
||||
if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
|
||||
consumed[0] += parentConsumed[0];
|
||||
consumed[1] += parentConsumed[1];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
|
||||
final int[] mParentOffsetInWindow = new int[2];
|
||||
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, mParentOffsetInWindow);
|
||||
|
||||
final int dy = dyUnconsumed + mParentOffsetInWindow[1];
|
||||
|
||||
if (mTotalUnconsumed == 0 && ((dy < 0 && !mShowPrev) || (dy > 0 && !mShowNext)))
|
||||
return;
|
||||
|
||||
if (dy != 0) {
|
||||
mTotalUnconsumed -= dy;
|
||||
onOverscroll(mTotalUnconsumed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopNestedScroll(View child) {
|
||||
mNestedScrollingParentHelper.onStopNestedScroll(child);
|
||||
|
||||
if (Math.abs(mTotalUnconsumed) > 0) {
|
||||
onOverscrollEnd(mTotalUnconsumed);
|
||||
mTotalUnconsumed = 0;
|
||||
}
|
||||
|
||||
stopNestedScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
|
||||
return dispatchNestedPreFling(velocityX, velocityY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
|
||||
return dispatchNestedFling(velocityX, velocityY, consumed);
|
||||
}
|
||||
|
||||
// NestedScrollingChild
|
||||
|
||||
@Override
|
||||
public void setNestedScrollingEnabled(boolean enabled) {
|
||||
mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNestedScrollingEnabled() {
|
||||
return mNestedScrollingChildHelper.isNestedScrollingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startNestedScroll(int axes) {
|
||||
return mNestedScrollingChildHelper.startNestedScroll(axes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopNestedScroll() {
|
||||
mNestedScrollingChildHelper.stopNestedScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNestedScrollingParent() {
|
||||
return mNestedScrollingChildHelper.hasNestedScrollingParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
|
||||
return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {
|
||||
return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
|
||||
return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
|
||||
return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
|
||||
}
|
||||
|
||||
public interface OnPageTurnListener {
|
||||
void onPrev(int page);
|
||||
void onNext(int page);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import org.kodein.di.direct
|
||||
import org.kodein.di.instance
|
||||
import org.kodein.log.LoggerFactory
|
||||
import org.kodein.log.newLogger
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.pupil.sources.*
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import xyz.quaver.pupil.util.source
|
||||
@@ -58,7 +57,7 @@ class MainViewModel(app: Application) : AndroidViewModel(app), DIAware {
|
||||
direct.source(it)
|
||||
}
|
||||
private var sourceFactory: (String) -> Source = defaultSourceFactory
|
||||
var source by mutableStateOf(sourceFactory("hiyobi.io"))
|
||||
var source by mutableStateOf(sourceFactory("hitomi.la"))
|
||||
private set
|
||||
|
||||
var sortModeIndex by mutableStateOf(0)
|
||||
@@ -74,9 +73,6 @@ class MainViewModel(app: Application) : AndroidViewModel(app), DIAware {
|
||||
ceil(it / perPage.toDouble()).roundToInt()
|
||||
}
|
||||
|
||||
private val _suggestions = MutableLiveData<List<SearchSuggestion>>()
|
||||
val suggestions: LiveData<List<SearchSuggestion>> = _suggestions
|
||||
|
||||
fun setSourceAndReset(sourceName: String) {
|
||||
source = sourceFactory(sourceName)
|
||||
sortModeIndex = 0
|
||||
@@ -153,21 +149,6 @@ class MainViewModel(app: Application) : AndroidViewModel(app), DIAware {
|
||||
}
|
||||
}
|
||||
|
||||
fun suggestion() {
|
||||
suggestionJob?.cancel()
|
||||
|
||||
_suggestions.value = mutableListOf()
|
||||
|
||||
suggestionJob = viewModelScope.launch {
|
||||
@SuppressLint("NullSafeMutableLiveData")
|
||||
_suggestions.value = withContext(Dispatchers.IO) {
|
||||
kotlin.runCatching {
|
||||
source.suggestion(query)
|
||||
}.getOrElse { emptyList() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if backpress is consumed, false otherwise
|
||||
*/
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.util
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import xyz.quaver.pupil.R
|
||||
|
||||
class ItemClickSupport(private val recyclerView: RecyclerView) {
|
||||
|
||||
var onItemClickListener: ((RecyclerView, Int, View) -> Unit)? = null
|
||||
var onItemLongClickListener: ((RecyclerView, Int, View) -> Boolean)? = null
|
||||
|
||||
init {
|
||||
recyclerView.apply {
|
||||
setTag(R.id.item_click_support, this)
|
||||
addOnChildAttachStateChangeListener(object: RecyclerView.OnChildAttachStateChangeListener {
|
||||
override fun onChildViewAttachedToWindow(view: View) {
|
||||
onItemClickListener?.let { listener ->
|
||||
view.setOnClickListener {
|
||||
recyclerView.getChildViewHolder(view).let { holder ->
|
||||
listener.invoke(recyclerView, holder.adapterPosition, view)
|
||||
}
|
||||
}
|
||||
}
|
||||
onItemLongClickListener?.let { listener ->
|
||||
view.setOnLongClickListener {
|
||||
recyclerView.getChildViewHolder(view).let { holder ->
|
||||
listener.invoke(recyclerView, holder.adapterPosition, view)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChildViewDetachedFromWindow(view: View) {
|
||||
// Do Nothing
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun detach() {
|
||||
recyclerView.apply {
|
||||
clearOnChildAttachStateChangeListeners()
|
||||
setTag(R.id.item_click_support, null)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun addTo(view: RecyclerView) = view.let { removeFrom(it); ItemClickSupport(it) }
|
||||
fun removeFrom(view: RecyclerView) = (view.tag as? ItemClickSupport)?.detach()
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2020 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="300"
|
||||
android:fromXDelta="0"
|
||||
android:interpolator="@anim/shake_cycle"
|
||||
android:toXDelta="10" />
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2020 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:cycles="3" />
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2020 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="@android:color/darker_gray"/>
|
||||
<item android:color="@color/colorPrimary"/>
|
||||
</selector>
|
||||
|
Before Width: | Height: | Size: 325 B |
|
Before Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 571 B |
|
Before Width: | Height: | Size: 279 B |
|
Before Width: | Height: | Size: 469 B |
|
Before Width: | Height: | Size: 235 B |
|
Before Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 222 B |
|
Before Width: | Height: | Size: 352 B |
|
Before Width: | Height: | Size: 383 B |
|
Before Width: | Height: | Size: 125 B |
|
Before Width: | Height: | Size: 676 B |
|
Before Width: | Height: | Size: 314 B |
|
Before Width: | Height: | Size: 628 B |
|
Before Width: | Height: | Size: 550 B |
|
Before Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 1000 B |
|
Before Width: | Height: | Size: 395 B |
|
Before Width: | Height: | Size: 914 B |
@@ -1,4 +0,0 @@
|
||||
<!--drawable/account_group.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M12 5.5A3.5 3.5 0 0 1 15.5 9a3.5 3.5 0 0 1-3.5 3.5A3.5 3.5 0 0 1 8.5 9 3.5 3.5 0 0 1 12 5.5M5 8c0.56 0 1.08 0.15 1.53 0.42-0.15 1.43 0.27 2.85 1.13 3.96C7.16 13.34 6.16 14 5 14a3 3 0 0 1-3-3 3 3 0 0 1 3-3m14 0a3 3 0 0 1 3 3 3 3 0 0 1-3 3c-1.16 0-2.16-0.66-2.66-1.62 0.86-1.11 1.28-2.53 1.13-3.96C17.92 8.15 18.44 8 19 8M5.5 18.25c0-2.07 2.91-3.75 6.5-3.75s6.5 1.68 6.5 3.75V20h-13v-1.75M0 20v-1.5c0-1.39 1.89-2.56 4.45-2.9-0.59 0.68-0.95 1.62-0.95 2.65V20H0m24 0h-3.5v-1.75c0-1.03-0.36-1.97-0.95-2.65 2.56 0.34 4.45 1.51 4.45 2.9V20z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/account_star.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M15 14c-2.67 0-8 1.33-8 4v2h16v-2c0-2.67-5.33-4-8-4m0-2a4 4 0 0 0 4-4 4 4 0 0 0-4-4 4 4 0 0 0-4 4 4 4 0 0 0 4 4M5 13.28l2.45 1.49-0.65-2.81L9 10.08 6.11 9.83 5 7.19 3.87 9.83 1 10.08l2.18 1.88-0.68 2.81L5 13.28z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/arrow_right.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"/>
|
||||
</vector>
|
||||
@@ -1,14 +0,0 @@
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt" xmlns:tools="http://schemas.android.com/tools" tools:ignore="newApi">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:name="vector" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:name="path" android:pathData="M 12 15.39 L 8.24 17.66 L 9.23 13.38 L 5.91 10.5 L 10.29 10.13 L 12 6.09 L 13.71 10.13 L 18.09 10.5 L 14.77 13.38 L 15.76 17.66 M 22 9.24 L 14.81 8.63 L 12 2 L 9.19 8.63 L 2 9.24 L 7.45 13.97 L 5.82 21 L 12 17.27 L 18.18 21 L 16.54 13.97 L 22 9.24 Z" android:fillColor="@color/material_orange_500"/>
|
||||
<clip-path android:name="clip" android:pathData="M 2 21 L 2 21 L 22 21 L 22 21 Z"/>
|
||||
<path android:name="path_1" android:pathData="M 12 17.27 L 18.18 21 L 16.54 13.97 L 22 9.24 L 14.81 8.62 L 12 2 L 9.19 8.62 L 2 9.24 L 7.45 13.97 L 5.82 21 L 12 17.27 Z" android:fillColor="@color/material_orange_500"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="clip">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator android:propertyName="pathData" android:duration="500" android:valueFrom="M 2 21 L 2 21 L 22 21 L 22 21 Z" android:valueTo="M 2 2 L 2 21 L 22 21 L 22 2 Z" android:valueType="pathType" android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/backspace_outline.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M19 15.59L17.59 17 14 13.41 10.41 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59M22 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H7c-0.69 0-1.23-0.36-1.59-0.89L0 12l5.41-8.12C5.77 3.35 6.31 3 7 3h15m0 2H7l-4.72 7L7 19h15V5z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/book_open.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M13 12h7v1.5h-7m0-4h7V11h-7m0 3.5h7V16h-7m8-12H3a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2m0 15h-9V6h9"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/brush.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M20.71 4.63l-1.34-1.34c-0.37-0.39-1.02-0.39-1.41 0L9 12.25 11.75 15l8.96-8.96c0.39-0.39 0.39-1.04 0-1.41M7 14a3 3 0 0 0-3 3c0 1.31-1.16 2-2 2 0.92 1.22 2.5 2 4 2a4 4 0 0 0 4-4 3 3 0 0 0-3-3z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/cancel.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M12 2a10 10 0 0 1 10 10 10 10 0 0 1-10 10A10 10 0 0 1 2 12 10 10 0 0 1 12 2m0 2a8 8 0 0 0-8 8c0 1.85 0.63 3.55 1.68 4.91L16.91 5.68C15.55 4.63 13.85 4 12 4m0 16a8 8 0 0 0 8-8c0-1.85-0.63-3.55-1.68-4.91L7.09 18.32C8.45 19.37 10.15 20 12 20z"/>
|
||||
</vector>
|
||||
@@ -1,22 +0,0 @@
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2021 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<!--drawable/clock_end.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M12 1C8.14 1 5 4.14 5 8a7 7 0 0 0 7 7c3.86 0 7-3.13 7-7 0-3.86-3.14-7-7-7m0 2.15c2.67 0 4.85 2.17 4.85 4.85 0 2.68-2.18 4.85-4.85 4.85A4.85 4.85 0 0 1 7.15 8 4.85 4.85 0 0 1 12 3.15M11 5v3.69l3.19 1.84 0.75-1.3-2.44-1.41V5M15 16v3H3v2h12v3l4-4m0 0v4h2v-8h-2"/>
|
||||
</vector>
|
||||
@@ -1,22 +0,0 @@
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2021 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<!--drawable/clock_start.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M12 1C8.14 1 5 4.14 5 8a7 7 0 0 0 7 7c3.86 0 7-3.13 7-7 0-3.86-3.14-7-7-7m0 2.15c2.67 0 4.85 2.17 4.85 4.85 0 2.68-2.18 4.85-4.85 4.85A4.85 4.85 0 0 1 7.15 8 4.85 4.85 0 0 1 12 3.15M11 5v3.69l3.19 1.84 0.75-1.3-2.44-1.41V5M4 16v8h2v-3h12v3l4-4-4-4v3H6v-3"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/close.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/delete.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M19 4h-3.5l-1-1h-5l-1 1H5v2h14M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6v12z"/>
|
||||
</vector>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2020 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
|
||||
<solid
|
||||
android:color="@color/colorAccent"/>
|
||||
|
||||
<size
|
||||
android:width="24dp"
|
||||
android:height="24dp"/>
|
||||
</shape>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!-- drawable/eye.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z" />
|
||||
</vector>
|
||||
@@ -1,44 +0,0 @@
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2020 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="15dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="15">
|
||||
<path
|
||||
android:pathData="M21.61,5.4C14.21,13.39 7.16,13.37 0.43,5.32"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="?attr/colorControlNormal"/>
|
||||
<path
|
||||
android:pathData="M1.32,9.8L3.03,7.8"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="?attr/colorControlNormal"/>
|
||||
<path
|
||||
android:pathData="M5.14,12.37L6.16,10.37"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="?attr/colorControlNormal"/>
|
||||
<path
|
||||
android:pathData="M16.27,12.37L15.25,10.37"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="?attr/colorControlNormal"/>
|
||||
<path
|
||||
android:pathData="M18.78,7.8L20.49,9.8"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="?attr/colorControlNormal"/>
|
||||
</vector>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!-- drawable/eye_off.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z" />
|
||||
</vector>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!-- drawable/eye_off.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z" />
|
||||
</vector>
|
||||
@@ -1,8 +0,0 @@
|
||||
<!-- drawable/eye.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z" />
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/fingerprint.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M17.81 4.47c-0.08 0-0.16-0.02-0.23-0.06C15.66 3.42 14 3 12 3c-1.97 0-3.85 0.47-5.56 1.41C6.2 4.54 5.9 4.45 5.76 4.21c-0.13-0.24-0.04-0.55 0.2-0.68C7.82 2.5 9.86 2 12 2s4 0.47 6.04 1.5c0.25 0.15 0.34 0.45 0.21 0.69-0.09 0.18-0.25 0.28-0.44 0.28M3.5 9.72c-0.1 0-0.2-0.03-0.29-0.09C3 9.47 2.93 9.16 3.09 8.93c0.99-1.4 2.25-2.5 3.75-3.27C10 4.04 14 4.03 17.15 5.65c1.5 0.77 2.76 1.85 3.75 3.25 0.16 0.22 0.1 0.54-0.12 0.7-0.23 0.16-0.54 0.11-0.7-0.1-0.9-1.28-2.04-2.27-3.39-2.96-2.87-1.47-6.54-1.47-9.4 0.01-1.36 0.7-2.5 1.7-3.4 2.95C3.81 9.65 3.66 9.72 3.5 9.72m6.25 12.07c-0.13 0-0.25-0.05-0.35-0.15-0.87-0.87-1.34-1.43-2.01-2.64-0.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39a0.5 0.5 0 0 1-0.5 0.5 0.5 0.5 0 0 1-0.5-0.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44 0.32 2.77 0.93 3.84 0.64 1.16 1.08 1.65 1.85 2.43 0.19 0.2 0.19 0.51 0 0.71-0.12 0.1-0.24 0.15-0.37 0.15m7.17-1.85c-1.19 0-2.24-0.3-3.1-0.89-1.49-1.01-2.38-2.65-2.38-4.39a0.5 0.5 0 0 1 0.5-0.5 0.5 0.5 0 0 1 0.5 0.5c0 1.41 0.72 2.74 1.94 3.56 0.71 0.48 1.54 0.71 2.54 0.71 0.24 0 0.64-0.03 1.04-0.1 0.27-0.05 0.54 0.13 0.58 0.41 0.05 0.26-0.13 0.53-0.41 0.58-0.57 0.11-1.07 0.12-1.21 0.12M14.91 22h-0.13c-1.59-0.46-2.63-1.05-3.72-2.12-1.4-1.38-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07 0.95 1.94 2.08 1.94 1.15 0 2.08-0.87 2.08-1.94 0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.46 1.58-6.61 4.03-0.39 0.81-0.59 1.76-0.59 2.8 0 0.78 0.07 2.01 0.67 3.61 0.1 0.26-0.03 0.55-0.29 0.64C4.88 19 4.59 18.87 4.5 18.62 4 17.31 3.77 16 3.77 14.66c0-1.2 0.23-2.29 0.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.54 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94-1.7 0-3.08-1.32-3.08-2.94 0-1.07-0.93-1.94-2.08-1.94s-2.08 0.87-2.08 1.94c0 1.71 0.66 3.31 1.87 4.51 0.95 0.94 1.86 1.46 3.27 1.84 0.27 0.08 0.42 0.36 0.35 0.62-0.05 0.23-0.26 0.38-0.47 0.38z" tools:ignore="VectorPath"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/gender_female.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M12 4a6 6 0 0 1 6 6c0 2.97-2.16 5.44-5 5.92V18h2v2h-2v2h-2v-2H9v-2h2v-2.08C8.16 15.44 6 12.97 6 10a6 6 0 0 1 6-6m0 2a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/gender_female.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#FFF" android:pathData="M12 4a6 6 0 0 1 6 6c0 2.97-2.16 5.44-5 5.92V18h2v2h-2v2h-2v-2H9v-2h2v-2.08C8.16 15.44 6 12.97 6 10a6 6 0 0 1 6-6m0 2a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/gender_male.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M9 9c1.29 0 2.5 0.41 3.47 1.11L17.58 5H13V3h8v8h-2V6.41l-5.11 5.09c0.7 1 1.11 2.2 1.11 3.5a6 6 0 0 1-6 6 6 6 0 0 1-6-6 6 6 0 0 1 6-6m0 2a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/gender_male.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#FFF" android:pathData="M9 9c1.29 0 2.5 0.41 3.47 1.11L17.58 5H13V3h8v8h-2V6.41l-5.11 5.09c0.7 1 1.11 2.2 1.11 3.5a6 6 0 0 1-6 6 6 6 0 0 1-6-6 6 6 0 0 1 6-6m0 2a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/github-circle.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5 0.5 0.08 0.66-0.23 0.66-0.5v-1.69c-2.77 0.6-3.36-1.34-3.36-1.34-0.46-1.16-1.11-1.47-1.11-1.47-0.91-0.62 0.07-0.6 0.07-0.6 1 0.07 1.53 1.03 1.53 1.03 0.87 1.52 2.34 1.07 2.91 0.83 0.09-0.65 0.35-1.09 0.63-1.34-2.22-0.25-4.55-1.11-4.55-4.92 0-1.11 0.38-2 1.03-2.71-0.1-0.25-0.45-1.29 0.1-2.64 0 0 0.84-0.27 2.75 1.02 0.79-0.22 1.65-0.33 2.5-0.33 0.85 0 1.71 0.11 2.5 0.33 1.91-1.29 2.75-1.02 2.75-1.02 0.55 1.35 0.2 2.39 0.1 2.64 0.65 0.71 1.03 1.6 1.03 2.71 0 3.82-2.34 4.66-4.57 4.91 0.36 0.31 0.69 0.92 0.69 1.85V21c0 0.27 0.16 0.59 0.67 0.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/history.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M13.5 8H12v5l4.28 2.54 0.72-1.21-3.5-2.08V8M13 3a9 9 0 0 0-9 9H1l3.96 4.03L9 12H6a7 7 0 0 1 7-7 7 7 0 0 1 7 7 7 7 0 0 1-7 7c-1.93 0-3.68-0.79-4.94-2.06l-1.42 1.42C8.27 20 10.5 21 13 21a9 9 0 0 0 9-9 9 9 0 0 0-9-9"/>
|
||||
</vector>
|
||||
@@ -1,3 +0,0 @@
|
||||
<vector android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#fff" android:pathData="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
|
||||
</vector>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--~ Pupil, Hitomi.la viewer for Android ~ Copyright (C) 2019 tom5079 ~ ~ This program 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. ~ ~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.-->
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:aapt="http://schemas.android.com/aapt" tools:ignore="NewApi">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:name="vector" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:name="path" android:pathData="M 19 9 L 15 9 L 15 3 L 9 3 L 9 9 L 5 9 L 12 16 L 19 9 Z" android:fillColor="#fff" android:strokeWidth="1"/>
|
||||
<path android:name="path_2" android:pathData="M 5 19 L 19 19" android:fillColor="#fff" android:strokeColor="#fff" android:strokeWidth="2"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="path_2">
|
||||
<aapt:attr name="android:animation">
|
||||
<set>
|
||||
<objectAnimator android:propertyName="trimPathEnd" android:duration="500" android:valueFrom="0" android:valueTo="0.8" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
<objectAnimator android:propertyName="trimPathStart" android:startOffset="500" android:duration="500" android:valueFrom="0" android:valueTo="0.8" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
<objectAnimator android:propertyName="trimPathOffset" android:duration="1000" android:valueFrom="0" android:valueTo="0.2" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</set>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,4 +0,0 @@
|
||||
<!--drawable/message.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4c0-1.11-0.9-2-2-2z"/>
|
||||
</vector>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:name="vector" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" android:tintMode="multiply">
|
||||
<path android:name="path_1" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#b9f6ca" android:strokeWidth="24"/>
|
||||
<path android:name="path" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#00c853" android:strokeWidth="24"/>
|
||||
</vector>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:name="vector" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" android:tintMode="multiply">
|
||||
<path android:name="path_1" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#80d8ff" android:strokeWidth="24"/>
|
||||
<path android:name="path" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#0091ea" android:strokeWidth="24"/>
|
||||
</vector>
|
||||
@@ -1,13 +0,0 @@
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:aapt="http://schemas.android.com/aapt" tools:ignore="NewApi">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:name="vector" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" android:tintMode="multiply">
|
||||
<path android:name="path_1" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#b9f6ca" android:strokeWidth="24"/>
|
||||
<path android:name="path" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#00c853" android:strokeWidth="24"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="path">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator android:propertyName="trimPathEnd" android:duration="1000" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
@@ -1,13 +0,0 @@
|
||||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:aapt="http://schemas.android.com/aapt" tools:ignore="NewApi">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector android:name="vector" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" android:tintMode="multiply">
|
||||
<path android:name="path_1" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#80d8ff" android:strokeWidth="24"/>
|
||||
<path android:name="path" android:pathData="M 0 12 L 24 12" android:fillColor="#000" android:strokeColor="#0091ea" android:strokeWidth="24"/>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="path">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator android:propertyName="trimPathEnd" android:duration="1000" android:valueFrom="0" android:valueTo="1" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in"/>
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
||||
@@ -1,3 +0,0 @@
|
||||
<vector android:height="24dp" android:width="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@color/material_orange_500" android:pathData="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-0.62L12 2 9.19 8.62 2 9.24l5.45 4.73L5.82 21 12 17.27z"/>
|
||||
</vector>
|
||||
@@ -1,30 +0,0 @@
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2020 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="640"
|
||||
android:viewportHeight="640">
|
||||
<path
|
||||
android:pathData="M640,320C640,496.61 496.61,640 320,640C143.39,640 0,496.61 0,320C0,143.38 143.39,0 320,0C496.61,0 640,143.38 640,320Z"
|
||||
android:fillColor="#4ec1f5"/>
|
||||
<path
|
||||
android:pathData="M420,320C420,375.19 375.19,420 320,420C264.81,420 220,375.19 220,320C220,264.81 264.81,220 320,220C375.19,220 420,264.81 420,320Z"
|
||||
android:fillColor="#1d1d1d"/>
|
||||
</vector>
|
||||
@@ -1,30 +0,0 @@
|
||||
<!--
|
||||
~ Pupil, Hitomi.la viewer for Android
|
||||
~ Copyright (C) 2020 tom5079
|
||||
~
|
||||
~ This program 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="640"
|
||||
android:viewportHeight="640">
|
||||
<path
|
||||
android:pathData="M640,320C640,496.61 496.61,640 320,640C143.39,640 0,496.61 0,320C0,143.38 143.39,0 320,0C496.61,0 640,143.38 640,320Z"
|
||||
android:fillColor="@color/colorAccent"/>
|
||||
<path
|
||||
android:pathData="M420,320C420,375.19 375.19,420 320,420C264.81,420 220,375.19 220,320C220,264.81 264.81,220 320,220C375.19,220 420,264.81 420,320Z"
|
||||
android:fillColor="#1d1d1d"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/image_broken_variant.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M21 5v6.59l-3-3.01-4 4.01-4-4-4 4-3-3.01V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2m-3 6.42l3 3.01V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-6.58l3 2.99 4-4 4 4"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/lastpass.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M14 12a2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2m20-7h-2v14h2V5z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/lock_pattern.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#fff" android:pathData="M7 3a4 4 0 0 1 4 4c0 1.86-1.27 3.43-3 3.87v2.26c0.37 0.09 0.72 0.24 1.04 0.43l4.52-4.52C13.2 8.44 13 7.75 13 7a4 4 0 0 1 4-4 4 4 0 0 1 4 4 4 4 0 0 1-4 4c-0.74 0-1.43-0.2-2-0.55L10.45 15C10.8 15.57 11 16.26 11 17a4 4 0 0 1-4 4 4 4 0 0 1-4-4c0-1.86 1.27-3.43 3-3.87v-2.26C4.27 10.43 3 8.86 3 7a4 4 0 0 1 4-4m10 10a4 4 0 0 1 4 4 4 4 0 0 1-4 4 4 4 0 0 1-4-4 4 4 0 0 1 4-4m0 2a2 2 0 0 0-2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0-2-2z"/>
|
||||
</vector>
|
||||
@@ -1,4 +0,0 @@
|
||||
<!--drawable/menu.xml-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/>
|
||||
</vector>
|
||||
@@ -1,3 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
|
||||
<path android:fillColor="#FF000000" android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
||||
</vector>
|
||||