8770fbe986
* Convert ComposeActivity to Kotlin * More ComposeActivity cleanups * Move ComposeActivity to it's own package * Remove ComposeActivity.IntentBuilder * Re-do part of the media downsizing/uploading * Add sending of status to ViewModel, draft media descriptions * Allow uploading video, update description after uploading * Enable camera, enable upload cancelling * Cleanup of ComposeActivity * Extract CaptionDialog, extract ComposeActivity methods * Fix handling of redrafted media * Add initial state and media uploading out of Activity * Change ComposeOptions.mentionedUsernames to be Set rather than List We probably don't want repeated usernames when we are writing a post and Set provides such guarantee for free plus it tells it to the callers. The only disadvantage is lack of order but it shouldn't be a problem. * Add combineOptionalLiveData. Add docs. It it useful for nullable LiveData's. I think we cannot differentiate between value not being set and value being null so I just added the variant without null check. * Add poll support to Compose. * cleanup code * move more classes into compose package * cleanup code * fix button behavior * add error handling for media upload * add caching for instance data again * merge develop * fix scheduled toots * delete unused string * cleanup ComposeActivity * fix restoring media from drafts * make media upload code a little bit clearer * cleanup autocomplete search code * avoid duplicate object creation in SavedTootActivity * perf: avoid unnecessary work when initializing ComposeActivity * add license header to new files * use small toot button on bigger displays * fix ComposeActivityTest * fix bad merge * use Singles.zip instead of Single.zip
158 lines
7 KiB
Kotlin
158 lines
7 KiB
Kotlin
/* Copyright 2018 Jeremiasz Nelz <remi6397(a)gmail.com>
|
|
*
|
|
* 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.receiver
|
|
|
|
import android.content.BroadcastReceiver
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.util.Log
|
|
import androidx.core.app.NotificationCompat
|
|
import androidx.core.app.NotificationManagerCompat
|
|
import androidx.core.app.RemoteInput
|
|
import androidx.core.content.ContextCompat
|
|
import com.keylesspalace.tusky.R
|
|
import com.keylesspalace.tusky.components.compose.ComposeActivity
|
|
import com.keylesspalace.tusky.components.compose.ComposeActivity.ComposeOptions
|
|
import com.keylesspalace.tusky.db.AccountManager
|
|
import com.keylesspalace.tusky.entity.Status
|
|
import com.keylesspalace.tusky.service.SendTootService
|
|
import com.keylesspalace.tusky.service.TootToSend
|
|
import com.keylesspalace.tusky.util.NotificationHelper
|
|
import com.keylesspalace.tusky.util.randomAlphanumericString
|
|
import dagger.android.AndroidInjection
|
|
import javax.inject.Inject
|
|
|
|
private const val TAG = "SendStatusBR"
|
|
|
|
class SendStatusBroadcastReceiver : BroadcastReceiver() {
|
|
|
|
@Inject
|
|
lateinit var accountManager: AccountManager
|
|
|
|
override fun onReceive(context: Context, intent: Intent) {
|
|
AndroidInjection.inject(this, context)
|
|
|
|
val notificationId = intent.getIntExtra(NotificationHelper.KEY_NOTIFICATION_ID, -1)
|
|
val senderId = intent.getLongExtra(NotificationHelper.KEY_SENDER_ACCOUNT_ID, -1)
|
|
val senderIdentifier = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_IDENTIFIER)
|
|
val senderFullName = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_FULL_NAME)
|
|
val citedStatusId = intent.getStringExtra(NotificationHelper.KEY_CITED_STATUS_ID)
|
|
val visibility = intent.getSerializableExtra(NotificationHelper.KEY_VISIBILITY) as Status.Visibility
|
|
val spoiler = intent.getStringExtra(NotificationHelper.KEY_SPOILER)
|
|
val mentions = intent.getStringArrayExtra(NotificationHelper.KEY_MENTIONS)
|
|
val citedText = intent.getStringExtra(NotificationHelper.KEY_CITED_TEXT)
|
|
val localAuthorId = intent.getStringExtra(NotificationHelper.KEY_CITED_AUTHOR_LOCAL)
|
|
|
|
val account = accountManager.getAccountById(senderId)
|
|
|
|
val notificationManager = NotificationManagerCompat.from(context)
|
|
|
|
|
|
if (intent.action == NotificationHelper.REPLY_ACTION) {
|
|
|
|
val message = getReplyMessage(intent)
|
|
|
|
if (account == null) {
|
|
Log.w(TAG, "Account \"$senderId\" not found in database. Aborting quick reply!")
|
|
|
|
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier)
|
|
.setSmallIcon(R.drawable.ic_notify)
|
|
.setColor(ContextCompat.getColor(context, (R.color.tusky_blue)))
|
|
.setGroup(senderFullName)
|
|
.setDefaults(0) // So it doesn't ring twice, notify only in Target callback
|
|
|
|
builder.setContentTitle(context.getString(R.string.error_generic))
|
|
builder.setContentText(context.getString(R.string.error_sender_account_gone))
|
|
|
|
builder.setSubText(senderFullName)
|
|
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
|
builder.setOnlyAlertOnce(true)
|
|
|
|
notificationManager.notify(notificationId, builder.build())
|
|
} else {
|
|
val text = mentions.joinToString(" ", postfix = " ") { "@$it" } + message.toString()
|
|
|
|
val sendIntent = SendTootService.sendTootIntent(
|
|
context,
|
|
TootToSend(
|
|
text,
|
|
spoiler,
|
|
visibility.serverString(),
|
|
false,
|
|
emptyList(),
|
|
emptyList(),
|
|
emptyList(),
|
|
null,
|
|
citedStatusId,
|
|
null,
|
|
null,
|
|
null,
|
|
null, account.id,
|
|
0,
|
|
randomAlphanumericString(16),
|
|
0
|
|
)
|
|
)
|
|
|
|
context.startService(sendIntent)
|
|
|
|
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier)
|
|
.setSmallIcon(R.drawable.ic_notify)
|
|
.setColor(ContextCompat.getColor(context, (R.color.tusky_blue)))
|
|
.setGroup(senderFullName)
|
|
.setDefaults(0) // So it doesn't ring twice, notify only in Target callback
|
|
|
|
builder.setContentTitle(context.getString(R.string.status_sent))
|
|
builder.setContentText(context.getString(R.string.status_sent_long))
|
|
|
|
builder.setSubText(senderFullName)
|
|
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
|
builder.setOnlyAlertOnce(true)
|
|
|
|
notificationManager.notify(notificationId, builder.build())
|
|
}
|
|
} else if (intent.action == NotificationHelper.COMPOSE_ACTION) {
|
|
|
|
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
|
|
|
notificationManager.cancel(notificationId)
|
|
|
|
accountManager.setActiveAccount(senderId)
|
|
|
|
val composeIntent = ComposeActivity.startIntent(context, ComposeOptions(
|
|
inReplyToId = citedStatusId,
|
|
replyVisibility = visibility,
|
|
contentWarning = spoiler,
|
|
mentionedUsernames = mentions.toSet(),
|
|
replyingStatusAuthor = localAuthorId,
|
|
replyingStatusContent = citedText
|
|
))
|
|
|
|
composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
|
|
context.startActivity(composeIntent)
|
|
}
|
|
}
|
|
|
|
private fun getReplyMessage(intent: Intent): CharSequence {
|
|
val remoteInput = RemoteInput.getResultsFromIntent(intent)
|
|
|
|
return remoteInput.getCharSequence(NotificationHelper.KEY_REPLY, "")
|
|
}
|
|
|
|
} |