mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-17 04:00:48 +01:00
supports save media for ExoPlayerPageFragment
This commit is contained in:
parent
993e95b08c
commit
9e615969f5
@ -802,13 +802,6 @@ public interface TwidereDataStore {
|
||||
Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH);
|
||||
}
|
||||
|
||||
interface ByFriends extends Activities {
|
||||
|
||||
String CONTENT_PATH = "activities_by_friends";
|
||||
String TABLE_NAME = "activities_by_friends";
|
||||
|
||||
Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
interface Tabs extends BaseColumns {
|
||||
|
@ -31,4 +31,14 @@ fun String?.toDouble(def: Double): Double {
|
||||
fun Int.coerceInOr(range: ClosedRange<Int>, or: Int): Int {
|
||||
if (range.isEmpty()) return or
|
||||
return coerceIn(range)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method checking int flags
|
||||
*/
|
||||
operator fun Int.contains(i: Int): Boolean = (this and i) == i
|
||||
|
||||
/**
|
||||
* Convenience method checking long flags
|
||||
*/
|
||||
operator fun Long.contains(i: Long): Boolean = (this and i) == i
|
@ -68,6 +68,7 @@ import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.kpreferences.set
|
||||
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.ktextension.coerceInOr
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.twidere.Constants.*
|
||||
import org.mariotaku.twidere.R
|
||||
@ -221,7 +222,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||
tabDisplayOptionInt = TabPagerIndicator.DisplayOption.ICON
|
||||
}
|
||||
mainTabs.setTabDisplayOption(tabDisplayOptionInt)
|
||||
mainTabs.setTabExpandEnabled(tabDisplayOptionInt and TabPagerIndicator.DisplayOption.LABEL == 0)
|
||||
mainTabs.setTabExpandEnabled(TabPagerIndicator.DisplayOption.LABEL !in tabDisplayOptionInt)
|
||||
mainTabs.setDisplayBadge(preferences[unreadCountKey])
|
||||
mainTabs.updateAppearance()
|
||||
|
||||
|
@ -24,10 +24,10 @@ import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.Parcelable
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.hasRunningLoadersSafe
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v4.graphics.ColorUtils
|
||||
import android.support.v4.view.ViewPager
|
||||
@ -429,18 +429,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||
if (shareMediaPosition == -1) return
|
||||
val viewPager = findViewPager()
|
||||
val adapter = viewPager.adapter
|
||||
val f = adapter.instantiateItem(viewPager, shareMediaPosition) as? CacheDownloadMediaViewerFragment ?: return
|
||||
val cacheUri = f.downloadResult?.cacheUri ?: return
|
||||
val f = adapter.instantiateItem(viewPager, shareMediaPosition) as? MediaViewerFragment ?: return
|
||||
val fileInfo = f.cacheFileInfo() ?: return
|
||||
val destination = ShareProvider.getFilesDir(this) ?: return
|
||||
val type: String
|
||||
when (f) {
|
||||
is VideoPageFragment -> type = CacheFileType.VIDEO
|
||||
is ImagePageFragment -> type = CacheFileType.IMAGE
|
||||
is GifPageFragment -> type = CacheFileType.IMAGE
|
||||
else -> throw UnsupportedOperationException("Unsupported fragment $f")
|
||||
}
|
||||
val task = object : SaveFileTask(this@MediaViewerActivity, cacheUri, destination,
|
||||
CacheProvider.CacheFileTypeCallback(this@MediaViewerActivity, type)) {
|
||||
val task = object : SaveFileTask(this@MediaViewerActivity, destination, fileInfo) {
|
||||
private val PROGRESS_FRAGMENT_TAG = "progress"
|
||||
|
||||
override fun dismissProgress() {
|
||||
@ -491,17 +483,44 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||
if (saveToStoragePosition == -1) return
|
||||
val viewPager = findViewPager()
|
||||
val adapter = viewPager.adapter
|
||||
val f = adapter.instantiateItem(viewPager, saveToStoragePosition) as? CacheDownloadMediaViewerFragment ?: return
|
||||
val cacheUri = f.downloadResult?.cacheUri ?: return
|
||||
val task: SaveFileTask = when (f) {
|
||||
is ImagePageFragment -> SaveMediaToGalleryTask.create(this, cacheUri, CacheFileType.IMAGE)
|
||||
is VideoPageFragment -> SaveMediaToGalleryTask.create(this, cacheUri, CacheFileType.VIDEO)
|
||||
is GifPageFragment -> SaveMediaToGalleryTask.create(this, cacheUri, CacheFileType.IMAGE)
|
||||
else -> throw UnsupportedOperationException()
|
||||
val f = adapter.instantiateItem(viewPager, saveToStoragePosition) as? MediaViewerFragment ?: return
|
||||
val fileInfo = f.cacheFileInfo() ?: return
|
||||
val type = (fileInfo as? CacheProvider.CacheFileTypeSupport)?.cacheFileType
|
||||
val pubDir = when (type) {
|
||||
CacheFileType.VIDEO -> {
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
|
||||
}
|
||||
CacheFileType.IMAGE -> {
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
|
||||
}
|
||||
else -> {
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
}
|
||||
}
|
||||
val saveDir = File(pubDir, "Twidere")
|
||||
val task = SaveMediaToGalleryTask(this, fileInfo, saveDir)
|
||||
AsyncTaskUtils.executeTask(task)
|
||||
}
|
||||
|
||||
private fun MediaViewerFragment.cacheFileInfo(): SaveFileTask.FileInfo? {
|
||||
return when (this) {
|
||||
is CacheDownloadMediaViewerFragment -> {
|
||||
val cacheUri = downloadResult?.cacheUri ?: return null
|
||||
val type = when (this) {
|
||||
is ImagePageFragment -> CacheFileType.IMAGE
|
||||
is VideoPageFragment -> CacheFileType.VIDEO
|
||||
is GifPageFragment -> CacheFileType.IMAGE
|
||||
else -> return null
|
||||
}
|
||||
CacheProvider.ContentUriFileInfo(activity, cacheUri, type)
|
||||
}
|
||||
is ExoPlayerPageFragment -> {
|
||||
return getRequestFileInfo()
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val REQUEST_SHARE_MEDIA = 201
|
||||
|
@ -31,6 +31,7 @@ import android.widget.TextView
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.layout_list_with_empty_view.*
|
||||
import org.mariotaku.ktextension.Bundle
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.set
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.REQUEST_SELECT_USER
|
||||
@ -175,7 +176,7 @@ class UserListSelectorActivity : BaseActivity(),
|
||||
override fun onLoadMoreContents(@IndicatorPosition position: Long) {
|
||||
val accountKey = this.accountKey ?: return
|
||||
val userKey = this.userKey ?: return
|
||||
if (refreshing || position and adapter.loadMoreSupportedPosition == 0L) {
|
||||
if (refreshing || position !in adapter.loadMoreSupportedPosition) {
|
||||
return
|
||||
}
|
||||
adapter.loadMoreIndicatorPosition = position
|
||||
|
@ -28,6 +28,7 @@ import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.apache.commons.lang3.ArrayUtils
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.rangeOfSize
|
||||
import org.mariotaku.ktextension.safeMoveToPosition
|
||||
import org.mariotaku.library.objectcursor.ObjectCursor
|
||||
@ -243,7 +244,7 @@ class ParcelableActivitiesAdapter(
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (loadMoreIndicatorPosition and ILoadMoreSupportAdapter.START != 0L && position == 0) {
|
||||
if (position == 0 && ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) {
|
||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
} else if (position == activityCount) {
|
||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
|
@ -26,6 +26,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.adapter.iface.IGroupsAdapter
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
@ -119,7 +120,7 @@ class ParcelableGroupsAdapter(
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (loadMoreIndicatorPosition and ILoadMoreSupportAdapter.START != 0L && position == 0) {
|
||||
if (position == 0 && ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) {
|
||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
}
|
||||
if (position == groupsCount) {
|
||||
|
@ -27,6 +27,7 @@ import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.findPositionByItemId
|
||||
import org.mariotaku.ktextension.rangeOfSize
|
||||
import org.mariotaku.ktextension.safeMoveToPosition
|
||||
@ -319,7 +320,7 @@ abstract class ParcelableStatusesAdapter(
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (loadMoreIndicatorPosition and ILoadMoreSupportAdapter.START != 0L && position == 0) {
|
||||
if (position == 0 && ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) {
|
||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
}
|
||||
when (getItemCountIndex(position)) {
|
||||
|
@ -25,6 +25,7 @@ import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.Companion.ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
@ -110,7 +111,7 @@ class ParcelableUserListsAdapter(
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (loadMoreIndicatorPosition and ILoadMoreSupportAdapter.START != 0L && position == 0) {
|
||||
if (position == 0 && ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) {
|
||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
}
|
||||
if (position == userListsCount) {
|
||||
|
@ -24,6 +24,7 @@ import android.support.v7.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.Companion.ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
@ -150,7 +151,7 @@ class ParcelableUsersAdapter(
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (loadMoreIndicatorPosition and ILoadMoreSupportAdapter.START != 0L && position == 0) {
|
||||
if (position == 0 && ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) {
|
||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||
}
|
||||
if (position == userCount) {
|
||||
|
@ -26,11 +26,11 @@ import android.support.annotation.IntDef
|
||||
*/
|
||||
interface ILoadMoreSupportAdapter {
|
||||
|
||||
@IndicatorPosition
|
||||
var loadMoreIndicatorPosition: Long
|
||||
@IndicatorPosition get @IndicatorPosition set
|
||||
|
||||
@IndicatorPosition
|
||||
var loadMoreSupportedPosition: Long
|
||||
@IndicatorPosition get @IndicatorPosition set
|
||||
|
||||
@IntDef(flag = true, value = *longArrayOf(NONE, START, END, BOTH))
|
||||
annotation class IndicatorPosition
|
||||
@ -48,9 +48,5 @@ interface ILoadMoreSupportAdapter {
|
||||
return orig and supported
|
||||
}
|
||||
|
||||
@IndicatorPosition
|
||||
fun has(@IndicatorPosition flags: Long, @IndicatorPosition compare: Long): Boolean {
|
||||
return flags and compare != 0L
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,13 +165,13 @@ internal object AccountDataQueue {
|
||||
|
||||
fun getUserData(manager: AccountManager, account: Account, key: String): String? {
|
||||
val future = FutureTask<String?> { manager.getUserData(account, key) }
|
||||
if (Thread.currentThread() == Looper.getMainLooper().thread) {
|
||||
if (Thread.currentThread() === Looper.getMainLooper().thread) {
|
||||
future.run()
|
||||
} else handler.post {
|
||||
future.run()
|
||||
}
|
||||
try {
|
||||
return future.get(5, TimeUnit.SECONDS)
|
||||
return future.get(1, TimeUnit.SECONDS)
|
||||
} catch (e: TimeoutException) {
|
||||
return manager.getUserData(account, key)
|
||||
}
|
||||
@ -179,13 +179,13 @@ internal object AccountDataQueue {
|
||||
|
||||
fun peekAuthToken(manager: AccountManager, account: Account, authTokenType: String): String? {
|
||||
val future = FutureTask<String?> { manager.peekAuthToken(account, authTokenType) }
|
||||
if (Thread.currentThread() == Looper.getMainLooper().thread) {
|
||||
if (Thread.currentThread() === Looper.getMainLooper().thread) {
|
||||
future.run()
|
||||
} else handler.post {
|
||||
future.run()
|
||||
}
|
||||
try {
|
||||
return future.get(5, TimeUnit.SECONDS)
|
||||
return future.get(1, TimeUnit.SECONDS)
|
||||
} catch (e: TimeoutException) {
|
||||
return manager.peekAuthToken(account, authTokenType)
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import android.content.Context
|
||||
import android.support.v7.widget.FixedLinearLayoutManager
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import org.mariotaku.ktextension.contains
|
||||
|
||||
import org.mariotaku.twidere.adapter.LoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration
|
||||
@ -36,17 +37,16 @@ import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter.IndicatorPosi
|
||||
abstract class AbsContentListRecyclerViewFragment<A : LoadMoreSupportAdapter<RecyclerView.ViewHolder>>
|
||||
: AbsContentRecyclerViewFragment<A, LinearLayoutManager>() {
|
||||
|
||||
override fun createItemDecoration(context: Context,
|
||||
recyclerView: RecyclerView,
|
||||
layoutManager: LinearLayoutManager): RecyclerView.ItemDecoration? {
|
||||
override fun createItemDecoration(context: Context, recyclerView: RecyclerView,
|
||||
layoutManager: LinearLayoutManager): RecyclerView.ItemDecoration? {
|
||||
return DividerItemDecoration(context, layoutManager.orientation)
|
||||
}
|
||||
|
||||
override fun setLoadMoreIndicatorPosition(@IndicatorPosition position: Long) {
|
||||
val decor = itemDecoration
|
||||
if (decor is DividerItemDecoration) {
|
||||
decor.setDecorationStart(if (position and ILoadMoreSupportAdapter.START != 0L) 1 else 0)
|
||||
decor.setDecorationEndOffset(if (position and ILoadMoreSupportAdapter.END != 0L) 1 else 0)
|
||||
decor.setDecorationStart(if (ILoadMoreSupportAdapter.START in position) 1 else 0)
|
||||
decor.setDecorationEndOffset(if (ILoadMoreSupportAdapter.END in position) 1 else 0)
|
||||
}
|
||||
super.setLoadMoreIndicatorPosition(position)
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import android.support.v4.content.Loader
|
||||
import android.widget.Toast
|
||||
import com.squareup.otto.Subscribe
|
||||
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.ktextension.toNulls
|
||||
import org.mariotaku.library.objectcursor.ObjectCursor
|
||||
@ -140,7 +141,7 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
|
||||
override fun onLoadMoreContents(@IndicatorPosition position: Long) {
|
||||
// Only supports load from end, skip START flag
|
||||
if (position and ILoadMoreSupportAdapter.START != 0L || refreshing) return
|
||||
if (ILoadMoreSupportAdapter.START in position || refreshing) return
|
||||
super.onLoadMoreContents(position)
|
||||
if (position == 0L) return
|
||||
getActivities(object : SimpleRefreshTaskParam() {
|
||||
@ -337,8 +338,8 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
}
|
||||
|
||||
class CursorActivitiesLoader(context: Context, uri: Uri, projection: Array<String>,
|
||||
selection: String, selectionArgs: Array<String>,
|
||||
sortOrder: String, fromUser: Boolean) : ExtendedObjectCursorLoader<ParcelableActivity>(context, ParcelableActivityCursorIndices::class.java, uri, projection, selection, selectionArgs, sortOrder, fromUser) {
|
||||
selection: String, selectionArgs: Array<String>,
|
||||
sortOrder: String, fromUser: Boolean) : ExtendedObjectCursorLoader<ParcelableActivity>(context, ParcelableActivityCursorIndices::class.java, uri, projection, selection, selectionArgs, sortOrder, fromUser) {
|
||||
|
||||
override fun createObjectCursor(cursor: Cursor, indices: ObjectCursor.CursorIndices<ParcelableActivity>): ObjectCursor<ParcelableActivity> {
|
||||
val filteredUserIds = DataStoreUtils.getFilteredUserIds(context)
|
||||
@ -346,6 +347,6 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
}
|
||||
|
||||
class ActivityCursor(cursor: Cursor, indies: ObjectCursor.CursorIndices<ParcelableActivity>,
|
||||
val filteredUserIds: Array<UserKey>) : ObjectCursor<ParcelableActivity>(cursor, indies)
|
||||
val filteredUserIds: Array<UserKey>) : ObjectCursor<ParcelableActivity>(cursor, indies)
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import com.bumptech.glide.Glide
|
||||
import com.squareup.otto.Subscribe
|
||||
import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
|
||||
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.ktextension.toNulls
|
||||
import org.mariotaku.sqliteqb.library.Columns.Column
|
||||
@ -174,7 +175,7 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() {
|
||||
|
||||
override fun onLoadMoreContents(@IndicatorPosition position: Long) {
|
||||
// Only supports load from end, skip START flag
|
||||
if (position and ILoadMoreSupportAdapter.START != 0L) return
|
||||
if (ILoadMoreSupportAdapter.START in position) return
|
||||
super.onLoadMoreContents(position)
|
||||
if (position == 0L) return
|
||||
getStatuses(object : SimpleRefreshTaskParam() {
|
||||
|
@ -45,6 +45,7 @@ import kotlinx.android.synthetic.main.layout_draggable_list_with_empty_view.*
|
||||
import kotlinx.android.synthetic.main.list_item_section_header.view.*
|
||||
import org.mariotaku.chameleon.Chameleon
|
||||
import org.mariotaku.ktextension.Bundle
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.set
|
||||
import org.mariotaku.sqliteqb.library.Columns.Column
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
@ -353,8 +354,13 @@ class CustomTabsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, MultiChoice
|
||||
positiveButton.setOnClickListener {
|
||||
tab.name = tabName.text.toString()
|
||||
tab.icon = (iconSpinner.selectedItem as DrawableHolder).persistentKey
|
||||
tab.arguments = CustomTabUtils.newTabArguments(tabType)
|
||||
if (hasAccount) {
|
||||
if (tab.arguments == null) {
|
||||
tab.arguments = CustomTabUtils.newTabArguments(tabType)
|
||||
}
|
||||
if (tab.extras == null) {
|
||||
tab.extras = CustomTabUtils.newTabExtras(tabType)
|
||||
}
|
||||
if (hasAccount && (!editMode || TabConfiguration.FLAG_ACCOUNT_MUTABLE in conf.accountFlags)) {
|
||||
val account = accountSpinner.selectedItem as? AccountDetails ?: return@setOnClickListener
|
||||
if (!account.dummy) {
|
||||
tab.arguments?.accountKeys = arrayOf(account.key)
|
||||
@ -362,7 +368,6 @@ class CustomTabsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, MultiChoice
|
||||
tab.arguments?.accountKeys = null
|
||||
}
|
||||
}
|
||||
tab.extras = CustomTabUtils.newTabExtras(tabType)
|
||||
extraConfigurations.forEach { extraConf ->
|
||||
// Make sure immutable configuration skipped in edit mode
|
||||
if (editMode && !extraConf.isMutable) return@forEach
|
||||
@ -524,3 +529,4 @@ class CustomTabsFragment : BaseFragment(), LoaderCallbacks<Cursor?>, MultiChoice
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ import kotlinx.android.synthetic.main.header_status_common.view.*
|
||||
import kotlinx.android.synthetic.main.layout_content_fragment_common.*
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.applyFontFamily
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.findPositionByItemId
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
@ -1891,7 +1892,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||
}
|
||||
|
||||
var isConversationsLoading: Boolean
|
||||
get() = ILoadMoreSupportAdapter.has(loadMoreIndicatorPosition, ILoadMoreSupportAdapter.START)
|
||||
get() = ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition
|
||||
set(loading) {
|
||||
if (loading) {
|
||||
loadMoreIndicatorPosition = loadMoreIndicatorPosition or ILoadMoreSupportAdapter.START
|
||||
@ -1902,7 +1903,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||
}
|
||||
|
||||
var isRepliesLoading: Boolean
|
||||
get() = ILoadMoreSupportAdapter.has(loadMoreIndicatorPosition, ILoadMoreSupportAdapter.END)
|
||||
get() = ILoadMoreSupportAdapter.END in loadMoreIndicatorPosition
|
||||
set(loading) {
|
||||
if (loading) {
|
||||
loadMoreIndicatorPosition = loadMoreIndicatorPosition or ILoadMoreSupportAdapter.END
|
||||
@ -1913,10 +1914,9 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
|
||||
}
|
||||
|
||||
class StatusErrorItemViewHolder(itemView: View) : ViewHolder(itemView) {
|
||||
private val textView: TextView
|
||||
private val textView = itemView.findViewById(android.R.id.text1) as TextView
|
||||
|
||||
init {
|
||||
textView = itemView.findViewById(android.R.id.text1) as TextView
|
||||
textView.movementMethod = LinkMovementMethod.getInstance()
|
||||
textView.linksClickable = true
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import android.support.v7.widget.RecyclerView
|
||||
import android.support.v7.widget.StaggeredGridLayoutManager
|
||||
import android.text.TextUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.twidere.adapter.StaggeredGridParcelableStatusesAdapter
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.constant.IntentConstants.*
|
||||
@ -119,7 +120,7 @@ class UserMediaTimelineFragment : AbsContentRecyclerViewFragment<StaggeredGridPa
|
||||
|
||||
override fun onLoadMoreContents(position: Long) {
|
||||
// Only supports load from end, skip START flag
|
||||
if (position and ILoadMoreSupportAdapter.START != 0L) return
|
||||
if (ILoadMoreSupportAdapter.START in position) return
|
||||
super.onLoadMoreContents(position)
|
||||
if (position == 0L) return
|
||||
val maxId = adapter.getStatusId(adapter.statusCount - 1)
|
||||
|
@ -156,7 +156,7 @@ abstract class BaseFiltersImportFragment : AbsContentListRecyclerViewFragment<Se
|
||||
|
||||
override fun onLoadMoreContents(@IndicatorPosition position: Long) {
|
||||
// Only supports load from end, skip START flag
|
||||
if (position and ILoadMoreSupportAdapter.START != 0L) return
|
||||
if (ILoadMoreSupportAdapter.START in position) return
|
||||
super.onLoadMoreContents(position)
|
||||
if (position == 0L) return
|
||||
val loaderArgs = Bundle(arguments)
|
||||
|
@ -44,6 +44,9 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_exo_player_view.*
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_video_overlay.*
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.mariotaku.mediaviewer.library.MediaViewerFragment
|
||||
import org.mariotaku.mediaviewer.library.subsampleimageview.SubsampleImageViewerFragment
|
||||
import org.mariotaku.restfu.RestRequest
|
||||
@ -52,6 +55,7 @@ import org.mariotaku.restfu.http.MultiValueMap
|
||||
import org.mariotaku.restfu.oauth.OAuthAuthorization
|
||||
import org.mariotaku.restfu.oauth.OAuthEndpoint
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.annotation.CacheFileType
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_POSITION
|
||||
import org.mariotaku.twidere.extension.model.getAuthorization
|
||||
import org.mariotaku.twidere.fragment.iface.IBaseFragment
|
||||
@ -63,11 +67,14 @@ import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.isContro
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.isLoopEnabled
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.isMutedByDefault
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.media
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.provider.CacheProvider
|
||||
import org.mariotaku.twidere.task.SaveFileTask
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import org.mariotaku.twidere.util.media.TwidereMediaDownloader
|
||||
import java.io.InputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@ -84,12 +91,20 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
@Inject
|
||||
internal lateinit var extractorsFactory: ExtractorsFactory
|
||||
|
||||
@Inject
|
||||
internal lateinit var okHttpClient: OkHttpClient
|
||||
|
||||
private lateinit var mainHandler: Handler
|
||||
|
||||
private var playAudio: Boolean = false
|
||||
private var pausedByUser: Boolean = false
|
||||
private var playbackCompleted: Boolean = false
|
||||
private var positionBackup: Long = -1L
|
||||
private var playerHasError: Boolean = false
|
||||
|
||||
private val account by lazy {
|
||||
AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)
|
||||
}
|
||||
|
||||
private val playerListener = object : ExoPlayer.EventListener {
|
||||
override fun onLoadingChanged(isLoading: Boolean) {
|
||||
@ -97,7 +112,8 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: ExoPlaybackException) {
|
||||
|
||||
playerHasError = true
|
||||
hideProgress()
|
||||
}
|
||||
|
||||
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
|
||||
@ -119,6 +135,7 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
}
|
||||
ExoPlayer.STATE_READY -> {
|
||||
playbackCompleted = playWhenReady
|
||||
playerHasError = false
|
||||
hideProgress()
|
||||
}
|
||||
ExoPlayer.STATE_IDLE -> {
|
||||
@ -235,13 +252,11 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
}
|
||||
|
||||
override fun isMediaLoaded(): Boolean {
|
||||
val player = playerView.player ?: return false
|
||||
return player.playbackState != ExoPlayer.STATE_IDLE
|
||||
return !playerHasError
|
||||
}
|
||||
|
||||
override fun isMediaLoading(): Boolean {
|
||||
val player = playerView.player ?: return false
|
||||
return player.isLoading
|
||||
return false
|
||||
}
|
||||
|
||||
private fun releasePlayer() {
|
||||
@ -264,13 +279,13 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
player.seekTo(positionBackup)
|
||||
}
|
||||
player.playWhenReady = !pausedByUser
|
||||
playerHasError = false
|
||||
player.addListener(playerListener)
|
||||
return@run player
|
||||
}
|
||||
|
||||
val uri = media?.getDownloadUri() ?: return
|
||||
val am = AccountManager.get(context)
|
||||
val factory = AuthDelegatingDataSourceFactory(uri, accountKey, am, dataSourceFactory)
|
||||
val factory = AuthDelegatingDataSourceFactory(uri, account, dataSourceFactory)
|
||||
val uriSource = ExtractorMediaSource(uri, factory, extractorsFactory, null, null)
|
||||
if (isLoopEnabled) {
|
||||
playerView.player.prepare(LoopingMediaSource(uriSource))
|
||||
@ -290,7 +305,7 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
}
|
||||
}
|
||||
|
||||
fun ParcelableMedia.getDownloadUri(): Uri? {
|
||||
private fun ParcelableMedia.getDownloadUri(): Uri? {
|
||||
val bestVideoUrlAndType = VideoPageFragment.getBestVideoUrlAndType(this, SUPPORTED_VIDEO_TYPES)
|
||||
if (bestVideoUrlAndType != null && bestVideoUrlAndType.first != null) {
|
||||
return Uri.parse(bestVideoUrlAndType.first)
|
||||
@ -298,12 +313,18 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
return arguments.getParcelable<Uri>(SubsampleImageViewerFragment.EXTRA_MEDIA_URI)
|
||||
}
|
||||
|
||||
|
||||
fun getRequestFileInfo(): RequestFileInfo? {
|
||||
val uri = media?.getDownloadUri() ?: return null
|
||||
return RequestFileInfo(uri, account, okHttpClient)
|
||||
}
|
||||
|
||||
class AuthDelegatingDataSourceFactory(
|
||||
val uri: Uri,
|
||||
val accountKey: UserKey,
|
||||
val am: AccountManager,
|
||||
val account: AccountDetails?,
|
||||
val delegate: DataSource.Factory
|
||||
) : DataSource.Factory {
|
||||
|
||||
override fun createDataSource(): DataSource {
|
||||
val source = delegate.createDataSource()
|
||||
if (source is HttpDataSource) {
|
||||
@ -313,28 +334,75 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
}
|
||||
|
||||
private fun setAuthorizationHeader(dataSource: HttpDataSource) {
|
||||
val account = AccountUtils.getAccountDetails(am, accountKey, true) ?: return
|
||||
val modifiedUri = TwidereMediaDownloader.getReplacedUri(uri, account.credentials.api_url_format) ?: uri
|
||||
if (TwidereMediaDownloader.isAuthRequired(account, uri)) {
|
||||
val auth = account.credentials.getAuthorization()
|
||||
val endpoint: Endpoint
|
||||
if (auth is OAuthAuthorization) {
|
||||
endpoint = OAuthEndpoint(TwidereMediaDownloader.getEndpoint(modifiedUri),
|
||||
TwidereMediaDownloader.getEndpoint(uri))
|
||||
} else {
|
||||
endpoint = Endpoint(TwidereMediaDownloader.getEndpoint(modifiedUri))
|
||||
}
|
||||
val queries = MultiValueMap<String>()
|
||||
for (name in uri.queryParameterNames) {
|
||||
for (value in uri.getQueryParameters(name)) {
|
||||
queries.add(name, value)
|
||||
}
|
||||
}
|
||||
val info = RestRequest("GET", false, uri.path, null, queries, null, null, null, null)
|
||||
dataSource.setRequestProperty("Authorization", auth.getHeader(endpoint, info))
|
||||
}
|
||||
|
||||
val authorizationHeader = account?.authorizationHeader(uri) ?: return
|
||||
dataSource.setRequestProperty("Authorization", authorizationHeader)
|
||||
}
|
||||
}
|
||||
|
||||
class RequestFileInfo(
|
||||
val uri: Uri,
|
||||
val account: AccountDetails?,
|
||||
val okHttpClient: OkHttpClient
|
||||
) : SaveFileTask.FileInfo, CacheProvider.CacheFileTypeSupport {
|
||||
|
||||
private var response: Response? = null
|
||||
|
||||
override val cacheFileType: String? = CacheFileType.VIDEO
|
||||
|
||||
override val fileName: String? = uri.lastPathSegment
|
||||
|
||||
override val mimeType: String?
|
||||
get() = request().body()?.contentType()?.toString()
|
||||
|
||||
override val specialCharacter: Char = '_'
|
||||
|
||||
override fun inputStream(): InputStream {
|
||||
return request().body().byteStream()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
response?.close()
|
||||
}
|
||||
|
||||
private fun request(): Response {
|
||||
if (response != null) return response!!
|
||||
val builder = Request.Builder()
|
||||
builder.url(uri.toString())
|
||||
val authHeader = account?.authorizationHeader(uri)
|
||||
if (authHeader != null) {
|
||||
builder.addHeader("Authorization", authHeader)
|
||||
}
|
||||
response = okHttpClient.newCall(builder.build()).execute()
|
||||
return response!!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun AccountDetails.authorizationHeader(uri: Uri): String? {
|
||||
val modifiedUri = TwidereMediaDownloader.getReplacedUri(uri, credentials.api_url_format) ?: uri
|
||||
if (!TwidereMediaDownloader.isAuthRequired(this, uri)) {
|
||||
return null
|
||||
}
|
||||
val auth = credentials.getAuthorization()
|
||||
val endpoint: Endpoint
|
||||
if (auth is OAuthAuthorization) {
|
||||
endpoint = OAuthEndpoint(TwidereMediaDownloader.getEndpoint(modifiedUri),
|
||||
TwidereMediaDownloader.getEndpoint(uri))
|
||||
} else {
|
||||
endpoint = Endpoint(TwidereMediaDownloader.getEndpoint(modifiedUri))
|
||||
}
|
||||
val queries = MultiValueMap<String>()
|
||||
for (name in uri.queryParameterNames) {
|
||||
for (value in uri.getQueryParameters(name)) {
|
||||
queries.add(name, value)
|
||||
}
|
||||
}
|
||||
val info = RestRequest("GET", false, uri.path, null, queries, null, null, null, null)
|
||||
return auth.getHeader(endpoint, info)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ import org.mariotaku.abstask.library.TaskStarter
|
||||
import org.mariotaku.chameleon.Chameleon
|
||||
import org.mariotaku.chameleon.ChameleonUtils
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.ktextension.empty
|
||||
import org.mariotaku.ktextension.set
|
||||
import org.mariotaku.pickncrop.library.MediaPickerActivity
|
||||
@ -283,7 +284,7 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
||||
}
|
||||
|
||||
override fun onLoadMoreContents(position: Long) {
|
||||
if (position and ILoadMoreSupportAdapter.START == 0L) return
|
||||
if (ILoadMoreSupportAdapter.START !in position) return
|
||||
val message = adapter.getMessage(adapter.messageRange.endInclusive) ?: return
|
||||
setLoadMoreIndicatorPosition(position)
|
||||
val param = GetMessagesTask.LoadMoreMessageTaskParam(context, accountKey, conversationId,
|
||||
|
@ -47,7 +47,6 @@ class ClearDatabasesPreference(
|
||||
resolver.delete(uri, null, null)
|
||||
}
|
||||
resolver.delete(Activities.AboutMe.CONTENT_URI, null, null)
|
||||
resolver.delete(Activities.ByFriends.CONTENT_URI, null, null)
|
||||
resolver.delete(SavedSearches.CONTENT_URI, null, null)
|
||||
// TODO clear all notifications
|
||||
|
||||
|
@ -7,11 +7,11 @@ import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.webkit.MimeTypeMap
|
||||
import okio.ByteString
|
||||
import org.mariotaku.commons.logansquare.LoganSquareMapperFinder
|
||||
import org.mariotaku.mediaviewer.library.FileCache
|
||||
import org.mariotaku.twidere.TwidereConstants
|
||||
import org.mariotaku.twidere.TwidereConstants.AUTHORITY_TWIDERE_CACHE
|
||||
import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_TYPE
|
||||
import org.mariotaku.twidere.annotation.CacheFileType
|
||||
import org.mariotaku.twidere.model.CacheMetadata
|
||||
import org.mariotaku.twidere.task.SaveFileTask
|
||||
@ -20,7 +20,7 @@ import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.io.InputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@ -45,7 +45,7 @@ class CacheProvider : ContentProvider() {
|
||||
if (metadata != null) {
|
||||
return metadata.contentType
|
||||
}
|
||||
val type = uri.getQueryParameter(TwidereConstants.QUERY_PARAM_TYPE)
|
||||
val type = uri.getQueryParameter(QUERY_PARAM_TYPE)
|
||||
when (type) {
|
||||
CacheFileType.IMAGE -> {
|
||||
val file = fileCache.get(getCacheKey(uri)) ?: return null
|
||||
@ -95,37 +95,43 @@ class CacheProvider : ContentProvider() {
|
||||
|
||||
}
|
||||
|
||||
class CacheFileTypeCallback(private val context: Context, @CacheFileType private val type: String?) : SaveFileTask.FileInfoCallback {
|
||||
|
||||
override fun getFilename(source: Uri): String {
|
||||
var cacheKey = getCacheKey(source)
|
||||
class ContentUriFileInfo(
|
||||
private val context: Context,
|
||||
private val uri: Uri,
|
||||
@CacheFileType override val cacheFileType: String?
|
||||
) : SaveFileTask.FileInfo, CacheFileTypeSupport {
|
||||
override val fileName: String by lazy {
|
||||
var cacheKey = getCacheKey(uri)
|
||||
val indexOfSsp = cacheKey.indexOf("://")
|
||||
if (indexOfSsp != -1) {
|
||||
cacheKey = cacheKey.substring(indexOfSsp + 3)
|
||||
}
|
||||
return cacheKey.replace("[^\\w\\d_]".toRegex(), specialCharacter.toString())
|
||||
return@lazy cacheKey.replace("[^\\w\\d_]".toRegex(), specialCharacter.toString())
|
||||
}
|
||||
|
||||
override fun getMimeType(source: Uri): String? {
|
||||
if (type == null || source.getQueryParameter(TwidereConstants.QUERY_PARAM_TYPE) != null) {
|
||||
return context.contentResolver.getType(source)
|
||||
}
|
||||
val builder = source.buildUpon()
|
||||
builder.appendQueryParameter(TwidereConstants.QUERY_PARAM_TYPE, type)
|
||||
return context.contentResolver.getType(builder.build())
|
||||
}
|
||||
|
||||
override fun getExtension(mimeType: String?): String? {
|
||||
val typeLowered = mimeType?.toLowerCase(Locale.US) ?: return null
|
||||
return when (typeLowered) {
|
||||
// Hack for fanfou image type
|
||||
"image/jpg" -> "jpg"
|
||||
else -> MimeTypeMap.getSingleton().getExtensionFromMimeType(typeLowered)
|
||||
override val mimeType: String? by lazy {
|
||||
if (cacheFileType == null || uri.getQueryParameter(QUERY_PARAM_TYPE) != null) {
|
||||
return@lazy context.contentResolver.getType(uri)
|
||||
}
|
||||
val builder = uri.buildUpon()
|
||||
builder.appendQueryParameter(QUERY_PARAM_TYPE, cacheFileType)
|
||||
return@lazy context.contentResolver.getType(builder.build())
|
||||
}
|
||||
|
||||
override val specialCharacter: Char
|
||||
get() = '_'
|
||||
|
||||
override fun inputStream(): InputStream {
|
||||
return context.contentResolver.openInputStream(uri)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
interface CacheFileTypeSupport {
|
||||
val cacheFileType: String?
|
||||
}
|
||||
|
||||
|
||||
@ -134,10 +140,10 @@ class CacheProvider : ContentProvider() {
|
||||
fun getCacheUri(key: String, @CacheFileType type: String?): Uri {
|
||||
val builder = Uri.Builder()
|
||||
builder.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
builder.authority(TwidereConstants.AUTHORITY_TWIDERE_CACHE)
|
||||
builder.authority(AUTHORITY_TWIDERE_CACHE)
|
||||
builder.appendPath(ByteString.encodeUtf8(key).base64Url())
|
||||
if (type != null) {
|
||||
builder.appendQueryParameter(TwidereConstants.QUERY_PARAM_TYPE, type)
|
||||
builder.appendQueryParameter(QUERY_PARAM_TYPE, type)
|
||||
}
|
||||
return builder.build()
|
||||
}
|
||||
@ -145,7 +151,7 @@ class CacheProvider : ContentProvider() {
|
||||
fun getCacheKey(uri: Uri): String {
|
||||
if (ContentResolver.SCHEME_CONTENT != uri.scheme)
|
||||
throw IllegalArgumentException(uri.toString())
|
||||
if (TwidereConstants.AUTHORITY_TWIDERE_CACHE != uri.authority)
|
||||
if (AUTHORITY_TWIDERE_CACHE != uri.authority)
|
||||
throw IllegalArgumentException(uri.toString())
|
||||
return ByteString.decodeBase64(uri.lastPathSegment).utf8()
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class AddUserListMembersTask(
|
||||
val nameFirst = preferences.getBoolean(KEY_NAME_FIRST)
|
||||
val displayName = userColorNameManager.getDisplayName(user.key, user.name,
|
||||
user.screen_name, nameFirst)
|
||||
message = context.getString(R.string.added_user_to_list, displayName, result.data.name)
|
||||
message = context.getString(R.string.message_toast_added_user_to_list, displayName, result.data.name)
|
||||
} else {
|
||||
val res = context.resources
|
||||
message = res.getQuantityString(R.plurals.added_N_users_to_list, users.size, users.size,
|
||||
|
@ -20,7 +20,6 @@
|
||||
package org.mariotaku.twidere.task
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.support.v4.app.DialogFragment
|
||||
import org.mariotaku.twidere.activity.iface.IBaseActivity
|
||||
import org.mariotaku.twidere.fragment.ProgressDialogFragment
|
||||
@ -31,10 +30,9 @@ import java.io.File
|
||||
*/
|
||||
abstract class ProgressSaveFileTask(
|
||||
context: Context,
|
||||
source: Uri,
|
||||
destination: File,
|
||||
getMimeType: SaveFileTask.FileInfoCallback
|
||||
) : SaveFileTask(context, source, destination, getMimeType) {
|
||||
fileInfo: FileInfo
|
||||
) : SaveFileTask(context, destination, fileInfo) {
|
||||
|
||||
override fun showProgress() {
|
||||
(context as IBaseActivity<*>).executeAfterFragmentResumed { activity ->
|
||||
|
@ -20,35 +20,28 @@
|
||||
package org.mariotaku.twidere.task
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.text.TextUtils.isEmpty
|
||||
import android.util.Log
|
||||
import okio.BufferedSink
|
||||
import okio.Okio
|
||||
import okio.Source
|
||||
import android.webkit.MimeTypeMap
|
||||
import org.mariotaku.twidere.TwidereConstants.LOGTAG
|
||||
import org.mariotaku.twidere.util.Utils
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
|
||||
abstract class SaveFileTask(
|
||||
context: Context,
|
||||
private val source: Uri,
|
||||
private val destination: File,
|
||||
private val getMimeType: SaveFileTask.FileInfoCallback
|
||||
private val fileInfo: FileInfo
|
||||
) : AsyncTask<Any, Any, SaveFileTask.SaveFileResult>() {
|
||||
|
||||
private val contextRef: WeakReference<Context>
|
||||
|
||||
init {
|
||||
this.contextRef = WeakReference(context)
|
||||
}
|
||||
private val contextRef = WeakReference(context)
|
||||
|
||||
override fun doInBackground(vararg args: Any): SaveFileResult? {
|
||||
val context = contextRef.get() ?: return null
|
||||
return saveFile(context, source, getMimeType, destination, requiresValidExtension)
|
||||
return saveFile(fileInfo, destination, requiresValidExtension)
|
||||
}
|
||||
|
||||
override fun onCancelled() {
|
||||
@ -81,14 +74,23 @@ abstract class SaveFileTask(
|
||||
protected val context: Context?
|
||||
get() = contextRef.get()
|
||||
|
||||
interface FileInfoCallback {
|
||||
fun getFilename(source: Uri): String?
|
||||
interface FileInfo : Closeable {
|
||||
val fileName: String?
|
||||
|
||||
fun getMimeType(source: Uri): String?
|
||||
val mimeType: String?
|
||||
|
||||
fun getExtension(mimeType: String?): String?
|
||||
val fileExtension: String? get() {
|
||||
val typeLowered = mimeType?.toLowerCase(Locale.US) ?: return null
|
||||
return when (typeLowered) {
|
||||
// Hack for fanfou image type
|
||||
"image/jpg" -> "jpg"
|
||||
else -> MimeTypeMap.getSingleton().getExtensionFromMimeType(typeLowered)
|
||||
}
|
||||
}
|
||||
|
||||
val specialCharacter: Char
|
||||
|
||||
fun inputStream(): InputStream
|
||||
}
|
||||
|
||||
class SaveFileResult(savedFile: File, mimeType: String) {
|
||||
@ -105,50 +107,42 @@ abstract class SaveFileTask(
|
||||
|
||||
companion object {
|
||||
|
||||
fun saveFile(context: Context, source: Uri,
|
||||
fileInfoCallback: FileInfoCallback,
|
||||
destinationDir: File, requiresValidExtension: Boolean): SaveFileResult? {
|
||||
val cr = context.contentResolver
|
||||
var ioSrc: Source? = null
|
||||
var sink: BufferedSink? = null
|
||||
try {
|
||||
var name: String = fileInfoCallback.getFilename(source) ?: return null
|
||||
fun saveFile(fileInfo: FileInfo, destinationDir: File, requiresValidExtension: Boolean) = try {
|
||||
fileInfo.use {
|
||||
var name: String = it.fileName ?: return null
|
||||
if (isEmpty(name)) return null
|
||||
if (name.length > 32) {
|
||||
name = name.substring(0, 32)
|
||||
}
|
||||
val mimeType = fileInfoCallback.getMimeType(source) ?: return null
|
||||
val extension = fileInfoCallback.getExtension(mimeType)
|
||||
val mimeType = it.mimeType ?: return null
|
||||
val extension = it.fileExtension
|
||||
if (requiresValidExtension && extension == null) {
|
||||
return null
|
||||
}
|
||||
if (!destinationDir.isDirectory && !destinationDir.mkdirs()) return null
|
||||
var nameToSave = getFileNameWithExtension(name, extension,
|
||||
fileInfoCallback.specialCharacter, null)
|
||||
it.specialCharacter, null)
|
||||
var saveFile = File(destinationDir, nameToSave)
|
||||
if (saveFile.exists()) {
|
||||
nameToSave = getFileNameWithExtension(name, extension,
|
||||
fileInfoCallback.specialCharacter,
|
||||
it.specialCharacter,
|
||||
System.currentTimeMillis().toString())
|
||||
saveFile = File(destinationDir, nameToSave)
|
||||
}
|
||||
val `in` = cr.openInputStream(source) ?: return null
|
||||
ioSrc = Okio.source(`in`)
|
||||
sink = Okio.buffer(Okio.sink(saveFile))
|
||||
sink!!.writeAll(ioSrc)
|
||||
sink.flush()
|
||||
return SaveFileResult(saveFile, mimeType)
|
||||
} catch (e: IOException) {
|
||||
Log.w(LOGTAG, "Failed to save file", e)
|
||||
return null
|
||||
} finally {
|
||||
Utils.closeSilently(sink)
|
||||
Utils.closeSilently(ioSrc)
|
||||
saveFile.outputStream().use { output ->
|
||||
it.inputStream().use { input ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
return@use SaveFileResult(saveFile, mimeType)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.w(LOGTAG, "Failed to save file", e)
|
||||
null
|
||||
}
|
||||
|
||||
internal fun getFileNameWithExtension(name: String, extension: String?,
|
||||
specialCharacter: Char, suffix: String?): String {
|
||||
specialCharacter: Char, suffix: String?): String {
|
||||
val sb = StringBuilder()
|
||||
var end = name.length
|
||||
if (extension != null) {
|
||||
|
@ -21,12 +21,8 @@ package org.mariotaku.twidere.task
|
||||
|
||||
import android.app.Activity
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import android.widget.Toast
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.annotation.CacheFileType
|
||||
import org.mariotaku.twidere.provider.CacheProvider
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
@ -34,10 +30,9 @@ import java.io.File
|
||||
*/
|
||||
class SaveMediaToGalleryTask(
|
||||
activity: Activity,
|
||||
source: Uri,
|
||||
destination: File,
|
||||
type: String
|
||||
) : ProgressSaveFileTask(activity, source, destination, CacheProvider.CacheFileTypeCallback(activity, type)) {
|
||||
fileInfo: FileInfo,
|
||||
destination: File
|
||||
) : ProgressSaveFileTask(activity, destination, fileInfo) {
|
||||
|
||||
override fun onFileSaved(savedFile: File, mimeType: String?) {
|
||||
val context = context ?: return
|
||||
@ -51,24 +46,4 @@ class SaveMediaToGalleryTask(
|
||||
Toast.makeText(context, R.string.message_toast_error_occurred, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun create(activity: Activity, source: Uri, @CacheFileType type: String): SaveFileTask {
|
||||
val pubDir: File
|
||||
when (type) {
|
||||
CacheFileType.VIDEO -> {
|
||||
pubDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
|
||||
}
|
||||
CacheFileType.IMAGE -> {
|
||||
pubDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
|
||||
}
|
||||
else -> {
|
||||
pubDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
}
|
||||
}
|
||||
val saveDir = File(pubDir, "Twidere")
|
||||
return SaveMediaToGalleryTask(activity, source, saveDir, type)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.text
|
||||
|
||||
import android.text.TextPaint
|
||||
import android.text.style.CharacterStyle
|
||||
import org.mariotaku.ktextension.contains
|
||||
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE
|
||||
@ -28,10 +29,10 @@ import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHL
|
||||
class TwidereHighLightStyle(private val option: Int) : CharacterStyle() {
|
||||
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
if (option and VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE != 0) {
|
||||
if (VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE in option) {
|
||||
ds.isUnderlineText = true
|
||||
}
|
||||
if (option and VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT != 0) {
|
||||
if (VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT in option) {
|
||||
ds.color = ds.linkColor
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ package org.mariotaku.twidere.text
|
||||
import android.text.TextPaint
|
||||
import android.text.style.URLSpan
|
||||
import android.view.View
|
||||
import org.mariotaku.ktextension.contains
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE
|
||||
@ -46,10 +47,10 @@ class TwidereURLSpan(
|
||||
}
|
||||
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
if (highlightStyle and VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE != 0) {
|
||||
if (VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE in highlightStyle) {
|
||||
ds.isUnderlineText = true
|
||||
}
|
||||
if (highlightStyle and VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT != 0) {
|
||||
if (VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT in highlightStyle) {
|
||||
ds.color = ds.linkColor
|
||||
}
|
||||
}
|
||||
|
@ -41,8 +41,8 @@ import org.mariotaku.twidere.annotation.NotificationType
|
||||
import org.mariotaku.twidere.constant.IntentConstants
|
||||
import org.mariotaku.twidere.constant.iWantMyStarsBackKey
|
||||
import org.mariotaku.twidere.constant.nameFirstKey
|
||||
import org.mariotaku.twidere.extension.model.getTitle
|
||||
import org.mariotaku.twidere.extension.model.getSummaryText
|
||||
import org.mariotaku.twidere.extension.model.getTitle
|
||||
import org.mariotaku.twidere.extension.model.notificationDisabled
|
||||
import org.mariotaku.twidere.extension.rawQuery
|
||||
import org.mariotaku.twidere.model.*
|
||||
@ -158,7 +158,7 @@ class ContentNotificationManager(
|
||||
Expression.equalsArgs(Activities.ACCOUNT_KEY),
|
||||
Expression.greaterThanArgs(Activities.POSITION_KEY)
|
||||
).sql
|
||||
val whereArgs = arrayOf(accountKey.toString(), position.toString())
|
||||
val whereArgs = arrayOf(accountKey.toString(), "0")
|
||||
@SuppressLint("Recycle")
|
||||
val c = cr.query(Activities.AboutMe.CONTENT_URI, Activities.COLUMNS, where, whereArgs,
|
||||
OrderBy(Activities.TIMESTAMP, false).sql) ?: return
|
||||
@ -182,9 +182,10 @@ class ContentNotificationManager(
|
||||
|
||||
var timestamp: Long = -1
|
||||
val filteredUserIds = DataStoreUtils.getFilteredUserIds(context)
|
||||
var consumed = 0
|
||||
val remaining = c.forEachRow(5) { cur, idx ->
|
||||
|
||||
val activity = ci.newObject(c)
|
||||
val activity = ci.newObject(cur)
|
||||
if (pref.isNotificationMentionsOnly && activity.action !in Activity.Action.MENTION_ACTIONS) {
|
||||
return@forEachRow false
|
||||
}
|
||||
@ -217,14 +218,16 @@ class ContentNotificationManager(
|
||||
pebbleNotificationStringBuilder.append(summary)
|
||||
pebbleNotificationStringBuilder.append("\n")
|
||||
}
|
||||
consumed++
|
||||
return@forEachRow true
|
||||
}
|
||||
if (remaining < 0) return
|
||||
if (remaining > 0) {
|
||||
style.addLine(resources.getString(R.string.and_N_more, count - c.position))
|
||||
pebbleNotificationStringBuilder.append(resources.getString(R.string.and_N_more, count - c.position))
|
||||
style.addLine(resources.getString(R.string.and_N_more, remaining))
|
||||
pebbleNotificationStringBuilder.append(resources.getString(R.string.and_N_more, remaining))
|
||||
}
|
||||
val displayCount = 5 + remaining
|
||||
val displayCount = consumed + remaining
|
||||
if (displayCount <= 0) return
|
||||
val title = resources.getQuantityString(R.plurals.N_new_interactions,
|
||||
displayCount, displayCount)
|
||||
builder.setContentTitle(title)
|
||||
@ -325,6 +328,7 @@ class ContentNotificationManager(
|
||||
moveToFirst()
|
||||
var current = 0
|
||||
while (!isAfterLast) {
|
||||
@Suppress("ConvertTwoComparisonsToRangeCheck")
|
||||
if (limit >= 0 && current >= limit) break
|
||||
if (action(this, current)) {
|
||||
current++
|
||||
|
@ -78,8 +78,6 @@ object DataStoreUtils {
|
||||
TABLE_ID_STATUSES)
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Activities.AboutMe.CONTENT_PATH,
|
||||
TABLE_ID_ACTIVITIES_ABOUT_ME)
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Activities.ByFriends.CONTENT_PATH,
|
||||
TABLE_ID_ACTIVITIES_BY_FRIENDS)
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Drafts.CONTENT_PATH,
|
||||
TABLE_ID_DRAFTS)
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, CachedUsers.CONTENT_PATH,
|
||||
@ -389,7 +387,6 @@ object DataStoreUtils {
|
||||
when (id) {
|
||||
TABLE_ID_STATUSES -> return Statuses.TABLE_NAME
|
||||
TABLE_ID_ACTIVITIES_ABOUT_ME -> return Activities.AboutMe.TABLE_NAME
|
||||
TABLE_ID_ACTIVITIES_BY_FRIENDS -> return Activities.ByFriends.TABLE_NAME
|
||||
TABLE_ID_DRAFTS -> return Drafts.TABLE_NAME
|
||||
TABLE_ID_FILTERED_USERS -> return Filters.Users.TABLE_NAME
|
||||
TABLE_ID_FILTERED_KEYWORDS -> return Filters.Keywords.TABLE_NAME
|
||||
|
@ -52,7 +52,6 @@ class TwidereSQLiteOpenHelper(
|
||||
db.beginTransaction()
|
||||
db.execSQL(createTable(Statuses.TABLE_NAME, Statuses.COLUMNS, Statuses.TYPES, true))
|
||||
db.execSQL(createTable(Activities.AboutMe.TABLE_NAME, Activities.AboutMe.COLUMNS, Activities.AboutMe.TYPES, true))
|
||||
db.execSQL(createTable(Activities.ByFriends.TABLE_NAME, Activities.ByFriends.COLUMNS, Activities.ByFriends.TYPES, true))
|
||||
db.execSQL(createTable(Drafts.TABLE_NAME, Drafts.COLUMNS, Drafts.TYPES, true))
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
@ -225,8 +224,6 @@ class TwidereSQLiteOpenHelper(
|
||||
safeUpgrade(db, Statuses.TABLE_NAME, Statuses.COLUMNS, Statuses.TYPES, true, null)
|
||||
safeUpgrade(db, Activities.AboutMe.TABLE_NAME, Activities.AboutMe.COLUMNS,
|
||||
Activities.AboutMe.TYPES, true, null)
|
||||
safeUpgrade(db, Activities.ByFriends.TABLE_NAME, Activities.ByFriends.COLUMNS,
|
||||
Activities.ByFriends.TYPES, true, null)
|
||||
migrateDrafts(db)
|
||||
safeUpgrade(db, CachedUsers.TABLE_NAME, CachedUsers.COLUMNS, CachedUsers.TYPES, true, null,
|
||||
createConflictReplaceConstraint(CachedUsers.USER_KEY))
|
||||
@ -254,6 +251,7 @@ class TwidereSQLiteOpenHelper(
|
||||
db.beginTransaction()
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, "network_usages").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, "mentions").sql)
|
||||
db.execSQL(SQLQueryBuilder.dropTable(true, "activities_by_friends").sql)
|
||||
createTriggers(db)
|
||||
createIndices(db)
|
||||
db.setTransactionSuccessful()
|
||||
|
@ -286,6 +286,15 @@ class ApplicationModule(private val application: Application) {
|
||||
return application.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun okHttpClient(preferences: SharedPreferencesWrapper, dns: Dns, connectionPool: ConnectionPool,
|
||||
cache: Cache): OkHttpClient {
|
||||
val conf = HttpClientFactory.HttpClientConfiguration(preferences)
|
||||
val builder = OkHttpClient.Builder()
|
||||
HttpClientFactory.initOkHttpClient(conf, builder, dns, connectionPool, cache)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun dataSourceFactory(preferences: SharedPreferencesWrapper, dns: Dns, connectionPool: ConnectionPool,
|
||||
|
@ -12,6 +12,7 @@ import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.View.OnLongClickListener
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.bumptech.glide.RequestManager
|
||||
import kotlinx.android.synthetic.main.list_item_status.view.*
|
||||
import org.mariotaku.ktextension.applyFontFamily
|
||||
@ -314,6 +315,10 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
||||
}
|
||||
|
||||
if (status.media.isNotNullOrEmpty()) {
|
||||
|
||||
mediaLabel.displayMediaLabel(status.card_name, status.media, status.location,
|
||||
status.place_full_name, status.is_possibly_sensitive)
|
||||
|
||||
if (!adapter.sensitiveContentEnabled && status.is_possibly_sensitive) {
|
||||
// Sensitive content, show label instead of media view
|
||||
mediaLabel.visibility = View.VISIBLE
|
||||
@ -418,6 +423,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
||||
private fun displayQuotedMedia(requestManager: RequestManager, status: ParcelableStatus) {
|
||||
if (status.quoted_media?.isNotEmpty() ?: false) {
|
||||
|
||||
quotedMediaLabel.displayMediaLabel(null, status.quoted_media, null, null,
|
||||
status.is_possibly_sensitive)
|
||||
|
||||
if (!adapter.sensitiveContentEnabled && status.is_possibly_sensitive) {
|
||||
// Sensitive content, show label instead of media view
|
||||
quotedMediaPreview.visibility = View.GONE
|
||||
@ -559,35 +567,47 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
||||
return !adapter.isCardActionsShown(RecyclerView.NO_POSITION)
|
||||
}
|
||||
|
||||
private fun displayExtraTypeIcon(cardName: String?, media: Array<ParcelableMedia?>?,
|
||||
private fun TextView.displayMediaLabel(cardName: String?, media: Array<ParcelableMedia?>?,
|
||||
location: ParcelableLocation?, placeFullName: String?,
|
||||
sensitive: Boolean) {
|
||||
val icon = if (sensitive) {
|
||||
R.drawable.ic_label_warning
|
||||
if (sensitive) {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_warning, 0, 0, 0)
|
||||
setText(R.string.label_sensitive)
|
||||
} else if (media != null && media.isNotEmpty()) {
|
||||
val type = media.type
|
||||
if (type in videoTypes) {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_video, 0, 0, 0)
|
||||
setText(R.string.label_video)
|
||||
} else if (media.size > 1) {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_gallery, 0, 0, 0)
|
||||
setText(R.string.label_photos)
|
||||
} else {
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_gallery, 0, 0, 0)
|
||||
setText(R.string.label_photo)
|
||||
}
|
||||
} else {
|
||||
R.drawable.ic_label_gallery
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(this, R.drawable.ic_label_gallery, 0, 0, 0)
|
||||
setText(R.string.label_media)
|
||||
}
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(mediaLabel, icon, 0, 0, 0)
|
||||
mediaLabel.refreshDrawableState()
|
||||
refreshDrawableState()
|
||||
}
|
||||
|
||||
private inline val Array<ParcelableMedia?>.type: Int get() {
|
||||
forEach { if (it != null) return it.type }
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun hasVideo(media: Array<ParcelableMedia?>?): Boolean {
|
||||
if (media == null) return false
|
||||
media.filterNotNull().forEach {
|
||||
when (it.type) {
|
||||
ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF, ParcelableMedia.Type.EXTERNAL_PLAYER -> return true
|
||||
}
|
||||
return media.any { item ->
|
||||
if (item == null) return@any false
|
||||
return@any videoTypes.contains(item.type)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
internal class EventListener(holder: StatusViewHolder) : OnClickListener, OnLongClickListener {
|
||||
|
||||
val holderRef: WeakReference<StatusViewHolder>
|
||||
|
||||
init {
|
||||
this.holderRef = WeakReference(holder)
|
||||
}
|
||||
private val holderRef = WeakReference(holder)
|
||||
|
||||
override fun onClick(v: View) {
|
||||
val holder = holderRef.get() ?: return
|
||||
@ -649,6 +669,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
||||
|
||||
companion object {
|
||||
const val layoutResource = R.layout.list_item_status
|
||||
|
||||
private val videoTypes = intArrayOf(ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF,
|
||||
ParcelableMedia.Type.EXTERNAL_PLAYER)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@
|
||||
<string name="action_add_tab">إضافة لسان</string>
|
||||
<string name="action_add_to_filter">إضافة إلى لائحة الكتم</string>
|
||||
<string name="action_add_to_list">إضافة إلى القائمة</string>
|
||||
<string name="added_user_to_list">أُضيف <xliff:g id="user">%1$s</xliff:g> إلى قائمة "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">أُضيف <xliff:g id="user">%1$s</xliff:g> إلى قائمة "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">و <xliff:g id="count">%d</xliff:g> أخرون</string>
|
||||
<string name="api_url_format">صيغة رابط الAPI</string>
|
||||
<string name="app_description">برنامجك الخاص لتويتر</string>
|
||||
|
@ -181,7 +181,7 @@
|
||||
<string name="action_add_tab">Amestar llingüeta</string>
|
||||
<string name="action_add_to_filter">Amestar a Peñeres</string>
|
||||
<string name="action_add_to_list">Amestar al llistáu</string>
|
||||
<string name="added_user_to_list">Amestóse a <xliff:g id="user">%1$s</xliff:g> al llistáu «<xliff:g id="list">%2$s</xliff:g>».</string>
|
||||
<string name="message_toast_added_user_to_list">Amestóse a <xliff:g id="user">%1$s</xliff:g> al llistáu «<xliff:g id="list">%2$s</xliff:g>».</string>
|
||||
<string name="and_N_more">y <xliff:g id="count">%d</xliff:g> más</string>
|
||||
<string name="api_url_format">Formatu d\'URL d\'API</string>
|
||||
<string name="app_description">El to veceru propiu de Twitter</string>
|
||||
|
@ -156,7 +156,7 @@
|
||||
<string name="action_add_tab">Afegeix una pestanya</string>
|
||||
<string name="action_add_to_filter">Afegeix al filtre</string>
|
||||
<string name="action_add_to_list">Afegeix a la llista</string>
|
||||
<string name="added_user_to_list">S\'ha afegit l\'usuari <xliff:g id="user">%1$s</xliff:g> a la llista «<xliff:g id="list">%2$s</xliff:g>».</string>
|
||||
<string name="message_toast_added_user_to_list">S\'ha afegit l\'usuari <xliff:g id="user">%1$s</xliff:g> a la llista «<xliff:g id="list">%2$s</xliff:g>».</string>
|
||||
<string name="and_N_more">i <xliff:g id="count">%d</xliff:g> més</string>
|
||||
<string name="api_url_format">Format de la URL de l\'API</string>
|
||||
<string name="app_description">La vostra app de Twitter</string>
|
||||
|
@ -183,7 +183,7 @@
|
||||
<string name="action_add_tab">Tab hinzufügen</string>
|
||||
<string name="action_add_to_filter">Zum Filter hinzufügen</string>
|
||||
<string name="action_add_to_list">Zur Liste hinzufügen</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> wurde zur Liste "<xliff:g id="list">%2$s</xliff:g>\" hinzugefügt.</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> wurde zur Liste "<xliff:g id="list">%2$s</xliff:g>\" hinzugefügt.</string>
|
||||
<string name="and_N_more">und <xliff:g id="count">%d</xliff:g> weitere</string>
|
||||
<string name="api_url_format">API URL Format</string>
|
||||
<string name="app_description">Deine eigene Twitter-App</string>
|
||||
|
@ -180,7 +180,7 @@
|
||||
<string name="action_add_tab">Agregar pestaña</string>
|
||||
<string name="action_add_to_filter">Añadir a filtros</string>
|
||||
<string name="action_add_to_list">Añadir a la lista</string>
|
||||
<string name="added_user_to_list">Agregado <xliff:g id="user">%1$s</xliff:g> a la lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Agregado <xliff:g id="user">%1$s</xliff:g> a la lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">y <xliff:g id="count">%d</xliff:g> más</string>
|
||||
<string name="api_url_format">Formato URL de la API</string>
|
||||
<string name="app_description">Tu propia aplicación de Twitter</string>
|
||||
|
@ -164,7 +164,7 @@
|
||||
<string name="action_add_tab">افزودن برگه</string>
|
||||
<string name="action_add_to_filter">افزودن به پالایه</string>
|
||||
<string name="action_add_to_list">افزودن به فهرست</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> را به فهرست «<xliff:g id="list">%2$s</xliff:g>» افزود.</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> را به فهرست «<xliff:g id="list">%2$s</xliff:g>» افزود.</string>
|
||||
<string name="and_N_more">و <xliff:g id="count">%d</xliff:g> بیشتر</string>
|
||||
<string name="api_url_format">قالب نشانی API</string>
|
||||
<string name="app_description">کارهٔ توییتر خودتان</string>
|
||||
|
@ -161,7 +161,7 @@
|
||||
<string name="action_add_tab">Lisää välilehti</string>
|
||||
<string name="action_add_to_filter">Lisää suodattimeen</string>
|
||||
<string name="action_add_to_list">Lisää listaan</string>
|
||||
<string name="added_user_to_list">Lisättiin <xliff:g id="user">%1$s</xliff:g> listalle "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Lisättiin <xliff:g id="user">%1$s</xliff:g> listalle "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">ja <xliff:g id="count">%d</xliff:g> muuta</string>
|
||||
<string name="api_url_format">API-URL:n muoto</string>
|
||||
<string name="app_description">Oma Twitter-sovelluksesi</string>
|
||||
|
@ -183,7 +183,7 @@
|
||||
<string name="action_add_tab">Ajouter un onglet</string>
|
||||
<string name="action_add_to_filter">Ajouter au filtre</string>
|
||||
<string name="action_add_to_list">Ajouter à la liste</string>
|
||||
<string name="added_user_to_list">Utilisateur <xliff:g id="user">%1$s</xliff:g> ajouté à la liste "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Utilisateur <xliff:g id="user">%1$s</xliff:g> ajouté à la liste "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">et encore <xliff:g id="count">%d</xliff:g></string>
|
||||
<string name="api_url_format">Format de l\'adresse API</string>
|
||||
<string name="app_description">Votre propre application Twitter</string>
|
||||
|
@ -157,7 +157,7 @@
|
||||
<string name="action_add_tab">Engadir tab.</string>
|
||||
<string name="action_add_to_filter">Engadir a filtro</string>
|
||||
<string name="action_add_to_list">Engadir á lista</string>
|
||||
<string name="added_user_to_list">Engadiches a <xliff:g id="user">%1$s</xliff:g> á lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Engadiches a <xliff:g id="user">%1$s</xliff:g> á lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">e <xliff:g id="count">%d</xliff:g> máis</string>
|
||||
<string name="api_url_format">Formato URL API</string>
|
||||
<string name="app_description">A túa propia aplicación Twitter</string>
|
||||
|
@ -127,7 +127,7 @@
|
||||
<string name="action_add_tab">Dodaj tab</string>
|
||||
<string name="action_add_to_filter">Dodaj u filter</string>
|
||||
<string name="action_add_to_list">Dodaj na listu</string>
|
||||
<string name="added_user_to_list">Dodano <xliff:g id="user">%1$s</xliff:g> na listu "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Dodano <xliff:g id="user">%1$s</xliff:g> na listu "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">i <xliff:g id="count">%d</xliff:g> više</string>
|
||||
<string name="api_url_format">API URL Format</string>
|
||||
<!-- App name, normally you don't need to translate this. -->
|
||||
|
@ -168,7 +168,7 @@
|
||||
<string name="action_add_tab">Fül hozzáadása</string>
|
||||
<string name="action_add_to_filter">Hozzáadás a szűrőhöz</string>
|
||||
<string name="action_add_to_list">Hozzáadás a listához</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> hozzáadva a listához: "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> hozzáadva a listához: "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">és még <xliff:g id="count">%d</xliff:g> elem</string>
|
||||
<string name="api_url_format">API URL formátum</string>
|
||||
<string name="app_description">A te Twitter alkalmazásod</string>
|
||||
|
@ -176,7 +176,7 @@
|
||||
<string name="action_add_tab">Tambah tab</string>
|
||||
<string name="action_add_to_filter">Tambahkan ke penyaringan</string>
|
||||
<string name="action_add_to_list">Masukkan ke daftar</string>
|
||||
<string name="added_user_to_list">Menambahkan <xliff:g id="user">%1$s</xliff:g> ke daftar "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Menambahkan <xliff:g id="user">%1$s</xliff:g> ke daftar "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">dan <xliff:g id="count">%d</xliff:g> lebih lagi</string>
|
||||
<string name="api_url_format">Format URL API</string>
|
||||
<string name="app_description">Aplikasi Twitter anda</string>
|
||||
|
@ -157,7 +157,7 @@
|
||||
<string name="action_add_tab">Aggiungi tab</string>
|
||||
<string name="action_add_to_filter">Aggiungi a filtro</string>
|
||||
<string name="action_add_to_list">Aggiungi alla lista</string>
|
||||
<string name="added_user_to_list">Aggiunto <xliff:g id="user">%1$s</xliff:g> alla lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Aggiunto <xliff:g id="user">%1$s</xliff:g> alla lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">e altri <xliff:g id="count">%d</xliff:g></string>
|
||||
<string name="api_url_format">Formato API URL</string>
|
||||
<string name="app_description">La tua Twitter app</string>
|
||||
|
@ -110,7 +110,7 @@
|
||||
<string name="action_add_member">הוסף משתמש</string>
|
||||
<string name="action_add_tab">הוסף כרטיסייה</string>
|
||||
<string name="action_add_to_list">הוסף לרשימה</string>
|
||||
<string name="added_user_to_list">המשתמש <xliff:g id="user">%1$s</xliff:g> נוסף לרשימה "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">המשתמש <xliff:g id="user">%1$s</xliff:g> נוסף לרשימה "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">ועוד <xliff:g id="count">%d</xliff:g></string>
|
||||
<string name="api_url_format">פורמט URL של הAPI</string>
|
||||
<string name="app_description">אפליקציית טוויטר משלך</string>
|
||||
|
@ -183,7 +183,7 @@
|
||||
<string name="action_add_tab">タブを追加</string>
|
||||
<string name="action_add_to_filter">フィルタに追加</string>
|
||||
<string name="action_add_to_list">リストに追加</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g>さんをリスト"<xliff:g id="list">%2$s</xliff:g>\"に追加しました。</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g>さんをリスト"<xliff:g id="list">%2$s</xliff:g>\"に追加しました。</string>
|
||||
<string name="and_N_more">他<xliff:g id="count">%d</xliff:g></string>
|
||||
<string name="api_url_format">API URL の形式</string>
|
||||
<string name="app_description">あなた自身の Twitter アプリ</string>
|
||||
|
@ -156,7 +156,7 @@
|
||||
<string name="action_add_tab">탭 추가</string>
|
||||
<string name="action_add_to_filter">필터에 추가</string>
|
||||
<string name="action_add_to_list">리스트에 추가</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g>님을 "<xliff:g id="list">%2$s</xliff:g>\" 리스트에 추가하였습니다.</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g>님을 "<xliff:g id="list">%2$s</xliff:g>\" 리스트에 추가하였습니다.</string>
|
||||
<string name="and_N_more">등 <xliff:g id="count">%d</xliff:g>개 이상</string>
|
||||
<string name="api_url_format">API 주소 형식</string>
|
||||
<string name="app_description">당신만의 트위터 앱</string>
|
||||
|
@ -158,7 +158,7 @@
|
||||
<string name="action_add_tab">Voeg een tabblad toe</string>
|
||||
<string name="action_add_to_filter">Voeg toe aan filter</string>
|
||||
<string name="action_add_to_list">Toevoegen aan lijst</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> toegevoegd aan lijst \'\'<xliff:g id="list">%2$s</xliff:g>\'\'.</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> toegevoegd aan lijst \'\'<xliff:g id="list">%2$s</xliff:g>\'\'.</string>
|
||||
<string name="and_N_more">en <xliff:g id="count">%d</xliff:g> meer</string>
|
||||
<string name="api_url_format">API URL-formaat</string>
|
||||
<string name="app_description">Je eigen Twitter-app</string>
|
||||
|
@ -143,7 +143,7 @@
|
||||
<string name="action_add_tab">Legg til fane</string>
|
||||
<string name="action_add_to_filter">Legg til filter</string>
|
||||
<string name="action_add_to_list">Legg til listen</string>
|
||||
<string name="added_user_to_list">La <xliff:g id="user">%1$s</xliff:g> til listen «<xliff:g id="list">%2$s</xliff:g>».</string>
|
||||
<string name="message_toast_added_user_to_list">La <xliff:g id="user">%1$s</xliff:g> til listen «<xliff:g id="list">%2$s</xliff:g>».</string>
|
||||
<string name="and_N_more">og <xliff:g id="count">%d</xliff:g> flere</string>
|
||||
<string name="api_url_format">API-URL-format</string>
|
||||
<string name="app_description">Din egen Twitter-app</string>
|
||||
|
@ -113,7 +113,7 @@
|
||||
<string name="action_add_tab">Dodaj zakładkę</string>
|
||||
<string name="action_add_to_filter">Dodaj do filtra</string>
|
||||
<string name="action_add_to_list">Dodaj do listy</string>
|
||||
<string name="added_user_to_list">Dodano <xliff:g id="user">%1$s</xliff:g> do listy "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Dodano <xliff:g id="user">%1$s</xliff:g> do listy "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">oraz <xliff:g id="count">%d</xliff:g> więcej</string>
|
||||
<string name="api_url_format">Format API URL</string>
|
||||
<!-- App name, normally you don't need to translate this. -->
|
||||
|
@ -163,7 +163,7 @@
|
||||
<string name="action_add_tab">Adicionar aba</string>
|
||||
<string name="action_add_to_filter">Adicionar filtro</string>
|
||||
<string name="action_add_to_list">Adicionar à lista</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> foi adicionado à lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> foi adicionado à lista "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">e <xliff:g id="count">%d</xliff:g> mais</string>
|
||||
<string name="api_url_format">Formato da URL da API</string>
|
||||
<string name="app_description">Seu próprio app de Twitter</string>
|
||||
|
@ -178,7 +178,7 @@
|
||||
<string name="action_add_tab">Добавить вкладку</string>
|
||||
<string name="action_add_to_filter">Добавить в фильтр</string>
|
||||
<string name="action_add_to_list">Добавить в список</string>
|
||||
<string name="added_user_to_list">Добавлен <xliff:g id="user">%1$s</xliff:g> в список "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Добавлен <xliff:g id="user">%1$s</xliff:g> в список "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">и еще <xliff:g id="count">%d</xliff:g></string>
|
||||
<string name="api_url_format">Формат API URL</string>
|
||||
<string name="app_description">Ваш собственный Твиттер-клиент</string>
|
||||
|
@ -160,7 +160,7 @@
|
||||
<string name="action_add_tab">เพิ่มแถบ</string>
|
||||
<string name="action_add_to_filter">เพิ่มไปยังตัวกรอง</string>
|
||||
<string name="action_add_to_list">เพิ่มไปยังรายการ</string>
|
||||
<string name="added_user_to_list">เพิ่ม <xliff:g id="user">%1$s</xliff:g> เข้าสู่ลิสต์ <xliff:g id="list">%2$s</xliff:g> แล้ว</string>
|
||||
<string name="message_toast_added_user_to_list">เพิ่ม <xliff:g id="user">%1$s</xliff:g> เข้าสู่ลิสต์ <xliff:g id="list">%2$s</xliff:g> แล้ว</string>
|
||||
<string name="and_N_more">และอีก <xliff:g id="count">%d</xliff:g></string>
|
||||
<string name="api_url_format">รูปแบบ URL ของ API</string>
|
||||
<string name="app_description">แอพทวิตเตอร์ของคุณเอง</string>
|
||||
|
@ -159,7 +159,7 @@
|
||||
<string name="action_add_tab">Sekme ekle</string>
|
||||
<string name="action_add_to_filter">Filtre ekle</string>
|
||||
<string name="action_add_to_list">Listeye ekle</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> listeye eklendi "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> listeye eklendi "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">ve <xliff:g id="count">%d</xliff:g> daha</string>
|
||||
<string name="api_url_format">API URL Format</string>
|
||||
<string name="app_description">Senin Twitter uygulaman</string>
|
||||
|
@ -160,7 +160,7 @@
|
||||
<string name="action_add_tab">Додати вкладку</string>
|
||||
<string name="action_add_to_filter">Додати до фільтру</string>
|
||||
<string name="action_add_to_list">Додати до списку</string>
|
||||
<string name="added_user_to_list">Додано <xliff:g id="user">%1$s</xliff:g> до списку "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="message_toast_added_user_to_list">Додано <xliff:g id="user">%1$s</xliff:g> до списку "<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
<string name="and_N_more">і ще <xliff:g id="count">%d</xliff:g></string>
|
||||
<string name="api_url_format">Формат API URL</string>
|
||||
<string name="app_description">Свій власний додаток Twitter</string>
|
||||
|
@ -183,7 +183,7 @@
|
||||
<string name="action_add_tab">添加标签页</string>
|
||||
<string name="action_add_to_filter">添加到过滤器</string>
|
||||
<string name="action_add_to_list">添加到列表</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> 被添加到了列表 “<xliff:g id="list">%2$s</xliff:g>”</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> 被添加到了列表 “<xliff:g id="list">%2$s</xliff:g>”</string>
|
||||
<string name="and_N_more">和其他 <xliff:g id="count">%d</xliff:g> 个</string>
|
||||
<string name="api_url_format">API URL 格式</string>
|
||||
<string name="app_description">属于您的 Twitter 应用</string>
|
||||
|
@ -183,7 +183,7 @@
|
||||
<string name="action_add_tab">新增標籤頁</string>
|
||||
<string name="action_add_to_filter">新增到過濾器</string>
|
||||
<string name="action_add_to_list">新增到列表</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> 被新增到了 "<xliff:g id="list">%2$s</xliff:g>\" 列表</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> 被新增到了 "<xliff:g id="list">%2$s</xliff:g>\" 列表</string>
|
||||
<string name="and_N_more">和其他<xliff:g id="count">%d</xliff:g>個</string>
|
||||
<string name="api_url_format">API URL 格式</string>
|
||||
<string name="app_description">您的 Twitter 應用程式</string>
|
||||
|
@ -183,7 +183,7 @@
|
||||
<string name="action_add_tab">新增標籤頁</string>
|
||||
<string name="action_add_to_filter">新增到過濾器</string>
|
||||
<string name="action_add_to_list">新增到列表</string>
|
||||
<string name="added_user_to_list"><xliff:g id="user">%1$s</xliff:g> 被新增到了 "<xliff:g id="list">%2$s</xliff:g>\" 列表</string>
|
||||
<string name="message_toast_added_user_to_list"><xliff:g id="user">%1$s</xliff:g> 被新增到了 "<xliff:g id="list">%2$s</xliff:g>\" 列表</string>
|
||||
<string name="and_N_more">和其他<xliff:g id="count">%d</xliff:g>個</string>
|
||||
<string name="api_url_format">API URL 格式</string>
|
||||
<string name="app_description">您的 Twitter 應用程式</string>
|
||||
|
@ -167,10 +167,10 @@
|
||||
android:drawableStart="@drawable/ic_label_gallery"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/element_size_small"
|
||||
android:text="@string/media"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:textStyle="bold"
|
||||
app:iabColor="?android:textColorSecondary"/>
|
||||
app:iabColor="?android:textColorSecondary"
|
||||
tools:text="@string/label_media"/>
|
||||
|
||||
<org.mariotaku.twidere.view.CardMediaContainer
|
||||
android:id="@+id/mediaPreview"
|
||||
@ -265,10 +265,10 @@
|
||||
android:drawableLeft="@drawable/ic_label_gallery"
|
||||
android:drawableStart="@drawable/ic_label_gallery"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/media"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:textStyle="bold"
|
||||
app:iabColor="?android:textColorSecondary"
|
||||
tools:text="@string/label_media"
|
||||
tools:visibility="gone"/>
|
||||
|
||||
<org.mariotaku.twidere.view.CardMediaContainer
|
||||
|
@ -150,58 +150,56 @@
|
||||
<string name="activities_about_me">Activities about me</string>
|
||||
<string name="activities_by_friends">Activities by friends</string>
|
||||
|
||||
<string name="activity_about_me_favorite"><xliff:g id="user">%s</xliff:g> favorited your tweet.</string>
|
||||
<string name="activity_about_me_favorite_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited your tweet.</string>
|
||||
<string name="activity_about_me_favorited_media_tagged"><xliff:g id="user">%s</xliff:g> favorited a tweet you were tagged in.</string>
|
||||
<string name="activity_about_me_favorited_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited a tweet you were tagged in.</string>
|
||||
<string name="activity_about_me_favorited_mention"><xliff:g id="user">%s</xliff:g> favorited a tweet you were mentioned in.</string>
|
||||
<string name="activity_about_me_favorited_mention_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited a tweet you were mentioned in.</string>
|
||||
<string name="activity_about_me_favorited_retweet"><xliff:g id="user">%s</xliff:g> favorited your retweet.</string>
|
||||
<string name="activity_about_me_favorited_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited your retweet.</string>
|
||||
<string name="activity_about_me_follow"><xliff:g id="user">%s</xliff:g> is following you.</string>
|
||||
<string name="activity_about_me_follow_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> are following you.</string>
|
||||
<string name="activity_about_me_like"><xliff:g id="user">%s</xliff:g> liked your tweet.</string>
|
||||
<string name="activity_about_me_like_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked your tweet.</string>
|
||||
<string name="activity_about_me_liked_media_tagged"><xliff:g id="user">%s</xliff:g> liked a tweet you were tagged in.</string>
|
||||
<string name="activity_about_me_liked_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked a tweet you were tagged in.</string>
|
||||
<string name="activity_about_me_liked_mention"><xliff:g id="user">%s</xliff:g> liked a tweet you were mentioned in.</string>
|
||||
<string name="activity_about_me_liked_mention_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked a tweet you were mentioned in.</string>
|
||||
<string name="activity_about_me_liked_retweet"><xliff:g id="user">%s</xliff:g> liked your retweet.</string>
|
||||
<string name="activity_about_me_liked_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked your retweet.</string>
|
||||
<string name="activity_about_me_list_member_added"><xliff:g id="user">%s</xliff:g> added you to list.</string>
|
||||
<string name="activity_about_me_list_member_added_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> added you to their lists.</string>
|
||||
<string name="activity_about_me_list_member_added_with_name"><xliff:g id="user">%1$s</xliff:g> added you to list <xliff:g id="list">%2$s</xliff:g>".</string>
|
||||
<string name="activity_about_me_media_tagged"><xliff:g id="user">%s</xliff:g> tagged you.</string>
|
||||
<string name="activity_about_me_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> tagged you.</string>
|
||||
<string name="activity_about_me_retweet"><xliff:g id="user">%s</xliff:g> retweeted your tweet.</string>
|
||||
<string name="activity_about_me_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted your tweet.</string>
|
||||
<string name="activity_about_me_retweeted_media_tagged"><xliff:g id="user">%s</xliff:g> retweeted a tweet you were tagged in.</string>
|
||||
<string name="activity_about_me_retweeted_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted a tweet you were tagged in.</string>
|
||||
<string name="activity_about_me_retweeted_mention"><xliff:g id="user">%s</xliff:g> retweeted a tweet you were mentioned in.</string>
|
||||
<string name="activity_about_me_retweeted_mention_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted a tweet you were mentioned in.</string>
|
||||
<string name="activity_about_me_retweeted_retweet"><xliff:g id="user">%s</xliff:g> retweeted your retweet.</string>
|
||||
<string name="activity_about_me_retweeted_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted your retweet.</string>
|
||||
<string name="activity_by_friends_favorite"><xliff:g id="user">%1$s</xliff:g> favorited <xliff:g id="target">%2$s</xliff:g>\'s tweet.</string>
|
||||
<string name="activity_by_friends_favorite_multi"><xliff:g id="user">%1$s</xliff:g> favorited <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g>\'s tweet.</string>
|
||||
<string name="activity_by_friends_follow"><xliff:g id="user">%1$s</xliff:g> is following <xliff:g id="target">%2$s</xliff:g>.</string>
|
||||
<string name="activity_by_friends_follow_multi"><xliff:g id="user">%1$s</xliff:g> is following <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g>.</string>
|
||||
<string name="activity_by_friends_like"><xliff:g id="user">%1$s</xliff:g> liked <xliff:g id="target">%2$s</xliff:g>\'s tweet.</string>
|
||||
<string name="activity_by_friends_like_multi"><xliff:g id="user">%1$s</xliff:g> liked <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g>\'s tweet.</string>
|
||||
<string name="activity_by_friends_list_created"><xliff:g id="user">%1$s</xliff:g> created list <xliff:g id="target">%2$s</xliff:g>.</string>
|
||||
<string name="activity_by_friends_list_created_multi"><xliff:g id="user">%1$s</xliff:g> created list <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%1$s</xliff:g>.</string>
|
||||
<string name="activity_by_friends_list_member_added"><xliff:g id="user">%1$s</xliff:g> added <xliff:g id="target">%2$s</xliff:g> to list.</string>
|
||||
<string name="activity_by_friends_list_member_added_multi"><xliff:g id="user">%1$s</xliff:g> added <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%1$s</xliff:g> to list.</string>
|
||||
<string name="activity_by_friends_retweet"><xliff:g id="user">%1$s</xliff:g> retweeted <xliff:g id="target">%2$s</xliff:g>\'s tweet.</string>
|
||||
<string name="activity_by_friends_retweet_multi"><xliff:g id="user">%1$s</xliff:g> retweeted <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g>\'s tweet.</string>
|
||||
<string name="activity_joined_twitter"><xliff:g id="user">%s</xliff:g> joined Twitter.</string>
|
||||
<string name="activity_joined_twitter_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> joined Twitter.</string>
|
||||
<string name="activity_about_me_favorite"><xliff:g id="user">%s</xliff:g> favorited</string>
|
||||
<string name="activity_about_me_favorite_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited</string>
|
||||
<string name="activity_about_me_favorited_media_tagged"><xliff:g id="user">%s</xliff:g> favorited a tweet you were tagged in</string>
|
||||
<string name="activity_about_me_favorited_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited a tweet you were tagged in</string>
|
||||
<string name="activity_about_me_favorited_mention"><xliff:g id="user">%s</xliff:g> favorited a tweet you were mentioned in</string>
|
||||
<string name="activity_about_me_favorited_mention_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited a tweet you were mentioned in</string>
|
||||
<string name="activity_about_me_favorited_retweet"><xliff:g id="user">%s</xliff:g> favorited your retweet</string>
|
||||
<string name="activity_about_me_favorited_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> favorited your retweet</string>
|
||||
<string name="activity_about_me_follow"><xliff:g id="user">%s</xliff:g> is following you</string>
|
||||
<string name="activity_about_me_follow_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> are following you</string>
|
||||
<string name="activity_about_me_like"><xliff:g id="user">%s</xliff:g> liked</string>
|
||||
<string name="activity_about_me_like_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked</string>
|
||||
<string name="activity_about_me_liked_media_tagged"><xliff:g id="user">%s</xliff:g> liked a tweet you were tagged in</string>
|
||||
<string name="activity_about_me_liked_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked a tweet you were tagged in</string>
|
||||
<string name="activity_about_me_liked_mention"><xliff:g id="user">%s</xliff:g> liked a tweet you were mentioned in</string>
|
||||
<string name="activity_about_me_liked_mention_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked a tweet you were mentioned in</string>
|
||||
<string name="activity_about_me_liked_retweet"><xliff:g id="user">%s</xliff:g> liked your retweet</string>
|
||||
<string name="activity_about_me_liked_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> liked your retweet</string>
|
||||
<string name="activity_about_me_list_member_added"><xliff:g id="user">%s</xliff:g> added you to list</string>
|
||||
<string name="activity_about_me_list_member_added_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> added you to their lists</string>
|
||||
<string name="activity_about_me_list_member_added_with_name"><xliff:g id="user">%1$s</xliff:g> added you to list <xliff:g id="list">%2$s</xliff:g>"</string>
|
||||
<string name="activity_about_me_media_tagged"><xliff:g id="user">%s</xliff:g> tagged you</string>
|
||||
<string name="activity_about_me_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> tagged you</string>
|
||||
<string name="activity_about_me_retweet"><xliff:g id="user">%s</xliff:g> retweeted</string>
|
||||
<string name="activity_about_me_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted</string>
|
||||
<string name="activity_about_me_retweeted_media_tagged"><xliff:g id="user">%s</xliff:g> retweeted a tweet you were tagged in</string>
|
||||
<string name="activity_about_me_retweeted_media_tagged_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted a tweet you were tagged in</string>
|
||||
<string name="activity_about_me_retweeted_mention"><xliff:g id="user">%s</xliff:g> retweeted a tweet you were mentioned in</string>
|
||||
<string name="activity_about_me_retweeted_mention_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted a tweet you were mentioned in</string>
|
||||
<string name="activity_about_me_retweeted_retweet"><xliff:g id="user">%s</xliff:g> retweeted your retweet</string>
|
||||
<string name="activity_about_me_retweeted_retweet_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> retweeted your retweet</string>
|
||||
<string name="activity_by_friends_favorite"><xliff:g id="user">%1$s</xliff:g> favorited <xliff:g id="target">%2$s</xliff:g>\'s tweet</string>
|
||||
<string name="activity_by_friends_favorite_multi"><xliff:g id="user">%1$s</xliff:g> favorited <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g>\'s tweet</string>
|
||||
<string name="activity_by_friends_follow"><xliff:g id="user">%1$s</xliff:g> is following <xliff:g id="target">%2$s</xliff:g></string>
|
||||
<string name="activity_by_friends_follow_multi"><xliff:g id="user">%1$s</xliff:g> is following <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g></string>
|
||||
<string name="activity_by_friends_like"><xliff:g id="user">%1$s</xliff:g> liked <xliff:g id="target">%2$s</xliff:g>\'s tweet</string>
|
||||
<string name="activity_by_friends_like_multi"><xliff:g id="user">%1$s</xliff:g> liked <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g>\'s tweet</string>
|
||||
<string name="activity_by_friends_list_created"><xliff:g id="user">%1$s</xliff:g> created list <xliff:g id="target">%2$s</xliff:g></string>
|
||||
<string name="activity_by_friends_list_created_multi"><xliff:g id="user">%1$s</xliff:g> created list <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%1$s</xliff:g></string>
|
||||
<string name="activity_by_friends_list_member_added"><xliff:g id="user">%1$s</xliff:g> added <xliff:g id="target">%2$s</xliff:g> to list</string>
|
||||
<string name="activity_by_friends_list_member_added_multi"><xliff:g id="user">%1$s</xliff:g> added <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%1$s</xliff:g> to list</string>
|
||||
<string name="activity_by_friends_retweet"><xliff:g id="user">%1$s</xliff:g> retweeted <xliff:g id="target">%2$s</xliff:g>\'s tweet</string>
|
||||
<string name="activity_by_friends_retweet_multi"><xliff:g id="user">%1$s</xliff:g> retweeted <xliff:g id="target">%2$s</xliff:g> and <xliff:g id="other">%3$s</xliff:g>\'s tweet</string>
|
||||
<string name="activity_joined_twitter"><xliff:g id="user">%s</xliff:g> joined Twitter</string>
|
||||
<string name="activity_joined_twitter_multi"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="other">%2$s</xliff:g> joined Twitter</string>
|
||||
|
||||
<string name="add_account">Add account</string>
|
||||
<string name="add_host_mapping">Add host mapping</string>
|
||||
<string name="add_image">Add image</string>
|
||||
|
||||
<string name="added_user_to_list">Added <xliff:g id="user">%1$s</xliff:g> to list \"<xliff:g id="list">%2$s</xliff:g>\".</string>
|
||||
|
||||
<string name="and_N_more">and <xliff:g id="count">%d</xliff:g> more</string>
|
||||
|
||||
<string name="api_url_format">API URL Format</string>
|
||||
@ -574,6 +572,11 @@
|
||||
<string name="mark_as_sensitive">Mark as sensitive</string>
|
||||
|
||||
<string name="media">Media</string>
|
||||
<string name="label_media">Media</string>
|
||||
<string name="label_sensitive">Sensitive</string>
|
||||
<string name="label_photo">Photo</string>
|
||||
<string name="label_photos">Photos</string>
|
||||
<string name="label_video">Video</string>
|
||||
<string name="media_preload">Media preload</string>
|
||||
<string name="media_preview">Media preview</string>
|
||||
<string name="media_preview_style">Media preview style</string>
|
||||
@ -622,8 +625,9 @@
|
||||
~ periods should be omitted
|
||||
-->
|
||||
<eat-comment/>
|
||||
<string name="message_toast_accepted_users_follow_request">Accepted <xliff:g id="user">%s</xliff:g>\'s follow request.</string>
|
||||
<string name="message_toast_accepted_users_follow_request">Accepted <xliff:g id="user">%s</xliff:g>\'s follow request</string>
|
||||
<string name="message_toast_added_to_filter">Added to filter</string>
|
||||
<string name="message_toast_added_user_to_list">Added <xliff:g id="user">%1$s</xliff:g> to list \"<xliff:g id="list">%2$s</xliff:g>\"</string>
|
||||
<string name="message_toast_already_logged_in">You have already logged in</string>
|
||||
<string name="message_toast_cannot_get_location">Can\'t get your location</string>
|
||||
<string name="message_toast_compose_write_storage_no_permission">Permission required to delete taken photo/video</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user