List tabs

This commit is contained in:
kyori19 2019-11-24 11:56:32 +09:00
parent 8fb159ae22
commit b21d711819
8 changed files with 113 additions and 5 deletions

View File

@ -553,8 +553,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;

View File

@ -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<String> = 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")
}
}

View File

@ -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)

View File

@ -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 <http://www.gnu.org/licenses>. */
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<MastoList>(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
}
}

View File

@ -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<TabData>,
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) {

View File

@ -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<TabData>?): String? {
return tabData?.joinToString(";") { it.id + ":" + it.arguments.joinToString(":") }
return tabData?.joinToString(";") { it.id + ":" + it.arguments.joinToString(":") { s -> URLEncoder.encode(s, "UTF-8") } }
}
@TypeConverter

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,13h2v-2L3,11v2zM3,17h2v-2L3,15v2zM3,9h2L5,7L3,7v2zM7,13h14v-2L7,11v2zM7,17h14v-2L7,15v2zM7,7v2h14L21,7L7,7z"/>
</vector>

View File

@ -496,6 +496,8 @@
<string name="edit_hashtag_title">Edit hashtag</string>
<string name="edit_hashtag_hint">Hashtag without #</string>
<string name="hashtag">Hashtag</string>
<string name="select_list_title">Select list</string>
<string name="list">List</string>
<string name="notifications_clear">Clear</string>
<string name="notifications_apply_filter">Filter</string>
<string name="filter_apply">Apply</string>