parent
31543f1d25
commit
4ca81cac7d
|
@ -57,7 +57,8 @@ subprojects {
|
|||
MediaViewerLibrary: '0.9.23',
|
||||
MultiValueSwitch : '0.9.8',
|
||||
PickNCrop : '0.9.22',
|
||||
AndroidGIFDrawable: '1.2.6'
|
||||
AndroidGIFDrawable: '1.2.6',
|
||||
KPreferences : '0.9.6'
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -30,11 +30,6 @@ public class StatusUpdate extends SimpleValueMap {
|
|||
put("status", status);
|
||||
}
|
||||
|
||||
public StatusUpdate displayCoordinates(final boolean displayCoordinates) {
|
||||
setDisplayCoordinates(displayCoordinates);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setInReplyToStatusId(final String inReplyToStatusId) {
|
||||
put("in_reply_to_status_id", inReplyToStatusId);
|
||||
}
|
||||
|
@ -43,14 +38,6 @@ public class StatusUpdate extends SimpleValueMap {
|
|||
put("repost_status_id", repostStatusId);
|
||||
}
|
||||
|
||||
public void setLocation(final GeoLocation location) {
|
||||
remove("lat");
|
||||
remove("long");
|
||||
if (location == null) return;
|
||||
put("lat", location.getLatitude());
|
||||
put("long", location.getLongitude());
|
||||
}
|
||||
|
||||
public void setMediaIds(final String... mediaIds) {
|
||||
remove("media_ids");
|
||||
if (mediaIds == null) return;
|
||||
|
@ -71,17 +58,22 @@ public class StatusUpdate extends SimpleValueMap {
|
|||
}
|
||||
|
||||
|
||||
public void setDisplayCoordinates(final boolean displayCoordinates) {
|
||||
public StatusUpdate displayCoordinates(final boolean displayCoordinates) {
|
||||
put("display_coordinates", displayCoordinates);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public void setPossiblySensitive(final boolean possiblySensitive) {
|
||||
put("possibly_sensitive", possiblySensitive);
|
||||
public StatusUpdate autoPopulateReplyMetadata(final boolean autoPopulateReplyMetadata) {
|
||||
put("auto_populate_reply_metadata", autoPopulateReplyMetadata);
|
||||
return this;
|
||||
}
|
||||
|
||||
public StatusUpdate location(final GeoLocation location) {
|
||||
setLocation(location);
|
||||
remove("lat");
|
||||
remove("long");
|
||||
if (location == null) return this;
|
||||
put("lat", location.getLatitude());
|
||||
put("long", location.getLongitude());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -101,7 +93,7 @@ public class StatusUpdate extends SimpleValueMap {
|
|||
}
|
||||
|
||||
public StatusUpdate possiblySensitive(final boolean possiblySensitive) {
|
||||
setPossiblySensitive(possiblySensitive);
|
||||
put("possibly_sensitive", possiblySensitive);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ dependencies {
|
|||
compile "com.github.mariotaku.CommonsLibrary:io:${libVersions['MariotakuCommons']}"
|
||||
compile "com.github.mariotaku.CommonsLibrary:text:${libVersions['MariotakuCommons']}"
|
||||
compile "com.github.mariotaku.CommonsLibrary:text-kotlin:${libVersions['MariotakuCommons']}"
|
||||
compile 'com.github.mariotaku:KPreferences:0.9.5'
|
||||
compile "com.github.mariotaku:KPreferences:${libVersions['KPreferences']}"
|
||||
compile 'com.github.mariotaku:Chameleon:0.9.16'
|
||||
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:${libVersions['Kotlin']}"
|
||||
|
|
|
@ -33,6 +33,9 @@ public class DefaultFeatures {
|
|||
@JsonField(name = "media_link_counts_in_status")
|
||||
boolean mediaLinkCountsInStatus = false;
|
||||
|
||||
@JsonField(name = "mentions_counts_in_status")
|
||||
boolean mentionsCountsInStatus = false;
|
||||
|
||||
@JsonField(name = "default_twitter_consumer_key")
|
||||
String defaultTwitterConsumerKey;
|
||||
|
||||
|
@ -49,6 +52,10 @@ public class DefaultFeatures {
|
|||
return mediaLinkCountsInStatus;
|
||||
}
|
||||
|
||||
public boolean isMentionsCountsInStatus() {
|
||||
return mentionsCountsInStatus;
|
||||
}
|
||||
|
||||
public String getDefaultTwitterConsumerKey() {
|
||||
return defaultTwitterConsumerKey;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.model.timeline;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/3/31.
|
||||
*/
|
||||
|
||||
public interface TimelineFilter extends Parcelable {
|
||||
CharSequence getSummary(Context context);
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.model.timeline;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
|
||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/3/31.
|
||||
*/
|
||||
@ParcelablePlease
|
||||
public class UserTimelineFilter implements TimelineFilter, Parcelable {
|
||||
@ParcelableThisPlease
|
||||
boolean includeRetweets = true;
|
||||
@ParcelableThisPlease
|
||||
boolean includeReplies = true;
|
||||
|
||||
public boolean isIncludeRetweets() {
|
||||
return includeRetweets;
|
||||
}
|
||||
|
||||
public void setIncludeRetweets(final boolean includeRetweets) {
|
||||
this.includeRetweets = includeRetweets;
|
||||
}
|
||||
|
||||
public boolean isIncludeReplies() {
|
||||
return includeReplies;
|
||||
}
|
||||
|
||||
public void setIncludeReplies(final boolean includeReplies) {
|
||||
this.includeReplies = includeReplies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary(final Context context) {
|
||||
if (includeRetweets && includeReplies) {
|
||||
return context.getString(R.string.label_statuses_retweets_replies);
|
||||
} else if (includeReplies) {
|
||||
return context.getString(R.string.label_statuses_replies);
|
||||
}
|
||||
return context.getString(R.string.label_statuses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
UserTimelineFilterParcelablePlease.writeToParcel(this, dest, flags);
|
||||
}
|
||||
|
||||
public static final Creator<UserTimelineFilter> CREATOR = new Creator<UserTimelineFilter>() {
|
||||
public UserTimelineFilter createFromParcel(Parcel source) {
|
||||
UserTimelineFilter target = new UserTimelineFilter();
|
||||
UserTimelineFilterParcelablePlease.readFromParcel(target, source);
|
||||
return target;
|
||||
}
|
||||
|
||||
public UserTimelineFilter[] newArray(int size) {
|
||||
return new UserTimelineFilter[size];
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1434,7 +1434,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
val accountKeys = accountsAdapter.selectedAccountKeys
|
||||
val accounts = AccountUtils.getAllAccountDetails(AccountManager.get(this), accountKeys, true)
|
||||
val ignoreMentions = accounts.all { it.type == AccountType.TWITTER }
|
||||
val tweetLength = validator.getTweetLength(text, ignoreMentions)
|
||||
val tweetLength = validator.getTweetLength(text, ignoreMentions &&
|
||||
defaultFeatures.isMentionsCountsInStatus)
|
||||
val maxLength = statusTextCount.maxLength
|
||||
if (accountsAdapter.isSelectionEmpty) {
|
||||
editText.error = getString(R.string.message_toast_no_account_selected)
|
||||
|
@ -1491,10 +1492,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
private fun updateTextCount() {
|
||||
val am = AccountManager.get(this)
|
||||
val text = editText.text?.toString() ?: return
|
||||
val ignoreMentions = accountsAdapter.selectedAccountKeys.all {
|
||||
val ignoreMentions = inReplyToStatus != null && accountsAdapter.selectedAccountKeys.all {
|
||||
val account = AccountUtils.findByAccountKey(am, it) ?: return@all false
|
||||
return@all account.getAccountType(am) == AccountType.TWITTER
|
||||
}
|
||||
} && defaultFeatures.isMentionsCountsInStatus
|
||||
statusTextCount.textCount = validator.getTweetLength(text, ignoreMentions)
|
||||
}
|
||||
|
||||
|
|
|
@ -40,13 +40,19 @@ import org.mariotaku.twidere.adapter.iface.IStatusesAdapter
|
|||
import org.mariotaku.twidere.annotation.PreviewStyle
|
||||
import org.mariotaku.twidere.constant.*
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_DISPLAY_SENSITIVE_CONTENTS
|
||||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.ItemCounts
|
||||
import org.mariotaku.twidere.model.ObjectId
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.timeline.TimelineFilter
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
||||
import org.mariotaku.twidere.util.StatusAdapterLinkClickHandler
|
||||
import org.mariotaku.twidere.util.TwidereLinkify
|
||||
import org.mariotaku.twidere.util.Utils
|
||||
import org.mariotaku.twidere.view.holder.EmptyViewHolder
|
||||
import org.mariotaku.twidere.view.holder.GapViewHolder
|
||||
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder
|
||||
import org.mariotaku.twidere.view.holder.TimelineFilterHeaderViewHolder
|
||||
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
|
||||
import java.util.*
|
||||
|
||||
|
@ -56,8 +62,8 @@ import java.util.*
|
|||
abstract class ParcelableStatusesAdapter(
|
||||
context: Context,
|
||||
requestManager: RequestManager
|
||||
) : LoadMoreSupportAdapter<RecyclerView.ViewHolder>(context, requestManager), IStatusesAdapter<List<ParcelableStatus>>,
|
||||
IItemCountsAdapter {
|
||||
) : LoadMoreSupportAdapter<RecyclerView.ViewHolder>(context, requestManager),
|
||||
IStatusesAdapter<List<ParcelableStatus>>, IItemCountsAdapter {
|
||||
|
||||
protected val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||
|
||||
|
@ -105,6 +111,12 @@ abstract class ParcelableStatusesAdapter(
|
|||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
var timelineFilter: TimelineFilter? = null
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private var data: List<ParcelableStatus>? = null
|
||||
private var displayPositions: IntArray? = null
|
||||
private var displayDataCount: Int = 0
|
||||
|
@ -112,7 +124,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
|
||||
private var showingActionCardId = RecyclerView.NO_ID
|
||||
|
||||
override val itemCounts = ItemCounts(4)
|
||||
override val itemCounts = ItemCounts(5)
|
||||
|
||||
val statusStartIndex: Int
|
||||
get() = getItemStartPosition(ITEM_INDEX_STATUS)
|
||||
|
@ -148,8 +160,8 @@ abstract class ParcelableStatusesAdapter(
|
|||
if (data is ObjectCursor) {
|
||||
val cursor = (data as ObjectCursor).cursor
|
||||
if (!cursor.moveToPosition(dataPosition)) return false
|
||||
val indices = (data as ObjectCursor).indices as ParcelableStatusCursorIndices
|
||||
return cursor.getShort(indices.is_gap).toInt() == 1
|
||||
val indices = (data as ObjectCursor).indices
|
||||
return cursor.getShort(indices[Statuses.STATUS_ID]).toInt() == 1
|
||||
}
|
||||
return getStatus(position).is_gap
|
||||
}
|
||||
|
@ -205,8 +217,8 @@ abstract class ParcelableStatusesAdapter(
|
|||
return mask + status.hashCode()
|
||||
}
|
||||
ITEM_INDEX_STATUS -> return getFieldValue(position, { cursor, indices ->
|
||||
val accountKey = UserKey.valueOf(cursor.getString(indices.account_key))
|
||||
val id = cursor.getString(indices.id)
|
||||
val accountKey = UserKey.valueOf(cursor.getString(indices[Statuses.ACCOUNT_KEY]))
|
||||
val id = cursor.getString(indices[Statuses.STATUS_ID])
|
||||
return@getFieldValue ParcelableStatus.calculateHashCode(accountKey, id).toLong()
|
||||
}, { status ->
|
||||
return@getFieldValue status.hashCode().toLong()
|
||||
|
@ -217,7 +229,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
|
||||
override fun getStatusId(position: Int, raw: Boolean): String {
|
||||
return getFieldValue(position, { cursor, indices ->
|
||||
return@getFieldValue cursor.getString(indices.id)
|
||||
return@getFieldValue cursor.getString(indices[Statuses.STATUS_ID])
|
||||
}, { status ->
|
||||
return@getFieldValue status.id
|
||||
}, "")
|
||||
|
@ -225,7 +237,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
|
||||
fun getStatusSortId(position: Int, raw: Boolean): Long {
|
||||
return getFieldValue(position, { cursor, indices ->
|
||||
return@getFieldValue cursor.safeGetLong(indices.sort_id)
|
||||
return@getFieldValue cursor.safeGetLong(indices[Statuses.SORT_ID])
|
||||
}, { status ->
|
||||
return@getFieldValue status.sort_id
|
||||
}, -1L, raw)
|
||||
|
@ -233,7 +245,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
|
||||
override fun getStatusTimestamp(position: Int, raw: Boolean): Long {
|
||||
return getFieldValue(position, { cursor, indices ->
|
||||
return@getFieldValue cursor.safeGetLong(indices.timestamp)
|
||||
return@getFieldValue cursor.safeGetLong(indices[Statuses.STATUS_TIMESTAMP])
|
||||
}, { status ->
|
||||
return@getFieldValue status.timestamp
|
||||
}, -1L)
|
||||
|
@ -241,9 +253,9 @@ abstract class ParcelableStatusesAdapter(
|
|||
|
||||
override fun getStatusPositionKey(position: Int, raw: Boolean): Long {
|
||||
return getFieldValue(position, { cursor, indices ->
|
||||
val positionKey = cursor.safeGetLong(indices.position_key)
|
||||
val positionKey = cursor.safeGetLong(indices[Statuses.POSITION_KEY])
|
||||
if (positionKey > 0) return@getFieldValue positionKey
|
||||
return@getFieldValue cursor.safeGetLong(indices.timestamp)
|
||||
return@getFieldValue cursor.safeGetLong(indices[Statuses.STATUS_TIMESTAMP])
|
||||
}, { status ->
|
||||
val positionKey = status.position_key
|
||||
if (positionKey > 0) return@getFieldValue positionKey
|
||||
|
@ -254,7 +266,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
override fun getAccountKey(position: Int, raw: Boolean): UserKey {
|
||||
val def: UserKey? = null
|
||||
return getFieldValue(position, { cursor, indices ->
|
||||
return@getFieldValue UserKey.valueOf(cursor.getString(indices.account_key))
|
||||
return@getFieldValue UserKey.valueOf(cursor.getString(indices[Statuses.ACCOUNT_KEY]))
|
||||
}, { status ->
|
||||
return@getFieldValue status.account_key
|
||||
}, def, raw)!!
|
||||
|
@ -281,9 +293,6 @@ abstract class ParcelableStatusesAdapter(
|
|||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
when (viewType) {
|
||||
VIEW_TYPE_STATUS -> {
|
||||
return onCreateStatusViewHolder(parent) as RecyclerView.ViewHolder
|
||||
}
|
||||
ITEM_VIEW_TYPE_GAP -> {
|
||||
val view = inflater.inflate(GapViewHolder.layoutResource, parent, false)
|
||||
return GapViewHolder(this, view)
|
||||
|
@ -292,9 +301,17 @@ abstract class ParcelableStatusesAdapter(
|
|||
val view = inflater.inflate(R.layout.list_item_load_indicator, parent, false)
|
||||
return LoadIndicatorViewHolder(view)
|
||||
}
|
||||
VIEW_TYPE_STATUS -> {
|
||||
return onCreateStatusViewHolder(parent) as RecyclerView.ViewHolder
|
||||
}
|
||||
VIEW_TYPE_EMPTY -> {
|
||||
return EmptyViewHolder(Space(context))
|
||||
}
|
||||
VIEW_TYPE_FILTER_HEADER -> {
|
||||
val view = inflater.inflate(TimelineFilterHeaderViewHolder.layoutResource,
|
||||
parent, false)
|
||||
return TimelineFilterHeaderViewHolder(this, view)
|
||||
}
|
||||
}
|
||||
throw IllegalStateException("Unknown view type " + viewType)
|
||||
}
|
||||
|
@ -307,6 +324,9 @@ abstract class ParcelableStatusesAdapter(
|
|||
(holder as IStatusViewHolder).displayStatus(status, displayInReplyTo = isShowInReplyTo,
|
||||
displayPinned = countIdx == ITEM_INDEX_PINNED_STATUS)
|
||||
}
|
||||
VIEW_TYPE_FILTER_HEADER -> {
|
||||
(holder as TimelineFilterHeaderViewHolder).display(timelineFilter!!)
|
||||
}
|
||||
ITEM_VIEW_TYPE_GAP -> {
|
||||
val status = getStatus(position)
|
||||
val loading = gapLoadingIds.any { it.accountKey == status.account_key && it.id == status.id }
|
||||
|
@ -333,6 +353,9 @@ abstract class ParcelableStatusesAdapter(
|
|||
return VIEW_TYPE_STATUS
|
||||
}
|
||||
}
|
||||
ITEM_INDEX_FILTER_HEADER -> {
|
||||
return VIEW_TYPE_FILTER_HEADER
|
||||
}
|
||||
}
|
||||
throw AssertionError()
|
||||
}
|
||||
|
@ -404,7 +427,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
}
|
||||
|
||||
private inline fun <T> getFieldValue(position: Int,
|
||||
readCursorValueAction: (cursor: Cursor, indices: ParcelableStatusCursorIndices) -> T,
|
||||
readCursorValueAction: (cursor: Cursor, indices: ObjectCursor.CursorIndices<ParcelableStatus>) -> T,
|
||||
readStatusValueAction: (status: ParcelableStatus) -> T,
|
||||
defValue: T, raw: Boolean = false): T {
|
||||
if (data is ObjectCursor) {
|
||||
|
@ -414,7 +437,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
}
|
||||
val cursor = (data as ObjectCursor).cursor
|
||||
if (!cursor.safeMoveToPosition(dataPosition)) return defValue
|
||||
val indices = (data as ObjectCursor).indices as ParcelableStatusCursorIndices
|
||||
val indices = (data as ObjectCursor).indices
|
||||
return readCursorValueAction(cursor, indices)
|
||||
}
|
||||
return readStatusValueAction(getStatus(position, raw))
|
||||
|
@ -443,6 +466,7 @@ abstract class ParcelableStatusesAdapter(
|
|||
|
||||
private fun updateItemCount() {
|
||||
itemCounts[ITEM_INDEX_LOAD_START_INDICATOR] = if (ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) 1 else 0
|
||||
itemCounts[ITEM_INDEX_FILTER_HEADER] = if (timelineFilter != null) 1 else 0
|
||||
itemCounts[ITEM_INDEX_PINNED_STATUS] = pinnedStatuses?.size ?: 0
|
||||
itemCounts[ITEM_INDEX_STATUS] = getStatusCount(false)
|
||||
itemCounts[ITEM_INDEX_LOAD_END_INDICATOR] = if (ILoadMoreSupportAdapter.END in loadMoreIndicatorPosition) 1 else 0
|
||||
|
@ -451,11 +475,13 @@ abstract class ParcelableStatusesAdapter(
|
|||
companion object {
|
||||
const val VIEW_TYPE_STATUS = 2
|
||||
const val VIEW_TYPE_EMPTY = 3
|
||||
const val VIEW_TYPE_FILTER_HEADER = 4
|
||||
|
||||
const val ITEM_INDEX_LOAD_START_INDICATOR = 0
|
||||
const val ITEM_INDEX_PINNED_STATUS = 1
|
||||
const val ITEM_INDEX_STATUS = 2
|
||||
const val ITEM_INDEX_LOAD_END_INDICATOR = 3
|
||||
const val ITEM_INDEX_FILTER_HEADER = 1
|
||||
const val ITEM_INDEX_PINNED_STATUS = 2
|
||||
const val ITEM_INDEX_STATUS = 3
|
||||
const val ITEM_INDEX_LOAD_END_INDICATOR = 4
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.mariotaku.twidere.constant
|
|||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.support.v4.util.ArraySet
|
||||
import android.text.TextUtils
|
||||
import org.apache.commons.lang3.LocaleUtils
|
||||
import org.mariotaku.kpreferences.*
|
||||
|
@ -18,6 +19,7 @@ import org.mariotaku.twidere.model.CustomAPIConfig
|
|||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.account.cred.Credentials
|
||||
import org.mariotaku.twidere.model.sync.SyncProviderInfo
|
||||
import org.mariotaku.twidere.model.timeline.UserTimelineFilter
|
||||
import org.mariotaku.twidere.preference.ThemeBackgroundPreference
|
||||
import org.mariotaku.twidere.util.sync.SyncProviderInfoFactory
|
||||
import java.util.*
|
||||
|
@ -242,3 +244,28 @@ object composeAccountsKey : KSimpleKey<Array<UserKey>?>(KEY_COMPOSE_ACCOUNTS, nu
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
object userTimelineFilterKey : KSimpleKey<UserTimelineFilter>("user_timeline_filter", UserTimelineFilter()) {
|
||||
override fun read(preferences: SharedPreferences): UserTimelineFilter {
|
||||
val rawString = preferences.getString(key, null) ?: return def
|
||||
val options = rawString.split(",")
|
||||
return UserTimelineFilter().apply {
|
||||
isIncludeReplies = "replies" in options
|
||||
isIncludeRetweets = "retweets" in options
|
||||
}
|
||||
}
|
||||
|
||||
override fun write(editor: SharedPreferences.Editor, value: UserTimelineFilter): Boolean {
|
||||
val options = ArraySet<String>().apply {
|
||||
if (value.isIncludeReplies) {
|
||||
add("replies")
|
||||
}
|
||||
if (value.isIncludeRetweets) {
|
||||
add("retweets")
|
||||
}
|
||||
}.joinToString(",")
|
||||
editor.putString(key, options)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
|
@ -57,6 +57,7 @@ import org.mariotaku.twidere.loader.iface.IExtendedLoader
|
|||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.analyzer.Share
|
||||
import org.mariotaku.twidere.model.event.StatusListChangedEvent
|
||||
import org.mariotaku.twidere.model.timeline.TimelineFilter
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
||||
import org.mariotaku.twidere.util.*
|
||||
|
@ -127,6 +128,10 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
|||
get() = (parentFragment as? StatusesFragmentDelegate)?.shouldInitLoader ?: true
|
||||
|
||||
|
||||
protected open val enableTimelineFilter: Boolean = false
|
||||
|
||||
protected open val timelineFilter: TimelineFilter? = null
|
||||
|
||||
// Fragment life cycles
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
@ -311,6 +316,7 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
|||
}
|
||||
// 2. Change adapter data
|
||||
adapterData = data
|
||||
adapter.timelineFilter = timelineFilter
|
||||
|
||||
refreshEnabled = true
|
||||
|
||||
|
@ -490,7 +496,8 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
|||
protected fun saveReadPosition(position: Int) {
|
||||
if (host == null) return
|
||||
if (position == RecyclerView.NO_POSITION || adapter.getStatusCount(false) <= 0) return
|
||||
val status = adapter.getStatus(position)
|
||||
val status = adapter.getStatus(position.coerceIn(rangeOfSize(adapter.statusStartIndex,
|
||||
adapter.getStatusCount(false))))
|
||||
val readPosition = if (useSortIdAsReadPosition) {
|
||||
status.sort_id
|
||||
} else {
|
||||
|
|
|
@ -49,7 +49,6 @@ import org.mariotaku.twidere.constant.IntentConstants.*
|
|||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_QUICK_SEND
|
||||
import org.mariotaku.twidere.extension.applyTheme
|
||||
import org.mariotaku.twidere.extension.getTweetLength
|
||||
import org.mariotaku.twidere.extension.model.getAccountType
|
||||
import org.mariotaku.twidere.extension.model.textLimit
|
||||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
|
@ -200,9 +199,7 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
|
|||
}
|
||||
val textCountView = dialog.findViewById(R.id.commentTextCount) as StatusTextCountView
|
||||
val am = AccountManager.get(context)
|
||||
val ignoreMentions = AccountUtils.findByAccountKey(am, accountKey)?.getAccountType(am) ==
|
||||
AccountType.TWITTER
|
||||
textCountView.textCount = validator.getTweetLength(s.toString(), ignoreMentions)
|
||||
textCountView.textCount = validator.getTweetLength(s.toString(), false)
|
||||
}
|
||||
|
||||
private val status: ParcelableStatus
|
||||
|
|
|
@ -1425,22 +1425,12 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
|
|||
tabArgs.putParcelable(EXTRA_USER_KEY, args.getParcelable<Parcelable>(EXTRA_USER_KEY))
|
||||
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME))
|
||||
}
|
||||
if (userKey?.host == USER_TYPE_TWITTER_COM) {
|
||||
pagerAdapter.add(cls = UserTimelineFragment::class.java, args = Bundle(tabArgs).apply {
|
||||
putBoolean(EXTRA_EXCLUDE_REPLIES, true)
|
||||
this[UserTimelineFragment.EXTRA_ENABLE_TIMELINE_FILTER] = true
|
||||
}, name = getString(R.string.title_statuses), type = TAB_TYPE_STATUSES,
|
||||
position = TAB_POSITION_STATUSES)
|
||||
pagerAdapter.add(cls = UserTimelineFragment::class.java, args = tabArgs,
|
||||
name = getString(R.string.title_statuses_and_replies), type = TAB_TYPE_STATUSES_WITH_REPLIES,
|
||||
position = TAB_POSITION_STATUSES)
|
||||
} else {
|
||||
pagerAdapter.add(cls = UserTimelineFragment::class.java, args = tabArgs,
|
||||
name = getString(R.string.title_statuses), type = TAB_TYPE_STATUSES,
|
||||
position = TAB_POSITION_STATUSES)
|
||||
}
|
||||
pagerAdapter.add(cls = UserMediaTimelineFragment::class.java, args = tabArgs,
|
||||
name = getString(R.string.media), type = TAB_TYPE_MEDIA,
|
||||
position = TAB_POSITION_MEDIA)
|
||||
name = getString(R.string.media), type = TAB_TYPE_MEDIA, position = TAB_POSITION_MEDIA)
|
||||
if (preferences.getBoolean(KEY_I_WANT_MY_STARS_BACK)) {
|
||||
pagerAdapter.add(cls = UserFavoritesFragment::class.java, args = tabArgs,
|
||||
name = getString(R.string.title_favorites), type = TAB_TYPE_FAVORITES,
|
||||
|
|
|
@ -9,9 +9,11 @@ import android.support.v7.widget.RecyclerView
|
|||
import android.support.v7.widget.StaggeredGridLayoutManager
|
||||
import android.text.TextUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.twidere.adapter.StaggeredGridParcelableStatusesAdapter
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.constant.IntentConstants.*
|
||||
import org.mariotaku.twidere.constant.userTimelineFilterKey
|
||||
import org.mariotaku.twidere.extensions.reachingEnd
|
||||
import org.mariotaku.twidere.extensions.reachingStart
|
||||
import org.mariotaku.twidere.loader.MediaTimelineLoader
|
||||
|
|
|
@ -19,15 +19,25 @@
|
|||
|
||||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.content.Loader
|
||||
import android.support.v7.app.AlertDialog
|
||||
import edu.tsinghua.hotmobi.model.TimelineType
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.kpreferences.set
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.*
|
||||
import org.mariotaku.twidere.constant.userTimelineFilterKey
|
||||
import org.mariotaku.twidere.extension.applyTheme
|
||||
import org.mariotaku.twidere.loader.UserTimelineLoader
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.timeline.TimelineFilter
|
||||
import org.mariotaku.twidere.model.timeline.UserTimelineFilter
|
||||
import org.mariotaku.twidere.util.Utils
|
||||
import org.mariotaku.twidere.view.holder.TimelineFilterHeaderViewHolder
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
|
@ -42,11 +52,9 @@ class UserTimelineFragment : ParcelableStatusesFragment() {
|
|||
|
||||
override val savedStatusesFileArgs: Array<String>?
|
||||
get() {
|
||||
val args = arguments!!
|
||||
val accountKey = Utils.getAccountKey(context, args)!!
|
||||
val userKey = args.getParcelable<UserKey>(EXTRA_USER_KEY)
|
||||
val screenName = args.getString(EXTRA_SCREEN_NAME)
|
||||
val excludeReplies = args.getBoolean(EXTRA_EXCLUDE_REPLIES)
|
||||
val accountKey = Utils.getAccountKey(context, arguments)!!
|
||||
val userKey = arguments.getParcelable<UserKey>(EXTRA_USER_KEY)
|
||||
val screenName = arguments.getString(EXTRA_SCREEN_NAME)
|
||||
val result = ArrayList<String>()
|
||||
result.add(AUTHORITY_USER_TIMELINE)
|
||||
result.add("account=$accountKey")
|
||||
|
@ -57,21 +65,24 @@ class UserTimelineFragment : ParcelableStatusesFragment() {
|
|||
} else {
|
||||
return null
|
||||
}
|
||||
if (excludeReplies) {
|
||||
result.add("exclude_replies")
|
||||
(timelineFilter as? UserTimelineFilter)?.let {
|
||||
if (it.isIncludeReplies) {
|
||||
result.add("include_replies")
|
||||
}
|
||||
if (it.isIncludeRetweets) {
|
||||
result.add("include_retweets")
|
||||
}
|
||||
}
|
||||
return result.toTypedArray()
|
||||
}
|
||||
|
||||
override val readPositionTagWithArguments: String?
|
||||
get() {
|
||||
val args = arguments!!
|
||||
val tabPosition = args.getInt(EXTRA_TAB_POSITION, -1)
|
||||
if (arguments.getLong(EXTRA_TAB_ID, -1) < 0) return null
|
||||
val sb = StringBuilder("user_timeline_")
|
||||
if (tabPosition < 0) return null
|
||||
|
||||
val userKey = args.getParcelable<UserKey>(EXTRA_USER_KEY)
|
||||
val screenName = args.getString(EXTRA_SCREEN_NAME)
|
||||
val userKey = arguments.getParcelable<UserKey>(EXTRA_USER_KEY)
|
||||
val screenName = arguments.getString(EXTRA_SCREEN_NAME)
|
||||
if (userKey != null) {
|
||||
sb.append(userKey)
|
||||
} else if (screenName != null) {
|
||||
|
@ -82,6 +93,12 @@ class UserTimelineFragment : ParcelableStatusesFragment() {
|
|||
return sb.toString()
|
||||
}
|
||||
|
||||
override val enableTimelineFilter: Boolean
|
||||
get() = arguments.getBoolean(EXTRA_ENABLE_TIMELINE_FILTER)
|
||||
|
||||
override val timelineFilter: TimelineFilter?
|
||||
get() = if (enableTimelineFilter) preferences[userTimelineFilterKey] else null
|
||||
|
||||
override fun onCreateStatusesLoader(context: Context, args: Bundle, fromUser: Boolean):
|
||||
Loader<List<ParcelableStatus>?> {
|
||||
refreshing = true
|
||||
|
@ -93,10 +110,10 @@ class UserTimelineFragment : ParcelableStatusesFragment() {
|
|||
val screenName = args.getString(EXTRA_SCREEN_NAME)
|
||||
val tabPosition = args.getInt(EXTRA_TAB_POSITION, -1)
|
||||
val loadingMore = args.getBoolean(EXTRA_LOADING_MORE, false)
|
||||
val excludeReplies = args.getBoolean(EXTRA_EXCLUDE_REPLIES, false)
|
||||
val pinnedIds = if (adapter.hasPinnedStatuses) null else pinnedStatusIds
|
||||
return UserTimelineLoader(context, accountKey, userKey, screenName, sinceId, maxId, data,
|
||||
savedStatusesFileArgs, tabPosition, fromUser, loadingMore, pinnedIds, excludeReplies)
|
||||
savedStatusesFileArgs, tabPosition, fromUser, loadingMore, pinnedIds,
|
||||
timelineFilter as? UserTimelineFilter)
|
||||
}
|
||||
|
||||
override fun onStatusesLoaded(loader: Loader<List<ParcelableStatus>?>, data: List<ParcelableStatus>?) {
|
||||
|
@ -107,7 +124,63 @@ class UserTimelineFragment : ParcelableStatusesFragment() {
|
|||
super.onStatusesLoaded(loader, data)
|
||||
}
|
||||
|
||||
override fun onFilterClick(holder: TimelineFilterHeaderViewHolder) {
|
||||
val df = UserTimelineFilterDialogFragment()
|
||||
df.setTargetFragment(this, REQUEST_SET_TIMELINE_FILTER)
|
||||
df.show(childFragmentManager, "set_timeline_filter")
|
||||
}
|
||||
|
||||
private fun reloadAllStatuses() {
|
||||
adapterData = null
|
||||
triggerRefresh()
|
||||
showProgress()
|
||||
}
|
||||
|
||||
interface UserTimelineFragmentDelegate {
|
||||
val pinnedStatusIds: Array<String>?
|
||||
|
||||
}
|
||||
|
||||
class UserTimelineFilterDialogFragment : BaseDialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val builder = AlertDialog.Builder(context)
|
||||
val values = resources.getStringArray(R.array.values_user_timeline_filter)
|
||||
val checkedItems = BooleanArray(values.size) {
|
||||
val filter = preferences[userTimelineFilterKey]
|
||||
when (values[it]) {
|
||||
"replies" -> filter.isIncludeReplies
|
||||
"retweets" -> filter.isIncludeRetweets
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
builder.setTitle(R.string.title_user_timeline_filter)
|
||||
builder.setMultiChoiceItems(R.array.entries_user_timeline_filter, checkedItems, null)
|
||||
builder.setNegativeButton(android.R.string.cancel, null)
|
||||
builder.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
||||
dialog as AlertDialog
|
||||
val listView = dialog.listView
|
||||
val filter = UserTimelineFilter().apply {
|
||||
isIncludeRetweets = listView.isItemChecked(values.indexOf("retweets"))
|
||||
isIncludeReplies = listView.isItemChecked(values.indexOf("replies"))
|
||||
}
|
||||
preferences.edit().apply {
|
||||
this[userTimelineFilterKey] = filter
|
||||
}.apply()
|
||||
(targetFragment as UserTimelineFragment).reloadAllStatuses()
|
||||
}
|
||||
val dialog = builder.create()
|
||||
dialog.setOnShowListener {
|
||||
it as AlertDialog
|
||||
it.applyTheme()
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_ENABLE_TIMELINE_FILTER = "enable_timeline_filter"
|
||||
const val REQUEST_SET_TIMELINE_FILTER = 101
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.mariotaku.twidere.R
|
|||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.timeline.UserTimelineFilter
|
||||
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
|
||||
import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
@ -50,7 +51,7 @@ class UserTimelineLoader(
|
|||
fromUser: Boolean,
|
||||
loadingMore: Boolean,
|
||||
val pinnedStatusIds: Array<String>?,
|
||||
val excludeReplies: Boolean = false
|
||||
val timelineFilter: UserTimelineFilter? = null
|
||||
) : MicroBlogAPIStatusesLoader(context, accountId, sinceId, maxId, -1, data, savedStatusesArgs,
|
||||
tabPosition, fromUser, loadingMore) {
|
||||
|
||||
|
@ -80,7 +81,10 @@ class UserTimelineLoader(
|
|||
}
|
||||
}
|
||||
val option = TimelineOption()
|
||||
option.setExcludeReplies(excludeReplies)
|
||||
if (timelineFilter != null) {
|
||||
option.setExcludeReplies(!timelineFilter.isIncludeReplies)
|
||||
option.setIncludeRetweets(timelineFilter.isIncludeRetweets)
|
||||
}
|
||||
if (userId != null) {
|
||||
return microBlog.getUserTimeline(userId.id, paging, option)
|
||||
} else if (screenName != null) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import com.squareup.otto.Bus
|
||||
import org.mariotaku.abstask.library.AbstractTask
|
||||
import org.mariotaku.kpreferences.KPreferences
|
||||
import org.mariotaku.twidere.model.DefaultFeatures
|
||||
import org.mariotaku.twidere.util.*
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import org.mariotaku.twidere.util.media.MediaPreloader
|
||||
|
@ -38,6 +39,8 @@ abstract class BaseAbstractTask<Params, Result, Callback>(val context: Context)
|
|||
@Inject
|
||||
lateinit var extraFeaturesService: ExtraFeaturesService
|
||||
@Inject
|
||||
lateinit var defaultFeatures: DefaultFeatures
|
||||
@Inject
|
||||
lateinit var scheduleProviderFactory: StatusScheduleProvider.Factory
|
||||
|
||||
val scheduleProvider: StatusScheduleProvider?
|
||||
|
|
|
@ -14,6 +14,7 @@ import android.support.annotation.WorkerThread
|
|||
import android.text.TextUtils
|
||||
import android.webkit.MimeTypeMap
|
||||
import com.bumptech.glide.Glide
|
||||
import com.twitter.Validator
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger
|
||||
import edu.tsinghua.hotmobi.model.MediaUploadEvent
|
||||
import net.ypresto.androidtranscoder.MediaTranscoder
|
||||
|
@ -36,6 +37,7 @@ import org.mariotaku.twidere.R
|
|||
import org.mariotaku.twidere.TwidereConstants.*
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.app.TwidereApplication
|
||||
import org.mariotaku.twidere.extension.getTweetLength
|
||||
import org.mariotaku.twidere.extension.model.mediaSizeLimit
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.extension.model.textLimit
|
||||
|
@ -217,13 +219,16 @@ class UpdateStatusTask(
|
|||
update: ParcelableStatusUpdate,
|
||||
pending: PendingStatusUpdate) {
|
||||
if (shortener == null) return
|
||||
val validator = Validator()
|
||||
stateCallback.onShorteningStatus()
|
||||
val sharedShortened = HashMap<UserKey, StatusShortenResult>()
|
||||
for (i in 0 until pending.length) {
|
||||
val account = update.accounts[i]
|
||||
val text = pending.overrideTexts[i]
|
||||
val textLimit = account.textLimit
|
||||
if (textLimit >= 0 && text.length <= textLimit) {
|
||||
val ignoreMentions = update.in_reply_to_status != null && account.type ==
|
||||
AccountType.TWITTER && defaultFeatures.isMentionsCountsInStatus
|
||||
if (textLimit >= 0 && validator.getTweetLength(text, ignoreMentions) <= textLimit) {
|
||||
continue
|
||||
}
|
||||
shortener.waitForService()
|
||||
|
@ -403,6 +408,9 @@ class UpdateStatusTask(
|
|||
status.location(ParcelableLocationUtils.toGeoLocation(statusUpdate.location))
|
||||
status.displayCoordinates(statusUpdate.display_coordinates)
|
||||
}
|
||||
if (statusUpdate.accounts[index].type == AccountType.TWITTER) {
|
||||
status.autoPopulateReplyMetadata(true)
|
||||
}
|
||||
val mediaIds = pendingUpdate.mediaIds[index]
|
||||
if (mediaIds != null) {
|
||||
status.mediaIds(*mediaIds)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.view.holder
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.header_user_timeline_filter.view.*
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter
|
||||
import org.mariotaku.twidere.model.timeline.TimelineFilter
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/3/31.
|
||||
*/
|
||||
|
||||
class TimelineFilterHeaderViewHolder(val adapter: IStatusesAdapter<*>, itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
private val filterLabel = itemView.filterLabel
|
||||
private val filterButton = itemView.filterButton
|
||||
|
||||
init {
|
||||
filterButton.setOnClickListener {
|
||||
adapter.statusClickListener?.onFilterClick(this)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val layoutResource = R.layout.header_user_timeline_filter
|
||||
}
|
||||
|
||||
fun display(filter: TimelineFilter) {
|
||||
filterLabel.text = filter.getSummary(itemView.context)
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import org.mariotaku.twidere.model.ParcelableMedia
|
|||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.view.CardMediaContainer
|
||||
import org.mariotaku.twidere.view.holder.TimelineFilterHeaderViewHolder
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/10/26.
|
||||
|
@ -62,6 +63,8 @@ interface IStatusViewHolder : CardMediaContainer.OnMediaClickListener {
|
|||
fun onStatusLongClick(holder: IStatusViewHolder, position: Int): Boolean = false
|
||||
|
||||
fun onUserProfileClick(holder: IStatusViewHolder, position: Int) {}
|
||||
|
||||
fun onFilterClick(holder: TimelineFilterHeaderViewHolder) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ 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.
|
||||
~
|
||||
~ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<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="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/element_size_msmall"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/element_spacing_small">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/filterLabel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/element_spacing_normal"
|
||||
tools:text="Tweets, retweets, replies"/>
|
||||
|
||||
<org.mariotaku.twidere.view.IconActionButton
|
||||
android:id="@+id/filterButton"
|
||||
android:layout_width="@dimen/element_size_msmall"
|
||||
android:layout_height="@dimen/element_size_msmall"
|
||||
android:layout_weight="0"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_action_filter"
|
||||
app:iabColor="?android:textColorSecondary"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -80,4 +80,8 @@
|
|||
<item>List</item>
|
||||
<item>List timeline</item>
|
||||
</string-array>
|
||||
<string-array name="entries_user_timeline_filter">
|
||||
<item>Replies</item>
|
||||
<item>Retweets</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -103,4 +103,8 @@
|
|||
<item>list</item>
|
||||
<item>list_timeline</item>
|
||||
</string-array>
|
||||
<string-array name="values_user_timeline_filter">
|
||||
<item>replies</item>
|
||||
<item>retweets</item>
|
||||
</string-array>
|
||||
</resources>
|
|
@ -1289,4 +1289,9 @@
|
|||
<string name="users_lists_with_name"><xliff:g id="name">%s</xliff:g>\'s lists</string>
|
||||
<string name="users_statuses">User\'s tweets</string>
|
||||
<string name="hint_search_gif">Search GIF</string>
|
||||
<string name="title_user_timeline_filter">Timeline filter</string>
|
||||
<string name="label_statuses">Tweets</string>
|
||||
<string name="label_statuses_retweets">Tweets and retweets</string>
|
||||
<string name="label_statuses_replies">Tweets and replies</string>
|
||||
<string name="label_statuses_retweets_replies">Tweets, retweets and replies</string>
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>ic_action_filter-mdpi</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Action-Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="ic_action_filter-mdpi">
|
||||
<path d="M14,22 L18,22 L18,20 L14,20 L14,22 Z M7,10 L7,12 L25,12 L25,10 L7,10 Z M10,17 L22,17 L22,15 L10,15 L10,17 Z" id="Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<polygon id="Shape" points="4 4 28 4 28 28 4 28"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 774 B |
Loading…
Reference in New Issue