From a0b1eda799df030e813a5df67ca6a0211846799e Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sun, 8 Apr 2018 23:54:58 +0200
Subject: [PATCH] Implement topic editing

---
 app/src/main/AndroidManifest.xml              |   6 +
 .../quasseldroid/dagger/ActivityModule.kt     |   5 +
 .../quasseldroid/ui/chat/ToolbarFragment.kt   |   5 +-
 .../ui/chat/info/InfoDescriptor.kt            |   3 +-
 .../quasseldroid/ui/chat/info/InfoFragment.kt |  13 +-
 .../ui/chat/input/ChatlineFragment.kt         |   2 +-
 .../ui/chat/nicks/NickListFragment.kt         |  24 ++--
 .../ui/chat/topic/TopicActivity.kt            |   5 +
 .../ui/chat/topic/TopicFragment.kt            | 115 ++++++++++++++++++
 .../ui/chat/topic/TopicFragmentProvider.kt    |  10 ++
 app/src/main/res/layout/fragment_topic.xml    |  48 ++++++++
 app/src/main/res/layout/layout_editor.xml     |   2 +-
 app/src/main/res/values-de/strings.xml        |   4 +-
 app/src/main/res/values/strings.xml           |   4 +-
 14 files changed, 225 insertions(+), 21 deletions(-)
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicActivity.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragment.kt
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragmentProvider.kt
 create mode 100644 app/src/main/res/layout/fragment_topic.xml

diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7b23fbd97..a092edb2e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -41,6 +41,12 @@
       android:label="@string/label_details"
       android:parentActivityName=".ui.chat.ChatActivity"
       android:windowSoftInputMode="adjustResize" />
+    <activity
+      android:name=".ui.chat.topic.TopicActivity"
+      android:exported="false"
+      android:label="@string/label_topic"
+      android:parentActivityName=".ui.chat.info.InfoActivity"
+      android:windowSoftInputMode="adjustResize" />
 
     <!-- Client Settings -->
     <activity
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 5fa67e3b4..193c77612 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/dagger/ActivityModule.kt
@@ -8,6 +8,8 @@ import de.kuschku.quasseldroid.ui.chat.ChatActivityModule
 import de.kuschku.quasseldroid.ui.chat.ChatFragmentProvider
 import de.kuschku.quasseldroid.ui.chat.info.InfoActivity
 import de.kuschku.quasseldroid.ui.chat.info.InfoFragmentProvider
