update ui

This commit is contained in:
arm64v8a 2023-03-18 13:21:51 +09:00
parent 249511a4c0
commit c2f39c3bbc
84 changed files with 1125 additions and 289 deletions

1
app/.gitignore vendored
View File

@ -1,2 +1 @@
/build /build
/schemas

View File

@ -31,24 +31,21 @@ dependencies {
implementation(fileTree("libs")) implementation(fileTree("libs"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.3") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.3")
implementation("androidx.core:core-ktx:1.7.0") implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.recyclerview:recyclerview:1.2.1") implementation("androidx.recyclerview:recyclerview:1.3.0")
implementation("androidx.activity:activity-ktx:1.4.0") implementation("androidx.activity:activity-ktx:1.6.1")
implementation("androidx.fragment:fragment-ktx:1.4.1") implementation("androidx.fragment:fragment-ktx:1.5.5")
implementation("androidx.browser:browser:1.4.0") implementation("androidx.browser:browser:1.5.0")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.navigation:navigation-fragment-ktx:2.4.2") implementation("androidx.navigation:navigation-fragment-ktx:2.5.3")
implementation("androidx.navigation:navigation-ui-ktx:2.4.2") implementation("androidx.navigation:navigation-ui-ktx:2.5.3")
implementation("androidx.preference:preference-ktx:1.2.0") implementation("androidx.preference:preference-ktx:1.2.0")
implementation("androidx.appcompat:appcompat:1.4.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.work:work-runtime-ktx:2.7.1") implementation("androidx.work:work-runtime-ktx:2.8.0")
implementation("androidx.work:work-multiprocess:2.7.1") implementation("androidx.work:work-multiprocess:2.8.0")
implementation(project(":external:preferencex:preferencex")) implementation("com.google.android.material:material:1.8.0")
implementation(project(":external:preferencex:preferencex-simplemenu"))
implementation("com.google.android.material:material:1.6.0")
implementation("com.google.code.gson:gson:2.8.9") implementation("com.google.code.gson:gson:2.8.9")
implementation("com.github.jenly1314:zxing-lite:2.1.1") implementation("com.github.jenly1314:zxing-lite:2.1.1")
@ -71,9 +68,9 @@ dependencies {
exclude(group = "com.google.guava", module = "guava") exclude(group = "com.google.guava", module = "guava")
} }
implementation("androidx.room:room-runtime:2.4.2") implementation("androidx.room:room-runtime:2.5.0")
kapt("androidx.room:room-compiler:2.4.2") kapt("androidx.room:room-compiler:2.5.0")
implementation("androidx.room:room-ktx:2.4.2") implementation("androidx.room:room-ktx:2.5.0")
implementation("com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4") implementation("com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4")
kapt("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4") kapt("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4")

View File

@ -0,0 +1,330 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "f66fd943df1d9e86d281a2e32c9fdd47",
"entities": [
{
"tableName": "proxy_groups",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userOrder",
"columnName": "userOrder",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ungrouped",
"columnName": "ungrouped",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "subscription",
"columnName": "subscription",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "order",
"columnName": "order",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "proxy_entities",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "groupId",
"columnName": "groupId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userOrder",
"columnName": "userOrder",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tx",
"columnName": "tx",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rx",
"columnName": "rx",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ping",
"columnName": "ping",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "socksBean",
"columnName": "socksBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "httpBean",
"columnName": "httpBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "ssBean",
"columnName": "ssBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "vmessBean",
"columnName": "vmessBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "trojanBean",
"columnName": "trojanBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "trojanGoBean",
"columnName": "trojanGoBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "naiveBean",
"columnName": "naiveBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "hysteriaBean",
"columnName": "hysteriaBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "tuicBean",
"columnName": "tuicBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "sshBean",
"columnName": "sshBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "wgBean",
"columnName": "wgBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "chainBean",
"columnName": "chainBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "nekoBean",
"columnName": "nekoBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "configBean",
"columnName": "configBean",
"affinity": "BLOB",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "groupId",
"unique": false,
"columnNames": [
"groupId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
}
],
"foreignKeys": []
},
{
"tableName": "rules",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "userOrder",
"columnName": "userOrder",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "enabled",
"columnName": "enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "domains",
"columnName": "domains",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "ip",
"columnName": "ip",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "port",
"columnName": "port",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sourcePort",
"columnName": "sourcePort",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "network",
"columnName": "network",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "protocol",
"columnName": "protocol",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "outbound",
"columnName": "outbound",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "packages",
"columnName": "packages",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f66fd943df1d9e86d281a2e32c9fdd47')"
]
}
}

View File

@ -0,0 +1,342 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "062104587ad7088bb9926683389e995d",
"entities": [
{
"tableName": "proxy_groups",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userOrder",
"columnName": "userOrder",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ungrouped",
"columnName": "ungrouped",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "subscription",
"columnName": "subscription",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "order",
"columnName": "order",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isSelector",
"columnName": "isSelector",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "frontProxy",
"columnName": "frontProxy",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "proxy_entities",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "groupId",
"columnName": "groupId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userOrder",
"columnName": "userOrder",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tx",
"columnName": "tx",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rx",
"columnName": "rx",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "ping",
"columnName": "ping",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uuid",
"columnName": "uuid",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "error",
"columnName": "error",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "socksBean",
"columnName": "socksBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "httpBean",
"columnName": "httpBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "ssBean",
"columnName": "ssBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "vmessBean",
"columnName": "vmessBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "trojanBean",
"columnName": "trojanBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "trojanGoBean",
"columnName": "trojanGoBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "naiveBean",
"columnName": "naiveBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "hysteriaBean",
"columnName": "hysteriaBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "tuicBean",
"columnName": "tuicBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "sshBean",
"columnName": "sshBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "wgBean",
"columnName": "wgBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "chainBean",
"columnName": "chainBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "nekoBean",
"columnName": "nekoBean",
"affinity": "BLOB",
"notNull": false
},
{
"fieldPath": "configBean",
"columnName": "configBean",
"affinity": "BLOB",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "groupId",
"unique": false,
"columnNames": [
"groupId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
}
],
"foreignKeys": []
},
{
"tableName": "rules",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "userOrder",
"columnName": "userOrder",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "enabled",
"columnName": "enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "domains",
"columnName": "domains",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "ip",
"columnName": "ip",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "port",
"columnName": "port",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "sourcePort",
"columnName": "sourcePort",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "network",
"columnName": "network",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "protocol",
"columnName": "protocol",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "outbound",
"columnName": "outbound",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "packages",
"columnName": "packages",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '062104587ad7088bb9926683389e995d')"
]
}
}

View File

@ -0,0 +1,46 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "f1aab1fb633378621635c344dbc8ac7b",
"entities": [
{
"tableName": "KeyValuePair",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "valueType",
"columnName": "valueType",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "BLOB",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"key"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f1aab1fb633378621635c344dbc8ac7b')"
]
}
}

View File

@ -0,0 +1,46 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "f1aab1fb633378621635c344dbc8ac7b",
"entities": [
{
"tableName": "KeyValuePair",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "valueType",
"columnName": "valueType",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "BLOB",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"key"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f1aab1fb633378621635c344dbc8ac7b')"
]
}
}

View File

@ -133,6 +133,7 @@ object Key {
const val GROUP_NAME = "groupName" const val GROUP_NAME = "groupName"
const val GROUP_TYPE = "groupType" const val GROUP_TYPE = "groupType"
const val GROUP_ORDER = "groupOrder" const val GROUP_ORDER = "groupOrder"
const val GROUP_IS_SELECTOR = "groupIsSelector"
const val GROUP_SUBSCRIPTION = "groupSubscription" const val GROUP_SUBSCRIPTION = "groupSubscription"
const val SUBSCRIPTION_LINK = "subscriptionLink" const val SUBSCRIPTION_LINK = "subscriptionLink"

View File

@ -8,7 +8,10 @@ import android.os.IBinder
import android.os.RemoteException import android.os.RemoteException
import io.nekohasekai.sagernet.Action import io.nekohasekai.sagernet.Action
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.aidl.* import io.nekohasekai.sagernet.aidl.ISagerNetService
import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback
import io.nekohasekai.sagernet.aidl.SpeedDisplayData
import io.nekohasekai.sagernet.aidl.TrafficData
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.ktx.runOnMainDispatcher import io.nekohasekai.sagernet.ktx.runOnMainDispatcher

View File

@ -22,9 +22,9 @@ import io.nekohasekai.sagernet.plugin.PluginManager
import kotlinx.coroutines.* import kotlinx.coroutines.*
import libcore.BoxInstance import libcore.BoxInstance
import libcore.Libcore import libcore.Libcore
import moe.matsuri.nb4a.plugin.NekoPluginManager
import moe.matsuri.nb4a.proxy.neko.NekoBean import moe.matsuri.nb4a.proxy.neko.NekoBean
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
import moe.matsuri.nb4a.plugin.NekoPluginManager
import moe.matsuri.nb4a.proxy.neko.updateAllConfig import moe.matsuri.nb4a.proxy.neko.updateAllConfig
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File

View File

@ -234,6 +234,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var groupName by profileCacheStore.string(Key.GROUP_NAME) var groupName by profileCacheStore.string(Key.GROUP_NAME)
var groupType by profileCacheStore.stringToInt(Key.GROUP_TYPE) var groupType by profileCacheStore.stringToInt(Key.GROUP_TYPE)
var groupOrder by profileCacheStore.stringToInt(Key.GROUP_ORDER) var groupOrder by profileCacheStore.stringToInt(Key.GROUP_ORDER)
var groupIsSelector by profileCacheStore.boolean(Key.GROUP_IS_SELECTOR)
var subscriptionLink by profileCacheStore.string(Key.SUBSCRIPTION_LINK) var subscriptionLink by profileCacheStore.string(Key.SUBSCRIPTION_LINK)
var subscriptionForceResolve by profileCacheStore.boolean(Key.SUBSCRIPTION_FORCE_RESOLVE) var subscriptionForceResolve by profileCacheStore.boolean(Key.SUBSCRIPTION_FORCE_RESOLVE)

View File

@ -2,7 +2,6 @@ package io.nekohasekai.sagernet.database
import android.database.sqlite.SQLiteCantOpenDatabaseException import android.database.sqlite.SQLiteCantOpenDatabaseException
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.aidl.SpeedDisplayData
import io.nekohasekai.sagernet.aidl.TrafficData import io.nekohasekai.sagernet.aidl.TrafficData
import io.nekohasekai.sagernet.fmt.AbstractBean import io.nekohasekai.sagernet.fmt.AbstractBean
import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.Logs

View File

@ -31,13 +31,9 @@ import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.applyDefaultValues import io.nekohasekai.sagernet.ktx.applyDefaultValues
import io.nekohasekai.sagernet.ui.profile.* import io.nekohasekai.sagernet.ui.profile.*
import moe.matsuri.nb4a.Protocols import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.proxy.neko.*
import moe.matsuri.nb4a.proxy.config.ConfigBean import moe.matsuri.nb4a.proxy.config.ConfigBean
import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
import moe.matsuri.nb4a.proxy.neko.NekoBean import moe.matsuri.nb4a.proxy.neko.*
import moe.matsuri.nb4a.proxy.neko.NekoSettingActivity
import moe.matsuri.nb4a.proxy.neko.haveStandardLink
import moe.matsuri.nb4a.proxy.neko.shareLink
@Entity( @Entity(
tableName = "proxy_entities", indices = [Index("groupId", name = "groupId")] tableName = "proxy_entities", indices = [Index("groupId", name = "groupId")]

View File

@ -19,6 +19,8 @@ data class ProxyGroup(
var type: Int = GroupType.BASIC, var type: Int = GroupType.BASIC,
var subscription: SubscriptionBean? = null, var subscription: SubscriptionBean? = null,
var order: Int = GroupOrder.ORIGIN, var order: Int = GroupOrder.ORIGIN,
var isSelector: Boolean = false,
var frontProxy: Long = 0L
) : Serializable() { ) : Serializable() {
@Transient @Transient

View File

@ -15,7 +15,7 @@ import kotlinx.coroutines.launch
@Database( @Database(
entities = [ProxyGroup::class, ProxyEntity::class, RuleEntity::class], entities = [ProxyGroup::class, ProxyEntity::class, RuleEntity::class],
version = 1 version = 2
) )
@TypeConverters(value = [KryoConverters::class, GsonConverters::class]) @TypeConverters(value = [KryoConverters::class, GsonConverters::class])
@GenerateRoomMigrations @GenerateRoomMigrations

View File

@ -19,7 +19,6 @@ import io.nekohasekai.sagernet.fmt.socks.buildSingBoxOutboundSocksBean
import io.nekohasekai.sagernet.fmt.ssh.SSHBean import io.nekohasekai.sagernet.fmt.ssh.SSHBean
import io.nekohasekai.sagernet.fmt.ssh.buildSingBoxOutboundSSHBean import io.nekohasekai.sagernet.fmt.ssh.buildSingBoxOutboundSSHBean
import io.nekohasekai.sagernet.fmt.tuic.TuicBean import io.nekohasekai.sagernet.fmt.tuic.TuicBean
import moe.matsuri.nb4a.SingBoxOptions.*
import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean
import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundStandardV2RayBean import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundStandardV2RayBean
import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean
@ -29,8 +28,9 @@ import io.nekohasekai.sagernet.ktx.mkPort
import io.nekohasekai.sagernet.utils.PackageCache import io.nekohasekai.sagernet.utils.PackageCache
import moe.matsuri.nb4a.DNS.applyDNSNetworkSettings import moe.matsuri.nb4a.DNS.applyDNSNetworkSettings
import moe.matsuri.nb4a.DNS.makeSingBoxRule import moe.matsuri.nb4a.DNS.makeSingBoxRule
import moe.matsuri.nb4a.proxy.config.ConfigBean import moe.matsuri.nb4a.SingBoxOptions.*
import moe.matsuri.nb4a.plugin.Plugins import moe.matsuri.nb4a.plugin.Plugins
import moe.matsuri.nb4a.proxy.config.ConfigBean
import moe.matsuri.nb4a.utils.JavaUtil.gson import moe.matsuri.nb4a.utils.JavaUtil.gson
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

View File

@ -24,8 +24,8 @@ import io.nekohasekai.sagernet.fmt.v2ray.VMessBean;
import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean; import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean;
import io.nekohasekai.sagernet.ktx.KryosKt; import io.nekohasekai.sagernet.ktx.KryosKt;
import io.nekohasekai.sagernet.ktx.Logs; import io.nekohasekai.sagernet.ktx.Logs;
import moe.matsuri.nb4a.proxy.neko.NekoBean;
import moe.matsuri.nb4a.proxy.config.ConfigBean; import moe.matsuri.nb4a.proxy.config.ConfigBean;
import moe.matsuri.nb4a.proxy.neko.NekoBean;
import moe.matsuri.nb4a.utils.JavaUtil; import moe.matsuri.nb4a.utils.JavaUtil;
public class KryoConverters { public class KryoConverters {

View File

@ -4,7 +4,6 @@ import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.fmt.LOCALHOST import io.nekohasekai.sagernet.fmt.LOCALHOST
import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ktx.*
import moe.matsuri.nb4a.SingBoxOptions import moe.matsuri.nb4a.SingBoxOptions
import moe.matsuri.nb4a.utils.Util
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File

View File

@ -1,7 +1,7 @@
package io.nekohasekai.sagernet.fmt.shadowsocks package io.nekohasekai.sagernet.fmt.shadowsocks
import moe.matsuri.nb4a.SingBoxOptions
import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ktx.*
import moe.matsuri.nb4a.SingBoxOptions
import moe.matsuri.nb4a.utils.Util import moe.matsuri.nb4a.utils.Util
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.json.JSONObject import org.json.JSONObject

View File

@ -1,7 +1,10 @@
package io.nekohasekai.sagernet.fmt.socks package io.nekohasekai.sagernet.fmt.socks
import io.nekohasekai.sagernet.ktx.decodeBase64UrlSafe
import io.nekohasekai.sagernet.ktx.toLink
import io.nekohasekai.sagernet.ktx.unUrlSafe
import io.nekohasekai.sagernet.ktx.urlSafe
import moe.matsuri.nb4a.SingBoxOptions import moe.matsuri.nb4a.SingBoxOptions
import io.nekohasekai.sagernet.ktx.*
import moe.matsuri.nb4a.utils.NGUtil import moe.matsuri.nb4a.utils.NGUtil
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

View File

@ -7,7 +7,6 @@ import com.esotericsoftware.kryo.io.ByteBufferOutput;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import io.nekohasekai.sagernet.fmt.AbstractBean;
import io.nekohasekai.sagernet.fmt.KryoConverters; import io.nekohasekai.sagernet.fmt.KryoConverters;
import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean; import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean;

View File

@ -3,8 +3,8 @@ package io.nekohasekai.sagernet.fmt.v2ray
import com.google.gson.Gson import com.google.gson.Gson
import io.nekohasekai.sagernet.fmt.http.HttpBean import io.nekohasekai.sagernet.fmt.http.HttpBean
import io.nekohasekai.sagernet.fmt.trojan.TrojanBean import io.nekohasekai.sagernet.fmt.trojan.TrojanBean
import moe.matsuri.nb4a.SingBoxOptions.*
import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ktx.*
import moe.matsuri.nb4a.SingBoxOptions.*
import moe.matsuri.nb4a.utils.NGUtil import moe.matsuri.nb4a.utils.NGUtil
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl

View File

@ -12,8 +12,8 @@ import io.nekohasekai.sagernet.fmt.socks.parseSOCKS
import io.nekohasekai.sagernet.fmt.trojan.parseTrojan import io.nekohasekai.sagernet.fmt.trojan.parseTrojan
import io.nekohasekai.sagernet.fmt.trojan_go.parseTrojanGo import io.nekohasekai.sagernet.fmt.trojan_go.parseTrojanGo
import io.nekohasekai.sagernet.fmt.v2ray.parseV2Ray import io.nekohasekai.sagernet.fmt.v2ray.parseV2Ray
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
import moe.matsuri.nb4a.plugin.NekoPluginManager import moe.matsuri.nb4a.plugin.NekoPluginManager
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
import moe.matsuri.nb4a.proxy.neko.parseShareLink import moe.matsuri.nb4a.proxy.neko.parseShareLink
import moe.matsuri.nb4a.utils.JavaUtil.gson import moe.matsuri.nb4a.utils.JavaUtil.gson
import moe.matsuri.nb4a.utils.Util import moe.matsuri.nb4a.utils.Util

View File

@ -1,7 +1,6 @@
package io.nekohasekai.sagernet.ktx package io.nekohasekai.sagernet.ktx
import android.graphics.Rect import android.graphics.Rect
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore

View File

@ -38,9 +38,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
import moe.matsuri.nb4a.plugin.NekoPluginManager import moe.matsuri.nb4a.plugin.NekoPluginManager
import moe.matsuri.nb4a.plugin.Plugins import moe.matsuri.nb4a.plugin.Plugins
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
import moe.matsuri.nb4a.ui.Dialogs import moe.matsuri.nb4a.ui.Dialogs
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext

View File

@ -56,9 +56,9 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import moe.matsuri.nb4a.Protocols import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.Protocols.getProtocolColor import moe.matsuri.nb4a.Protocols.getProtocolColor
import moe.matsuri.nb4a.plugin.NekoPluginManager
import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
import moe.matsuri.nb4a.plugin.NekoPluginManager
import moe.matsuri.nb4a.proxy.neko.NekoSettingActivity import moe.matsuri.nb4a.proxy.neko.NekoSettingActivity
import moe.matsuri.nb4a.proxy.neko.canShare import moe.matsuri.nb4a.proxy.neko.canShare
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
@ -1467,14 +1467,14 @@ class ConfigurationFragment @JvmOverloads constructor(
popup.menuInflater.inflate(R.menu.profile_share_menu, popup.menu) popup.menuInflater.inflate(R.menu.profile_share_menu, popup.menu)
if (proxyEntity.vmessBean == null || proxyEntity.vmessBean!!.isVLESS) { if (proxyEntity.vmessBean == null || proxyEntity.vmessBean!!.isVLESS) {
popup.menu.findItem(R.id.action_group_qr).subMenu.removeItem(R.id.action_v2rayn_qr) popup.menu.findItem(R.id.action_group_qr).subMenu?.removeItem(R.id.action_v2rayn_qr)
popup.menu.findItem(R.id.action_group_clipboard).subMenu.removeItem(R.id.action_v2rayn_clipboard) popup.menu.findItem(R.id.action_group_clipboard).subMenu?.removeItem(R.id.action_v2rayn_clipboard)
} }
when { when {
!proxyEntity.haveStandardLink() -> { !proxyEntity.haveStandardLink() -> {
popup.menu.findItem(R.id.action_group_qr).subMenu.removeItem(R.id.action_standard_qr) popup.menu.findItem(R.id.action_group_qr).subMenu?.removeItem(R.id.action_standard_qr)
popup.menu.findItem(R.id.action_group_clipboard).subMenu.removeItem( popup.menu.findItem(R.id.action_group_clipboard).subMenu?.removeItem(
R.id.action_standard_clipboard R.id.action_standard_clipboard
) )
} }

View File

@ -1,20 +1,21 @@
package io.nekohasekai.sagernet.ui package io.nekohasekai.sagernet.ui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.preference.* import androidx.preference.*
import com.github.shadowsocks.plugin.Empty import com.github.shadowsocks.plugin.Empty
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.takisoft.preferencex.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.GroupType import io.nekohasekai.sagernet.GroupType
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
@ -24,8 +25,10 @@ import io.nekohasekai.sagernet.ktx.applyDefaultValues
import io.nekohasekai.sagernet.ktx.onMainDispatcher import io.nekohasekai.sagernet.ktx.onMainDispatcher
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
import io.nekohasekai.sagernet.widget.ListListener import io.nekohasekai.sagernet.widget.ListListener
import io.nekohasekai.sagernet.widget.OutboundPreference
import io.nekohasekai.sagernet.widget.UserAgentPreference import io.nekohasekai.sagernet.widget.UserAgentPreference
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import moe.matsuri.nb4a.ui.SimpleMenuPreference
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
class GroupSettingsActivity( class GroupSettingsActivity(
@ -33,10 +36,16 @@ class GroupSettingsActivity(
) : ThemedActivity(resId), ) : ThemedActivity(resId),
OnPreferenceDataStoreChangeListener { OnPreferenceDataStoreChangeListener {
private lateinit var frontProxyPreference: OutboundPreference
fun ProxyGroup.init() { fun ProxyGroup.init() {
DataStore.groupName = name ?: "" DataStore.groupName = name ?: ""
DataStore.groupType = type DataStore.groupType = type
DataStore.groupOrder = order DataStore.groupOrder = order
DataStore.groupIsSelector = isSelector
DataStore.routeOutboundRule = frontProxy
DataStore.routeOutbound = if (frontProxy >= 0) 3 else 0
val subscription = subscription ?: SubscriptionBean().applyDefaultValues() val subscription = subscription ?: SubscriptionBean().applyDefaultValues()
DataStore.subscriptionLink = subscription.link DataStore.subscriptionLink = subscription.link
DataStore.subscriptionForceResolve = subscription.forceResolve DataStore.subscriptionForceResolve = subscription.forceResolve
@ -51,6 +60,8 @@ class GroupSettingsActivity(
name = DataStore.groupName.takeIf { it.isNotBlank() } ?: "My group" name = DataStore.groupName.takeIf { it.isNotBlank() } ?: "My group"
type = DataStore.groupType type = DataStore.groupType
order = DataStore.groupOrder order = DataStore.groupOrder
isSelector = DataStore.groupIsSelector
frontProxy = if (DataStore.routeOutbound == 3) DataStore.routeOutboundRule else -1
val isSubscription = type == GroupType.SUBSCRIPTION val isSubscription = type == GroupType.SUBSCRIPTION
if (isSubscription) { if (isSubscription) {
@ -77,6 +88,22 @@ class GroupSettingsActivity(
) { ) {
addPreferencesFromResource(R.xml.group_preferences) addPreferencesFromResource(R.xml.group_preferences)
frontProxyPreference = findPreference(Key.ROUTE_OUTBOUND)!!
frontProxyPreference.apply {
entries = listOf("None", "Select...").toTypedArray()
entryValues = listOf("0", "3").toTypedArray()
setOnPreferenceChangeListener { _, newValue ->
if (newValue.toString() == "3") {
selectProfileForAdd.launch(
Intent(this@GroupSettingsActivity, ProfileSelectActivity::class.java)
)
false
} else {
true
}
}
}
val groupType = findPreference<SimpleMenuPreference>(Key.GROUP_TYPE)!! val groupType = findPreference<SimpleMenuPreference>(Key.GROUP_TYPE)!!
val groupSubscription = findPreference<PreferenceCategory>(Key.GROUP_SUBSCRIPTION)!! val groupSubscription = findPreference<PreferenceCategory>(Key.GROUP_SUBSCRIPTION)!!
val subscriptionUpdate = findPreference<PreferenceCategory>(Key.SUBSCRIPTION_UPDATE)!! val subscriptionUpdate = findPreference<PreferenceCategory>(Key.SUBSCRIPTION_UPDATE)!!
@ -252,7 +279,7 @@ class GroupSettingsActivity(
lateinit var activity: GroupSettingsActivity lateinit var activity: GroupSettingsActivity
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = DataStore.profileCacheStore preferenceManager.preferenceDataStore = DataStore.profileCacheStore
activity.apply { activity.apply {
createPreferences(savedInstanceState, rootKey) createPreferences(savedInstanceState, rootKey)
@ -312,4 +339,20 @@ class GroupSettingsActivity(
} }
val selectProfileForAdd = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) runOnDefaultDispatcher {
val profile = ProfileManager.getProfile(
it.data!!.getLongExtra(
ProfileSelectActivity.EXTRA_PROFILE_ID, 0
)
) ?: return@runOnDefaultDispatcher
DataStore.routeOutboundRule = profile.id
onMainDispatcher {
frontProxyPreference.value = "3"
}
}
}
} }

View File

@ -30,7 +30,6 @@ import io.nekohasekai.sagernet.group.GroupInterfaceAdapter
import io.nekohasekai.sagernet.group.GroupUpdater import io.nekohasekai.sagernet.group.GroupUpdater
import io.nekohasekai.sagernet.ktx.* import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.widget.ListHolderListener import io.nekohasekai.sagernet.widget.ListHolderListener
import kotlinx.coroutines.launch
import libcore.Libcore import libcore.Libcore
import moe.matsuri.nb4a.utils.Util import moe.matsuri.nb4a.utils.Util
import java.text.SimpleDateFormat import java.text.SimpleDateFormat

View File

@ -17,10 +17,10 @@ import androidx.core.view.ViewCompat
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceDataStore
import androidx.preference.PreferenceFragmentCompat
import com.github.shadowsocks.plugin.Empty import com.github.shadowsocks.plugin.Empty
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.takisoft.preferencex.PreferenceFragmentCompat
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
@ -308,7 +308,7 @@ class RouteSettingsActivity(
lateinit var activity: RouteSettingsActivity lateinit var activity: RouteSettingsActivity
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = DataStore.profileCacheStore preferenceManager.preferenceDataStore = DataStore.profileCacheStore
activity.apply { activity.apply {
createPreferences(savedInstanceState, rootKey) createPreferences(savedInstanceState, rootKey)

View File

@ -7,13 +7,8 @@ import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.EditText import android.widget.EditText
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.preference.EditTextPreference import androidx.preference.*
import androidx.preference.MultiSelectListPreference
import androidx.preference.Preference
import androidx.preference.SwitchPreference
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.takisoft.preferencex.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet import io.nekohasekai.sagernet.SagerNet
@ -25,8 +20,8 @@ import io.nekohasekai.sagernet.widget.AppListPreference
import moe.matsuri.nb4a.Protocols import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.ui.ColorPickerPreference import moe.matsuri.nb4a.ui.ColorPickerPreference
import moe.matsuri.nb4a.ui.LongClickMenuPreference import moe.matsuri.nb4a.ui.LongClickMenuPreference
import moe.matsuri.nb4a.ui.LongClickSwitchPreference
import moe.matsuri.nb4a.ui.MTUPreference import moe.matsuri.nb4a.ui.MTUPreference
import moe.matsuri.nb4a.ui.SimpleMenuPreference
class SettingsPreferenceFragment : PreferenceFragmentCompat() { class SettingsPreferenceFragment : PreferenceFragmentCompat() {
@ -44,7 +39,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
true true
} }
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = DataStore.configurationStore preferenceManager.preferenceDataStore = DataStore.configurationStore
DataStore.initGlobal() DataStore.initGlobal()
addPreferencesFromResource(R.xml.global_preferences) addPreferencesFromResource(R.xml.global_preferences)

View File

@ -13,11 +13,11 @@ import androidx.activity.result.component1
import androidx.activity.result.component2 import androidx.activity.result.component2
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.preference.PreferenceFragmentCompat
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.takisoft.preferencex.PreferenceFragmentCompat
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProfileManager import io.nekohasekai.sagernet.database.ProfileManager

View File

@ -2,14 +2,14 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.fmt.hysteria.HysteriaBean import io.nekohasekai.sagernet.fmt.hysteria.HysteriaBean
import io.nekohasekai.sagernet.ktx.applyDefaultValues import io.nekohasekai.sagernet.ktx.applyDefaultValues
import moe.matsuri.nb4a.ui.SimpleMenuPreference
class HysteriaSettingsActivity : ProfileSettingsActivity<HysteriaBean>() { class HysteriaSettingsActivity : ProfileSettingsActivity<HysteriaBean>() {

View File

@ -2,7 +2,7 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore

View File

@ -21,12 +21,12 @@ import androidx.core.view.isVisible
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceDataStore
import androidx.preference.PreferenceFragmentCompat
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.input.input import com.afollestad.materialdialogs.input.input
import com.github.shadowsocks.plugin.Empty import com.github.shadowsocks.plugin.Empty
import com.github.shadowsocks.plugin.fragment.AlertDialogFragment import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.takisoft.preferencex.PreferenceFragmentCompat
import io.nekohasekai.sagernet.* import io.nekohasekai.sagernet.*
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.GroupManager import io.nekohasekai.sagernet.database.GroupManager
@ -213,7 +213,7 @@ abstract class ProfileSettingsActivity<T : AbstractBean>(
lateinit var activity: ProfileSettingsActivity<*> lateinit var activity: ProfileSettingsActivity<*>
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = DataStore.profileCacheStore preferenceManager.preferenceDataStore = DataStore.profileCacheStore
activity.apply { activity.apply {
createPreferences(savedInstanceState, rootKey) createPreferences(savedInstanceState, rootKey)

View File

@ -2,13 +2,13 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.fmt.ssh.SSHBean import io.nekohasekai.sagernet.fmt.ssh.SSHBean
import moe.matsuri.nb4a.ui.SimpleMenuPreference
class SSHSettingsActivity : ProfileSettingsActivity<SSHBean>() { class SSHSettingsActivity : ProfileSettingsActivity<SSHBean>() {

View File

@ -2,7 +2,7 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers

View File

@ -2,14 +2,13 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.fmt.socks.SOCKSBean import io.nekohasekai.sagernet.fmt.socks.SOCKSBean
import moe.matsuri.nb4a.ui.SimpleMenuPreference
class SocksSettingsActivity : ProfileSettingsActivity<SOCKSBean>() { class SocksSettingsActivity : ProfileSettingsActivity<SOCKSBean>() {
override fun createEntity() = SOCKSBean() override fun createEntity() = SOCKSBean()

View File

@ -3,8 +3,7 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
@ -12,10 +11,10 @@ import io.nekohasekai.sagernet.fmt.http.HttpBean
import io.nekohasekai.sagernet.fmt.trojan.TrojanBean import io.nekohasekai.sagernet.fmt.trojan.TrojanBean
import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean
import io.nekohasekai.sagernet.fmt.v2ray.VMessBean import io.nekohasekai.sagernet.fmt.v2ray.VMessBean
import io.nekohasekai.sagernet.ktx.Logs
import moe.matsuri.nb4a.proxy.PreferenceBinding import moe.matsuri.nb4a.proxy.PreferenceBinding
import moe.matsuri.nb4a.proxy.PreferenceBindingManager import moe.matsuri.nb4a.proxy.PreferenceBindingManager
import moe.matsuri.nb4a.proxy.Type import moe.matsuri.nb4a.proxy.Type
import moe.matsuri.nb4a.ui.SimpleMenuPreference
abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV2RayBean>() { abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV2RayBean>() {

View File

@ -3,14 +3,14 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.fmt.trojan_go.TrojanGoBean import io.nekohasekai.sagernet.fmt.trojan_go.TrojanGoBean
import io.nekohasekai.sagernet.ktx.app import io.nekohasekai.sagernet.ktx.app
import moe.matsuri.nb4a.ui.SimpleMenuPreference
class TrojanGoSettingsActivity : ProfileSettingsActivity<TrojanGoBean>() { class TrojanGoSettingsActivity : ProfileSettingsActivity<TrojanGoBean>() {

View File

@ -1,11 +1,9 @@
package io.nekohasekai.sagernet.ui.profile package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import android.widget.Switch
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
import com.takisoft.preferencex.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore

View File

@ -2,7 +2,7 @@ package io.nekohasekai.sagernet.ui.profile
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean

View File

@ -2,20 +2,14 @@ package io.nekohasekai.sagernet.widget
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import com.takisoft.preferencex.SimpleMenuPreference import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.SagerDatabase import io.nekohasekai.sagernet.database.SagerDatabase
import moe.matsuri.nb4a.ui.SimpleMenuPreference
class GroupPreference : SimpleMenuPreference { class GroupPreference
@JvmOverloads constructor(
constructor(context: Context?) : super(context) context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) ) : SimpleMenuPreference(context, attrs, defStyle, 0) {
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context, attrs, defStyle
)
constructor(
context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
init { init {
val groups = SagerDatabase.groupDao.allGroups() val groups = SagerDatabase.groupDao.allGroups()

View File

@ -3,26 +3,26 @@ package io.nekohasekai.sagernet.widget
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.util.AttributeSet import android.util.AttributeSet
import androidx.core.content.res.TypedArrayUtils
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import androidx.preference.EditTextPreference
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.takisoft.preferencex.EditTextPreference
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.ktx.app import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.readableMessage import io.nekohasekai.sagernet.ktx.readableMessage
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
class LinkOrContentPreference : EditTextPreference { class LinkOrContentPreference
@JvmOverloads
constructor(context: Context?) : super(context) constructor(
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) context: Context,
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( attrs: AttributeSet? = null,
context, attrs, defStyleAttr defStyleAttr: Int = TypedArrayUtils.getAttr(
) context, R.attr.editTextPreferenceStyle,
android.R.attr.editTextPreferenceStyle
constructor( ),
context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int defStyleRes: Int = 0
) : super(context, attrs, defStyleAttr, defStyleRes) ) : EditTextPreference(context, attrs, defStyleAttr, defStyleRes) {
init { init {
dialogLayoutResource = R.layout.layout_link_dialog dialogLayoutResource = R.layout.layout_link_dialog

View File

@ -2,50 +2,28 @@ package io.nekohasekai.sagernet.widget
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import androidx.core.content.res.TypedArrayUtils
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import androidx.preference.EditTextPreference
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.takisoft.preferencex.EditTextPreference
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.ktx.app import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.readableMessage import io.nekohasekai.sagernet.ktx.readableMessage
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
class LinkPreference : EditTextPreference { class LinkPreference
@JvmOverloads
var defaultValue: String? = null constructor(
constructor(context: Context) : this(context, null)
constructor(
context: Context, context: Context,
attrs: AttributeSet?, attrs: AttributeSet? = null,
) : this(context, attrs, com.takisoft.preferencex.R.attr.editTextPreferenceStyle) defStyleAttr: Int = TypedArrayUtils.getAttr(
context, R.attr.editTextPreferenceStyle,
android.R.attr.editTextPreferenceStyle
),
defStyleRes: Int = 0
) : EditTextPreference(context, attrs, defStyleAttr, defStyleRes) {
constructor( // var defaultValue: String? = null
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
) : this(context, attrs, defStyleAttr, 0)
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int,
) : super(context, attrs, defStyleAttr, defStyleRes) {
val a = context.obtainStyledAttributes(
attrs, R.styleable.Preference, defStyleAttr, defStyleRes
)
if (a.hasValue(androidx.preference.R.styleable.Preference_defaultValue)) {
defaultValue = onGetDefaultValue(
a, androidx.preference.R.styleable.Preference_defaultValue
)?.toString()
} else if (a.hasValue(androidx.preference.R.styleable.Preference_android_defaultValue)) {
defaultValue = onGetDefaultValue(
a, androidx.preference.R.styleable.Preference_android_defaultValue
)?.toString()
}
}
init { init {
dialogLayoutResource = R.layout.layout_link_dialog dialogLayoutResource = R.layout.layout_link_dialog
@ -79,7 +57,7 @@ class LinkPreference : EditTextPreference {
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->
if ((newValue as String).isBlank()) { if ((newValue as String).isBlank()) {
text = defaultValue // text = defaultValue
false false
} else try { } else try {
newValue.toHttpUrl() newValue.toHttpUrl()

View File

@ -2,27 +2,15 @@ package io.nekohasekai.sagernet.widget
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProfileManager import io.nekohasekai.sagernet.database.ProfileManager
import moe.matsuri.nb4a.ui.SimpleMenuPreference
class OutboundPreference : SimpleMenuPreference { class OutboundPreference
@JvmOverloads constructor(
constructor(context: Context?) : super(context) context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) ) : SimpleMenuPreference(context, attrs, defStyle, 0) {
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
init { init {
setEntries(R.array.outbound_entry) setEntries(R.array.outbound_entry)

View File

@ -2,20 +2,17 @@ package io.nekohasekai.sagernet.widget
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import com.takisoft.preferencex.EditTextPreference import androidx.core.content.res.TypedArrayUtils
import androidx.preference.EditTextPreference
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.ktx.USER_AGENT import io.nekohasekai.sagernet.ktx.USER_AGENT
class UserAgentPreference : EditTextPreference { class UserAgentPreference
@JvmOverloads constructor(
constructor(context: Context?) : super(context) context: Context, attrs: AttributeSet? = null, defStyle: Int = TypedArrayUtils.getAttr(
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) context, R.attr.editTextPreferenceStyle, android.R.attr.editTextPreferenceStyle
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context, attrs, defStyle
) )
) : EditTextPreference(context, attrs, defStyle) {
constructor(
context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
public override fun notifyChanged() { public override fun notifyChanged() {
super.notifyChanged() super.notifyChanged()

View File

@ -8,7 +8,6 @@ import android.net.Uri
import android.os.Build import android.os.Build
import android.widget.Toast import android.widget.Toast
import io.nekohasekai.sagernet.SagerNet import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.plugin.PluginManager.loadString import io.nekohasekai.sagernet.plugin.PluginManager.loadString
import io.nekohasekai.sagernet.utils.PackageCache import io.nekohasekai.sagernet.utils.PackageCache

View File

@ -1,9 +1,7 @@
package moe.matsuri.nb4a.proxy package moe.matsuri.nb4a.proxy
import androidx.preference.Preference import androidx.preference.Preference
import com.takisoft.preferencex.EditTextPreference import androidx.preference.PreferenceFragmentCompat
import com.takisoft.preferencex.PreferenceFragmentCompat
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.readableMessage import io.nekohasekai.sagernet.ktx.readableMessage

View File

@ -1,6 +1,7 @@
package moe.matsuri.nb4a.proxy package moe.matsuri.nb4a.proxy
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
class PreferenceBindingManager { class PreferenceBindingManager {
val items = mutableListOf<PreferenceBinding>() val items = mutableListOf<PreferenceBinding>()

View File

@ -1,10 +1,10 @@
package moe.matsuri.nb4a.proxy.config package moe.matsuri.nb4a.proxy.config
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceDataStore
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
import com.takisoft.preferencex.EditTextPreference
import com.takisoft.preferencex.PreferenceFragmentCompat
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore

View File

@ -5,7 +5,6 @@ import android.webkit.*
import android.widget.Toast import android.widget.Toast
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.BuildConfig import io.nekohasekai.sagernet.BuildConfig
import io.nekohasekai.sagernet.SagerNet import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
@ -14,6 +13,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import moe.matsuri.nb4a.plugin.NekoPluginManager import moe.matsuri.nb4a.plugin.NekoPluginManager
import moe.matsuri.nb4a.ui.SimpleMenuPreference
import moe.matsuri.nb4a.utils.JavaUtil import moe.matsuri.nb4a.utils.JavaUtil
import moe.matsuri.nb4a.utils.Util import moe.matsuri.nb4a.utils.Util
import moe.matsuri.nb4a.utils.WebViewUtil import moe.matsuri.nb4a.utils.WebViewUtil

View File

@ -1,17 +1,13 @@
package moe.matsuri.nb4a.proxy.neko package moe.matsuri.nb4a.proxy.neko
import androidx.preference.Preference import androidx.preference.*
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference
import com.takisoft.preferencex.EditTextPreference
import com.takisoft.preferencex.PreferenceCategory
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.ktx.forEach import io.nekohasekai.sagernet.ktx.forEach
import io.nekohasekai.sagernet.ktx.getStr import io.nekohasekai.sagernet.ktx.getStr
import io.nekohasekai.sagernet.ui.profile.ProfileSettingsActivity import io.nekohasekai.sagernet.ui.profile.ProfileSettingsActivity
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import moe.matsuri.nb4a.ui.SimpleMenuPreference
import moe.matsuri.nb4a.utils.getDrawableByName import moe.matsuri.nb4a.utils.getDrawableByName
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
@ -37,14 +33,24 @@ object NekoPreferenceInflater {
"EditTextPreference" -> { "EditTextPreference" -> {
p = EditTextPreference(context).apply { p = EditTextPreference(context).apply {
when (any.getStr("summaryProvider")) { when (any.getStr("summaryProvider")) {
null -> summaryProvider = androidx.preference.EditTextPreference.SimpleSummaryProvider.getInstance() null -> summaryProvider =
"PasswordSummaryProvider" -> summaryProvider = ProfileSettingsActivity.PasswordSummaryProvider EditTextPreference.SimpleSummaryProvider.getInstance()
"PasswordSummaryProvider" -> summaryProvider =
ProfileSettingsActivity.PasswordSummaryProvider
} }
when (any.getStr("EditTextPreferenceModifiers")) { when (any.getStr("EditTextPreferenceModifiers")) {
"Monospace" -> onBindEditTextListener = EditTextPreferenceModifiers.Monospace "Monospace" -> setOnBindEditTextListener(
"Hosts" -> onBindEditTextListener = EditTextPreferenceModifiers.Hosts EditTextPreferenceModifiers.Monospace
"Port" -> onBindEditTextListener = EditTextPreferenceModifiers.Port )
"Number" -> onBindEditTextListener = EditTextPreferenceModifiers.Number "Hosts" -> setOnBindEditTextListener(
EditTextPreferenceModifiers.Hosts
)
"Port" -> setOnBindEditTextListener(
EditTextPreferenceModifiers.Port
)
"Number" -> setOnBindEditTextListener(
EditTextPreferenceModifiers.Number
)
} }
} }
} }
@ -53,7 +59,6 @@ object NekoPreferenceInflater {
} }
"SimpleMenuPreference" -> { "SimpleMenuPreference" -> {
p = SimpleMenuPreference(context).apply { p = SimpleMenuPreference(context).apply {
summaryProvider = androidx.preference.ListPreference.SimpleSummaryProvider.getInstance()
val entries = any.optJSONObject("entries") val entries = any.optJSONObject("entries")
if (entries != null) setMenu(this, entries) if (entries != null) setMenu(this, entries)
} }
@ -85,8 +90,8 @@ object NekoPreferenceInflater {
menuEntries.add(b as String) menuEntries.add(b as String)
} }
entries.apply { entries.apply {
p.setEntries(menuEntries.toTypedArray()) p.entries = menuEntries.toTypedArray()
p.setEntryValues(menuEntryValues.toTypedArray()) p.entryValues = menuEntryValues.toTypedArray()
} }
} }
} }

View File

@ -4,7 +4,7 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceDataStore
import com.takisoft.preferencex.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import io.nekohasekai.sagernet.Key import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore

View File

@ -4,18 +4,12 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import com.takisoft.preferencex.SimpleMenuPreference
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
class LongClickMenuPreference class LongClickMenuPreference
@JvmOverloads constructor( @JvmOverloads constructor(
context: Context, context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
attrs: AttributeSet? = null, ) : SimpleMenuPreference(context, attrs, defStyle, 0) {
defStyleAttr: Int = com.takisoft.preferencex.simplemenu.R.attr.simpleMenuPreferenceStyle,
defStyleRes: Int = R.style.Preference_SimpleMenuPreference
) : SimpleMenuPreference(
context, attrs, defStyleAttr, defStyleRes
) {
private var mLongClickListener: View.OnLongClickListener? = null private var mLongClickListener: View.OnLongClickListener? = null
override fun onBindViewHolder(holder: PreferenceViewHolder) { override fun onBindViewHolder(holder: PreferenceViewHolder) {

View File

@ -5,21 +5,15 @@ import android.util.AttributeSet
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.EditText import android.widget.EditText
import androidx.core.content.res.TypedArrayUtils
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.takisoft.preferencex.SimpleMenuPreference import io.nekohasekai.sagernet.R
class MTUPreference : SimpleMenuPreference {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context, attrs, defStyleAttr
)
constructor(
context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
class MTUPreference
@JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyle: Int = R.attr.dropdownPreferenceStyle
) : SimpleMenuPreference(context, attrs, defStyle, 0) {
init { init {
setSummaryProvider { setSummaryProvider {
value.toString() value.toString()

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package moe.matsuri.nb4a.ui
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Spinner
import androidx.core.content.ContextCompat
import androidx.preference.DropDownPreference
import androidx.preference.PreferenceViewHolder
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.ktx.getColorAttr
/**
* Bend [DropDownPreference] to support
* [Simple Menus](https://material.google.com/components/menus.html#menus-behavior).
*/
open class SimpleMenuPreference
@JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = androidx.preference.R.attr.dropdownPreferenceStyle,
defStyleRes: Int = 0
) : DropDownPreference(context!!, attrs, defStyleAttr, defStyleRes) {
private lateinit var mAdapter: SimpleMenuAdapter
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
val mSpinner = holder.itemView.findViewById<Spinner>(R.id.spinner)
mSpinner.layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
}
override fun createAdapter(): ArrayAdapter<CharSequence?> {
mAdapter = SimpleMenuAdapter(getContext(), R.layout.simple_menu_dropdown_item)
return mAdapter
}
override fun setValue(value: String?) {
super.setValue(value)
if (::mAdapter.isInitialized) {
mAdapter.currentPosition = entryValues.indexOf(value)
mAdapter.notifyDataSetChanged()
}
}
private class SimpleMenuAdapter(context: Context, resource: Int) :
ArrayAdapter<CharSequence?>(context, resource) {
var currentPosition = -1
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
val view: View = super.getDropDownView(position, convertView, parent)
if (position == currentPosition) {
view.setBackgroundColor(context.getColorAttr(R.attr.colorMaterial100))
} else {
view.setBackgroundColor(
ContextCompat.getColor(
context,
R.color.preference_simple_menu_background
)
)
}
return view
}
}
}

View File

@ -2,13 +2,7 @@ package moe.matsuri.nb4a.utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.util.Base64 import android.util.Base64
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.lang.reflect.Type
import java.text.NumberFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.zip.Deflater import java.util.zip.Deflater

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"

View File

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"

View File

@ -0,0 +1,25 @@
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/spinnerDropDownItemStyle"
android:layout_width="match_parent"
android:layout_height="48dp"
android:ellipsize="marquee"
android:gravity="center"
android:minWidth="112dp"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:singleLine="true" />

View File

@ -1,5 +1,4 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/uninstall_all" android:id="@+id/uninstall_all"
android:title="Uninstall All Plugins" /> android:title="Uninstall All Plugins" />

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/action_clear_traffic_statistics" android:id="@+id/action_clear_traffic_statistics"
android:title="@string/clear_traffic_statistics" /> android:title="@string/clear_traffic_statistics" />

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="fab_color_progress">@color/material_light_white</color> <color name="fab_color_progress">@color/material_light_white</color>
<color name="preference_simple_menu_background">#303030</color>
</resources> </resources>

View File

@ -288,15 +288,6 @@
<color name="color_ng_black_accent">#9E9E9E</color> <color name="color_ng_black_accent">#9E9E9E</color>
<color name="color_ng_black_primary">#2B2B2B</color> <color name="color_ng_black_primary">#2B2B2B</color>
<!-- <color name="colorPrimary">#607D8B</color>--> <color name="preference_simple_menu_background">#FAFAFA</color>
<!-- <color name="colorPrimary_dark">#455A64</color>-->
<!-- <color name="colorPrimary_light">#CFD8DC</color>-->
<!-- <color name="accent">#</color>-->
<!-- <color name="colorPrimary_text">#212121</color>-->
<!-- <color name="secondary_text">#757575</color>-->
<!-- <color name="icons">#FFFFFF</color>-->
<!-- <color name="divider">#BDBDBD</color>-->
<!-- <color name="colorPing">#185534</color>-->
<!-- <color name="colorSubscription">#247BA0</color>-->
</resources> </resources>

View File

@ -1,4 +1,4 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources>
<dimen name="qrcode_size">264dp</dimen> <dimen name="qrcode_size">264dp</dimen>
<dimen name="main_list_padding_bottom">88dp</dimen> <dimen name="main_list_padding_bottom">88dp</dimen>
<dimen name="bottom_sheet_padding">8dp</dimen> <dimen name="bottom_sheet_padding">8dp</dimen>

View File

@ -502,5 +502,7 @@ Anyone can write advanced plugins, which can control NekoBox. please download an
<string name="ads">Ads</string> <string name="ads">Ads</string>
<string name="bypass_lan_in_core">Bypass LAN in Core</string> <string name="bypass_lan_in_core">Bypass LAN in Core</string>
<string name="need_restart">Restart APP to apply changes</string> <string name="need_restart">Restart APP to apply changes</string>
<string name="use_selector">Use selector</string>
<string name="front_proxy">Front proxy</string>
</resources> </resources>

View File

@ -1,4 +1,4 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.SagerNet" parent="Theme.MaterialComponents.DayNight.NoActionBar"> <style name="Theme.SagerNet" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="actionBarStyle">@style/Widget.MaterialComponents.ActionBar.Solid</item> <item name="actionBarStyle">@style/Widget.MaterialComponents.ActionBar.Solid</item>

View File

@ -6,7 +6,7 @@
app:title="@string/profile_name" app:title="@string/profile_name"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0" app:defaultValue="0"
app:entries="@array/balancer_type" app:entries="@array/balancer_type"
app:entryValues="@array/int_array_2" app:entryValues="@array/int_array_2"
@ -15,7 +15,7 @@
app:title="@string/balancer_type" app:title="@string/balancer_type"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/balancer_strategy_entry" app:entries="@array/balancer_strategy_entry"
app:entryValues="@array/balancer_strategy_value" app:entryValues="@array/balancer_strategy_value"
app:icon="@drawable/ic_baseline_compare_arrows_24" app:icon="@drawable/ic_baseline_compare_arrows_24"

View File

@ -1,5 +1,4 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference <EditTextPreference
app:icon="@drawable/ic_social_emoji_symbols" app:icon="@drawable/ic_social_emoji_symbols"

View File

@ -10,7 +10,7 @@
android:title="@string/theme" android:title="@string/theme"
app:icon="@drawable/ic_baseline_color_lens_24" app:icon="@drawable/ic_baseline_color_lens_24"
app:key="appTheme" /> app:key="appTheme" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0" app:defaultValue="0"
app:entries="@array/night_mode" app:entries="@array/night_mode"
app:entryValues="@array/int_array_4" app:entryValues="@array/int_array_4"
@ -18,7 +18,7 @@
app:key="nightTheme" app:key="nightTheme"
app:title="@string/night_mode" app:title="@string/night_mode"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="vpn" app:defaultValue="vpn"
app:entries="@array/service_modes" app:entries="@array/service_modes"
app:entryValues="@array/service_mode_values" app:entryValues="@array/service_mode_values"
@ -26,7 +26,7 @@
app:key="serviceMode" app:key="serviceMode"
app:title="@string/service_mode" app:title="@string/service_mode"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="1" app:defaultValue="1"
app:entries="@array/tun_implementation" app:entries="@array/tun_implementation"
app:entryValues="@array/int_array_2" app:entryValues="@array/int_array_2"
@ -46,7 +46,7 @@
app:key="profileTrafficStatistics" app:key="profileTrafficStatistics"
app:summary="@string/profile_traffic_statistics_summary" app:summary="@string/profile_traffic_statistics_summary"
app:title="@string/profile_traffic_statistics" /> app:title="@string/profile_traffic_statistics" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="1000" app:defaultValue="1000"
app:entries="@array/notification_entry" app:entries="@array/notification_entry"
app:entryValues="@array/notification_value" app:entryValues="@array/notification_value"
@ -104,7 +104,7 @@
app:key="resolveDestination" app:key="resolveDestination"
app:summary="@string/resolve_destination_summary" app:summary="@string/resolve_destination_summary"
app:title="@string/resolve_destination" /> app:title="@string/resolve_destination" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0" app:defaultValue="0"
app:entries="@array/ipv6_mode" app:entries="@array/ipv6_mode"
app:entryValues="@array/int_array_4" app:entryValues="@array/int_array_4"
@ -112,7 +112,7 @@
app:key="ipv6Mode" app:key="ipv6Mode"
app:title="@string/ipv6" app:title="@string/ipv6"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0" app:defaultValue="0"
app:entries="@array/rules_dat_provider" app:entries="@array/rules_dat_provider"
app:entryValues="@array/int_array_2" app:entryValues="@array/int_array_2"
@ -197,7 +197,7 @@
app:key="transproxyPort" app:key="transproxyPort"
app:title="@string/port_transproxy" app:title="@string/port_transproxy"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0" app:defaultValue="0"
app:entries="@array/transproxy_mode" app:entries="@array/transproxy_mode"
app:entryValues="@array/int_array_2" app:entryValues="@array/int_array_2"
@ -234,7 +234,7 @@
app:key="tcpKeepAliveInterval" app:key="tcpKeepAliveInterval"
app:title="@string/tcp_keep_alive_interval" app:title="@string/tcp_keep_alive_interval"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="1.2" app:defaultValue="1.2"
app:entries="@array/app_tls_version" app:entries="@array/app_tls_version"
app:entryValues="@array/app_tls_version" app:entryValues="@array/app_tls_version"

View File

@ -6,7 +6,7 @@
app:title="@string/group_name" app:title="@string/group_name"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="0" app:defaultValue="0"
app:entries="@array/group_types" app:entries="@array/group_types"
app:entryValues="@array/int_array_2" app:entryValues="@array/int_array_2"
@ -14,13 +14,16 @@
app:key="groupType" app:key="groupType"
app:title="@string/group_type" app:title="@string/group_type"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference
app:defaultValue="0" <SwitchPreference
app:entries="@array/group_orders" app:icon="@drawable/ic_baseline_manage_search_24"
app:entryValues="@array/int_array_3" app:key="groupIsSelector"
app:icon="@drawable/ic_baseline_low_priority_24" app:title="@string/use_selector" />
app:key="groupOrder"
app:title="@string/group_order" <io.nekohasekai.sagernet.widget.OutboundPreference
app:icon="@drawable/ic_hardware_router"
app:key="routeOutbound"
app:title="@string/front_proxy"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<PreferenceCategory <PreferenceCategory

View File

@ -24,7 +24,7 @@
app:key="serverObfs" app:key="serverObfs"
app:title="@string/hysteria_obfs" app:title="@string/hysteria_obfs"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/hysteria_auth_type" app:entries="@array/hysteria_auth_type"
app:entryValues="@array/int_array_3" app:entryValues="@array/int_array_3"
app:icon="@drawable/ic_baseline_compare_arrows_24" app:icon="@drawable/ic_baseline_compare_arrows_24"
@ -36,7 +36,7 @@
app:icon="@drawable/ic_settings_password" app:icon="@drawable/ic_settings_password"
app:key="serverPassword" app:key="serverPassword"
app:title="@string/hysteria_auth_payload" /> app:title="@string/hysteria_auth_payload" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="https" app:defaultValue="https"
app:entries="@array/hysteria_protocol" app:entries="@array/hysteria_protocol"
app:entryValues="@array/int_array_3" app:entryValues="@array/int_array_3"

View File

@ -29,7 +29,7 @@
app:icon="@drawable/ic_settings_password" app:icon="@drawable/ic_settings_password"
app:key="serverPassword" app:key="serverPassword"
app:title="@string/password_opt" /> app:title="@string/password_opt" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
android:layout_height="match_parent" android:layout_height="match_parent"
app:defaultValue="https" app:defaultValue="https"
app:entries="@array/naive_proto_entry" app:entries="@array/naive_proto_entry"

View File

@ -1,5 +1,4 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference <EditTextPreference
app:icon="@drawable/ic_social_emoji_symbols" app:icon="@drawable/ic_social_emoji_symbols"

View File

@ -33,7 +33,7 @@
app:key="routeSourcePort" app:key="routeSourcePort"
app:title="sourcePort" app:title="sourcePort"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/route_protocol_entry" app:entries="@array/route_protocol_entry"
app:entryValues="@array/route_protocol_value" app:entryValues="@array/route_protocol_value"
app:icon="@drawable/ic_baseline_compare_arrows_24" app:icon="@drawable/ic_baseline_compare_arrows_24"

View File

@ -17,7 +17,7 @@
app:key="serverPort" app:key="serverPort"
app:title="@string/server_port" app:title="@string/server_port"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/ss_enc_method_value" app:entries="@array/ss_enc_method_value"
app:entryValues="@array/ss_enc_method_value" app:entryValues="@array/ss_enc_method_value"
app:icon="@drawable/ic_notification_enhanced_encryption" app:icon="@drawable/ic_notification_enhanced_encryption"
@ -32,7 +32,7 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory app:title="@string/plugin"> <PreferenceCategory app:title="@string/plugin">
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="" app:defaultValue=""
app:entries="@array/box_shadowsocks_plugins" app:entries="@array/box_shadowsocks_plugins"
app:entryValues="@array/box_shadowsocks_plugins" app:entryValues="@array/box_shadowsocks_plugins"

View File

@ -7,7 +7,7 @@
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<PreferenceCategory app:title="@string/proxy_cat"> <PreferenceCategory app:title="@string/proxy_cat">
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="2" app:defaultValue="2"
app:entries="@array/socks_versions" app:entries="@array/socks_versions"
app:entryValues="@array/int_array_3" app:entryValues="@array/int_array_3"

View File

@ -24,7 +24,7 @@
app:title="@string/username" app:title="@string/username"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/ssh_auth_type" app:entries="@array/ssh_auth_type"
app:entryValues="@array/int_array_3" app:entryValues="@array/int_array_3"
app:icon="@drawable/ic_baseline_compare_arrows_24" app:icon="@drawable/ic_baseline_compare_arrows_24"

View File

@ -38,21 +38,21 @@
app:key="alterId" app:key="alterId"
app:title="@string/alter_id" app:title="@string/alter_id"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/vmess_encryption_value" app:entries="@array/vmess_encryption_value"
app:entryValues="@array/vmess_encryption_value" app:entryValues="@array/vmess_encryption_value"
app:icon="@drawable/ic_notification_enhanced_encryption" app:icon="@drawable/ic_notification_enhanced_encryption"
app:key="encryption" app:key="encryption"
app:title="@string/encryption" app:title="@string/encryption"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/packet_encoding_entry" app:entries="@array/packet_encoding_entry"
app:entryValues="@array/int_array_3" app:entryValues="@array/int_array_3"
app:icon="@drawable/baseline_widgets_24" app:icon="@drawable/baseline_widgets_24"
app:key="packetEncoding" app:key="packetEncoding"
app:title="@string/packet_encoding" app:title="@string/packet_encoding"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/networks_value" app:entries="@array/networks_value"
app:entryValues="@array/networks_value" app:entryValues="@array/networks_value"
app:icon="@drawable/ic_baseline_compare_arrows_24" app:icon="@drawable/ic_baseline_compare_arrows_24"
@ -69,7 +69,7 @@
app:key="path" app:key="path"
app:title="@string/http_path" app:title="@string/http_path"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/transport_layer_encryption_value" app:entries="@array/transport_layer_encryption_value"
app:entryValues="@array/transport_layer_encryption_value" app:entryValues="@array/transport_layer_encryption_value"
app:icon="@drawable/ic_baseline_layers_24" app:icon="@drawable/ic_baseline_layers_24"
@ -118,7 +118,7 @@
app:key="allowInsecure" app:key="allowInsecure"
app:summary="@string/allow_insecure_sum" app:summary="@string/allow_insecure_sum"
app:title="@string/allow_insecure" /> app:title="@string/allow_insecure" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="" app:defaultValue=""
app:entries="@array/utls_fingerprint_entry" app:entries="@array/utls_fingerprint_entry"
app:entryValues="@array/utls_fingerprint_entry" app:entryValues="@array/utls_fingerprint_entry"

View File

@ -33,7 +33,7 @@
app:key="serverAllowInsecure" app:key="serverAllowInsecure"
app:summary="@string/allow_insecure_sum" app:summary="@string/allow_insecure_sum"
app:title="@string/allow_insecure" /> app:title="@string/allow_insecure" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="none" app:defaultValue="none"
app:entries="@array/trojan_go_networks_entry" app:entries="@array/trojan_go_networks_entry"
app:entryValues="@array/trojan_go_networks_value" app:entryValues="@array/trojan_go_networks_value"
@ -41,7 +41,7 @@
app:key="serverNetwork" app:key="serverNetwork"
app:title="@string/network" app:title="@string/network"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/trojan_go_security_entry" app:entries="@array/trojan_go_security_entry"
app:entryValues="@array/trojan_go_security_value" app:entryValues="@array/trojan_go_security_value"
app:icon="@drawable/ic_baseline_layers_24" app:icon="@drawable/ic_baseline_layers_24"
@ -69,7 +69,7 @@
app:key="serverSsCategory" app:key="serverSsCategory"
app:title="@string/ss_cat"> app:title="@string/ss_cat">
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="AES-128-GCM" app:defaultValue="AES-128-GCM"
app:entries="@array/trojan_go_methods" app:entries="@array/trojan_go_methods"
app:entryValues="@array/trojan_go_methods" app:entryValues="@array/trojan_go_methods"

View File

@ -33,7 +33,7 @@
app:key="serverCertificates" app:key="serverCertificates"
app:title="@string/certificates" app:title="@string/certificates"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="https" app:defaultValue="https"
app:entries="@array/tuic_udp_relay_mode_entry" app:entries="@array/tuic_udp_relay_mode_entry"
app:entryValues="@array/tuic_udp_relay_mode_value" app:entryValues="@array/tuic_udp_relay_mode_value"
@ -41,7 +41,7 @@
app:key="serverUDPRelayMode" app:key="serverUDPRelayMode"
app:title="@string/tuic_udp_relay_mode" app:title="@string/tuic_udp_relay_mode"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<com.takisoft.preferencex.SimpleMenuPreference <moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue="https" app:defaultValue="https"
app:entries="@array/tuic_congestion_controller_entry" app:entries="@array/tuic_congestion_controller_entry"
app:entryValues="@array/tuic_congestion_controller_value" app:entryValues="@array/tuic_congestion_controller_value"

View File

@ -5,6 +5,8 @@ set -e
#### Download assets #### Download assets
bash buildScript/lib/assets.sh bash buildScript/lib/assets.sh
exit
#### Download "external" from Internet #### Download "external" from Internet
rm -rf external rm -rf external
mkdir -p external mkdir -p external

View File

@ -86,10 +86,10 @@ fun Project.requireTargetAbi(): String {
fun Project.setupCommon() { fun Project.setupCommon() {
android.apply { android.apply {
buildToolsVersion("30.0.3") buildToolsVersion("30.0.3")
compileSdkVersion(32) compileSdkVersion(33)
defaultConfig { defaultConfig {
minSdk = 21 minSdk = 21
targetSdk = 32 targetSdk = 33
} }
buildTypes { buildTypes {
getByName("release") { getByName("release") {

View File

@ -1,5 +1,2 @@
include(":external:preferencex:preferencex")
include(":external:preferencex:preferencex-simplemenu")
include(":app") include(":app")
rootProject.name = "NB4A" rootProject.name = "NB4A"