1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-17 04:00:48 +01:00

rewriting userlist picker

This commit is contained in:
Mariotaku Lee 2017-01-31 12:04:36 +08:00
parent 20c49e727c
commit 4ceaf681c4
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
17 changed files with 272 additions and 340 deletions

View File

@ -209,4 +209,5 @@ public interface IntentConstants {
String EXTRA_COUNT = "count";
String EXTRA_REQUEST_CODE = "request_code";
String EXTRA_FROM_CACHE = "from_cache";
String EXTRA_SHOW_MY_LISTS = "show_my_lists";
}

View File

@ -139,7 +139,6 @@ dependencies {
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0'
compile 'com.squareup:otto:1.3.8'
compile 'dnsjava:dnsjava:2.1.7'
compile 'com.commonsware.cwac:merge:1.1.1'
compile 'com.commonsware.cwac:layouts:0.4.3'
compile 'com.rengwuxian.materialedittext:library:2.1.4'
compile 'com.pnikosis:materialish-progress:1.7'

View File

@ -252,6 +252,12 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable {
if (mNotifyOnChange) notifyDataSetChanged();
}
public List<T> getAll() {
synchronized (mLock) {
return new ArrayList<>(mObjects);
}
}
/**
* {@inheritDoc}
*/

View File

@ -26,4 +26,9 @@ fun String?.toDouble(def: Double): Double {
} catch (e: NumberFormatException) {
return def
}
}
fun Int.coerceInOr(range: ClosedRange<Int>, or: Int): Int {
if (range.isEmpty()) return or
return coerceIn(range)
}

View File

