diff --git a/gradle.properties b/gradle.properties index 7625c74d5..c00fb02d8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,4 +16,5 @@ # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -org.gradle.jvmargs=-Xmx2048M \ No newline at end of file +org.gradle.jvmargs=-Xmx2048M +kotlin.incremental=true \ No newline at end of file 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 56fa3e89f..4857e5ba2 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 @@ -54,6 +54,9 @@ public interface PrivateDirectMessagesResources extends PrivateResources { @POST("/dm/new.json") DMResponse sendDm(@Param NewDm newDm) throws MicroBlogException; + @POST("/dm/destroy.json") + ResponseCode destroyDm(@Param("dm_id") String id) throws MicroBlogException; + @GET("/dm/user_inbox.json") UserInbox getUserInbox(@Query Paging paging) throws MicroBlogException; diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt index 3c240083d..e5c9f62cd 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt @@ -62,7 +62,10 @@ import org.apache.commons.lang3.ObjectUtils import org.mariotaku.abstask.library.AbstractTask import org.mariotaku.abstask.library.TaskStarter import org.mariotaku.kpreferences.get -import org.mariotaku.ktextension.* +import org.mariotaku.ktextension.checkAnySelfPermissionsGranted +import org.mariotaku.ktextension.getTypedArray +import org.mariotaku.ktextension.setItemChecked +import org.mariotaku.ktextension.toTypedArray import org.mariotaku.pickncrop.library.MediaPickerActivity import org.mariotaku.twidere.Constants.* import org.mariotaku.twidere.R @@ -651,25 +654,32 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener } override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo) { - if (v === attachedMediaPreview) { - menu.setHeaderTitle(R.string.edit_media) - supportMenuInflater.inflate(R.menu.menu_attached_media_edit, menu) + if (menuInfo !is ExtendedRecyclerView.ContextMenuInfo) return + when (menuInfo.recyclerViewId) { + R.id.attachedMediaPreview -> { + menu.setHeaderTitle(R.string.edit_media) + supportMenuInflater.inflate(R.menu.menu_attached_media_edit, menu) + } } } override fun onContextItemSelected(item: MenuItem): Boolean { - val menuInfo = item.menuInfo - if (menuInfo is ExtendedRecyclerView.ContextMenuInfo) { - when (menuInfo.recyclerViewId) { - R.id.attachedMediaPreview -> { - val position = menuInfo.position - val altText = mediaPreviewAdapter.getItem(position).alt_text - executeAfterFragmentResumed { activity -> - EditAltTextDialogFragment.show(activity.supportFragmentManager, position, - altText) + val menuInfo = item.menuInfo as? ExtendedRecyclerView.ContextMenuInfo ?: run { + return super.onContextItemSelected(item) + } + when (menuInfo.recyclerViewId) { + R.id.attachedMediaPreview -> { + when (item.itemId) { + R.id.edit_description -> { + val position = menuInfo.position + val altText = mediaPreviewAdapter.getItem(position).alt_text + executeAfterFragmentResumed { activity -> + EditAltTextDialogFragment.show(activity.supportFragmentManager, position, + altText) + } } - return true } + return true } } return super.onContextItemSelected(item) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/HomeActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/HomeActivity.kt index bcdbd7b35..51509bd79 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/HomeActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/HomeActivity.kt @@ -72,13 +72,15 @@ import org.mariotaku.ktextension.convert import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe import org.mariotaku.twidere.Constants.* import org.mariotaku.twidere.R -import org.mariotaku.twidere.activity.iface.IControlBarActivity +import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper import org.mariotaku.twidere.adapter.SupportTabsAdapter import org.mariotaku.twidere.annotation.CustomTabType import org.mariotaku.twidere.annotation.ReadPositionTag import org.mariotaku.twidere.constant.* import org.mariotaku.twidere.extension.applyTheme -import org.mariotaku.twidere.fragment.* +import org.mariotaku.twidere.fragment.AccountsDashboardFragment +import org.mariotaku.twidere.fragment.BaseDialogFragment +import org.mariotaku.twidere.fragment.CustomTabsFragment import org.mariotaku.twidere.fragment.iface.IFloatingActionButtonFragment import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback @@ -87,7 +89,6 @@ import org.mariotaku.twidere.model.AccountDetails import org.mariotaku.twidere.model.SupportTabSpec import org.mariotaku.twidere.model.Tab import org.mariotaku.twidere.model.UserKey -import org.mariotaku.twidere.model.event.TaskStateChangedEvent import org.mariotaku.twidere.model.event.UnreadCountUpdatedEvent import org.mariotaku.twidere.provider.TwidereDataStore.Activities import org.mariotaku.twidere.provider.TwidereDataStore.Statuses @@ -112,7 +113,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp private var updateUnreadCountTask: UpdateUnreadCountTask? = null private val readStateChangeListener = OnSharedPreferenceChangeListener { sharedPreferences, key -> updateUnreadCount() } - private val controlBarShowHideHelper = IControlBarActivity.ControlBarShowHideHelper(this) + private val controlBarShowHideHelper = ControlBarShowHideHelper(this) private val homeDrawerToggleDelegate = object : ActionBarDrawerToggle.Delegate { override fun setActionBarUpIndicator(upDrawable: Drawable, @StringRes contentDescRes: Int) { @@ -172,133 +173,6 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp val leftDrawerFragment: Fragment? get() = supportFragmentManager.findFragmentById(R.id.leftDrawer) - override fun getSystemWindowsInsets(insets: Rect): Boolean { - if (mainTabs == null || homeContent == null) return false - val height = mainTabs.height - if (height != 0) { - insets.top = height - } else { - insets.top = ThemeUtils.getActionBarHeight(this) - } - return true - } - - override fun setControlBarVisibleAnimate(visible: Boolean, listener: IControlBarActivity.ControlBarShowHideHelper.ControlBarAnimationListener?) { - controlBarShowHideHelper.setControlBarVisibleAnimate(visible, listener) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (drawerToggle.onOptionsItemSelected(item)) { - return true - } - when (item.itemId) { - android.R.id.home -> { - val fm = supportFragmentManager - val count = fm.backStackEntryCount - if (homeMenu.isDrawerOpen(GravityCompat.START) || homeMenu.isDrawerOpen(GravityCompat.END)) { - homeMenu.closeDrawers() - return true - } else if (count == 0) { - homeMenu.openDrawer(GravityCompat.START) - return true - } - return true - } - R.id.search -> { - openSearchView(selectedAccountToSearch) - return true - } - R.id.actions -> { - triggerActionsClick() - return true - } - } - return super.onOptionsItemSelected(item) - } - - override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean { - if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event, metaState)) return true - var action = handler.getKeyAction(KeyboardShortcutConstants.CONTEXT_TAG_HOME, keyCode, event, metaState) - if (action != null) { - when (action) { - KeyboardShortcutConstants.ACTION_HOME_ACCOUNTS_DASHBOARD -> { - if (homeMenu.isDrawerOpen(GravityCompat.START)) { - homeMenu.closeDrawers() - } else { - homeMenu.openDrawer(GravityCompat.START) - setControlBarVisibleAnimate(true) - } - return true - } - } - } - action = handler.getKeyAction(KeyboardShortcutConstants.CONTEXT_TAG_NAVIGATION, keyCode, event, metaState) - if (action != null) { - when (action) { - KeyboardShortcutConstants.ACTION_NAVIGATION_PREVIOUS_TAB -> { - val previous = mainPager.currentItem - 1 - if (previous < 0 && DrawerLayoutAccessor.findDrawerWithGravity(homeMenu, Gravity.START) != null) { - homeMenu.openDrawer(GravityCompat.START) - setControlBarVisibleAnimate(true) - } else if (previous < pagerAdapter.count) { - if (homeMenu.isDrawerOpen(GravityCompat.END)) { - homeMenu.closeDrawers() - } else { - mainPager.setCurrentItem(previous, true) - } - } - return true - } - KeyboardShortcutConstants.ACTION_NAVIGATION_NEXT_TAB -> { - val next = mainPager.currentItem + 1 - if (next >= pagerAdapter.count && DrawerLayoutAccessor.findDrawerWithGravity(homeMenu, Gravity.END) != null) { - homeMenu.openDrawer(GravityCompat.END) - setControlBarVisibleAnimate(true) - } else if (next >= 0) { - if (homeMenu.isDrawerOpen(GravityCompat.START)) { - homeMenu.closeDrawers() - } else { - mainPager.setCurrentItem(next, true) - } - } - return true - } - } - } - return handler.handleKey(this, null, keyCode, event, metaState) - } - - override fun isKeyboardShortcutHandled(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean { - if (isFragmentKeyboardShortcutHandled(handler, keyCode, event, metaState)) return true - return super.isKeyboardShortcutHandled(handler, keyCode, event, metaState) - } - - override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler, keyCode: Int, repeatCount: Int, event: KeyEvent, metaState: Int): Boolean { - if (handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)) - return true - return super.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState) - } - - override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { - when (keyCode) { - KeyEvent.KEYCODE_MENU -> { - if (isDrawerOpen) { - homeMenu.closeDrawers() - } else { - homeMenu.openDrawer(GravityCompat.START) - } - return true - } - KeyEvent.KEYCODE_BACK -> { - if (isDrawerOpen) { - homeMenu.closeDrawers() - return true - } - } - } - return super.onKeyUp(keyCode, event) - } - private val isDrawerOpen: Boolean get() { val drawer = homeMenu ?: return false @@ -405,6 +279,12 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp } } + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + // Sync the toggle state after onRestoreInstanceState has occurred. + drawerToggle.syncState() + } + override fun onStart() { super.onStart() multiSelectHandler.dispatchOnStart() @@ -431,23 +311,33 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp super.onStop() } - fun notifyAccountsChanged() { + override fun onDestroy() { + stopService(Intent(this, StreamingService::class.java)) + + // Delete unused items in databases. + + val context = applicationContext + TaskStarter.execute(object : AbstractTask() { + override fun doLongOperation(o: Any?): Any? { + DataStoreUtils.cleanDatabasesByItemLimit(context) + return null + } + }) + super.onDestroy() + } + + override fun onAttachFragment(fragment: Fragment?) { + super.onAttachFragment(fragment) + // Must exclude fragments not belongs tabs, otherwise it will crash + if (fragment !is AccountsDashboardFragment) { + updateActionsButton() + } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) } - @Subscribe - fun notifyTaskStateChanged(event: TaskStateChangedEvent) { - updateActionsButton() - } - - @Subscribe - fun notifyUnreadCountUpdated(event: UnreadCountUpdatedEvent) { - updateUnreadCount() - } - override fun onClick(v: View) { when (v) { actionsButton -> { @@ -499,11 +389,6 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp return true } - fun openSearchView(account: AccountDetails?) { - selectedAccountToSearch = account - onSearchRequested() - } - override fun onFitSystemWindows(insets: Rect) { super.onFitSystemWindows(insets) val fragment = leftDrawerFragment @@ -512,6 +397,158 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp } } + override fun onNewIntent(intent: Intent) { + val tabPosition = handleIntent(intent, false) + if (tabPosition >= 0) { + mainPager.currentItem = tabPosition.coerceInOr(0 until pagerAdapter.count, 0) + } + } + + override fun getSystemWindowsInsets(insets: Rect): Boolean { + if (mainTabs == null || homeContent == null) return false + val height = mainTabs.height + if (height != 0) { + insets.top = height + } else { + insets.top = ThemeUtils.getActionBarHeight(this) + } + return true + } + + override fun setControlBarVisibleAnimate(visible: Boolean, + listener: ControlBarShowHideHelper.ControlBarAnimationListener?) { + controlBarShowHideHelper.setControlBarVisibleAnimate(visible, listener) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (drawerToggle.onOptionsItemSelected(item)) { + return true + } + when (item.itemId) { + android.R.id.home -> { + val fm = supportFragmentManager + val count = fm.backStackEntryCount + if (homeMenu.isDrawerOpen(GravityCompat.START) || homeMenu.isDrawerOpen(GravityCompat.END)) { + homeMenu.closeDrawers() + return true + } else if (count == 0) { + homeMenu.openDrawer(GravityCompat.START) + return true + } + return true + } + R.id.search -> { + openSearchView(selectedAccountToSearch) + return true + } + R.id.actions -> { + triggerActionsClick() + return true + } + } + return super.onOptionsItemSelected(item) + } + + override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, + event: KeyEvent, metaState: Int): Boolean { + if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event, metaState)) return true + var action = handler.getKeyAction(KeyboardShortcutConstants.CONTEXT_TAG_HOME, keyCode, event, metaState) + if (action != null) { + when (action) { + KeyboardShortcutConstants.ACTION_HOME_ACCOUNTS_DASHBOARD -> { + if (homeMenu.isDrawerOpen(GravityCompat.START)) { + homeMenu.closeDrawers() + } else { + homeMenu.openDrawer(GravityCompat.START) + setControlBarVisibleAnimate(true) + } + return true + } + } + } + action = handler.getKeyAction(KeyboardShortcutConstants.CONTEXT_TAG_NAVIGATION, keyCode, event, metaState) + if (action != null) { + when (action) { + KeyboardShortcutConstants.ACTION_NAVIGATION_PREVIOUS_TAB -> { + val previous = mainPager.currentItem - 1 + if (previous < 0 && DrawerLayoutAccessor.findDrawerWithGravity(homeMenu, Gravity.START) != null) { + homeMenu.openDrawer(GravityCompat.START) + setControlBarVisibleAnimate(true) + } else if (previous < pagerAdapter.count) { + if (homeMenu.isDrawerOpen(GravityCompat.END)) { + homeMenu.closeDrawers() + } else { + mainPager.setCurrentItem(previous, true) + } + } + return true + } + KeyboardShortcutConstants.ACTION_NAVIGATION_NEXT_TAB -> { + val next = mainPager.currentItem + 1 + if (next >= pagerAdapter.count && DrawerLayoutAccessor.findDrawerWithGravity(homeMenu, Gravity.END) != null) { + homeMenu.openDrawer(GravityCompat.END) + setControlBarVisibleAnimate(true) + } else if (next >= 0) { + if (homeMenu.isDrawerOpen(GravityCompat.START)) { + homeMenu.closeDrawers() + } else { + mainPager.setCurrentItem(next, true) + } + } + return true + } + } + } + return handler.handleKey(this, null, keyCode, event, metaState) + } + + override fun isKeyboardShortcutHandled(handler: KeyboardShortcutsHandler, keyCode: Int, + event: KeyEvent, metaState: Int): Boolean { + if (isFragmentKeyboardShortcutHandled(handler, keyCode, event, metaState)) return true + return super.isKeyboardShortcutHandled(handler, keyCode, event, metaState) + } + + override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler, keyCode: Int, + repeatCount: Int, event: KeyEvent, metaState: Int): Boolean { + if (handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)) + return true + return super.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState) + } + + override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_MENU -> { + if (isDrawerOpen) { + homeMenu.closeDrawers() + } else { + homeMenu.openDrawer(GravityCompat.START) + } + return true + } + KeyEvent.KEYCODE_BACK -> { + if (isDrawerOpen) { + homeMenu.closeDrawers() + return true + } + } + } + return super.onKeyUp(keyCode, event) + } + + + fun notifyAccountsChanged() { + } + + @Subscribe + fun notifyUnreadCountUpdated(event: UnreadCountUpdatedEvent) { + updateUnreadCount() + } + + fun openSearchView(account: AccountDetails?) { + selectedAccountToSearch = account + onSearchRequested() + } + fun updateUnreadCount() { if (mainTabs == null || updateUnreadCountTask != null && updateUnreadCountTask!!.status == AsyncTask.Status.RUNNING) return @@ -524,34 +561,6 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp val tabs: List get() = pagerAdapter.tabs - override fun onNewIntent(intent: Intent) { - val tabPosition = handleIntent(intent, false) - if (tabPosition >= 0) { - mainPager.currentItem = tabPosition.coerceInOr(0 until pagerAdapter.count, 0) - } - } - - override fun onDestroy() { - stopService(Intent(this, StreamingService::class.java)) - - // Delete unused items in databases. - - val context = applicationContext - TaskStarter.execute(object : AbstractTask() { - override fun doLongOperation(o: Any?): Any? { - DataStoreUtils.cleanDatabasesByItemLimit(context) - return null - } - }) - super.onDestroy() - } - - override fun onPostCreate(savedInstanceState: Bundle?) { - super.onPostCreate(savedInstanceState) - // Sync the toggle state after onRestoreInstanceState has occurred. - drawerToggle.syncState() - } - override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // Pass any configuration change to the drawer toggle @@ -842,9 +851,15 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp } private fun updateActionsButton() { - val position = mainPager.currentItem - if (pagerAdapter.count == 0) return - val fragment = pagerAdapter.instantiateItem(mainPager, position) as? IFloatingActionButtonFragment + val fragment = run { + if (pagerAdapter.count == 0) return@run null + val position = mainPager.currentItem + val f = pagerAdapter.instantiateItem(mainPager, position) as? IFloatingActionButtonFragment + if (f is Fragment && (f.isDetached || f.host == null)) { + return@run null + } + return@run f + } val info = fragment?.getActionInfo("home") ?: run { actionsButton.setImageResource(R.drawable.ic_action_status_compose) actionsButton.contentDescription = getString(R.string.action_compose) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt index c0e8e71d7..28d28ba2c 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/MessagesConversationAdapter.kt @@ -164,7 +164,11 @@ class MessagesConversationAdapter(context: Context) : LoadMoreSupportAdapter { + val message = adapter.getMessage(menuInfo.position) ?: return + val conversation = adapter.conversation + menu.setHeaderTitle(message.getSummaryText(context, userColorNameManager, conversation, + preferences[nameFirstKey])) + activity.menuInflater.inflate(R.menu.menu_conversation_message_item, menu) + } + R.id.attachedMediaPreview -> { + menu.setHeaderTitle(R.string.edit_media) + activity.menuInflater.inflate(R.menu.menu_attached_media_edit, menu) + } } } override fun onContextItemSelected(item: MenuItem): Boolean { - val menuInfo = item.menuInfo - if (menuInfo is ExtendedRecyclerView.ContextMenuInfo) { - when (menuInfo.recyclerViewId) { - R.id.attachedMediaPreview -> { - val position = menuInfo.position - val altText = mediaPreviewAdapter.getItem(position).alt_text - executeAfterFragmentResumed { fragment -> - EditAltTextDialogFragment.show(fragment.childFragmentManager, position, - altText) + val menuInfo = item.menuInfo as? ExtendedRecyclerView.ContextMenuInfo ?: run { + return super.onContextItemSelected(item) + } + when (menuInfo.recyclerViewId) { + R.id.recyclerView -> { + val message = adapter.getMessage(menuInfo.position) ?: return true + when (item.itemId) { + R.id.copy -> { + ClipboardUtils.setText(context, message.text_unescaped) + } + R.id.delete -> { + val task = DestroyMessageTask(context, message.account_key, + message.conversation_id, message.id) + TaskStarter.execute(task) } - return true } + return true + } + R.id.attachedMediaPreview -> { + when (item.itemId) { + R.id.edit_description -> { + val position = menuInfo.position + val altText = mediaPreviewAdapter.getItem(position).alt_text + executeAfterFragmentResumed { fragment -> + EditAltTextDialogFragment.show(fragment.childFragmentManager, position, + altText) + } + } + } + return true } } return super.onContextItemSelected(item) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesEntriesFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesEntriesFragment.kt index 63264c984..e886bfa86 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesEntriesFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesEntriesFragment.kt @@ -47,7 +47,7 @@ import org.mariotaku.twidere.model.ParcelableMessageConversationCursorIndices import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.event.GetMessagesTaskEvent import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations -import org.mariotaku.twidere.task.GetMessagesTask +import org.mariotaku.twidere.task.twitter.message.GetMessagesTask import org.mariotaku.twidere.util.DataStoreUtils import org.mariotaku.twidere.util.ErrorInfoStore import org.mariotaku.twidere.util.IntentUtils diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt index 7c9e51d0f..a9549ab12 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt @@ -62,7 +62,7 @@ import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils import org.mariotaku.twidere.provider.TwidereDataStore.Drafts import org.mariotaku.twidere.task.CreateFavoriteTask import org.mariotaku.twidere.task.RetweetStatusTask -import org.mariotaku.twidere.task.message.SendMessageTask +import org.mariotaku.twidere.task.twitter.message.SendMessageTask import org.mariotaku.twidere.task.twitter.UpdateStatusTask import org.mariotaku.twidere.util.NotificationManagerWrapper import org.mariotaku.twidere.util.Utils diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetTrendsTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetTrendsTask.kt deleted file mode 100644 index 8603cdd48..000000000 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetTrendsTask.kt +++ /dev/null @@ -1,83 +0,0 @@ -package org.mariotaku.twidere.task - -import android.accounts.AccountManager -import android.content.ContentResolver -import android.content.ContentValues -import android.content.Context -import android.net.Uri -import android.support.v4.util.ArraySet -import org.mariotaku.microblog.library.MicroBlog -import org.mariotaku.microblog.library.MicroBlogException -import org.mariotaku.microblog.library.twitter.model.Trends -import org.mariotaku.sqliteqb.library.Expression -import org.mariotaku.twidere.TwidereConstants.LOGTAG -import org.mariotaku.twidere.annotation.AccountType -import org.mariotaku.twidere.extension.model.newMicroBlogInstance -import org.mariotaku.twidere.model.ParcelableTrend -import org.mariotaku.twidere.model.ParcelableTrendValuesCreator -import org.mariotaku.twidere.model.UserKey -import org.mariotaku.twidere.model.event.TrendsRefreshedEvent -import org.mariotaku.twidere.model.util.AccountUtils -import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags -import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends -import org.mariotaku.twidere.util.DebugLog -import org.mariotaku.twidere.util.content.ContentResolverUtils -import java.util.* - -/** - * Created by mariotaku on 16/2/24. - */ -class GetTrendsTask( - context: Context, - private val accountKey: UserKey, - private val woeId: Int -) : BaseAbstractTask(context) { - - override fun doLongOperation(param: Any?) { - val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true) ?: return - val twitter = details.newMicroBlogInstance(context, cls = MicroBlog::class.java) - try { - val trends = when { - details.type == AccountType.FANFOU -> twitter.fanfouTrends - else -> twitter.getLocationTrends(woeId).firstOrNull() - } ?: return - storeTrends(context.contentResolver, CachedTrends.Local.CONTENT_URI, trends) - } catch (e: MicroBlogException) { - DebugLog.w(LOGTAG, tr = e) - } - } - - override fun afterExecute(handler: Any?, result: Unit) { - bus.post(TrendsRefreshedEvent()) - } - - private fun storeTrends(cr: ContentResolver, uri: Uri, trends: Trends) { - val hashtags = ArraySet() - val deleteWhere = Expression.and(Expression.equalsArgs(CachedTrends.ACCOUNT_KEY), - Expression.equalsArgs(CachedTrends.WOEID)).sql - val deleteWhereArgs = arrayOf(accountKey.toString(), woeId.toString()) - cr.delete(CachedTrends.Local.CONTENT_URI, deleteWhere, deleteWhereArgs) - - val allTrends = ArrayList() - - trends.trends.forEachIndexed { idx, trend -> - val hashtag = trend.name.replaceFirst("#", "") - hashtags.add(hashtag) - allTrends.add(ParcelableTrend().apply { - this.account_key = accountKey - this.woe_id = woeId - this.name = trend.name - this.timestamp = System.currentTimeMillis() - this.trend_order = idx - }) - } - ContentResolverUtils.bulkInsert(cr, uri, allTrends.map(ParcelableTrendValuesCreator::create)) - ContentResolverUtils.bulkDelete(cr, CachedHashtags.CONTENT_URI, CachedHashtags.NAME, false, - hashtags, null, null) - ContentResolverUtils.bulkInsert(cr, CachedHashtags.CONTENT_URI, hashtags.map { - val values = ContentValues() - values.put(CachedHashtags.NAME, it) - return@map values - }) - } -} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetActivitiesAboutMeTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesAboutMeTask.kt similarity index 74% rename from twidere/src/main/kotlin/org/mariotaku/twidere/task/GetActivitiesAboutMeTask.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesAboutMeTask.kt index 2b4e3f3c1..9a91438d5 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetActivitiesAboutMeTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesAboutMeTask.kt @@ -1,4 +1,23 @@ -package org.mariotaku.twidere.task +/* + * 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 import android.content.Context import android.net.Uri diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetHomeTimelineTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetHomeTimelineTask.kt similarity index 57% rename from twidere/src/main/kotlin/org/mariotaku/twidere/task/GetHomeTimelineTask.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetHomeTimelineTask.kt index 655c413e2..3188ef67e 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetHomeTimelineTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetHomeTimelineTask.kt @@ -1,4 +1,23 @@ -package org.mariotaku.twidere.task +/* + * 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 import android.content.Context import android.net.Uri diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetSavedSearchesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetSavedSearchesTask.kt similarity index 66% rename from twidere/src/main/kotlin/org/mariotaku/twidere/task/GetSavedSearchesTask.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetSavedSearchesTask.kt index 8475cd454..daf2921a4 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetSavedSearchesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetSavedSearchesTask.kt @@ -1,4 +1,23 @@ -package org.mariotaku.twidere.task +/* + * 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 import android.content.Context import org.mariotaku.abstask.library.AbstractTask diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetTrendsTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetTrendsTask.kt new file mode 100644 index 000000000..a00701f6d --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetTrendsTask.kt @@ -0,0 +1,102 @@ +/* + * 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 + +import android.accounts.AccountManager +import android.content.ContentResolver +import android.content.ContentValues +import android.content.Context +import android.net.Uri +import android.support.v4.util.ArraySet +import org.mariotaku.microblog.library.MicroBlog +import org.mariotaku.microblog.library.MicroBlogException +import org.mariotaku.microblog.library.twitter.model.Trends +import org.mariotaku.sqliteqb.library.Expression +import org.mariotaku.twidere.TwidereConstants.LOGTAG +import org.mariotaku.twidere.annotation.AccountType +import org.mariotaku.twidere.extension.model.newMicroBlogInstance +import org.mariotaku.twidere.model.ParcelableTrend +import org.mariotaku.twidere.model.ParcelableTrendValuesCreator +import org.mariotaku.twidere.model.UserKey +import org.mariotaku.twidere.model.event.TrendsRefreshedEvent +import org.mariotaku.twidere.model.util.AccountUtils +import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags +import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends +import org.mariotaku.twidere.util.DebugLog +import org.mariotaku.twidere.util.content.ContentResolverUtils +import java.util.* + +/** + * Created by mariotaku on 16/2/24. + */ +class GetTrendsTask( + context: android.content.Context, + private val accountKey: org.mariotaku.twidere.model.UserKey, + private val woeId: Int +) : org.mariotaku.twidere.task.BaseAbstractTask(context) { + + override fun doLongOperation(param: Any?) { + val details = org.mariotaku.twidere.model.util.AccountUtils.getAccountDetails(android.accounts.AccountManager.get(context), accountKey, true) ?: return + val twitter = details.newMicroBlogInstance(context, cls = org.mariotaku.microblog.library.MicroBlog::class.java) + try { + val trends = when { + details.type == org.mariotaku.twidere.annotation.AccountType.FANFOU -> twitter.fanfouTrends + else -> twitter.getLocationTrends(woeId).firstOrNull() + } ?: return + storeTrends(context.contentResolver, org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends.Local.CONTENT_URI, trends) + } catch (e: org.mariotaku.microblog.library.MicroBlogException) { + org.mariotaku.twidere.util.DebugLog.w(LOGTAG, tr = e) + } + } + + override fun afterExecute(handler: Any?, result: Unit) { + bus.post(org.mariotaku.twidere.model.event.TrendsRefreshedEvent()) + } + + private fun storeTrends(cr: android.content.ContentResolver, uri: android.net.Uri, trends: org.mariotaku.microblog.library.twitter.model.Trends) { + val hashtags = android.support.v4.util.ArraySet() + val deleteWhere = org.mariotaku.sqliteqb.library.Expression.and(org.mariotaku.sqliteqb.library.Expression.equalsArgs(org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends.ACCOUNT_KEY), + org.mariotaku.sqliteqb.library.Expression.equalsArgs(org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends.WOEID)).sql + val deleteWhereArgs = arrayOf(accountKey.toString(), woeId.toString()) + cr.delete(org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends.Local.CONTENT_URI, deleteWhere, deleteWhereArgs) + + val allTrends = java.util.ArrayList() + + trends.trends.forEachIndexed { idx, trend -> + val hashtag = trend.name.replaceFirst("#", "") + hashtags.add(hashtag) + allTrends.add(org.mariotaku.twidere.model.ParcelableTrend().apply { + this.account_key = accountKey + this.woe_id = woeId + this.name = trend.name + this.timestamp = System.currentTimeMillis() + this.trend_order = idx + }) + } + org.mariotaku.twidere.util.content.ContentResolverUtils.bulkInsert(cr, uri, allTrends.map(org.mariotaku.twidere.model.ParcelableTrendValuesCreator::create)) + ContentResolverUtils.bulkDelete(cr, CachedHashtags.CONTENT_URI, CachedHashtags.NAME, false, + hashtags, null, null) + ContentResolverUtils.bulkInsert(cr, CachedHashtags.CONTENT_URI, hashtags.map { + val values = ContentValues() + values.put(CachedHashtags.NAME, it) + return@map values + }) + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/message/DestroyConversationTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/DestroyConversationTask.kt similarity index 96% rename from twidere/src/main/kotlin/org/mariotaku/twidere/task/message/DestroyConversationTask.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/DestroyConversationTask.kt index 393a5960b..a5b48d0bd 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/message/DestroyConversationTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/DestroyConversationTask.kt @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package org.mariotaku.twidere.task.message +package org.mariotaku.twidere.task.twitter.message import android.content.Context import org.mariotaku.microblog.library.MicroBlogException diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/DestroyMessageTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/DestroyMessageTask.kt new file mode 100644 index 000000000..aee1c0d0f --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/DestroyMessageTask.kt @@ -0,0 +1,82 @@ +/* + * 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.sqliteqb.library.Expression +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.provider.TwidereDataStore.Messages +import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask + +/** + * Created by mariotaku on 2017/2/16. + */ + +class DestroyMessageTask( + context: Context, + val accountKey: UserKey, + val conversationId: String?, + val messageId: String +) : ExceptionHandlingAbstractTask(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) + if (!performDestroyMessage(microBlog, account)) { + return false + } + val deleteWhere: String + val deleteWhereArgs: Array + if (conversationId != null) { + deleteWhere = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY), + Expression.equalsArgs(Messages.CONVERSATION_ID), + Expression.equalsArgs(Messages.MESSAGE_ID)).sql + deleteWhereArgs = arrayOf(accountKey.toString(), conversationId, messageId) + } else { + deleteWhere = Expression.and(Expression.equalsArgs(Messages.ACCOUNT_KEY), + Expression.equalsArgs(Messages.MESSAGE_ID)).sql + deleteWhereArgs = arrayOf(accountKey.toString(), messageId) + } + context.contentResolver.delete(Messages.CONTENT_URI, deleteWhere, deleteWhereArgs) + return true + } + + private fun performDestroyMessage(microBlog: MicroBlog, account: AccountDetails): Boolean { + when (account.type) { + AccountType.TWITTER -> { + if (account.isOfficial(context)) { + return microBlog.destroyDm(messageId).isSuccessful + } + } + } + microBlog.destroyDirectMessage(messageId) + return true + } + + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/message/SendMessageTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SendMessageTask.kt similarity index 96% rename from twidere/src/main/kotlin/org/mariotaku/twidere/task/message/SendMessageTask.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SendMessageTask.kt index c61be117b..23b6109a1 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/message/SendMessageTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/SendMessageTask.kt @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package org.mariotaku.twidere.task.message +package org.mariotaku.twidere.task.twitter.message import android.content.Context import org.mariotaku.ktextension.isNotNullOrEmpty @@ -38,9 +38,9 @@ import org.mariotaku.twidere.model.event.SendMessageTaskEvent import org.mariotaku.twidere.model.util.ParcelableMessageUtils import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations import org.mariotaku.twidere.task.ExceptionHandlingAbstractTask -import org.mariotaku.twidere.task.GetMessagesTask -import org.mariotaku.twidere.task.GetMessagesTask.Companion.addConversation -import org.mariotaku.twidere.task.GetMessagesTask.Companion.addLocalConversations +import org.mariotaku.twidere.task.twitter.message.GetMessagesTask +import org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.addConversation +import org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.addLocalConversations import org.mariotaku.twidere.task.twitter.UpdateStatusTask /** diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetMessagesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/temp2.kt similarity index 61% rename from twidere/src/main/kotlin/org/mariotaku/twidere/task/GetMessagesTask.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/temp2.kt index 4df5c94a8..4ca8f41e8 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/GetMessagesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/message/temp2.kt @@ -1,35 +1,45 @@ -package org.mariotaku.twidere.task +/* + * 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.annotation.SuppressLint import android.content.ContentValues import android.content.Context import org.mariotaku.ktextension.toInt import org.mariotaku.ktextension.useCursor -import org.mariotaku.microblog.library.MicroBlog -import org.mariotaku.microblog.library.MicroBlogException import org.mariotaku.microblog.library.twitter.model.DMResponse -import org.mariotaku.microblog.library.twitter.model.Paging import org.mariotaku.microblog.library.twitter.model.User import org.mariotaku.microblog.library.twitter.model.fixMedia import org.mariotaku.sqliteqb.library.Expression -import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.extension.model.applyFrom import org.mariotaku.twidere.extension.model.isOfficial import org.mariotaku.twidere.extension.model.newMicroBlogInstance 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.TwitterOfficialConversationExtras -import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.model.util.AccountUtils.getAccountDetails -import org.mariotaku.twidere.model.util.ParcelableMessageUtils import org.mariotaku.twidere.model.util.ParcelableUserUtils import org.mariotaku.twidere.model.util.UserKeyUtils import org.mariotaku.twidere.provider.TwidereDataStore.Messages import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations -import org.mariotaku.twidere.util.DataStoreUtils import org.mariotaku.twidere.util.content.ContentResolverUtils import java.util.* @@ -38,35 +48,35 @@ import java.util.* */ class GetMessagesTask( - context: Context -) : BaseAbstractTask Unit>(context) { - override fun doLongOperation(param: RefreshMessagesTaskParam) { + context: android.content.Context +) : org.mariotaku.twidere.task.BaseAbstractTask Unit>(context) { + override fun doLongOperation(param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam) { val accountKeys = param.accountKeys - val am = AccountManager.get(context) + val am = android.accounts.AccountManager.get(context) accountKeys.forEachIndexed { i, accountKey -> val details = getAccountDetails(am, accountKey, true) ?: return@forEachIndexed - val microBlog = details.newMicroBlogInstance(context, true, cls = MicroBlog::class.java) + val microBlog = details.newMicroBlogInstance(context, true, cls = org.mariotaku.microblog.library.MicroBlog::class.java) val messages = try { getMessages(microBlog, details, param, i) - } catch (e: MicroBlogException) { + } catch (e: org.mariotaku.microblog.library.MicroBlogException) { return@forEachIndexed } - storeMessages(context, messages, details) + org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.storeMessages(context, messages, details) } } override fun afterExecute(callback: ((Boolean) -> Unit)?, result: Unit) { callback?.invoke(true) - bus.post(GetMessagesTaskEvent(Messages.CONTENT_URI, params?.taskTag, false, null)) + bus.post(org.mariotaku.twidere.model.event.GetMessagesTaskEvent(org.mariotaku.twidere.provider.TwidereDataStore.Messages.CONTENT_URI, params?.taskTag, false, null)) } - private fun getMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { + private fun getMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: org.mariotaku.twidere.model.AccountDetails, param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam, index: Int): org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { when (details.type) { - AccountType.FANFOU -> { + org.mariotaku.twidere.annotation.AccountType.FANFOU -> { // Use fanfou DM api, disabled since it's conversation api is not suitable for paging // return getFanfouMessages(microBlog, details, param, index) } - AccountType.TWITTER -> { + org.mariotaku.twidere.annotation.AccountType.TWITTER -> { // Use official DM api if (details.isOfficial(context)) { return getTwitterOfficialMessages(microBlog, details, param, index) @@ -77,8 +87,8 @@ class GetMessagesTask( return getDefaultMessages(microBlog, details, param, index) } - private fun getTwitterOfficialMessages(microBlog: MicroBlog, details: AccountDetails, - param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { + private fun getTwitterOfficialMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: org.mariotaku.twidere.model.AccountDetails, + param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam, index: Int): org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { val conversationId = param.conversationId if (conversationId == null) { return getTwitterOfficialUserInbox(microBlog, details, param, index) @@ -87,22 +97,22 @@ class GetMessagesTask( } } - private fun getFanfouMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { + private fun getFanfouMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: org.mariotaku.twidere.model.AccountDetails, param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam, index: Int): org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { val conversationId = param.conversationId if (conversationId == null) { return getFanfouConversations(microBlog, details, param, index) } else { - return DatabaseUpdateData(emptyList(), emptyList()) + return org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData(emptyList(), emptyList()) } } - private fun getDefaultMessages(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { + private fun getDefaultMessages(microBlog: org.mariotaku.microblog.library.MicroBlog, details: org.mariotaku.twidere.model.AccountDetails, param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam, index: Int): org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { val accountKey = details.key val sinceIds = if (param.hasSinceIds) param.sinceIds else null val maxIds = if (param.hasMaxIds) param.maxIds else null - val received = microBlog.getDirectMessages(Paging().apply { + val received = microBlog.getDirectMessages(org.mariotaku.microblog.library.twitter.model.Paging().apply { count(100) val maxId = maxIds?.get(index) val sinceId = sinceIds?.get(index) @@ -113,7 +123,7 @@ class GetMessagesTask( sinceId(sinceId) } }) - val sent = microBlog.getSentDirectMessages(Paging().apply { + val sent = microBlog.getSentDirectMessages(org.mariotaku.microblog.library.twitter.model.Paging().apply { count(100) val accountsCount = param.accountKeys.size val maxId = maxIds?.get(accountsCount + index) @@ -127,75 +137,75 @@ class GetMessagesTask( }) - val insertMessages = arrayListOf() - val conversations = hashMapOf() + val insertMessages = arrayListOf() + val conversations = hashMapOf() val conversationIds = hashSetOf() received.forEach { - conversationIds.add(ParcelableMessageUtils.incomingConversationId(it.senderId, it.recipientId)) + conversationIds.add(org.mariotaku.twidere.model.util.ParcelableMessageUtils.incomingConversationId(it.senderId, it.recipientId)) } sent.forEach { - conversationIds.add(ParcelableMessageUtils.outgoingConversationId(it.senderId, it.recipientId)) + conversationIds.add(org.mariotaku.twidere.model.util.ParcelableMessageUtils.outgoingConversationId(it.senderId, it.recipientId)) } conversations.addLocalConversations(context, accountKey, conversationIds) received.forEachIndexed { i, dm -> - val message = ParcelableMessageUtils.fromMessage(accountKey, dm, false, + val message = org.mariotaku.twidere.model.util.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)) } sent.forEachIndexed { i, dm -> - val message = ParcelableMessageUtils.fromMessage(accountKey, dm, true, + val message = org.mariotaku.twidere.model.util.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)) } - return DatabaseUpdateData(conversations.values, insertMessages) + return org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData(conversations.values, insertMessages) } - private fun getTwitterOfficialConversation(microBlog: MicroBlog, details: AccountDetails, - conversationId: String, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { - val maxId = param.maxIds?.get(index) ?: return DatabaseUpdateData(emptyList(), emptyList()) - val paging = Paging().apply { + private fun getTwitterOfficialConversation(microBlog: org.mariotaku.microblog.library.MicroBlog, details: org.mariotaku.twidere.model.AccountDetails, + conversationId: String, param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam, index: Int): org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { + val maxId = param.maxIds?.get(index) ?: return org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData(emptyList(), emptyList()) + val paging = org.mariotaku.microblog.library.twitter.model.Paging().apply { maxId(maxId) } val response = microBlog.getDmConversation(conversationId, paging).conversationTimeline response.fixMedia(microBlog) - return createDatabaseUpdateData(context, details, response) + return org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.createDatabaseUpdateData(context, details, response) } - private fun getTwitterOfficialUserInbox(microBlog: MicroBlog, details: AccountDetails, - param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { + private fun getTwitterOfficialUserInbox(microBlog: org.mariotaku.microblog.library.MicroBlog, details: org.mariotaku.twidere.model.AccountDetails, + param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam, index: Int): org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { val maxId = if (param.hasMaxIds) param.maxIds?.get(index) else null val cursor = if (param.hasCursors) param.cursors?.get(index) else null val response = if (cursor != null) { microBlog.getUserUpdates(cursor).userEvents } else { - microBlog.getUserInbox(Paging().apply { + microBlog.getUserInbox(org.mariotaku.microblog.library.twitter.model.Paging().apply { if (maxId != null) { maxId(maxId) } }).userInbox } response.fixMedia(microBlog) - return createDatabaseUpdateData(context, details, response) + return org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.createDatabaseUpdateData(context, details, response) } - private fun getFanfouConversations(microBlog: MicroBlog, details: AccountDetails, param: RefreshMessagesTaskParam, index: Int): DatabaseUpdateData { + private fun getFanfouConversations(microBlog: org.mariotaku.microblog.library.MicroBlog, details: org.mariotaku.twidere.model.AccountDetails, param: org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam, index: Int): org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { val accountKey = details.key val cursor = param.cursors?.get(index) val page = cursor?.substringAfter("page:").toInt(-1) - val result = microBlog.getConversationList(Paging().apply { + val result = microBlog.getConversationList(org.mariotaku.microblog.library.twitter.model.Paging().apply { count(60) if (page >= 0) { page(page) } }) - val conversations = hashMapOf() + val conversations = hashMapOf() val conversationIds = hashSetOf() result.mapTo(conversationIds) { "${accountKey.id}-${it.otherId}" } @@ -203,32 +213,32 @@ class GetMessagesTask( result.forEachIndexed { i, item -> val dm = item.dm // Sender is our self, treat as outgoing message - val message = ParcelableMessageUtils.fromMessage(accountKey, dm, dm.senderId == accountKey.id, + val message = org.mariotaku.twidere.model.util.ParcelableMessageUtils.fromMessage(accountKey, dm, dm.senderId == accountKey.id, 1.0 - (i.toDouble() / result.size)) val mc = conversations.addConversation(message.conversation_id, details, message, setOf(dm.sender, dm.recipient)) mc.request_cursor = "page:$page" } - return DatabaseUpdateData(conversations.values, emptyList()) + return org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData(conversations.values, emptyList()) } data class DatabaseUpdateData( - val conversations: Collection, - val messages: Collection, + val conversations: Collection, + val messages: Collection, val deleteConversations: List = emptyList(), val deleteMessages: Map> = emptyMap(), val conversationRequestCursor: String? = null ) abstract class RefreshNewTaskParam( - context: Context - ) : RefreshMessagesTaskParam(context) { + context: android.content.Context + ) : org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam(context) { override val sinceIds: Array? get() { - val incomingIds = DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI, + val incomingIds = org.mariotaku.twidere.util.DataStoreUtils.getNewestMessageIds(context, org.mariotaku.twidere.provider.TwidereDataStore.Messages.CONTENT_URI, defaultKeys, false) - val outgoingIds = DataStoreUtils.getNewestMessageIds(context, Messages.CONTENT_URI, + val outgoingIds = org.mariotaku.twidere.util.DataStoreUtils.getNewestMessageIds(context, org.mariotaku.twidere.provider.TwidereDataStore.Messages.CONTENT_URI, defaultKeys, true) return incomingIds + outgoingIds } @@ -236,8 +246,8 @@ class GetMessagesTask( override val cursors: Array? get() { val cursors = arrayOfNulls(defaultKeys.size) - val newestConversations = DataStoreUtils.getNewestConversations(context, - Messages.Conversations.CONTENT_URI, twitterOfficialKeys) + val newestConversations = org.mariotaku.twidere.util.DataStoreUtils.getNewestConversations(context, + org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations.CONTENT_URI, twitterOfficialKeys) newestConversations.forEachIndexed { i, conversation -> cursors[i] = conversation?.request_cursor } @@ -250,18 +260,18 @@ class GetMessagesTask( } abstract class LoadMoreEntriesTaskParam( - context: Context - ) : RefreshMessagesTaskParam(context) { + context: android.content.Context + ) : org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam(context) { override val maxIds: Array? by lazy { - val incomingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI, + val incomingIds = org.mariotaku.twidere.util.DataStoreUtils.getOldestMessageIds(context, org.mariotaku.twidere.provider.TwidereDataStore.Messages.CONTENT_URI, defaultKeys, false) - val outgoingIds = DataStoreUtils.getOldestMessageIds(context, Messages.CONTENT_URI, + val outgoingIds = org.mariotaku.twidere.util.DataStoreUtils.getOldestMessageIds(context, org.mariotaku.twidere.provider.TwidereDataStore.Messages.CONTENT_URI, defaultKeys, true) - val oldestConversations = DataStoreUtils.getOldestConversations(context, - Messages.Conversations.CONTENT_URI, twitterOfficialKeys) + val oldestConversations = org.mariotaku.twidere.util.DataStoreUtils.getOldestConversations(context, + org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations.CONTENT_URI, twitterOfficialKeys) oldestConversations.forEachIndexed { i, conversation -> - val extras = conversation?.conversation_extras as? TwitterOfficialConversationExtras ?: return@forEachIndexed + val extras = conversation?.conversation_extras as? org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras ?: return@forEachIndexed incomingIds[i] = extras.maxEntryId } return@lazy incomingIds + outgoingIds @@ -272,19 +282,19 @@ class GetMessagesTask( } class LoadMoreMessageTaskParam( - context: Context, - accountKey: UserKey, + context: android.content.Context, + accountKey: org.mariotaku.twidere.model.UserKey, override val conversationId: String, maxId: String - ) : RefreshMessagesTaskParam(context) { - override val accountKeys: Array = arrayOf(accountKey) + ) : org.mariotaku.twidere.task.twitter.message.GetMessagesTask.RefreshMessagesTaskParam(context) { + override val accountKeys: Array = arrayOf(accountKey) override val maxIds: Array? = arrayOf(maxId) override val hasMaxIds: Boolean = true } abstract class RefreshMessagesTaskParam( - val context: Context - ) : SimpleRefreshTaskParam() { + val context: android.content.Context + ) : org.mariotaku.twidere.model.SimpleRefreshTaskParam() { /** * If `conversationId` has value, load messages in conversationId @@ -293,21 +303,21 @@ class GetMessagesTask( var taskTag: String? = null - protected val accounts: Array by lazy { - AccountUtils.getAllAccountDetails(AccountManager.get(context), accountKeys, false) + protected val accounts: Array by lazy { + org.mariotaku.twidere.model.util.AccountUtils.getAllAccountDetails(android.accounts.AccountManager.get(context), accountKeys, false) } - protected val defaultKeys: Arrayby lazy { + protected val defaultKeys: Arrayby lazy { return@lazy accounts.map { account -> account ?: return@map null - if (account.isOfficial(context) || account.type == AccountType.FANFOU) { + if (account.isOfficial(context) || account.type == org.mariotaku.twidere.annotation.AccountType.FANFOU) { return@map null } return@map account.key }.toTypedArray() } - protected val twitterOfficialKeys: Array by lazy { + protected val twitterOfficialKeys: Array by lazy { return@lazy accounts.map { account -> account ?: return@map null if (!account.isOfficial(context)) { @@ -321,22 +331,22 @@ class GetMessagesTask( companion object { - fun createDatabaseUpdateData(context: Context, account: AccountDetails, response: DMResponse): - DatabaseUpdateData { + fun createDatabaseUpdateData(context: android.content.Context, account: org.mariotaku.twidere.model.AccountDetails, response: org.mariotaku.microblog.library.twitter.model.DMResponse): + org.mariotaku.twidere.task.twitter.message.GetMessagesTask.DatabaseUpdateData { val respConversations = response.conversations.orEmpty() val respEntries = response.entries.orEmpty() val respUsers = response.users.orEmpty() - val conversations = hashMapOf() + val conversations = hashMapOf() conversations.addLocalConversations(context, account.key, respConversations.keys) - val messages = ArrayList() - val messageDeletionsMap = HashMap>() - val conversationDeletions = ArrayList() + val messages = java.util.ArrayList() + val messageDeletionsMap = java.util.HashMap>() + val conversationDeletions = java.util.ArrayList() respEntries.mapNotNullTo(messages) { entry -> when { entry.messageDelete != null -> { - val list = messageDeletionsMap.getOrPut(entry.messageDelete.conversationId) { ArrayList() } + val list = messageDeletionsMap.getOrPut(entry.messageDelete.conversationId) { java.util.ArrayList() } entry.messageDelete.messages?.forEach { list.add(it.messageId) } @@ -347,11 +357,11 @@ class GetMessagesTask( return@mapNotNullTo null } else -> { - return@mapNotNullTo ParcelableMessageUtils.fromEntry(account.key, entry, respUsers) + return@mapNotNullTo org.mariotaku.twidere.model.util.ParcelableMessageUtils.fromEntry(account.key, entry, respUsers) } } } - val messagesMap = messages.groupBy(ParcelableMessage::conversation_id) + val messagesMap = messages.groupBy(org.mariotaku.twidere.model.ParcelableMessage::conversation_id) for ((k, v) in respConversations) { val message = messagesMap[k]?.maxBy(ParcelableMessage::message_timestamp) ?: continue val participants = respUsers.filterKeys { userId -> diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt index 391d66632..dfaee02c4 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/AsyncTwitterWrapper.kt @@ -45,6 +45,11 @@ import org.mariotaku.twidere.model.event.* import org.mariotaku.twidere.model.util.ParcelableUserListUtils import org.mariotaku.twidere.provider.TwidereDataStore.* import org.mariotaku.twidere.task.* +import org.mariotaku.twidere.task.twitter.GetActivitiesAboutMeTask +import org.mariotaku.twidere.task.twitter.GetHomeTimelineTask +import org.mariotaku.twidere.task.twitter.GetSavedSearchesTask +import org.mariotaku.twidere.task.twitter.GetTrendsTask +import org.mariotaku.twidere.task.twitter.message.GetMessagesTask import org.mariotaku.twidere.util.collection.CompactHashSet import java.util.* diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/TaskServiceRunner.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/TaskServiceRunner.kt index 922c20a4b..28eb53bee 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/TaskServiceRunner.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/TaskServiceRunner.kt @@ -15,9 +15,9 @@ import org.mariotaku.twidere.model.SimpleRefreshTaskParam import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.provider.TwidereDataStore.Activities import org.mariotaku.twidere.provider.TwidereDataStore.Statuses -import org.mariotaku.twidere.task.GetActivitiesAboutMeTask -import org.mariotaku.twidere.task.GetHomeTimelineTask -import org.mariotaku.twidere.task.GetMessagesTask +import org.mariotaku.twidere.task.twitter.GetActivitiesAboutMeTask +import org.mariotaku.twidere.task.twitter.GetHomeTimelineTask +import org.mariotaku.twidere.task.twitter.message.GetMessagesTask import org.mariotaku.twidere.task.filter.RefreshFiltersSubscriptionsTask /** diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageViewHolder.kt index 7a4e3406d..e3371b7d4 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageViewHolder.kt @@ -53,6 +53,11 @@ class MessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) : val textSize = adapter.textSize text.textSize = textSize mediaPreview.style = adapter.mediaPreviewStyle + + messageBubble.setOnLongClickListener { + val listener = adapter.listener ?: return@setOnLongClickListener false + return@setOnLongClickListener listener.onMessageLongClick(layoutPosition, this) + } } override fun display(message: ParcelableMessage, showDate: Boolean) { diff --git a/twidere/src/main/res/menu/menu_conversation_message_item.xml b/twidere/src/main/res/menu/menu_conversation_message_item.xml new file mode 100644 index 000000000..653d00cf3 --- /dev/null +++ b/twidere/src/main/res/menu/menu_conversation_message_item.xml @@ -0,0 +1,28 @@ + + + + + + + \ No newline at end of file