-
diff --git a/res/layout/preference_with_button.xml b/res/layout/preference_with_button.xml
--- a/res/layout/preference_with_button.xml
+++ b/res/layout/preference_with_button.xml
@@ -16,7 +16,9 @@
-
-
diff --git a/res/values-v21/styles-dark.xml b/res/values-v21/styles-dark.xml
new file mode 100644
--- /dev/null
+++ b/res/values-v21/styles-dark.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
new file mode 100644
--- /dev/null
+++ b/res/values/attrs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/styles-dark.xml b/res/values/styles-dark.xml
new file mode 100644
--- /dev/null
+++ b/res/values/styles-dark.xml
@@ -0,0 +1,40 @@
+
+
+ #555555
+ #222222
+ #333333
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/styles.xml b/res/values/styles.xml
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -10,6 +10,10 @@
- @color/primary
- @color/primaryDark
- @color/accent
+ - @style/KdeConnectTheme.Toolbar
+ - @style/ThemeOverlay.AppCompat.Light
+ - @style/MainNavigationView
+ - @android:color/black
- @android:color/black
- @android:color/black
@@ -21,8 +25,18 @@
+
+
+
diff --git a/src/org/kde/kdeconnect/Plugins/FindMyPhonePlugin/FindMyPhoneActivity.java b/src/org/kde/kdeconnect/Plugins/FindMyPhonePlugin/FindMyPhoneActivity.java
--- a/src/org/kde/kdeconnect/Plugins/FindMyPhonePlugin/FindMyPhoneActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/FindMyPhonePlugin/FindMyPhoneActivity.java
@@ -34,6 +34,7 @@
import android.view.Window;
import android.view.WindowManager;
+import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
public class FindMyPhoneActivity extends Activity {
@@ -56,6 +57,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeUtil.setUserPreferredTheme(this);
setContentView(R.layout.activity_find_my_phone);
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
diff --git a/src/org/kde/kdeconnect/Plugins/MousePadPlugin/MousePadActivity.java b/src/org/kde/kdeconnect/Plugins/MousePadPlugin/MousePadActivity.java
--- a/src/org/kde/kdeconnect/Plugins/MousePadPlugin/MousePadActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/MousePadPlugin/MousePadActivity.java
@@ -37,6 +37,7 @@
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
+import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
public class MousePadActivity extends AppCompatActivity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, MousePadGestureDetector.OnGestureListener {
@@ -80,6 +81,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeUtil.setUserPreferredTheme(this);
setContentView(R.layout.activity_mousepad);
diff --git a/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java b/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java
--- a/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java
@@ -46,6 +46,7 @@
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.NetworkPacket;
+import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
import java.util.List;
@@ -314,6 +315,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeUtil.setUserPreferredTheme(this);
setContentView(R.layout.activity_mpris);
final String targetPlayerName = getIntent().getStringExtra("player");
diff --git a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java
--- a/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/NotificationsPlugin/NotificationFilterActivity.java
@@ -39,6 +39,7 @@
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Helpers.StringsHelper;
+import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
import java.util.Arrays;
@@ -93,6 +94,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeUtil.setUserPreferredTheme(this);
setContentView(R.layout.activity_notification_filter);
appDatabase = new AppDatabase(NotificationFilterActivity.this, false);
diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandActivity.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandActivity.java
--- a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandActivity.java
@@ -35,6 +35,7 @@
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
+import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
@@ -115,6 +116,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeUtil.setUserPreferredTheme(this);
setContentView(R.layout.activity_runcommand);
deviceId = getIntent().getStringExtra("deviceId");
diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/SendFileActivity.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/SendFileActivity.java
--- a/src/org/kde/kdeconnect/Plugins/SharePlugin/SendFileActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/SendFileActivity.java
@@ -32,6 +32,7 @@
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
+import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
@@ -44,6 +45,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeUtil.setUserPreferredTheme(this);
mDeviceId = getIntent().getStringExtra("deviceId");
diff --git a/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareActivity.java b/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareActivity.java
--- a/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareActivity.java
+++ b/src/org/kde/kdeconnect/Plugins/SharePlugin/ShareActivity.java
@@ -38,6 +38,7 @@
import org.kde.kdeconnect.UserInterface.List.EntryItem;
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
import org.kde.kdeconnect.UserInterface.List.SectionItem;
+import org.kde.kdeconnect.UserInterface.ThemeUtil;
import org.kde.kdeconnect_tp.R;
import java.util.ArrayList;
@@ -145,8 +146,11 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ ThemeUtil.setUserPreferredTheme(this);
setContentView(R.layout.devices_list);
+
ActionBar actionBar = getSupportActionBar();
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_list_layout);
mSwipeRefreshLayout.setOnRefreshListener(
diff --git a/src/org/kde/kdeconnect/UserInterface/AppCompatPreferenceActivity.java b/src/org/kde/kdeconnect/UserInterface/AppCompatPreferenceActivity.java
--- a/src/org/kde/kdeconnect/UserInterface/AppCompatPreferenceActivity.java
+++ b/src/org/kde/kdeconnect/UserInterface/AppCompatPreferenceActivity.java
@@ -45,6 +45,8 @@
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
+ // The superclass's onCreate() method calls setContentView, so this ThemeUtil call must be before that
+ ThemeUtil.setUserPreferredTheme(this);
super.onCreate(savedInstanceState);
}
diff --git a/src/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java b/src/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java
--- a/src/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java
+++ b/src/org/kde/kdeconnect/UserInterface/CustomDevicesActivity.java
@@ -57,6 +57,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initializeDeviceList(this);
+ ThemeUtil.setUserPreferredTheme(this);
setContentView(R.layout.custom_ip_list);
list = (ListView) findViewById(android.R.id.list);
diff --git a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java
--- a/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java
+++ b/src/org/kde/kdeconnect/UserInterface/DeviceFragment.java
@@ -334,6 +334,7 @@
boolean onData = NetworkHelper.isOnMobileNetwork(getContext());
rootView.findViewById(R.id.pairing_buttons).setVisibility(paired ? View.GONE : View.VISIBLE);
+ rootView.findViewById(R.id.error_message_container).setVisibility((paired && !reachable) ? View.VISIBLE : View.GONE);
rootView.findViewById(R.id.not_reachable_message).setVisibility((paired && !reachable && !onData) ? View.VISIBLE : View.GONE);
rootView.findViewById(R.id.on_data_message).setVisibility((paired && !reachable && onData) ? View.VISIBLE : View.GONE);
diff --git a/src/org/kde/kdeconnect/UserInterface/MainActivity.java b/src/org/kde/kdeconnect/UserInterface/MainActivity.java
--- a/src/org/kde/kdeconnect/UserInterface/MainActivity.java
+++ b/src/org/kde/kdeconnect/UserInterface/MainActivity.java
@@ -7,21 +7,27 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Bundle;
+import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.SwitchCompat;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
@@ -55,6 +61,10 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ // We need to set this theme before the call to 'setContentView' below
+ ThemeUtil.setUserPreferredTheme(this);
+
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mNavigationView = (NavigationView) findViewById(R.id.navigation_drawer);
@@ -91,6 +101,10 @@
mDrawerHeader.findViewById(R.id.kdeconnect_label).setOnClickListener(renameListener);
mDrawerHeader.findViewById(R.id.device_name).setOnClickListener(renameListener);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ addDarkModeSwitch((ViewGroup) mDrawerHeader);
+ }
+
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
@@ -132,6 +146,36 @@
onDeviceSelected(savedDevice);
}
+ /**
+ * Adds a {@link SwitchCompat} to the bottom of the navigation header for
+ * toggling dark mode on and off. Call from {@link #onCreate(Bundle)}.
+ *
+ * Only supports android ICS and higher because {@link SwitchCompat}
+ * requires that.
+ *
+ *
+ * @param drawerHeader the layout which should contain the switch
+ */
+ @RequiresApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+ private void addDarkModeSwitch(ViewGroup drawerHeader) {
+ getLayoutInflater().inflate(R.layout.nav_dark_mode_switch, drawerHeader);
+
+ SwitchCompat darkThemeSwitch = (SwitchCompat) drawerHeader.findViewById(R.id.dark_theme);
+ darkThemeSwitch.setChecked(ThemeUtil.shouldUseDarkTheme(this));
+ darkThemeSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @RequiresApi(Build.VERSION_CODES.HONEYCOMB)
+ @Override
+ public void onCheckedChanged(CompoundButton darkThemeSwitch, boolean isChecked) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
+ boolean isDarkAlready = prefs.getBoolean("darkTheme", false);
+ if (isDarkAlready != isChecked) {
+ prefs.edit().putBoolean("darkTheme", isChecked).apply();
+ MainActivity.this.recreate();
+ }
+ }
+ });
+ }
+
//like onNewDeviceSelected but assumes that the new device is simply requesting to be paired
//and can't be null
private void onNewDeviceSelected(String deviceId, String pairStatus) {
diff --git a/src/org/kde/kdeconnect/UserInterface/ThemeUtil.java b/src/org/kde/kdeconnect/UserInterface/ThemeUtil.java
new file mode 100644
--- /dev/null
+++ b/src/org/kde/kdeconnect/UserInterface/ThemeUtil.java
@@ -0,0 +1,46 @@
+package org.kde.kdeconnect.UserInterface;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import org.kde.kdeconnect_tp.R;
+
+/**
+ * Utilities for working with android {@link android.content.res.Resources.Theme Themes}.
+ */
+public class ThemeUtil {
+
+ /**
+ * This method should be called from the {@code activity}'s onCreate method, before
+ * any calls to {@link Activity#setContentView} or
+ * {@link android.preference.PreferenceActivity#setPreferenceScreen}.
+ *
+ * @param activity any Activity on screen
+ */
+ public static void setUserPreferredTheme(Activity activity) {
+ boolean useDarkTheme = shouldUseDarkTheme(activity);
+
+ // Only MainActivity sets its own Toolbar as the ActionBar.
+ boolean usesOwnActionBar = activity instanceof MainActivity;
+
+ if (useDarkTheme) {
+ activity.setTheme(usesOwnActionBar ? R.style.KdeConnectTheme_Dark_NoActionBar : R.style.KdeConnectTheme_Dark);
+ } else {
+ activity.setTheme(usesOwnActionBar ? R.style.KdeConnectTheme_NoActionBar : R.style.KdeConnectTheme);
+ }
+ }
+
+ /**
+ * Checks {@link SharedPreferences} to figure out whether we should use the light
+ * theme or the dark theme. The app defaults to light theme.
+ *
+ * @param context any active context (Activity, Service, Application, etc.)
+ * @return true if the dark theme should be active, false otherwise
+ */
+ public static boolean shouldUseDarkTheme(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean("darkTheme", false);
+ }
+}