From 4a8b6b270419f0fb6789e3f325bfdb1c07e2b081 Mon Sep 17 00:00:00 2001
From: kr328 <kr328app@outlook.com>
Date: Sun, 12 Sep 2021 13:01:08 +0800
Subject: [PATCH] Refactor: refactor design structure

---
 build.gradle.kts                              |  12 +-
 .../clash/design/OverrideSettingsDesign.kt    | 399 ------------------
 .../kr328/clash/design/component/ProxyMenu.kt | 113 -----
 design/src/foss/res/menu/menu_proxy.xml       |  56 ---
 .../github/kr328/clash/design/HelpDesign.kt   |  41 +-
 .../clash/design/OverrideSettingsDesign.kt    |  55 ++-
 .../kr328/clash/design/component/ProxyMenu.kt |   3 +
 .../{premium => main}/res/menu/menu_proxy.xml |   0
 .../github/kr328/clash/design/HelpDesign.kt   |  84 ----
 9 files changed, 75 insertions(+), 688 deletions(-)
 delete mode 100644 design/src/foss/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
 delete mode 100644 design/src/foss/java/com/github/kr328/clash/design/component/ProxyMenu.kt
 delete mode 100644 design/src/foss/res/menu/menu_proxy.xml
 rename design/src/{foss => main}/java/com/github/kr328/clash/design/HelpDesign.kt (70%)
 rename design/src/{premium => main}/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt (90%)
 rename design/src/{premium => main}/java/com/github/kr328/clash/design/component/ProxyMenu.kt (96%)
 rename design/src/{premium => main}/res/menu/menu_proxy.xml (100%)
 delete mode 100644 design/src/premium/java/com/github/kr328/clash/design/HelpDesign.kt