+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
@@ -38,6 +40,9 @@ abstract class ActivityModule {
   @ContributesAndroidInjector(modules = [InfoFragmentProvider::class])
   abstract fun bindInfoActivity(): InfoActivity
 
+  @ContributesAndroidInjector(modules = [TopicFragmentProvider::class])
+  abstract fun bindTopicActivity(): TopicActivity
+
   @ContributesAndroidInjector(modules = [AppSettingsFragmentProvider::class])
   abstract fun bindAppSettingsActivity(): AppSettingsActivity
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt
index ca7cd350e..7f0e96b92 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt
@@ -103,15 +103,18 @@ class ToolbarFragment : ServiceBoundFragment() {
           BufferInfo.Type.QueryBuffer.toInt()   -> InfoDescriptor(
             type = InfoType.User,
             nick = info.bufferName,
+            buffer = info.bufferId,
             network = info.networkId
           )
           BufferInfo.Type.ChannelBuffer.toInt() -> InfoDescriptor(
             type = InfoType.Channel,
             channel = info.bufferName,
+            buffer = info.bufferId,
             network = info.networkId
           )
           BufferInfo.Type.StatusBuffer.toInt()  -> InfoDescriptor(
             type = InfoType.Network,
+            buffer = info.bufferId,
             network = info.networkId
           )
           else                                  -> null
@@ -129,4 +132,4 @@ class ToolbarFragment : ServiceBoundFragment() {
   private fun colorizeDescription(description: String?) = ircFormatDeserializer.formatString(
     requireContext(), description, messageSettings.colorizeMirc
   )
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoDescriptor.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoDescriptor.kt
index ad5328320..95c5a772e 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoDescriptor.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoDescriptor.kt
@@ -6,5 +6,6 @@ data class InfoDescriptor(
   val type: InfoType,
   val nick: String? = null,
   val channel: String? = null,
+  val buffer: Int,
   val network: Int
-) : Serializable
\ No newline at end of file
+) : Serializable
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoFragment.kt
index acb8d8c7b..4d2df684d 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/InfoFragment.kt
@@ -1,18 +1,19 @@
 package de.kuschku.quasseldroid.ui.chat.info
 
 import android.arch.lifecycle.Observer
+import android.content.Intent
 import android.os.Bundle
 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 android.widget.Toast
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.compatibility.LoggingHandler
 import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.ui.chat.topic.TopicActivity
 import de.kuschku.quasseldroid.util.helper.toLiveData
 import de.kuschku.quasseldroid.util.irc.format.ContentFormatter
 import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
@@ -98,11 +99,9 @@ class InfoFragment : ServiceBoundFragment() {
                             name = getString(R.string.property_ircchannel_topic_action_edit),
                             featured = true,
                             onClick = {
-                              Toast.makeText(
-                                requireContext(),
-                                "Not implemented",
-                                Toast.LENGTH_SHORT
-                              ).show()
+                              val intent = Intent(requireContext(), TopicActivity::class.java)
+                              intent.putExtra("buffer", info.buffer)
+                              startActivity(intent)
                             }
                           )
                         )
@@ -130,4 +129,4 @@ class InfoFragment : ServiceBoundFragment() {
 
     return view
   }
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt
index fcd2f8578..cebc155c4 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt
@@ -77,7 +77,7 @@ class ChatlineFragment : ServiceBoundFragment() {
 
   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                             savedInstanceState: Bundle?): View? {
-    val view = LayoutInflater.from(activity).inflate(R.layout.fragment_chatline, container, false)
+    val view = inflater.inflate(R.layout.fragment_chatline, container, false)
     ButterKnife.bind(this, view)
 
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt
index edda15255..8d0362fbf 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt
@@ -19,6 +19,7 @@ import com.bumptech.glide.Glide
 import com.bumptech.glide.ListPreloader
 import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
 import com.bumptech.glide.util.FixedPreloadSizeProvider
+import de.kuschku.libquassel.protocol.Buffer_Type
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.util.IrcUserUtils
 import de.kuschku.libquassel.util.helpers.value
@@ -151,14 +152,21 @@ class NickListFragment : ServiceBoundFragment() {
   }
 
   private val clickListener: ((String) -> Unit)? = { nick ->
-    viewModel.bufferData.value?.info?.let(BufferInfo::networkId)?.let { networkId ->
-      val intent = Intent(requireContext(), InfoActivity::class.java)
-      intent.putExtra("info", InfoDescriptor(
-        type = InfoType.User,
-        nick = nick,
-        network = networkId
-      ))
-      startActivity(intent)
+    viewModel.session.value?.orNull()?.bufferSyncer?.let { bufferSyncer ->
+      viewModel.bufferData.value?.info?.let(BufferInfo::networkId)?.let { networkId ->
+        val intent = Intent(requireContext(), InfoActivity::class.java)
+        intent.putExtra("info", InfoDescriptor(
+          type = InfoType.User,
+          nick = nick,
+          buffer = bufferSyncer.find(
+            bufferName = nick,
+            networkId = networkId,
+            type = Buffer_Type.of(Buffer_Type.QueryBuffer)
+          )?.bufferId ?: -1,
+          network = networkId
+        ))
+        startActivity(intent)
+      }
     }
   }
 
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
new file mode 100644
index 000000000..83fb366f0
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicActivity.kt
@@ -0,0 +1,5 @@
+package de.kuschku.quasseldroid.ui.chat.topic
+
+import de.kuschku.quasseldroid.util.ui.SettingsActivity
+
+class TopicActivity : SettingsActivity(TopicFragment())
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragment.kt
new file mode 100644
index 000000000..5c7d3ac8a
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragment.kt
@@ -0,0 +1,115 @@
+package de.kuschku.quasseldroid.ui.chat.topic
+
+import android.arch.lifecycle.Observer
+import android.arch.lifecycle.ViewModelProviders
+import android.os.Bundle
+import android.support.v7.widget.DefaultItemAnimator
+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.settings.AppearanceSettings
+import de.kuschku.quasseldroid.settings.AutoCompleteSettings
+import de.kuschku.quasseldroid.settings.MessageSettings
+import de.kuschku.quasseldroid.ui.chat.input.*
+import de.kuschku.quasseldroid.ui.coresettings.SettingsFragment
+import de.kuschku.quasseldroid.util.helper.invoke
+import de.kuschku.quasseldroid.util.helper.toLiveData
+import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
+import de.kuschku.quasseldroid.util.irc.format.IrcFormatSerializer
+import de.kuschku.quasseldroid.viewmodel.EditorViewModel
+import javax.inject.Inject
+
+class TopicFragment : SettingsFragment() {
+  @BindView(R.id.chatline)
+  lateinit var chatline: RichEditText
+
+  @BindView(R.id.formatting_toolbar)
+  lateinit var toolbar: RichToolbar
+
+  @Inject
+  lateinit var autoCompleteSettings: AutoCompleteSettings
+
+  @Inject
+  lateinit var messageSettings: MessageSettings
+
+  @Inject
+  lateinit var appearanceSettings: AppearanceSettings
+
+  @Inject
+  lateinit var formatDeserializer: IrcFormatDeserializer
+
+  @Inject
+  lateinit var formatSerializer: IrcFormatSerializer
+
+  lateinit var editorHelper: EditorHelper
+
+  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+                            savedInstanceState: Bundle?): View? {
+    val view = inflater.inflate(R.layout.fragment_topic, container, false)
+    ButterKnife.bind(this, view)
+
+    val editorViewModel = ViewModelProviders.of(this).get(EditorViewModel::class.java)
+    editorViewModel.quasselViewModel.onNext(viewModel)
+
+    val autoCompleteHelper = AutoCompleteHelper(
+      requireActivity(),
+      autoCompleteSettings,
+      messageSettings,
+      formatDeserializer,
+      editorViewModel
+    )
+
+    editorHelper = EditorHelper(
+      requireActivity(),
+      chatline,
+      toolbar,
+      autoCompleteHelper,
+      autoCompleteSettings,
+      appearanceSettings
+    )
+
+    editorViewModel.lastWord.onNext(editorHelper.lastWord)
+
+    if (autoCompleteSettings.prefix || autoCompleteSettings.auto) {
+      val autoCompleteLists = listOfNotNull<RecyclerView>(
+        view.findViewById(R.id.autocomplete_list)
+      )
+      val autocompleteAdapter = AutoCompleteAdapter(messageSettings, chatline::autoComplete)
+      for (autoCompleteList in autoCompleteLists) {
+        autoCompleteList.layoutManager = LinearLayoutManager(activity)
+        autoCompleteList.itemAnimator = DefaultItemAnimator()
+        autoCompleteList.adapter = autocompleteAdapter
+      }
+    }
+
+
+    val bufferId = arguments?.getInt("buffer", -1) ?: -1
+    viewModel.buffer.onNext(bufferId)
+    viewModel.bufferData.filter {
+      it.info != null
+    }.firstElement().toLiveData().observe(this, Observer {
+      chatline.setText(formatDeserializer.formatString(chatline.context, it?.description, true))
+    })
+
+    return view
+  }
+
+  override fun onSave(): Boolean {
+    viewModel.session { sessionOptional ->
+      val session = sessionOptional.orNull()
+      viewModel.buffer { bufferId ->
+        session?.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo ->
+          val topic = formatSerializer.toEscapeCodes(chatline.text)
+          session.rpcHandler?.sendInput(bufferInfo, "/topic $topic")
+          return true
+        }
+      }
+    }
+    return false
+  }
+}
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragmentProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragmentProvider.kt
new file mode 100644
index 000000000..0cdcb82b0
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/topic/TopicFragmentProvider.kt
@@ -0,0 +1,10 @@
+package de.kuschku.quasseldroid.ui.chat.topic
+
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+
+@Module
+abstract class TopicFragmentProvider {
+  @ContributesAndroidInjector
+  abstract fun bindTopicFragment(): TopicFragment
+}
diff --git a/app/src/main/res/layout/fragment_topic.xml b/app/src/main/res/layout/fragment_topic.xml
new file mode 100644
index 000000000..0cbc3a0de
--- /dev/null
+++ b/app/src/main/res/layout/fragment_topic.xml
@@ -0,0 +1,48 @@
+<?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"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:orientation="vertical">
+
+  <ScrollView
+    android:id="@+id/chatline_scroller"
+    android:layout_width="match_parent"
+    android:layout_height="0dip"
+    android:layout_weight="1">
+
+    <de.kuschku.quasseldroid.ui.chat.input.RichEditText
+      android:id="@+id/chatline"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:background="@android:color/transparent"
+      android:gravity="center_vertical"
+      android:hint="@string/label_placeholder_topic"
+      android:imeOptions="flagNoExtractUi"
+      android:inputType="textCapSentences|textAutoCorrect|textShortMessage|textMultiLine"
+      android:minHeight="?attr/actionBarSize"
+      android:paddingBottom="8dp"
+      android:paddingLeft="20dp"
+      android:paddingRight="20dp"
+      android:paddingTop="8dp"
+      android:textColor="?attr/colorForeground"
+      android:textSize="16sp" />
+  </ScrollView>
+
+  <de.kuschku.quasseldroid.util.ui.AutoCompleteRecyclerView
+    android:id="@+id/autocomplete_list"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" />
+
+  <android.support.design.widget.AppBarLayout
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?attr/colorBackgroundCard">
+
+    <de.kuschku.quasseldroid.ui.chat.input.RichToolbar
+      android:id="@+id/formatting_toolbar"
+      android:layout_width="match_parent"
+      android:layout_height="?attr/actionBarSize"
+      app:contentInsetStart="0dip" />
+  </android.support.design.widget.AppBarLayout>
+</LinearLayout>
diff --git a/app/src/main/res/layout/layout_editor.xml b/app/src/main/res/layout/layout_editor.xml
index 65fc344c9..e0f2d6658 100644
--- a/app/src/main/res/layout/layout_editor.xml
+++ b/app/src/main/res/layout/layout_editor.xml
@@ -33,7 +33,7 @@
       android:layout_height="wrap_content"
       android:background="@android:color/transparent"
       android:gravity="center_vertical"
-      android:hint="@string/label_placeholder"
+      android:hint="@string/label_placeholder_message"
       android:imeOptions="flagNoExtractUi"
       android:inputType="textCapSentences|textAutoCorrect|textShortMessage"
       android:minHeight="?attr/actionBarSize"
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 503ddec9a..594b7cfcd 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -42,7 +42,8 @@
   <string name="label_reset">Zurücksetzen</string>
   <string name="label_open">Öffnen</string>
   <string name="label_part">Verlassen</string>
-  <string name="label_placeholder">Nachricht schreiben…</string>
+  <string name="label_placeholder_message">Nachricht schreiben…</string>
+  <string name="label_placeholder_topic">Beschreib das Thema des Kanals…</string>
   <string name="label_rename">Umbenennen</string>
   <string name="label_save">Speichern</string>
   <string name="label_select">Auswählen</string>
@@ -52,6 +53,7 @@
   <string name="label_share">Teilen</string>
   <string name="label_share_crashreport">Absturzbericht Teilen</string>
   <string name="label_show_hidden">Alle anzeigen</string>
+  <string name="label_topic">Kanal-Thema</string>
   <string name="label_unhide">Nicht mehr ausblenden</string>
   <string name="label_website">Webseite</string>
   <string name="label_yes">Ja</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 64d745e20..1aecf7ac0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -42,7 +42,8 @@
   <string name="label_reset">Reset</string>
   <string name="label_open">Open</string>
   <string name="label_part">Part</string>
-  <string name="label_placeholder">Write a message…</string>
+  <string name="label_placeholder_message">Write a message…</string>
+  <string name="label_placeholder_topic">Describe the channel topic…</string>
   <string name="label_rename">Rename</string>
   <string name="label_save">Save</string>
   <string name="label_select">Select</string>
@@ -52,6 +53,7 @@
   <string name="label_share">Share</string>
   <string name="label_share_crashreport">Share Crash Report</string>
   <string name="label_show_hidden">Show Hidden</string>
+  <string name="label_topic">Channel Topic</string>
   <string name="label_unhide">Make Visible</string>
   <string name="label_website">Website</string>
   <string name="label_yes">Yes</string>
-- 
GitLab