add zh-cn
This commit is contained in:
26 files changed
+142
-56
No files matched your search
@@ -103,7 +103,7 @@ abstract class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope()
|
||||
if (language.isEmpty())
|
||||
return super.attachBaseContext(base)
|
||||
|
||||
val configuration = base.resources.configuration
|
||||
val configuration = Configuration()
|
||||
val localeOverride = if (languageOverride.size == 2)
|
||||
Locale(languageOverride[0], languageOverride[1])
|
||||
else
|
||||
@@ -117,6 +117,8 @@ abstract class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope()
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
language = uiSettings.get(UiSettings.LANGUAGE)
|
||||
|
||||
resetDarkMode()
|
||||
|
||||
resetLightNavigationBar()
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.github.kr328.clash.service.ClashService
|
||||
import com.github.kr328.clash.service.data.ClashProfileEntity
|
||||
import com.github.kr328.clash.service.util.intent
|
||||
import com.github.kr328.clash.service.util.startForegroundServiceCompat
|
||||
import com.github.kr328.clash.utils.startClashService
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -35,10 +36,8 @@ class MainActivity : BaseActivity() {
|
||||
if (clashRunning) {
|
||||
stopService(ClashService::class.intent)
|
||||
} else {
|
||||
val vpnRequest = VpnService.prepare(this)
|
||||
if (vpnRequest == null)
|
||||
startForegroundServiceCompat(ClashService::class.intent)
|
||||
else
|
||||
val vpnRequest = startClashService()
|
||||
if ( vpnRequest != null )
|
||||
startActivityForResult(vpnRequest, REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@ package com.github.kr328.clash
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import com.github.kr328.clash.core.Global
|
||||
import com.github.kr328.clash.core.utils.Log
|
||||
import com.github.kr328.clash.preference.UiSettings
|
||||
import com.github.kr328.clash.remote.Broadcasts
|
||||
import com.github.kr328.clash.remote.Remote
|
||||
import com.microsoft.appcenter.AppCenter
|
||||
import com.microsoft.appcenter.analytics.Analytics
|
||||
import com.microsoft.appcenter.crashes.Crashes
|
||||
import java.util.*
|
||||
|
||||
@Suppress("unused")
|
||||
class MainApplication : Application() {
|
||||
|
||||
@@ -3,9 +3,19 @@ package com.github.kr328.clash
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.github.kr328.clash.service.Intents
|
||||
import com.github.kr328.clash.service.ProfileBackgroundService
|
||||
import com.github.kr328.clash.service.util.componentName
|
||||
import com.github.kr328.clash.service.util.startForegroundServiceCompat
|
||||
import com.github.kr328.clash.utils.startClashService
|
||||
|
||||
class OnBootReceiver: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if ( intent?.action != Intent.ACTION_BOOT_COMPLETED || context == null )
|
||||
return
|
||||
|
||||
context.startClashService()
|
||||
context.startForegroundServiceCompat(Intent(Intents.INTENT_ACTION_PROFILE_SETUP)
|
||||
.setComponent(ProfileBackgroundService::class.componentName))
|
||||
}
|
||||
}
|
||||
@@ -294,11 +294,18 @@ class ProxiesActivity : BaseActivity(), ScrollBinding.Callback {
|
||||
PrefixMerger.Result(p.name, "", p)
|
||||
}
|
||||
|
||||
val data = if ( r.content.isEmpty() ) {
|
||||
r.prefix to p.type.toString()
|
||||
}
|
||||
else {
|
||||
r.content to r.prefix
|
||||
}
|
||||
|
||||
ProxyAdapter.ProxyInfo(
|
||||
p.name,
|
||||
it.name,
|
||||
r.prefix,
|
||||
if (r.content.isEmpty()) p.type.toString() else r.content,
|
||||
data.first,
|
||||
data.second,
|
||||
p.delay.toShort(),
|
||||
it.type == Proxy.Type.SELECT,
|
||||
p.name == it.current
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.github.kr328.clash
|
||||
|
||||
import android.os.Bundle
|
||||
import com.github.kr328.clash.settings.NetworkFragment
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
class SettingsNetworkActivity : BaseActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -13,6 +14,9 @@ class SettingsNetworkActivity : BaseActivity() {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment, NetworkFragment())
|
||||
.commit()
|
||||
|
||||
if ( clashRunning )
|
||||
Snackbar.make(rootView, R.string.options_unavailable, Snackbar.LENGTH_INDEFINITE).show()
|
||||
}
|
||||
|
||||
override val activityLabel: CharSequence?
|
||||
|
||||
@@ -132,6 +132,6 @@ class ProfileAdapter(private val context: Context, private val callback: Callbac
|
||||
}
|
||||
|
||||
private fun offsetDate(date: Long): CharSequence {
|
||||
return IntervalUtils.intervalString(System.currentTimeMillis() - date)
|
||||
return IntervalUtils.intervalString(context,System.currentTimeMillis() - date)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.github.kr328.clash.settings
|
||||
|
||||
import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.preference.UiSettings
|
||||
import com.github.kr328.clash.service.settings.ServiceSettings
|
||||
|
||||
class InterfaceFragment: BaseSettingFragment() {
|
||||
companion object {
|
||||
@@ -15,6 +16,10 @@ class InterfaceFragment: BaseSettingFragment() {
|
||||
on(KEY_LANGUAGE, UiSettings.LANGUAGE.asSource(ui))
|
||||
|
||||
onApply {
|
||||
service.commit {
|
||||
put(ServiceSettings.LANGUAGE, ui.get(UiSettings.LANGUAGE))
|
||||
}
|
||||
|
||||
requireActivity().recreate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.github.kr328.clash.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import com.github.kr328.clash.BaseActivity
|
||||
import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.preference.UiSettings
|
||||
import com.github.kr328.clash.service.settings.ServiceSettings
|
||||
@@ -15,6 +17,13 @@ class NetworkFragment: BaseSettingFragment() {
|
||||
private const val KEY_ACCESS_CONTROL_MODE = "access_control_mode"
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if ((requireActivity() as BaseActivity).clashRunning)
|
||||
preferenceScreen.isEnabled = false
|
||||
}
|
||||
|
||||
override fun onCreateDataStore(): SettingsDataStore {
|
||||
return SettingsDataStore().apply {
|
||||
on(KEY_ENABLE_VPN_SERVICE, UiSettings.ENABLE_VPN.asSource(ui))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.kr328.clash.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.core.Global
|
||||
|
||||
@@ -11,9 +12,7 @@ object IntervalUtils {
|
||||
private const val MILLIS_MONTH = MILLIS_DAY * 30
|
||||
private const val MILLIS_YEAR = MILLIS_MONTH * 12
|
||||
|
||||
fun intervalString(interval: Long): String {
|
||||
val context = Global.application
|
||||
|
||||
fun intervalString(context: Context, interval: Long): String {
|
||||
val year = interval / MILLIS_YEAR
|
||||
val month = interval / MILLIS_MONTH
|
||||
val day = interval / MILLIS_DAY
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.github.kr328.clash.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.VpnService
|
||||
import com.github.kr328.clash.preference.UiSettings
|
||||
import com.github.kr328.clash.service.ClashService
|
||||
import com.github.kr328.clash.service.Intents
|
||||
import com.github.kr328.clash.service.util.intent
|
||||
import com.github.kr328.clash.service.util.startForegroundServiceCompat
|
||||
|
||||
fun Context.startClashService(): Intent? {
|
||||
val startTun = UiSettings(this).get(UiSettings.ENABLE_VPN)
|
||||
|
||||
if ( startTun ) {
|
||||
val vpnRequest = VpnService.prepare(this)
|
||||
if ( vpnRequest != null )
|
||||
return vpnRequest
|
||||
}
|
||||
|
||||
startForegroundServiceCompat(ClashService::class.intent
|
||||
.putExtra(Intents.INTENT_EXTRA_START_TUN, startTun))
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorOnSurface"
|
||||
android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10 10,-4.49 10,-10S17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15,12c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3 1.34,-3 3,-3 3,1.34 3,3z"/>
|
||||
</vector>
|
||||
@@ -2,7 +2,6 @@
|
||||
<resources>
|
||||
<string name="access_control_packages_summary">为应用配置访问权限</string>
|
||||
<string name="about">关于</string>
|
||||
<string name="access_control">访问控制</string>
|
||||
<string name="access_control_mode">访问控制模式</string>
|
||||
<string name="access_control_packages">访问控制应用包列表</string>
|
||||
<string name="append_system_dns">追加系统 DNS</string>
|
||||
@@ -15,7 +14,6 @@
|
||||
<string name="bypass_private_network">绕过私有网络</string>
|
||||
<string name="bypass_private_network_summary">绕过私有网络地址</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="capturing_clash_log">正在捕捉日志</string>
|
||||
<string name="clash_logcat">Clash 日志捕捉工具</string>
|
||||
<string name="clash_new_profile">新配置</string>
|
||||
<string name="clash_start_failure">Clash 启动失败</string>
|
||||
@@ -42,12 +40,10 @@
|
||||
<string name="edit_profile">编辑配置</string>
|
||||
<string name="empty_name">空名称</string>
|
||||
<string name="enable_ipv6">启用 IPv6 支持 (不建议)</string>
|
||||
<string name="enabled">已启用</string>
|
||||
<string name="exit_without_save">退出而不保存</string>
|
||||
<string name="exit_without_save_warning">所有变更将会丢失</string>
|
||||
<string name="export">导出</string>
|
||||
<string name="external">外部</string>
|
||||
<string name="feedback">反馈</string>
|
||||
<string name="file">文件</string>
|
||||
<string name="file_exported">文件已导出</string>
|
||||
<string name="format_date_time">%s %s</string>
|
||||
@@ -86,7 +82,7 @@
|
||||
<string name="profile">配置</string>
|
||||
<string name="profile_name">配置名称</string>
|
||||
<string name="profile_url">配置 URL</string>
|
||||
<string name="profiles">配置文件</string>
|
||||
<string name="profiles">配置</string>
|
||||
<string name="properties">参数</string>
|
||||
<string name="proxy">代理</string>
|
||||
<string name="recently">近期</string>
|
||||
@@ -97,7 +93,6 @@
|
||||
<string name="rule">规则</string>
|
||||
<string name="rule_mode">规则模式</string>
|
||||
<string name="running">运行中</string>
|
||||
<string name="send">发送</string>
|
||||
<string name="settings">设置</string>
|
||||
<string name="show_traffic">显示流量</string>
|
||||
<string name="show_traffic_summary">在通知中自动刷新流量</string>
|
||||
@@ -114,4 +109,5 @@
|
||||
<string name="url">URL</string>
|
||||
<string name="utils">实用工具</string>
|
||||
<string name="vpn_service">VPN Service</string>
|
||||
<string name="options_unavailable">选项在 Clash 运行时不可用</string>
|
||||
</resources>
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
<string name="logs">Logs</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="feedback">Feedback</string>
|
||||
<string name="support">Support</string>
|
||||
<string name="about">About</string>
|
||||
|
||||
@@ -54,7 +53,6 @@
|
||||
<string name="edit">Edit</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="export">Export</string>
|
||||
<string name="send">Send</string>
|
||||
<string name="properties">Properties</string>
|
||||
<string name="duplicate">Duplicate</string>
|
||||
<string name="reset_provider">Reset Providers</string>
|
||||
@@ -91,9 +89,7 @@
|
||||
<string name="cancel">Cancel</string>
|
||||
|
||||
<string name="clash_logcat">Clash Logcat</string>
|
||||
<string name="capturing_clash_log">Capturing logs</string>
|
||||
<string name="history">History</string>
|
||||
<string name="enabled">Enabled</string>
|
||||
<string name="log_viewer">Log Viewer</string>
|
||||
<string name="format_date_time">%s %s</string>
|
||||
<string name="format_export_log_name">%s %s.log</string>
|
||||
@@ -131,11 +127,12 @@
|
||||
<string name="dns_override_summary">Force use builtin DNS config</string>
|
||||
<string name="append_system_dns">Append System DNS</string>
|
||||
<string name="append_system_dns_summary">Auto add system dns to clash</string>
|
||||
<string name="access_control">Access Control</string>
|
||||
<string name="access_control_mode">Access Control Mode</string>
|
||||
<string name="access_control_packages">Access Control Packages</string>
|
||||
<string name="access_control_packages_summary">Configure access permission for apps</string>
|
||||
|
||||
<string name="language">Language</string>
|
||||
<string name="dark_mode">Dark Mode</string>
|
||||
|
||||
<string name="options_unavailable">Options Unavailable until Clash Stopped</string>
|
||||
</resources>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<cache-path
|
||||
name="export_logs"
|
||||
path="logs" />
|
||||
<external-cache-path
|
||||
name="export_external_logs"
|
||||
path="logs" />
|
||||
</paths>
|
||||
@@ -104,6 +104,7 @@ func parseConfig(data []byte, baseDir string) (*config.Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
raw.Experimental.Interface = ""
|
||||
raw.ExternalUI = ""
|
||||
raw.ExternalController = ""
|
||||
raw.Rule = append([]string{fmt.Sprintf("IP-CIDR,%s,REJECT", tunAddress)}, raw.Rule...)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.github.kr328.clash.core
|
||||
|
||||
import android.app.Application
|
||||
import android.content.res.Configuration
|
||||
|
||||
object Global {
|
||||
lateinit var application: Application
|
||||
val overrideConfiguration = Configuration()
|
||||
|
||||
fun init(application: Application) {
|
||||
this.application = application
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<string name="launch_name">core</string>
|
||||
</resources>
|
||||
@@ -1,12 +1,37 @@
|
||||
package com.github.kr328.clash.service
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import com.github.kr328.clash.core.Clash
|
||||
import com.github.kr328.clash.service.settings.ServiceSettings
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import java.util.*
|
||||
|
||||
abstract class BaseService : Service(), CoroutineScope by MainScope() {
|
||||
lateinit var settings: ServiceSettings
|
||||
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
settings = ServiceSettings(base ?: return super.attachBaseContext(base))
|
||||
|
||||
val language = settings.get(ServiceSettings.LANGUAGE)
|
||||
if ( language.isEmpty() )
|
||||
return super.attachBaseContext(base)
|
||||
val languageOverride = language.split("-")
|
||||
|
||||
val configuration = Configuration()
|
||||
val localeOverride = if (languageOverride.size == 2)
|
||||
Locale(languageOverride[0], languageOverride[1])
|
||||
else
|
||||
Locale(languageOverride[0])
|
||||
|
||||
configuration.setLocale(localeOverride)
|
||||
|
||||
super.attachBaseContext(base.createConfigurationContext(configuration))
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
|
||||
@@ -63,9 +63,7 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
|
||||
init {
|
||||
createNotificationChannel()
|
||||
|
||||
runBlocking {
|
||||
update()
|
||||
}
|
||||
notifyBaseNotification()
|
||||
|
||||
if (enableRefresh) {
|
||||
launch {
|
||||
@@ -133,6 +131,15 @@ class ClashNotification(private val context: ClashService, enableRefresh: Boolea
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyBaseNotification() {
|
||||
val notification = baseBuilder
|
||||
.setContentTitle(profile)
|
||||
.setContentText(context.getText(R.string.running))
|
||||
.build()
|
||||
|
||||
context.startForeground(CLASH_STATUS_NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
private suspend fun update() {
|
||||
val notification = withContext(Dispatchers.Default) {
|
||||
createNotification()
|
||||
|
||||
@@ -18,9 +18,6 @@ import kotlinx.coroutines.sync.Mutex
|
||||
|
||||
class ClashService : BaseService() {
|
||||
companion object {
|
||||
const val INTENT_EXTRA_START_TUN =
|
||||
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.start.tun"
|
||||
|
||||
var isServiceRunning = false
|
||||
}
|
||||
|
||||
@@ -29,7 +26,6 @@ class ClashService : BaseService() {
|
||||
private lateinit var notification: ClashNotification
|
||||
private var stopReason: String? = null
|
||||
private val reloadChannel = Channel<Unit>(Channel.CONFLATED)
|
||||
private val settings: ServiceSettings by lazy { ServiceSettings(this) }
|
||||
private val reloadReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent?.`package` != packageName)
|
||||
@@ -64,7 +60,8 @@ class ClashService : BaseService() {
|
||||
|
||||
broadcastClashStarted(this)
|
||||
|
||||
val startVpn = intent?.getBooleanExtra(INTENT_EXTRA_START_TUN, true) ?: true
|
||||
val startVpn = intent?.getBooleanExtra(
|
||||
Intents.INTENT_EXTRA_START_TUN, true) ?: true
|
||||
|
||||
if (startVpn)
|
||||
startService(TunService::class.intent)
|
||||
|
||||
@@ -22,4 +22,6 @@ object Intents {
|
||||
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.profile"
|
||||
const val INTENT_EXTRA_PROFILE_REQUEST =
|
||||
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.profile.request"
|
||||
const val INTENT_EXTRA_START_TUN =
|
||||
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.start.tun"
|
||||
}
|
||||
@@ -68,8 +68,6 @@ class DefaultNetworkChannel(val context: Context, scope: CoroutineScope) :
|
||||
return
|
||||
|
||||
launch {
|
||||
delay(1000)
|
||||
|
||||
val network = detectDefaultNetwork()
|
||||
val link = network?.let(connectivity::getLinkProperties)
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ class ServiceSettings(context: Context):
|
||||
const val ACCESS_CONTROL_MODE_BLACKLIST = "access_control_mode_blacklist"
|
||||
const val ACCESS_CONTROL_MODE_WHITELIST = "access_control_mode_whitelist"
|
||||
|
||||
val LANGUAGE =
|
||||
StringEntry("language", "")
|
||||
val IPV6_SUPPORT =
|
||||
BooleanEntry("ipv6_support", false)
|
||||
val BYPASS_PRIVATE_NETWORK =
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="clash_manager_service_label">Clash 管理器服务</string>
|
||||
<string name="clash_profile_service_label">Clash 配置管理服务</string>
|
||||
<string name="clash_service_label">Clash 核心服务</string>
|
||||
<string name="clash_service_status_channel">Clash 状态</string>
|
||||
<string name="profile_service_status_channel">配置服务状态</string>
|
||||
<string name="profile_service_status_title">配置更新工具正在运行</string>
|
||||
<string name="profile_status_channel">配置处理状态</string>
|
||||
<string name="profile_status_title">正在处理配置文件</string>
|
||||
<string name="profile_status_update_completed">更新 %s 完成</string>
|
||||
<string name="profile_status_update_failure">更新 %s 失败</string>
|
||||
<string name="profile_status_updating">正在更新 %s</string>
|
||||
<string name="running">正在运行</string>
|
||||
<string name="tun_service_label">Tun 服务</string>
|
||||
</resources>
|
||||
@@ -1,10 +1,8 @@
|
||||
<resources>
|
||||
<string name="launch_name">Clash</string>
|
||||
|
||||
<string name="clash_service_status_channel">Clash Status</string>
|
||||
|
||||
<!-- from https://github.com/shadowsocks/shadowsocks-android/blob/master/core/src/main/res/values/strings.xml -->
|
||||
<string name="clash_notification_content">"%1$s↑\t%2$s↓"</string>
|
||||
<string name="clash_notification_content" translatable="false">"%1$s↑\t%2$s↓"</string>
|
||||
|
||||
<string name="profile_service_status_channel">Profile Service Status</string>
|
||||
<string name="profile_service_status_title">Profile Updater Running</string>
|
||||
@@ -19,4 +17,6 @@
|
||||
<string name="tun_service_label">Tun Device Service</string>
|
||||
<string name="clash_manager_service_label">Clash Manager Service</string>
|
||||
<string name="clash_profile_service_label">Clash Profile Manager Service</string>
|
||||
|
||||
<string name="running">Running</string>
|
||||
</resources>
|
||||
Reference in new issue
Block a user