diff --git a/build.gradle.kts b/build.gradle.kts
index f1d59d4c..2caf1702 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -70,10 +70,6 @@ subprojects {
             versionName = buildVersionName
             versionCode = buildVersionCode
 
-            if (!isApp) {
-                consumerProguardFiles("consumer-rules.pro")
-            }
-
             resValue("string", "release_name", "v$buildVersionName")
             resValue("integer", "release_code", "$buildVersionCode")
 
@@ -82,6 +78,10 @@ subprojects {
                     abiFilters("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
                 }
             }
+
+            if (!isApp) {
+                consumerProguardFiles("consumer-rules.pro")
+            }
         }
 
         if (isApp) {
@@ -108,6 +108,8 @@ subprojects {
                 dimension = defaultDimension
                 versionNameSuffix = ".foss"
 
+                buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
+
                 if (isApp) {
                     applicationIdSuffix = ".foss"
                 }
@@ -116,6 +118,8 @@ subprojects {
                 dimension = defaultDimension
                 versionNameSuffix = ".premium"
 
+                buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"true\")")
+
                 val trackFile = rootProject.file("track.properties")
                 if (trackFile.exists()) {
                     val track = Properties().apply {
diff --git a/design/src/foss/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt b/design/src/foss/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
deleted file mode 100644
index ae0a592f..00000000
--- a/design/src/foss/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
+++ /dev/null
@@ -1,399 +0,0 @@
-package com.github.kr328.clash.design
-
-import android.content.Context
-import android.view.View
-import com.github.kr328.clash.core.model.ConfigurationOverride
-import com.github.kr328.clash.core.model.LogMessage
-import com.github.kr328.clash.core.model.TunnelState
-import com.github.kr328.clash.design.adapter.SideloadProviderAdapter
-import com.github.kr328.clash.design.databinding.DesignSettingsOverideBinding
-import com.github.kr328.clash.design.databinding.DialogPreferenceListBinding
-import com.github.kr328.clash.design.dialog.FullScreenDialog
-import com.github.kr328.clash.design.model.AppInfo
-import com.github.kr328.clash.design.preference.*
-import com.github.kr328.clash.design.util.*
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.suspendCancellableCoroutine
-import kotlinx.coroutines.withContext
-import kotlin.coroutines.resume
-
-class OverrideSettingsDesign(
-    context: Context,
-    configuration: ConfigurationOverride
-) : Design<OverrideSettingsDesign.Request>(context) {
-    enum class Request {
-        ResetOverride, EditSideloadGeoip
-    }
-
-    private val binding = DesignSettingsOverideBinding
-        .inflate(context.layoutInflater, context.root, false)
-
-    override val root: View
-        get() = binding.root
-
-    suspend fun requestResetConfirm(): Boolean {
-        return suspendCancellableCoroutine { ctx ->
-            val dialog = MaterialAlertDialogBuilder(context)
-                .setTitle(R.string.reset_override_settings)
-                .setMessage(R.string.reset_override_settings_message)
-                .setPositiveButton(R.string.ok) { _, _ -> ctx.resume(true) }
-                .setNegativeButton(R.string.cancel) { _, _ -> }
-                .show()
-
-            dialog.setOnDismissListener {
-                if (!ctx.isCompleted)
-                    ctx.resume(false)
-            }
-
-            ctx.invokeOnCancellation {
-                dialog.dismiss()
-            }
-        }
-    }
-
-    suspend fun requestSelectSideload(initial: String, apps: List<AppInfo>): String =
-        withContext(Dispatchers.Main) {
-            suspendCancellableCoroutine { ctx ->
-                val binding = DialogPreferenceListBinding
-                    .inflate(context.layoutInflater, context.root, false)
-                val adapter = SideloadProviderAdapter(context, apps, initial)
-                val dialog = FullScreenDialog(context)
-
-                dialog.setContentView(binding.root)
-
-                binding.surface = dialog.surface
-
-                binding.titleView.text = context.getString(R.string.sideload_geoip)
-
-                binding.newView.visibility = View.INVISIBLE
-
-                binding.mainList.applyLinearAdapter(context, adapter)
-
-                binding.resetView.setOnClickListener {
-                    ctx.resume("")
-
-                    dialog.dismiss()
-                }
-
-                binding.cancelView.setOnClickListener {
-                    dialog.dismiss()
-                }
-
-                binding.okView.setOnClickListener {
-                    ctx.resume(adapter.selectedPackageName)
-
-                    dialog.dismiss()
-                }
-
-                dialog.setOnDismissListener {
-                    if (!ctx.isCompleted)
-                        ctx.resume(initial)
-                }
-
-                dialog.show()
-            }
-        }
-
-    init {
-        binding.self = this
-
-        binding.activityBarLayout.applyFrom(context)
-
-        binding.scrollRoot.bindAppBarElevation(binding.activityBarLayout)
-
-        val booleanValues: Array<Boolean?> = arrayOf(
-            null,
-            true,
-            false
-        )
-        val booleanValuesText: Array<Int> = arrayOf(
-            R.string.dont_modify,
-            R.string.enabled,
-            R.string.disabled
-        )
-
-        val screen = preferenceScreen(context) {
-            category(R.string.general)
-
-            editableText(
-                value = configuration::httpPort,
-                adapter = NullableTextAdapter.Port,
-                title = R.string.http_port,
-                placeholder = R.string.dont_modify,
-                empty = R.string.disabled,
-            )
-
-            editableText(
-                value = configuration::socksPort,
-                adapter = NullableTextAdapter.Port,
-                title = R.string.socks_port,
-                placeholder = R.string.dont_modify,
-                empty = R.string.disabled,
-            )
-
-            editableText(
-                value = configuration::redirectPort,
-                adapter = NullableTextAdapter.Port,
-                title = R.string.redirect_port,
-                placeholder = R.string.dont_modify,
-                empty = R.string.disabled,
-            )
-
-            editableText(
-                value = configuration::tproxyPort,
-                adapter = NullableTextAdapter.Port,
-                title = R.string.tproxy_port,
-                placeholder = R.string.dont_modify,
-                empty = R.string.disabled,
-            )
-
-            editableText(
-                value = configuration::mixedPort,
-                adapter = NullableTextAdapter.Port,
-                title = R.string.mixed_port,
-                placeholder = R.string.dont_modify,
-                empty = R.string.disabled,
-            )
-
-            editableTextList(
-                value = configuration::authentication,
-                adapter = TextAdapter.String,
-                title = R.string.authentication,
-                placeholder = R.string.dont_modify,
-            )
-
-            selectableList(
-                value = configuration::allowLan,
-                values = booleanValues,
-                valuesText = booleanValuesText,
-                title = R.string.allow_lan,
-            )
-
-            selectableList(
-                value = configuration::ipv6,
-                values = booleanValues,
-                valuesText = booleanValuesText,
-                title = R.string.ipv6,
-            )
-
-            editableText(
-                value = configuration::bindAddress,
-                adapter = NullableTextAdapter.String,
-                title = R.string.bind_address,
-                placeholder = R.string.dont_modify,
-                empty = R.string.default_
-            )
-
-            selectableList(
-                value = configuration::mode,
-                values = arrayOf(
-                    null,
-                    TunnelState.Mode.Direct,
-                    TunnelState.Mode.Global,
-                    TunnelState.Mode.Rule,
-                ),
-                valuesText = arrayOf(
-                    R.string.dont_modify,
-                    R.string.direct_mode,
-                    R.string.global_mode,
-                    R.string.rule_mode,
-                ),
-                title = R.string.mode
-            )
-
-            selectableList(
-                value = configuration::logLevel,
-                values = arrayOf(
-                    null,
-                    LogMessage.Level.Info,
-                    LogMessage.Level.Warning,
-                    LogMessage.Level.Error,
-                    LogMessage.Level.Debug,
-                    LogMessage.Level.Silent,
-                ),
-                valuesText = arrayOf(
-                    R.string.dont_modify,
-                    R.string.info,
-                    R.string.warning,
-                    R.string.error,
-                    R.string.debug,
-                    R.string.silent,
-                ),
-                title = R.string.log_level,
-            )
-
-            editableTextMap(
-                value = configuration::hosts,
-                keyAdapter = TextAdapter.String,
-                valueAdapter = TextAdapter.String,
-                title = R.string.hosts,
-                placeholder = R.string.dont_modify,
-            )
-
-            clickable(
-                title = R.string.sideload_geoip,
-                summary = R.string.sideload_geoip_summary
-            ) {
-                clicked {
-                    requests.trySend(Request.EditSideloadGeoip)
-                }
-            }
-
-            category(R.string.dns)
-
-            val dnsDependencies: MutableList<Preference> = mutableListOf()
-
-            val dns = selectableList(
-                value = configuration.dns::enable,
-                values = arrayOf(
-                    null,
-                    true,
-                    false
-                ),
-                valuesText = arrayOf(
-                    R.string.dont_modify,
-                    R.string.force_enable,
-                    R.string.use_built_in,
-                ),
-                title = R.string.strategy
-            ) {
-                listener = OnChangedListener {
-                    if (configuration.dns.enable == false) {
-                        dnsDependencies.forEach {
-                            it.enabled = false
-                        }
-                    } else {
-                        dnsDependencies.forEach {
-                            it.enabled = true
-                        }
-                    }
-                }
-            }
-
-            editableText(
-                value = configuration.dns::listen,
-                adapter = NullableTextAdapter.String,
-                title = R.string.listen,
-                placeholder = R.string.dont_modify,
-                empty = R.string.disabled,
-                configure = dnsDependencies::add,
-            )
-
-            selectableList(
-                value = configuration.app::appendSystemDns,
-                values = booleanValues,
-                valuesText = booleanValuesText,
-                title = R.string.append_system_dns,
-                configure = dnsDependencies::add,
-            )
-
-            selectableList(
-                value = configuration.dns::ipv6,
-                values = booleanValues,
-                valuesText = booleanValuesText,
-                title = R.string.ipv6,
-                configure = dnsDependencies::add,
-            )
-
-            selectableList(
-                value = configuration.dns::useHosts,
-                values = booleanValues,
-                valuesText = booleanValuesText,
-                title = R.string.use_hosts,
-                configure = dnsDependencies::add,
-            )
-
-            selectableList(
-                value = configuration.dns::enhancedMode,
-                values = arrayOf(
-                    null,
-                    ConfigurationOverride.DnsEnhancedMode.None,
-                    ConfigurationOverride.DnsEnhancedMode.FakeIp,
-                    ConfigurationOverride.DnsEnhancedMode.Mapping
-                ),
-                valuesText = arrayOf(
-                    R.string.dont_modify,
-                    R.string.disabled,
-                    R.string.fakeip,
-                    R.string.mapping
-                ),
-                title = R.string.enhanced_mode,
-                configure = dnsDependencies::add,
-            )
-
-            editableTextList(
-                value = configuration.dns::nameServer,
-                adapter = TextAdapter.String,
-                title = R.string.name_server,
-                placeholder = R.string.dont_modify,
-                configure = dnsDependencies::add,
-            )
-
-            editableTextList(
-                value = configuration.dns::fallback,
-                adapter = TextAdapter.String,
-                title = R.string.fallback,
-                placeholder = R.string.dont_modify,
-                configure = dnsDependencies::add,
-            )
-
-            editableTextList(
-                value = configuration.dns::defaultServer,
-                adapter = TextAdapter.String,
-                title = R.string.default_name_server,
-                placeholder = R.string.dont_modify,
-                configure = dnsDependencies::add,
-            )
-
-            editableTextList(
-                value = configuration.dns::fakeIpFilter,
-                adapter = TextAdapter.String,
-                title = R.string.fakeip_filter,
-                placeholder = R.string.dont_modify,
-                configure = dnsDependencies::add,
-            )
-
-            selectableList(
-                value = configuration.dns.fallbackFilter::geoIp,
-                values = booleanValues,
-                valuesText = booleanValuesText,
-                title = R.string.geoip_fallback,
-                configure = dnsDependencies::add,
-            )
-
-            editableTextList(
-                value = configuration.dns.fallbackFilter::domain,
-                adapter = TextAdapter.String,
-                title = R.string.domain_fallback,
-                placeholder = R.string.dont_modify,
-                configure = dnsDependencies::add,
-            )
-
-            editableTextList(
-                value = configuration.dns.fallbackFilter::ipcidr,
-                adapter = TextAdapter.String,
-                title = R.string.ipcidr_fallback,
-                placeholder = R.string.dont_modify,
-                configure = dnsDependencies::add,
-            )
-
-            editableTextMap(
-                value = configuration.dns::nameserverPolicy,
-                keyAdapter = TextAdapter.String,
-                valueAdapter = TextAdapter.String,
-                title = R.string.name_server_policy,
-                placeholder = R.string.dont_modify,
-                configure = dnsDependencies::add,
-            )
-
-            dns.listener?.onChanged()
-        }
-
-        binding.content.addView(screen.root)
-    }
-
-    fun requestClear() {
-        requests.trySend(Request.ResetOverride)
-    }
-}
\ No newline at end of file
diff --git a/design/src/foss/java/com/github/kr328/clash/design/component/ProxyMenu.kt b/design/src/foss/java/com/github/kr328/clash/design/component/ProxyMenu.kt
deleted file mode 100644
index 017601f9..00000000
--- a/design/src/foss/java/com/github/kr328/clash/design/component/ProxyMenu.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.github.kr328.clash.design.component
-
-import android.content.Context
-import android.view.MenuItem
-import android.view.View
-import androidx.appcompat.widget.PopupMenu
-import com.github.kr328.clash.core.model.ProxySort
-import com.github.kr328.clash.core.model.TunnelState
-import com.github.kr328.clash.design.ProxyDesign
-import com.github.kr328.clash.design.R
-import com.github.kr328.clash.design.store.UiStore
-import kotlinx.coroutines.channels.Channel
-
-class ProxyMenu(
-    context: Context,
-    menuView: View,
-    mode: TunnelState.Mode?,
-    private val uiStore: UiStore,
-    private val requests: Channel<ProxyDesign.Request>,
-    private val updateConfig: () -> Unit,
-) : PopupMenu.OnMenuItemClickListener {
-    private val menu = PopupMenu(context, menuView)
-
-    fun show() {
-        menu.show()
-    }
-
-    override fun onMenuItemClick(item: MenuItem): Boolean {
-        item.isChecked = !item.isChecked
-
-        when (item.itemId) {
-            R.id.not_selectable -> {
-                uiStore.proxyExcludeNotSelectable = item.isChecked
-
-                requests.trySend(ProxyDesign.Request.ReLaunch)
-            }
-            R.id.single -> {
-                uiStore.proxySingleLine = true
-
-                updateConfig()
-
-                requests.trySend(ProxyDesign.Request.ReloadAll)
-            }
-            R.id.multiple -> {
-                uiStore.proxySingleLine = false
-
-                updateConfig()
-
-                requests.trySend(ProxyDesign.Request.ReloadAll)
-            }
-            R.id.default_ -> {
-                uiStore.proxySort = ProxySort.Default
-
-                requests.trySend(ProxyDesign.Request.ReloadAll)
-            }
-            R.id.name -> {
-                uiStore.proxySort = ProxySort.Title
-
-                requests.trySend(ProxyDesign.Request.ReloadAll)
-            }
-            R.id.delay -> {
-                uiStore.proxySort = ProxySort.Delay
-
-                requests.trySend(ProxyDesign.Request.ReloadAll)
-            }
-            R.id.dont_modify -> {
-                requests.trySend(ProxyDesign.Request.PatchMode(null))
-            }
-            R.id.direct_mode -> {
-                requests.trySend(ProxyDesign.Request.PatchMode(TunnelState.Mode.Direct))
-            }
-            R.id.global_mode -> {
-                requests.trySend(ProxyDesign.Request.PatchMode(TunnelState.Mode.Global))
-            }
-            R.id.rule_mode -> {
-                requests.trySend(ProxyDesign.Request.PatchMode(TunnelState.Mode.Rule))
-            }
-            else -> return false
-        }
-
-        return true
-    }
-
-    init {
-        menu.menuInflater.inflate(R.menu.menu_proxy, menu.menu)
-
-        menu.menu.apply {
-            findItem(R.id.not_selectable).isChecked = uiStore.proxyExcludeNotSelectable
-
-            if (uiStore.proxySingleLine) {
-                findItem(R.id.single).isChecked = true
-            } else {
-                findItem(R.id.multiple).isChecked = true
-            }
-
-            when (uiStore.proxySort) {
-                ProxySort.Default -> findItem(R.id.default_).isChecked = true
-                ProxySort.Title -> findItem(R.id.name).isChecked = true
-                ProxySort.Delay -> findItem(R.id.delay).isChecked = true
-            }
-
-            when (mode) {
-                null -> findItem(R.id.dont_modify).isChecked = true
-                TunnelState.Mode.Direct -> findItem(R.id.direct_mode).isChecked = true
-                TunnelState.Mode.Global -> findItem(R.id.global_mode).isChecked = true
-                TunnelState.Mode.Rule -> findItem(R.id.rule_mode).isChecked = true
-                TunnelState.Mode.Script -> throw IllegalStateException("invalid mode")
-            }
-        }
-
-        menu.setOnMenuItemClickListener(this)
-    }
-}
\ No newline at end of file
diff --git a/design/src/foss/res/menu/menu_proxy.xml b/design/src/foss/res/menu/menu_proxy.xml
deleted file mode 100644
index aefb5f93..00000000
--- a/design/src/foss/res/menu/menu_proxy.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:title="@string/filter">
-        <menu>
-            <item
-                android:id="@+id/not_selectable"
-                android:checkable="true"
-                android:title="@string/not_selectable" />
-        </menu>
-    </item>
-    <item android:title="@string/mode">
-        <menu>
-            <group android:checkableBehavior="single">
-                <item
-                    android:id="@+id/dont_modify"
-                    android:title="@string/dont_modify" />
-                <item
-                    android:id="@+id/direct_mode"
-                    android:title="@string/direct_mode" />
-                <item
-                    android:id="@+id/global_mode"
-                    android:title="@string/global_mode" />
-                <item
-                    android:id="@+id/rule_mode"
-                    android:title="@string/rule_mode" />
-            </group>
-        </menu>
-    </item>
-    <item android:title="@string/layout">
-        <menu>
-            <group android:checkableBehavior="single">
-                <item
-                    android:id="@+id/single"
-                    android:title="@string/single" />
-                <item
-                    android:id="@+id/multiple"
-                    android:title="@string/multiple" />
-            </group>
-        </menu>
-    </item>
-    <item android:title="@string/sort">
-        <menu>
-            <group android:checkableBehavior="single">
-                <item
-                    android:id="@+id/default_"
-                    android:title="@string/default_" />
-                <item
-                    android:id="@+id/name"
-                    android:title="@string/name" />
-                <item
-                    android:id="@+id/delay"
-                    android:title="@string/delay" />
-            </group>
-        </menu>
-    </item>
-</menu>
diff --git a/design/src/foss/java/com/github/kr328/clash/design/HelpDesign.kt b/design/src/main/java/com/github/kr328/clash/design/HelpDesign.kt
similarity index 70%
rename from design/src/foss/java/com/github/kr328/clash/design/HelpDesign.kt
rename to design/src/main/java/com/github/kr328/clash/design/HelpDesign.kt
index 4522fc03..047eb3d1 100644
--- a/design/src/foss/java/com/github/kr328/clash/design/HelpDesign.kt
+++ b/design/src/main/java/com/github/kr328/clash/design/HelpDesign.kt
@@ -47,6 +47,17 @@ class HelpDesign(
 
             category(R.string.feedback)
 
+            if (BuildConfig.PREMIUM) {
+                clickable(
+                    title = R.string.google_play,
+                    summary = R.string.google_play_url
+                ) {
+                    clicked {
+                        openLink(Uri.parse(context.getString(R.string.google_play_url)))
+                    }
+                }
+            }
+
             clickable(
                 title = R.string.github_issues,
                 summary = R.string.github_issues_url
@@ -56,23 +67,25 @@ class HelpDesign(
                 }
             }
 
-            category(R.string.sources)
+            if (!BuildConfig.PREMIUM) {
+                category(R.string.sources)
 
-            clickable(
-                title = R.string.clash_for_android,
-                summary = R.string.github_url
-            ) {
-                clicked {
-                    openLink(Uri.parse(context.getString(R.string.github_url)))
+                clickable(
+                    title = R.string.clash_for_android,
+                    summary = R.string.github_url
+                ) {
+                    clicked {
+                        openLink(Uri.parse(context.getString(R.string.github_url)))
+                    }
                 }
-            }
 
-            clickable(
-                title = R.string.clash_core,
-                summary = R.string.clash_core_url
-            ) {
-                clicked {
-                    openLink(Uri.parse(context.getString(R.string.clash_core_url)))
+                clickable(
+                    title = R.string.clash_core,
+                    summary = R.string.clash_core_url
+                ) {
+                    clicked {
+                        openLink(Uri.parse(context.getString(R.string.clash_core_url)))
+                    }
                 }
             }
 
diff --git a/design/src/premium/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt b/design/src/main/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
similarity index 90%
rename from design/src/premium/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
rename to design/src/main/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
index 6bfd597e..118744c5 100644
--- a/design/src/premium/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
+++ b/design/src/main/java/com/github/kr328/clash/design/OverrideSettingsDesign.kt
@@ -185,24 +185,43 @@ class OverrideSettingsDesign(
                 empty = R.string.default_
             )
 
-            selectableList(
-                value = configuration::mode,
-                values = arrayOf(
-                    null,
-                    TunnelState.Mode.Direct,
-                    TunnelState.Mode.Global,
-                    TunnelState.Mode.Rule,
-                    TunnelState.Mode.Script
-                ),
-                valuesText = arrayOf(
-                    R.string.dont_modify,
-                    R.string.direct_mode,
-                    R.string.global_mode,
-                    R.string.rule_mode,
-                    R.string.script_mode
-                ),
-                title = R.string.mode
-            )
+            if (BuildConfig.PREMIUM) {
+                selectableList(
+                    value = configuration::mode,
+                    values = arrayOf(
+                        null,
+                        TunnelState.Mode.Direct,
+                        TunnelState.Mode.Global,
+                        TunnelState.Mode.Rule,
+                        TunnelState.Mode.Script
+                    ),
+                    valuesText = arrayOf(
+                        R.string.dont_modify,
+                        R.string.direct_mode,
+                        R.string.global_mode,
+                        R.string.rule_mode,
+                        R.string.script_mode
+                    ),
+                    title = R.string.mode
+                )
+            } else {
+                selectableList(
+                    value = configuration::mode,
+                    values = arrayOf(
+                        null,
+                        TunnelState.Mode.Direct,
+                        TunnelState.Mode.Global,
+                        TunnelState.Mode.Rule
+                    ),
+                    valuesText = arrayOf(
+                        R.string.dont_modify,
+                        R.string.direct_mode,
+                        R.string.global_mode,
+                        R.string.rule_mode
+                    ),
+                    title = R.string.mode
+                )
+            }
 
             selectableList(
                 value = configuration::logLevel,
diff --git a/design/src/premium/java/com/github/kr328/clash/design/component/ProxyMenu.kt b/design/src/main/java/com/github/kr328/clash/design/component/ProxyMenu.kt
similarity index 96%
rename from design/src/premium/java/com/github/kr328/clash/design/component/ProxyMenu.kt
rename to design/src/main/java/com/github/kr328/clash/design/component/ProxyMenu.kt
index 89c81f40..bd05cdfc 100644
--- a/design/src/premium/java/com/github/kr328/clash/design/component/ProxyMenu.kt
+++ b/design/src/main/java/com/github/kr328/clash/design/component/ProxyMenu.kt
@@ -6,6 +6,7 @@ import android.view.View
 import androidx.appcompat.widget.PopupMenu
 import com.github.kr328.clash.core.model.ProxySort
 import com.github.kr328.clash.core.model.TunnelState
+import com.github.kr328.clash.design.BuildConfig
 import com.github.kr328.clash.design.ProxyDesign
 import com.github.kr328.clash.design.R
 import com.github.kr328.clash.design.store.UiStore
@@ -88,6 +89,8 @@ class ProxyMenu(
         menu.menuInflater.inflate(R.menu.menu_proxy, menu.menu)
 
         menu.menu.apply {
+            findItem(R.id.script_mode).isVisible = BuildConfig.PREMIUM
+
             findItem(R.id.not_selectable).isChecked = uiStore.proxyExcludeNotSelectable
 
             if (uiStore.proxySingleLine) {
diff --git a/design/src/premium/res/menu/menu_proxy.xml b/design/src/main/res/menu/menu_proxy.xml
similarity index 100%
rename from design/src/premium/res/menu/menu_proxy.xml
rename to design/src/main/res/menu/menu_proxy.xml
diff --git a/design/src/premium/java/com/github/kr328/clash/design/HelpDesign.kt b/design/src/premium/java/com/github/kr328/clash/design/HelpDesign.kt
deleted file mode 100644
index d81ce885..00000000
--- a/design/src/premium/java/com/github/kr328/clash/design/HelpDesign.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.github.kr328.clash.design
-
-import android.content.Context
-import android.net.Uri
-import android.view.View
-import com.github.kr328.clash.common.compat.preferredLocale
-import com.github.kr328.clash.design.databinding.DesignSettingsCommonBinding
-import com.github.kr328.clash.design.preference.category
-import com.github.kr328.clash.design.preference.clickable
-import com.github.kr328.clash.design.preference.preferenceScreen
-import com.github.kr328.clash.design.preference.tips
-import com.github.kr328.clash.design.util.applyFrom
-import com.github.kr328.clash.design.util.bindAppBarElevation
-import com.github.kr328.clash.design.util.layoutInflater
-import com.github.kr328.clash.design.util.root
-
-class HelpDesign(
-    context: Context,
-    openLink: (Uri) -> Unit,
-) : Design<Unit>(context) {
-    private val binding = DesignSettingsCommonBinding
-        .inflate(context.layoutInflater, context.root, false)
-
-    override val root: View
-        get() = binding.root
-
-    init {
-        binding.surface = surface
-
-        binding.activityBarLayout.applyFrom(context)
-
-        binding.scrollRoot.bindAppBarElevation(binding.activityBarLayout)
-
-        val screen = preferenceScreen(context) {
-            tips(R.string.tips_help)
-
-            category(R.string.document)
-
-            clickable(
-                title = R.string.clash_wiki,
-                summary = R.string.clash_wiki_url
-            ) {
-                clicked {
-                    openLink(Uri.parse(context.getString(R.string.clash_wiki_url)))
-                }
-            }
-
-            category(R.string.feedback)
-
-            clickable(
-                title = R.string.github_issues,
-                summary = R.string.github_issues_url
-            ) {
-                clicked {
-                    openLink(Uri.parse(context.getString(R.string.github_issues_url)))
-                }
-            }
-
-            clickable(
-                title = R.string.google_play,
-                summary = R.string.google_play_url
-            ) {
-                clicked {
-                    openLink(Uri.parse(context.getString(R.string.google_play_url)))
-                }
-            }
-
-            if (context.resources.configuration.preferredLocale.language == "zh") {
-                category(R.string.donate)
-
-                clickable(
-                    title = R.string.donate,
-                    summary = R.string.donate_url
-                ) {
-                    clicked {
-                        openLink(Uri.parse(context.getString(R.string.donate_url)))
-                    }
-                }
-            }
-        }
-
-        binding.content.addView(screen.root)
-    }
-}
\ No newline at end of file
-- 
GitLab