Commit e2364b14 authored by マシュ・キリエライト's avatar マシュ・キリエライト Committed by Mygod

support night theme (#1750)

* kotlin version materialdrawer

* support dark theme

* add night mode settings

* revert materialdrawer

* revert translucent style

* update dark theme color

* add night mode changed listener

* fix dependency issue

* Fix issues with bottom sheet

* Use support lib default value

* fix stat title color

* change default nightmode value

* update background color

* add night about page

* clean style

* Fix colors in selection mode in custom rules

* Fix weird AboutFragment issues

* Misc refinements

* Fix cucstom tabs colors

* Fix inconsistent color in background_profile

* Add EXTRA_NIGHT_MODE to plugin interface

* Revert changes to plugin/build.gradle

* update toolbar popupTheme
parent 2b3524df
......@@ -26,9 +26,11 @@
android:fullBackupContent="@xml/backup_descriptor"
android:fullBackupOnly="true"
android:label="@string/app_name"
android:theme="@style/Theme.Shadowsocks.App"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:banner="@drawable/ic_service_active">
android:banner="@drawable/ic_service_active"
tools:replace="android:theme">
<meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
android:value="true" />
......
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>MarkdownPad Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
/* Author: Nicolas Hery - http://nicolashery.com */
/* Version: 29d1c5bc36da364ad5aa86946d420b7bbc54a253 */
/* Source: https://github.com/nicolahery/markdownpad-github */
/* RESET
=============================================================================*/
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
}
/* BODY
=============================================================================*/
body {
font-family: Helvetica, arial, freesans, clean, sans-serif;
font-size: 14px;
line-height: 1.6;
color: #333;
background-color: #303030;
padding: 20px;
max-width: 960px;
margin: 0 auto;
}
body>*:first-child {
margin-top: 0 !important;
}
body>*:last-child {
margin-bottom: 0 !important;
}
/* BLOCKS
=============================================================================*/
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
color: white;
}
/* HEADERS
=============================================================================*/
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}
h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}
h1 {
font-size: 28px;
color: #000;
}
h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}
h3 {
font-size: 18px;
color: white;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
color: #777;
font-size: 14px;
}
body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}
/* LINKS
=============================================================================*/
a {
color: #4183C4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* LISTS
=============================================================================*/
ul, ol {
padding-left: 30px;
}
ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}
ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}
dl {
padding: 0;
}
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
dl dt:first-child {
padding: 0;
}
dl dt>:first-child {
margin-top: 0px;
}
dl dt>:last-child {
margin-bottom: 0px;
}
dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
dl dd>:first-child {
margin-top: 0px;
}
dl dd>:last-child {
margin-bottom: 0px;
}
/* CODE
=============================================================================*/
pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}
code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}
/* QUOTES
=============================================================================*/
blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}
blockquote>:first-child {
margin-top: 0px;
}
blockquote>:last-child {
margin-bottom: 0px;
}
/* HORIZONTAL RULES
=============================================================================*/
hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}
/* TABLES
=============================================================================*/
table th {
font-weight: bold;
}
table th, table td {
border: 1px solid #ccc;
padding: 6px 13px;
}
table tr {
border-top: 1px solid #ccc;
background-color: #303030;
}
table tr:nth-child(2n) {
background-color: #f8f8f8;
}
/* IMAGES
=============================================================================*/
img {
max-width: 100%
}
</style>
</head>
<body>
<p>A <a href="http://shadowsocks.org">Shadowsocks</a> client for Android, written in Kotlin.</p>
<p>Copyright (C) 2017 by Max Lv <a href="&#x6d;&#97;&#x69;&#108;&#116;&#111;&#x3a;&#x6d;&#97;x&#46;&#99;.&#108;&#118;&#x40;&#103;&#109;&#97;&#x69;&#108;&#46;&#x63;&#x6f;&#109;">&#x6d;&#97;&#x78;.&#x63;&#x2e;&#108;v&#64;&#x67;&#109;&#x61;&#x69;&#108;&#x2e;&#99;&#111;&#109;</a></p>
<p>Copyright (C) 2017 by Mygod Studio <a href="mailto:contact-shadowsocks-android@mygod.be">contact-shadowsocks-android@mygod.be</a></p>
<p>This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.</p>
<p>This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.</p>
<p>You should have received a copy of the GNU General Public License
along with this program. If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.</p>
<h3>Open Source Licenses</h3>
<ul>
<li>redsocks: <a href="https://github.com/shadowsocks/redsocks/blob/shadowsocks-android/README">APL 2.0</a></li>
<li>mbed TLS: <a href="https://github.com/ARMmbed/mbedtls/blob/development/LICENSE">APL 2.0</a></li>
<li>libevent: <a href="https://github.com/shadowsocks/libevent/blob/master/LICENSE">BSD</a></li>
<li>tun2socks: <a href="https://github.com/shadowsocks/badvpn/blob/shadowsocks-android/COPYING">BSD</a></li>
<li>pcre: <a href="https://android.googlesource.com/platform/external/pcre/+/master/dist2/LICENCE">BSD</a></li>
<li>libancillary: <a href="https://github.com/shadowsocks/libancillary/blob/shadowsocks-android/COPYING">BSD</a></li>
<li>shadowsocks-libev: <a href="https://github.com/shadowsocks/shadowsocks-libev/blob/master/LICENSE">GPLv3</a></li>
<li>overture: <a href="https://github.com/shawn1m/overture/blob/master/LICENSE">MIT</a></li>
<li>libev: <a href="https://github.com/shadowsocks/libev/blob/master/LICENSE">GPLv2</a></li>
<li>libsodium: <a href="https://github.com/jedisct1/libsodium/blob/master/LICENSE">ISC</a></li>
</ul>
</body>
</html>
<!-- This document was created with MarkdownPad, the Markdown editor for Windows (http://markdownpad.com) -->
......@@ -20,9 +20,8 @@
package com.github.shadowsocks
import android.annotation.TargetApi
import android.os.Build
import android.os.Bundle
import android.support.v4.content.ContextCompat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
......@@ -31,14 +30,20 @@ import android.webkit.WebView
import android.webkit.WebViewClient
class AboutFragment : ToolbarFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
inflater.inflate(R.layout.layout_about, container, false)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// workaround for weird night mode bug
val configuration = resources.configuration
val result = inflater.inflate(R.layout.layout_about, container, false)
if (resources.configuration !== configuration) requireActivity().recreate()
return result
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
toolbar.title = getString(R.string.about_title, BuildConfig.VERSION_NAME)
val web = view.findViewById<WebView>(R.id.web_view)
web.loadUrl("file:///android_asset/pages/about.html")
web.setBackgroundColor(ContextCompat.getColor(requireActivity(), R.color.background))
web.loadUrl(getString(R.string.about_url))
web.webViewClient = object : WebViewClient() {
@Suppress("OverridingDeprecatedMember")
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
......@@ -46,7 +51,6 @@ class AboutFragment : ToolbarFragment() {
return true
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest): Boolean {
(activity as MainActivity).launchUrl(request.url)
return true
......
......@@ -160,7 +160,7 @@ class App : Application() {
}
DataStore.publicStore.putLong(Key.assetUpdateTime, info.lastUpdateTime)
}
AppCompatDelegate.setDefaultNightMode(DataStore.nightMode)
updateNotificationChannels()
}
......
......@@ -37,6 +37,7 @@ import android.support.design.widget.Snackbar
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.app.AppCompatDelegate
import android.support.v7.content.res.AppCompatResources
import android.support.v7.preference.PreferenceDataStore
import android.text.format.Formatter
......@@ -101,7 +102,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
private val customTabsIntent by lazy {
CustomTabsIntent.Builder()
.setToolbarColor(ContextCompat.getColor(this, R.color.material_primary_500))
.setToolbarColor(ContextCompat.getColor(this, R.color.color_primary))
.build()
}
fun launchUrl(uri: Uri) = try {
......@@ -321,10 +322,16 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
}
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) {
if (key == Key.serviceMode) app.handler.post {
when (key) {
Key.serviceMode -> app.handler.post {
connection.disconnect()
connection.connect()
}
Key.nightMode -> {
AppCompatDelegate.setDefaultNightMode(DataStore.nightMode)
recreate()
}
}
}
private fun displayFragment(fragment: ToolbarFragment) {
......
......@@ -157,11 +157,11 @@ class ProfileConfigFragment : PreferenceFragmentCompatDividers(), Toolbar.OnMenu
override fun onDisplayPreferenceDialog(preference: Preference) {
if (preference.key == Key.pluginConfigure) {
val intent = PluginManager.buildIntent(pluginConfiguration.selected, PluginContract.ACTION_CONFIGURE)
if (intent.resolveActivity(requireContext().packageManager) != null)
startActivityForResult(intent.putExtra(PluginContract.EXTRA_OPTIONS,
pluginConfiguration.selectedOptions.toString()), REQUEST_CODE_PLUGIN_CONFIGURE) else {
showPluginEditor()
}
if (intent.resolveActivity(requireContext().packageManager) == null) showPluginEditor() else
startActivityForResult(intent
.putExtra(PluginContract.EXTRA_OPTIONS, pluginConfiguration.selectedOptions.toString())
.putExtra(PluginContract.EXTRA_NIGHT_MODE, DataStore.nightMode),
REQUEST_CODE_PLUGIN_CONFIGURE)
} else super.onDisplayPreferenceDialog(preference)
}
......
......@@ -23,6 +23,7 @@ package com.github.shadowsocks.acl
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.support.design.widget.Snackbar
......@@ -466,10 +467,16 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener,
val activity = requireActivity()
val window = activity.window
// In the end material_grey_100 is used for background, see AppCompatDrawableManager (very complicated)
if (Build.VERSION.SDK_INT >= 23) {
window.statusBarColor = ContextCompat.getColor(activity, R.color.material_grey_300)
// for dark mode, it's roughly 850? (#303030)
window.statusBarColor = ContextCompat.getColor(activity, when {
resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES ->
R.color.md_black_1000
Build.VERSION.SDK_INT >= 23 -> {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else window.statusBarColor = ContextCompat.getColor(activity, R.color.material_grey_600)
R.color.material_grey_300
}
else -> R.color.material_grey_600
})
activity.menuInflater.inflate(R.menu.custom_rules_selection, menu)
toolbar.touchscreenBlocksFocus = true
return true
......
......@@ -21,6 +21,7 @@
package com.github.shadowsocks.preference
import android.os.Binder
import android.support.v7.app.AppCompatDelegate
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.database.PrivateDatabase
import com.github.shadowsocks.database.PublicDatabase
......@@ -51,6 +52,16 @@ object DataStore {
}
val canToggleLocked: Boolean get() = publicStore.getBoolean(Key.directBootAware) == true
val directBootAware: Boolean get() = app.directBootSupported && canToggleLocked
private var nightModeString: String
get() = publicStore.getString(Key.nightMode) ?: Key.nightModeSystem
set(value) = publicStore.putString(Key.nightMode, value)
@AppCompatDelegate.NightMode
val nightMode: Int get() = when (nightModeString) {
Key.nightModeAuto -> AppCompatDelegate.MODE_NIGHT_AUTO
Key.nightModeOff -> AppCompatDelegate.MODE_NIGHT_NO
Key.nightModeOn -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
var serviceMode: String
get() = publicStore.getString(Key.serviceMode) ?: Key.modeVpn
set(value) = publicStore.putString(Key.serviceMode, value)
......@@ -66,6 +77,7 @@ object DataStore {
fun initGlobal() {
// temporary workaround for support lib bug
if (publicStore.getString(Key.nightMode) == null) nightModeString = nightModeString
if (publicStore.getString(Key.serviceMode) == null) serviceMode = serviceMode
if (publicStore.getString(Key.portProxy) == null) portProxy = portProxy
if (publicStore.getString(Key.portLocalDns) == null) portLocalDns = portLocalDns
......
......@@ -32,6 +32,12 @@ object Key {
const val individual = "Proxyed"
const val nightMode = "nightMode"
const val nightModeSystem = "system"
const val nightModeAuto = "auto"
const val nightModeOff = "off"
const val nightModeOn = "on"
const val serviceMode = "serviceMode"
const val modeProxy = "proxy"
const val modeVpn = "vpn"
......
......@@ -2,7 +2,7 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/material_primary_300" />
<solid android:color="@color/background_stat" />
</shape>
</item>
<item>
......@@ -18,7 +18,7 @@
<!-- android:start not available until API 23 -->
<item android:left="8dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
<solid android:color="@color/background" />
</shape>
</item>
<item android:drawable="?android:attr/selectableItemBackground"/>
......
......@@ -4,7 +4,7 @@
<selector android:enterFadeDuration="@android:integer/config_mediumAnimTime"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_selected="true">
<color android:color="@color/material_primary_100"/>
<color android:color="@color/background_selected"/>
</item>
</selector>
</item>
......
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/material_primary_300"/>
<color android:color="@color/background_stat"/>
</item>
<item android:drawable="?android:attr/selectableItemBackground"/>
</layer-list>
......@@ -4,6 +4,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:fillColor="@color/primary_drawable"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>
......@@ -5,6 +5,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:fillColor="@color/primary_drawable"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
</vector>
......@@ -18,7 +18,6 @@
android:layout_gravity="center_vertical">
<TextView android:id="@android:id/text1"
android:textAppearance="?android:attr/textAppearance"
android:textColor="@android:color/primary_text_light"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
......
......@@ -11,7 +11,7 @@
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:elevation="1dp"
android:background="@android:color/white"
android:background="@color/background"
android:orientation="vertical"
tools:ignore="RtlSymmetry">
......
......@@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/snackbar"
android:background="@color/material_primary_700"
android:background="@color/color_primary_dark"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
......@@ -60,6 +60,7 @@
android:ellipsize="marquee"
android:gravity="end"
android:text="@string/sent"
android:textColor="?android:attr/textColorPrimary"
app:layout_column="0"/>
<TextView
......@@ -102,6 +103,7 @@
android:ellipsize="marquee"
android:gravity="end"
android:text="@string/received"
android:textColor="?android:attr/textColorPrimary"
app:layout_column="0"
app:layout_row="1"/>
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="background">@color/md_dark_background</color>
<color name="background_selected">@color/material_primary_800</color>
<color name="primary_drawable">@android:color/white</color>
<color name="background_stat">@color/material_primary_600</color>
<!-- MaterialDrawer colors -->
<color name="drawer_background">@color/material_drawer_dark_background</color>
<color name="drawer_primary_text">@color/material_drawer_dark_primary_text</color>
<color name="drawer_primary_icon">@color/material_drawer_dark_primary_icon</color>
<color name="drawer_secondary_text">@color/material_drawer_dark_secondary_text</color>
<color name="drawer_hint_text">@color/material_drawer_dark_hint_text</color>
<color name="drawer_divider">@color/material_drawer_dark_divider</color>
<color name="drawer_selected">@color/material_drawer_dark_selected</color>
<color name="drawer_selected_text">@color/material_accent_200</color>
<color name="drawer_header_selection_text">@color/material_drawer_dark_header_selection_text</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about_url" translatable="false">file:///android_asset/pages/about_night.html</string>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Design.DayNight.BottomSheetDialog" parent="@style/Theme.Design.BottomSheetDialog"/>
</resources>
......@@ -38,6 +38,11 @@
<string name="tcp_fastopen_summary_unsupported">"不支持的内核版本: %s &lt; 3.7.1"</string>
<string name="udp_dns">"DNS 转发"</string>
<string name="udp_dns_summary">"转发所有 DNS 请求到远程服务器"</string>
<string name="night_mode">夜间模式</string>
<string name="night_mode_system">跟随系统</string>
<string name="night_mode_auto">自动</string>
<string name="night_mode_on">开启</string>
<string name="night_mode_off">关闭</string>
<!-- notification category -->
<string name="forward_success">"后台服务已开始运行。"</string>
......
......@@ -237,4 +237,16 @@
<item>vpn</item>
<item>transproxy</item>
</string-array>
<string-array name="night_modes">
<item>@string/night_mode_system</item>
<item>@string/night_mode_auto</item>
<item>@string/night_mode_off</item>
<item>@string/night_mode_on</item>
</string-array>
<string-array name="night_mode_values" translatable="false">
<item>system</item>
<item>auto</item>
<item>off</item>
<item>on</item>
</string-array>
</resources>
......@@ -2,4 +2,19 @@
<resources>
<color name="ic_launcher_background">#7488A1</color>
<color name="material_drawer_selected_text">@color/material_accent_200</color>
<color name="background">@color/md_light_background</color>
<color name="background_selected">@color/material_primary_100</color>
<color name="primary_drawable">@android:color/black</color>
<color name="background_stat">@color/material_primary_300</color>
<!-- MaterialDrawer colors -->
<color name="drawer_background">@color/material_drawer_background</color>
<color name="drawer_primary_text">@color/material_drawer_primary_text</color>
<color name="drawer_primary_icon">@color/material_drawer_primary_icon</color>
<color name="drawer_secondary_text">@color/material_drawer_secondary_text</color>
<color name="drawer_hint_text">@color/material_drawer_hint_text</color>
<color name="drawer_divider">@color/material_drawer_divider</color>
<color name="drawer_selected">@color/material_drawer_selected</color>
<color name="drawer_selected_text">@color/material_accent_200</color>
<color name="drawer_header_selection_text">@color/material_drawer_header_selection_text</color>
</resources>
......@@ -3,6 +3,7 @@
<string name="app_name">Shadowsocks</string>
<string name="quick_toggle">Toggle</string>
<string name="about_url" translatable="false">file:///android_asset/pages/about.html</string>
<!-- misc -->
<string name="profile">Profile</string>
......@@ -59,6 +60,11 @@
<string name="tcp_fastopen_summary_unsupported">Unsupported kernel version: %s &lt; 3.7.1</string>
<string name="udp_dns">DNS Forwarding</string>
<string name="udp_dns_summary">Forward all DNS requests to remote</string>
<string name="night_mode">Night mode</string>
<string name="night_mode_system">Follow system</string>
<string name="night_mode_auto">Auto</string>
<string name="night_mode_on">On</string>
<string name="night_mode_off">Off</string>
<!-- notification category -->
<string name="service_vpn">VPN Service</string>
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Shadowsocks.App">
<item name="bottomSheetDialogTheme">@style/Theme.Design.DayNight.BottomSheetDialog</item>
<!-- MaterialDrawer specific values -->
<item name="material_drawer_background">@color/drawer_background</item>
<item name="material_drawer_primary_text">@color/drawer_primary_text</item>
<item name="material_drawer_primary_icon">@color/drawer_primary_icon</item>
<item name="material_drawer_secondary_text">@color/drawer_secondary_text</item>
<item name="material_drawer_hint_text">@color/drawer_hint_text</item>
<item name="material_drawer_divider">@color/drawer_divider</item>
<item name="material_drawer_selected">@color/drawer_selected</item>
<item name="material_drawer_selected_text">@color/drawer_selected_text</item>
<item name="material_drawer_header_selection_text">@color/drawer_header_selection_text</item>
</style>
<style name="Theme.Design.DayNight.BottomSheetDialog" parent="@style/Theme.Design.Light.BottomSheetDialog"/>
<style name="StyledScrollerTextAppearance" parent="@android:style/TextAppearance">
<item name="android:textSize">24sp</item>
<item name="android:textStyle">bold</item>
......
......@@ -12,6 +12,13 @@
<SwitchPreference android:key="tcp_fastopen"
android:summary="@string/tcp_fastopen_summary"
android:title="TCP Fast Open"/>
<SimpleMenuPreference
android:key="nightMode"
android:entries="@array/night_modes"
android:entryValues="@array/night_mode_values"
android:defaultValue="system"
android:summary="%s"
android:title="@string/night_mode"/>
<PreferenceCategory
android:title="@string/advanced">
<SimpleMenuPreference
......
......@@ -80,6 +80,8 @@ If the plugin doesn't provide a configuration activity, it's highly recommended
* MUST be able to receive data URI `plugin://com.github.shadowsocks/$PLUGIN_ID`;
* CAN parse string extra `com.github.shadowsocks.plugin.EXTRA_OPTIONS` and display some more
relevant information;
* SHOULD parse `@NightMode` int extra `com.github.shadowsocks.plugin.EXTRA_NIGHT_MODE` and act
accordingly;
* SHOULD either:
- Be invisible and return help message with CharSequence extra
`com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE` in the data intent with `RESULT_OK`; (in this
......
......@@ -23,6 +23,7 @@ package com.github.shadowsocks.plugin
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.app.AppCompatDelegate
import android.widget.Toast
/**
......@@ -43,6 +44,13 @@ abstract class OptionsCapableActivity : AppCompatActivity() {
*/
protected abstract fun onInitializePluginOptions(options: PluginOptions = pluginOptions())
override fun onCreate(savedInstanceState: Bundle?) {
val nightMode = intent.getIntExtra(PluginContract.EXTRA_NIGHT_MODE, -100) // MODE_NIGHT_UNSPECIFIED
if (nightMode >= AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM && nightMode <= AppCompatDelegate.MODE_NIGHT_YES)
AppCompatDelegate.setDefaultNightMode(nightMode)
super.onCreate(savedInstanceState) // applyDayNight is called in AppCompatActivity.onCreate
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
if (savedInstanceState == null) onInitializePluginOptions()
......
......@@ -20,6 +20,8 @@
package com.github.shadowsocks.plugin
import android.support.v7.app.AppCompatDelegate
/**
* The contract between the plugin provider and host. Contains definitions for the supported actions, extras, etc.
*
......@@ -71,6 +73,13 @@ object PluginContract {
* Constant Value: "com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE"
</host_name> */
const val EXTRA_HELP_MESSAGE = "com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE"
/**
* The lookup key for an @NightMode int that suggests a night mode that is being used in the main app.
*
* Constant Value: "com.github.shadowsocks.plugin.EXTRA_NIGHT_MODE"
*/
@AppCompatDelegate.NightMode
const val EXTRA_NIGHT_MODE = "com.github.shadowsocks.plugin.EXTRA_NIGHT_MODE"
/**
* The metadata key to retrieve plugin id. Required for plugins.
......
......@@ -8,5 +8,5 @@
android:elevation="4dp"
android:touchscreenBlocksFocus="false"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:popupTheme="@style/ThemeOverlay.AppCompat.DayNight"
android:id="@+id/toolbar" />
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="color_primary">@color/material_primary_800</color>
<color name="color_primary_dark">@color/material_primary_900</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="ThemeOverlay.AppCompat.DayNight" parent="ThemeOverlay.AppCompat.Dark"/>
</resources>
\ No newline at end of file
......@@ -14,6 +14,11 @@
<color name="material_primary_500">@color/material_blue_grey_500</color>
<color name="material_primary_600">@color/material_blue_grey_600</color>
<color name="material_primary_700">@color/material_blue_grey_700</color>
<color name="material_primary_800">@color/material_blue_grey_800</color>
<color name="material_primary_900">@color/material_blue_grey_900</color>
<color name="material_accent_200">@color/material_green_a700</color>
<color name="color_primary">@color/material_blue_grey_500</color>
<color name="color_primary_dark">@color/material_blue_grey_700</color>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Shadowsocks" parent="PreferenceFixTheme.Light.NoActionBar">
<item name="android:navigationBarColor">@color/material_primary_700</item>
<style name="Theme.Shadowsocks" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:navigationBarColor">@color/color_primary_dark</item>
<item name="actionModeCloseDrawable">@drawable/ic_navigation_close</item>
<item name="colorAccent">@color/material_accent_200</item>
<item name="colorButtonNormal">@color/material_accent_200</item>
<item name="colorPrimary">@color/material_primary_500</item>
<item name="colorPrimaryDark">@color/material_primary_700</item>
<item name="colorPrimary">@color/color_primary</item>
<item name="colorPrimaryDark">@color/color_primary_dark</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material.Fix</item>
<item name="preferenceCategory_marginBottom">8dp</item>
<item name="windowActionModeOverlay">true</item>
......@@ -22,4 +22,5 @@
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="ThemeOverlay.AppCompat.DayNight" parent="ThemeOverlay.AppCompat.Light"/>
</resources>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment