added send dm media, close #831
This commit is contained in:
parent
c62231da97
commit
cc91209578
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.mariotaku.microblog.library.twitter;
|
||||
|
||||
import org.mariotaku.microblog.library.twitter.api.DirectMessagesEventResources;
|
||||
import org.mariotaku.microblog.library.twitter.api.DirectMessagesResources;
|
||||
import org.mariotaku.microblog.library.twitter.api.FavoritesResources;
|
||||
import org.mariotaku.microblog.library.twitter.api.FriendsFollowersResources;
|
||||
|
@ -37,7 +38,8 @@ import org.mariotaku.microblog.library.twitter.api.UsersResources;
|
|||
* Created by mariotaku on 16/5/13.
|
||||
*/
|
||||
public interface Twitter extends SearchResources, TimelineResources, TweetResources, UsersResources,
|
||||
ListResources, DirectMessagesResources, FriendsFollowersResources, FavoritesResources,
|
||||
SpamReportingResources, SavedSearchesResources, TrendsResources, PlacesGeoResources,
|
||||
ListResources, DirectMessagesResources, DirectMessagesEventResources,
|
||||
FriendsFollowersResources, FavoritesResources, SpamReportingResources,
|
||||
SavedSearchesResources, TrendsResources, PlacesGeoResources,
|
||||
HelpResources, MutesResources, TwitterPrivate {
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ public interface TwitterUpload {
|
|||
@Params(@KeyValue(key = "command", value = "INIT"))
|
||||
MediaUploadResponse initUploadMedia(@Param("media_type") String mediaType,
|
||||
@Param("total_bytes") long totalBytes,
|
||||
@Param("media_category") String mediaCategory,
|
||||
@Param(value = "additional_owners", arrayDelimiter = ',')
|
||||
String[] additionalOwners) throws MicroBlogException;
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.microblog.library.twitter.api;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.twitter.model.DirectMessageEventObject;
|
||||
import org.mariotaku.microblog.library.twitter.template.DirectMessageAnnotationTemplate;
|
||||
import org.mariotaku.restfu.annotation.method.POST;
|
||||
import org.mariotaku.restfu.annotation.param.Params;
|
||||
import org.mariotaku.restfu.annotation.param.Raw;
|
||||
import org.mariotaku.restfu.http.BodyType;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/5/11.
|
||||
*/
|
||||
@Params(template = DirectMessageAnnotationTemplate.class)
|
||||
public interface DirectMessagesEventResources {
|
||||
|
||||
@POST("/direct_messages/events/new.json")
|
||||
@BodyType(BodyType.RAW)
|
||||
DirectMessageEventObject newDirectMessageEvent(@Raw(contentType = "application/json", encoding = "UTF-8")
|
||||
DirectMessageEventObject event) throws MicroBlogException;
|
||||
|
||||
}
|
|
@ -22,19 +22,16 @@ import org.mariotaku.microblog.library.MicroBlogException;
|
|||
import org.mariotaku.microblog.library.twitter.model.DirectMessage;
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging;
|
||||
import org.mariotaku.microblog.library.twitter.model.ResponseList;
|
||||
import org.mariotaku.microblog.library.twitter.template.DirectMessageAnnotationTemplate;
|
||||
import org.mariotaku.restfu.annotation.method.GET;
|
||||
import org.mariotaku.restfu.annotation.method.POST;
|
||||
import org.mariotaku.restfu.annotation.param.KeyValue;
|
||||
import org.mariotaku.restfu.annotation.param.Param;
|
||||
import org.mariotaku.restfu.annotation.param.Params;
|
||||
import org.mariotaku.restfu.annotation.param.Query;
|
||||
import org.mariotaku.restfu.http.BodyType;
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
@Params({@KeyValue(key = "full_text", valueKey = "full_text"),
|
||||
@KeyValue(key = "include_entities", valueKey = "include_entities"),
|
||||
@KeyValue(key = "include_cards", valueKey = "include_cards"),
|
||||
@KeyValue(key = "cards_platform", valueKey = "cards_platform")})
|
||||
@Params(template = DirectMessageAnnotationTemplate.class)
|
||||
public interface DirectMessagesResources {
|
||||
|
||||
@POST("/direct_messages/destroy.json")
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.microblog.library.twitter.model;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/5/11.
|
||||
*/
|
||||
@JsonObject
|
||||
public class DirectMessageEventObject {
|
||||
@JsonField(name = "event")
|
||||
Event event;
|
||||
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
public void setEvent(Event event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@JsonObject
|
||||
public static class Event {
|
||||
@JsonField(name = "id")
|
||||
String id;
|
||||
|
||||
@JsonField(name = "type")
|
||||
String type;
|
||||
|
||||
@JsonField(name = "message_create")
|
||||
MessageCreate messageCreate;
|
||||
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public MessageCreate getMessageCreate() {
|
||||
return messageCreate;
|
||||
}
|
||||
|
||||
public void setMessageCreate(MessageCreate messageCreate) {
|
||||
this.messageCreate = messageCreate;
|
||||
}
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@JsonObject
|
||||
public static class MessageCreate {
|
||||
|
||||
@JsonField(name = "target")
|
||||
Target target;
|
||||
@JsonField(name = "message_data")
|
||||
MessageData messageData;
|
||||
|
||||
public Target getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(Target target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public MessageData getMessageData() {
|
||||
return messageData;
|
||||
}
|
||||
|
||||
public void setMessageData(MessageData messageData) {
|
||||
this.messageData = messageData;
|
||||
}
|
||||
|
||||
@JsonObject
|
||||
public static class Target {
|
||||
@JsonField(name = "recipient_id")
|
||||
String recipientId;
|
||||
|
||||
public String getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public void setRecipientId(String recipientId) {
|
||||
this.recipientId = recipientId;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonObject
|
||||
public static class MessageData {
|
||||
@JsonField(name = "text")
|
||||
String text;
|
||||
@JsonField(name = "attachment")
|
||||
Attachment attachment;
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public Attachment getAttachment() {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public void setAttachment(Attachment attachment) {
|
||||
this.attachment = attachment;
|
||||
}
|
||||
|
||||
@JsonObject
|
||||
public static class Attachment {
|
||||
@JsonField(name = "type")
|
||||
String type;
|
||||
|
||||
@JsonField(name = "media")
|
||||
Media media;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Media getMedia() {
|
||||
return media;
|
||||
}
|
||||
|
||||
public void setMedia(Media media) {
|
||||
this.media = media;
|
||||
}
|
||||
|
||||
@JsonObject
|
||||
public static class Media {
|
||||
@JsonField(name = "id")
|
||||
String id;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.microblog.library.twitter.template;
|
||||
|
||||
import org.mariotaku.restfu.annotation.param.KeyValue;
|
||||
import org.mariotaku.restfu.annotation.param.Params;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/5/11.
|
||||
*/
|
||||
|
||||
@Params({@KeyValue(key = "full_text", valueKey = "full_text"),
|
||||
@KeyValue(key = "include_entities", valueKey = "include_entities"),
|
||||
@KeyValue(key = "include_cards", valueKey = "include_cards"),
|
||||
@KeyValue(key = "cards_platform", valueKey = "cards_platform")})
|
||||
public class DirectMessageAnnotationTemplate {
|
||||
}
|
|
@ -28,6 +28,10 @@ operator fun Bundle.set(key: String, value: String?) {
|
|||
return putString(key, value)
|
||||
}
|
||||
|
||||
operator fun Bundle.set(key: String, value: IntArray?) {
|
||||
return putIntArray(key, value)
|
||||
}
|
||||
|
||||
operator fun Bundle.set(key: String, value: Parcelable?) {
|
||||
return putParcelable(key, value)
|
||||
}
|
||||
|
|
|
@ -395,7 +395,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
REQUEST_TAKE_PHOTO, REQUEST_PICK_MEDIA -> {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val src = MediaPickerActivity.getMediaUris(data)
|
||||
TaskStarter.execute(AddMediaTask(this, src, false, false))
|
||||
TaskStarter.execute(AddMediaTask(this, src, null, false, false))
|
||||
val extras = data.getBundleExtra(MediaPickerActivity.EXTRA_EXTRAS)
|
||||
if (extras?.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE) ?: false) {
|
||||
possiblySensitive = true
|
||||
|
@ -432,7 +432,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
val src = MediaPickerActivity.getMediaUris(data)?.takeIf(Array<Uri>::isNotEmpty) ?:
|
||||
data.getParcelableExtra<Uri>(EXTRA_IMAGE_URI)?.let { arrayOf(it) }
|
||||
if (src != null) {
|
||||
TaskStarter.execute(AddMediaTask(this, src, false, false))
|
||||
TaskStarter.execute(AddMediaTask(this, src, null, false, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1097,7 +1097,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
val stream = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (stream != null) {
|
||||
val src = arrayOf(stream)
|
||||
TaskStarter.execute(AddMediaTask(this, src, true, false))
|
||||
TaskStarter.execute(AddMediaTask(this, src, null, true, false))
|
||||
}
|
||||
} else if (Intent.ACTION_SEND_MULTIPLE == action) {
|
||||
shouldSaveAccounts = false
|
||||
|
@ -1105,7 +1105,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
val extraStream = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (extraStream != null) {
|
||||
val src = extraStream.toTypedArray()
|
||||
TaskStarter.execute(AddMediaTask(this, src, true, false))
|
||||
TaskStarter.execute(AddMediaTask(this, src, null, true, false))
|
||||
}
|
||||
} else {
|
||||
shouldSaveAccounts = !hasAccountKeys
|
||||
|
@ -1113,7 +1113,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
val data = intent.data
|
||||
if (data != null) {
|
||||
val src = arrayOf(data)
|
||||
TaskStarter.execute(AddMediaTask(this, src, true, false))
|
||||
TaskStarter.execute(AddMediaTask(this, src, null, true, false))
|
||||
}
|
||||
}
|
||||
val extraSubject = intent.getCharSequenceExtra(Intent.EXTRA_SUBJECT)
|
||||
|
@ -1788,7 +1788,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
})
|
||||
editText.customSelectionActionModeCallback = this
|
||||
editText.imageInputListener = { contentInfo ->
|
||||
val task = AddMediaTask(this, arrayOf(contentInfo.contentUri), true, false)
|
||||
val task = AddMediaTask(this, arrayOf(contentInfo.contentUri), null, true, false)
|
||||
TaskStarter.execute(task)
|
||||
task.callback = {
|
||||
contentInfo.releasePermission()
|
||||
|
@ -2032,9 +2032,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
|||
}
|
||||
}
|
||||
|
||||
private class AddMediaTask(activity: ComposeActivity, sources: Array<Uri>, copySrc: Boolean,
|
||||
deleteSrc: Boolean) : AbsAddMediaTask<((List<ParcelableMediaUpdate>?) -> Unit)?>(
|
||||
activity, sources, copySrc, deleteSrc) {
|
||||
private class AddMediaTask(activity: ComposeActivity, sources: Array<Uri>, types: IntArray?,
|
||||
copySrc: Boolean, deleteSrc: Boolean) : AbsAddMediaTask<((List<ParcelableMediaUpdate>?) -> Unit)?>(
|
||||
activity, sources, types, copySrc, deleteSrc) {
|
||||
|
||||
override fun afterExecute(callback: ((List<ParcelableMediaUpdate>?) -> Unit)?,
|
||||
result: List<ParcelableMediaUpdate>?) {
|
||||
|
|
|
@ -13,6 +13,9 @@ import org.mariotaku.twidere.util.BitmapFactoryUtils
|
|||
fun ParcelableMediaUpdate.getMimeType(resolver: ContentResolver): String? {
|
||||
val uri = Uri.parse(this.uri)
|
||||
return resolver.getType(uri) ?: when (type) {
|
||||
ParcelableMedia.Type.ANIMATED_GIF -> {
|
||||
return "image/gif"
|
||||
}
|
||||
ParcelableMedia.Type.IMAGE -> {
|
||||
val o = BitmapFactory.Options()
|
||||
o.inJustDecodeBounds = true
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.extension.model.api
|
||||
|
||||
import org.mariotaku.microblog.library.twitter.model.DirectMessageEventObject
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/5/11.
|
||||
*/
|
||||
fun DirectMessageEventObject(action: DirectMessageEventObject.Event.() -> Unit): DirectMessageEventObject {
|
||||
val obj = DirectMessageEventObject()
|
||||
val event = DirectMessageEventObject.Event()
|
||||
action(event)
|
||||
obj.event = event
|
||||
return obj
|
||||
}
|
||||
|
||||
fun DirectMessageEventObject.Event.messageCreate(action: DirectMessageEventObject.Event.MessageCreate.() -> Unit) {
|
||||
val messageCreate = DirectMessageEventObject.Event.MessageCreate()
|
||||
action(messageCreate)
|
||||
this.messageCreate = messageCreate
|
||||
}
|
||||
|
||||
fun DirectMessageEventObject.Event.MessageCreate.target(action: DirectMessageEventObject.Event.MessageCreate.Target.() -> Unit) {
|
||||
val target = DirectMessageEventObject.Event.MessageCreate.Target()
|
||||
action(target)
|
||||
this.target = target
|
||||
}
|
||||
|
||||
fun DirectMessageEventObject.Event.MessageCreate.messageData(action: DirectMessageEventObject.Event.MessageCreate.MessageData.() -> Unit) {
|
||||
val messageData = DirectMessageEventObject.Event.MessageCreate.MessageData()
|
||||
action(messageData)
|
||||
this.messageData = messageData
|
||||
}
|
||||
|
||||
fun DirectMessageEventObject.Event.MessageCreate.MessageData.attachment(action: DirectMessageEventObject.Event.MessageCreate.MessageData.Attachment.() -> Unit) {
|
||||
val attachment = DirectMessageEventObject.Event.MessageCreate.MessageData.Attachment()
|
||||
action(attachment)
|
||||
this.attachment = attachment
|
||||
}
|
||||
|
||||
fun DirectMessageEventObject.Event.MessageCreate.MessageData.Attachment.media(action: DirectMessageEventObject.Event.MessageCreate.MessageData.Attachment.Media.() -> Unit) {
|
||||
val media = DirectMessageEventObject.Event.MessageCreate.MessageData.Attachment.Media()
|
||||
action(media)
|
||||
this.media = media
|
||||
}
|
|
@ -33,6 +33,7 @@ import org.mariotaku.twidere.fragment.iface.IBaseFragment
|
|||
import org.mariotaku.twidere.model.DefaultFeatures
|
||||
import org.mariotaku.twidere.util.*
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponent
|
||||
import org.mariotaku.twidere.util.gifshare.GifShareProvider
|
||||
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
|
||||
import org.mariotaku.twidere.util.schedule.StatusScheduleProvider
|
||||
import org.mariotaku.twidere.util.sync.SyncPreferences
|
||||
|
@ -73,6 +74,8 @@ open class BaseFragment : Fragment(), IBaseFragment<BaseFragment> {
|
|||
@Inject
|
||||
lateinit var timelineSyncManagerFactory: TimelineSyncManager.Factory
|
||||
@Inject
|
||||
lateinit var gifShareProviderFactory: GifShareProvider.Factory
|
||||
@Inject
|
||||
lateinit var restHttpClient: RestHttpClient
|
||||
@Inject
|
||||
lateinit var dns: Dns
|
||||
|
@ -85,6 +88,9 @@ open class BaseFragment : Fragment(), IBaseFragment<BaseFragment> {
|
|||
protected val timelineSyncManager: TimelineSyncManager?
|
||||
get() = timelineSyncManagerFactory.get()
|
||||
|
||||
protected val gifShareProvider: GifShareProvider?
|
||||
get() = gifShareProviderFactory.newInstance(context)
|
||||
|
||||
private val actionHelper = IBaseFragment.ActionHelper(this)
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
|
|
|
@ -405,7 +405,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
|
|||
this.delete_always = true
|
||||
})
|
||||
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
|
||||
upload, account, media, null, true, null)
|
||||
upload, account, media, null, null, true, null)
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
val avatarId = uploadResult.ids.first()
|
||||
val result = microBlog.updateDmConversationAvatar(conversationId, avatarId)
|
||||
|
|
|
@ -48,10 +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.mapToArray
|
||||
import org.mariotaku.ktextension.set
|
||||
import org.mariotaku.ktextension.*
|
||||
import org.mariotaku.pickncrop.library.MediaPickerActivity
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.sqliteqb.library.OrderBy
|
||||
|
@ -62,6 +59,7 @@ import org.mariotaku.twidere.activity.ThemedMediaPickerActivity
|
|||
import org.mariotaku.twidere.adapter.MediaPreviewAdapter
|
||||
import org.mariotaku.twidere.adapter.MessagesConversationAdapter
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.constant.IntentConstants.*
|
||||
import org.mariotaku.twidere.constant.nameFirstKey
|
||||
import org.mariotaku.twidere.constant.newDocumentApiKey
|
||||
|
@ -188,7 +186,7 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
|||
refreshEnabled = false
|
||||
adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.NONE
|
||||
|
||||
if (account.isOfficial(context)) {
|
||||
if (account.type == AccountType.TWITTER) {
|
||||
addMedia.visibility = View.VISIBLE
|
||||
} else {
|
||||
addMedia.visibility = View.GONE
|
||||
|
@ -225,16 +223,33 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
|||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
when (requestCode) {
|
||||
REQUEST_PICK_MEDIA -> {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val mediaUris = MediaPickerActivity.getMediaUris(data)
|
||||
TaskStarter.execute(AddMediaTask(this, mediaUris))
|
||||
when (resultCode) {
|
||||
Activity.RESULT_OK -> if (data != null) {
|
||||
val mediaUris = MediaPickerActivity.getMediaUris(data)
|
||||
val types = data.getBundleExtra(MediaPickerActivity.EXTRA_EXTRAS)?.getIntArray(EXTRA_TYPES)
|
||||
TaskStarter.execute(AddMediaTask(this, mediaUris, types))
|
||||
}
|
||||
RESULT_SEARCH_GIF -> {
|
||||
val provider = gifShareProvider ?: return
|
||||
startActivityForResult(provider.createGifSelectorIntent(), REQUEST_ADD_GIF)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
REQUEST_MANAGE_CONVERSATION_INFO -> {
|
||||
if (resultCode == MessageConversationInfoFragment.RESULT_CLOSE) {
|
||||
activity?.finish()
|
||||
}
|
||||
}
|
||||
REQUEST_ADD_GIF -> {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val intent = ThemedMediaPickerActivity.withThemed(context)
|
||||
.getMedia(data.data)
|
||||
.extras(Bundle { this[EXTRA_TYPES] = intArrayOf(ParcelableMedia.Type.ANIMATED_GIF) })
|
||||
.build()
|
||||
startActivityForResult(intent, REQUEST_PICK_MEDIA)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,7 +405,7 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
|||
editText.error = getString(R.string.hint_error_message_no_content)
|
||||
return
|
||||
}
|
||||
if (conversationAccount.isOfficial(context)) {
|
||||
if (conversationAccount.type == AccountType.TWITTER) {
|
||||
if (mediaPreviewAdapter.itemCount > defaultFeatures.twitterDirectMessageMediaLimit) {
|
||||
editText.error = getString(R.string.error_message_media_message_too_many)
|
||||
return
|
||||
|
@ -423,14 +438,17 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
|||
}
|
||||
|
||||
private fun openMediaPicker() {
|
||||
val intent = ThemedMediaPickerActivity.withThemed(context)
|
||||
.pickSources(arrayOf(MediaPickerActivity.SOURCE_CAMERA,
|
||||
val builder = ThemedMediaPickerActivity.withThemed(context)
|
||||
builder.pickSources(arrayOf(MediaPickerActivity.SOURCE_CAMERA,
|
||||
MediaPickerActivity.SOURCE_CAMCORDER,
|
||||
MediaPickerActivity.SOURCE_GALLERY,
|
||||
MediaPickerActivity.SOURCE_CLIPBOARD))
|
||||
.containsVideo(true)
|
||||
.allowMultiple(false)
|
||||
.build()
|
||||
if (gifShareProvider != null) {
|
||||
builder.addEntry(getString(R.string.action_add_gif), "gif", RESULT_SEARCH_GIF)
|
||||
}
|
||||
builder.containsVideo(true)
|
||||
builder.allowMultiple(false)
|
||||
val intent = builder.build()
|
||||
startActivityForResult(intent, REQUEST_PICK_MEDIA)
|
||||
}
|
||||
|
||||
|
@ -499,8 +517,9 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
|||
|
||||
internal class AddMediaTask(
|
||||
fragment: MessagesConversationFragment,
|
||||
sources: Array<Uri>
|
||||
) : AbsAddMediaTask<MessagesConversationFragment>(fragment.context, sources) {
|
||||
sources: Array<Uri>,
|
||||
types: IntArray?
|
||||
) : AbsAddMediaTask<MessagesConversationFragment>(fragment.context, sources, types) {
|
||||
|
||||
init {
|
||||
callback = fragment
|
||||
|
@ -572,6 +591,10 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
|
|||
|
||||
companion object {
|
||||
private const val REQUEST_MANAGE_CONVERSATION_INFO = 101
|
||||
private const val REQUEST_ADD_GIF = 102
|
||||
private const val RESULT_SEARCH_GIF = 11
|
||||
|
||||
private const val EXTRA_TYPES = "types"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") {
|
|||
val mediaType = body.contentType().contentType
|
||||
val length = body.length()
|
||||
val stream = body.stream()
|
||||
var response = upload.initUploadMedia(mediaType, length, null)
|
||||
var response = upload.initUploadMedia(mediaType, length, null, null)
|
||||
val segments = if (length == 0L) 0 else (length / BULK_SIZE + 1).toInt()
|
||||
for (segmentIndex in 0..segments - 1) {
|
||||
val currentBulkSize = Math.min(BULK_SIZE, length - segmentIndex * BULK_SIZE).toInt()
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.lang.ref.WeakReference
|
|||
open class AbsAddMediaTask<Callback>(
|
||||
context: Context,
|
||||
val sources: Array<Uri>,
|
||||
val types: IntArray?,
|
||||
val copySrc: Boolean = false,
|
||||
val deleteSrc: Boolean = false
|
||||
) : AbstractTask<Unit, List<ParcelableMediaUpdate>?, Callback>() {
|
||||
|
@ -50,8 +51,9 @@ open class AbsAddMediaTask<Callback>(
|
|||
var os: OutputStream? = null
|
||||
try {
|
||||
val sourceMimeType = resolver.getType(source)
|
||||
val mediaType = sourceMimeType?.let {
|
||||
val mediaType = types?.get(index) ?: sourceMimeType?.let {
|
||||
return@let when {
|
||||
it == "image/gif" -> ParcelableMedia.Type.ANIMATED_GIF
|
||||
it.startsWith("video/") -> ParcelableMedia.Type.VIDEO
|
||||
it.startsWith("image/") -> ParcelableMedia.Type.IMAGE
|
||||
else -> ParcelableMedia.Type.IMAGE
|
||||
|
|
|
@ -369,7 +369,7 @@ class UpdateStatusTask(
|
|||
mediaIds = pendingUpdate.sharedMediaIds
|
||||
} else {
|
||||
val (ids, deleteOnSuccess, deleteAlways) = uploadMicroBlogMediaShared(context,
|
||||
upload, account, update.media, ownerIds, true, stateCallback)
|
||||
upload, account, update.media, null, ownerIds, true, stateCallback)
|
||||
mediaIds = ids
|
||||
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
|
||||
deleteAlways.addAllTo(pendingUpdate.deleteAlways)
|
||||
|
@ -384,7 +384,7 @@ class UpdateStatusTask(
|
|||
// TODO use their native API
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val (ids, deleteOnSuccess, deleteAlways) = uploadMicroBlogMediaShared(context,
|
||||
upload, account, update.media, ownerIds, false, stateCallback)
|
||||
upload, account, update.media, null, ownerIds, false, stateCallback)
|
||||
mediaIds = ids
|
||||
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
|
||||
deleteAlways.addAllTo(pendingUpdate.deleteAlways)
|
||||
|
@ -697,13 +697,13 @@ class UpdateStatusTask(
|
|||
|
||||
companion object {
|
||||
|
||||
private val BULK_SIZE = 256 * 1024// 128 Kib
|
||||
private val BULK_SIZE = 512 * 1024// 512 Kib
|
||||
|
||||
@Throws(UploadException::class)
|
||||
fun uploadMicroBlogMediaShared(context: Context, upload: TwitterUpload,
|
||||
account: AccountDetails, media: Array<ParcelableMediaUpdate>,
|
||||
ownerIds: Array<String>?, chucked: Boolean, callback: UploadCallback?):
|
||||
SharedMediaUploadResult {
|
||||
mediaCategory: String? = null, ownerIds: Array<String>?, chucked: Boolean,
|
||||
callback: UploadCallback?): SharedMediaUploadResult {
|
||||
val deleteOnSuccess = ArrayList<MediaDeletionItem>()
|
||||
val deleteAlways = ArrayList<MediaDeletionItem>()
|
||||
val mediaIds = media.mapIndexedToArray { index, media ->
|
||||
|
@ -717,7 +717,7 @@ class UpdateStatusTask(
|
|||
callback?.onUploadingProgressChanged(index, position, length)
|
||||
})
|
||||
if (chucked) {
|
||||
resp = uploadMediaChucked(upload, body.body, ownerIds)
|
||||
resp = uploadMediaChucked(upload, body.body, mediaCategory, ownerIds)
|
||||
} else {
|
||||
resp = upload.uploadMedia(body.body, ownerIds)
|
||||
}
|
||||
|
@ -841,11 +841,11 @@ class UpdateStatusTask(
|
|||
|
||||
@Throws(IOException::class, MicroBlogException::class)
|
||||
private fun uploadMediaChucked(upload: TwitterUpload, body: Body,
|
||||
ownerIds: Array<String>?): MediaUploadResponse {
|
||||
mediaCategory: String? = null, ownerIds: Array<String>?): MediaUploadResponse {
|
||||
val mediaType = body.contentType().contentType
|
||||
val length = body.length()
|
||||
val stream = body.stream()
|
||||
var response = upload.initUploadMedia(mediaType, length, ownerIds)
|
||||
var response = upload.initUploadMedia(mediaType, length, mediaCategory, ownerIds)
|
||||
val segments = if (length == 0L) 0 else (length / BULK_SIZE + 1).toInt()
|
||||
for (segmentIndex in 0..segments - 1) {
|
||||
val currentBulkSize = Math.min(BULK_SIZE.toLong(), length - segmentIndex * BULK_SIZE).toInt()
|
||||
|
|
|
@ -29,10 +29,11 @@ import org.mariotaku.microblog.library.twitter.model.NewDm
|
|||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.*
|
||||
import org.mariotaku.twidere.extension.model.isOfficial
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.ParcelableMessageConversation
|
||||
import org.mariotaku.twidere.model.ParcelableNewMessage
|
||||
import org.mariotaku.twidere.model.event.SendMessageTaskEvent
|
||||
|
@ -86,6 +87,8 @@ class SendMessageTask(
|
|||
AccountType.TWITTER -> {
|
||||
if (account.isOfficial(context)) {
|
||||
return sendTwitterOfficialDM(microBlog, account, message)
|
||||
} else {
|
||||
return sendTwitterMessageEvent(microBlog, account, message)
|
||||
}
|
||||
}
|
||||
AccountType.FANFOU -> {
|
||||
|
@ -114,7 +117,7 @@ class SendMessageTask(
|
|||
if (message.media.isNotNullOrEmpty()) {
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
|
||||
upload, account, message.media, null, true, null)
|
||||
upload, account, message.media, null, null, true, null)
|
||||
newDm.setMediaId(uploadResult.ids[0])
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
deleteOnSuccess = uploadResult.deleteOnSuccess
|
||||
|
@ -136,6 +139,38 @@ class SendMessageTask(
|
|||
return GetMessagesTask.createDatabaseUpdateData(context, account, response, profileImageSize)
|
||||
}
|
||||
|
||||
private fun sendTwitterMessageEvent(microBlog: MicroBlog, account: AccountDetails,
|
||||
message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
val recipientId = message.recipient_ids.singleOrNull() ?: throw MicroBlogException("No recipient")
|
||||
val category = when (message.media?.firstOrNull()?.type) {
|
||||
ParcelableMedia.Type.IMAGE -> "dm_image"
|
||||
ParcelableMedia.Type.VIDEO -> "dm_video"
|
||||
ParcelableMedia.Type.ANIMATED_GIF -> "dm_gif"
|
||||
else -> null
|
||||
}
|
||||
val response = uploadMediaThen(account, message, category) { mediaId ->
|
||||
val obj = DirectMessageEventObject {
|
||||
type = "message_create"
|
||||
messageCreate {
|
||||
target { this.recipientId = recipientId }
|
||||
messageData {
|
||||
text = message.text
|
||||
if (mediaId != null) {
|
||||
attachment {
|
||||
type = "media"
|
||||
media {
|
||||
id = mediaId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return@uploadMediaThen microBlog.newDirectMessageEvent(obj)
|
||||
}
|
||||
return createDatabaseUpdateData(account, microBlog.showDirectMessage(response.event.id))
|
||||
}
|
||||
|
||||
private fun sendFanfouDM(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
val recipientId = message.recipient_ids.singleOrNull() ?: throw MicroBlogException("No recipient")
|
||||
val response = microBlog.sendFanfouDirectMessage(recipientId, message.text)
|
||||
|
@ -143,24 +178,34 @@ class SendMessageTask(
|
|||
}
|
||||
|
||||
private fun sendDefaultDM(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
var deleteOnSuccess: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
var deleteAlways: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
val recipientId = message.recipient_ids.singleOrNull() ?: throw MicroBlogException("No recipient")
|
||||
val response = try {
|
||||
var mediaId: String? = null
|
||||
if (message.media.isNotNullOrEmpty()) {
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
|
||||
upload, account, message.media, null, true, null)
|
||||
mediaId = uploadResult.ids[0]
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
deleteOnSuccess = uploadResult.deleteOnSuccess
|
||||
}
|
||||
val response = uploadMediaThen(account, message) { mediaId ->
|
||||
if (mediaId != null) {
|
||||
microBlog.sendDirectMessage(recipientId, message.text, mediaId)
|
||||
} else {
|
||||
microBlog.sendDirectMessage(recipientId, message.text)
|
||||
}
|
||||
}
|
||||
return createDatabaseUpdateData(account, response)
|
||||
}
|
||||
|
||||
private fun <T> uploadMediaThen(account: AccountDetails, message: ParcelableNewMessage,
|
||||
category: String? = null, action: (mediaId: String?) -> T): T {
|
||||
var deleteOnSuccess: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
var deleteAlways: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
try {
|
||||
var mediaId: String? = null
|
||||
if (message.media.isNotNullOrEmpty()) {
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
|
||||
upload, account, message.media, category, null, true, null)
|
||||
mediaId = uploadResult.ids[0]
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
deleteOnSuccess = uploadResult.deleteOnSuccess
|
||||
}
|
||||
val result = action(mediaId)
|
||||
deleteOnSuccess?.forEach { it.delete(context) }
|
||||
return result
|
||||
} catch (e: UpdateStatusTask.UploadException) {
|
||||
e.deleteAlways?.forEach {
|
||||
it.delete(context)
|
||||
|
@ -169,8 +214,6 @@ class SendMessageTask(
|
|||
} finally {
|
||||
deleteAlways?.forEach { it.delete(context) }
|
||||
}
|
||||
deleteOnSuccess?.forEach { it.delete(context) }
|
||||
return createDatabaseUpdateData(account, response)
|
||||
}
|
||||
|
||||
private fun createDatabaseUpdateData(details: AccountDetails, dm: DirectMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
|
|
Loading…
Reference in New Issue