From 7bdec40543a3358bd033d34a8d25c94078888749 Mon Sep 17 00:00:00 2001 From: Janne Koschinski <janne@kuschku.de> Date: Thu, 19 Apr 2018 19:50:04 +0200 Subject: [PATCH] Implement SSL whitelist UI --- app/src/main/AndroidManifest.xml | 20 ++-- .../quasseldroid/dagger/ActivityModule.kt | 37 ++++--- .../quasseldroid/service/QuasselService.kt | 6 +- .../quasseldroid/ui/chat/ChatActivity.kt | 6 +- ...utSettingsActivity.kt => AboutActivity.kt} | 4 +- ...utSettingsFragment.kt => AboutFragment.kt} | 4 +- ...ntProvider.kt => AboutFragmentProvider.kt} | 4 +- .../ui/clientsettings/about/LibraryAdapter.kt | 8 +- .../app/AppSettingsFragmentProvider.kt | 10 -- .../client/ClientSettingsActivity.kt | 12 +++ .../ClientSettingsFragment.kt} | 25 +++-- .../client/ClientSettingsFragmentProvider.kt | 10 ++ ...shSettingsActivity.kt => CrashActivity.kt} | 4 +- ...shSettingsFragment.kt => CrashFragment.kt} | 6 +- ...ntProvider.kt => CrashFragmentProvider.kt} | 4 +- ...SettingsActivity.kt => LicenseActivity.kt} | 4 +- ...SettingsFragment.kt => LicenseFragment.kt} | 4 +- ...Provider.kt => LicenseFragmentProvider.kt} | 4 +- .../ui/clientsettings/whitelist/Whitelist.kt | 8 ++ .../WhitelistActivity.kt} | 6 +- .../whitelist/WhitelistCertificateAdapter.kt | 97 ++++++++++++++++++ .../whitelist/WhitelistFragment.kt | 99 +++++++++++++++++++ .../whitelist/WhitelistFragmentProvider.kt | 10 ++ .../whitelist/WhitelistHostnameAdapter.kt | 90 +++++++++++++++++ .../quasseldroid/ui/setup/SetupActivity.kt | 17 ++-- .../res/layout-sw720dp/activity_settings.xml | 2 +- app/src/main/res/layout/layout_editor.xml | 5 +- ...agment_about.xml => preferences_about.xml} | 4 +- ...eader.xml => preferences_about_header.xml} | 0 ...agment_crash.xml => preferences_crash.xml} | 0 ...nt_license.xml => preferences_license.xml} | 0 .../main/res/layout/preferences_whitelist.xml | 41 ++++++++ ...preferences_whitelist_certificate_item.xml | 55 +++++++++++ .../preferences_whitelist_hostname_item.xml | 55 +++++++++++ .../main/res/layout/widget_contributor.xml | 2 +- app/src/main/res/layout/widget_library.xml | 2 +- app/src/main/res/menu/activity_settings.xml | 3 + app/src/main/res/menu/activity_setup.xml | 3 + app/src/main/res/values-de/strings.xml | 4 + app/src/main/res/values-de/strings_error.xml | 12 ++- .../main/res/values-v17/styles_widgets.xml | 14 +++ app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/strings_error.xml | 11 ++- app/src/main/res/values/styles_widgets.xml | 12 +++ .../libquassel/session/SessionManager.kt | 13 ++- .../persistence/QuasselDatabase.kt | 12 +++ .../viewmodel/QuasselViewModel.kt | 6 +- 47 files changed, 664 insertions(+), 95 deletions(-) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/{AboutSettingsActivity.kt => AboutActivity.kt} (63%) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/{AboutSettingsFragment.kt => AboutFragment.kt} (98%) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/{AboutSettingsFragmentProvider.kt => AboutFragmentProvider.kt} (59%) delete mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsFragmentProvider.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsActivity.kt rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/{app/AppSettingsFragment.kt => client/ClientSettingsFragment.kt} (74%) create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragmentProvider.kt rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/{CrashSettingsActivity.kt => CrashActivity.kt} (63%) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/{CrashSettingsFragment.kt => CrashFragment.kt} (94%) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/{CrashSettingsFragmentProvider.kt => CrashFragmentProvider.kt} (60%) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/{LicenseSettingsActivity.kt => LicenseActivity.kt} (80%) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/{LicenseSettingsFragment.kt => LicenseFragment.kt} (85%) rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/{LicenseSettingsFragmentProvider.kt => LicenseFragmentProvider.kt} (58%) create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt rename app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/{app/AppSettingsActivity.kt => whitelist/WhitelistActivity.kt} (51%) create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragmentProvider.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt rename app/src/main/res/layout/{fragment_about.xml => preferences_about.xml} (96%) rename app/src/main/res/layout/{layout_about_header.xml => preferences_about_header.xml} (100%) rename app/src/main/res/layout/{fragment_crash.xml => preferences_crash.xml} (100%) rename app/src/main/res/layout/{fragment_license.xml => preferences_license.xml} (100%) create mode 100644 app/src/main/res/layout/preferences_whitelist.xml create mode 100644 app/src/main/res/layout/preferences_whitelist_certificate_item.xml create mode 100644 app/src/main/res/layout/preferences_whitelist_hostname_item.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 49809b1aa..ace3e96d6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -160,28 +160,34 @@ <!-- Client Settings --> <activity - android:name=".ui.clientsettings.app.AppSettingsActivity" + android:name=".ui.clientsettings.client.ClientSettingsActivity" android:exported="false" android:label="@string/label_settings_client" android:parentActivityName=".ui.chat.ChatActivity" android:windowSoftInputMode="adjustResize" /> <activity - android:name=".ui.clientsettings.crash.CrashSettingsActivity" + android:name=".ui.clientsettings.crash.CrashActivity" android:exported="false" android:label="@string/label_crashes" - android:parentActivityName=".ui.clientsettings.app.AppSettingsActivity" + android:parentActivityName=".ui.clientsettings.client.ClientSettingsActivity" android:windowSoftInputMode="adjustResize" /> <activity - android:name=".ui.clientsettings.about.AboutSettingsActivity" + android:name=".ui.clientsettings.whitelist.WhitelistActivity" + android:exported="false" + android:label="@string/label_certificates" + android:parentActivityName=".ui.clientsettings.client.ClientSettingsActivity" + android:windowSoftInputMode="adjustResize" /> + <activity + android:name=".ui.clientsettings.about.AboutActivity" android:exported="false" android:label="@string/label_about" - android:parentActivityName=".ui.clientsettings.app.AppSettingsActivity" + android:parentActivityName=".ui.clientsettings.client.ClientSettingsActivity" android:windowSoftInputMode="adjustResize" /> <activity - android:name=".ui.clientsettings.license.LicenseSettingsActivity" + android:name=".ui.clientsettings.license.LicenseActivity" android:exported="false" android:label="@string/label_license" - android:parentActivityName=".ui.clientsettings.about.AboutSettingsActivity" + android:parentActivityName=".ui.clientsettings.about.AboutActivity" android:windowSoftInputMode="adjustResize" /> <!-- Client Setup Flow --> diff --git a/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt b/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt index 62aa64020..9a281ef66 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt @@ -12,14 +12,16 @@ import de.kuschku.quasseldroid.ui.chat.info.user.UserInfoActivity import de.kuschku.quasseldroid.ui.chat.info.user.UserInfoFragmentProvider import de.kuschku.quasseldroid.ui.chat.topic.TopicActivity import de.kuschku.quasseldroid.ui.chat.topic.TopicFragmentProvider -import de.kuschku.quasseldroid.ui.clientsettings.about.AboutSettingsActivity -import de.kuschku.quasseldroid.ui.clientsettings.about.AboutSettingsFragmentProvider -import de.kuschku.quasseldroid.ui.clientsettings.app.AppSettingsActivity -import de.kuschku.quasseldroid.ui.clientsettings.app.AppSettingsFragmentProvider -import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashSettingsActivity -import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashSettingsFragmentProvider -import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseSettingsActivity -import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseSettingsFragmentProvider +import de.kuschku.quasseldroid.ui.clientsettings.about.AboutActivity +import de.kuschku.quasseldroid.ui.clientsettings.about.AboutFragmentProvider +import de.kuschku.quasseldroid.ui.clientsettings.client.ClientSettingsActivity +import de.kuschku.quasseldroid.ui.clientsettings.client.ClientSettingsFragmentProvider +import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashActivity +import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashFragmentProvider +import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseActivity +import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseFragmentProvider +import de.kuschku.quasseldroid.ui.clientsettings.whitelist.WhitelistActivity +import de.kuschku.quasseldroid.ui.clientsettings.whitelist.WhitelistFragmentProvider import de.kuschku.quasseldroid.ui.coresettings.CoreSettingsActivity import de.kuschku.quasseldroid.ui.coresettings.CoreSettingsFragmentProvider import de.kuschku.quasseldroid.ui.coresettings.aliasitem.AliasItemActivity @@ -70,17 +72,20 @@ abstract class ActivityModule { @ContributesAndroidInjector(modules = [TopicFragmentProvider::class]) abstract fun bindTopicActivity(): TopicActivity - @ContributesAndroidInjector(modules = [AppSettingsFragmentProvider::class]) - abstract fun bindAppSettingsActivity(): AppSettingsActivity + @ContributesAndroidInjector(modules = [ClientSettingsFragmentProvider::class]) + abstract fun bindClientSettingsActivity(): ClientSettingsActivity - @ContributesAndroidInjector(modules = [CrashSettingsFragmentProvider::class]) - abstract fun bindCrashSettingsActivity(): CrashSettingsActivity + @ContributesAndroidInjector(modules = [WhitelistFragmentProvider::class]) + abstract fun bindWhitelistActivity(): WhitelistActivity - @ContributesAndroidInjector(modules = [AboutSettingsFragmentProvider::class]) - abstract fun bindAboutSettingsActivity(): AboutSettingsActivity + @ContributesAndroidInjector(modules = [CrashFragmentProvider::class]) + abstract fun bindCrashActivity(): CrashActivity - @ContributesAndroidInjector(modules = [LicenseSettingsFragmentProvider::class]) - abstract fun bindLicenseSettingsActivity(): LicenseSettingsActivity + @ContributesAndroidInjector(modules = [AboutFragmentProvider::class]) + abstract fun bindAboutActivity(): AboutActivity + + @ContributesAndroidInjector(modules = [LicenseFragmentProvider::class]) + abstract fun bindLicenseActivity(): LicenseActivity @ContributesAndroidInjector(modules = [CoreSettingsFragmentProvider::class]) abstract fun bindCoreSettingsActivity(): CoreSettingsActivity diff --git a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt index 9908f5366..4a41bfaef 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/service/QuasselService.kt @@ -276,7 +276,8 @@ class QuasselService : DaggerLifecycleService(), .throttleFirst(1, TimeUnit.SECONDS) .toLiveData() .observe(this, Observer { - if (wasEverConnected) sessionManager.reconnect(true) + if (wasEverConnected && !sessionManager.hasErrored) + sessionManager.reconnect(true) }) sessionManager.state @@ -287,7 +288,8 @@ class QuasselService : DaggerLifecycleService(), .observe( this, Observer { if (it == ConnectionState.DISCONNECTED || it == ConnectionState.CLOSED) { - if (wasEverConnected) sessionManager.reconnect() + if (wasEverConnected && !sessionManager.hasErrored) + sessionManager.reconnect() } else { wasEverConnected = true } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt index 82b9bff21..883a9e4be 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt @@ -39,7 +39,7 @@ import de.kuschku.quasseldroid.settings.MessageSettings import de.kuschku.quasseldroid.settings.Settings import de.kuschku.quasseldroid.ui.chat.input.AutoCompleteAdapter import de.kuschku.quasseldroid.ui.chat.input.ChatlineFragment -import de.kuschku.quasseldroid.ui.clientsettings.app.AppSettingsActivity +import de.kuschku.quasseldroid.ui.clientsettings.client.ClientSettingsActivity import de.kuschku.quasseldroid.ui.coresettings.CoreSettingsActivity import de.kuschku.quasseldroid.util.helper.* import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer @@ -162,7 +162,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc val dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) viewModel.errors.toLiveData().observe(this, Observer { error -> - error?.orNull()?.let { + error?.let { when (it) { is Error.HandshakeError -> it.message.let { when (it) { @@ -567,7 +567,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc true } R.id.action_client_settings -> { - AppSettingsActivity.launch(this) + ClientSettingsActivity.launch(this) true } R.id.action_disconnect -> { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutActivity.kt similarity index 63% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsActivity.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutActivity.kt index c13a3762c..0ca4b84fd 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutActivity.kt @@ -4,9 +4,9 @@ import android.content.Context import android.content.Intent import de.kuschku.quasseldroid.util.ui.SettingsActivity -class AboutSettingsActivity : SettingsActivity(AboutSettingsFragment()) { +class AboutActivity : SettingsActivity(AboutFragment()) { companion object { fun launch(context: Context) = context.startActivity(intent(context)) - fun intent(context: Context) = Intent(context, AboutSettingsActivity::class.java) + fun intent(context: Context) = Intent(context, AboutActivity::class.java) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt similarity index 98% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsFragment.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt index 204297e59..136dc02dc 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt @@ -18,7 +18,7 @@ import dagger.android.support.DaggerFragment import de.kuschku.quasseldroid.BuildConfig import de.kuschku.quasseldroid.R -class AboutSettingsFragment : DaggerFragment() { +class AboutFragment : DaggerFragment() { @BindView(R.id.version) lateinit var version: TextView @@ -40,7 +40,7 @@ class AboutSettingsFragment : DaggerFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_about, container, false) + val view = inflater.inflate(R.layout.preferences_about, container, false) ButterKnife.bind(this, view) version.text = BuildConfig.VERSION_NAME diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragmentProvider.kt similarity index 59% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsFragmentProvider.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragmentProvider.kt index 87c2b85f9..1f05d0a60 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutSettingsFragmentProvider.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragmentProvider.kt @@ -4,7 +4,7 @@ import dagger.Module import dagger.android.ContributesAndroidInjector @Module -abstract class AboutSettingsFragmentProvider { +abstract class AboutFragmentProvider { @ContributesAndroidInjector - abstract fun bindAboutSettingsFragment(): AboutSettingsFragment + abstract fun bindAboutFragment(): AboutFragment } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt index 28c092fc8..c8a49d52c 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/LibraryAdapter.kt @@ -8,7 +8,7 @@ import android.widget.TextView import butterknife.BindView import butterknife.ButterKnife import de.kuschku.quasseldroid.R -import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseSettingsActivity +import de.kuschku.quasseldroid.ui.clientsettings.license.LicenseActivity import de.kuschku.quasseldroid.util.helper.visibleIf class LibraryAdapter(private val libraries: List<Library>) : @@ -39,9 +39,9 @@ class LibraryAdapter(private val libraries: List<Library>) : ButterKnife.bind(this, itemView) itemView.setOnClickListener { this.item?.run { - LicenseSettingsActivity.launch(itemView.context, - license_name = license.fullName, - license_text = license.text) + LicenseActivity.launch(itemView.context, + license_name = license.fullName, + license_text = license.text) } } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsFragmentProvider.kt deleted file mode 100644 index 237399cb3..000000000 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsFragmentProvider.kt +++ /dev/null @@ -1,10 +0,0 @@ -package de.kuschku.quasseldroid.ui.clientsettings.app - -import dagger.Module -import dagger.android.ContributesAndroidInjector - -@Module -abstract class AppSettingsFragmentProvider { - @ContributesAndroidInjector - abstract fun bindAppSettingsFragment(): AppSettingsFragment -} 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 new file mode 100644 index 000000000..af04881f2 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsActivity.kt @@ -0,0 +1,12 @@ +package de.kuschku.quasseldroid.ui.clientsettings.client + +import android.content.Context +import android.content.Intent +import de.kuschku.quasseldroid.util.ui.SettingsActivity + +class ClientSettingsActivity : SettingsActivity(ClientSettingsFragment()) { + companion object { + fun launch(context: Context) = context.startActivity(intent(context)) + fun intent(context: Context) = Intent(context, ClientSettingsActivity::class.java) + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt similarity index 74% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsFragment.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt index db3ce7a5a..2894d1923 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragment.kt @@ -1,4 +1,4 @@ -package de.kuschku.quasseldroid.ui.clientsettings.app +package de.kuschku.quasseldroid.ui.clientsettings.client import android.content.SharedPreferences import android.os.Bundle @@ -11,13 +11,14 @@ import android.view.MenuItem import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.Settings -import de.kuschku.quasseldroid.ui.clientsettings.about.AboutSettingsActivity -import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashSettingsActivity +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 javax.inject.Inject -class AppSettingsFragment : DaggerPreferenceFragmentCompat(), - SharedPreferences.OnSharedPreferenceChangeListener { +class ClientSettingsFragment : DaggerPreferenceFragmentCompat(), + SharedPreferences.OnSharedPreferenceChangeListener { @Inject lateinit var appearanceSettings: AppearanceSettings @@ -68,14 +69,18 @@ class AppSettingsFragment : DaggerPreferenceFragmentCompat(), } override fun onOptionsItemSelected(item: MenuItem?) = when (item?.itemId) { - R.id.action_about -> { - AboutSettingsActivity.launch(requireContext()) + R.id.action_certificates -> { + WhitelistActivity.launch(requireContext()) true } - R.id.action_crashes -> { - CrashSettingsActivity.launch(requireContext()) + R.id.action_crashes -> { + CrashActivity.launch(requireContext()) true } - else -> super.onOptionsItemSelected(item) + R.id.action_about -> { + AboutActivity.launch(requireContext()) + true + } + else -> super.onOptionsItemSelected(item) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragmentProvider.kt new file mode 100644 index 000000000..f7a0672ce --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/client/ClientSettingsFragmentProvider.kt @@ -0,0 +1,10 @@ +package de.kuschku.quasseldroid.ui.clientsettings.client + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +abstract class ClientSettingsFragmentProvider { + @ContributesAndroidInjector + abstract fun bindClientSettingsFragment(): ClientSettingsFragment +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashActivity.kt similarity index 63% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsActivity.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashActivity.kt index 6a17c61cc..e8d9992cf 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashActivity.kt @@ -4,9 +4,9 @@ import android.content.Context import android.content.Intent import de.kuschku.quasseldroid.util.ui.SettingsActivity -class CrashSettingsActivity : SettingsActivity(CrashSettingsFragment()) { +class CrashActivity : SettingsActivity(CrashFragment()) { companion object { fun launch(context: Context) = context.startActivity(intent(context)) - fun intent(context: Context) = Intent(context, CrashSettingsActivity::class.java) + fun intent(context: Context) = Intent(context, CrashActivity::class.java) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt similarity index 94% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsFragment.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt index 55f1cd5bf..2f00c2c5d 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt @@ -18,7 +18,7 @@ import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.util.helper.fromJson import java.io.File -class CrashSettingsFragment : DaggerFragment() { +class CrashFragment : DaggerFragment() { @BindView(R.id.list) lateinit var list: RecyclerView @@ -31,7 +31,7 @@ class CrashSettingsFragment : DaggerFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - handlerThread = HandlerThread("CrashSettings") + handlerThread = HandlerThread("Crash") handlerThread.start() handler = Handler(handlerThread.looper) } @@ -43,7 +43,7 @@ class CrashSettingsFragment : DaggerFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_crash, container, false) + val view = inflater.inflate(R.layout.preferences_crash, container, false) ButterKnife.bind(this, view) setHasOptionsMenu(true) diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragmentProvider.kt similarity index 60% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsFragmentProvider.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragmentProvider.kt index 8c54633c4..4e6b4c456 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashSettingsFragmentProvider.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragmentProvider.kt @@ -4,7 +4,7 @@ import dagger.Module import dagger.android.ContributesAndroidInjector @Module -abstract class CrashSettingsFragmentProvider { +abstract class CrashFragmentProvider { @ContributesAndroidInjector - abstract fun bindAppSettingsFragment(): CrashSettingsFragment + abstract fun bindClientSettingsFragment(): CrashFragment } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt similarity index 80% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsActivity.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt index 8b4d4b604..d514d01d1 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseActivity.kt @@ -5,7 +5,7 @@ import android.content.Intent import android.support.annotation.StringRes import de.kuschku.quasseldroid.util.ui.SettingsActivity -class LicenseSettingsActivity : SettingsActivity(LicenseSettingsFragment()) { +class LicenseActivity : SettingsActivity(LicenseFragment()) { companion object { fun launch( context: Context, @@ -17,7 +17,7 @@ class LicenseSettingsActivity : SettingsActivity(LicenseSettingsFragment()) { context: Context, license_name: String, @StringRes license_text: Int - ) = Intent(context, LicenseSettingsActivity::class.java).apply { + ) = Intent(context, LicenseActivity::class.java).apply { putExtra("license_name", license_name) putExtra("license_text", license_text) } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseFragment.kt similarity index 85% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsFragment.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseFragment.kt index a13da2823..c5fe5f15b 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseFragment.kt @@ -11,13 +11,13 @@ import butterknife.ButterKnife import dagger.android.support.DaggerFragment import de.kuschku.quasseldroid.R -class LicenseSettingsFragment : DaggerFragment() { +class LicenseFragment : DaggerFragment() { @BindView(R.id.text) lateinit var text: TextView override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_license, container, false) + val view = inflater.inflate(R.layout.preferences_license, container, false) ButterKnife.bind(this, view) val textResource = arguments?.getInt("license_text", 0) ?: 0 diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseFragmentProvider.kt similarity index 58% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsFragmentProvider.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseFragmentProvider.kt index c1f290046..930478f73 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseSettingsFragmentProvider.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/license/LicenseFragmentProvider.kt @@ -4,7 +4,7 @@ import dagger.Module import dagger.android.ContributesAndroidInjector @Module -abstract class LicenseSettingsFragmentProvider { +abstract class LicenseFragmentProvider { @ContributesAndroidInjector - abstract fun bindLicenseSettingsFragment(): LicenseSettingsFragment + abstract fun bindLicenseFragment(): LicenseFragment } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt new file mode 100644 index 000000000..fdf38f2d8 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/Whitelist.kt @@ -0,0 +1,8 @@ +package de.kuschku.quasseldroid.ui.clientsettings.whitelist + +import de.kuschku.quasseldroid.persistence.QuasselDatabase + +data class Whitelist( + val certificates: List<QuasselDatabase.SslValidityWhitelistEntry>, + val hostnames: List<QuasselDatabase.SslHostnameWhitelistEntry> +) diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistActivity.kt similarity index 51% rename from app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsActivity.kt rename to app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistActivity.kt index b42b38709..c420a4106 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/app/AppSettingsActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistActivity.kt @@ -1,12 +1,12 @@ -package de.kuschku.quasseldroid.ui.clientsettings.app +package de.kuschku.quasseldroid.ui.clientsettings.whitelist import android.content.Context import android.content.Intent import de.kuschku.quasseldroid.util.ui.SettingsActivity -class AppSettingsActivity : SettingsActivity(AppSettingsFragment()) { +class WhitelistActivity : SettingsActivity(WhitelistFragment()) { companion object { fun launch(context: Context) = context.startActivity(intent(context)) - fun intent(context: Context) = Intent(context, AppSettingsActivity::class.java) + fun intent(context: Context) = Intent(context, WhitelistActivity::class.java) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt new file mode 100644 index 000000000..3c408718c --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistCertificateAdapter.kt @@ -0,0 +1,97 @@ +package de.kuschku.quasseldroid.ui.clientsettings.whitelist + +import android.support.v7.widget.AppCompatImageButton +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.persistence.QuasselDatabase +import de.kuschku.quasseldroid.util.helper.visibleIf + +class WhitelistCertificateAdapter : + RecyclerView.Adapter<WhitelistCertificateAdapter.WhitelistItemViewHolder>() { + private var clickListener: ((QuasselDatabase.SslValidityWhitelistEntry) -> Unit)? = null + + fun setOnClickListener(listener: ((QuasselDatabase.SslValidityWhitelistEntry) -> Unit)?) { + clickListener = listener + } + + private val data = mutableListOf<QuasselDatabase.SslValidityWhitelistEntry>() + var list: List<QuasselDatabase.SslValidityWhitelistEntry> + get() = data + set(value) { + val length = data.size + data.clear() + notifyItemRangeRemoved(0, length) + data.addAll(value) + notifyItemRangeInserted(0, list.size) + } + + fun add(item: QuasselDatabase.SslValidityWhitelistEntry) { + val index = data.size + data.add(item) + notifyItemInserted(index) + } + + fun replace(index: Int, item: QuasselDatabase.SslValidityWhitelistEntry) { + data[index] = item + notifyItemChanged(index) + } + + fun indexOf(item: QuasselDatabase.SslValidityWhitelistEntry) = data.indexOf(item) + + fun remove(index: Int) { + data.removeAt(index) + notifyItemRemoved(index) + } + + fun remove(item: QuasselDatabase.SslValidityWhitelistEntry) = remove(indexOf(item)) + + override fun getItemCount() = data.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = WhitelistItemViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.preferences_whitelist_certificate_item, + parent, + false), + ::remove + ) + + override fun onBindViewHolder(holder: WhitelistItemViewHolder, position: Int) { + holder.bind(data[position]) + } + + class WhitelistItemViewHolder( + itemView: View, + clickListener: ((QuasselDatabase.SslValidityWhitelistEntry) -> Unit)? + ) : RecyclerView.ViewHolder(itemView) { + @BindView(R.id.fingerprint) + lateinit var fingerprint: TextView + + @BindView(R.id.ignore_date) + lateinit var ignoreDate: View + + @BindView(R.id.action_delete) + lateinit var delete: AppCompatImageButton + + private var item: QuasselDatabase.SslValidityWhitelistEntry? = null + + init { + ButterKnife.bind(this, itemView) + delete.setOnClickListener { + item?.let { + clickListener?.invoke(it) + } + } + } + + fun bind(item: QuasselDatabase.SslValidityWhitelistEntry) { + this.item = item + fingerprint.text = item.fingerprint + ignoreDate.visibleIf(item.ignoreDate) + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt new file mode 100644 index 000000000..14a0315b0 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragment.kt @@ -0,0 +1,99 @@ +package de.kuschku.quasseldroid.ui.clientsettings.whitelist + +import android.os.Bundle +import android.os.Handler +import android.os.HandlerThread +import android.support.v4.view.ViewCompat +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.persistence.QuasselDatabase +import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment +import javax.inject.Inject + +class WhitelistFragment : SettingsFragment(), SettingsFragment.Changeable, + SettingsFragment.Savable { + @BindView(R.id.certificate_whitelist) + lateinit var certificateList: RecyclerView + + @BindView(R.id.hostname_whitelist) + lateinit var hostnameList: RecyclerView + + @Inject + lateinit var database: QuasselDatabase + + private var whitelist: Whitelist? = null + + private lateinit var handlerThread: HandlerThread + private lateinit var handler: Handler + + private var certificateAdapter = WhitelistCertificateAdapter() + private var hostnameAdapter = WhitelistHostnameAdapter() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + handlerThread = HandlerThread("Crash") + handlerThread.start() + handler = Handler(handlerThread.looper) + } + + override fun onDestroy() { + super.onDestroy() + handlerThread.quit() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.preferences_whitelist, container, false) + ButterKnife.bind(this, view) + + setHasOptionsMenu(true) + + certificateList.layoutManager = LinearLayoutManager(context) + certificateList.adapter = certificateAdapter + certificateList.addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL)) + ViewCompat.setNestedScrollingEnabled(certificateList, false) + + hostnameList.layoutManager = LinearLayoutManager(context) + hostnameList.adapter = hostnameAdapter + hostnameList.addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL)) + ViewCompat.setNestedScrollingEnabled(hostnameList, false) + + handler.post { + whitelist = Whitelist(database.validityWhitelist().all(), database.hostnameWhitelist().all()) + whitelist?.let { + certificateAdapter.list = it.certificates + hostnameAdapter.list = it.hostnames + } + } + return view + } + + fun applyChanges() = Whitelist( + certificateAdapter.list, + hostnameAdapter.list + ) + + override fun onSave() = whitelist?.let { + val data = applyChanges() + handler.post { + database.runInTransaction { + for (item in it.certificates - data.certificates) { + database.validityWhitelist().delete(item.fingerprint) + } + for (item in it.hostnames - data.hostnames) { + database.hostnameWhitelist().delete(item.fingerprint, item.hostname) + } + } + } + true + } ?: false + + override fun hasChanged() = whitelist != applyChanges() +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragmentProvider.kt new file mode 100644 index 000000000..90ae41197 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistFragmentProvider.kt @@ -0,0 +1,10 @@ +package de.kuschku.quasseldroid.ui.clientsettings.whitelist + +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module +abstract class WhitelistFragmentProvider { + @ContributesAndroidInjector + abstract fun bindWhitelistFragment(): WhitelistFragment +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt new file mode 100644 index 000000000..569df654b --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/whitelist/WhitelistHostnameAdapter.kt @@ -0,0 +1,90 @@ +package de.kuschku.quasseldroid.ui.clientsettings.whitelist + +import android.support.v7.widget.AppCompatImageButton +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.persistence.QuasselDatabase + +class WhitelistHostnameAdapter : + RecyclerView.Adapter<WhitelistHostnameAdapter.WhitelistItemViewHolder>() { + private val data = mutableListOf<QuasselDatabase.SslHostnameWhitelistEntry>() + var list: List<QuasselDatabase.SslHostnameWhitelistEntry> + get() = data + set(value) { + val length = data.size + data.clear() + notifyItemRangeRemoved(0, length) + data.addAll(value) + notifyItemRangeInserted(0, list.size) + } + + fun add(item: QuasselDatabase.SslHostnameWhitelistEntry) { + val index = data.size + data.add(item) + notifyItemInserted(index) + } + + fun replace(index: Int, item: QuasselDatabase.SslHostnameWhitelistEntry) { + data[index] = item + notifyItemChanged(index) + } + + fun indexOf(item: QuasselDatabase.SslHostnameWhitelistEntry) = data.indexOf(item) + + fun remove(index: Int) { + data.removeAt(index) + notifyItemRemoved(index) + } + + fun remove(item: QuasselDatabase.SslHostnameWhitelistEntry) = remove(indexOf(item)) + + override fun getItemCount() = data.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = WhitelistItemViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.preferences_whitelist_hostname_item, + parent, + false), + ::remove + ) + + override fun onBindViewHolder(holder: WhitelistItemViewHolder, position: Int) { + holder.bind(data[position]) + } + + class WhitelistItemViewHolder( + itemView: View, + clickListener: ((QuasselDatabase.SslHostnameWhitelistEntry) -> Unit)? + ) : RecyclerView.ViewHolder(itemView) { + @BindView(R.id.hostname) + lateinit var hostname: TextView + + @BindView(R.id.fingerprint) + lateinit var fingerprint: TextView + + @BindView(R.id.action_delete) + lateinit var delete: AppCompatImageButton + + private var item: QuasselDatabase.SslHostnameWhitelistEntry? = null + + init { + ButterKnife.bind(this, itemView) + delete.setOnClickListener { + item?.let { + clickListener?.invoke(it) + } + } + } + + fun bind(item: QuasselDatabase.SslHostnameWhitelistEntry) { + this.item = item + hostname.text = item.hostname + fingerprint.text = item.fingerprint + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/SetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/SetupActivity.kt index 6eee73e76..370e27a00 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/SetupActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/SetupActivity.kt @@ -17,9 +17,10 @@ import butterknife.BindView import butterknife.ButterKnife import dagger.android.support.DaggerAppCompatActivity import de.kuschku.quasseldroid.R -import de.kuschku.quasseldroid.ui.clientsettings.about.AboutSettingsActivity -import de.kuschku.quasseldroid.ui.clientsettings.app.AppSettingsActivity -import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashSettingsActivity +import de.kuschku.quasseldroid.ui.clientsettings.about.AboutActivity +import de.kuschku.quasseldroid.ui.clientsettings.client.ClientSettingsActivity +import de.kuschku.quasseldroid.ui.clientsettings.crash.CrashActivity +import de.kuschku.quasseldroid.ui.clientsettings.whitelist.WhitelistActivity import de.kuschku.quasseldroid.util.helper.observeSticky import de.kuschku.quasseldroid.util.helper.or import de.kuschku.quasseldroid.util.helper.switchMap @@ -92,15 +93,19 @@ abstract class SetupActivity : DaggerAppCompatActivity() { menuView.setOnMenuItemClickListener { when (it.itemId) { R.id.action_client_settings -> { - AppSettingsActivity.launch(this) + ClientSettingsActivity.launch(this) + true + } + R.id.action_certificates -> { + WhitelistActivity.launch(this) true } R.id.action_crashes -> { - CrashSettingsActivity.launch(this) + CrashActivity.launch(this) true } R.id.action_about -> { - AboutSettingsActivity.launch(this) + AboutActivity.launch(this) true } else -> false diff --git a/app/src/main/res/layout-sw720dp/activity_settings.xml b/app/src/main/res/layout-sw720dp/activity_settings.xml index c1b350d69..43c3eeea2 100644 --- a/app/src/main/res/layout-sw720dp/activity_settings.xml +++ b/app/src/main/res/layout-sw720dp/activity_settings.xml @@ -41,7 +41,7 @@ android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" - tools:layout="@layout/fragment_about" /> + tools:layout="@layout/preferences_about" /> </android.support.v7.widget.CardView> </LinearLayout> diff --git a/app/src/main/res/layout/layout_editor.xml b/app/src/main/res/layout/layout_editor.xml index 54c2793af..3bd7eb0ef 100644 --- a/app/src/main/res/layout/layout_editor.xml +++ b/app/src/main/res/layout/layout_editor.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> @@ -51,12 +52,14 @@ android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:layout_gravity="top" + android:autoMirrored="true" android:background="?attr/selectableItemBackgroundBorderless" android:padding="12dp" android:scaleType="fitXY" app:layout_constraintEnd_toEndOf="parent" app:srcCompat="@drawable/ic_send" - app:tint="?attr/colorAccent" /> + app:tint="?attr/colorAccent" + tools:ignore="UnusedAttribute" /> <de.kuschku.quasseldroid.util.ui.AutoCompleteRecyclerView android:id="@+id/autocomplete_list" diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/preferences_about.xml similarity index 96% rename from app/src/main/res/layout/fragment_about.xml rename to app/src/main/res/layout/preferences_about.xml index 53c4d37b7..5e2048142 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/preferences_about.xml @@ -10,7 +10,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - <include layout="@layout/layout_about_header" /> + <include layout="@layout/preferences_about_header" /> <LinearLayout android:layout_width="match_parent" @@ -74,4 +74,4 @@ </LinearLayout> </LinearLayout> -</android.support.v4.widget.NestedScrollView> \ No newline at end of file +</android.support.v4.widget.NestedScrollView> diff --git a/app/src/main/res/layout/layout_about_header.xml b/app/src/main/res/layout/preferences_about_header.xml similarity index 100% rename from app/src/main/res/layout/layout_about_header.xml rename to app/src/main/res/layout/preferences_about_header.xml diff --git a/app/src/main/res/layout/fragment_crash.xml b/app/src/main/res/layout/preferences_crash.xml similarity index 100% rename from app/src/main/res/layout/fragment_crash.xml rename to app/src/main/res/layout/preferences_crash.xml diff --git a/app/src/main/res/layout/fragment_license.xml b/app/src/main/res/layout/preferences_license.xml similarity index 100% rename from app/src/main/res/layout/fragment_license.xml rename to app/src/main/res/layout/preferences_license.xml diff --git a/app/src/main/res/layout/preferences_whitelist.xml b/app/src/main/res/layout/preferences_whitelist.xml new file mode 100644 index 000000000..a2071bd68 --- /dev/null +++ b/app/src/main/res/layout/preferences_whitelist.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <TextView + style="@style/Widget.Subhead" + android:text="@string/label_whitelist_certificates" /> + + <android.support.v7.widget.RecyclerView + android:id="@+id/certificate_whitelist" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="2dp" + android:paddingRight="2dp" + tools:itemCount="2" + tools:listitem="@layout/preferences_whitelist_certificate_item" /> + + <TextView + style="@style/Widget.Subhead" + android:text="@string/label_whitelist_hostnames" /> + + <android.support.v7.widget.RecyclerView + android:id="@+id/hostname_whitelist" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="2dp" + android:paddingRight="2dp" + tools:itemCount="3" + tools:listitem="@layout/preferences_whitelist_hostname_item" /> + + </LinearLayout> +</android.support.v4.widget.NestedScrollView> diff --git a/app/src/main/res/layout/preferences_whitelist_certificate_item.xml b/app/src/main/res/layout/preferences_whitelist_certificate_item.xml new file mode 100644 index 000000000..d4ea0d821 --- /dev/null +++ b/app/src/main/res/layout/preferences_whitelist_certificate_item.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:orientation="horizontal" + tools:showIn="@layout/preferences_whitelist"> + + <LinearLayout + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:orientation="vertical" + android:paddingBottom="16dp" + android:paddingEnd="0dip" + android:paddingLeft="?listPreferredItemPaddingLeft" + android:paddingRight="0dip" + android:paddingStart="?listPreferredItemPaddingLeft" + android:paddingTop="16dp"> + + <TextView + android:id="@+id/fingerprint" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:textAppearanceMedium" + android:textColor="?colorTextPrimary" + android:textSize="16sp" + tools:text="65:F9:0D:04:8A:7B:4F:D8:C8:D8:75:8D:EC:48:8C:F2:96:86:00:44" /> + + <TextView + android:id="@+id/ignore_date" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/label_whitelist_ignore_date" + android:textAppearance="?textAppearanceListItemSecondary" + android:textColor="?colorTextSecondary" /> + + </LinearLayout> + + <android.support.v7.widget.AppCompatImageButton + android:id="@+id/action_delete" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_vertical" + android:background="?selectableItemBackgroundBorderless" + android:paddingEnd="?listPreferredItemPaddingRight" + android:paddingLeft="32dp" + android:paddingRight="?listPreferredItemPaddingRight" + android:paddingStart="32dp" + app:srcCompat="@drawable/ic_delete" + app:tint="?colorTextSecondary" /> +</LinearLayout> diff --git a/app/src/main/res/layout/preferences_whitelist_hostname_item.xml b/app/src/main/res/layout/preferences_whitelist_hostname_item.xml new file mode 100644 index 000000000..f6ffa942d --- /dev/null +++ b/app/src/main/res/layout/preferences_whitelist_hostname_item.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:orientation="horizontal" + tools:showIn="@layout/preferences_whitelist"> + + <LinearLayout + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:orientation="vertical" + android:paddingBottom="16dp" + android:paddingEnd="0dip" + android:paddingLeft="?listPreferredItemPaddingLeft" + android:paddingRight="0dip" + android:paddingStart="?listPreferredItemPaddingLeft" + android:paddingTop="16dp"> + + <TextView + android:id="@+id/hostname" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:textAppearanceMedium" + android:textColor="?colorTextPrimary" + android:textSize="16sp" + tools:text="www.google.com" /> + + <TextView + android:id="@+id/fingerprint" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?textAppearanceListItemSecondary" + android:textColor="?colorTextSecondary" + tools:text="65:F9:0D:04:8A:7B:4F:D8:C8:D8:75:8D:EC:48:8C:F2:96:86:00:44" /> + + </LinearLayout> + + <android.support.v7.widget.AppCompatImageButton + android:id="@+id/action_delete" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_vertical" + android:background="?selectableItemBackgroundBorderless" + android:paddingEnd="?listPreferredItemPaddingRight" + android:paddingLeft="32dp" + android:paddingRight="?listPreferredItemPaddingRight" + android:paddingStart="32dp" + app:srcCompat="@drawable/ic_delete" + app:tint="?colorTextSecondary" /> +</LinearLayout> diff --git a/app/src/main/res/layout/widget_contributor.xml b/app/src/main/res/layout/widget_contributor.xml index 9df93a33b..de699de65 100644 --- a/app/src/main/res/layout/widget_contributor.xml +++ b/app/src/main/res/layout/widget_contributor.xml @@ -11,7 +11,7 @@ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" android:paddingRight="?android:attr/listPreferredItemPaddingRight" android:paddingStart="?android:attr/listPreferredItemPaddingLeft" - tools:showIn="@layout/fragment_about"> + tools:showIn="@layout/preferences_about"> <LinearLayout android:layout_width="match_parent" diff --git a/app/src/main/res/layout/widget_library.xml b/app/src/main/res/layout/widget_library.xml index 827a187eb..7ad732fc8 100644 --- a/app/src/main/res/layout/widget_library.xml +++ b/app/src/main/res/layout/widget_library.xml @@ -11,7 +11,7 @@ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" android:paddingRight="?android:attr/listPreferredItemPaddingRight" android:paddingStart="?android:attr/listPreferredItemPaddingLeft" - tools:showIn="@layout/fragment_about"> + tools:showIn="@layout/preferences_about"> <LinearLayout android:layout_width="match_parent" diff --git a/app/src/main/res/menu/activity_settings.xml b/app/src/main/res/menu/activity_settings.xml index 391c758fa..85f5addf8 100644 --- a/app/src/main/res/menu/activity_settings.xml +++ b/app/src/main/res/menu/activity_settings.xml @@ -1,5 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/action_certificates" + android:title="@string/label_certificates" /> <item android:id="@+id/action_crashes" android:title="@string/label_crashes" /> diff --git a/app/src/main/res/menu/activity_setup.xml b/app/src/main/res/menu/activity_setup.xml index 8e26096af..90461b687 100644 --- a/app/src/main/res/menu/activity_setup.xml +++ b/app/src/main/res/menu/activity_setup.xml @@ -3,6 +3,9 @@ <item android:id="@+id/action_client_settings" android:title="@string/label_settings_client" /> + <item + android:id="@+id/action_certificates" + android:title="@string/label_certificates" /> <item android:id="@+id/action_crashes" android:title="@string/label_crashes" /> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 651de5611..c49cff8a1 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -13,6 +13,7 @@ <string name="label_buffer_name">Chatname</string> <string name="label_cancel">Abbrechen</string> <string name="label_update_user_password">Benutzernamen/Passwort ändern</string> + <string name="label_certificates">Zertifikate</string> <string name="label_close">Schließen</string> <string name="label_colors_custom">Anpassen</string> <string name="label_colors_mirc">mIRC</string> @@ -74,6 +75,9 @@ <string name="label_unhide">Nicht mehr ausblenden</string> <string name="label_website">Webseite</string> <string name="label_whitelist">Ignorieren</string> + <string name="label_whitelist_ignore_date">Verfallsdatum wird ignoriert für dieses Zertifikat</string> + <string name="label_whitelist_certificates">Zertifikate</string> + <string name="label_whitelist_hostnames">Hosts</string> <string name="label_who">Who</string> <string name="label_who_long">Informationen aller Nutzer aktualisieren</string> <string name="label_whois">Whois</string> diff --git a/app/src/main/res/values-de/strings_error.xml b/app/src/main/res/values-de/strings_error.xml index b18e43f92..0af607f1e 100644 --- a/app/src/main/res/values-de/strings_error.xml +++ b/app/src/main/res/values-de/strings_error.xml @@ -7,12 +7,18 @@ <string name="label_error_certificate_no_certificate">Kein Zertifikat verfügbar</string> <string name="label_error_certificate_no_hostname">Kein Rechnername verfügbar</string> <string name="label_error_certificate_invalid"><![CDATA[ - <p>Das Zertifikat mit Fingerabdruck <code>%1$s</code> ist nur gültig im Zeitraum von %2$s bis %3$s</p> + <p>Das Zertifikat mit Fingerabdruck<br/> + <code>%1$s</code><br/> + ist nur gültig im Zeitraum von %2$s bis %3$s</p> ]]></string> <string name="label_error_certificate_untrusted"><![CDATA[ - <p>Das Zertifikat mit Fingerabdruck <code>%1$s</code> ist nicht vertrauenswürdig.</p> + <p>Das Zertifikat mit Fingerabdruck<br/> + <code>%1$s</code><br/> + ist nicht vertrauenswürdig.</p> ]]></string> <string name="label_error_certificate_no_match"><![CDATA[ - <p>Das Zertifikat mit Fingerabdruck <code>%1$s</code> ist nicht gültig für %2$s.</p> + <p>Das Zertifikat mit Fingerabdruck<br/> + <code>%1$s</code><br/> + ist nicht gültig für %2$s.</p> ]]></string> </resources> diff --git a/app/src/main/res/values-v17/styles_widgets.xml b/app/src/main/res/values-v17/styles_widgets.xml index b4027250e..eac3b62a0 100644 --- a/app/src/main/res/values-v17/styles_widgets.xml +++ b/app/src/main/res/values-v17/styles_widgets.xml @@ -88,4 +88,18 @@ <item name="android:paddingStart">?android:attr/listPreferredItemPaddingLeft</item> <item name="android:paddingTop">16dp</item> </style> + + <style name="Widget.Subhead" parent=""> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:gravity">center_vertical</item> + <item name="android:minHeight">?listPreferredItemHeightSmall</item> + <item name="android:paddingEnd">?listPreferredItemPaddingRight</item> + <item name="android:paddingLeft">?listPreferredItemPaddingLeft</item> + <item name="android:paddingRight">?listPreferredItemPaddingRight</item> + <item name="android:paddingStart">?listPreferredItemPaddingLeft</item> + <item name="android:textColor">?colorAccent</item> + <item name="android:textSize">14sp</item> + <item name="android:textStyle">bold</item> + </style> </resources> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 97b10b2f9..fa55b8daa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,6 +13,7 @@ <string name="label_buffer_name">Buffer Name</string> <string name="label_cancel">Cancel</string> <string name="label_update_user_password">Update User/Password</string> + <string name="label_certificates">Certificates</string> <string name="label_close">Close</string> <string name="label_colors_custom">Custom</string> <string name="label_colors_mirc">mIRC</string> @@ -74,6 +75,9 @@ <string name="label_unhide">Make Visible</string> <string name="label_website">Website</string> <string name="label_whitelist">Ignore</string> + <string name="label_whitelist_ignore_date">Expiration date is ignored for this certificate</string> + <string name="label_whitelist_certificates">Certificates</string> + <string name="label_whitelist_hostnames">Hosts</string> <string name="label_who">Who</string> <string name="label_who_long">Update user information of all users</string> <string name="label_whois">Whois</string> diff --git a/app/src/main/res/values/strings_error.xml b/app/src/main/res/values/strings_error.xml index 4e9bdca3a..9d287180b 100644 --- a/app/src/main/res/values/strings_error.xml +++ b/app/src/main/res/values/strings_error.xml @@ -7,12 +7,17 @@ <string name="label_error_certificate_no_certificate">No certificate available</string> <string name="label_error_certificate_no_hostname">No hostname available</string> <string name="label_error_certificate_invalid"><![CDATA[ - <p>The certificate <code>%1$s</code> is only valid from %2$s to %3$s</p> + <p>The certificate with fingerprint<br/> + <code>%1$s</code> is only valid from %2$s to %3$s</p> ]]></string> <string name="label_error_certificate_untrusted"><![CDATA[ - <p>The certificate <code>%1$s</code> is not trusted.</p> + <p>The certificate with fingerprint<br/> + <code>%1$s</code><br/> + is not trusted.</p> ]]></string> <string name="label_error_certificate_no_match"><![CDATA[ - <p>The certificate <code>%1$s</code> is not valid for %2$s.</p> + <p>The certificate with fingerprint<br/> + <code>%1$s</code><br/> + is not valid for %2$s.</p> ]]></string> </resources> diff --git a/app/src/main/res/values/styles_widgets.xml b/app/src/main/res/values/styles_widgets.xml index 6d8a4743f..6c51192ce 100644 --- a/app/src/main/res/values/styles_widgets.xml +++ b/app/src/main/res/values/styles_widgets.xml @@ -235,6 +235,18 @@ <item name="android:textColor">?colorTextSecondary</item> </style> + <style name="Widget.Subhead" parent=""> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:gravity">center_vertical</item> + <item name="android:minHeight">?listPreferredItemHeightSmall</item> + <item name="android:paddingLeft">?listPreferredItemPaddingLeft</item> + <item name="android:paddingRight">?listPreferredItemPaddingRight</item> + <item name="android:textColor">?colorAccent</item> + <item name="android:textSize">14sp</item> + <item name="android:textStyle">bold</item> + </style> + <!-- NavigationDrawerLayout --> <declare-styleable name="NavigationDrawerLayout"> <attr name="insetBackground" /> diff --git a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt index 9adb12b36..966985d46 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt @@ -10,6 +10,7 @@ import de.kuschku.libquassel.util.compatibility.LoggingHandler import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log import de.kuschku.libquassel.util.helpers.or import io.reactivex.BackpressureStrategy +import io.reactivex.Flowable import io.reactivex.Observable import io.reactivex.functions.BiFunction import io.reactivex.subjects.BehaviorSubject @@ -42,11 +43,14 @@ class SessionManager( else lastSession } - val error: Observable<Error> + + var hasErrored: Boolean = false + private set + + val error: Flowable<Error> get() = inProgressSession .toFlowable(BackpressureStrategy.LATEST) .switchMap(ISession::error) - .toObservable() val connectionProgress: Observable<Triple<ConnectionState, Int, Int>> = Observable.combineLatest( state, initStatus, @@ -63,6 +67,10 @@ class SessionManager( } } + error.subscribe { + hasErrored = true + } + // This should preload them Invokers } @@ -90,6 +98,7 @@ class SessionManager( lastAddress = address lastUserData = userData lastShouldReconnect = shouldReconnect + hasErrored = false inProgressSession.onNext( Session( clientData, diff --git a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt index d76b9060f..4761d606e 100644 --- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt +++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt @@ -161,6 +161,12 @@ abstract class QuasselDatabase : RoomDatabase() { @Query("SELECT * FROM ssl_validity_whitelist WHERE fingerprint = :fingerprint") fun find(fingerprint: String): SslValidityWhitelistEntry? + + @Query("DELETE FROM ssl_validity_whitelist WHERE fingerprint = :fingerprint") + fun delete(fingerprint: String) + + @Query("DELETE FROM ssl_validity_whitelist") + fun clear() } @Entity(tableName = "ssl_hostname_whitelist", primaryKeys = ["fingerprint", "hostname"]) @@ -179,6 +185,12 @@ abstract class QuasselDatabase : RoomDatabase() { @Query("SELECT * FROM ssl_hostname_whitelist WHERE fingerprint = :fingerprint AND hostname = :hostname") fun find(fingerprint: String, hostname: String): SslHostnameWhitelistEntry? + + @Query("DELETE FROM ssl_hostname_whitelist WHERE fingerprint = :fingerprint AND hostname = :hostname") + fun delete(fingerprint: String, hostname: String) + + @Query("DELETE FROM ssl_hostname_whitelist") + fun clear() } object Creator { diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt index eda7456ad..8a3e7d08e 100644 --- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt +++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt @@ -18,6 +18,8 @@ import de.kuschku.libquassel.util.helpers.* import de.kuschku.libquassel.util.irc.IrcCaseMappers import de.kuschku.quasseldroid.util.helper.combineLatest import de.kuschku.quasseldroid.viewmodel.data.* +import io.reactivex.BackpressureStrategy +import io.reactivex.Flowable import io.reactivex.Observable import io.reactivex.subjects.BehaviorSubject import java.util.concurrent.TimeUnit @@ -65,7 +67,9 @@ class QuasselViewModel : ViewModel() { } } - val errors = sessionManager.mapSwitchMap(SessionManager::error) + val errors = sessionManager.toFlowable(BackpressureStrategy.LATEST).switchMap { + it.orNull()?.error ?: Flowable.empty() + } val networkConfig = session.mapMapNullable(ISession::networkConfig) -- GitLab