ConfigurableExtension(PreferenceScreen) support (#163)
* initial PreferenceScreen support, works with 'NeoXXX Scans' (pt-br) * convert EditTextPreference to json successfully * commit what I've got * bring back the old SharedPreferences for CustomContext, implement Toast * put back syer's implementation
This commit is contained in:
@@ -13,7 +13,7 @@ do
|
||||
which $dep >/dev/null 2>&1 || { echo >&2 "Error: This script needs $dep installed."; abort=yes; }
|
||||
done
|
||||
|
||||
if [ $abort = yes ]; then
|
||||
if [ "$abort" = yes ]; then
|
||||
echo "Some of the dependencies didn't exist. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package android.widget;
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
public class Toast {
|
||||
public static final int LENGTH_LONG = 1;
|
||||
public static final int LENGTH_SHORT = 0;
|
||||
|
||||
private CharSequence text;
|
||||
|
||||
private Toast(CharSequence text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public Toast(android.content.Context context) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void show() {
|
||||
System.out.printf("made a Toast: \"%s\"\n", text.toString());
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setView(android.view.View view) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public android.view.View getView() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setMargin(float horizontalMargin, float verticalMargin) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public float getHorizontalMargin() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public float getVerticalMargin() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setGravity(int gravity, int xOffset, int yOffset) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public int getGravity() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public int getXOffset() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public int getYOffset() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public static Toast makeText(android.content.Context context, java.lang.CharSequence text, int duration) {
|
||||
return new Toast(text);
|
||||
}
|
||||
|
||||
public static android.widget.Toast makeText(android.content.Context context, int resId, int duration) throws android.content.res.Resources.NotFoundException {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setText(int resId) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void setText(java.lang.CharSequence s) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package androidx.preference;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public class EditTextPreference extends Preference {
|
||||
private String title;
|
||||
private CharSequence summary;
|
||||
private CharSequence dialogTitle;
|
||||
private CharSequence dialogMessage;
|
||||
|
||||
public EditTextPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
this.title = (String) title;
|
||||
}
|
||||
|
||||
public CharSequence getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
public void setSummary(CharSequence summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public CharSequence getDialogTitle() {
|
||||
return dialogTitle;
|
||||
}
|
||||
|
||||
public void setDialogTitle(CharSequence dialogTitle) {
|
||||
this.dialogTitle = dialogTitle;
|
||||
}
|
||||
|
||||
public CharSequence getDialogMessage() {
|
||||
return dialogMessage;
|
||||
}
|
||||
|
||||
public void setDialogMessage(CharSequence dialogMessage) {
|
||||
this.dialogMessage = dialogMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package androidx.preference;
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import android.content.Context;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/** A minimal implementation of androidx.preference.Preference */
|
||||
public class Preference {
|
||||
// reference: https://android.googlesource.com/platform/frameworks/support/+/996971f962fcd554339a7cb2859cef9ca89dbcb7/preference/preference/src/main/java/androidx/preference/Preference.java
|
||||
// Note: `Preference` doesn't actually hold or persist the value, `OnPreferenceChangeListener` is called and it's up to the extension to persist it.
|
||||
|
||||
@JsonIgnore
|
||||
protected Context context;
|
||||
|
||||
private String key;
|
||||
private CharSequence title;
|
||||
private Object defaultValue;
|
||||
|
||||
@JsonIgnore
|
||||
public OnPreferenceChangeListener onChangeListener;
|
||||
|
||||
public Preference(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void setDefaultValue(Object defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
|
||||
this.onChangeListener = onPreferenceChangeListener;
|
||||
}
|
||||
|
||||
public boolean callChangeListener(Object newValue) {
|
||||
return onChangeListener == null || onChangeListener.onPreferenceChange(this, newValue);
|
||||
}
|
||||
|
||||
public Object getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public interface OnPreferenceChangeListener {
|
||||
boolean onPreferenceChange(Preference preference, Object newValue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,32 @@
|
||||
package androidx.preference;
|
||||
|
||||
public class PreferenceScreen {
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class PreferenceScreen extends Preference {
|
||||
private List<Preference> preferences = new LinkedList<>();
|
||||
|
||||
|
||||
public PreferenceScreen(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public boolean addPreference(Preference preference) {
|
||||
preferences.add(preference);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Preference> getPreferences(){
|
||||
return preferences;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -50,10 +50,9 @@ import java.util.Map;
|
||||
/**
|
||||
* Custom context implementation.
|
||||
*
|
||||
* TODO Deal with packagemanager for extension sources
|
||||
*/
|
||||
public class CustomContext extends Context implements DIAware {
|
||||
private DI kodein;
|
||||
private final DI kodein;
|
||||
public CustomContext() {
|
||||
this(KodeinGlobalHelper.kodein());
|
||||
}
|
||||
@@ -734,4 +733,3 @@ public class CustomContext extends Context implements DIAware {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ class AndroidFiles(val configManager: ConfigManager = GlobalConfigManager) {
|
||||
val downloadCacheDir: File get() = registerFile(filesConfig.downloadCacheDir)
|
||||
val databasesDir: File get() = registerFile(filesConfig.databasesDir)
|
||||
|
||||
val prefsDir: File get() = registerFile(filesConfig.prefsDir)
|
||||
|
||||
val packagesDir: File get() = registerFile(filesConfig.packageDir)
|
||||
|
||||
fun registerFile(file: String): File {
|
||||
|
||||
+7
@@ -1,5 +1,12 @@
|
||||
package xyz.nulldev.androidcompat.io.sharedprefs
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import com.russhwolf.settings.ExperimentalSettingsApi
|
||||
import com.russhwolf.settings.ExperimentalSettingsImplementation
|
||||
|
||||
+1
-1
@@ -233,7 +233,7 @@ public class JsonSharedPreferences implements SharedPreferences {
|
||||
private JsonSharedPreferencesEditor() {
|
||||
}
|
||||
|
||||
private void recordChange(String key) {
|
||||
private void recordChange(String key) {
|
||||
if (!affectedKeys.contains(key)) {
|
||||
affectedKeys.add(key);
|
||||
}
|
||||
|
||||
@@ -84,5 +84,8 @@ configure(projects) {
|
||||
|
||||
// APK parser
|
||||
implementation("net.dongliu:apk-parser:2.6.10")
|
||||
|
||||
// Jackson
|
||||
implementation("com.fasterxml.jackson.core:jackson-annotations:2.10.3")
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import suwayomi.tachidesk.manga.impl.Search.sourceGlobalSearch
|
||||
import suwayomi.tachidesk.manga.impl.Search.sourceSearch
|
||||
import suwayomi.tachidesk.manga.impl.Source.getSource
|
||||
import suwayomi.tachidesk.manga.impl.Source.getSourceList
|
||||
import suwayomi.tachidesk.manga.impl.Source.getSourcePreferences
|
||||
import suwayomi.tachidesk.manga.impl.backup.BackupFlags
|
||||
import suwayomi.tachidesk.manga.impl.backup.legacy.LegacyBackupExport.createLegacyBackup
|
||||
import suwayomi.tachidesk.manga.impl.backup.legacy.LegacyBackupImport.restoreLegacyBackup
|
||||
@@ -109,6 +110,12 @@ object TachideskAPI {
|
||||
ctx.json(getSource(sourceId))
|
||||
}
|
||||
|
||||
// fetch preferences of source with id `sourceId`
|
||||
app.get("/api/v1/source/:sourceId/preference-screen") { ctx ->
|
||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||
ctx.json(getSourcePreferences(sourceId))
|
||||
}
|
||||
|
||||
// popular mangas from source with id `sourceId`
|
||||
app.get("/api/v1/source/:sourceId/popular/:pageNum") { ctx ->
|
||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||
|
||||
@@ -7,15 +7,21 @@ package suwayomi.tachidesk.manga.impl
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import suwayomi.tachidesk.manga.impl.extension.Extension.getExtensionIconUrl
|
||||
import suwayomi.tachidesk.manga.impl.util.GetHttpSource.getHttpSource
|
||||
import suwayomi.tachidesk.manga.model.dataclass.SourceDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
import xyz.nulldev.androidcompat.androidimpl.CustomContext
|
||||
|
||||
object Source {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
@@ -28,7 +34,8 @@ object Source {
|
||||
it[SourceTable.name],
|
||||
it[SourceTable.lang],
|
||||
getExtensionIconUrl(ExtensionTable.select { ExtensionTable.id eq it[SourceTable.extension] }.first()[ExtensionTable.apkName]),
|
||||
getHttpSource(it[SourceTable.id].value).supportsLatest
|
||||
getHttpSource(it[SourceTable.id].value).supportsLatest,
|
||||
getHttpSource(it[SourceTable.id].value) is ConfigurableSource
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -43,8 +50,36 @@ object Source {
|
||||
source?.get(SourceTable.name),
|
||||
source?.get(SourceTable.lang),
|
||||
source?.let { ExtensionTable.select { ExtensionTable.id eq source[SourceTable.extension] }.first()[ExtensionTable.iconUrl] },
|
||||
source?.let { getHttpSource(sourceId).supportsLatest }
|
||||
source?.let { getHttpSource(sourceId).supportsLatest },
|
||||
source?.let { getHttpSource(sourceId) is ConfigurableSource },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val context by DI.global.instance<CustomContext>()
|
||||
|
||||
data class PreferenceObject(
|
||||
val type: String,
|
||||
val props: Any
|
||||
)
|
||||
|
||||
var lastPreferenceScreen: PreferenceScreen? = null
|
||||
|
||||
fun getSourcePreferences(sourceId: Long): List<PreferenceObject> {
|
||||
val source = getHttpSource(sourceId)
|
||||
|
||||
if (source is ConfigurableSource) {
|
||||
val screen = PreferenceScreen(context)
|
||||
lastPreferenceScreen = screen
|
||||
|
||||
source.setupPreferenceScreen(screen)
|
||||
|
||||
screen.preferences.first().callChangeListener("yo")
|
||||
|
||||
return screen.preferences.map {
|
||||
PreferenceObject(it::class.java.name, it)
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,5 +12,6 @@ data class SourceDataClass(
|
||||
val name: String?,
|
||||
val lang: String?,
|
||||
val iconUrl: String?,
|
||||
val supportsLatest: Boolean?
|
||||
val supportsLatest: Boolean?,
|
||||
val isConfigurable: Boolean?
|
||||
)
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package suwayomi.tachidesk.server
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import io.javalin.Javalin
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -13,13 +20,6 @@ import java.io.IOException
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
object JavalinSetup {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user