From e411ea5a63c41614ef5b0f59ec808d288b4ee861 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Wed, 18 Apr 2018 20:31:46 +0200
Subject: [PATCH] Allow full functionality for joining networks

---
 .../chat/buffers/BufferViewConfigFragment.kt  | 19 ++++-
 .../quasseldroid/util/ui/SettingsActivity.kt  |  4 +-
 app/src/main/res/menu/context_buffer.xml      |  5 +-
 app/src/main/res/values-de/strings.xml        |  1 +
 app/src/main/res/values/strings.xml           |  1 +
 .../persistence/QuasselDatabase.kt            | 36 ++++++++-
 .../viewmodel/QuasselViewModel.kt             | 74 ++++++++++++++++---
 7 files changed, 122 insertions(+), 18 deletions(-)

diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
index 236aa7b55..dd287dadb 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt
@@ -22,6 +22,7 @@ import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.persistence.QuasselDatabase
 import de.kuschku.quasseldroid.settings.AppearanceSettings
 import de.kuschku.quasseldroid.settings.MessageSettings
+import de.kuschku.quasseldroid.ui.coresettings.network.NetworkEditActivity
 import de.kuschku.quasseldroid.util.helper.combineLatest
 import de.kuschku.quasseldroid.util.helper.styledAttributes
 import de.kuschku.quasseldroid.util.helper.toLiveData
