mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-12 17:50:38 +01:00
mastodon media upload seems working
fixed npe
This commit is contained in:
parent
4e9a167a73
commit
f224c0f0be
@ -36,7 +36,7 @@ subprojects {
|
||||
Kotlin : '1.1.1',
|
||||
SupportLib : '25.3.1',
|
||||
MariotakuCommons : '0.9.13',
|
||||
RestFu : '0.9.50',
|
||||
RestFu : '0.9.51',
|
||||
ObjectCursor : '0.9.16',
|
||||
PlayServices : '10.2.1',
|
||||
MapsUtils : '0.4.4',
|
||||
|
@ -21,9 +21,21 @@
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.api;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.mastodon.model.Attachment;
|
||||
import org.mariotaku.restfu.annotation.method.POST;
|
||||
import org.mariotaku.restfu.annotation.param.Param;
|
||||
import org.mariotaku.restfu.http.BodyType;
|
||||
import org.mariotaku.restfu.http.mime.Body;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/17.
|
||||
*/
|
||||
|
||||
public interface MediaResources {
|
||||
|
||||
@POST("/v1/media")
|
||||
@BodyType(BodyType.MULTIPART)
|
||||
Attachment uploadMediaAttachment(@Param("file") Body body) throws MicroBlogException;
|
||||
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ public class StatusUpdate extends SimpleValueMap {
|
||||
|
||||
public StatusUpdate mediaIds(String[] ids) {
|
||||
if (ids != null) {
|
||||
put("in_reply_to_id[]", ids);
|
||||
put("media_ids[]", ids);
|
||||
} else {
|
||||
remove("in_rpely_to_id[]");
|
||||
remove("media_ids[]");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -26,6 +26,10 @@ inline fun <T, reified R> Array<T>.mapToArray(transform: (T) -> R): Array<R> {
|
||||
return Array(size) { transform(this[it]) }
|
||||
}
|
||||
|
||||
inline fun <T, reified R> Array<T>.mapIndexedToArray(transform: (Int, T) -> R): Array<R> {
|
||||
return Array(size) { transform(it, this[it]) }
|
||||
}
|
||||
|
||||
inline fun <reified R> LongArray.mapToArray(transform: (Long) -> R): Array<R> {
|
||||
return Array(size) { transform(this[it]) }
|
||||
}
|
@ -1415,7 +1415,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
val (replyStartIndex, replyText, _, excludedMentions, replyToOriginalUser) =
|
||||
replyTextAndMentions
|
||||
if (replyText.isEmpty() && media.isEmpty()) throw NoContentException()
|
||||
if (!statusShortenerUsed && validator.getTweetLength(replyText) > maxLength) {
|
||||
if (!statusShortenerUsed && maxLength > 0 && validator.getTweetLength(replyText) > maxLength) {
|
||||
throw StatusTooLongException(replyStartIndex + replyText.offsetByCodePoints(0, maxLength))
|
||||
}
|
||||
update.text = replyText
|
||||
@ -1428,7 +1428,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
} else {
|
||||
if (text.isEmpty() && media.isEmpty()) throw NoContentException()
|
||||
if (!statusShortenerUsed && validator.getTweetLength(text) > maxLength) {
|
||||
if (!statusShortenerUsed && maxLength > 0 && validator.getTweetLength(text) > maxLength) {
|
||||
throw StatusTooLongException(text.offsetByCodePoints(0, maxLength))
|
||||
}
|
||||
update.text = text
|
||||
|
@ -113,7 +113,7 @@ fun ParcelableMessageConversation.getSummaryText(context: Context, manager: User
|
||||
|
||||
|
||||
fun ParcelableMessageConversation.addParticipants(users: Collection<ParcelableUser>) {
|
||||
val participants = this.participants
|
||||
val participants: Array<ParcelableUser?>? = this.participants
|
||||
if (participants == null) {
|
||||
if (user != null) {
|
||||
this.participants = arrayOf(user)
|
||||
@ -123,7 +123,7 @@ fun ParcelableMessageConversation.addParticipants(users: Collection<ParcelableUs
|
||||
} else {
|
||||
val addingUsers = ArrayList<ParcelableUser>()
|
||||
users.forEach { user ->
|
||||
val index = participants.indexOfFirst { it.key == user.key }
|
||||
val index = participants.indexOfFirst { it?.key == user.key }
|
||||
if (index >= 0) {
|
||||
participants[index] = user
|
||||
} else {
|
||||
|
@ -404,7 +404,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
|
||||
this.uri = uri.toString()
|
||||
this.delete_always = true
|
||||
})
|
||||
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
|
||||
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
|
||||
upload, account, media, null, true, null)
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
val avatarId = uploadResult.ids.first()
|
||||
|
@ -23,12 +23,12 @@ import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.fanfou.model.PhotoStatusUpdate
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.mastodon.model.Attachment
|
||||
import org.mariotaku.microblog.library.twitter.TwitterUpload
|
||||
import org.mariotaku.microblog.library.twitter.model.ErrorInfo
|
||||
import org.mariotaku.microblog.library.twitter.model.MediaUploadResponse
|
||||
import org.mariotaku.microblog.library.twitter.model.NewMediaMetadata
|
||||
import org.mariotaku.microblog.library.twitter.model.StatusUpdate
|
||||
import org.mariotaku.microblog.library.mastodon.model.StatusUpdate as MastodonStatusUpdate
|
||||
import org.mariotaku.restfu.http.ContentType
|
||||
import org.mariotaku.restfu.http.mime.Body
|
||||
import org.mariotaku.restfu.http.mime.FileBody
|
||||
@ -62,6 +62,7 @@ import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import org.mariotaku.microblog.library.mastodon.model.StatusUpdate as MastodonStatusUpdate
|
||||
|
||||
/**
|
||||
* Update status
|
||||
@ -368,7 +369,7 @@ class UpdateStatusTask(
|
||||
if (pendingUpdate.sharedMediaIds != null) {
|
||||
mediaIds = pendingUpdate.sharedMediaIds
|
||||
} else {
|
||||
val (ids, deleteOnSuccess, deleteAlways) = uploadAllMediaShared(context,
|
||||
val (ids, deleteOnSuccess, deleteAlways) = uploadMicroBlogMediaShared(context,
|
||||
upload, account, update.media, ownerIds, true, stateCallback)
|
||||
mediaIds = ids
|
||||
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
|
||||
@ -383,12 +384,20 @@ class UpdateStatusTask(
|
||||
AccountType.STATUSNET -> {
|
||||
// TODO use their native API
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val (ids, deleteOnSuccess, deleteAlways) = uploadAllMediaShared(context,
|
||||
val (ids, deleteOnSuccess, deleteAlways) = uploadMicroBlogMediaShared(context,
|
||||
upload, account, update.media, ownerIds, false, stateCallback)
|
||||
mediaIds = ids
|
||||
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
|
||||
deleteAlways.addAllTo(pendingUpdate.deleteAlways)
|
||||
}
|
||||
AccountType.MASTODON -> {
|
||||
val mastodon = account.newMicroBlogInstance(context, cls = Mastodon::class.java)
|
||||
val (ids, deleteOnSuccess, deleteAlways) = uploadMastodonMedia(context,
|
||||
mastodon, account, update.media, false, stateCallback)
|
||||
mediaIds = ids
|
||||
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
|
||||
deleteAlways.addAllTo(pendingUpdate.deleteAlways)
|
||||
}
|
||||
else -> {
|
||||
mediaIds = null
|
||||
}
|
||||
@ -686,18 +695,13 @@ class UpdateStatusTask(
|
||||
private val BULK_SIZE = 256 * 1024// 128 Kib
|
||||
|
||||
@Throws(UploadException::class)
|
||||
fun uploadAllMediaShared(
|
||||
context: Context,
|
||||
upload: TwitterUpload,
|
||||
account: AccountDetails,
|
||||
media: Array<ParcelableMediaUpdate>,
|
||||
ownerIds: Array<String>?,
|
||||
chucked: Boolean,
|
||||
callback: UploadCallback?
|
||||
): SharedMediaUploadResult {
|
||||
fun uploadMicroBlogMediaShared(context: Context, upload: TwitterUpload,
|
||||
account: AccountDetails, media: Array<ParcelableMediaUpdate>,
|
||||
ownerIds: Array<String>?, chucked: Boolean, callback: UploadCallback?):
|
||||
SharedMediaUploadResult {
|
||||
val deleteOnSuccess = ArrayList<MediaDeletionItem>()
|
||||
val deleteAlways = ArrayList<MediaDeletionItem>()
|
||||
val mediaIds = media.mapIndexed { index, media ->
|
||||
val mediaIds = media.mapIndexedToArray { index, media ->
|
||||
val resp: MediaUploadResponse
|
||||
//noinspection TryWithIdenticalCatches
|
||||
var body: MediaStreamBody? = null
|
||||
@ -732,9 +736,44 @@ class UpdateStatusTask(
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
return@mapIndexed resp.id
|
||||
return@mapIndexedToArray resp.id
|
||||
}
|
||||
return SharedMediaUploadResult(mediaIds.toTypedArray(), deleteOnSuccess, deleteAlways)
|
||||
return SharedMediaUploadResult(mediaIds, deleteOnSuccess, deleteAlways)
|
||||
}
|
||||
|
||||
@Throws(UploadException::class)
|
||||
fun uploadMastodonMedia(context: Context, mastodon: Mastodon,
|
||||
account: AccountDetails, media: Array<ParcelableMediaUpdate>,
|
||||
chucked: Boolean, callback: UploadCallback?): SharedMediaUploadResult {
|
||||
val deleteOnSuccess = ArrayList<MediaDeletionItem>()
|
||||
val deleteAlways = ArrayList<MediaDeletionItem>()
|
||||
val mediaIds = media.mapIndexedToArray { index, media ->
|
||||
val resp: Attachment
|
||||
//noinspection TryWithIdenticalCatches
|
||||
var body: MediaStreamBody? = null
|
||||
try {
|
||||
val sizeLimit = account.mediaSizeLimit
|
||||
body = getBodyFromMedia(context, media, sizeLimit, chucked,
|
||||
ContentLengthInputStream.ReadListener { length, position ->
|
||||
callback?.onUploadingProgressChanged(index, position, length)
|
||||
})
|
||||
resp = mastodon.uploadMediaAttachment(body.body)
|
||||
} catch (e: IOException) {
|
||||
throw UploadException(e).apply {
|
||||
this.deleteAlways = deleteAlways
|
||||
}
|
||||
} catch (e: MicroBlogException) {
|
||||
throw UploadException(e).apply {
|
||||
this.deleteAlways = deleteAlways
|
||||
}
|
||||
} finally {
|
||||
body?.close()
|
||||
}
|
||||
body?.deleteOnSuccess?.addAllTo(deleteOnSuccess)
|
||||
body?.deleteAlways?.addAllTo(deleteAlways)
|
||||
return@mapIndexedToArray resp.id
|
||||
}
|
||||
return SharedMediaUploadResult(mediaIds, deleteOnSuccess, deleteAlways)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@ -772,7 +811,9 @@ class UpdateStatusTask(
|
||||
}
|
||||
cis.setReadListener(readListener)
|
||||
val mimeType = data?.type ?: mediaType ?: "application/octet-stream"
|
||||
val body = FileBody(cis, "attachment", cis.length(), ContentType.parse(mimeType))
|
||||
val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType) ?: ".bin"
|
||||
val fileName = mediaUri.lastPathSegment?.substringBeforeLast(".") ?: "attachment"
|
||||
val body = FileBody(cis, "$fileName.$extension", cis.length(), ContentType.parse(mimeType))
|
||||
val deleteOnSuccess: MutableList<MediaDeletionItem> = mutableListOf()
|
||||
val deleteAlways: MutableList<MediaDeletionItem> = mutableListOf()
|
||||
if (media.delete_always) {
|
||||
@ -854,11 +895,9 @@ class UpdateStatusTask(
|
||||
return null
|
||||
}
|
||||
|
||||
if (imageLimit != null) {
|
||||
if (imageLimit.checkGeomentry(o.outWidth, o.outHeight)) return null
|
||||
if (imageLimit == null || imageLimit.checkGeomentry(o.outWidth, o.outHeight)) return null
|
||||
o.inSampleSize = BitmapUtils.calculateInSampleSize(o.outWidth, o.outHeight,
|
||||
imageLimit.maxWidth, imageLimit.maxHeight)
|
||||
}
|
||||
o.inJustDecodeBounds = false
|
||||
// Do actual image decoding
|
||||
val bitmap = context.contentResolver.openInputStream(mediaUri).use {
|
||||
|
@ -113,7 +113,7 @@ class SendMessageTask(
|
||||
|
||||
if (message.media.isNotNullOrEmpty()) {
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
|
||||
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
|
||||
upload, account, message.media, null, true, null)
|
||||
newDm.setMediaId(uploadResult.ids[0])
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
@ -150,7 +150,7 @@ class SendMessageTask(
|
||||
var mediaId: String? = null
|
||||
if (message.media.isNotNullOrEmpty()) {
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
|
||||
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
|
||||
upload, account, message.media, null, true, null)
|
||||
mediaId = uploadResult.ids[0]
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
|
@ -174,9 +174,13 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
|
||||
|
||||
statusContentUpperSpace.visibility = View.GONE
|
||||
} else if (status.in_reply_to_status_id != null && status.in_reply_to_user_key != null && displayInReplyTo) {
|
||||
val inReplyTo = colorNameManager.getDisplayName(status.in_reply_to_user_key!!,
|
||||
status.in_reply_to_name, status.in_reply_to_screen_name, nameFirst)
|
||||
statusInfoLabel.text = context.getString(R.string.in_reply_to_name, formatter.unicodeWrap(inReplyTo))
|
||||
if (status.in_reply_to_name != null && status.in_reply_to_screen_name != null) {
|
||||
val inReplyTo = colorNameManager.getDisplayName(status.in_reply_to_user_key!!,
|
||||
status.in_reply_to_name, status.in_reply_to_screen_name, nameFirst)
|
||||
statusInfoLabel.text = context.getString(R.string.in_reply_to_name, formatter.unicodeWrap(inReplyTo))
|
||||
} else {
|
||||
statusInfoLabel.text = context.getString(R.string.label_status_type_reply)
|
||||
}
|
||||
statusInfoIcon.setImageResource(R.drawable.ic_activity_action_reply)
|
||||
statusInfoLabel.visibility = View.VISIBLE
|
||||
statusInfoIcon.visibility = View.VISIBLE
|
||||
|
@ -567,6 +567,7 @@
|
||||
<string name="label_sensitive_content">Sensitive content</string>
|
||||
<string name="label_status_hint">What\'s happening?</string>
|
||||
<string name="label_status_not_available">Tweet not available</string>
|
||||
<string name="label_status_type_reply">Reply</string>
|
||||
<string name="label_statuses">Tweets</string>
|
||||
<string name="label_statuses_replies">Tweets and replies</string>
|
||||
<string name="label_statuses_retweets">Tweets and retweets</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user