supports display new avatar after change

improved media picker theme
This commit is contained in:
Mariotaku Lee 2017-02-26 22:25:07 +08:00
parent db37f9711a
commit ce5492655e
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
6 changed files with 122 additions and 48 deletions

View File

@ -21,6 +21,8 @@
package org.mariotaku.microblog.library.twitter.api;
import android.support.annotation.Nullable;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.twitter.model.ConversationTimeline;
import org.mariotaku.microblog.library.twitter.model.DMResponse;
@ -60,10 +62,17 @@ public interface PrivateDirectMessagesResources extends PrivateResources {
ResponseCode updateDmConversationName(@Path("conversation_id") String conversationId,
@Param("name") String name) throws MicroBlogException;
/**
* Update DM conversation avatar
*
* @param conversationId DM conversation ID
* @param avatarId Avatar media ID, null for removing avatar
* @return HTTP response code
*/
@POST("/dm/conversation/{conversation_id}/update_avatar.json")
@BodyType(BodyType.FORM)
ResponseCode updateDmConversationAvatar(@Path("conversation_id") String conversationId,
@Param("avatar_id") String avatarId) throws MicroBlogException;
@Param(value = "avatar_id", ignoreOnNull = true) @Nullable String avatarId) throws MicroBlogException;
@POST("/dm/conversation/{conversation_id}/disable_notifications.json")
ResponseCode disableDmConversations(@Path("conversation_id") String conversationId)

View File

@ -1,17 +0,0 @@
package org.mariotaku.twidere.activity;
import android.content.Context;
import org.mariotaku.pickncrop.library.MediaPickerActivity;
import org.mariotaku.twidere.util.RestFuNetworkStreamDownloader;
public class ThemedMediaPickerActivity extends MediaPickerActivity {
public static IntentBuilder withThemed(Context context) {
final IntentBuilder builder = new IntentBuilder(context, ThemedMediaPickerActivity.class);
builder.cropImageActivityClass(ImageCropperActivity.class);
builder.streamDownloaderClass(RestFuNetworkStreamDownloader.class);
return builder;
}
}

View File

