657 lines
26 KiB
Kotlin
657 lines
26 KiB
Kotlin
/* Copyright 2021 Tusky Contributors
|
|
*
|
|
* This file is a part of Tusky.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
* Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
|
* see <http://www.gnu.org/licenses>. */
|
|
|
|
package com.keylesspalace.tusky.components.search.fragments
|
|
|
|
import android.Manifest
|
|
import android.app.DownloadManager
|
|
import android.content.ClipData
|
|
import android.content.ClipboardManager
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.net.Uri
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.os.Environment
|
|
import android.util.Log
|
|
import android.view.View
|
|
import android.widget.Toast
|
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
import androidx.appcompat.app.AlertDialog
|
|
import androidx.appcompat.widget.PopupMenu
|
|
import androidx.core.app.ActivityOptionsCompat
|
|
import androidx.core.content.getSystemService
|
|
import androidx.core.view.ViewCompat
|
|
import androidx.lifecycle.lifecycleScope
|
|
import androidx.paging.PagingData
|
|
import androidx.paging.PagingDataAdapter
|
|
import androidx.preference.PreferenceManager
|
|
import androidx.recyclerview.widget.DividerItemDecoration
|
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
import at.connyduck.calladapter.networkresult.fold
|
|
import at.connyduck.calladapter.networkresult.onFailure
|
|
import com.google.android.material.snackbar.Snackbar
|
|
import com.keylesspalace.tusky.R
|
|
import com.keylesspalace.tusky.ViewMediaActivity
|
|
import com.keylesspalace.tusky.components.compose.ComposeActivity
|
|
import com.keylesspalace.tusky.components.compose.ComposeActivity.ComposeOptions
|
|
import com.keylesspalace.tusky.components.report.ReportActivity
|
|
import com.keylesspalace.tusky.components.search.adapter.SearchStatusesAdapter
|
|
import com.keylesspalace.tusky.db.AccountEntity
|
|
import com.keylesspalace.tusky.db.AccountManager
|
|
import com.keylesspalace.tusky.entity.Attachment
|
|
import com.keylesspalace.tusky.entity.Status
|
|
import com.keylesspalace.tusky.entity.Status.Mention
|
|
import com.keylesspalace.tusky.interfaces.AccountSelectionListener
|
|
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
|
import com.keylesspalace.tusky.settings.PrefKeys
|
|
import com.keylesspalace.tusky.util.CardViewMode
|
|
import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate
|
|
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
|
import com.keylesspalace.tusky.util.openLink
|
|
import com.keylesspalace.tusky.util.startActivityWithSlideInAnimation
|
|
import com.keylesspalace.tusky.view.showMuteAccountDialog
|
|
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
|
import com.keylesspalace.tusky.viewdata.StatusViewData
|
|
import java.util.Locale
|
|
import javax.inject.Inject
|
|
import kotlinx.coroutines.flow.Flow
|
|
import kotlinx.coroutines.launch
|
|
|
|
class SearchStatusesFragment : SearchFragment<StatusViewData.Concrete>(), StatusActionListener {
|
|
@Inject
|
|
lateinit var accountManager: AccountManager
|
|
|
|
override val data: Flow<PagingData<StatusViewData.Concrete>>
|
|
get() = viewModel.statusesFlow
|
|
|
|
private val searchAdapter
|
|
get() = super.adapter as SearchStatusesAdapter
|
|
|
|
private var pendingMediaDownloads: List<String>? = null
|
|
|
|
private val downloadAllMediaPermissionLauncher =
|
|
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
|
if (isGranted) {
|
|
pendingMediaDownloads?.let { downloadAllMedia(it) }
|
|
} else {
|
|
Toast.makeText(
|
|
context,
|
|
R.string.error_media_download_permission,
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
}
|
|
pendingMediaDownloads = null
|
|
}
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
pendingMediaDownloads = savedInstanceState?.getStringArrayList(PENDING_MEDIA_DOWNLOADS_STATE_KEY)
|
|
}
|
|
|
|
override fun onSaveInstanceState(outState: Bundle) {
|
|
super.onSaveInstanceState(outState)
|
|
pendingMediaDownloads?.let {
|
|
outState.putStringArrayList(PENDING_MEDIA_DOWNLOADS_STATE_KEY, ArrayList(it))
|
|
}
|
|
}
|
|
|
|
override fun createAdapter(): PagingDataAdapter<StatusViewData.Concrete, *> {
|
|
val preferences = PreferenceManager.getDefaultSharedPreferences(
|
|
binding.searchRecyclerView.context
|
|
)
|
|
val statusDisplayOptions = StatusDisplayOptions(
|
|
animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false),
|
|
mediaPreviewEnabled = viewModel.mediaPreviewEnabled,
|
|
useAbsoluteTime = preferences.getBoolean(PrefKeys.ABSOLUTE_TIME_VIEW, false),
|
|
showBotOverlay = preferences.getBoolean(PrefKeys.SHOW_BOT_OVERLAY, true),
|
|
useBlurhash = preferences.getBoolean(PrefKeys.USE_BLURHASH, true),
|
|
cardViewMode = CardViewMode.NONE,
|
|
confirmReblogs = preferences.getBoolean(PrefKeys.CONFIRM_REBLOGS, true),
|
|
confirmFavourites = preferences.getBoolean(PrefKeys.CONFIRM_FAVOURITES, false),
|
|
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false),
|
|
animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false),
|
|
showStatsInline = preferences.getBoolean(PrefKeys.SHOW_STATS_INLINE, false),
|
|
showSensitiveMedia = accountManager.activeAccount!!.alwaysShowSensitiveMedia,
|
|
openSpoiler = accountManager.activeAccount!!.alwaysOpenSpoiler
|
|
)
|
|
|
|
binding.searchRecyclerView.setAccessibilityDelegateCompat(
|
|
ListStatusAccessibilityDelegate(binding.searchRecyclerView, this) { pos ->
|
|
if (pos in 0 until adapter.itemCount) {
|
|
adapter.peek(pos)
|
|
} else {
|
|
null
|
|
}
|
|
}
|
|
)
|
|
|
|
binding.searchRecyclerView.addItemDecoration(
|
|
DividerItemDecoration(
|
|
binding.searchRecyclerView.context,
|
|
DividerItemDecoration.VERTICAL
|
|
)
|
|
)
|
|
binding.searchRecyclerView.layoutManager =
|
|
LinearLayoutManager(binding.searchRecyclerView.context)
|
|
return SearchStatusesAdapter(statusDisplayOptions, this)
|
|
}
|
|
|
|
override fun onContentHiddenChange(isShowing: Boolean, position: Int) {
|
|
searchAdapter.peek(position)?.let {
|
|
viewModel.contentHiddenChange(it, isShowing)
|
|
}
|
|
}
|
|
|
|
override fun onReply(position: Int) {
|
|
searchAdapter.peek(position)?.let { status ->
|
|
reply(status)
|
|
}
|
|
}
|
|
|
|
override fun onFavourite(favourite: Boolean, position: Int) {
|
|
searchAdapter.peek(position)?.let { status ->
|
|
viewModel.favorite(status, favourite)
|
|
}
|
|
}
|
|
|
|
override fun onBookmark(bookmark: Boolean, position: Int) {
|
|
searchAdapter.peek(position)?.let { status ->
|
|
viewModel.bookmark(status, bookmark)
|
|
}
|
|
}
|
|
|
|
override fun onMore(view: View, position: Int) {
|
|
searchAdapter.peek(position)?.let {
|
|
more(it, view, position)
|
|
}
|
|
}
|
|
|
|
override fun onViewMedia(position: Int, attachmentIndex: Int, view: View?) {
|
|
searchAdapter.peek(position)?.status?.actionableStatus?.let { actionable ->
|
|
when (actionable.attachments[attachmentIndex].type) {
|
|
Attachment.Type.GIFV, Attachment.Type.VIDEO, Attachment.Type.IMAGE, Attachment.Type.AUDIO -> {
|
|
val attachments = AttachmentViewData.list(actionable)
|
|
val intent = ViewMediaActivity.newIntent(
|
|
context,
|
|
attachments,
|
|
attachmentIndex
|
|
)
|
|
if (view != null) {
|
|
val url = actionable.attachments[attachmentIndex].url
|
|
ViewCompat.setTransitionName(view, url)
|
|
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
|
|
requireActivity(),
|
|
view,
|
|
url
|
|
)
|
|
startActivity(intent, options.toBundle())
|
|
} else {
|
|
startActivity(intent)
|
|
}
|
|
}
|
|
|
|
Attachment.Type.UNKNOWN -> {
|
|
context?.openLink(actionable.attachments[attachmentIndex].url)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onViewThread(position: Int) {
|
|
searchAdapter.peek(position)?.status?.let { status ->
|
|
val actionableStatus = status.actionableStatus
|
|
bottomSheetActivity?.viewThread(actionableStatus.id, actionableStatus.url)
|
|
}
|
|
}
|
|
|
|
override fun onOpenReblog(position: Int) {
|
|
searchAdapter.peek(position)?.status?.let { status ->
|
|
bottomSheetActivity?.viewAccount(status.account.id)
|
|
}
|
|
}
|
|
|
|
override fun onExpandedChange(expanded: Boolean, position: Int) {
|
|
searchAdapter.peek(position)?.let {
|
|
viewModel.expandedChange(it, expanded)
|
|
}
|
|
}
|
|
|
|
override fun onLoadMore(position: Int) {
|
|
// Not possible here
|
|
}
|
|
|
|
override fun onContentCollapsedChange(isCollapsed: Boolean, position: Int) {
|
|
searchAdapter.peek(position)?.let {
|
|
viewModel.collapsedChange(it, isCollapsed)
|
|
}
|
|
}
|
|
|
|
override fun onVoteInPoll(position: Int, choices: MutableList<Int>) {
|
|
searchAdapter.peek(position)?.let {
|
|
viewModel.voteInPoll(it, choices)
|
|
}
|
|
}
|
|
|
|
override fun clearWarningAction(position: Int) {}
|
|
|
|
private fun removeItem(position: Int) {
|
|
searchAdapter.peek(position)?.let {
|
|
viewModel.removeItem(it)
|
|
}
|
|
}
|
|
|
|
override fun onReblog(reblog: Boolean, position: Int) {
|
|
searchAdapter.peek(position)?.let { status ->
|
|
viewModel.reblog(status, reblog)
|
|
}
|
|
}
|
|
|
|
override fun onUntranslate(position: Int) {
|
|
searchAdapter.peek(position)?.let {
|
|
viewModel.untranslate(it)
|
|
}
|
|
}
|
|
|
|
private fun reply(status: StatusViewData.Concrete) {
|
|
val actionableStatus = status.actionable
|
|
val mentionedUsernames = actionableStatus.mentions.map { it.username }
|
|
.toMutableSet()
|
|
.apply {
|
|
add(actionableStatus.account.username)
|
|
remove(viewModel.activeAccount?.username)
|
|
}
|
|
|
|
val intent = ComposeActivity.startIntent(
|
|
requireContext(),
|
|
ComposeOptions(
|
|
inReplyToId = status.actionableId,
|
|
replyVisibility = actionableStatus.visibility,
|
|
contentWarning = actionableStatus.spoilerText,
|
|
mentionedUsernames = mentionedUsernames,
|
|
replyingStatusAuthor = actionableStatus.account.localUsername,
|
|
replyingStatusContent = status.content.toString(),
|
|
language = actionableStatus.language,
|
|
kind = ComposeActivity.ComposeKind.NEW
|
|
)
|
|
)
|
|
bottomSheetActivity?.startActivityWithSlideInAnimation(intent)
|
|
}
|
|
|
|
private fun more(statusViewData: StatusViewData.Concrete, view: View, position: Int) {
|
|
val status = statusViewData.status
|
|
val id = status.actionableId
|
|
val accountId = status.actionableStatus.account.id
|
|
val accountUsername = status.actionableStatus.account.username
|
|
val statusUrl = status.actionableStatus.url
|
|
val loggedInAccountId = viewModel.activeAccount?.accountId
|
|
|
|
val popup = PopupMenu(view.context, view)
|
|
val statusIsByCurrentUser = loggedInAccountId?.equals(accountId) == true
|
|
// Give a different menu depending on whether this is the user's own toot or not.
|
|
if (statusIsByCurrentUser) {
|
|
popup.inflate(R.menu.status_more_for_user)
|
|
val menu = popup.menu
|
|
menu.findItem(R.id.status_open_as).isVisible = !statusUrl.isNullOrBlank()
|
|
when (status.visibility) {
|
|
Status.Visibility.PUBLIC, Status.Visibility.UNLISTED -> {
|
|
val textId =
|
|
getString(
|
|
if (status.pinned) R.string.unpin_action else R.string.pin_action
|
|
)
|
|
menu.add(0, R.id.pin, 1, textId)
|
|
}
|
|
|
|
Status.Visibility.PRIVATE -> {
|
|
var reblogged = status.reblogged
|
|
if (status.reblog != null) reblogged = status.reblog.reblogged
|
|
menu.findItem(R.id.status_reblog_private).isVisible = !reblogged
|
|
menu.findItem(R.id.status_unreblog_private).isVisible = reblogged
|
|
}
|
|
|
|
Status.Visibility.UNKNOWN, Status.Visibility.DIRECT -> {
|
|
} // Ignore
|
|
}
|
|
} else {
|
|
popup.inflate(R.menu.status_more)
|
|
val menu = popup.menu
|
|
menu.findItem(R.id.status_download_media).isVisible = status.attachments.isNotEmpty()
|
|
}
|
|
|
|
val openAsItem = popup.menu.findItem(R.id.status_open_as)
|
|
val openAsText = bottomSheetActivity?.openAsText
|
|
if (openAsText == null) {
|
|
openAsItem.isVisible = false
|
|
} else {
|
|
openAsItem.title = openAsText
|
|
}
|
|
|
|
val mutable =
|
|
statusIsByCurrentUser || accountIsInMentions(viewModel.activeAccount, status.mentions)
|
|
val muteConversationItem = popup.menu.findItem(R.id.status_mute_conversation).apply {
|
|
isVisible = mutable
|
|
}
|
|
if (mutable) {
|
|
muteConversationItem.setTitle(
|
|
if (status.muted) {
|
|
R.string.action_unmute_conversation
|
|
} else {
|
|
R.string.action_mute_conversation
|
|
}
|
|
)
|
|
}
|
|
|
|
// translation not there for your own posts
|
|
popup.menu.findItem(R.id.status_translate)?.let { translateItem ->
|
|
translateItem.isVisible =
|
|
!status.language.equals(Locale.getDefault().language, ignoreCase = true) &&
|
|
viewModel.supportsTranslation()
|
|
translateItem.setTitle(if (statusViewData.translation != null) R.string.action_show_original else R.string.action_translate)
|
|
}
|
|
|
|
popup.setOnMenuItemClickListener { item ->
|
|
when (item.itemId) {
|
|
R.id.post_share_content -> {
|
|
val statusToShare: Status = status.actionableStatus
|
|
|
|
val sendIntent = Intent()
|
|
sendIntent.action = Intent.ACTION_SEND
|
|
|
|
val stringToShare = statusToShare.account.username +
|
|
" - " +
|
|
statusToShare.content
|
|
sendIntent.putExtra(Intent.EXTRA_TEXT, stringToShare)
|
|
sendIntent.type = "text/plain"
|
|
startActivity(
|
|
Intent.createChooser(
|
|
sendIntent,
|
|
resources.getText(R.string.send_post_content_to)
|
|
)
|
|
)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.post_share_link -> {
|
|
val sendIntent = Intent()
|
|
sendIntent.action = Intent.ACTION_SEND
|
|
sendIntent.putExtra(Intent.EXTRA_TEXT, statusUrl)
|
|
sendIntent.type = "text/plain"
|
|
startActivity(
|
|
Intent.createChooser(
|
|
sendIntent,
|
|
resources.getText(R.string.send_post_link_to)
|
|
)
|
|
)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_copy_link -> {
|
|
val clipboard = requireActivity().getSystemService(
|
|
Context.CLIPBOARD_SERVICE
|
|
) as ClipboardManager
|
|
clipboard.setPrimaryClip(ClipData.newPlainText(null, statusUrl))
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_open_as -> {
|
|
showOpenAsDialog(statusUrl!!, item.title)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_download_media -> {
|
|
requestDownloadAllMedia(status)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_mute_conversation -> {
|
|
searchAdapter.peek(position)?.let { foundStatus ->
|
|
viewModel.muteConversation(foundStatus, !status.muted)
|
|
}
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_mute -> {
|
|
onMute(accountId, accountUsername)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_block -> {
|
|
onBlock(accountId, accountUsername)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_report -> {
|
|
openReportPage(accountId, accountUsername, id)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_unreblog_private -> {
|
|
onReblog(false, position)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_reblog_private -> {
|
|
onReblog(true, position)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_delete -> {
|
|
showConfirmDeleteDialog(id, position)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_delete_and_redraft -> {
|
|
showConfirmEditDialog(id, position, status)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_edit -> {
|
|
editStatus(id, position, status)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.pin -> {
|
|
viewModel.pinAccount(status, !status.pinned)
|
|
return@setOnMenuItemClickListener true
|
|
}
|
|
|
|
R.id.status_translate -> {
|
|
if (statusViewData.translation != null) {
|
|
viewModel.untranslate(statusViewData)
|
|
} else {
|
|
lifecycleScope.launch {
|
|
viewModel.translate(statusViewData)
|
|
.onFailure {
|
|
Snackbar.make(
|
|
requireView(),
|
|
getString(R.string.ui_error_translate, it.message),
|
|
Snackbar.LENGTH_LONG
|
|
).show()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
false
|
|
}
|
|
popup.show()
|
|
}
|
|
|
|
private fun onBlock(accountId: String, accountUsername: String) {
|
|
AlertDialog.Builder(requireContext())
|
|
.setMessage(getString(R.string.dialog_block_warning, accountUsername))
|
|
.setPositiveButton(android.R.string.ok) { _, _ -> viewModel.blockAccount(accountId) }
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
.show()
|
|
}
|
|
|
|
private fun onMute(accountId: String, accountUsername: String) {
|
|
showMuteAccountDialog(
|
|
this.requireActivity(),
|
|
accountUsername
|
|
) { notifications, duration ->
|
|
viewModel.muteAccount(accountId, notifications, duration)
|
|
}
|
|
}
|
|
|
|
private fun accountIsInMentions(account: AccountEntity?, mentions: List<Mention>): Boolean {
|
|
return mentions.firstOrNull {
|
|
account?.username == it.username && account.domain == Uri.parse(it.url)?.host
|
|
} != null
|
|
}
|
|
|
|
private fun showOpenAsDialog(statusUrl: String, dialogTitle: CharSequence?) {
|
|
bottomSheetActivity?.showAccountChooserDialog(
|
|
dialogTitle,
|
|
false,
|
|
object : AccountSelectionListener {
|
|
override fun onAccountSelected(account: AccountEntity) {
|
|
bottomSheetActivity?.openAsAccount(statusUrl, account)
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
private fun downloadAllMedia(mediaUrls: List<String>) {
|
|
Toast.makeText(context, R.string.downloading_media, Toast.LENGTH_SHORT).show()
|
|
val downloadManager: DownloadManager = requireContext().getSystemService()!!
|
|
|
|
for (url in mediaUrls) {
|
|
val uri = Uri.parse(url)
|
|
val request = DownloadManager.Request(uri)
|
|
request.setDestinationInExternalPublicDir(
|
|
Environment.DIRECTORY_DOWNLOADS,
|
|
uri.lastPathSegment
|
|
)
|
|
downloadManager.enqueue(request)
|
|
}
|
|
}
|
|
|
|
private fun requestDownloadAllMedia(status: Status) {
|
|
if (status.attachments.isEmpty()) {
|
|
return
|
|
}
|
|
val mediaUrls = status.attachments.map { it.url }
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
|
pendingMediaDownloads = mediaUrls
|
|
downloadAllMediaPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
} else {
|
|
downloadAllMedia(mediaUrls)
|
|
}
|
|
}
|
|
|
|
private fun openReportPage(accountId: String, accountUsername: String, statusId: String) {
|
|
startActivity(
|
|
ReportActivity.getIntent(requireContext(), accountId, accountUsername, statusId)
|
|
)
|
|
}
|
|
|
|
private fun showConfirmDeleteDialog(id: String, position: Int) {
|
|
context?.let {
|
|
AlertDialog.Builder(it)
|
|
.setMessage(R.string.dialog_delete_post_warning)
|
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
|
viewModel.deleteStatusAsync(id)
|
|
removeItem(position)
|
|
}
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
.show()
|
|
}
|
|
}
|
|
|
|
private fun showConfirmEditDialog(id: String, position: Int, status: Status) {
|
|
activity?.let {
|
|
AlertDialog.Builder(it)
|
|
.setMessage(R.string.dialog_redraft_post_warning)
|
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
|
lifecycleScope.launch {
|
|
viewModel.deleteStatusAsync(id).await().fold(
|
|
{ deletedStatus ->
|
|
removeItem(position)
|
|
|
|
val redraftStatus = if (deletedStatus.isEmpty) {
|
|
status.toDeletedStatus()
|
|
} else {
|
|
deletedStatus
|
|
}
|
|
|
|
val intent = ComposeActivity.startIntent(
|
|
requireContext(),
|
|
ComposeOptions(
|
|
content = redraftStatus.text.orEmpty(),
|
|
inReplyToId = redraftStatus.inReplyToId,
|
|
visibility = redraftStatus.visibility,
|
|
contentWarning = redraftStatus.spoilerText,
|
|
mediaAttachments = redraftStatus.attachments,
|
|
sensitive = redraftStatus.sensitive,
|
|
poll = redraftStatus.poll?.toNewPoll(status.createdAt),
|
|
language = redraftStatus.language,
|
|
kind = ComposeActivity.ComposeKind.NEW
|
|
)
|
|
)
|
|
startActivity(intent)
|
|
},
|
|
{ error ->
|
|
Log.w("SearchStatusesFragment", "error deleting status", error)
|
|
Toast.makeText(
|
|
context,
|
|
R.string.error_generic,
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
}
|
|
)
|
|
}
|
|
}
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
.show()
|
|
}
|
|
}
|
|
|
|
private fun editStatus(id: String, position: Int, status: Status) {
|
|
lifecycleScope.launch {
|
|
mastodonApi.statusSource(id).fold(
|
|
{ source ->
|
|
val composeOptions = ComposeOptions(
|
|
content = source.text,
|
|
inReplyToId = status.inReplyToId,
|
|
visibility = status.visibility,
|
|
contentWarning = source.spoilerText,
|
|
mediaAttachments = status.attachments,
|
|
sensitive = status.sensitive,
|
|
language = status.language,
|
|
statusId = source.id,
|
|
poll = status.poll?.toNewPoll(status.createdAt),
|
|
kind = ComposeActivity.ComposeKind.EDIT_POSTED
|
|
)
|
|
startActivity(ComposeActivity.startIntent(requireContext(), composeOptions))
|
|
},
|
|
{
|
|
Snackbar.make(
|
|
requireView(),
|
|
getString(R.string.error_status_source_load),
|
|
Snackbar.LENGTH_SHORT
|
|
).show()
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
private const val PENDING_MEDIA_DOWNLOADS_STATE_KEY = "pending_media_downloads"
|
|
|
|
fun newInstance() = SearchStatusesFragment()
|
|
}
|
|
}
|