@@ -68,6 +69,13 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
 
       return if (info != null && session != null) {
         when (item?.itemId) {
+          R.id.action_configure  -> {
+            network?.let {
+              NetworkEditActivity.launch(requireContext(), network = it.networkId())
+            }
+            actionMode?.finish()
+            true
+          }
           R.id.action_connect    -> {
             network?.requestConnect()
             actionMode?.finish()
@@ -294,6 +302,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
         val menu = actionMode?.menu
         if (menu != null) {
           val allActions = setOf(
+            R.id.action_configure,
             R.id.action_connect,
             R.id.action_disconnect,
             R.id.action_join,
@@ -323,10 +332,14 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
           val availableActions = when (buffer.info?.type?.enabledValues()?.firstOrNull()) {
             Buffer_Type.StatusBuffer  -> {
               when (buffer.connectionState) {
-                INetwork.ConnectionState.Disconnected -> setOf(R.id.action_connect)
-                INetwork.ConnectionState.Initialized  -> setOf(R.id.action_disconnect)
+                INetwork.ConnectionState.Disconnected -> setOf(
+                  R.id.action_configure, R.id.action_connect
+                )
+                INetwork.ConnectionState.Initialized  -> setOf(
+                  R.id.action_configure, R.id.action_disconnect
+                )
                 else                                  -> setOf(
-                  R.id.action_connect, R.id.action_disconnect
+                  R.id.action_configure, R.id.action_connect, R.id.action_disconnect
                 )
               }
             }
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt
index 06d18039d..91725f7df 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/ui/SettingsActivity.kt
@@ -2,7 +2,6 @@ package de.kuschku.quasseldroid.util.ui
 
 import android.os.Bundle
 import android.support.v4.app.Fragment
-import android.support.v4.app.NavUtils
 import android.support.v7.widget.Toolbar
 import android.view.MenuItem
 import butterknife.BindView
@@ -68,7 +67,8 @@ abstract class SettingsActivity(private val fragment: Fragment? = null) : Servic
         if (supportParentActivityIntent == null) {
           super.onBackPressed()
         } else {
-          NavUtils.navigateUpFromSameTask(this)
+          startActivity(supportParentActivityIntent)
+          finish()
         }
       }
       true
diff --git a/app/src/main/res/menu/context_buffer.xml b/app/src/main/res/menu/context_buffer.xml
index 246eb68ef..a5c05a243 100644
--- a/app/src/main/res/menu/context_buffer.xml
+++ b/app/src/main/res/menu/context_buffer.xml
@@ -1,6 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
+  <item
+    android:id="@+id/action_configure"
+    android:title="@string/label_configure" />
   <item
     android:id="@+id/action_connect"
     android:title="@string/label_connect" />
@@ -31,4 +34,4 @@
     android:id="@+id/action_hide_perm"
     android:title="@string/label_hide_perm"
     app:showAsAction="never" />
-</menu>
\ No newline at end of file
+</menu>
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 09415fbd4..8052c0cc1 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -15,6 +15,7 @@
   <string name="label_close">Schließen</string>
   <string name="label_colors_custom">Anpassen</string>
   <string name="label_colors_mirc">mIRC</string>
+  <string name="label_configure">Konfigurieren</string>
   <string name="label_connect">Verbinden</string>
   <string name="label_contributors">Mitwirkende</string>
   <string name="label_copy">Kopieren</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index cb8bdcf66..1d1d3f458 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -15,6 +15,7 @@
   <string name="label_close">Close</string>
   <string name="label_colors_custom">Custom</string>
   <string name="label_colors_mirc">mIRC</string>
+  <string name="label_configure">Configure</string>
   <string name="label_connect">Connect</string>
   <string name="label_contributors">Contributors</string>
   <string name="label_copy">Copy</string>
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 0902d97fe..9ba9c3abf 100644
--- a/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
+++ b/persistence/src/main/java/de/kuschku/quasseldroid/persistence/QuasselDatabase.kt
@@ -10,16 +10,16 @@ import android.support.annotation.IntRange
 import de.kuschku.libquassel.protocol.Message_Flag
 import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.protocol.MsgId
-import de.kuschku.quasseldroid.persistence.QuasselDatabase.DatabaseMessage
-import de.kuschku.quasseldroid.persistence.QuasselDatabase.Filtered
+import de.kuschku.quasseldroid.persistence.QuasselDatabase.*
 import io.reactivex.Flowable
 import org.threeten.bp.Instant
 
-@Database(entities = [DatabaseMessage::class, Filtered::class], version = 8)
+@Database(entities = [DatabaseMessage::class, Filtered::class, SslException::class], version = 9)
 @TypeConverters(DatabaseMessage.MessageTypeConverters::class)
 abstract class QuasselDatabase : RoomDatabase() {
   abstract fun message(): MessageDao
   abstract fun filtered(): FilteredDao
+  abstract fun sslExceptions(): SslExceptionDao
 
   @Entity(tableName = "message", indices = [Index("bufferId"), Index("ignored")])
   data class DatabaseMessage(
@@ -142,6 +142,31 @@ abstract class QuasselDatabase : RoomDatabase() {
     fun clear(accountId: Long, bufferId: Int)
   }
 
+  @Entity(tableName = "ssl_exception", primaryKeys = ["accountId", "certificateFingerprint"])
+  data class SslException(
+    var accountId: Long,
+    var certificateFingerprint: String,
+    var ignoreValidityDate: Boolean
+  )
+
+  @Dao
+  interface SslExceptionDao {
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun save(vararg entities: SslException)
+
+    @Query("SELECT * FROM ssl_exception WHERE accountId = :accountId AND certificateFingerprint = :certificateFingerprint")
+    fun all(accountId: Long, certificateFingerprint: String): List<SslException>
+
+    @Query("DELETE FROM ssl_exception")
+    fun clear()
+
+    @Query("DELETE FROM ssl_exception WHERE accountId = :accountId")
+    fun clear(accountId: Long)
+
+    @Query("DELETE FROM ssl_exception WHERE accountId = :accountId AND certificateFingerprint = :certificateFingerprint")
+    fun clear(accountId: Long, certificateFingerprint: String)
+  }
+
   object Creator {
     private var database: QuasselDatabase? = null
 
@@ -193,6 +218,11 @@ abstract class QuasselDatabase : RoomDatabase() {
                   database.execSQL("CREATE INDEX index_message_bufferId ON message(bufferId);")
                   database.execSQL("CREATE INDEX index_message_ignored ON message(ignored);")
                 }
+              },
+              object : Migration(8, 9) {
+                override fun migrate(database: SupportSQLiteDatabase) {
+                  database.execSQL("create table ssl_exception (accountId INTEGER not null, certificateFingerprint TEXT not null, ignoreValidityDate INTEGER not null, primary key(accountId, certificateFingerprint));")
+                }
               }
             ).build()
           }
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 8e8e54401..d9a4ce4e9 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt
@@ -1,10 +1,7 @@
 package de.kuschku.quasseldroid.viewmodel
 
 import android.arch.lifecycle.ViewModel
-import de.kuschku.libquassel.protocol.BufferId
-import de.kuschku.libquassel.protocol.Buffer_Type
-import de.kuschku.libquassel.protocol.MsgId
-import de.kuschku.libquassel.protocol.NetworkId
+import de.kuschku.libquassel.protocol.*
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
 import de.kuschku.libquassel.quassel.syncables.IrcChannel
@@ -248,7 +245,15 @@ class QuasselViewModel : ViewModel() {
               BufferHiddenState.VISIBLE
           }
 
-          val info = bufferSyncer.bufferInfo(buffer)
+          val info = if (buffer < 0) networks[-buffer]?.let {
+            BufferInfo(
+              bufferId = buffer,
+              networkId = it.networkId(),
+              groupId = 0,
+              bufferName = it.networkName(),
+              type = Buffer_Type.of(Buffer_Type.StatusBuffer)
+            )
+          } else bufferSyncer.bufferInfo(buffer)
           if (info != null) {
             val network = networks[info.networkId]
             when (info.type.enabledValues().firstOrNull()) {
@@ -308,7 +313,7 @@ class QuasselViewModel : ViewModel() {
                       currentConfig.networkId() <= 0 || currentConfig.networkId() == it.networkId
                     }.filter {
                       (currentConfig.allowedBufferTypes() and it.type).isNotEmpty() ||
-                      it.type.hasFlag(Buffer_Type.StatusBuffer)
+                      (it.type.hasFlag(Buffer_Type.StatusBuffer) && currentConfig.networkId() < 0)
                     }.mapNotNull {
                       val network = networks[it.networkId]
                       if (network == null) {
@@ -396,13 +401,62 @@ class QuasselViewModel : ViewModel() {
                       }
                     }
 
+                  fun missingStatusBuffers(
+                    list: Collection<BufferId>): Sequence<Observable<BufferProps>?> {
+                    val totalNetworks = networks.keys
+                    val wantedNetworks = if (currentConfig.networkId() <= 0) totalNetworks
+                    else listOf(currentConfig.networkId())
+
+                    val availableNetworks = list.asSequence().mapNotNull { id ->
+                      bufferSyncer.bufferInfo(id)
+                    }.filter {
+                      it.type.hasFlag(Buffer_Type.StatusBuffer)
+                    }.map {
+                      it.networkId
+                    }
+
+                    val missingNetworks = wantedNetworks - availableNetworks
+
+                    return missingNetworks.asSequence().filter {
+                      currentConfig.networkId() <= 0 || currentConfig.networkId() == it
+                    }.filter {
+                      currentConfig.allowedBufferTypes().hasFlag(Buffer_Type.StatusBuffer)
+                    }.mapNotNull {
+                      networks[it]
+                    }.filter {
+                      !config.hideInactiveNetworks() || it.isConnected()
+                    }.map<Network, Observable<BufferProps>?> { network ->
+                      network.liveNetworkInfo().switchMap { networkInfo ->
+                        network.live_connectionState.map {
+                          BufferProps(
+                            info = BufferInfo(
+                              bufferId = -networkInfo.networkId,
+                              networkId = networkInfo.networkId,
+                              groupId = 0,
+                              bufferName = networkInfo.networkName,
+                              type = Buffer_Type.of(Buffer_Type.StatusBuffer)
+                            ),
+                            network = networkInfo,
+                            bufferStatus = BufferStatus.OFFLINE,
+                            description = "",
+                            activity = Message_Type.of(),
+                            highlights = 0,
+                            hiddenState = BufferHiddenState.VISIBLE
+                          )
+                        }
+                      }
+                    }
+                  }
+
                   bufferSyncer.liveBufferInfos().switchMap {
                     val buffers = if (showHidden) {
                       transformIds(ids, BufferHiddenState.VISIBLE) +
                       transformIds(temp - ids, BufferHiddenState.HIDDEN_TEMPORARY) +
-                      transformIds(perm - temp - ids, BufferHiddenState.HIDDEN_PERMANENT)
+                      transformIds(perm - temp - ids, BufferHiddenState.HIDDEN_PERMANENT) +
+                      missingStatusBuffers(ids + temp + perm)
                     } else {
-                      transformIds(ids.distinct(), BufferHiddenState.VISIBLE)
+                      transformIds(ids, BufferHiddenState.VISIBLE) +
+                      missingStatusBuffers(ids)
                     }
 
                     combineLatest<BufferProps>(buffers.toList()).map { list ->
@@ -417,7 +471,9 @@ class QuasselViewModel : ViewModel() {
                             it.sortedBy { IrcCaseMappers.unicode.toLowerCaseNullable(it.info.bufferName) }
                               .sortedByDescending { it.hiddenState == BufferHiddenState.VISIBLE }
                           else it
-                        }.distinctBy { it.info.bufferId }.toList()
+                        }.distinctBy {
+                          it.info.bufferId
+                        }.toList()
                       )
                     }
                   }
-- 
GitLab