From 76820c1a3c8579946f9dcaa9f0cd9dd5cbc38792 Mon Sep 17 00:00:00 2001 From: Mariotaku Lee Date: Sat, 25 Feb 2017 22:05:52 +0800 Subject: [PATCH] added basic user/follow intent support supports toggle notification for dm --- .../api/PrivateDirectMessagesResources.java | 5 + .../model/ParcelableMessageConversation.java | 4 +- .../DefaultConversationExtras.java | 72 ++++++++++++ .../twidere/view/ShapedImageView.java | 4 +- .../activity/WebLinkHandlerActivity.kt | 5 + ...ParcelableMessageConversationExtensions.kt | 27 ++++- .../MessageConversationInfoFragment.kt | 107 ++++++++++++++++-- .../twidere/loader/ExtensionsListLoader.kt | 2 +- .../twitter/message/AddParticipantsTask.kt | 71 ++++++++++++ .../task/twitter/message/GetMessagesTask.kt | 15 ++- .../twitter/message/MarkMessageReadTask.kt | 37 +++--- .../task/twitter/message/SendMessageTask.kt | 3 +- ...SetConversationNotificationDisabledTask.kt | 86 ++++++++++++++ .../org/mariotaku/twidere/util/IntentUtils.kt | 2 +- .../twidere/util/view/AppBarChildBehavior.kt | 5 +- .../fragment_messages_conversation_info.xml | 4 +- ...out_toolbar_message_conversation_title.xml | 5 + twidere/src/main/res/values/strings.xml | 2 + 18 files changed, 414 insertions(+), 42 deletions(-) create mode 100644 twidere.component.common/src/main/java/org/mariotaku/twidere/model/message/conversation/DefaultConversationExtras.java create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/AddParticipantsTask.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SetConversationNotificationDisabledTask.kt diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java index 7b13c2bb2..c18db7801 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/api/PrivateDirectMessagesResources.java @@ -76,6 +76,11 @@ public interface PrivateDirectMessagesResources extends PrivateResources { @POST("/dm/new.json") DMResponse sendDm(@Param NewDm newDm) throws MicroBlogException; + @POST("/dm/conversation/{conversation_id}/add_participants.json") + DMResponse addParticipants(@Path("conversation_id") String conversationId, + @Param(value = "participant_ids", arrayDelimiter = ',') String[] participantIds) + throws MicroBlogException; + @POST("/dm/destroy.json") ResponseCode destroyDm(@Param("dm_id") String id) throws MicroBlogException; diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableMessageConversation.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableMessageConversation.java index 2757b4337..6619e61a3 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableMessageConversation.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableMessageConversation.java @@ -234,10 +234,10 @@ public class ParcelableMessageConversation implements Parcelable { String GROUP = "group"; } - @StringDef({ExtrasType.FANFOU, ExtrasType.TWITTER_OFFICIAL}) + @StringDef({ExtrasType.DEFAULT, ExtrasType.TWITTER_OFFICIAL}) @Retention(RetentionPolicy.SOURCE) public @interface ExtrasType { - String FANFOU = "fanfou"; + String DEFAULT = "default"; String TWITTER_OFFICIAL = "twitter_official"; } diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/message/conversation/DefaultConversationExtras.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/message/conversation/DefaultConversationExtras.java new file mode 100644 index 000000000..b27655a60 --- /dev/null +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/message/conversation/DefaultConversationExtras.java @@ -0,0 +1,72 @@ +/* + * Twidere - Twitter client for Android + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.twidere.model.message.conversation; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; +import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease; + +import org.mariotaku.microblog.library.twitter.model.DMResponse; + +/** + * Created by mariotaku on 2017/2/13. + */ + +@ParcelablePlease +@JsonObject +public class DefaultConversationExtras extends ConversationExtras implements Parcelable { + + @JsonField(name = "notifications_disabled") + public boolean notificationsDisabled; + + @Override + public String toString() { + return "DefaultConversationExtras{" + + "notificationsDisabled=" + notificationsDisabled + + "} " + super.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + DefaultConversationExtrasParcelablePlease.writeToParcel(this, dest, flags); + } + + public static final Creator CREATOR = new Creator() { + public DefaultConversationExtras createFromParcel(Parcel source) { + DefaultConversationExtras target = new DefaultConversationExtras(); + DefaultConversationExtrasParcelablePlease.readFromParcel(target, source); + return target; + } + + public DefaultConversationExtras[] newArray(int size) { + return new DefaultConversationExtras[size]; + } + }; +} diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java b/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java index dd7f6ffdb..c965c7b91 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java +++ b/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java @@ -300,7 +300,7 @@ public class ShapedImageView extends ImageView { final int contentWidth = contentRight - contentLeft, contentHeight = contentBottom - contentTop; final int size = Math.min(contentWidth, contentHeight); - if (mShadowBitmap != null) { + if (mShadowBitmap != null && mDrawShadow) { canvas.drawBitmap(mShadowBitmap, contentLeft + (contentWidth - size) / 2 - mShadowRadius, contentTop + (contentHeight - size) / 2 - mShadowRadius, null); } @@ -468,7 +468,7 @@ public class ShapedImageView extends ImageView { } private void updateShadowBitmap() { - if (useOutline()) return; + if (useOutline() || !mDrawShadow) return; final int width = getWidth(), height = getHeight(); if (width <= 0 || height <= 0) return; final int contentLeft = getPaddingLeft(), contentTop = getPaddingTop(), diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/WebLinkHandlerActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/WebLinkHandlerActivity.kt index 0a73ffdb9..dd5fe8b9a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/WebLinkHandlerActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/WebLinkHandlerActivity.kt @@ -281,6 +281,11 @@ class WebLinkHandlerActivity : Activity() { val tweetId = uri.getQueryParameter("tweet_id") ?: return Pair(null, false) return Pair(IntentUtils.status(null, tweetId), true) } + "user", "follow" -> { + val userKey = uri.getQueryParameter("user_id")?.let { UserKey(it, "twitter.com") } + val screenName = uri.getQueryParameter("screen_name") + return Pair(IntentUtils.userProfile(null, userKey, screenName), true) + } } return Pair(null, false) } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/ParcelableMessageConversationExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/ParcelableMessageConversationExtensions.kt index c9a0f8c70..afe294e29 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/ParcelableMessageConversationExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/ParcelableMessageConversationExtensions.kt @@ -9,6 +9,7 @@ import org.mariotaku.twidere.model.ParcelableMessageConversation import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType import org.mariotaku.twidere.model.ParcelableMessageConversation.ExtrasType import org.mariotaku.twidere.model.ParcelableUser +import org.mariotaku.twidere.model.message.conversation.DefaultConversationExtras import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras import org.mariotaku.twidere.util.MediaLoaderWrapper import org.mariotaku.twidere.util.UserColorNameManager @@ -86,12 +87,34 @@ val ParcelableMessageConversation.readOnly: Boolean return false } -val ParcelableMessageConversation.notificationDisabled: Boolean +var ParcelableMessageConversation.notificationDisabled: Boolean get() { when (conversation_extras_type) { ExtrasType.TWITTER_OFFICIAL -> { return (conversation_extras as? TwitterOfficialConversationExtras)?.notificationsDisabled ?: false } + else -> { + return (conversation_extras as? DefaultConversationExtras)?.notificationsDisabled ?: false + } + } + } + set(value) { + when (conversation_extras_type) { + ExtrasType.TWITTER_OFFICIAL -> { + val extras = conversation_extras as? TwitterOfficialConversationExtras ?: run { + val obj = TwitterOfficialConversationExtras() + conversation_extras = obj + return@run obj + } + extras.notificationsDisabled = value + } + else -> { + val extras = conversation_extras as? DefaultConversationExtras ?: run { + val obj = DefaultConversationExtras() + conversation_extras = obj + return@run obj + } + extras.notificationsDisabled = value + } } - return false } \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt index 432a1835a..051dbc5a2 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt @@ -19,8 +19,10 @@ package org.mariotaku.twidere.fragment.message +import android.app.Activity import android.app.Dialog import android.content.Context +import android.content.Intent import android.os.Bundle import android.support.v4.app.DialogFragment import android.support.v4.app.FragmentActivity @@ -34,6 +36,7 @@ import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.support.v7.widget.Toolbar import android.view.* +import android.widget.CompoundButton import kotlinx.android.synthetic.main.activity_home_content.view.* import kotlinx.android.synthetic.main.fragment_messages_conversation_info.* import kotlinx.android.synthetic.main.header_message_conversation_info.view.* @@ -45,10 +48,11 @@ import org.mariotaku.kpreferences.get import org.mariotaku.ktextension.useCursor import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.twidere.R +import org.mariotaku.twidere.activity.UserSelectorActivity import org.mariotaku.twidere.adapter.BaseRecyclerViewAdapter import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter -import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY -import org.mariotaku.twidere.constant.IntentConstants.EXTRA_CONVERSATION_ID +import org.mariotaku.twidere.constant.IntentConstants +import org.mariotaku.twidere.constant.IntentConstants.* import org.mariotaku.twidere.constant.nameFirstKey import org.mariotaku.twidere.constant.profileImageStyleKey import org.mariotaku.twidere.extension.applyTheme @@ -65,7 +69,9 @@ import org.mariotaku.twidere.fragment.message.MessageConversationInfoFragment.Co import org.mariotaku.twidere.fragment.message.MessageConversationInfoFragment.ConversationInfoAdapter.Companion.VIEW_TYPE_SPACE import org.mariotaku.twidere.model.* import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations +import org.mariotaku.twidere.task.twitter.message.AddParticipantsTask import org.mariotaku.twidere.task.twitter.message.DestroyConversationTask +import org.mariotaku.twidere.task.twitter.message.SetConversationNotificationDisabledTask import org.mariotaku.twidere.util.IntentUtils import org.mariotaku.twidere.view.holder.SimpleUserViewHolder import java.lang.ref.WeakReference @@ -105,6 +111,18 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, startActivity(IntentUtils.userProfile(user)) } + override fun onAddUserClick(position: Int) { + val conversation = adapter.conversation ?: return + val intent = Intent(IntentConstants.INTENT_ACTION_SELECT_USER) + intent.putExtra(EXTRA_ACCOUNT_KEY, conversation.account_key) + intent.setClass(context, UserSelectorActivity::class.java) + startActivityForResult(intent, REQUEST_CONVERSATION_ADD_USER) + } + + override fun onDisableNotificationChanged(disabled: Boolean) { + performSetNotificationDisabled(disabled) + } + } recyclerView.adapter = adapter recyclerView.layoutManager = LayoutManager(context) @@ -123,9 +141,25 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, conversationTitle.setTextColor(ChameleonUtils.getColorDependent(theme.colorToolbar)) conversationSubtitle.setTextColor(ChameleonUtils.getColorDependent(theme.colorToolbar)) + editButton.setOnClickListener { + executeAfterFragmentResumed { fragment -> + val df = EditInfoDialogFragment() + df.show(fragment.childFragmentManager, "edit_info") + } + } + loaderManager.initLoader(0, null, this) + } - + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + when (requestCode) { + REQUEST_CONVERSATION_ADD_USER -> { + if (resultCode == Activity.RESULT_OK && data != null) { + val user = data.getParcelableExtra(EXTRA_USER) + performAddParticipant(user) + } + } + } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -185,9 +219,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, val task = DestroyConversationTask(context, accountKey, conversationId) task.callback = callback@ { succeed -> val f = weakThis.get() ?: return@callback - f.executeAfterFragmentResumed { fragment -> - val df = fragment.childFragmentManager.findFragmentByTag("leave_conversation_progress") as? DialogFragment - df?.dismiss() + f.dismissAlertDialogThen("leave_conversation_progress") { if (succeed) { activity?.setResult(RESULT_CLOSE) activity?.finish() @@ -197,6 +229,37 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, TaskStarter.execute(task) } + private fun performAddParticipant(user: ParcelableUser) { + ProgressDialogFragment.show(childFragmentManager, "add_participant_progress") + val weakThis = WeakReference(this) + val task = AddParticipantsTask(context, accountKey, conversationId, arrayOf(user.key.id)) + task.callback = callback@ { succeed -> + val f = weakThis.get() ?: return@callback + f.dismissAlertDialogThen("add_participant_progress") {} + } + TaskStarter.execute(task) + } + + private fun performSetNotificationDisabled(disabled: Boolean) { + ProgressDialogFragment.show(childFragmentManager, "set_notifications_disabled_progress") + val weakThis = WeakReference(this) + val task = SetConversationNotificationDisabledTask(context, accountKey, conversationId, disabled) + task.callback = callback@ { succeed -> + val f = weakThis.get() ?: return@callback + f.dismissAlertDialogThen("set_notifications_disabled_progress") {} + } + TaskStarter.execute(task) + } + + + private inline fun dismissAlertDialogThen(tag: String, crossinline action: BaseFragment.() -> Unit) { + executeAfterFragmentResumed { fragment -> + val df = fragment.childFragmentManager.findFragmentByTag(tag) as? DialogFragment + df?.dismiss() + action(fragment) + } + } + class ConversationInfoLoader( context: Context, val accountKey: UserKey, @@ -262,7 +325,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, when (viewType) { VIEW_TYPE_HEADER -> { val view = inflater.inflate(HeaderViewHolder.layoutResource, parent, false) - return HeaderViewHolder(view) + return HeaderViewHolder(view, this) } VIEW_TYPE_USER -> { val view = inflater.inflate(R.layout.list_item_conversation_info_user, parent, false) @@ -310,6 +373,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, interface Listener { fun onUserClick(position: Int) {} fun onAddUserClick(position: Int) {} + fun onDisableNotificationChanged(disabled: Boolean) {} } companion object { @@ -359,16 +423,21 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, } } - internal class HeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + internal class HeaderViewHolder(itemView: View, adapter: ConversationInfoAdapter) : RecyclerView.ViewHolder(itemView) { private val muteSwitch = itemView.muteNotifications + private val listener = CompoundButton.OnCheckedChangeListener { button, checked -> + adapter.listener?.onDisableNotificationChanged(checked) + } + fun display(conversation: ParcelableMessageConversation) { + muteSwitch.setOnCheckedChangeListener(null) muteSwitch.isChecked = conversation.notificationDisabled + muteSwitch.setOnCheckedChangeListener(listener) } companion object { const val layoutResource = R.layout.header_message_conversation_info - } } @@ -385,6 +454,25 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, } + class EditInfoDialogFragment : BaseDialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val actions = arrayOf(Action(getString(R.string.action_edit_conversation_name), "name"), + Action(getString(R.string.action_edit_conversation_avatar), "avatar")) + val builder = AlertDialog.Builder(context) + builder.setItems(actions.map(Action::title).toTypedArray()) { dialog, which -> + + } + val dialog = builder.create() + dialog.setOnShowListener { + it as AlertDialog + it.applyTheme() + } + return dialog + } + + data class Action(val title: String, val type: String) + } + class DestroyConversationConfirmDialogFragment : BaseDialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(context) @@ -405,5 +493,6 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment, companion object { const val RESULT_CLOSE = 101 + const val REQUEST_CONVERSATION_ADD_USER = 101 } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/loader/ExtensionsListLoader.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/loader/ExtensionsListLoader.kt index bb9408b5e..cc51bd823 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/loader/ExtensionsListLoader.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/loader/ExtensionsListLoader.kt @@ -51,7 +51,7 @@ class ExtensionsListLoader( extensions.add(ExtensionInfo(info, packageManager)) } } - extensions.sort(ExtensionInfoComparator(Collator.getInstance())) + Collections.sort(extensions, ExtensionInfoComparator(Collator.getInstance())) return extensions } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/AddParticipantsTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/AddParticipantsTask.kt new file mode 100644 index 000000000..714b38b04 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/AddParticipantsTask.kt @@ -0,0 +1,71 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.task.twitter.message + +import android.accounts.AccountManager +import android.content.Context +import org.mariotaku.microblog.library.MicroBlog +import org.mariotaku.microblog.library.MicroBlogException +import org.mariotaku.twidere.annotation.AccountType +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.UserKey +import org.mariotaku.twidere.model.util.AccountUtils +import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask + +/** + * Created by mariotaku on 2017/2/25. + */ + +class AddParticipantsTask( + context: Context, + val accountKey: UserKey, + val conversationId: String, + val participantIds: Array +) : ExceptionHandlingAbstractTask Unit)?>(context) { + override fun onExecute(params: Unit?): Boolean { + val account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?: + throw MicroBlogException("No account") + val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java) + val addData = requestAddParticipants(microBlog, account) + GetMessagesTask.storeMessages(context, addData, account) + return true + } + + override fun afterExecute(callback: ((Boolean) -> Unit)?, result: Boolean?, exception: MicroBlogException?) { + callback?.invoke(result ?: false) + } + + private fun requestAddParticipants(microBlog: MicroBlog, account: AccountDetails): + GetMessagesTask.DatabaseUpdateData { + when (account.type) { + AccountType.TWITTER -> { + if (account.isOfficial(context)) { + val response = microBlog.addParticipants(conversationId, participantIds); + return GetMessagesTask.createDatabaseUpdateData(context, account, response) + } + } + + } + throw MicroBlogException("Adding participants is not supported") + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt index 77d8ec2f1..e928aeef8 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/GetMessagesTask.kt @@ -40,6 +40,7 @@ import org.mariotaku.twidere.extension.model.timestamp import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType import org.mariotaku.twidere.model.event.GetMessagesTaskEvent +import org.mariotaku.twidere.model.message.conversation.DefaultConversationExtras import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.model.util.AccountUtils.getAccountDetails @@ -165,13 +166,23 @@ class GetMessagesTask( val message = ParcelableMessageUtils.fromMessage(accountKey, dm, false, 1.0 - (i.toDouble() / received.size)) insertMessages.add(message) - conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient)) + val conversation = conversations.addConversation(message.conversation_id, details, + message, setOf(dm.sender, dm.recipient)) ?: return@forEachIndexed + conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT + if (conversation.conversation_extras == null) { + conversation.conversation_extras = DefaultConversationExtras() + } } sent.forEachIndexed { i, dm -> val message = ParcelableMessageUtils.fromMessage(accountKey, dm, true, 1.0 - (i.toDouble() / sent.size)) insertMessages.add(message) - conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient)) + val conversation = conversations.addConversation(message.conversation_id, details, + message, setOf(dm.sender, dm.recipient)) ?: return@forEachIndexed + conversation.conversation_extras_type = ParcelableMessageConversation.ExtrasType.DEFAULT + if (conversation.conversation_extras == null) { + conversation.conversation_extras = DefaultConversationExtras() + } } return DatabaseUpdateData(conversations.values, insertMessages) } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/MarkMessageReadTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/MarkMessageReadTask.kt index b13ab4247..bc1f49b78 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/MarkMessageReadTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/MarkMessageReadTask.kt @@ -53,7 +53,7 @@ class MarkMessageReadTask( val account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?: throw MicroBlogException("No account") val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java) - val conversation = findConversation(accountKey, conversationId) + val conversation = findConversation(context, accountKey, conversationId) val lastReadEvent = conversation?.let { return@let performMarkRead(microBlog, account, conversation) } ?: return false @@ -92,22 +92,6 @@ class MarkMessageReadTask( return Pair(message.id, message.timestamp) } - private fun findConversation(accountKey: UserKey, conversationId: String): ParcelableMessageConversation? { - val deleteWhere = Expression.and(Expression.equalsArgs(Conversations.ACCOUNT_KEY), - Expression.equalsArgs(Conversations.CONVERSATION_ID)).sql - val deleteWhereArgs = arrayOf(accountKey.toString(), conversationId) - @SuppressLint("Recycle") - val cur = context.contentResolver.query(Conversations.CONTENT_URI, Conversations.COLUMNS, - deleteWhere, deleteWhereArgs, null) ?: return null - try { - if (cur.moveToFirst()) { - return ParcelableMessageConversationCursorIndices.fromCursor(cur) - } - } finally { - cur.close() - } - return null - } private fun findRecentMessage(accountKey: UserKey, conversationId: String): ParcelableMessage? { val where = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY), @@ -133,5 +117,24 @@ class MarkMessageReadTask( return Pair(id, maxEntryTimestamp) } + companion object { + fun findConversation(context: Context, accountKey: UserKey, conversationId: String): + ParcelableMessageConversation? { + val deleteWhere = Expression.and(Expression.equalsArgs(Conversations.ACCOUNT_KEY), + Expression.equalsArgs(Conversations.CONVERSATION_ID)).sql + val deleteWhereArgs = arrayOf(accountKey.toString(), conversationId) + @SuppressLint("Recycle") + val cur = context.contentResolver.query(Conversations.CONTENT_URI, Conversations.COLUMNS, + deleteWhere, deleteWhereArgs, null) ?: return null + try { + if (cur.moveToFirst()) { + return ParcelableMessageConversationCursorIndices.fromCursor(cur) + } + } finally { + cur.close() + } + return null + } + } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SendMessageTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SendMessageTask.kt index cb03462cd..08f13d88e 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SendMessageTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SendMessageTask.kt @@ -73,7 +73,8 @@ class SendMessageTask( result.conversationIds.singleOrNull(), true)) } - private fun requestSendMessage(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData { + private fun requestSendMessage(microBlog: MicroBlog, account: AccountDetails, + message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData { when (account.type) { AccountType.TWITTER -> { if (account.isOfficial(context)) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SetConversationNotificationDisabledTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SetConversationNotificationDisabledTask.kt new file mode 100644 index 000000000..cedb08003 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SetConversationNotificationDisabledTask.kt @@ -0,0 +1,86 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.task.twitter.message + +import android.accounts.AccountManager +import android.content.Context +import org.mariotaku.microblog.library.MicroBlog +import org.mariotaku.microblog.library.MicroBlogException +import org.mariotaku.twidere.annotation.AccountType +import org.mariotaku.twidere.extension.model.isOfficial +import org.mariotaku.twidere.extension.model.newMicroBlogInstance +import org.mariotaku.twidere.extension.model.notificationDisabled +import org.mariotaku.twidere.model.AccountDetails +import org.mariotaku.twidere.model.UserKey +import org.mariotaku.twidere.model.util.AccountUtils +import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask + +/** + * Created by mariotaku on 2017/2/25. + */ + +class SetConversationNotificationDisabledTask( + context: Context, + val accountKey: UserKey, + val conversationId: String, + val notificationDisabled: Boolean +) : ExceptionHandlingAbstractTask Unit)?>(context) { + override fun onExecute(params: Unit?): Boolean { + val account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?: + throw MicroBlogException("No account") + val microBlog = account.newMicroBlogInstance(context, cls = MicroBlog::class.java) + val addData = requestSetNotificationDisabled(microBlog, account) + GetMessagesTask.storeMessages(context, addData, account) + return true + } + + override fun afterExecute(callback: ((Boolean) -> Unit)?, result: Boolean?, exception: MicroBlogException?) { + callback?.invoke(result ?: false) + } + + private fun requestSetNotificationDisabled(microBlog: MicroBlog, account: AccountDetails): + GetMessagesTask.DatabaseUpdateData { + when (account.type) { + AccountType.TWITTER -> { + if (account.isOfficial(context)) { + val response = if (notificationDisabled) { + microBlog.enableDmConversations(conversationId); + } else { + microBlog.disableDmConversations(conversationId); + } + val conversation = MarkMessageReadTask.findConversation(context, accountKey, + conversationId) ?: return GetMessagesTask.DatabaseUpdateData(emptyList(), emptyList()) + if (response.isSuccessful) { + conversation.notificationDisabled = notificationDisabled + } + return GetMessagesTask.DatabaseUpdateData(listOf(conversation), emptyList()) + } + } + } + + val conversation = MarkMessageReadTask.findConversation(context, accountKey, + conversationId) ?: return GetMessagesTask.DatabaseUpdateData(emptyList(), emptyList()) + conversation.notificationDisabled = notificationDisabled + // Don't finish too fast + Thread.sleep(300L) + return GetMessagesTask.DatabaseUpdateData(listOf(conversation), emptyList()) + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/IntentUtils.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/IntentUtils.kt index e18def0fb..6b9f5b3a8 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/IntentUtils.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/IntentUtils.kt @@ -76,7 +76,7 @@ object IntentUtils { } fun userProfile(accountKey: UserKey?, userKey: UserKey?, screenName: String?, - @Referral referral: String? = null, profileUrl: String?): Intent { + @Referral referral: String? = null, profileUrl: String? = null): Intent { val uri = LinkCreator.getTwidereUserLink(accountKey, userKey, screenName) val intent = Intent(Intent.ACTION_VIEW, uri) if (referral != null) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/view/AppBarChildBehavior.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/view/AppBarChildBehavior.kt index 7deaf7a16..49da786a3 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/view/AppBarChildBehavior.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/view/AppBarChildBehavior.kt @@ -60,7 +60,6 @@ class AppBarChildBehavior( private val dependencyRect = Rect() private val thisRect = Rect() - private val thisInitRect = Rect() private val targetRect = Rect() private val tempRect = Rect() @@ -95,7 +94,7 @@ class AppBarChildBehavior( val dependency = parent.getDependencies(child).first() dependency.getFrameRelatedTo(dependencyRect, parent) - child.layoutRelatedTo(dependencyRect, layoutDirection) + child.layoutRelatedTo(parent, dependencyRect, layoutDirection) child.getFrameRelatedTo(thisRect, parent) target.getFrameRelatedTo(targetRect, parent) @@ -116,7 +115,7 @@ class AppBarChildBehavior( return true } - internal fun View.layoutRelatedTo(frame: Rect, layoutDirection: Int) { + internal fun View.layoutRelatedTo(parent: CoordinatorLayout, frame: Rect, layoutDirection: Int) { val verticalRule = alignmentRule and VERTICAL_MASK val horizontalRule = alignmentRule and HORIZONTAL_MASK tempRect.set(0, 0, measuredWidth, measuredHeight) diff --git a/twidere/src/main/res/layout/fragment_messages_conversation_info.xml b/twidere/src/main/res/layout/fragment_messages_conversation_info.xml index 0c181ddb1..24fc2f48e 100644 --- a/twidere/src/main/res/layout/fragment_messages_conversation_info.xml +++ b/twidere/src/main/res/layout/fragment_messages_conversation_info.xml @@ -82,7 +82,7 @@ android:layout_height="wrap_content" android:elevation="8dp" android:ellipsize="end" - android:minLines="1" + android:maxLines="1" android:textAppearance="?android:textAppearanceLarge" android:textColor="?android:textColorPrimary" android:textStyle="normal" @@ -102,7 +102,7 @@ android:layout_height="wrap_content" android:elevation="8dp" android:ellipsize="end" - android:minLines="1" + android:maxLines="1" android:textAppearance="?android:textAppearanceSmall" android:textColor="?android:textColorSecondary" android:textStyle="normal" diff --git a/twidere/src/main/res/layout/layout_toolbar_message_conversation_title.xml b/twidere/src/main/res/layout/layout_toolbar_message_conversation_title.xml index 873e21db8..5f433fc38 100644 --- a/twidere/src/main/res/layout/layout_toolbar_message_conversation_title.xml +++ b/twidere/src/main/res/layout/layout_toolbar_message_conversation_title.xml @@ -36,6 +36,7 @@ android:layout_height="match_parent" android:layout_margin="@dimen/element_spacing_normal" android:layout_weight="0" + app:sivDrawShadow="false" app:sivShape="circle" tools:src="@drawable/ic_profile_image_default_group"/> @@ -52,6 +53,8 @@ android:id="@+id/conversationTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" android:textAppearance="?android:textAppearanceMedium" android:textColor="?android:textColorPrimary" tools:text="Conversation name"/> @@ -60,6 +63,8 @@ android:id="@+id/conversationSubtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" android:textAppearance="?android:textAppearanceSmall" android:textColor="?android:textColorSecondary" tools:text="Conversation summary"/> diff --git a/twidere/src/main/res/values/strings.xml b/twidere/src/main/res/values/strings.xml index 62cd18f7f..affbd61db 100644 --- a/twidere/src/main/res/values/strings.xml +++ b/twidere/src/main/res/values/strings.xml @@ -1224,4 +1224,6 @@ Vibration Leave this conversation? + Edit name + Edit icon