chinwag-android/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt
Ivan Kupalov 8770fbe986 ComposeActivity refactor (#1541)
* 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
2019-12-19 19:09:40 +01:00

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, "")
}
}