From 4bc27eae7847386284f3364bae83b5a0c13aa138 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Fri, 4 May 2018 22:14:59 +0200
Subject: [PATCH] Implement notification settings, fixes #48

Signed-off-by: Janne Koschinski <janne@kuschku.de>
---
 app/src/debug/res/values/strings.xml          |   2 +
 .../QuasseldroidNotificationManager.kt        |   2 +-
 .../settings/NotificationSettings.kt          |   5 +-
 .../kuschku/quasseldroid/settings/Settings.kt |  14 +-
 .../chat/info/channel/ChannelInfoActivity.kt  |   2 +-
 .../ui/chat/info/user/UserInfoActivity.kt     |   2 +-
 .../ui/chat/topic/TopicActivity.kt            |   2 +-
 .../ui/clientsettings/about/AboutActivity.kt  |   2 +-
 .../client/ClientSettingsActivity.kt          |   2 +-
 .../client/ClientSettingsFragment.kt          |  11 +-
 .../ui/clientsettings/crash/CrashActivity.kt  |   2 +-
 .../clientsettings/license/LicenseActivity.kt |   2 +-
 .../whitelist/WhitelistActivity.kt            |   2 +-
 .../ui/coresettings/CoreSettingsActivity.kt   |   2 +-
 .../aliasitem/AliasItemActivity.kt            |   2 +-
 .../aliaslist/AliasListActivity.kt            |   2 +-
 .../chatlist/ChatlistCreateActivity.kt        |   2 +-
 .../chatlist/ChatlistEditActivity.kt          |   2 +-
 .../highlightlist/HighlightListActivity.kt    |   2 +-
 .../highlightrule/HighlightRuleActivity.kt    |   2 +-
 .../identity/IdentityCreateActivity.kt        |   2 +-
 .../identity/IdentityEditActivity.kt          |   2 +-
 .../ignoreitem/IgnoreItemActivity.kt          |   2 +-
 .../ignorelist/IgnoreListActivity.kt          |   2 +-
 .../network/NetworkCreateActivity.kt          |   2 +-
 .../network/NetworkEditActivity.kt            |   2 +-
 .../networkconfig/NetworkConfigActivity.kt    |   2 +-
 .../networkserver/NetworkServerActivity.kt    |   2 +-
 .../util/helper/PreferenceHelper.kt           |  26 ++
 .../util/ui/settings/ActivityLauncher.kt      |  29 +++
 .../AttachingPreferenceFragmentCompat.kt      |  64 +++++
 .../DaggerPreferenceFragmentCompat.kt         |   5 +-
 .../ui/settings/OnActivityResultListener.kt   |  32 +++
 .../ui/settings/RequiresActivityLauncher.kt   |  24 ++
 .../util/ui/settings/RingtonePreference.kt    | 226 ++++++++++++++++++
 .../ui/{ => settings}/SeekBarPreference.kt    |   2 +-
 .../ServiceBoundSettingsActivity.kt           |   2 +-
 .../ui/{ => settings}/SettingsActivity.kt     |   3 +-
 .../res/layout/widget_preference_divider.xml  |  23 ++
 .../res/layout/widget_spinner_item_inline.xml |   1 -
 app/src/main/res/values-de/strings.xml        |   1 +
 .../res/values-de/strings_preferences.xml     |  11 +
 app/src/main/res/values-lt/strings.xml        |   1 +
 .../res/values-lt/strings_preferences.xml     |   6 +
 app/src/main/res/values/strings.xml           |   3 +
 .../main/res/values/strings_preferences.xml   |  12 +
 app/src/main/res/values/styles_widgets.xml    |  28 +++
 app/src/main/res/values/themes_base.xml       |   4 +
 app/src/main/res/xml/preferences.xml          |  45 +++-
 49 files changed, 591 insertions(+), 37 deletions(-)
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/helper/PreferenceHelper.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/ActivityLauncher.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/AttachingPreferenceFragmentCompat.kt
 rename app/src/main/java/de/kuschku/quasseldroid/util/{backport => ui/settings}/DaggerPreferenceFragmentCompat.kt (88%)
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/OnActivityResultListener.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RequiresActivityLauncher.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt
 rename app/src/main/java/de/kuschku/quasseldroid/util/ui/{ => settings}/SeekBarPreference.kt (99%)
 rename app/src/main/java/de/kuschku/quasseldroid/util/ui/{ => settings}/ServiceBoundSettingsActivity.kt (98%)
 rename app/src/main/java/de/kuschku/quasseldroid/util/ui/{ => settings}/SettingsActivity.kt (96%)
 create mode 100644 app/src/main/res/layout/widget_preference_divider.xml

diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml
index 7bb3f6147..9410ec8e7 100644
--- a/app/src/debug/res/values/strings.xml
+++ b/app/src/debug/res/values/strings.xml
@@ -19,4 +19,6 @@
 
 <resources>
   <string name="app_name">QuasselTest</string>
+
+  <string name="package_name">com.iskrembilen.quasseldroid.debug</string>
 </resources>
diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/QuasseldroidNotificationManager.kt b/app/src/main/java/de/kuschku/quasseldroid/service/QuasseldroidNotificationManager.kt
index 0d7e52239..d1711f565 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasseldroidNotificationManager.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasseldroidNotificationManager.kt
@@ -149,7 +149,7 @@ class QuasseldroidNotificationManager @Inject constructor(private val context: C
       .apply {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
           var defaults = 0
-          if (!notificationSettings.sound.isNullOrEmpty()) {
+          if (!notificationSettings.sound.isEmpty()) {
             setSound(Uri.parse(notificationSettings.sound))
           }
           if (notificationSettings.vibrate) {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/settings/NotificationSettings.kt b/app/src/main/java/de/kuschku/quasseldroid/settings/NotificationSettings.kt
index 71cc73347..af07daba1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/settings/NotificationSettings.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/settings/NotificationSettings.kt
@@ -23,8 +23,9 @@ data class NotificationSettings(
   val query: Level = Level.ALL,
   val channel: Level = Level.HIGHLIGHT,
   val other: Level = Level.NONE,
-  val sound: String? = null,
-  val vibrate: Boolean = true
+  val sound: String = "content://settings/system/notification_sound",
+  val vibrate: Boolean = true,
+  val light: Boolean = true
 ) {
   enum class Level {
     ALL,
diff --git a/app/src/main/java/de/kuschku/quasseldroid/settings/Settings.kt b/app/src/main/java/de/kuschku/quasseldroid/settings/Settings.kt
index b690bb6a8..bb91e49b0 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/settings/Settings.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/settings/Settings.kt
@@ -143,7 +143,19 @@ object Settings {
           context.getString(R.string.preference_notification_other_key),
           ""
         )
-      ) ?: NotificationSettings.DEFAULT.other
+      ) ?: NotificationSettings.DEFAULT.other,
+      sound = getString(
+        context.getString(R.string.preference_notification_sound_key),
+        NotificationSettings.DEFAULT.sound
+      ),
+      vibrate = getBoolean(
+        context.getString(R.string.preference_notification_sound_key),
+        NotificationSettings.DEFAULT.vibrate
+      ),
+      light = getBoolean(
+        context.getString(R.string.preference_notification_light_key),
+        NotificationSettings.DEFAULT.light
+      )
     )
   }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/channel/ChannelInfoActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/channel/ChannelInfoActivity.kt
index f887d5576..3464146a1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/channel/ChannelInfoActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/channel/ChannelInfoActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.chat.info.channel
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class ChannelInfoActivity : ServiceBoundSettingsActivity(ChannelInfoFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoActivity.kt
index 67f9608bc..e7f23d358 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoActivity.kt
@@ -23,7 +23,7 @@ import android.content.Context
 import android.content.Intent
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.NetworkId
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class UserInfoActivity : ServiceBoundSettingsActivity(UserInfoFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicActivity.kt
index b7862e073..af7be969e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.chat.topic
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class TopicActivity : ServiceBoundSettingsActivity(TopicFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutActivity.kt
index 36789b40a..3e09e26fc 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.clientsettings.about
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.SettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.SettingsActivity
 
 class AboutActivity : SettingsActivity(AboutFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsActivity.kt
index be8e7d46c..0c4b8ba57 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.clientsettings.client
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.SettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.SettingsActivity
 
 class ClientSettingsActivity : SettingsActivity(ClientSettingsFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt
index c330f0d0b..a92c5be98 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt
@@ -20,6 +20,7 @@
 package de.kuschku.quasseldroid.ui.clientsettings.client
 
 import android.content.SharedPreferences
+import android.os.Build
 import android.os.Bundle
 import android.support.v7.preference.ListPreference
 import android.support.v7.preference.Preference
@@ -33,11 +34,12 @@ import de.kuschku.quasseldroid.settings.Settings
 import de.kuschku.quasseldroid.ui.clientsettings.about.AboutActivity
 import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashActivity
 import de.kuschku.quasseldroid.ui.clientsettings.whitelist.WhitelistActivity
-import de.kuschku.quasseldroid.util.backport.DaggerPreferenceFragmentCompat
+import de.kuschku.quasseldroid.util.ui.settings.DaggerPreferenceFragmentCompat
 import javax.inject.Inject
 
 class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
                                SharedPreferences.OnSharedPreferenceChangeListener {
+
   @Inject
   lateinit var appearanceSettings: AppearanceSettings
 
@@ -48,6 +50,13 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
 
   override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
     setPreferencesFromResource(R.xml.preferences, rootKey)
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+      findPreference(getString(R.string.preference_notification_sound_key)).isVisible = false
+      findPreference(getString(R.string.preference_notification_vibration_key)).isVisible = false
+      findPreference(getString(R.string.preference_notification_light_key)).isVisible = false
+    } else {
+      findPreference(getString(R.string.preference_notification_configure_key)).isVisible = true
+    }
   }
 
   override fun onStart() {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashActivity.kt
index 3b2a8c091..bdf688447 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.clientsettings.crash
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.SettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.SettingsActivity
 
 class CrashActivity : SettingsActivity(CrashFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt
index 92c824397..d5abe2bf1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.clientsettings.license
 import android.content.Context
 import android.content.Intent
 import android.support.annotation.StringRes
-import de.kuschku.quasseldroid.util.ui.SettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.SettingsActivity
 
 class LicenseActivity : SettingsActivity(LicenseFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistActivity.kt
index 72b518c73..ef04ba854 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.clientsettings.whitelist
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.SettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.SettingsActivity
 
 class WhitelistActivity : SettingsActivity(WhitelistFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsActivity.kt
index 72ae138eb..ea7b38c96 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/CoreSettingsActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class CoreSettingsActivity : ServiceBoundSettingsActivity(CoreSettingsFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemActivity.kt
index ee3c12666..f80f3e817 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliasitem/AliasItemActivity.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.coresettings.aliasitem
 import android.content.Context
 import android.content.Intent
 import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class AliasItemActivity : ServiceBoundSettingsActivity(AliasItemFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListActivity.kt
index 8f4b3e189..45ed0299b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/aliaslist/AliasListActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.aliaslist
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class AliasListActivity : ServiceBoundSettingsActivity(AliasListFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistCreateActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistCreateActivity.kt
index 7abe8b465..314cd5a27 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistCreateActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistCreateActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.chatlist
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class ChatlistCreateActivity : ServiceBoundSettingsActivity(ChatListCreateFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistEditActivity.kt
index 36f2235b0..7a7039a8e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistEditActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/chatlist/ChatlistEditActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.chatlist
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class ChatlistEditActivity : ServiceBoundSettingsActivity(ChatListEditFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListActivity.kt
index 94f6766b6..50c19866e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightlist/HighlightListActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.highlightlist
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class HighlightListActivity : ServiceBoundSettingsActivity(HighlightListFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightrule/HighlightRuleActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightrule/HighlightRuleActivity.kt
index f0d0bcd4c..685695801 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightrule/HighlightRuleActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/highlightrule/HighlightRuleActivity.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.coresettings.highlightrule
 import android.content.Context
 import android.content.Intent
 import de.kuschku.libquassel.quassel.syncables.HighlightRuleManager
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class HighlightRuleActivity : ServiceBoundSettingsActivity(HighlightRuleFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateActivity.kt
index b27b7b8a1..91c3210b6 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityCreateActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.identity
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class IdentityCreateActivity : ServiceBoundSettingsActivity(IdentityCreateFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityEditActivity.kt
index 5e0420296..e89980db1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityEditActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/identity/IdentityEditActivity.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.coresettings.identity
 import android.content.Context
 import android.content.Intent
 import de.kuschku.libquassel.protocol.IdentityId
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class IdentityEditActivity : ServiceBoundSettingsActivity(IdentityEditFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreItemActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreItemActivity.kt
index d41612372..e01e29df3 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreItemActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignoreitem/IgnoreItemActivity.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.coresettings.ignoreitem
 import android.content.Context
 import android.content.Intent
 import de.kuschku.libquassel.quassel.syncables.IgnoreListManager
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class IgnoreItemActivity : ServiceBoundSettingsActivity(IgnoreItemFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListActivity.kt
index fb0a6b157..0ed928a8d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/ignorelist/IgnoreListActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.ignorelist
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class IgnoreListActivity : ServiceBoundSettingsActivity(IgnoreListFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateActivity.kt
index 6e067129a..790fddc7c 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkCreateActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.network
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class NetworkCreateActivity : ServiceBoundSettingsActivity(NetworkCreateFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditActivity.kt
index 6820637a5..7c7e7674a 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/network/NetworkEditActivity.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.coresettings.network
 import android.content.Context
 import android.content.Intent
 import de.kuschku.libquassel.protocol.NetworkId
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class NetworkEditActivity : ServiceBoundSettingsActivity(NetworkEditFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkconfig/NetworkConfigActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkconfig/NetworkConfigActivity.kt
index 841e714bd..78b116ec2 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkconfig/NetworkConfigActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkconfig/NetworkConfigActivity.kt
@@ -21,7 +21,7 @@ package de.kuschku.quasseldroid.ui.coresettings.networkconfig
 
 import android.content.Context
 import android.content.Intent
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class NetworkConfigActivity : ServiceBoundSettingsActivity(NetworkConfigFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/NetworkServerActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/NetworkServerActivity.kt
index ba017085f..b1baf1f67 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/NetworkServerActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/coresettings/networkserver/NetworkServerActivity.kt
@@ -22,7 +22,7 @@ package de.kuschku.quasseldroid.ui.coresettings.networkserver
 import android.content.Context
 import android.content.Intent
 import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
-import de.kuschku.quasseldroid.util.ui.ServiceBoundSettingsActivity
+import de.kuschku.quasseldroid.util.ui.settings.ServiceBoundSettingsActivity
 
 class NetworkServerActivity : ServiceBoundSettingsActivity(NetworkServerFragment()) {
   companion object {
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/helper/PreferenceHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/helper/PreferenceHelper.kt
new file mode 100644
index 000000000..47a10d6dc
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/helper/PreferenceHelper.kt
@@ -0,0 +1,26 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2018 Janne Koschinski
+ * Copyright (c) 2018 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid.util.helper
+
+import android.support.v7.preference.PreferenceCategory
+import android.support.v7.preference.PreferenceScreen
+
+fun PreferenceCategory.preferences() = (0 until preferenceCount).map(this::getPreference)
+fun PreferenceScreen.preferences() = (0 until preferenceCount).map(this::getPreference)
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/ActivityLauncher.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/ActivityLauncher.kt
new file mode 100644
index 000000000..b3f5bdf99
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/ActivityLauncher.kt
@@ -0,0 +1,29 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2018 Janne Koschinski
+ * Copyright (c) 2018 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid.util.ui.settings
+
+import android.content.Intent
+
+interface ActivityLauncher {
+  fun startActivityForResult(intent: Intent, requestCode: Int)
+  fun registerOnActivityResultListener(listener: OnActivityResultListener)
+  fun unregisterOnActivityResultListener(listener: OnActivityResultListener)
+  fun getNextRequestCode(): Int
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/AttachingPreferenceFragmentCompat.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/AttachingPreferenceFragmentCompat.kt
new file mode 100644
index 000000000..b89e220da
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/AttachingPreferenceFragmentCompat.kt
@@ -0,0 +1,64 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2018 Janne Koschinski
+ * Copyright (c) 2018 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid.util.ui.settings
+
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.preference.Preference
+import android.support.v7.preference.PreferenceCategory
+import android.support.v7.preference.PreferenceFragmentCompat
+import android.support.v7.preference.PreferenceScreen
+import de.kuschku.quasseldroid.util.helper.preferences
+import java.util.concurrent.atomic.AtomicInteger
+
+abstract class AttachingPreferenceFragmentCompat : PreferenceFragmentCompat(), ActivityLauncher {
+  private val nextRequestCode = AtomicInteger(0)
+
+  private var activityResultListeners = emptySet<OnActivityResultListener>()
+
+  override fun registerOnActivityResultListener(listener: OnActivityResultListener) {
+    activityResultListeners += listener
+  }
+
+  override fun unregisterOnActivityResultListener(listener: OnActivityResultListener) {
+    activityResultListeners -= listener
+  }
+
+  override fun getNextRequestCode() = nextRequestCode.getAndIncrement()
+
+  override fun onCreate(savedInstanceState: Bundle?) {
+    super.onCreate(savedInstanceState)
+    attachPreference(preferenceScreen)
+  }
+
+  private fun attachPreference(preference: Preference) {
+    when (preference) {
+      is PreferenceScreen         -> preference.preferences().forEach(::attachPreference)
+      is PreferenceCategory       -> preference.preferences().forEach(::attachPreference)
+      is RequiresActivityLauncher -> preference.activityLauncher = this
+    }
+  }
+
+  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+    for (it in activityResultListeners) {
+      it.onActivityResult(requestCode, resultCode, data)
+    }
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/backport/DaggerPreferenceFragmentCompat.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/DaggerPreferenceFragmentCompat.kt
similarity index 88%
rename from app/src/main/java/de/kuschku/quasseldroid/util/backport/DaggerPreferenceFragmentCompat.kt
rename to app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/DaggerPreferenceFragmentCompat.kt
index 49e81c0ea..aa7cb6698 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/backport/DaggerPreferenceFragmentCompat.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/DaggerPreferenceFragmentCompat.kt
@@ -17,18 +17,17 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid.util.backport
+package de.kuschku.quasseldroid.util.ui.settings
 
 import android.content.Context
 import android.support.v4.app.Fragment
-import android.support.v7.preference.PreferenceFragmentCompat
 import dagger.android.AndroidInjector
 import dagger.android.DispatchingAndroidInjector
 import dagger.android.support.AndroidSupportInjection
 import dagger.android.support.HasSupportFragmentInjector
 import javax.inject.Inject
 
-abstract class DaggerPreferenceFragmentCompat : PreferenceFragmentCompat(),
+abstract class DaggerPreferenceFragmentCompat : AttachingPreferenceFragmentCompat(),
                                                 HasSupportFragmentInjector {
   @Inject
   lateinit var childFragmentInjector: DispatchingAndroidInjector<Fragment>
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/OnActivityResultListener.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/OnActivityResultListener.kt
new file mode 100644
index 000000000..160631e7e
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/OnActivityResultListener.kt
@@ -0,0 +1,32 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2018 Janne Koschinski
+ * Copyright (c) 2018 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid.util.ui.settings
+
+import android.content.Intent
+
+interface OnActivityResultListener {
+  /**
+   * See Activity's onActivityResult.
+   *
+   * @return Whether the request code was handled (in which case
+   * subsequent listeners will not be called.
+   */
+  fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RequiresActivityLauncher.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RequiresActivityLauncher.kt
new file mode 100644
index 000000000..13c33568e
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RequiresActivityLauncher.kt
@@ -0,0 +1,24 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2018 Janne Koschinski
+ * Copyright (c) 2018 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid.util.ui.settings
+
+interface RequiresActivityLauncher {
+  var activityLauncher: ActivityLauncher?
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt
new file mode 100644
index 000000000..e87f33555
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/RingtonePreference.kt
@@ -0,0 +1,226 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2018 Janne Koschinski
+ * Copyright (c) 2018 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid.util.ui.settings
+
+import android.content.Context
+import android.content.Intent
+import android.content.res.TypedArray
+import android.media.RingtoneManager
+import android.net.Uri
+import android.support.v7.preference.DialogPreference
+import android.text.TextUtils
+import android.util.AttributeSet
+import de.kuschku.quasseldroid.R
+
+class RingtonePreference : DialogPreference,
+                           RequiresActivityLauncher,
+                           OnActivityResultListener {
+  private val TAG = "RingtonePreference"
+
+  private var mRingtoneType: Int = 0
+  private var mShowDefault: Boolean = false
+  private var mShowSilent: Boolean = false
+
+  private var mRequestCode: Int? = null
+
+  override var activityLauncher: ActivityLauncher? = null
+    set(value) {
+      field?.unregisterOnActivityResultListener(this)
+
+      field = value
+
+      value?.registerOnActivityResultListener(this)
+      mRequestCode = value?.getNextRequestCode()
+    }
+
+  constructor(context: Context) :
+    this(context, null)
+
+  constructor(context: Context, attrs: AttributeSet?) :
+    this(context, attrs, R.attr.ringtonePreferenceStyle)
+
+  constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
+    this(context, attrs, defStyleAttr, 0)
+
+  constructor(context: Context, attrs: AttributeSet?, styleAttr: Int, styleRes: Int) :
+    super(context, attrs, styleAttr, styleRes) {
+    val a = context.obtainStyledAttributes(
+      attrs, R.styleable.RingtonePreference, styleAttr, styleRes)
+    mRingtoneType = a.getInt(R.styleable.RingtonePreference_ringtoneType,
+                             RingtoneManager.TYPE_RINGTONE)
+    mShowDefault = a.getBoolean(R.styleable.RingtonePreference_showDefault, true)
+    mShowSilent = a.getBoolean(R.styleable.RingtonePreference_showSilent, true)
+    a.recycle()
+  }
+
+  /**
+   * Returns the sound type(s) that are shown in the picker.
+   *
+   * @return The sound type(s) that are shown in the picker.
+   * @see .setRingtoneType
+   */
+  fun getRingtoneType(): Int {
+    return mRingtoneType
+  }
+
+  /**
+   * Sets the sound type(s) that are shown in the picker.
+   *
+   * @param type The sound type(s) that are shown in the picker.
+   * @see RingtoneManager.EXTRA_RINGTONE_TYPE
+   */
+  fun setRingtoneType(type: Int) {
+    mRingtoneType = type
+  }
+
+  /**
+   * Returns whether to a show an item for the default sound/ringtone.
+   *
+   * @return Whether to show an item for the default sound/ringtone.
+   */
+  fun getShowDefault(): Boolean {
+    return mShowDefault
+  }
+
+  /**
+   * Sets whether to show an item for the default sound/ringtone. The default
+   * to use will be deduced from the sound type(s) being shown.
+   *
+   * @param showDefault Whether to show the default or not.
+   * @see RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT
+   */
+  fun setShowDefault(showDefault: Boolean) {
+    mShowDefault = showDefault
+  }
+
+  /**
+   * Returns whether to a show an item for 'Silent'.
+   *
+   * @return Whether to show an item for 'Silent'.
+   */
+  fun getShowSilent(): Boolean {
+    return mShowSilent
+  }
+
+  /**
+   * Sets whether to show an item for 'Silent'.
+   *
+   * @param showSilent Whether to show 'Silent'.
+   * @see RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT
+   */
+  fun setShowSilent(showSilent: Boolean) {
+    mShowSilent = showSilent
+  }
+
+  override fun onClick() {
+    // Launch the ringtone picker
+    val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER)
+    onPrepareRingtonePickerIntent(intent)
+    mRequestCode?.let {
+      activityLauncher?.startActivityForResult(intent, it)
+    }
+  }
+
+  /**
+   * Prepares the intent to launch the ringtone picker. This can be modified
+   * to adjust the parameters of the ringtone picker.
+   *
+   * @param ringtonePickerIntent The ringtone picker intent that can be
+   * modified by putting extras.
+   */
+  protected fun onPrepareRingtonePickerIntent(ringtonePickerIntent: Intent) {
+
+    ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, mShowDefault)
+    ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent)
+    ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, mRingtoneType)
+    ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, title)
+    if (mShowDefault) {
+      ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
+                                    RingtoneManager.getDefaultUri(getRingtoneType()))
+    }
+    ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, onRestoreRingtone())
+  }
+
+  /**
+   * Called when a ringtone is chosen.
+   *
+   *
+   * By default, this saves the ringtone URI to the persistent storage as a
+   * string.
+   *
+   * @param ringtoneUri The chosen ringtone's [Uri]. Can be null.
+   */
+  protected fun onSaveRingtone(ringtoneUri: Uri?) {
+    persistString(ringtoneUri?.toString() ?: "")
+    updateSummary(ringtoneUri)
+  }
+
+  /**
+   * Called when the chooser is about to be shown and the current ringtone
+   * should be marked. Can return null to not mark any ringtone.
+   *
+   *
+   * By default, this restores the previous ringtone URI from the persistent
+   * storage.
+   *
+   * @return The ringtone to be marked as the current ringtone.
+   */
+  protected fun onRestoreRingtone(): Uri? {
+    val uriString = getPersistedString(null)
+    return if (!TextUtils.isEmpty(uriString)) Uri.parse(uriString) else null
+  }
+
+  private fun updateSummary(ringtoneUri: Uri?) {
+    summary = ringtoneUri?.let {
+      RingtoneManager.getRingtone(context, ringtoneUri).getTitle(context)
+    } ?: context.getString(R.string.label_no_sound)
+  }
+
+  override fun onGetDefaultValue(a: TypedArray, index: Int): Any? {
+    return a.getString(index)
+  }
+
+  override fun onSetInitialValue(restorePersistedValue: Boolean, defaultValueObj: Any?) {
+    val defaultValue = defaultValueObj as? String ?: ""
+
+    if (restorePersistedValue) {
+      updateSummary(onRestoreRingtone())
+      return
+    }
+
+    // If we are setting to the default value, we should persist it.
+    if (!TextUtils.isEmpty(defaultValue)) {
+      onSaveRingtone(Uri.parse(defaultValue))
+    }
+  }
+
+  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
+    if (requestCode == mRequestCode) {
+      if (data != null) {
+        val uri = data.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
+        if (callChangeListener(uri?.toString() ?: "")) {
+          onSaveRingtone(uri)
+        }
+      }
+      return true
+    }
+    return false
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/SeekBarPreference.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/SeekBarPreference.kt
similarity index 99%
rename from app/src/main/java/de/kuschku/quasseldroid/util/ui/SeekBarPreference.kt
rename to app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/SeekBarPreference.kt
index 35bc50d53..fa862ca4b 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/ui/SeekBarPreference.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/SeekBarPreference.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package de.kuschku.quasseldroid.util.ui
+package de.kuschku.quasseldroid.util.ui.settings
 
 import android.content.Context
 import android.content.res.TypedArray
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/ServiceBoundSettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/ServiceBoundSettingsActivity.kt
similarity index 98%
rename from app/src/main/java/de/kuschku/quasseldroid/util/ui/ServiceBoundSettingsActivity.kt
rename to app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/ServiceBoundSettingsActivity.kt
index f9e369950..27dbb9cd8 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/ui/ServiceBoundSettingsActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/ServiceBoundSettingsActivity.kt
@@ -17,7 +17,7 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid.util.ui
+package de.kuschku.quasseldroid.util.ui.settings
 
 import android.os.Bundle
 import android.support.v4.app.Fragment
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/SettingsActivity.kt
similarity index 96%
rename from app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt
rename to app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/SettingsActivity.kt
index ea6df6328..750f21d23 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/settings/SettingsActivity.kt
@@ -17,7 +17,7 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package de.kuschku.quasseldroid.util.ui
+package de.kuschku.quasseldroid.util.ui.settings
 
 import android.os.Bundle
 import android.support.v4.app.Fragment
@@ -28,6 +28,7 @@ import butterknife.ButterKnife
 import com.afollestad.materialdialogs.MaterialDialog
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment
+import de.kuschku.quasseldroid.util.ui.ThemedActivity
 
 abstract class SettingsActivity(private val fragment: Fragment? = null) : ThemedActivity() {
   protected open fun fragment(): Fragment? = null
diff --git a/app/src/main/res/layout/widget_preference_divider.xml b/app/src/main/res/layout/widget_preference_divider.xml
new file mode 100644
index 000000000..684544804
--- /dev/null
+++ b/app/src/main/res/layout/widget_preference_divider.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Quasseldroid - Quassel client for Android
+
+  Copyright (c) 2018 Janne Koschinski
+  Copyright (c) 2018 The Quassel Project
+
+  This program is free software: you can redistribute it and/or modify it
+  under the terms of the GNU General Public License version 3 as published
+  by the Free Software Foundation.
+
+  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.
+
+  You should have received a copy of the GNU General Public License along
+  with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent"
+  android:layout_height="1dp"
+  android:background="?colorDivider" />
diff --git a/app/src/main/res/layout/widget_spinner_item_inline.xml b/app/src/main/res/layout/widget_spinner_item_inline.xml
index e3102b3fd..d109243dc 100644
--- a/app/src/main/res/layout/widget_spinner_item_inline.xml
+++ b/app/src/main/res/layout/widget_spinner_item_inline.xml
@@ -25,7 +25,6 @@
   android:layout_height="wrap_content"
   android:gravity="center_vertical"
   android:minHeight="?listPreferredItemHeightSmall"
-  android:background="?background"
   android:paddingLeft="16dp"
   android:paddingRight="16dp"
   android:textAppearance="?android:attr/textAppearanceListItemSmall"
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 9da3b2a0a..db5a7effe 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -73,6 +73,7 @@
   <string name="label_nicklist">Benutzerliste</string>
   <string name="label_no">Nein</string>
   <string name="label_no_away_message">Kein Abwesenheitsgrund verfügbar</string>
+  <string name="label_no_sound">Ohne</string>
   <string name="label_reply">Antworten</string>
   <string name="label_reset">Zurücksetzen</string>
   <string name="label_open">Öffnen</string>
diff --git a/app/src/main/res/values-de/strings_preferences.xml b/app/src/main/res/values-de/strings_preferences.xml
index 1e3e0f078..695a00551 100644
--- a/app/src/main/res/values-de/strings_preferences.xml
+++ b/app/src/main/res/values-de/strings_preferences.xml
@@ -46,8 +46,19 @@
   <string name="preference_notifications_title">Benachrichtigungen</string>
 
   <string name="preference_notification_query_title">Direktnachrichten</string>
+
   <string name="preference_notification_channel_title">Räume</string>
+
   <string name="preference_notification_other_title">Andere Nachrichten</string>
+
+  <string name="preference_notification_sound_title">Benachrichtigungston</string>
+
+  <string name="preference_notification_vibration_title">Vibration</string>
+
+  <string name="preference_notification_light_title">LED</string>
+
+  <string name="preference_notification_configure_title">Benachrichtigungen konfigurieren</string>
+
   <string name="preference_notifications_level_all">Alle Nachrichten</string>
   <string name="preference_notifications_level_highlight">Erwähnungen</string>
   <string name="preference_notifications_level_none">Niemals</string>
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index 84c05075c..fe41efcb5 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -73,6 +73,7 @@
   <string name="label_nicklist">Slapyvardžių Sąrašas</string>
   <string name="label_no">Ne</string>
   <string name="label_no_away_message">Nėra pasišalinimo žinutės</string>
+  <string name="label_no_sound">Nėra</string>
   <string name="label_reply">Atsakyti</string>
   <string name="label_reset">Atstatyti</string>
   <string name="label_open">Atverti</string>
diff --git a/app/src/main/res/values-lt/strings_preferences.xml b/app/src/main/res/values-lt/strings_preferences.xml
index bd176ba2c..3e6e05abe 100644
--- a/app/src/main/res/values-lt/strings_preferences.xml
+++ b/app/src/main/res/values-lt/strings_preferences.xml
@@ -51,6 +51,12 @@
 
   <string name="preference_notification_other_title">Kitos žinutės</string>
 
+  <string name="preference_notification_sound_title">Pranešimo garsas</string>
+  <string name="preference_notification_vibration_title">Vibracija</string>
+  <string name="preference_notification_light_title">LED Lemputė</string>
+
+  <string name="preference_notification_configure_title">Pranešimų nustatymai</string>
+
   <string name="preference_notifications_level_all">Visos žinutės</string>
   <string name="preference_notifications_level_highlight">Paminėjimai</string>
   <string name="preference_notifications_level_none">Niekada</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c2734d5e6..cc111438f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -22,6 +22,8 @@
   <string name="app_description">An Android-based client for the decentralized Quassel IRC client.</string>
   <string name="app_description_long">Quassel is a distributed, decentralized IRC client, written using C++ and Qt. Quasseldroid is a pure-kotlin client for the Quassel core, allowing you to connect to your Quassel core using your Android™ phone.</string>
 
+  <string name="package_name">com.iskrembilen.quasseldroid</string>
+
   <string name="connection_service_title">Connection Service</string>
   <string name="connection_service_description">Keeps a connection to your core to allow for notifications, and to transmit messages.</string>
 
@@ -73,6 +75,7 @@
   <string name="label_nicklist">Nick List</string>
   <string name="label_no">No</string>
   <string name="label_no_away_message">No away message available</string>
+  <string name="label_no_sound">None</string>
   <string name="label_reply">Reply</string>
   <string name="label_reset">Reset</string>
   <string name="label_open">Open</string>
diff --git a/app/src/main/res/values/strings_preferences.xml b/app/src/main/res/values/strings_preferences.xml
index 896a78e8c..781f1b2be 100644
--- a/app/src/main/res/values/strings_preferences.xml
+++ b/app/src/main/res/values/strings_preferences.xml
@@ -105,6 +105,18 @@
   <string name="preference_notification_other_key" translatable="false">notification_other</string>
   <string name="preference_notification_other_title">Other Messages</string>
 
+  <string name="preference_notification_sound_key" translatable="false">notification_sound</string>
+  <string name="preference_notification_sound_title">Notification Sound</string>
+
+  <string name="preference_notification_vibration_key" translatable="false">notification_vibration</string>
+  <string name="preference_notification_vibration_title">Vibration</string>
+
+  <string name="preference_notification_light_key" translatable="false">notification_light</string>
+  <string name="preference_notification_light_title">LED</string>
+
+  <string name="preference_notification_configure_key" translatable="false">notification_configure</string>
+  <string name="preference_notification_configure_title">Configure Notifications</string>
+
   <string name="preference_notifications_level_all">All Messages</string>
   <string name="preference_notifications_level_highlight">Mentions</string>
   <string name="preference_notifications_level_none">Never</string>
diff --git a/app/src/main/res/values/styles_widgets.xml b/app/src/main/res/values/styles_widgets.xml
index 202296289..10bbddc83 100644
--- a/app/src/main/res/values/styles_widgets.xml
+++ b/app/src/main/res/values/styles_widgets.xml
@@ -104,6 +104,7 @@
     <item name="android:layout_height">wrap_content</item>
     <item name="android:paddingLeft">0dip</item>
     <item name="android:paddingRight">0dip</item>
+    <item name="android:popupBackground">?colorBackground</item>
   </style>
 
   <style name="Widget.CoreSettings.Wrapper" parent="">
@@ -263,6 +264,14 @@
     <item name="android:textColor">?colorTextSecondary</item>
   </style>
 
+  <style name="Widget.RingtonePreference" parent="">
+    <item name="android:layout">@layout/preference_vertical</item>
+
+    <item name="ringtoneType">ringtone</item>
+    <item name="showSilent">true</item>
+    <item name="showDefault">true</item>
+  </style>
+
   <style name="Widget.Subhead" parent="Widget.RtlConformTextView">
     <item name="android:layout_width">wrap_content</item>
     <item name="android:layout_height">wrap_content</item>
@@ -297,4 +306,23 @@
   <declare-styleable name="ShadowView">
     <attr name="android:gravity" />
   </declare-styleable>
+
+  <!-- RingtonePreference -->
+  <declare-styleable name="RingtonePreference">
+    <!-- Which ringtone type(s) to show in the picker. -->
+    <attr name="ringtoneType">
+      <!-- Ringtones. -->
+      <flag name="ringtone" value="1" />
+      <!-- Notification sounds. -->
+      <flag name="notification" value="2" />
+      <!-- Alarm sounds. -->
+      <flag name="alarm" value="4" />
+      <!-- All available ringtone sounds. -->
+      <flag name="all" value="7" />
+    </attr>
+    <!-- Whether to show an item for a default sound. -->
+    <attr name="showDefault" format="boolean" />
+    <!-- Whether to show an item for 'Silent'. -->
+    <attr name="showSilent" format="boolean" />
+  </declare-styleable>
 </resources>
diff --git a/app/src/main/res/values/themes_base.xml b/app/src/main/res/values/themes_base.xml
index 6ffe915e9..90022aeff 100644
--- a/app/src/main/res/values/themes_base.xml
+++ b/app/src/main/res/values/themes_base.xml
@@ -72,6 +72,8 @@
     <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
     <item name="actionBarPopupTheme">@style/Widget.PopupOverlay</item>
 
+    <item name="ringtonePreferenceStyle">@style/Widget.RingtonePreference</item>
+
     <item name="backgroundMenuItem">@drawable/bg_menuitem_dark</item>
     <item name="backgroundMenuItemRounded">@drawable/bg_menuitem_rounded_dark</item>
 
@@ -106,6 +108,8 @@
     <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
     <item name="actionBarPopupTheme">@style/Widget.PopupOverlay.Light</item>
 
+    <item name="ringtonePreferenceStyle">@style/Widget.RingtonePreference</item>
+
     <item name="backgroundMenuItem">@drawable/bg_menuitem_light</item>
     <item name="backgroundMenuItemRounded">@drawable/bg_menuitem_rounded_light</item>
 
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 08bcb2591..ae83ca152 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -18,6 +18,7 @@
   -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:robobunny="http://robobunny.com">
   <PreferenceCategory android:title="@string/preference_appearance_title">
     <ListPreference
@@ -48,6 +49,8 @@
       android:title="@string/preference_language_title" />
   </PreferenceCategory>
 
+  <PreferenceCategory android:layout="@layout/widget_preference_divider" />
+
   <PreferenceCategory android:title="@string/preference_notifications_title">
     <DropDownPreference
       android:defaultValue="ALL"
@@ -67,9 +70,41 @@
       android:entryValues="@array/preference_notifications_level_entryvalues"
       android:key="@string/preference_notification_other_key"
       android:title="@string/preference_notification_other_title" />
-    <!-- TODO: Add Notification ringtone/etc setting links -->
+
+    <de.kuschku.quasseldroid.util.ui.settings.RingtonePreference
+      android:defaultValue="content://settings/system/notification_sound"
+      android:key="@string/preference_notification_sound_key"
+      android:title="@string/preference_notification_sound_title"
+      app:ringtoneType="notification"
+      app:showDefault="true"
+      app:showSilent="true" />
+
+    <SwitchPreference
+      android:defaultValue="true"
+      android:key="@string/preference_notification_vibration_key"
+      android:title="@string/preference_notification_vibration_title" />
+
+    <SwitchPreference
+      android:defaultValue="true"
+      android:key="@string/preference_notification_light_key"
+      android:title="@string/preference_notification_light_title" />
+
+    <PreferenceScreen
+      android:key="@string/preference_notification_configure_key"
+      android:title="@string/preference_notification_configure_title">
+      <intent android:action="android.settings.CHANNEL_NOTIFICATION_SETTINGS">
+        <extra
+          android:name="android.provider.extra.APP_PACKAGE"
+          android:value="@string/package_name" />
+        <extra
+          android:name="android.provider.extra.CHANNEL_ID"
+          android:value="@string/notification_channel_highlight" />
+      </intent>
+    </PreferenceScreen>
   </PreferenceCategory>
 
+  <PreferenceCategory android:layout="@layout/widget_preference_divider" />
+
   <PreferenceCategory android:title="@string/preference_messages_title">
 
     <SwitchPreference
@@ -77,7 +112,7 @@
       android:key="@string/preference_monospace_key"
       android:title="@string/preference_monospace_title" />
 
-    <de.kuschku.quasseldroid.util.ui.SeekBarPreference
+    <de.kuschku.quasseldroid.util.ui.settings.SeekBarPreference
       android:defaultValue="14"
       android:key="@string/preference_textsize_key"
       android:max="24"
@@ -171,6 +206,8 @@
     -->
   </PreferenceCategory>
 
+  <PreferenceCategory android:layout="@layout/widget_preference_divider" />
+
   <PreferenceCategory android:title="@string/preference_autocomplete_title">
 
     <SwitchPreference
@@ -204,6 +241,8 @@
       android:title="@string/preference_autocomplete_prefix_title" />
   </PreferenceCategory>
 
+  <PreferenceCategory android:layout="@layout/widget_preference_divider" />
+
   <PreferenceCategory android:title="@string/preference_backlog_title">
     <EditTextPreference
       android:defaultValue="150"
@@ -219,6 +258,8 @@
       android:title="@string/preference_initial_amount_title" />
   </PreferenceCategory>
 
+  <PreferenceCategory android:layout="@layout/widget_preference_divider" />
+
   <PreferenceCategory android:title="@string/preference_connection_title">
     <SwitchPreference
       android:defaultValue="true"
-- 
GitLab