@ -21,128 +21,78 @@ package org.mariotaku.twidere.activity
import android.app.Activity
import android.content.Intent
import android.os.AsyncTask
import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.text.TextUtils
import android.text.TextUtils.isEmpty
import android.util.Log
import android.support.v4.app.LoaderManager
import android.support.v4.content.Loader
import android.view.View
import android.view.View.OnClickListener
import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener
import android.widget.ListView
import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.activity_user_list_selector.*
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.http.HttpResponseCode
import android.widget.TextView
import kotlinx.android.synthetic.main.layout_list_with_empty_view.*
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.set
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.LOGTAG
import org.mariotaku.twidere.TwidereConstants.REQUEST_SELECT_USER
import org.mariotaku.twidere.adapter.SimpleParcelableUserListsAdapter
import org.mariotaku.twidere.adapter.UserAutoCompleteAdapter
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.fragment.CreateUserListDialogFragment
import org.mariotaku.twidere.fragment.ProgressDialogFragment
import org.mariotaku.twidere.loader.UserListOwnershipsLoader
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.ParcelableUserList
import org.mariotaku.twidere.model.SingleResponse
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.message.UserListCreatedEvent
import org.mariotaku.twidere.model.util.ParcelableUserListUtils
import org.mariotaku.twidere.util.AsyncTaskUtils
import org.mariotaku.twidere.util.DataStoreUtils.getAccountScreenName
import org.mariotaku.twidere.util.MicroBlogAPIFactory
import java.util.*
class UserListSelectorActivity : BaseActivity(), OnClickListener, OnItemClickListener {
class UserListSelectorActivity : BaseActivity(),
LoaderManager.LoaderCallbacks<List<ParcelableUserList>> {
private lateinit var userListsAdapter: SimpleParcelableUserListsAdapter
private var screenName: String? = null
private lateinit var adapter: SimpleParcelableUserListsAdapter
private val accountKey: UserKey?
get() = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
private val showMyLists: Boolean
get() = intent.getBooleanExtra(EXTRA_SHOW_MY_LISTS, false)
private var userKey: UserKey? = null
private var loaderInitialized: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = intent
if (!intent.hasExtra(EXTRA_ACCOUNT_KEY)) {
val accountKey = accountKey ?: run {
finish()
return
}
setContentView(R.layout.activity_user_list_selector)
if (savedInstanceState == null) {
screenName = intent.getStringExtra(EXTRA_SCREEN_NAME)
adapter = SimpleParcelableUserListsAdapter(this)
listView.addFooterView(layoutInflater.inflate(R.layout.simple_list_item_activated_1,
listView, false).apply {
(findViewById(android.R.id.text1) as TextView).setText(R.string.action_select_user)
}, SelectUserAction, true)
listView.adapter = adapter
listView.onItemClickListener = OnItemClickListener { view, child, position, id ->
val item = view.getItemAtPosition(position)
when (item) {
is ParcelableUserList -> {
val data = Intent()
data.putExtra(EXTRA_USER_LIST, item)
setResult(Activity.RESULT_OK, data)
finish()
}
is SelectUserAction -> {
selectUser()
}
}
}
val userKey = intent.getParcelableExtra<UserKey>(EXTRA_USER_KEY) ?: if (showMyLists) {
accountKey
} else {
screenName = savedInstanceState.getString(EXTRA_SCREEN_NAME)
null
}
if (!isEmpty(screenName)) {
getUserLists(screenName)
}
val adapter = UserAutoCompleteAdapter(this)
adapter.accountKey = accountKey
userListsAdapter = SimpleParcelableUserListsAdapter(this)
userListsList.adapter = userListsAdapter
userListsList.onItemClickListener = this
createList.setOnClickListener(this)
}
override fun onClick(v: View) {
when (v.id) {
R.id.createList -> {
val f = CreateUserListDialogFragment()
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey)
f.arguments = args
f.show(supportFragmentManager, null)
}
}
}
override fun onItemClick(view: AdapterView<*>, child: View, position: Int, id: Long) {
val list = view as ListView
val data = Intent()
data.putExtra(EXTRA_USER_LIST, userListsAdapter.getItem(position - list.headerViewsCount))
setResult(Activity.RESULT_OK, data)
finish()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(EXTRA_SCREEN_NAME, screenName)
}
@Subscribe
fun onUserListCreated(event: UserListCreatedEvent) {
getUserLists(screenName)
}
private val accountKey: UserKey
get() = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
private fun getUserLists(screenName: String?) {
if (screenName == null) return
this.screenName = screenName
val task = GetUserListsTask(this, accountKey, screenName)
AsyncTaskUtils.executeTask(task)
}
private fun setUserListsData(data: List<ParcelableUserList>, isMyAccount: Boolean) {
userListsAdapter.setData(data, true)
userListsContainer.visibility = View.VISIBLE
createListContainer.visibility = if (isMyAccount) View.VISIBLE else View.GONE
}
private fun dismissDialogFragment(tag: String) {
executeAfterFragmentResumed { activity ->
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(tag)
if (f is DialogFragment) {
f.dismiss()
}
}
}
private fun showDialogFragment(df: DialogFragment, tag: String) {
executeAfterFragmentResumed { activity ->
df.show(activity.supportFragmentManager, tag)
if (userKey != null) {
loadUserLists(accountKey, userKey)
} else if (savedInstanceState == null) {
selectUser()
}
}
@ -156,61 +106,68 @@ class UserListSelectorActivity : BaseActivity(), OnClickListener, OnItemClickLis
super.onStop()
}
private class GetUserListsTask(
private val activity: UserListSelectorActivity,
private val accountKey: UserKey,
private val screenName: String
) : AsyncTask<Any, Any, SingleResponse<List<ParcelableUserList>>>() {
override fun doInBackground(vararg params: Any): SingleResponse<List<ParcelableUserList>> {
val twitter = MicroBlogAPIFactory.getInstance(activity, accountKey) ?: return SingleResponse.getInstance<List<ParcelableUserList>>()
try {
val lists = twitter.getUserListsByScreenName(screenName, true)
val data = ArrayList<ParcelableUserList>()
var isMyAccount = screenName.equals(getAccountScreenName(activity,
accountKey), ignoreCase = true)
for (item in lists) {
val user = item.user
if (user != null && screenName.equals(user.screenName, ignoreCase = true)) {
if (!isMyAccount && TextUtils.equals(user.id, accountKey.id)) {
isMyAccount = true
}
data.add(ParcelableUserListUtils.from(item, accountKey))
}
}
val result = SingleResponse.getInstance<List<ParcelableUserList>>(data)
result.extras.putBoolean(EXTRA_IS_MY_ACCOUNT, isMyAccount)
return result
} catch (e: MicroBlogException) {
Log.w(LOGTAG, e)
return SingleResponse.getInstance<List<ParcelableUserList>>(e)
}
}
override fun onPostExecute(result: SingleResponse<List<ParcelableUserList>>) {
activity.dismissDialogFragment(FRAGMENT_TAG_GET_USER_LISTS)
if (result.data != null) {
activity.setUserListsData(result.data, result.extras.getBoolean(EXTRA_IS_MY_ACCOUNT))
} else if (result.exception is MicroBlogException) {
if (result.exception.statusCode == HttpResponseCode.NOT_FOUND) {
// activity.searchUser(screenName)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_SELECT_USER -> {
if (resultCode == Activity.RESULT_OK && data != null) {
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER)
loadUserLists(accountKey!!, user.key)
}
}
}
override fun onPreExecute() {
val df = ProgressDialogFragment()
df.isCancelable = false
activity.showDialogFragment(df, FRAGMENT_TAG_GET_USER_LISTS)
}
companion object {
private const val FRAGMENT_TAG_GET_USER_LISTS = "get_user_lists"
}
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<List<ParcelableUserList>> {
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val userKey = args.getParcelable<UserKey>(EXTRA_USER_KEY)
return UserListOwnershipsLoader(this, accountKey, userKey, null, adapter.all)
}
override fun onLoaderReset(loader: Loader<List<ParcelableUserList>>?) {
adapter.setData(null)
}
override fun onLoadFinished(loader: Loader<List<ParcelableUserList>>?, data: List<ParcelableUserList>?) {
adapter.setData(data)
showList()
}
private fun loadUserLists(accountKey: UserKey, userKey: UserKey) {
if (userKey != this.userKey) {
adapter.clear()
showProgress()
this.userKey = userKey
}
val args = Bundle {
this[EXTRA_ACCOUNT_KEY] = accountKey
this[EXTRA_USER_KEY] = userKey
}
if (!loaderInitialized) {
loaderInitialized = true
supportLoaderManager.initLoader(0, args, this)
} else {
supportLoaderManager.restartLoader(0, args, this)
}
}
private fun showProgress() {
progressContainer.visibility = View.VISIBLE
listContainer.visibility = View.GONE
}
private fun showList() {
progressContainer.visibility = View.GONE
listContainer.visibility = View.VISIBLE
listView.visibility = View.VISIBLE
emptyView.visibility = View.GONE
}
private fun selectUser() {
val selectUserIntent = Intent(this, UserSelectorActivity::class.java)
selectUserIntent.putExtra(EXTRA_ACCOUNT_KEY, accountKey)
startActivityForResult(selectUserIntent, REQUEST_SELECT_USER)
}
object SelectUserAction
}

View File

@ -45,13 +45,13 @@ import org.mariotaku.twidere.util.view.SimpleTextWatcher
class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.LoaderCallbacks<List<ParcelableUser>> {
private lateinit var usersAdapter: SimpleParcelableUsersAdapter
private var loaderInitialized: Boolean = false
private lateinit var adapter: SimpleParcelableUsersAdapter
private val accountKey: UserKey?
get() = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
private var loaderInitialized: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val accountKey = this.accountKey ?: run {
@ -73,8 +73,8 @@ class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.
if (savedInstanceState == null) {
editScreenName.setText(intent.getStringExtra(EXTRA_SCREEN_NAME))
}
usersAdapter = SimpleParcelableUsersAdapter(this)
listView.adapter = usersAdapter
adapter = SimpleParcelableUsersAdapter(this)
listView.adapter = adapter
listView.onItemClickListener = this
showSearchHint()
@ -82,7 +82,7 @@ class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.
override fun onItemClick(view: AdapterView<*>, child: View, position: Int, id: Long) {
val list = view as ListView
val user = usersAdapter.getItem(position - list.headerViewsCount) ?: return
val user = adapter.getItem(position - list.headerViewsCount) ?: return
val data = Intent()
data.setExtrasClassLoader(classLoader)
data.putExtra(EXTRA_USER, user)
@ -101,13 +101,13 @@ class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.
}
override fun onLoaderReset(loader: Loader<List<ParcelableUser>>) {
usersAdapter.setData(null, true)
adapter.setData(null, true)
}
override fun onLoadFinished(loader: Loader<List<ParcelableUser>>, data: List<ParcelableUser>?) {
progressContainer.visibility = View.GONE
listContainer.visibility = View.VISIBLE
usersAdapter.setData(data, true)
adapter.setData(data, true)
loader as CacheUserSearchLoader
if (data.isNotNullOrEmpty()) {
showList()

View File

@ -24,11 +24,12 @@ import android.view.View
import android.view.ViewGroup
import org.mariotaku.twidere.R
import org.mariotaku.twidere.model.ParcelableUserList
import org.mariotaku.twidere.view.holder.TwoLineWithIconViewHolder
import org.mariotaku.twidere.util.view.display
import org.mariotaku.twidere.view.holder.SimpleUserListViewHolder
class SimpleParcelableUserListsAdapter(
context: Context
) : BaseArrayAdapter<ParcelableUserList>(context, R.layout.list_item_two_line) {
) : BaseArrayAdapter<ParcelableUserList>(context, R.layout.list_item_simple_user_list) {
override fun getItemId(position: Int): Long {
return (if (getItem(position) != null) getItem(position).hashCode() else -1).toLong()
@ -37,38 +38,22 @@ class SimpleParcelableUserListsAdapter(
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = super.getView(position, convertView, parent)
val tag = view.tag
val holder: TwoLineWithIconViewHolder
if (tag is TwoLineWithIconViewHolder) {
holder = tag
} else {
holder = TwoLineWithIconViewHolder(view)
view.tag = holder
val holder = tag as? SimpleUserListViewHolder ?: run {
val h = SimpleUserListViewHolder(view)
view.tag = h
return@run h
}
// Clear images in order to prevent images in recycled view shown.
holder.icon.setImageDrawable(null)
val userList = getItem(position)
val display_name = userColorNameManager.getDisplayName(userList, nameFirst)
holder.text1.text = userList.name
holder.text2.text = context.getString(R.string.created_by, display_name)
holder.icon.visibility = if (profileImageEnabled) View.VISIBLE else View.GONE
if (profileImageEnabled) {
mediaLoader.displayProfileImage(holder.icon, userList.user_profile_image_url)
} else {
mediaLoader.cancelDisplayTask(holder.icon)
}
holder.display(userList, mediaLoader, userColorNameManager, profileImageEnabled)
return view
}
fun setData(data: List<ParcelableUserList>?, clearOld: Boolean) {
if (clearOld) {
clear()
}
fun setData(data: List<ParcelableUserList>?) {
clear()
if (data == null) return
for (user in data) {
//TODO improve compare
if (clearOld || findItemPosition(user.hashCode().toLong()) < 0) {
if (findItemPosition(user.hashCode().toLong()) < 0) {
add(user)
}
}

View File

@ -36,6 +36,7 @@ import edu.tsinghua.hotmobi.HotMobiLogger
import edu.tsinghua.hotmobi.model.MediaEvent
import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.coerceInOr
import org.mariotaku.ktextension.isNullOrEmpty
import org.mariotaku.ktextension.rangeOfSize
import org.mariotaku.twidere.R
@ -225,15 +226,15 @@ abstract class AbsActivitiesFragment protected constructor() :
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
wasAtTop = firstVisibleItemPosition == 0
val statusRange = rangeOfSize(adapter.activityStartIndex, adapter.activityCount - 1)
val activityRange = rangeOfSize(adapter.activityStartIndex, Math.max(0, adapter.activityCount - 1))
val lastReadPosition = if (readFromBottom) {
lastVisibleItemPosition
} else {
firstVisibleItemPosition
}.coerceIn(statusRange)
}.coerceInOr(activityRange, -1)
lastReadId = adapter.getTimestamp(lastReadPosition)
lastReadViewTop = layoutManager.findViewByPosition(lastReadPosition)?.top ?: 0
loadMore = lastVisibleItemPosition >= statusRange.endInclusive
loadMore = activityRange.endInclusive >= 0 && lastVisibleItemPosition >= activityRange.endInclusive
} else if (rememberPosition && readPositionTag != null) {
lastReadId = readStateManager.getPosition(readPositionTag)
lastReadViewTop = 0

View File

@ -36,6 +36,7 @@ import edu.tsinghua.hotmobi.HotMobiLogger
import edu.tsinghua.hotmobi.model.MediaEvent
import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.coerceInOr
import org.mariotaku.ktextension.isNullOrEmpty
import org.mariotaku.ktextension.rangeOfSize
import org.mariotaku.twidere.R
@ -283,14 +284,14 @@ abstract class AbsStatusesFragment protected constructor() :
lastVisibleItemPosition
} else {
firstVisibleItemPosition
}.coerceIn(statusRange)
}.coerceInOr(statusRange, -1)
lastReadId = if (useSortIdAsReadPosition) {
adapter.getStatusSortId(lastReadPosition)
} else {
adapter.getStatusPositionKey(lastReadPosition)
}
lastReadViewTop = layoutManager.findViewByPosition(lastReadPosition)?.top ?: 0
loadMore = lastVisibleItemPosition >= statusRange.endInclusive
loadMore = statusRange.endInclusive >= 0 && lastVisibleItemPosition >= statusRange.endInclusive
} else if (rememberPosition && readPositionTag != null) {
lastReadId = readStateManager.getPosition(readPositionTag)
lastReadViewTop = 0

View File

@ -45,6 +45,7 @@ class UserListExtraConfiguration(key: String) : TabConfiguration.ExtraConfigurat
val account = fragment.account ?: return@setOnClickListener
val intent = Intent(INTENT_ACTION_SELECT_USER_LIST)
intent.putExtra(EXTRA_ACCOUNT_KEY, account.key)
intent.putExtra(EXTRA_SHOW_MY_LISTS, true)
intent.setClass(context, UserListSelectorActivity::class.java)
fragment.startExtraConfigurationActivityForResult(this@UserListExtraConfiguration, intent, 1)
}

View File

@ -12,13 +12,8 @@ import kotlinx.android.synthetic.main.list_item_simple_user_list.view.*
class SimpleUserListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val createdByView: TextView
val nameView: TextView
val profileImageView: ImageView
val createdByView: TextView = itemView.createdBy
val nameView: TextView = itemView.name
val profileImageView: ImageView = itemView.profileImage
init {
nameView = itemView.name
createdByView = itemView.createdBy
profileImageView = itemView.profileImage
}
}

View File

@ -18,45 +18,16 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<merge
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:minWidth="@dimen/minimum_width_list_layout_content"
tools:context=".activity.UserListSelectorActivity">
<LinearLayout
android:id="@+id/userListsContainer"
<include
layout="@layout/layout_list_with_empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="?android:dividerVertical"
android:orientation="vertical"
android:showDividers="middle"
android:visibility="gone">
<ListView
android:id="@+id/userListsList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:id="@+id/createListContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="vertical"
android:visibility="gone">
<Button
android:id="@+id/createList"
style="?android:borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="@dimen/button_bar_height"
android:gravity="center"
android:text="@string/new_user_list"/>
</LinearLayout>
</LinearLayout>
</merge>
android:layout_height="match_parent"/>
</FrameLayout>

View File

@ -18,20 +18,20 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout
android:id="@+id/usersListContainer"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:minWidth="@dimen/minimum_width_list_layout_content"
android:orientation="vertical"
tools:context=".activity.UserSelectorActivity">
<LinearLayout
android:id="@+id/searchContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="@dimen/element_spacing_normal">
@ -61,6 +61,5 @@
<include
layout="@layout/layout_list_with_empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/searchContainer"/>
</RelativeLayout>
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -27,7 +27,8 @@
<FrameLayout
android:id="@+id/listContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:minWidth="@dimen/minimum_width_list_layout_content">
<ListView
android:id="@+id/listView"
@ -41,6 +42,8 @@
android:layout_height="match_parent"
android:clickable="true"
android:gravity="center"
android:minHeight="@dimen/minimum_height_list_layout_content"
android:minWidth="@dimen/minimum_width_list_layout_content"
android:orientation="vertical"
tools:visibility="visible">
@ -65,7 +68,9 @@
android:id="@+id/progressContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true">
android:clickable="true"
android:minHeight="@dimen/minimum_height_list_layout_content"
android:minWidth="@dimen/minimum_width_list_layout_content">
<ProgressBar
android:id="@+id/progressBar"

View File

@ -64,8 +64,8 @@
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profileImage"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"
android:layout_width="@dimen/icon_size_list_item_small"
android:layout_height="@dimen/icon_size_list_item_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:layout_weight="0"

View File

@ -1,104 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<dimen name="element_size_xsmall">16dp</dimen>
<dimen name="element_size_small">24dp</dimen>
<dimen name="element_size_msmall">36dp</dimen>
<dimen name="element_size_normal">48dp</dimen>
<dimen name="element_size_mlarge">64dp</dimen>
<dimen name="button_size_content_card">42dp</dimen>
<dimen name="button_size_content_card_action">36dp</dimen>
<!-- Element spacings (padding, margin) -->
<dimen name="element_spacing_xsmall">2dp</dimen>
<dimen name="element_spacing_small">4dp</dimen>
<dimen name="element_spacing_msmall">6dp</dimen>
<dimen name="element_spacing_normal">8dp</dimen>
<dimen name="element_spacing_mlarge">12dp</dimen>
<dimen name="element_spacing_large">16dp</dimen>
<dimen name="element_spacing_xlarge">24dp</dimen>
<dimen name="element_spacing_minus_xsmall">-2dp</dimen>
<dimen name="element_spacing_minus_small">-4dp</dimen>
<dimen name="element_spacing_minus_msmall">-6dp</dimen>
<dimen name="element_spacing_minus_normal">-8dp</dimen>
<dimen name="element_spacing_minus_mlarge">-12dp</dimen>
<dimen name="element_spacing_minus_large">-16dp</dimen>
<dimen name="element_spacing_minus_xlarge">-24dp</dimen>
<!-- Preferred size -->
<dimen name="preferred_tab_column_width">420dp</dimen>
<dimen name="icon_size_list_item">56dp</dimen>
<dimen name="icon_size_list_item_small">42dp</dimen>
<dimen name="icon_size_card_list_item">48dp</dimen>
<dimen name="icon_size_card_details">@dimen/element_size_mlarge</dimen>
<dimen name="icon_size_user_profile">84dp</dimen>
<dimen name="profile_image_size_activity_small">32dp</dimen>
<dimen name="default_sliding_menu_shadow_width">8dp</dimen>
<dimen name="default_sliding_menu_margin_threshold">16dp</dimen>
<dimen name="button_bar_height">52dp</dimen>
<dimen name="minimum_element_size">48dp</dimen>
<dimen name="drawer_width_home">288dp</dimen>
<dimen name="drawer_offset_home">72dp</dimen>
<dimen name="float_action_button_size">56dp</dimen>
<dimen name="float_action_button_icon_size">24dp</dimen>
<dimen name="action_button_size">56dp</dimen>
<dimen name="text_size_extra_small">12sp</dimen>
<!-- Size of icons in the top-level of settings -->
<dimen name="header_icon_width">28dp</dimen>
<!-- Dimensions for color picker -->
<dimen name="color_button_width">48dp</dimen>
<dimen name="color_button_height">48dp</dimen>
<!-- Dimensions for compose dialog -->
<dimen name="compose_min_width">400dp</dimen>
<!-- Dimensions for alert dialog -->
<dimen name="icon_size_alert_dialog">32dp</dimen>
<!-- Dimensions for quick menu -->
<dimen name="header_height_quick_menu">@dimen/element_size_normal</dimen>
<!-- Dimensions for buttons -->
<dimen name="button_width_content_min">72dp</dimen>
<dimen name="action_icon_size">32dp</dimen>
<dimen name="unread_indicator_size">16dp</dimen>
<dimen name="account_selector_popup_width">180dp</dimen>
<dimen name="icon_size_status_profile_image">48dp</dimen>
<dimen name="icon_size_profile_type">16dp</dimen>
<dimen name="icon_size_profile_type_detail">22dp</dimen>
<dimen name="icon_size_profile_type_user_profile">26dp</dimen>
<dimen name="icon_size_activity_type">16dp</dimen>
<dimen name="action_button_size">56dp</dimen>
<dimen name="action_icon_size">32dp</dimen>
<!-- Elevation values -->
<dimen name="elevation_card">2dp</dimen>
<dimen name="corner_radius_card">2dp</dimen>
<dimen name="padding_profile_image_detail_page">@dimen/element_spacing_small</dimen>
<dimen name="padding_profile_image_list_item">@dimen/element_spacing_small</dimen>
<dimen name="icon_size_profile_image_dashboard_current">72dp</dimen>
<dimen name="elevation_settings_item">0dp</dimen>
<dimen name="popup_width_account_selector">160dp</dimen>
<dimen name="line_width_compose_account_profile_image">2dp</dimen>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="height_player_control_panel">40dp</dimen>
<dimen name="toolbar_elevation">8dp</dimen>
<dimen name="button_bar_height">52dp</dimen>
<dimen name="button_size_content_card">42dp</dimen>
<dimen name="button_size_content_card_action">36dp</dimen>
<!-- Dimensions for buttons -->
<dimen name="button_width_content_min">72dp</dimen>
<dimen name="color_button_height">48dp</dimen>
<!-- Dimensions for color picker -->
<dimen name="color_button_width">48dp</dimen>
<!-- Dimensions for compose dialog -->
<dimen name="compose_min_width">400dp</dimen>
<dimen name="corner_radius_card">2dp</dimen>
<dimen name="default_sliding_menu_margin_threshold">16dp</dimen>
<dimen name="default_sliding_menu_shadow_width">8dp</dimen>
<dimen name="drawer_offset_home">72dp</dimen>
<dimen name="drawer_width_home">288dp</dimen>
<dimen name="element_size_mlarge">64dp</dimen>
<dimen name="element_size_msmall">36dp</dimen>
<dimen name="element_size_normal">48dp</dimen>
<dimen name="element_size_quick_search_bar_item_icon">40dp</dimen>
<dimen name="element_size_small">24dp</dimen>
<dimen name="element_size_xsmall">16dp</dimen>
<dimen name="element_spacing_large">16dp</dimen>
<dimen name="element_spacing_minus_large">-16dp</dimen>
<dimen name="element_spacing_minus_mlarge">-12dp</dimen>
<dimen name="element_spacing_minus_msmall">-6dp</dimen>
<dimen name="element_spacing_minus_normal">-8dp</dimen>
<dimen name="element_spacing_minus_small">-4dp</dimen>
<dimen name="element_spacing_minus_xlarge">-24dp</dimen>
<dimen name="element_spacing_minus_xsmall">-2dp</dimen>
<dimen name="element_spacing_mlarge">12dp</dimen>
<dimen name="element_spacing_msmall">6dp</dimen>
<dimen name="element_spacing_normal">8dp</dimen>
<dimen name="element_spacing_small">4dp</dimen>
<dimen name="element_spacing_xlarge">24dp</dimen>
<!-- Element spacings (padding, margin) -->
<dimen name="element_spacing_xsmall">2dp</dimen>
<!-- Elevation values -->
<dimen name="elevation_card">2dp</dimen>
<dimen name="elevation_settings_item">0dp</dimen>
<dimen name="float_action_button_icon_size">24dp</dimen>
<dimen name="float_action_button_size">56dp</dimen>
<!-- Dimensions for quick menu -->
<dimen name="header_height_quick_menu">@dimen/element_size_normal</dimen>
<!-- Size of icons in the top-level of settings -->
<dimen name="header_icon_width">28dp</dimen>
<dimen name="height_player_control_panel">40dp</dimen>
<dimen name="home_page_margin">1dp</dimen>
<dimen name="settings_panel_width_entries">240dp</dimen>
<dimen name="settings_panel_margin_start_details">@dimen/element_size_normal</dimen>
<dimen name="icon_size_activity_type">16dp</dimen>
<!-- Dimensions for alert dialog -->
<dimen name="icon_size_alert_dialog">32dp</dimen>
<dimen name="icon_size_card_details">@dimen/element_size_mlarge</dimen>
<dimen name="icon_size_card_list_item">48dp</dimen>
<dimen name="icon_size_list_item">56dp</dimen>
<dimen name="icon_size_list_item_small">42dp</dimen>
<dimen name="icon_size_profile_image_dashboard_current">72dp</dimen>
<dimen name="icon_size_profile_type">16dp</dimen>
<dimen name="icon_size_profile_type_detail">22dp</dimen>
<dimen name="icon_size_profile_type_user_profile">26dp</dimen>
<dimen name="icon_size_status_profile_image">48dp</dimen>
<dimen name="icon_size_user_profile">84dp</dimen>
</resources>
<dimen name="line_width_compose_account_profile_image">2dp</dimen>
<dimen name="minimum_element_size">48dp</dimen>
<dimen name="minimum_height_list_layout_content">300dp</dimen>
<dimen name="minimum_width_list_layout_content">300dp</dimen>
<dimen name="padding_profile_image_detail_page">@dimen/element_spacing_small</dimen>
<dimen name="padding_profile_image_list_item">@dimen/element_spacing_small</dimen>
<dimen name="popup_width_account_selector">160dp</dimen>
<!-- Preferred size -->
<dimen name="preferred_tab_column_width">420dp</dimen>
<dimen name="profile_image_size_activity_small">32dp</dimen>
<dimen name="settings_panel_margin_start_details">@dimen/element_size_normal</dimen>
<dimen name="settings_panel_width_entries">240dp</dimen>
<dimen name="text_size_extra_small">12sp</dimen>
<dimen name="toolbar_elevation">8dp</dimen>
<dimen name="unread_indicator_size">16dp</dimen>
</resources>

View File

@ -82,6 +82,7 @@
<string name="action_saving_search">saving search</string>
<string name="action_select_all">Select all</string>
<string name="action_select_none">Select none</string>
<string name="action_select_user">Select user</string>
<!-- [verb] Send tweet/message -->
<string name="action_send">Send</string>
<string name="action_sending_direct_message">sending direct message</string>
@ -486,9 +487,6 @@
<string name="following_you">Following you</string>
<string name="follows">Follows</string>
<string name="title_user_list_subscriptions">Subscriptions</string>
<string name="title_user_list_memberships">Belongs to</string>
<string name="title_user_list_ownerships">Created</string>
<string name="font">Font</string>
<string name="font_family">Font family</string>
@ -1219,6 +1217,9 @@
<string name="title_sync_settings">Sync settings</string>
<string name="title_user">User</string>
<string name="title_user_colors">User colors</string>
<string name="title_user_list_memberships">Belongs to</string>
<string name="title_user_list_ownerships">Created</string>
<string name="title_user_list_subscriptions">Subscriptions</string>
<string name="title_users_favorited_this">Users favorited this</string>
<string name="title_users_liked_this">Users liked this</string>
<string name="title_users_retweeted_this">Users retweeted this</string>