From 76004298a15620ef7a94544a4d31dd961d1da23f Mon Sep 17 00:00:00 2001 From: kyori19 Date: Sun, 24 Nov 2019 11:56:32 +0900 Subject: [PATCH] List tabs --- .../com/keylesspalace/tusky/MainActivity.java | 8 +++- .../java/com/keylesspalace/tusky/TabData.kt | 2 + .../tusky/TabPreferenceActivity.kt | 37 +++++++++++++++ .../tusky/adapter/ListSelectionAdapter.kt | 47 +++++++++++++++++++ .../keylesspalace/tusky/adapter/TabAdapter.kt | 7 ++- .../com/keylesspalace/tusky/db/Converters.kt | 6 ++- app/src/main/res/drawable-anydpi/ic_list.xml | 9 ++++ app/src/main/res/values/strings.xml | 2 + 8 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt create mode 100644 app/src/main/res/drawable-anydpi/ic_list.xml diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java index 1c874c658..78d80d046 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java @@ -478,8 +478,12 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut tabLayout.removeAllTabs(); for (int i = 0; i < tabs.size(); i++) { TabLayout.Tab tab = tabLayout.newTab() - .setIcon(tabs.get(i).getIcon()) - .setContentDescription(tabs.get(i).getText()); + .setIcon(tabs.get(i).getIcon()); + if (tabs.get(i).getId().equals(TabDataKt.LIST)) { + tab.setContentDescription(tabs.get(i).getArguments().get(1)); + } else { + tab.setContentDescription(tabs.get(i).getText()); + } tabLayout.addTab(tab); if (tabs.get(i).getId().equals(TabDataKt.NOTIFICATIONS)) { notificationTabPosition = i; diff --git a/app/src/main/java/com/keylesspalace/tusky/TabData.kt b/app/src/main/java/com/keylesspalace/tusky/TabData.kt index 5e6b0d39d..5901d6e51 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TabData.kt +++ b/app/src/main/java/com/keylesspalace/tusky/TabData.kt @@ -30,6 +30,7 @@ const val LOCAL = "Local" const val FEDERATED = "Federated" const val DIRECT = "Direct" const val HASHTAG = "Hashtag" +const val LIST = "List" data class TabData(val id: String, @StringRes val text: Int, @@ -45,6 +46,7 @@ fun createTabDataFromId(id: String, arguments: List = emptyList()): TabD FEDERATED -> TabData(FEDERATED, R.string.title_public_federated, R.drawable.ic_public_24dp, { TimelineFragment.newInstance(TimelineFragment.Kind.PUBLIC_FEDERATED) }) DIRECT -> TabData(DIRECT, R.string.title_direct_messages, R.drawable.reblog_direct_dark, { ConversationsFragment.newInstance() }) HASHTAG -> TabData(HASHTAG, R.string.hashtag, R.drawable.ic_hashtag, { args -> TimelineFragment.newInstance(TimelineFragment.Kind.TAG, args.getOrNull(0).orEmpty()) }, arguments) + LIST -> TabData(LIST, R.string.list, R.drawable.ic_list, { args -> TimelineFragment.newInstance(TimelineFragment.Kind.LIST, args.getOrNull(0).orEmpty()) }, arguments) else -> throw IllegalArgumentException("unknown tab type") } } diff --git a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt index f2876bbec..76bcc6509 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt @@ -25,15 +25,18 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.keylesspalace.tusky.adapter.ItemInteractionListener +import com.keylesspalace.tusky.adapter.ListSelectionAdapter import com.keylesspalace.tusky.adapter.TabAdapter import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.MainTabsChangedEvent import com.keylesspalace.tusky.di.Injectable +import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.util.onTextChanged import com.keylesspalace.tusky.util.visible import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from import com.uber.autodispose.autoDispose import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.activity_tab_preference.* import kotlinx.android.synthetic.main.toolbar_basic.* @@ -42,6 +45,8 @@ import javax.inject.Inject class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListener { + @Inject + lateinit var mastodonApi: MastodonApi @Inject lateinit var eventHub: EventHub @@ -151,6 +156,11 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene return } + if (tab.id == LIST) { + showSelectListDialog() + return + } + currentTabs.add(tab) currentTabsAdapter.notifyItemInserted(currentTabs.size - 1) updateAvailableTabs() @@ -200,6 +210,32 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene editText.requestFocus() } + private fun showSelectListDialog() { + val adapter = ListSelectionAdapter(this) + mastodonApi.getLists() + .observeOn(AndroidSchedulers.mainThread()) + .autoDispose(from(this, Lifecycle.Event.ON_DESTROY)) + .subscribe ( + { lists -> + adapter.addAll(lists) + }, + { + } + ) + + AlertDialog.Builder(this) + .setTitle(R.string.select_list_title) + .setAdapter(adapter) { _, position -> + val list = adapter.getItem(position) + val newTab = createTabDataFromId(LIST, listOf(list!!.id, list.title)) + currentTabs.add(newTab) + currentTabsAdapter.notifyItemInserted(currentTabs.size - 1) + updateAvailableTabs() + saveTabs() + } + .show() + } + private fun validateHashtag(input: CharSequence?): Boolean { val trimmedInput = input?.trim() ?: "" return trimmedInput.isNotEmpty() && hashtagRegex.matcher(trimmedInput).matches() @@ -230,6 +266,7 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene } addableTabs.add(createTabDataFromId(HASHTAG)) + addableTabs.add(createTabDataFromId(LIST)) addTabAdapter.updateData(addableTabs) diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt new file mode 100644 index 000000000..03944878f --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/ListSelectionAdapter.kt @@ -0,0 +1,47 @@ +/* Copyright 2019 kyori19 + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ + +package com.keylesspalace.tusky.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.entity.MastoList +import kotlinx.android.synthetic.main.item_autocomplete_hashtag.view.* + +class ListSelectionAdapter(context: Context) : ArrayAdapter(context, R.layout.item_autocomplete_hashtag) { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + var view = convertView + + if (convertView == null) { + val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater + view = layoutInflater.inflate(R.layout.item_autocomplete_hashtag, parent, false) + } + view!! + + val list = getItem(position) + if (list != null) { + val title = view.hashtag + title.text = list.title + val icon = context.getDrawable(R.drawable.ic_list) + title.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null) + } + + return view + } +} diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt index dc08af5bf..a16898198 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt @@ -21,6 +21,7 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.keylesspalace.tusky.HASHTAG +import com.keylesspalace.tusky.LIST import com.keylesspalace.tusky.R import com.keylesspalace.tusky.TabData import com.keylesspalace.tusky.util.ThemeUtils @@ -57,7 +58,11 @@ class TabAdapter(private var data: List, override fun onBindViewHolder(holder: ViewHolder, position: Int) { val context = holder.itemView.context - holder.itemView.textView.setText(data[position].text) + if (!small && data[position].id == LIST) { + holder.itemView.textView.text = data[position].arguments.getOrNull(1).orEmpty() + } else { + holder.itemView.textView.setText(data[position].text) + } val iconDrawable = ThemeUtils.getTintedDrawable(context, data[position].icon, android.R.attr.textColorSecondary) holder.itemView.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(iconDrawable, null, null, null) if (small) { diff --git a/app/src/main/java/com/keylesspalace/tusky/db/Converters.kt b/app/src/main/java/com/keylesspalace/tusky/db/Converters.kt index 4dad5a08d..ba07a1afd 100644 --- a/app/src/main/java/com/keylesspalace/tusky/db/Converters.kt +++ b/app/src/main/java/com/keylesspalace/tusky/db/Converters.kt @@ -28,6 +28,8 @@ import com.keylesspalace.tusky.entity.Poll import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.json.SpannedTypeAdapter import com.keylesspalace.tusky.util.HtmlUtils +import java.net.URLDecoder +import java.net.URLEncoder import java.util.* class Converters { @@ -61,13 +63,13 @@ class Converters { return str?.split(";") ?.map { val data = it.split(":") - createTabDataFromId(data[0], data.drop(1)) + createTabDataFromId(data[0], data.drop(1).map { s -> URLDecoder.decode(s, "UTF-8") }) } } @TypeConverter fun tabDataToString(tabData: List?): String? { - return tabData?.joinToString(";") { it.id + ":" + it.arguments.joinToString(":") } + return tabData?.joinToString(";") { it.id + ":" + it.arguments.joinToString(":") { s -> URLEncoder.encode(s, "UTF-8") } } } @TypeConverter diff --git a/app/src/main/res/drawable-anydpi/ic_list.xml b/app/src/main/res/drawable-anydpi/ic_list.xml new file mode 100644 index 000000000..4c2fb8834 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_list.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 357695dae..f06e34dfc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -470,6 +470,8 @@ Edit hashtag Hashtag without # Hashtag + Select list + List Clear Filter Apply