diff --git a/vector/src/main/java/im/vector/riotredesign/core/epoxy/VectorEpoxyHolder.kt b/vector/src/main/java/im/vector/riotredesign/core/epoxy/VectorEpoxyHolder.kt index f715106a..7c6f200b 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/epoxy/VectorEpoxyHolder.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/epoxy/VectorEpoxyHolder.kt @@ -27,7 +27,7 @@ import kotlin.reflect.KProperty * See [SampleKotlinModelWithHolder] for a usage example. */ abstract class VectorEpoxyHolder : EpoxyHolder() { - private lateinit var view: View + lateinit var view: View override fun bindView(itemView: View) { view = itemView diff --git a/vector/src/main/java/im/vector/riotredesign/core/listener/Listener.kt b/vector/src/main/java/im/vector/riotredesign/core/listener/Listener.kt new file mode 100644 index 00000000..8746883c --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/listener/Listener.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotredesign.core.listener + +/** + * Simple generic listener interface + */ +interface Listener { + + fun onEvent(t: T) +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/EpoxyViewPresenter.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/EpoxyAutocompletePresenter.kt similarity index 92% rename from vector/src/main/java/im/vector/riotredesign/features/autocomplete/EpoxyViewPresenter.kt rename to vector/src/main/java/im/vector/riotredesign/features/autocomplete/EpoxyAutocompletePresenter.kt index f7c64c0a..cf5818d1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/EpoxyViewPresenter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/EpoxyAutocompletePresenter.kt @@ -24,8 +24,9 @@ import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.EpoxyRecyclerView import com.otaliastudios.autocomplete.AutocompleteCallback import com.otaliastudios.autocomplete.AutocompletePresenter +import im.vector.riotredesign.core.listener.Listener -abstract class EpoxyViewPresenter(context: Context) : AutocompletePresenter(context) { +abstract class EpoxyAutocompletePresenter(context: Context) : AutocompletePresenter(context), Listener { private var recyclerView: EpoxyRecyclerView? = null private var clicks: AutocompletePresenter.ClickProvider? = null @@ -73,6 +74,10 @@ abstract class EpoxyViewPresenter(context: Context) : AutocompletePresenter>() { + var listener: Listener? = null + override fun buildModels(data: List?) { if (data.isNullOrEmpty()) { return } - data.forEach { + data.forEach { command -> autocompleteCommandItem { - id(it.command) - name(it.command) - parameters(it.parameters) - description(stringProvider.getString(it.description)) + id(command.command) + name(command.command) + parameters(command.parameters) + description(stringProvider.getString(command.description)) + clickListener { _ -> + listener?.onEvent(command) + } } } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandItem.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandItem.kt index e0620e3d..cd6a0ff0 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/AutocompleteCommandItem.kt @@ -16,6 +16,7 @@ package im.vector.riotredesign.features.autocomplete.command +import android.view.View import android.widget.TextView import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass @@ -32,8 +33,12 @@ abstract class AutocompleteCommandItem : VectorEpoxyModel(context) { + private val controller: AutocompleteCommandController) : + EpoxyAutocompletePresenter(context) { + + init { + controller.listener = this + } override fun providesController(): EpoxyController { return controller diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/CommandPolicy.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/CommandPolicy.kt new file mode 100644 index 00000000..6cf6dfa3 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/command/CommandPolicy.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotredesign.features.autocomplete.command + +import android.text.Spannable +import com.otaliastudios.autocomplete.AutocompletePolicy + +class CommandPolicy : AutocompletePolicy { + override fun getQuery(text: Spannable): CharSequence { + if (text.length > 0) { + return text.substring(1, text.length) + } + + // Should not happen + return "" + } + + override fun onDismiss(text: Spannable?) { + } + + // Only if text which starts with '/' and without space + override fun shouldShowPopup(text: Spannable?, cursorPos: Int): Boolean { + return text?.startsWith("/") == true + && !text.contains(" ") + } + + override fun shouldDismissPopup(text: Spannable?, cursorPos: Int): Boolean { + return !shouldShowPopup(text, cursorPos) + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt index 31d69085..6c9965c5 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserController.kt @@ -18,18 +18,24 @@ package im.vector.riotredesign.features.autocomplete.user import com.airbnb.epoxy.TypedEpoxyController import im.vector.matrix.android.api.session.user.model.User +import im.vector.riotredesign.core.listener.Listener -class AutocompleteUserController() : TypedEpoxyController>() { +class AutocompleteUserController : TypedEpoxyController>() { + + var listener: Listener? = null override fun buildModels(data: List?) { if (data.isNullOrEmpty()) { return } - data.forEach { + data.forEach { user -> autocompleteUserItem { - id(it.userId) - name(it.displayName) - avatarUrl(it.avatarUrl) + id(user.userId) + name(user.displayName) + avatarUrl(user.avatarUrl) + clickListener { _ -> + listener?.onEvent(user) + } } } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt index 6ab9ead5..6678bff5 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt @@ -16,6 +16,7 @@ package im.vector.riotredesign.features.autocomplete.user +import android.view.View import android.widget.ImageView import android.widget.TextView import com.airbnb.epoxy.EpoxyAttribute @@ -32,8 +33,12 @@ abstract class AutocompleteUserItem : VectorEpoxyModel(context) { +) : EpoxyAutocompletePresenter(context), Listener { var callback: Callback? = null + init { + controller.listener = this + } + override fun providesController(): EpoxyController { return controller } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index e7294daa..d7873e11 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -20,12 +20,14 @@ import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.os.Parcelable +import android.text.Editable import android.view.View import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.airbnb.epoxy.EpoxyVisibilityTracker import com.airbnb.mvrx.fragmentViewModel import com.otaliastudios.autocomplete.Autocomplete +import com.otaliastudios.autocomplete.AutocompleteCallback import com.otaliastudios.autocomplete.CharPolicy import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.user.model.User @@ -34,6 +36,7 @@ import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer import im.vector.riotredesign.core.platform.ToolbarConfigurable import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter +import im.vector.riotredesign.features.autocomplete.command.CommandPolicy import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter import im.vector.riotredesign.features.command.Command import im.vector.riotredesign.features.home.AvatarRenderer @@ -133,10 +136,22 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac val elevation = 6f val backgroundDrawable = ColorDrawable(Color.WHITE) Autocomplete.on(composerEditText) - .with(CharPolicy('/', false)) + .with(CommandPolicy()) .with(autocompleteCommandPresenter) .with(elevation) .with(backgroundDrawable) + .with(object : AutocompleteCallback { + override fun onPopupItemClicked(editable: Editable?, item: Command?): Boolean { + editable?.clear() + editable + ?.append(item?.command) + ?.append(" ") + return true + } + + override fun onPopupVisibilityChanged(shown: Boolean) { + } + }) .build() autocompleteUserPresenter.callback = this @@ -145,6 +160,17 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac .with(autocompleteUserPresenter) .with(elevation) .with(backgroundDrawable) + .with(object : AutocompleteCallback { + override fun onPopupItemClicked(editable: Editable?, item: User?): Boolean { + // TODO + editable?.append(item?.displayName) + ?.append(" ") + return true + } + + override fun onPopupVisibilityChanged(shown: Boolean) { + } + }) .build() sendButton.setOnClickListener {