@ -19,12 +19,17 @@
package org.mariotaku.twidere.activity
import android.content.Context
import android.os.Bundle
import android.support.v7.widget.Toolbar
import com.soundcloud.android.crop.CropImageActivity
import org.mariotaku.kpreferences.get
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants
import org.mariotaku.twidere.activity.iface.IThemedActivity
import org.mariotaku.twidere.constant.themeKey
import org.mariotaku.twidere.util.ThemeUtils
import org.mariotaku.twidere.util.theme.getCurrentThemeResource
/**
* Created by mariotaku on 15/6/16.
@ -35,16 +40,20 @@ class ImageCropperActivity : CropImageActivity(), IThemedActivity {
override val currentThemeBackgroundAlpha by lazy { themeBackgroundAlpha }
override val currentThemeBackgroundOption by lazy { themeBackgroundOption }
private var mDoneCancelBar: Toolbar? = null
private var doneCancelBar: Toolbar? = null
override fun onCreate(savedInstanceState: Bundle?) {
val prefs = getSharedPreferences(TwidereConstants.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
val themeResource = getCurrentThemeResource(this, prefs[themeKey])
if (themeResource != 0) {
setTheme(themeResource)
}
super.onCreate(savedInstanceState)
}
override fun onContentChanged() {
super.onContentChanged()
mDoneCancelBar = findViewById(R.id.done_cancel_bar) as Toolbar
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
doneCancelBar = findViewById(R.id.done_cancel_bar) as Toolbar
}
override fun setContentView(layoutResID: Int) {

View File

@ -0,0 +1,52 @@
/*
* 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.activity
import android.content.Context
import android.os.Bundle
import org.mariotaku.kpreferences.get
import org.mariotaku.pickncrop.library.MediaPickerActivity
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
import org.mariotaku.twidere.constant.themeKey
import org.mariotaku.twidere.util.RestFuNetworkStreamDownloader
import org.mariotaku.twidere.util.theme.getCurrentThemeResource
class ThemedMediaPickerActivity : MediaPickerActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
val themeResource = getCurrentThemeResource(this, prefs[themeKey])
if (themeResource != 0) {
setTheme(themeResource)
}
super.onCreate(savedInstanceState)
}
companion object {
fun withThemed(context: Context): MediaPickerActivity.IntentBuilder {
val builder = MediaPickerActivity.IntentBuilder(context, ThemedMediaPickerActivity::class.java)
builder.cropImageActivityClass(ImageCropperActivity::class.java)
builder.streamDownloaderClass(RestFuNetworkStreamDownloader::class.java)
return builder
}
}
}

View File

@ -182,9 +182,14 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
}
}
REQUEST_PICK_MEDIA -> {
if (resultCode == Activity.RESULT_OK && data != null) {
val uri = MediaPickerActivity.getMediaUris(data).firstOrNull() ?: return
performSetConversationAvatar(uri)
when (resultCode) {
Activity.RESULT_OK -> {
val uri = MediaPickerActivity.getMediaUris(data).firstOrNull() ?: return
performSetConversationAvatar(uri)
}
RESULT_CODE_REMOVE_CONVERSATION_AVATAR -> {
performSetConversationAvatar(null)
}
}
}
}
@ -314,6 +319,8 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
.allowMultiple(false)
.aspectRatio(1, 1)
.containsVideo(false)
.addEntry(getString(R.string.action_remove_conversation_avatar),
"remove_avatar", RESULT_CODE_REMOVE_CONVERSATION_AVATAR)
.build()
startActivityForResult(intent, REQUEST_PICK_MEDIA)
}
@ -337,7 +344,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
})
}
private fun performSetConversationAvatar(uri: Uri) {
private fun performSetConversationAvatar(uri: Uri?) {
val conversationId = this.conversationId
performUpdateInfo("set_avatar_progress", updateAction = updateAction@ { fragment, account, microBlog ->
val context = fragment.context
@ -345,19 +352,31 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
AccountType.TWITTER -> {
if (account.isOfficial(context)) {
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
val media = arrayOf(ParcelableMediaUpdate().apply {
this.uri = uri.toString()
this.delete_always = true
})
if (uri == null) {
val result = microBlog.updateDmConversationAvatar(conversationId, null)
if (result.isSuccessful) {
val dmResponse = microBlog.getDmConversation(conversationId, null).conversationTimeline
return@updateAction dmResponse.conversations[conversationId]?.avatarImageHttps
}
throw MicroBlogException("Error ${result.responseCode}")
}
var deleteAlways: List<UpdateStatusTask.MediaDeletionItem>? = null
try {
val media = arrayOf(ParcelableMediaUpdate().apply {
this.uri = uri.toString()
this.delete_always = true
})
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
fragment.mediaLoader, upload, account, media, null, true, null)
deleteAlways = uploadResult.deleteAlways
val avatarId = uploadResult.ids.first()
val result = microBlog.updateDmConversationAvatar(conversationId, avatarId).isSuccessful
uploadResult.deleteOnSuccess.forEach { it.delete(context) }
return@updateAction result
val result = microBlog.updateDmConversationAvatar(conversationId, avatarId)
if (result.isSuccessful) {
uploadResult.deleteOnSuccess.forEach { it.delete(context) }
val dmResponse = microBlog.getDmConversation(conversationId, null).conversationTimeline
return@updateAction dmResponse.conversations[conversationId]?.avatarImageHttps
}
throw MicroBlogException("Error ${result.responseCode}")
} catch (e: UpdateStatusTask.UploadException) {
e.deleteAlways?.forEach {
it.delete(context)
@ -370,15 +389,15 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
}
}
throw UnsupportedOperationException()
}, successAction = {
putNull(Conversations.CONVERSATION_AVATAR)
}, successAction = { uri ->
put(Conversations.CONVERSATION_AVATAR, uri)
})
}
private inline fun performUpdateInfo(
private inline fun <T> performUpdateInfo(
tag: String,
crossinline updateAction: (MessageConversationInfoFragment, AccountDetails, MicroBlog) -> Boolean,
crossinline successAction: ContentValues.() -> Unit
crossinline updateAction: (MessageConversationInfoFragment, AccountDetails, MicroBlog) -> T,
crossinline successAction: ContentValues.(T) -> Unit
) {
ProgressDialogFragment.show(childFragmentManager, tag)
val weakThis = WeakReference(this)
@ -389,10 +408,10 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
val account = AccountUtils.getAccountDetails(AccountManager.get(fragment.context),
accountKey, true) ?: throw MicroBlogException("No account")
val microBlog = account.newMicroBlogInstance(fragment.context, cls = MicroBlog::class.java)
if (!updateAction(fragment, account, microBlog)) throw MicroBlogException("Update failed")
}.then {
return@task updateAction(fragment, account, microBlog)
}.then { result ->
val fragment = weakThis.get() ?: throw InterruptedException()
val values = ContentValues().apply(successAction)
val values = ContentValues().apply { successAction(result) }
val where = Expression.and(Expression.equalsArgs(Conversations.ACCOUNT_KEY),
Expression.equalsArgs(Conversations.CONVERSATION_ID)).sql
val whereArgs = arrayOf(accountKey.toString(), conversationId)
@ -738,6 +757,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
const val RESULT_CLOSE = 101
const val REQUEST_CONVERSATION_ADD_USER = 101
const val REQUEST_PICK_MEDIA = 102
const val RESULT_CODE_REMOVE_CONVERSATION_AVATAR = 10
}
}

View File

@ -43,6 +43,8 @@
<string name="action_dont_terminate">Don\'t quit</string>
<!-- [verb] Edit image/settings etc. -->
<string name="action_edit">Edit</string>
<string name="action_edit_conversation_avatar">Edit icon</string>
<string name="action_edit_conversation_name">Edit name</string>
<string name="action_edit_filter_rule">Edit rule</string>
<string name="action_favorite">Favorite</string>
<string name="action_favoriting">favoriting</string>
@ -79,6 +81,7 @@
<string name="action_refreshing_direct_messages">refreshing direct messages</string>
<string name="action_refreshing_home_timeline">refreshing home timeline</string>
<string name="action_refreshing_mentions">refreshing mentions</string>
<string name="action_remove_conversation_avatar">Remove icon</string>
<string name="action_removing_profile_banner_image">removing profile header image</string>
<string name="action_reply">Reply</string>
<string name="action_report_spam">Report spam</string>
@ -464,6 +467,7 @@
<string name="hint_accounts_dashboard_message">Swipe from screen edge to open accounts dashboard.</string>
<string name="hint_accounts_dashboard_title">Accounts dashboard</string>
<string name="hint_conversation_name">Conversation name</string>
<string name="hint_empty_filters_subscriptions">No subscriptions</string>
<string name="hint_error_message_no_content">No content</string>
<string name="hint_message_select_user">Search users</string>
@ -588,6 +592,7 @@
<string name="message_auto_refresh_confirm">Enable auto refresh to get new tweets automatically?</string>
<string name="message_blocked_user">Blocked <xliff:g id="user">%s</xliff:g>.</string>
<string name="message_conversation_created">Conversation created.</string>
<string name="message_destroy_conversation_confirm">Leave this conversation?</string>
<string name="message_direct_message_deleted">Direct message deleted.</string>
<string name="message_direct_message_sent">Direct message sent.</string>
<string name="message_error_invalid_account">Some account data are corrupted, Twidere will remove those accounts to prevent crash.</string>
@ -1223,8 +1228,4 @@
<string name="users_statuses">User\'s tweets</string>
<string name="vibration">Vibration</string>
<string name="message_destroy_conversation_confirm">Leave this conversation?</string>
<string name="action_edit_conversation_name">Edit name</string>
<string name="action_edit_conversation_avatar">Edit icon</string>
<string name="hint_conversation_name">Conversation name</string>
</resources>