mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-09 08:18:44 +01:00
migrating to kotlin
This commit is contained in:
parent
c1326955a7
commit
d8608d8cbf
@ -164,7 +164,7 @@ dependencies {
|
||||
compile 'com.github.mariotaku.SQLiteQB:library:0.9.6'
|
||||
compile 'com.github.mariotaku.ObjectCursor:core:0.9.9'
|
||||
compile 'com.github.mariotaku:MultiValueSwitch:0.9.6'
|
||||
compile 'com.github.mariotaku:AbstractTask:0.9.2'
|
||||
compile 'com.github.mariotaku:AbstractTask:0.9.3'
|
||||
compile 'com.github.mariotaku.CommonsLibrary:parcel:0.9.8'
|
||||
compile 'com.github.mariotaku.CommonsLibrary:io:0.9.8'
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
|
@ -171,13 +171,13 @@ public final class MediaViewerActivity extends BaseActivity implements IExtended
|
||||
CacheDownloadMediaViewerFragment f = (CacheDownloadMediaViewerFragment) object;
|
||||
final boolean running = f.getLoaderManager().hasRunningLoaders();
|
||||
final boolean downloaded = f.hasDownloadedData();
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.refresh, !running && !downloaded);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.share, !running && downloaded);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.save, !running && downloaded);
|
||||
MenuUtils.INSTANCE.setItemAvailability(menu, R.id.refresh, !running && !downloaded);
|
||||
MenuUtils.INSTANCE.setItemAvailability(menu, R.id.share, !running && downloaded);
|
||||
MenuUtils.INSTANCE.setItemAvailability(menu, R.id.save, !running && downloaded);
|
||||
} else {
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.refresh, false);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.share, true);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.save, false);
|
||||
MenuUtils.INSTANCE.setItemAvailability(menu, R.id.refresh, false);
|
||||
MenuUtils.INSTANCE.setItemAvailability(menu, R.id.share, true);
|
||||
MenuUtils.INSTANCE.setItemAvailability(menu, R.id.save, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.annotation.Referral
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NEW_DOCUMENT_API
|
||||
import org.mariotaku.twidere.fragment.CursorActivitiesFragment
|
||||
import org.mariotaku.twidere.fragment.UserFragment
|
||||
import org.mariotaku.twidere.model.ParcelableActivity
|
||||
import org.mariotaku.twidere.model.ParcelableActivityCursorIndices
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
@ -55,7 +54,10 @@ import java.lang.ref.WeakReference
|
||||
/**
|
||||
* Created by mariotaku on 15/1/3.
|
||||
*/
|
||||
class ParcelableActivitiesAdapter(context: Context, private val mIsByFriends: Boolean) : LoadMoreSupportAdapter<RecyclerView.ViewHolder>(context), IActivitiesAdapter<List<ParcelableActivity>> {
|
||||
class ParcelableActivitiesAdapter(
|
||||
context: Context,
|
||||
private val byFriends: Boolean
|
||||
) : LoadMoreSupportAdapter<RecyclerView.ViewHolder>(context), IActivitiesAdapter<List<ParcelableActivity>> {
|
||||
|
||||
private val inflater: LayoutInflater
|
||||
override val mediaLoadingHandler: MediaLoadingHandler
|
||||
@ -155,7 +157,7 @@ class ParcelableActivitiesAdapter(context: Context, private val mIsByFriends: Bo
|
||||
}
|
||||
|
||||
protected fun bindTitleSummaryViewHolder(holder: ActivityTitleSummaryViewHolder, position: Int) {
|
||||
holder.displayActivity(getActivity(position)!!, mIsByFriends)
|
||||
holder.displayActivity(getActivity(position)!!, byFriends)
|
||||
}
|
||||
|
||||
fun getData(): List<ParcelableActivity>? {
|
||||
|
@ -44,6 +44,9 @@ import org.mariotaku.twidere.Constants.*
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants
|
||||
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter
|
||||
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter.Companion.ITEM_VIEW_TYPE_GAP
|
||||
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter.Companion.ITEM_VIEW_TYPE_STATUS
|
||||
import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter.Companion.ITEM_VIEW_TYPE_TITLE_SUMMARY
|
||||
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration
|
||||
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
|
||||
import org.mariotaku.twidere.annotation.ReadPositionTag
|
||||
@ -361,7 +364,7 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
|
||||
if (activity == null) return
|
||||
val lm = layoutManager ?: return
|
||||
val view = lm.findViewByPosition(position) ?: return
|
||||
if (lm.getItemViewType(view) != ParcelableActivitiesAdapter.ITEM_VIEW_TYPE_STATUS) {
|
||||
if (lm.getItemViewType(view) != ITEM_VIEW_TYPE_STATUS) {
|
||||
return
|
||||
}
|
||||
recyclerView.showContextMenuForChild(view)
|
||||
@ -397,7 +400,7 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
|
||||
}
|
||||
}
|
||||
}
|
||||
task.setResultHandler(recyclerView)
|
||||
task.setCallback(recyclerView)
|
||||
TaskStarter.execute(task)
|
||||
bus.register(mStatusesBusCallback)
|
||||
}
|
||||
@ -519,7 +522,7 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
|
||||
val contextMenuInfo = menuInfo as ExtendedRecyclerView.ContextMenuInfo?
|
||||
val position = contextMenuInfo!!.position
|
||||
when (adapter!!.getItemViewType(position)) {
|
||||
ParcelableActivitiesAdapter.ITEM_VIEW_TYPE_STATUS -> {
|
||||
ITEM_VIEW_TYPE_STATUS -> {
|
||||
val status = getActivityStatus(position) ?: return
|
||||
inflater.inflate(R.menu.action_status, menu)
|
||||
MenuUtils.setupForStatus(context, preferences, menu, status,
|
||||
@ -535,7 +538,7 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
|
||||
val position = contextMenuInfo.position
|
||||
|
||||
when (adapter!!.getItemViewType(position)) {
|
||||
ParcelableActivitiesAdapter.ITEM_VIEW_TYPE_STATUS -> {
|
||||
ITEM_VIEW_TYPE_STATUS -> {
|
||||
val status = getActivityStatus(position) ?: return false
|
||||
if (item.itemId == R.id.share) {
|
||||
val shareIntent = Utils.createStatusShareIntent(activity, status)
|
||||
@ -552,20 +555,32 @@ abstract class AbsActivitiesFragment protected constructor() : AbsContentListRec
|
||||
}
|
||||
|
||||
|
||||
override fun createItemDecoration(context: Context, recyclerView: RecyclerView, layoutManager: LinearLayoutManager): RecyclerView.ItemDecoration? {
|
||||
val adapter = adapter
|
||||
val itemDecoration = DividerItemDecoration(context,
|
||||
(recyclerView.layoutManager as LinearLayoutManager).orientation)
|
||||
override fun createItemDecoration(context: Context, recyclerView: RecyclerView,
|
||||
layoutManager: LinearLayoutManager): RecyclerView.ItemDecoration? {
|
||||
val adapter = adapter!!
|
||||
val itemDecoration = object : DividerItemDecoration(context,
|
||||
(recyclerView.layoutManager as LinearLayoutManager).orientation) {
|
||||
override fun isDividerEnabled(childPos: Int): Boolean {
|
||||
when (adapter.getItemViewType(childPos)) {
|
||||
ITEM_VIEW_TYPE_STATUS, ITEM_VIEW_TYPE_TITLE_SUMMARY, ITEM_VIEW_TYPE_GAP -> {
|
||||
return true
|
||||
}
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val res = context.resources
|
||||
if (adapter!!.profileImageEnabled) {
|
||||
if (adapter.profileImageEnabled) {
|
||||
val decorPaddingLeft = res.getDimensionPixelSize(R.dimen.element_spacing_normal) * 2 + res.getDimensionPixelSize(R.dimen.icon_size_status_profile_image)
|
||||
itemDecoration.setPadding { position, rect ->
|
||||
val itemViewType = adapter.getItemViewType(position)
|
||||
var nextItemIsStatus = false
|
||||
if (position < adapter.itemCount - 1) {
|
||||
nextItemIsStatus = adapter.getItemViewType(position + 1) == ParcelableActivitiesAdapter.ITEM_VIEW_TYPE_STATUS
|
||||
nextItemIsStatus = adapter.getItemViewType(position + 1) == ITEM_VIEW_TYPE_STATUS
|
||||
}
|
||||
if (nextItemIsStatus && itemViewType == ParcelableActivitiesAdapter.ITEM_VIEW_TYPE_STATUS) {
|
||||
if (nextItemIsStatus && itemViewType == ITEM_VIEW_TYPE_STATUS) {
|
||||
rect.left = decorPaddingLeft
|
||||
} else {
|
||||
rect.left = 0
|
||||
|
@ -410,7 +410,7 @@ abstract class AbsStatusesFragment protected constructor() : AbsContentListRecyc
|
||||
}
|
||||
}
|
||||
}
|
||||
task.setResultHandler(recyclerView)
|
||||
task.setCallback(recyclerView)
|
||||
TaskStarter.execute(task)
|
||||
bus.register(statusesBusCallback)
|
||||
}
|
||||
|
@ -1,919 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.Animator.AnimatorListener;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.view.SupportMenuInflater;
|
||||
import android.support.v7.widget.ActionMenuView;
|
||||
import android.support.v7.widget.ActionMenuView.OnMenuItemClickListener;
|
||||
import android.support.v7.widget.FixedLinearLayoutManager;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.RecyclerView.Adapter;
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ViewSwitcher;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.mariotaku.sqliteqb.library.Expression;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.activity.ComposeActivity;
|
||||
import org.mariotaku.twidere.activity.HomeActivity;
|
||||
import org.mariotaku.twidere.activity.PlusServiceDashboardActivity;
|
||||
import org.mariotaku.twidere.activity.QuickSearchBarActivity;
|
||||
import org.mariotaku.twidere.activity.SettingsActivity;
|
||||
import org.mariotaku.twidere.annotation.CustomTabType;
|
||||
import org.mariotaku.twidere.annotation.Referral;
|
||||
import org.mariotaku.twidere.menu.AccountToggleProvider;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.SupportTabSpec;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
import org.mariotaku.twidere.util.CompareUtils;
|
||||
import org.mariotaku.twidere.util.DataStoreUtils;
|
||||
import org.mariotaku.twidere.util.IntentUtils;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
|
||||
import org.mariotaku.twidere.util.MediaLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.TransitionUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver;
|
||||
import org.mariotaku.twidere.view.ShapedImageView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AccountsDashboardFragment extends BaseSupportFragment implements LoaderCallbacks<Cursor>,
|
||||
OnSharedPreferenceChangeListener, OnClickListener, KeyboardShortcutCallback,
|
||||
NavigationView.OnNavigationItemSelectedListener {
|
||||
|
||||
private final Rect mSystemWindowsInsets = new Rect();
|
||||
private ContentResolver mResolver;
|
||||
|
||||
private AccountSelectorAdapter mAccountsAdapter;
|
||||
|
||||
private NavigationView mNavigationView;
|
||||
private View mAccountSelectorView;
|
||||
private RecyclerView mAccountsSelector;
|
||||
private ViewSwitcher mAccountProfileBannerView;
|
||||
private ImageView mFloatingProfileImageSnapshotView;
|
||||
private ShapedImageView mAccountProfileImageView;
|
||||
private TextView mAccountProfileNameView, mAccountProfileScreenNameView;
|
||||
private ActionMenuView mAccountsToggleMenu;
|
||||
private View mAccountProfileContainer;
|
||||
private View mNoAccountContainer;
|
||||
|
||||
private AccountToggleProvider mAccountActionProvider;
|
||||
private final SupportFragmentReloadCursorObserver mReloadContentObserver = new SupportFragmentReloadCursorObserver(
|
||||
this, 0, this) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, @Nullable Uri uri) {
|
||||
final ContentResolver cr = getContentResolver();
|
||||
if (cr == null) return;
|
||||
final Cursor c = cr.query(Accounts.CONTENT_URI, Accounts.COLUMNS, null, null, Accounts.SORT_POSITION);
|
||||
try {
|
||||
updateAccountProviderData(c);
|
||||
} finally {
|
||||
Utils.closeSilently(c);
|
||||
}
|
||||
super.onChange(selfChange, uri);
|
||||
}
|
||||
};
|
||||
private boolean mSwitchAccountAnimationPlaying;
|
||||
private boolean mUseStarsForLikes;
|
||||
private boolean mLoaderInitialized;
|
||||
|
||||
@NonNull
|
||||
public UserKey[] getActivatedAccountIds() {
|
||||
if (mAccountActionProvider != null) {
|
||||
return mAccountActionProvider.getActivatedAccountIds();
|
||||
}
|
||||
return DataStoreUtils.getActivatedAccountKeys(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutSingle(@NonNull final KeyboardShortcutsHandler handler,
|
||||
final int keyCode, @NonNull final KeyEvent event, int metaState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeyboardShortcutHandled(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState);
|
||||
return ACTION_NAVIGATION_PREVIOUS.equals(action) || ACTION_NAVIGATION_NEXT.equals(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleKeyboardShortcutRepeat(@NonNull final KeyboardShortcutsHandler handler,
|
||||
final int keyCode, final int repeatCount,
|
||||
@NonNull final KeyEvent event, int metaState) {
|
||||
final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState);
|
||||
if (action == null) return false;
|
||||
final int offset;
|
||||
switch (action) {
|
||||
case ACTION_NAVIGATION_PREVIOUS: {
|
||||
offset = -1;
|
||||
break;
|
||||
}
|
||||
case ACTION_NAVIGATION_NEXT: {
|
||||
offset = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// final int selectedItem = mNavigationView.getSelectedItemPosition();
|
||||
// final int count = mNavigationView.getCount();
|
||||
// int resultPosition;
|
||||
// if (!mNavigationView.isFocused() || selectedItem == ListView.INVALID_POSITION) {
|
||||
// resultPosition = firstVisiblePosition;
|
||||
// } else {
|
||||
// resultPosition = selectedItem + offset;
|
||||
// while (resultPosition >= 0 && resultPosition < count && !mAdapter.isEnabled(resultPosition)) {
|
||||
// resultPosition += offset;
|
||||
// }
|
||||
// }
|
||||
// final View focusedChild = mNavigationView.getFocusedChild();
|
||||
// if (focusedChild == null) {
|
||||
// mNavigationView.requestChildFocus(mNavigationView.getChildAt(0), null);
|
||||
// }
|
||||
// if (resultPosition >= 0 && resultPosition < count) {
|
||||
// mNavigationView.setSelection(resultPosition);
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_SETTINGS: {
|
||||
if (data == null) return;
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (data.getBooleanExtra(EXTRA_CHANGED, false)) {
|
||||
activity.recreate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateDefaultAccountState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.profileContainer: {
|
||||
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
|
||||
if (account == null) return;
|
||||
final FragmentActivity activity = getActivity();
|
||||
if (account.account_user != null) {
|
||||
IntentUtils.openUserProfile(activity, account.account_user, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.SELF_PROFILE);
|
||||
} else {
|
||||
IntentUtils.openUserProfile(activity, account.account_key,
|
||||
account.account_key, account.screen_name, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.SELF_PROFILE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
||||
return new CursorLoader(getActivity(), Accounts.CONTENT_URI, Accounts.COLUMNS, null, null, Accounts.SORT_POSITION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
|
||||
updateAccountProviderData(data);
|
||||
}
|
||||
|
||||
private void updateAccountProviderData(@Nullable final Cursor cursor) {
|
||||
if (cursor == null) return;
|
||||
final Menu menu = mAccountsToggleMenu.getMenu();
|
||||
mAccountActionProvider = (AccountToggleProvider) MenuItemCompat.getActionProvider(menu.findItem(R.id.select_account));
|
||||
final ParcelableAccount[] accounts = ParcelableAccountUtils.getAccounts(cursor);
|
||||
if (accounts.length > 0) {
|
||||
mNoAccountContainer.setVisibility(View.GONE);
|
||||
mAccountProfileContainer.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mNoAccountContainer.setVisibility(View.VISIBLE);
|
||||
mAccountProfileContainer.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
UserKey defaultId = null;
|
||||
for (ParcelableAccount account : accounts) {
|
||||
if (account.is_activated) {
|
||||
defaultId = account.account_key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mUseStarsForLikes = preferences.getBoolean(KEY_I_WANT_MY_STARS_BACK);
|
||||
|
||||
mAccountsAdapter.setAccounts(accounts);
|
||||
UserKey accountKey = UserKey.valueOf(preferences.getString(KEY_DEFAULT_ACCOUNT_KEY, null));
|
||||
if (accountKey == null) {
|
||||
accountKey = defaultId;
|
||||
}
|
||||
ParcelableAccount selectedAccount = null;
|
||||
for (ParcelableAccount account : accounts) {
|
||||
if (account.account_key.maybeEquals(accountKey)) {
|
||||
selectedAccount = account;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mAccountsAdapter.setSelectedAccount(selectedAccount);
|
||||
|
||||
if (mAccountActionProvider != null) {
|
||||
mAccountActionProvider.setExclusive(false);
|
||||
mAccountActionProvider.setAccounts(accounts);
|
||||
}
|
||||
updateAccountActions();
|
||||
ParcelableAccount currentAccount = mAccountsAdapter.getSelectedAccount();
|
||||
if (currentAccount != null) {
|
||||
displayAccountBanner(currentAccount);
|
||||
displayCurrentAccount(null);
|
||||
}
|
||||
updateDefaultAccountState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(final Loader<Cursor> loader) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
|
||||
if (KEY_DEFAULT_ACCOUNT_KEY.equals(key)) {
|
||||
updateDefaultAccountState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fitSystemWindows(Rect insets) {
|
||||
mSystemWindowsInsets.set(insets);
|
||||
updateSystemWindowsInsets();
|
||||
}
|
||||
|
||||
private void updateSystemWindowsInsets() {
|
||||
if (mAccountProfileContainer == null) return;
|
||||
final Rect insets = mSystemWindowsInsets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mResolver = getContentResolver();
|
||||
final View view = getView();
|
||||
assert view != null;
|
||||
final Context context = view.getContext();
|
||||
final LayoutInflater inflater = getLayoutInflater(savedInstanceState);
|
||||
mAccountsAdapter = new AccountSelectorAdapter(inflater, this);
|
||||
final LinearLayoutManager layoutManager = new FixedLinearLayoutManager(context);
|
||||
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
|
||||
layoutManager.setStackFromEnd(true);
|
||||
mAccountsSelector.setLayoutManager(layoutManager);
|
||||
mAccountsSelector.setAdapter(mAccountsAdapter);
|
||||
mAccountsSelector.setItemAnimator(null);
|
||||
final SupportMenuInflater menuInflater = new SupportMenuInflater(context);
|
||||
menuInflater.inflate(R.menu.action_dashboard_timeline_toggle, mAccountsToggleMenu.getMenu());
|
||||
mAccountsToggleMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.getGroupId() != AccountToggleProvider.MENU_GROUP) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.compose: {
|
||||
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
|
||||
if (account == null) return true;
|
||||
final Intent composeIntent = new Intent(INTENT_ACTION_COMPOSE);
|
||||
composeIntent.setClass(getActivity(), ComposeActivity.class);
|
||||
composeIntent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key);
|
||||
startActivity(composeIntent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
final ParcelableAccount[] accounts = mAccountActionProvider.getAccounts();
|
||||
final ParcelableAccount account = accounts[item.getOrder()];
|
||||
final ContentValues values = new ContentValues();
|
||||
final boolean newActivated = !account.is_activated;
|
||||
mAccountActionProvider.setAccountActivated(account.account_key, newActivated);
|
||||
values.put(Accounts.IS_ACTIVATED, newActivated);
|
||||
final String where = Expression.equalsArgs(Accounts.ACCOUNT_KEY).getSQL();
|
||||
final String[] whereArgs = {account.account_key.toString()};
|
||||
mResolver.update(Accounts.CONTENT_URI, values, where, whereArgs);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
mAccountProfileContainer.setOnClickListener(this);
|
||||
|
||||
mAccountProfileBannerView.setInAnimation(getContext(), android.R.anim.fade_in);
|
||||
mAccountProfileBannerView.setOutAnimation(getContext(), android.R.anim.fade_out);
|
||||
mAccountProfileBannerView.setFactory(new ViewSwitcher.ViewFactory() {
|
||||
@Override
|
||||
public View makeView() {
|
||||
return inflater.inflate(R.layout.layout_account_dashboard_profile_image,
|
||||
mAccountProfileBannerView, false);
|
||||
}
|
||||
});
|
||||
|
||||
mNavigationView.setNavigationItemSelectedListener(this);
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
loadAccounts();
|
||||
|
||||
updateSystemWindowsInsets();
|
||||
}
|
||||
|
||||
public void loadAccounts() {
|
||||
if (!mLoaderInitialized) {
|
||||
mLoaderInitialized = true;
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
} else {
|
||||
getLoaderManager().restartLoader(0, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_accounts_dashboard, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mNavigationView = (NavigationView) view.findViewById(R.id.navigation_view);
|
||||
mAccountSelectorView = mNavigationView.getHeaderView(0);
|
||||
mAccountsSelector = (RecyclerView) mAccountSelectorView.findViewById(R.id.otherAccountsList);
|
||||
mAccountProfileContainer = mAccountSelectorView.findViewById(R.id.profileContainer);
|
||||
mNoAccountContainer = mAccountSelectorView.findViewById(R.id.noAccountContainer);
|
||||
mAccountProfileImageView = (ShapedImageView) mAccountSelectorView.findViewById(R.id.profileImage);
|
||||
mAccountProfileBannerView = (ViewSwitcher) mAccountSelectorView.findViewById(R.id.accountProfileBanner);
|
||||
mFloatingProfileImageSnapshotView = (ImageView) mAccountSelectorView.findViewById(R.id.floatingProfileImageSnapshot);
|
||||
mAccountProfileNameView = (TextView) mAccountSelectorView.findViewById(R.id.name);
|
||||
mAccountProfileScreenNameView = (TextView) mAccountSelectorView.findViewById(R.id.screenName);
|
||||
mAccountsToggleMenu = (ActionMenuView) mAccountSelectorView.findViewById(R.id.accountDashboardMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
resolver.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver);
|
||||
getLoaderManager().restartLoader(0, null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
resolver.unregisterContentObserver(mReloadContentObserver);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
void updateAccountActions() {
|
||||
final HomeActivity activity = (HomeActivity) getActivity();
|
||||
if (activity == null) return;
|
||||
final List<SupportTabSpec> tabs = activity.getTabs();
|
||||
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
|
||||
if (account == null) return;
|
||||
boolean hasDmTab = false, hasInteractionsTab = false;
|
||||
for (SupportTabSpec tab : tabs) {
|
||||
if (tab.type == null) continue;
|
||||
switch (tab.type) {
|
||||
case CustomTabType.DIRECT_MESSAGES: {
|
||||
if (!hasDmTab) {
|
||||
hasDmTab = hasAccountInTab(tab, account.account_key, account.is_activated);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CustomTabType.NOTIFICATIONS_TIMELINE: {
|
||||
if (!hasInteractionsTab) {
|
||||
hasInteractionsTab = hasAccountInTab(tab, account.account_key, account.is_activated);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final Menu menu = mNavigationView.getMenu();
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.interactions, !hasInteractionsTab);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.messages, !hasDmTab);
|
||||
|
||||
if (mUseStarsForLikes) {
|
||||
MenuUtils.Companion.setMenuItemTitle(menu, R.id.favorites, R.string.favorites);
|
||||
MenuUtils.Companion.setMenuItemIcon(menu, R.id.favorites, R.drawable.ic_action_star);
|
||||
} else {
|
||||
MenuUtils.Companion.setMenuItemTitle(menu, R.id.favorites, R.string.likes);
|
||||
MenuUtils.Companion.setMenuItemIcon(menu, R.id.favorites, R.drawable.ic_action_heart);
|
||||
}
|
||||
boolean hasLists = false, hasGroups = false, hasPublicTimeline = false;
|
||||
switch (ParcelableAccountUtils.getAccountType(account)) {
|
||||
case ParcelableAccount.Type.TWITTER: {
|
||||
hasLists = true;
|
||||
break;
|
||||
}
|
||||
case ParcelableAccount.Type.STATUSNET: {
|
||||
hasGroups = true;
|
||||
break;
|
||||
}
|
||||
case ParcelableAccount.Type.FANFOU: {
|
||||
hasPublicTimeline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.groups, hasGroups);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.lists, hasLists);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.public_timeline, hasPublicTimeline);
|
||||
}
|
||||
|
||||
private boolean hasAccountInTab(SupportTabSpec tab, UserKey accountId, boolean isActivated) {
|
||||
if (tab.args == null) return false;
|
||||
final UserKey[] accountKeys = Utils.getAccountKeys(getContext(), tab.args);
|
||||
if (accountKeys == null) return isActivated;
|
||||
return ArrayUtils.contains(accountKeys, accountId);
|
||||
}
|
||||
|
||||
private void closeAccountsDrawer() {
|
||||
final Activity activity = getActivity();
|
||||
if (activity instanceof HomeActivity) {
|
||||
((HomeActivity) activity).closeAccountsDrawer();
|
||||
}
|
||||
}
|
||||
|
||||
private void getLocationOnScreen(View view, RectF rectF) {
|
||||
final int[] location = new int[2];
|
||||
view.getLocationOnScreen(location);
|
||||
rectF.set(location[0], location[1], location[0] + view.getWidth(), location[1] + view.getHeight());
|
||||
}
|
||||
|
||||
private void onAccountSelected(AccountProfileImageViewHolder holder, @NonNull final ParcelableAccount account) {
|
||||
if (mSwitchAccountAnimationPlaying) return;
|
||||
final ImageView snapshotView = mFloatingProfileImageSnapshotView;
|
||||
final ShapedImageView profileImageView = mAccountProfileImageView;
|
||||
final ShapedImageView clickedImageView = holder.getIconView();
|
||||
|
||||
// Reset snapshot view position
|
||||
snapshotView.setPivotX(0);
|
||||
snapshotView.setPivotY(0);
|
||||
snapshotView.setTranslationX(0);
|
||||
snapshotView.setTranslationY(0);
|
||||
|
||||
final Matrix matrix = new Matrix();
|
||||
final RectF sourceBounds = new RectF(), destBounds = new RectF(), snapshotBounds = new RectF();
|
||||
getLocationOnScreen(clickedImageView, sourceBounds);
|
||||
getLocationOnScreen(profileImageView, destBounds);
|
||||
getLocationOnScreen(snapshotView, snapshotBounds);
|
||||
final float finalScale = destBounds.width() / sourceBounds.width();
|
||||
final Bitmap snapshotBitmap = TransitionUtils.createViewBitmap(clickedImageView, matrix,
|
||||
new RectF(0, 0, sourceBounds.width(), sourceBounds.height()));
|
||||
final ViewGroup.LayoutParams lp = snapshotView.getLayoutParams();
|
||||
lp.width = clickedImageView.getWidth();
|
||||
lp.height = clickedImageView.getHeight();
|
||||
snapshotView.setLayoutParams(lp);
|
||||
// Copied from MaterialNavigationDrawer: https://github.com/madcyph3r/AdvancedMaterialDrawer/
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
set.play(ObjectAnimator.ofFloat(snapshotView, View.TRANSLATION_X,
|
||||
sourceBounds.left - snapshotBounds.left, destBounds.left - snapshotBounds.left))
|
||||
.with(ObjectAnimator.ofFloat(snapshotView, View.TRANSLATION_Y,
|
||||
sourceBounds.top - snapshotBounds.top, destBounds.top - snapshotBounds.top))
|
||||
.with(ObjectAnimator.ofFloat(snapshotView, View.SCALE_X, 1, finalScale))
|
||||
.with(ObjectAnimator.ofFloat(snapshotView, View.SCALE_Y, 1, finalScale))
|
||||
.with(ObjectAnimator.ofFloat(profileImageView, View.ALPHA, 1, 0))
|
||||
.with(ObjectAnimator.ofFloat(clickedImageView, View.SCALE_X, 0, 1))
|
||||
.with(ObjectAnimator.ofFloat(clickedImageView, View.SCALE_Y, 0, 1));
|
||||
final long animationTransition = 400;
|
||||
set.setDuration(animationTransition);
|
||||
set.setInterpolator(new DecelerateInterpolator());
|
||||
set.addListener(new AnimatorListener() {
|
||||
|
||||
private Drawable clickedDrawable;
|
||||
private int[] clickedColors;
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
snapshotView.setVisibility(View.VISIBLE);
|
||||
snapshotView.setImageBitmap(snapshotBitmap);
|
||||
final Drawable profileDrawable = profileImageView.getDrawable();
|
||||
clickedDrawable = clickedImageView.getDrawable();
|
||||
clickedColors = clickedImageView.getBorderColors();
|
||||
final ParcelableAccount oldSelectedAccount = mAccountsAdapter.getSelectedAccount();
|
||||
if (oldSelectedAccount == null) return;
|
||||
mediaLoader.displayDashboardProfileImage(clickedImageView,
|
||||
oldSelectedAccount, profileDrawable);
|
||||
clickedImageView.setBorderColors(profileImageView.getBorderColors());
|
||||
|
||||
displayAccountBanner(account);
|
||||
|
||||
mSwitchAccountAnimationPlaying = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
finishAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
finishAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
private void finishAnimation() {
|
||||
final Editor editor = preferences.edit();
|
||||
editor.putString(KEY_DEFAULT_ACCOUNT_KEY, account.account_key.toString());
|
||||
editor.apply();
|
||||
mAccountsAdapter.setSelectedAccount(account);
|
||||
updateAccountActions();
|
||||
displayCurrentAccount(clickedDrawable);
|
||||
snapshotView.setVisibility(View.INVISIBLE);
|
||||
snapshotView.setImageDrawable(null);
|
||||
profileImageView.setImageDrawable(clickedDrawable);
|
||||
profileImageView.setBorderColors(clickedColors);
|
||||
profileImageView.setAlpha(1f);
|
||||
clickedImageView.setScaleX(1);
|
||||
clickedImageView.setScaleY(1);
|
||||
clickedImageView.setAlpha(1f);
|
||||
mSwitchAccountAnimationPlaying = false;
|
||||
}
|
||||
});
|
||||
set.start();
|
||||
|
||||
}
|
||||
|
||||
protected void displayAccountBanner(@NonNull ParcelableAccount account) {
|
||||
final int bannerWidth = mAccountProfileBannerView.getWidth();
|
||||
final Resources res = getResources();
|
||||
final int defWidth = res.getDisplayMetrics().widthPixels;
|
||||
final int width = bannerWidth > 0 ? bannerWidth : defWidth;
|
||||
final ImageView bannerView = (ImageView) mAccountProfileBannerView.getNextView();
|
||||
if (bannerView.getDrawable() == null || !CompareUtils.objectEquals(account, bannerView.getTag())) {
|
||||
mediaLoader.displayProfileBanner(bannerView, account, width);
|
||||
bannerView.setTag(account);
|
||||
} else {
|
||||
mediaLoader.cancelDisplayTask(bannerView);
|
||||
}
|
||||
}
|
||||
|
||||
private void displayCurrentAccount(Drawable profileImageSnapshot) {
|
||||
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
mAccountProfileNameView.setText(account.name);
|
||||
mAccountProfileScreenNameView.setText(String.format("@%s", account.screen_name));
|
||||
mediaLoader.displayDashboardProfileImage(mAccountProfileImageView, account,
|
||||
profileImageSnapshot);
|
||||
mAccountProfileImageView.setBorderColors(account.color);
|
||||
mAccountProfileBannerView.showNext();
|
||||
}
|
||||
|
||||
private void updateDefaultAccountState() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem item) {
|
||||
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
|
||||
if (account == null) return false;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.search: {
|
||||
final Intent intent = new Intent(getActivity(), QuickSearchBarActivity.class);
|
||||
intent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key);
|
||||
startActivity(intent);
|
||||
closeAccountsDrawer();
|
||||
break;
|
||||
}
|
||||
case R.id.compose: {
|
||||
final Intent composeIntent = new Intent(INTENT_ACTION_COMPOSE);
|
||||
composeIntent.setClass(getActivity(), ComposeActivity.class);
|
||||
composeIntent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key);
|
||||
startActivity(composeIntent);
|
||||
break;
|
||||
}
|
||||
case R.id.favorites: {
|
||||
IntentUtils.openUserFavorites(getActivity(), account.account_key,
|
||||
account.account_key, account.screen_name);
|
||||
break;
|
||||
}
|
||||
case R.id.lists: {
|
||||
IntentUtils.openUserLists(getActivity(), account.account_key,
|
||||
account.account_key, account.screen_name);
|
||||
break;
|
||||
}
|
||||
case R.id.groups: {
|
||||
IntentUtils.openUserGroups(getActivity(), account.account_key,
|
||||
account.account_key, account.screen_name);
|
||||
break;
|
||||
}
|
||||
case R.id.public_timeline: {
|
||||
IntentUtils.openPublicTimeline(getActivity(), account.account_key);
|
||||
break;
|
||||
}
|
||||
case R.id.messages: {
|
||||
IntentUtils.openDirectMessages(getActivity(), account.account_key);
|
||||
break;
|
||||
}
|
||||
case R.id.interactions: {
|
||||
IntentUtils.openInteractions(getActivity(), account.account_key);
|
||||
break;
|
||||
}
|
||||
case R.id.edit: {
|
||||
IntentUtils.openProfileEditor(getActivity(), account.account_key);
|
||||
break;
|
||||
}
|
||||
case R.id.accounts: {
|
||||
IntentUtils.openAccountsManager(getActivity());
|
||||
closeAccountsDrawer();
|
||||
break;
|
||||
}
|
||||
case R.id.drafts: {
|
||||
IntentUtils.openDrafts(getActivity());
|
||||
closeAccountsDrawer();
|
||||
break;
|
||||
}
|
||||
case R.id.filters: {
|
||||
IntentUtils.openFilters(getActivity());
|
||||
closeAccountsDrawer();
|
||||
break;
|
||||
}
|
||||
case R.id.plus_service: {
|
||||
final Intent intent = new Intent(getActivity(), PlusServiceDashboardActivity.class);
|
||||
startActivity(intent);
|
||||
closeAccountsDrawer();
|
||||
break;
|
||||
}
|
||||
case R.id.settings: {
|
||||
final Intent intent = new Intent(getActivity(), SettingsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivityForResult(intent, REQUEST_SETTINGS);
|
||||
closeAccountsDrawer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setStatusBarHeight(int height) {
|
||||
final int top = Utils.getInsetsTopWithoutActionBarHeight(getActivity(), height);
|
||||
mAccountProfileContainer.setPadding(0, top, 0, 0);
|
||||
}
|
||||
|
||||
public RecyclerView getAccountsSelector() {
|
||||
return mAccountsSelector;
|
||||
}
|
||||
|
||||
static class AccountProfileImageViewHolder extends ViewHolder implements OnClickListener {
|
||||
|
||||
private final AccountSelectorAdapter adapter;
|
||||
private final ShapedImageView icon;
|
||||
|
||||
public AccountProfileImageViewHolder(AccountSelectorAdapter adapter, View itemView) {
|
||||
super(itemView);
|
||||
this.adapter = adapter;
|
||||
itemView.setOnClickListener(this);
|
||||
icon = (ShapedImageView) itemView.findViewById(android.R.id.icon);
|
||||
}
|
||||
|
||||
public ShapedImageView getIconView() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
adapter.dispatchItemSelected(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AccountSelectorAdapter extends Adapter<AccountProfileImageViewHolder> {
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final MediaLoaderWrapper mImageLoader;
|
||||
private final AccountsDashboardFragment mFragment;
|
||||
private ParcelableAccount[] mInternalAccounts;
|
||||
|
||||
AccountSelectorAdapter(LayoutInflater inflater, AccountsDashboardFragment fragment) {
|
||||
mInflater = inflater;
|
||||
mImageLoader = fragment.mediaLoader;
|
||||
mFragment = fragment;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
private static int indexOfAccount(List<ParcelableAccount> accounts, UserKey accountId) {
|
||||
for (int i = 0, j = accounts.size(); i < j; i++) {
|
||||
if (accounts.get(i).account_key.equals(accountId)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ParcelableAccount getAdapterAccount(int adapterPosition) {
|
||||
if (mInternalAccounts == null || mInternalAccounts.length < 1) {
|
||||
return null;
|
||||
}
|
||||
return mInternalAccounts[adapterPosition + 1];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ParcelableAccount getSelectedAccount() {
|
||||
if (mInternalAccounts == null || mInternalAccounts.length == 0) {
|
||||
return null;
|
||||
}
|
||||
return mInternalAccounts[0];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UserKey getSelectedAccountKey() {
|
||||
final ParcelableAccount selectedAccount = getSelectedAccount();
|
||||
if (selectedAccount == null) return null;
|
||||
return selectedAccount.account_key;
|
||||
}
|
||||
|
||||
public void setSelectedAccount(@Nullable ParcelableAccount account) {
|
||||
final ParcelableAccount selectedAccount = getSelectedAccount();
|
||||
if (selectedAccount == null || account == null) return;
|
||||
swap(account, selectedAccount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountProfileImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
final View view = mInflater.inflate(R.layout.adapter_item_dashboard_account, parent, false);
|
||||
return new AccountProfileImageViewHolder(this, view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(AccountProfileImageViewHolder holder, int position) {
|
||||
final ParcelableAccount account = getAdapterAccount(position);
|
||||
mImageLoader.displayDashboardProfileImage(holder.icon, account, null);
|
||||
holder.icon.setBorderColor(account.color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return getAdapterAccount(position).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (mInternalAccounts == null || mInternalAccounts.length == 0) return 0;
|
||||
return mInternalAccounts.length - 1;
|
||||
}
|
||||
|
||||
public void setAccounts(ParcelableAccount[] accounts) {
|
||||
if (accounts != null) {
|
||||
final ParcelableAccount[] previousAccounts = mInternalAccounts;
|
||||
mInternalAccounts = new ParcelableAccount[accounts.length];
|
||||
int tempIdx = 0;
|
||||
final List<ParcelableAccount> tempList = new ArrayList<>();
|
||||
Collections.addAll(tempList, accounts);
|
||||
if (previousAccounts != null) {
|
||||
for (ParcelableAccount previousAccount : previousAccounts) {
|
||||
final int idx = indexOfAccount(tempList, previousAccount.account_key);
|
||||
if (idx >= 0) {
|
||||
mInternalAccounts[tempIdx++] = tempList.remove(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ParcelableAccount account : tempList) {
|
||||
mInternalAccounts[tempIdx++] = account;
|
||||
}
|
||||
} else {
|
||||
mInternalAccounts = null;
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void dispatchItemSelected(AccountProfileImageViewHolder holder) {
|
||||
mFragment.onAccountSelected(holder, getAdapterAccount(holder.getAdapterPosition()));
|
||||
}
|
||||
|
||||
public ParcelableAccount[] getAccounts() {
|
||||
return mInternalAccounts;
|
||||
}
|
||||
|
||||
private void swap(@NonNull ParcelableAccount from, @NonNull ParcelableAccount to) {
|
||||
int fromIdx = -1, toIdx = -1;
|
||||
for (int i = 0, j = mInternalAccounts.length; i < j; i++) {
|
||||
final ParcelableAccount account = mInternalAccounts[i];
|
||||
if (from.id == account.id) {
|
||||
fromIdx = i;
|
||||
}
|
||||
if (to.id == account.id) {
|
||||
toIdx = i;
|
||||
}
|
||||
}
|
||||
if (fromIdx < 0 || toIdx < 0) return;
|
||||
final ParcelableAccount temp = mInternalAccounts[toIdx];
|
||||
mInternalAccounts[toIdx] = mInternalAccounts[fromIdx];
|
||||
mInternalAccounts[fromIdx] = temp;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class OptionItem {
|
||||
|
||||
private final int name, icon, id;
|
||||
|
||||
OptionItem(final int name, final int icon, final int id) {
|
||||
this.name = name;
|
||||
this.icon = icon;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (!(obj instanceof OptionItem)) return false;
|
||||
final OptionItem other = (OptionItem) obj;
|
||||
if (icon != other.icon) return false;
|
||||
if (id != other.id) return false;
|
||||
return name == other.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + icon;
|
||||
result = prime * result + id;
|
||||
result = prime * result + name;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AccountOption{name=" + name + ", icon=" + icon + ", id=" + id + "}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,769 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.Animator.AnimatorListener
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentValues
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.database.Cursor
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.NavigationView
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks
|
||||
import android.support.v4.content.CursorLoader
|
||||
import android.support.v4.content.Loader
|
||||
import android.support.v4.view.MenuItemCompat
|
||||
import android.support.v7.view.SupportMenuInflater
|
||||
import android.support.v7.widget.ActionMenuView
|
||||
import android.support.v7.widget.ActionMenuView.OnMenuItemClickListener
|
||||
import android.support.v7.widget.FixedLinearLayoutManager
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.support.v7.widget.RecyclerView.Adapter
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder
|
||||
import android.view.*
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.ViewSwitcher
|
||||
import org.apache.commons.lang3.ArrayUtils
|
||||
import org.mariotaku.ktextension.setItemAvailability
|
||||
import org.mariotaku.ktextension.setMenuItemIcon
|
||||
import org.mariotaku.ktextension.setMenuItemTitle
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.*
|
||||
import org.mariotaku.twidere.activity.*
|
||||
import org.mariotaku.twidere.annotation.CustomTabType
|
||||
import org.mariotaku.twidere.annotation.Referral
|
||||
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
|
||||
import org.mariotaku.twidere.menu.AccountToggleProvider
|
||||
import org.mariotaku.twidere.model.ParcelableAccount
|
||||
import org.mariotaku.twidere.model.SupportTabSpec
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.ParcelableAccountUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts
|
||||
import org.mariotaku.twidere.util.*
|
||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
|
||||
import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver
|
||||
import org.mariotaku.twidere.view.ShapedImageView
|
||||
import java.util.*
|
||||
|
||||
class AccountsDashboardFragment : BaseSupportFragment(), LoaderCallbacks<Cursor>, OnSharedPreferenceChangeListener, OnClickListener, KeyboardShortcutCallback, NavigationView.OnNavigationItemSelectedListener {
|
||||
|
||||
private val mSystemWindowsInsets = Rect()
|
||||
private var mResolver: ContentResolver? = null
|
||||
|
||||
private var mAccountsAdapter: AccountSelectorAdapter? = null
|
||||
|
||||
private var mNavigationView: NavigationView? = null
|
||||
private var mAccountSelectorView: View? = null
|
||||
var accountsSelector: RecyclerView? = null
|
||||
private set
|
||||
private var mAccountProfileBannerView: ViewSwitcher? = null
|
||||
private var mFloatingProfileImageSnapshotView: ImageView? = null
|
||||
private var mAccountProfileImageView: ShapedImageView? = null
|
||||
private var mAccountProfileNameView: TextView? = null
|
||||
private var mAccountProfileScreenNameView: TextView? = null
|
||||
private var mAccountsToggleMenu: ActionMenuView? = null
|
||||
private var mAccountProfileContainer: View? = null
|
||||
private var mNoAccountContainer: View? = null
|
||||
|
||||
private var mAccountActionProvider: AccountToggleProvider? = null
|
||||
private val mReloadContentObserver = object : SupportFragmentReloadCursorObserver(
|
||||
this, 0, this) {
|
||||
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||
val cr = contentResolver
|
||||
val c = cr.query(Accounts.CONTENT_URI, Accounts.COLUMNS, null, null, Accounts.SORT_POSITION)
|
||||
try {
|
||||
updateAccountProviderData(c)
|
||||
} finally {
|
||||
Utils.closeSilently(c)
|
||||
}
|
||||
super.onChange(selfChange, uri)
|
||||
}
|
||||
}
|
||||
private var mSwitchAccountAnimationPlaying: Boolean = false
|
||||
private var mUseStarsForLikes: Boolean = false
|
||||
private var mLoaderInitialized: Boolean = false
|
||||
|
||||
val activatedAccountIds: Array<UserKey>
|
||||
get() {
|
||||
if (mAccountActionProvider != null) {
|
||||
return mAccountActionProvider!!.activatedAccountIds
|
||||
}
|
||||
return DataStoreUtils.getActivatedAccountKeys(activity)
|
||||
}
|
||||
|
||||
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler,
|
||||
keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isKeyboardShortcutHandled(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
|
||||
val action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState)
|
||||
return ACTION_NAVIGATION_PREVIOUS == action || ACTION_NAVIGATION_NEXT == action
|
||||
}
|
||||
|
||||
override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
|
||||
keyCode: Int, repeatCount: Int,
|
||||
event: KeyEvent, metaState: Int): Boolean {
|
||||
val action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState) ?: return false
|
||||
val offset: Int
|
||||
when (action) {
|
||||
ACTION_NAVIGATION_PREVIOUS -> {
|
||||
offset = -1
|
||||
}
|
||||
ACTION_NAVIGATION_NEXT -> {
|
||||
offset = 1
|
||||
}
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// final int selectedItem = mNavigationView.getSelectedItemPosition();
|
||||
// final int count = mNavigationView.getCount();
|
||||
// int resultPosition;
|
||||
// if (!mNavigationView.isFocused() || selectedItem == ListView.INVALID_POSITION) {
|
||||
// resultPosition = firstVisiblePosition;
|
||||
// } else {
|
||||
// resultPosition = selectedItem + offset;
|
||||
// while (resultPosition >= 0 && resultPosition < count && !mAdapter.isEnabled(resultPosition)) {
|
||||
// resultPosition += offset;
|
||||
// }
|
||||
// }
|
||||
// final View focusedChild = mNavigationView.getFocusedChild();
|
||||
// if (focusedChild == null) {
|
||||
// mNavigationView.requestChildFocus(mNavigationView.getChildAt(0), null);
|
||||
// }
|
||||
// if (resultPosition >= 0 && resultPosition < count) {
|
||||
// mNavigationView.setSelection(resultPosition);
|
||||
// }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
when (requestCode) {
|
||||
REQUEST_SETTINGS -> {
|
||||
if (data == null) return
|
||||
val activity = activity
|
||||
if (data.getBooleanExtra(EXTRA_CHANGED, false)) {
|
||||
activity.recreate()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateDefaultAccountState()
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.profileContainer -> {
|
||||
val account = mAccountsAdapter!!.selectedAccount ?: return
|
||||
val activity = activity
|
||||
if (account.account_user != null) {
|
||||
IntentUtils.openUserProfile(activity, account.account_user!!, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.SELF_PROFILE)
|
||||
} else {
|
||||
IntentUtils.openUserProfile(activity, account.account_key,
|
||||
account.account_key, account.screen_name, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.SELF_PROFILE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor?> {
|
||||
return CursorLoader(activity, Accounts.CONTENT_URI, Accounts.COLUMNS, null, null, Accounts.SORT_POSITION)
|
||||
}
|
||||
|
||||
override fun onLoadFinished(loader: Loader<Cursor?>, data: Cursor?) {
|
||||
updateAccountProviderData(data)
|
||||
}
|
||||
|
||||
private fun updateAccountProviderData(cursor: Cursor?) {
|
||||
if (cursor == null) return
|
||||
val menu = mAccountsToggleMenu!!.menu
|
||||
mAccountActionProvider = MenuItemCompat.getActionProvider(menu.findItem(R.id.select_account)) as AccountToggleProvider
|
||||
val accounts = ParcelableAccountUtils.getAccounts(cursor)
|
||||
if (accounts.size > 0) {
|
||||
mNoAccountContainer!!.visibility = View.GONE
|
||||
mAccountProfileContainer!!.visibility = View.VISIBLE
|
||||
} else {
|
||||
mNoAccountContainer!!.visibility = View.VISIBLE
|
||||
mAccountProfileContainer!!.visibility = View.INVISIBLE
|
||||
}
|
||||
var defaultId: UserKey? = null
|
||||
for (account in accounts) {
|
||||
if (account.is_activated) {
|
||||
defaultId = account.account_key
|
||||
break
|
||||
}
|
||||
}
|
||||
mUseStarsForLikes = preferences.getBoolean(KEY_I_WANT_MY_STARS_BACK)
|
||||
|
||||
mAccountsAdapter!!.accounts = accounts
|
||||
var accountKey = UserKey.valueOf(preferences.getString(KEY_DEFAULT_ACCOUNT_KEY, null))
|
||||
if (accountKey == null) {
|
||||
accountKey = defaultId
|
||||
}
|
||||
var selectedAccount: ParcelableAccount? = null
|
||||
for (account in accounts) {
|
||||
if (account.account_key.maybeEquals(accountKey)) {
|
||||
selectedAccount = account
|
||||
break
|
||||
}
|
||||
}
|
||||
mAccountsAdapter!!.selectedAccount = selectedAccount
|
||||
|
||||
if (mAccountActionProvider != null) {
|
||||
mAccountActionProvider!!.isExclusive = false
|
||||
mAccountActionProvider!!.accounts = accounts
|
||||
}
|
||||
updateAccountActions()
|
||||
val currentAccount = mAccountsAdapter!!.selectedAccount
|
||||
if (currentAccount != null) {
|
||||
displayAccountBanner(currentAccount)
|
||||
displayCurrentAccount(null)
|
||||
}
|
||||
updateDefaultAccountState()
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<Cursor?>) {
|
||||
}
|
||||
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
if (KEY_DEFAULT_ACCOUNT_KEY == key) {
|
||||
updateDefaultAccountState()
|
||||
}
|
||||
}
|
||||
|
||||
override fun fitSystemWindows(insets: Rect) {
|
||||
mSystemWindowsInsets.set(insets)
|
||||
updateSystemWindowsInsets()
|
||||
}
|
||||
|
||||
private fun updateSystemWindowsInsets() {
|
||||
if (mAccountProfileContainer == null) return
|
||||
val insets = mSystemWindowsInsets
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
mResolver = contentResolver
|
||||
val view = view!!
|
||||
val context = view.context
|
||||
val inflater = getLayoutInflater(savedInstanceState)
|
||||
mAccountsAdapter = AccountSelectorAdapter(inflater, this)
|
||||
val layoutManager = FixedLinearLayoutManager(context)
|
||||
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
|
||||
layoutManager.stackFromEnd = true
|
||||
accountsSelector!!.layoutManager = layoutManager
|
||||
accountsSelector!!.adapter = mAccountsAdapter
|
||||
accountsSelector!!.itemAnimator = null
|
||||
val menuInflater = SupportMenuInflater(context)
|
||||
menuInflater.inflate(R.menu.action_dashboard_timeline_toggle, mAccountsToggleMenu!!.menu)
|
||||
mAccountsToggleMenu!!.setOnMenuItemClickListener(OnMenuItemClickListener { item ->
|
||||
if (item.groupId != AccountToggleProvider.MENU_GROUP) {
|
||||
when (item.itemId) {
|
||||
R.id.compose -> {
|
||||
val account = mAccountsAdapter!!.selectedAccount ?: return@OnMenuItemClickListener true
|
||||
val composeIntent = Intent(INTENT_ACTION_COMPOSE)
|
||||
composeIntent.setClass(activity, ComposeActivity::class.java)
|
||||
composeIntent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key)
|
||||
startActivity(composeIntent)
|
||||
return@OnMenuItemClickListener true
|
||||
}
|
||||
}
|
||||
return@OnMenuItemClickListener false
|
||||
}
|
||||
val accounts = mAccountActionProvider!!.accounts
|
||||
val account = accounts[item.order]
|
||||
val values = ContentValues()
|
||||
val newActivated = !account.is_activated
|
||||
mAccountActionProvider!!.setAccountActivated(account.account_key, newActivated)
|
||||
values.put(Accounts.IS_ACTIVATED, newActivated)
|
||||
val where = Expression.equalsArgs(Accounts.ACCOUNT_KEY).sql
|
||||
val whereArgs = arrayOf(account.account_key.toString())
|
||||
mResolver!!.update(Accounts.CONTENT_URI, values, where, whereArgs)
|
||||
true
|
||||
})
|
||||
|
||||
mAccountProfileContainer!!.setOnClickListener(this)
|
||||
|
||||
mAccountProfileBannerView!!.setInAnimation(getContext(), android.R.anim.fade_in)
|
||||
mAccountProfileBannerView!!.setOutAnimation(getContext(), android.R.anim.fade_out)
|
||||
mAccountProfileBannerView!!.setFactory {
|
||||
inflater.inflate(R.layout.layout_account_dashboard_profile_image,
|
||||
mAccountProfileBannerView, false)
|
||||
}
|
||||
|
||||
mNavigationView!!.setNavigationItemSelectedListener(this)
|
||||
preferences.registerOnSharedPreferenceChangeListener(this)
|
||||
|
||||
loadAccounts()
|
||||
|
||||
updateSystemWindowsInsets()
|
||||
}
|
||||
|
||||
fun loadAccounts() {
|
||||
if (!mLoaderInitialized) {
|
||||
mLoaderInitialized = true
|
||||
loaderManager.initLoader(0, null, this)
|
||||
} else {
|
||||
loaderManager.restartLoader(0, null, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater!!.inflate(R.layout.fragment_accounts_dashboard, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mNavigationView = view!!.findViewById(R.id.navigation_view) as NavigationView
|
||||
mAccountSelectorView = mNavigationView!!.getHeaderView(0)
|
||||
accountsSelector = mAccountSelectorView!!.findViewById(R.id.otherAccountsList) as RecyclerView
|
||||
mAccountProfileContainer = mAccountSelectorView!!.findViewById(R.id.profileContainer)
|
||||
mNoAccountContainer = mAccountSelectorView!!.findViewById(R.id.noAccountContainer)
|
||||
mAccountProfileImageView = mAccountSelectorView!!.findViewById(R.id.profileImage) as ShapedImageView
|
||||
mAccountProfileBannerView = mAccountSelectorView!!.findViewById(R.id.accountProfileBanner) as ViewSwitcher
|
||||
mFloatingProfileImageSnapshotView = mAccountSelectorView!!.findViewById(R.id.floatingProfileImageSnapshot) as ImageView
|
||||
mAccountProfileNameView = mAccountSelectorView!!.findViewById(R.id.name) as TextView
|
||||
mAccountProfileScreenNameView = mAccountSelectorView!!.findViewById(R.id.screenName) as TextView
|
||||
mAccountsToggleMenu = mAccountSelectorView!!.findViewById(R.id.accountDashboardMenu) as ActionMenuView
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val resolver = contentResolver
|
||||
resolver.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver)
|
||||
loaderManager.restartLoader(0, null, this)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
val resolver = contentResolver
|
||||
resolver.unregisterContentObserver(mReloadContentObserver)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
internal fun updateAccountActions() {
|
||||
val activity = activity as HomeActivity ?: return
|
||||
val tabs = activity.tabs
|
||||
val account = mAccountsAdapter!!.selectedAccount ?: return
|
||||
var hasDmTab = false
|
||||
var hasInteractionsTab = false
|
||||
for (tab in tabs) {
|
||||
if (tab.type == null) continue
|
||||
when (tab.type) {
|
||||
CustomTabType.DIRECT_MESSAGES -> {
|
||||
if (!hasDmTab) {
|
||||
hasDmTab = hasAccountInTab(tab, account.account_key, account.is_activated)
|
||||
}
|
||||
}
|
||||
CustomTabType.NOTIFICATIONS_TIMELINE -> {
|
||||
if (!hasInteractionsTab) {
|
||||
hasInteractionsTab = hasAccountInTab(tab, account.account_key, account.is_activated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val menu = mNavigationView!!.menu
|
||||
menu.setItemAvailability(R.id.interactions, !hasInteractionsTab)
|
||||
menu.setItemAvailability(R.id.messages, !hasDmTab)
|
||||
|
||||
if (mUseStarsForLikes) {
|
||||
menu.setMenuItemTitle(R.id.favorites, R.string.favorites)
|
||||
menu.setMenuItemIcon(R.id.favorites, R.drawable.ic_action_star)
|
||||
} else {
|
||||
menu.setMenuItemTitle(R.id.favorites, R.string.likes)
|
||||
menu.setMenuItemIcon(R.id.favorites, R.drawable.ic_action_heart)
|
||||
}
|
||||
var hasLists = false
|
||||
var hasGroups = false
|
||||
var hasPublicTimeline = false
|
||||
when (ParcelableAccountUtils.getAccountType(account)) {
|
||||
ParcelableAccount.Type.TWITTER -> {
|
||||
hasLists = true
|
||||
}
|
||||
ParcelableAccount.Type.STATUSNET -> {
|
||||
hasGroups = true
|
||||
}
|
||||
ParcelableAccount.Type.FANFOU -> {
|
||||
hasPublicTimeline = true
|
||||
}
|
||||
}
|
||||
MenuUtils.setItemAvailability(menu, R.id.groups, hasGroups)
|
||||
MenuUtils.setItemAvailability(menu, R.id.lists, hasLists)
|
||||
MenuUtils.setItemAvailability(menu, R.id.public_timeline, hasPublicTimeline)
|
||||
}
|
||||
|
||||
private fun hasAccountInTab(tab: SupportTabSpec, accountId: UserKey, isActivated: Boolean): Boolean {
|
||||
if (tab.args == null) return false
|
||||
val accountKeys = Utils.getAccountKeys(context, tab.args) ?: return isActivated
|
||||
return ArrayUtils.contains(accountKeys, accountId)
|
||||
}
|
||||
|
||||
private fun closeAccountsDrawer() {
|
||||
val activity = activity
|
||||
if (activity is HomeActivity) {
|
||||
activity.closeAccountsDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLocationOnScreen(view: View, rectF: RectF) {
|
||||
val location = IntArray(2)
|
||||
view.getLocationOnScreen(location)
|
||||
rectF.set(location[0].toFloat(), location[1].toFloat(), (location[0] + view.width).toFloat(), (location[1] + view.height).toFloat())
|
||||
}
|
||||
|
||||
private fun onAccountSelected(holder: AccountProfileImageViewHolder, account: ParcelableAccount) {
|
||||
if (mSwitchAccountAnimationPlaying) return
|
||||
val snapshotView = mFloatingProfileImageSnapshotView!!
|
||||
val profileImageView = mAccountProfileImageView!!
|
||||
val clickedImageView = holder.iconView
|
||||
|
||||
// Reset snapshot view position
|
||||
snapshotView.pivotX = 0f
|
||||
snapshotView.pivotY = 0f
|
||||
snapshotView.translationX = 0f
|
||||
snapshotView.translationY = 0f
|
||||
|
||||
val matrix = Matrix()
|
||||
val sourceBounds = RectF()
|
||||
val destBounds = RectF()
|
||||
val snapshotBounds = RectF()
|
||||
getLocationOnScreen(clickedImageView, sourceBounds)
|
||||
getLocationOnScreen(profileImageView, destBounds)
|
||||
getLocationOnScreen(snapshotView, snapshotBounds)
|
||||
val finalScale = destBounds.width() / sourceBounds.width()
|
||||
val snapshotBitmap = TransitionUtils.createViewBitmap(clickedImageView, matrix,
|
||||
RectF(0f, 0f, sourceBounds.width(), sourceBounds.height()))
|
||||
val lp = snapshotView.layoutParams
|
||||
lp.width = clickedImageView.width
|
||||
lp.height = clickedImageView.height
|
||||
snapshotView.layoutParams = lp
|
||||
// Copied from MaterialNavigationDrawer: https://github.com/madcyph3r/AdvancedMaterialDrawer/
|
||||
val set = AnimatorSet()
|
||||
set.play(ObjectAnimator.ofFloat(snapshotView, View.TRANSLATION_X, sourceBounds.left - snapshotBounds.left, destBounds.left - snapshotBounds.left))
|
||||
.with(ObjectAnimator.ofFloat(snapshotView, View.TRANSLATION_Y, sourceBounds.top - snapshotBounds.top, destBounds.top - snapshotBounds.top))
|
||||
.with(ObjectAnimator.ofFloat<View>(snapshotView, View.SCALE_X, 1f, finalScale))
|
||||
.with(ObjectAnimator.ofFloat<View>(snapshotView, View.SCALE_Y, 1f, finalScale))
|
||||
.with(ObjectAnimator.ofFloat<View>(profileImageView, View.ALPHA, 1f, 0f))
|
||||
.with(ObjectAnimator.ofFloat<View>(clickedImageView, View.SCALE_X, 0f, 1f))
|
||||
.with(ObjectAnimator.ofFloat<View>(clickedImageView, View.SCALE_Y, 0f, 1f))
|
||||
val animationTransition: Long = 400
|
||||
set.duration = animationTransition
|
||||
set.interpolator = DecelerateInterpolator()
|
||||
set.addListener(object : AnimatorListener {
|
||||
|
||||
private var clickedDrawable: Drawable? = null
|
||||
private var clickedColors: IntArray? = null
|
||||
|
||||
override fun onAnimationStart(animation: Animator) {
|
||||
snapshotView.visibility = View.VISIBLE
|
||||
snapshotView.setImageBitmap(snapshotBitmap)
|
||||
val profileDrawable = profileImageView!!.drawable
|
||||
clickedDrawable = clickedImageView.drawable
|
||||
clickedColors = clickedImageView.borderColors
|
||||
val oldSelectedAccount = mAccountsAdapter!!.selectedAccount ?: return
|
||||
mediaLoader.displayDashboardProfileImage(clickedImageView,
|
||||
oldSelectedAccount, profileDrawable)
|
||||
clickedImageView.setBorderColors(*profileImageView.borderColors)
|
||||
|
||||
displayAccountBanner(account)
|
||||
|
||||
mSwitchAccountAnimationPlaying = true
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
finishAnimation()
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator) {
|
||||
finishAnimation()
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animation: Animator) {
|
||||
|
||||
}
|
||||
|
||||
private fun finishAnimation() {
|
||||
val editor = preferences.edit()
|
||||
editor.putString(KEY_DEFAULT_ACCOUNT_KEY, account.account_key.toString())
|
||||
editor.apply()
|
||||
mAccountsAdapter!!.selectedAccount = account
|
||||
updateAccountActions()
|
||||
displayCurrentAccount(clickedDrawable)
|
||||
snapshotView.visibility = View.INVISIBLE
|
||||
snapshotView.setImageDrawable(null)
|
||||
profileImageView!!.setImageDrawable(clickedDrawable)
|
||||
profileImageView.setBorderColors(*clickedColors!!)
|
||||
profileImageView.alpha = 1f
|
||||
clickedImageView.scaleX = 1f
|
||||
clickedImageView.scaleY = 1f
|
||||
clickedImageView.alpha = 1f
|
||||
mSwitchAccountAnimationPlaying = false
|
||||
}
|
||||
})
|
||||
set.start()
|
||||
|
||||
}
|
||||
|
||||
protected fun displayAccountBanner(account: ParcelableAccount) {
|
||||
val bannerWidth = mAccountProfileBannerView!!.width
|
||||
val res = resources
|
||||
val defWidth = res.displayMetrics.widthPixels
|
||||
val width = if (bannerWidth > 0) bannerWidth else defWidth
|
||||
val bannerView = mAccountProfileBannerView!!.nextView as ImageView
|
||||
if (bannerView.drawable == null || !CompareUtils.objectEquals(account, bannerView.tag)) {
|
||||
mediaLoader.displayProfileBanner(bannerView, account, width)
|
||||
bannerView.tag = account
|
||||
} else {
|
||||
mediaLoader.cancelDisplayTask(bannerView)
|
||||
}
|
||||
}
|
||||
|
||||
private fun displayCurrentAccount(profileImageSnapshot: Drawable?) {
|
||||
val account = mAccountsAdapter!!.selectedAccount ?: return
|
||||
mAccountProfileNameView!!.text = account.name
|
||||
mAccountProfileScreenNameView!!.text = String.format("@%s", account.screen_name)
|
||||
mediaLoader.displayDashboardProfileImage(mAccountProfileImageView!!, account,
|
||||
profileImageSnapshot)
|
||||
mAccountProfileImageView!!.setBorderColors(account.color)
|
||||
mAccountProfileBannerView!!.showNext()
|
||||
}
|
||||
|
||||
private fun updateDefaultAccountState() {
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||
val account = mAccountsAdapter!!.selectedAccount ?: return false
|
||||
when (item.itemId) {
|
||||
R.id.search -> {
|
||||
val intent = Intent(activity, QuickSearchBarActivity::class.java)
|
||||
intent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key)
|
||||
startActivity(intent)
|
||||
closeAccountsDrawer()
|
||||
}
|
||||
R.id.compose -> {
|
||||
val composeIntent = Intent(INTENT_ACTION_COMPOSE)
|
||||
composeIntent.setClass(activity, ComposeActivity::class.java)
|
||||
composeIntent.putExtra(EXTRA_ACCOUNT_KEY, account.account_key)
|
||||
startActivity(composeIntent)
|
||||
}
|
||||
R.id.favorites -> {
|
||||
IntentUtils.openUserFavorites(activity, account.account_key,
|
||||
account.account_key, account.screen_name)
|
||||
}
|
||||
R.id.lists -> {
|
||||
IntentUtils.openUserLists(activity, account.account_key,
|
||||
account.account_key, account.screen_name)
|
||||
}
|
||||
R.id.groups -> {
|
||||
IntentUtils.openUserGroups(activity, account.account_key,
|
||||
account.account_key, account.screen_name)
|
||||
}
|
||||
R.id.public_timeline -> {
|
||||
IntentUtils.openPublicTimeline(activity, account.account_key)
|
||||
}
|
||||
R.id.messages -> {
|
||||
IntentUtils.openDirectMessages(activity, account.account_key)
|
||||
}
|
||||
R.id.interactions -> {
|
||||
IntentUtils.openInteractions(activity, account.account_key)
|
||||
}
|
||||
R.id.edit -> {
|
||||
IntentUtils.openProfileEditor(activity, account.account_key)
|
||||
}
|
||||
R.id.accounts -> {
|
||||
IntentUtils.openAccountsManager(activity)
|
||||
closeAccountsDrawer()
|
||||
}
|
||||
R.id.drafts -> {
|
||||
IntentUtils.openDrafts(activity)
|
||||
closeAccountsDrawer()
|
||||
}
|
||||
R.id.filters -> {
|
||||
IntentUtils.openFilters(activity)
|
||||
closeAccountsDrawer()
|
||||
}
|
||||
R.id.plus_service -> {
|
||||
val intent = Intent(activity, PlusServiceDashboardActivity::class.java)
|
||||
startActivity(intent)
|
||||
closeAccountsDrawer()
|
||||
}
|
||||
R.id.settings -> {
|
||||
val intent = Intent(activity, SettingsActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
startActivityForResult(intent, REQUEST_SETTINGS)
|
||||
closeAccountsDrawer()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun setStatusBarHeight(height: Int) {
|
||||
val top = Utils.getInsetsTopWithoutActionBarHeight(activity, height)
|
||||
mAccountProfileContainer!!.setPadding(0, top, 0, 0)
|
||||
}
|
||||
|
||||
internal class AccountProfileImageViewHolder(val adapter: AccountSelectorAdapter, itemView: View) : ViewHolder(itemView), OnClickListener {
|
||||
val iconView: ShapedImageView
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener(this)
|
||||
iconView = itemView.findViewById(android.R.id.icon) as ShapedImageView
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
adapter.dispatchItemSelected(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal class AccountSelectorAdapter(
|
||||
private val inflater: LayoutInflater,
|
||||
private val fragment: AccountsDashboardFragment
|
||||
) : Adapter<AccountProfileImageViewHolder>() {
|
||||
private val mediaLoader: MediaLoaderWrapper
|
||||
var accounts: Array<ParcelableAccount>? = null
|
||||
set(value) {
|
||||
if (value != null) {
|
||||
val previousAccounts = accounts
|
||||
if (previousAccounts != null) {
|
||||
val tmpList = arrayListOf(*value)
|
||||
val tmpResult = ArrayList<ParcelableAccount>()
|
||||
previousAccounts.forEach { previousAccount ->
|
||||
val prefIndexOfTmp = tmpList.indexOfFirst { previousAccount == it }
|
||||
if (prefIndexOfTmp >= 0) {
|
||||
tmpResult.add(tmpList.removeAt(prefIndexOfTmp))
|
||||
}
|
||||
}
|
||||
tmpResult.addAll(tmpList)
|
||||
field = tmpResult.toTypedArray()
|
||||
} else {
|
||||
field = value
|
||||
}
|
||||
} else {
|
||||
field = null
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
init {
|
||||
mediaLoader = fragment.mediaLoader
|
||||
setHasStableIds(true)
|
||||
}
|
||||
|
||||
private fun indexOfAccount(accounts: List<ParcelableAccount>, accountId: UserKey): Int {
|
||||
var i = 0
|
||||
val j = accounts.size
|
||||
while (i < j) {
|
||||
if (accounts[i].account_key == accountId) return i
|
||||
i++
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
fun getAdapterAccount(adapterPosition: Int): ParcelableAccount? {
|
||||
if (accounts == null || accounts!!.size < 1) {
|
||||
return null
|
||||
}
|
||||
return accounts!![adapterPosition + 1]
|
||||
}
|
||||
|
||||
var selectedAccount: ParcelableAccount?
|
||||
get() {
|
||||
if (accounts == null || accounts!!.size == 0) {
|
||||
return null
|
||||
}
|
||||
return accounts!![0]
|
||||
}
|
||||
set(account) {
|
||||
val selectedAccount = selectedAccount
|
||||
if (selectedAccount == null || account == null) return
|
||||
swap(account, selectedAccount)
|
||||
}
|
||||
|
||||
val selectedAccountKey: UserKey?
|
||||
get() {
|
||||
val selectedAccount = selectedAccount ?: return null
|
||||
return selectedAccount.account_key
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountProfileImageViewHolder {
|
||||
val view = inflater.inflate(R.layout.adapter_item_dashboard_account, parent, false)
|
||||
return AccountProfileImageViewHolder(this, view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AccountProfileImageViewHolder, position: Int) {
|
||||
val account = getAdapterAccount(position)
|
||||
mediaLoader.displayDashboardProfileImage(holder.iconView, account!!, null)
|
||||
holder.iconView.setBorderColor(account.color)
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return getAdapterAccount(position)!!.hashCode().toLong()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
if (accounts == null || accounts!!.size == 0) return 0
|
||||
return accounts!!.size - 1
|
||||
}
|
||||
|
||||
fun dispatchItemSelected(holder: AccountProfileImageViewHolder) {
|
||||
fragment.onAccountSelected(holder, getAdapterAccount(holder.adapterPosition)!!)
|
||||
}
|
||||
|
||||
private fun swap(from: ParcelableAccount, to: ParcelableAccount) {
|
||||
val accounts = accounts ?: return
|
||||
val fromIdx = accounts.indexOfFirst { it == from }
|
||||
val toIdx = accounts.indexOfFirst { it == to }
|
||||
if (fromIdx < 0 || toIdx < 0) return
|
||||
val temp = accounts[toIdx]
|
||||
accounts[toIdx] = accounts[fromIdx]
|
||||
accounts[fromIdx] = temp
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class OptionItem(val name: Int, val icon: Int, val id: Int)
|
||||
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AbsListView.OnScrollListener;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class BaseListFragment extends ListFragment implements Constants, OnScrollListener, RefreshScrollTopInterface {
|
||||
|
||||
@Inject
|
||||
protected AsyncTwitterWrapper mTwitterWrapper;
|
||||
@Inject
|
||||
protected SharedPreferencesWrapper mPreferences;
|
||||
private boolean mActivityFirstCreated;
|
||||
private boolean mIsInstanceStateSaved;
|
||||
private boolean mReachedBottom, mNotReachedBottomBefore = true;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
GeneralComponentHelper.build(activity).inject(this);
|
||||
}
|
||||
|
||||
public final TwidereApplication getApplication() {
|
||||
return TwidereApplication.Companion.getInstance(getActivity());
|
||||
}
|
||||
|
||||
public final ContentResolver getContentResolver() {
|
||||
final Activity activity = getActivity();
|
||||
if (activity != null) return activity.getContentResolver();
|
||||
return null;
|
||||
}
|
||||
|
||||
public final SharedPreferences getSharedPreferences(final String name, final int mode) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity != null) return activity.getSharedPreferences(name, mode);
|
||||
return null;
|
||||
}
|
||||
|
||||
public final Object getSystemService(final String name) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity != null) return activity.getSystemService(name);
|
||||
return null;
|
||||
}
|
||||
|
||||
public final int getTabPosition() {
|
||||
final Bundle args = getArguments();
|
||||
return args != null ? args.getInt(EXTRA_TAB_POSITION, -1) : -1;
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
activity.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public boolean isActivityFirstCreated() {
|
||||
return mActivityFirstCreated;
|
||||
}
|
||||
|
||||
public boolean isInstanceStateSaved() {
|
||||
return mIsInstanceStateSaved;
|
||||
}
|
||||
|
||||
public boolean isReachedBottom() {
|
||||
return mReachedBottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mIsInstanceStateSaved = savedInstanceState != null;
|
||||
final ListView lv = getListView();
|
||||
lv.setOnScrollListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mActivityFirstCreated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mActivityFirstCreated = true;
|
||||
}
|
||||
|
||||
public void onPostStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
|
||||
final int totalItemCount) {
|
||||
final boolean reached = firstVisibleItem + visibleItemCount >= totalItemCount
|
||||
&& totalItemCount >= visibleItemCount;
|
||||
|
||||
if (mReachedBottom != reached) {
|
||||
mReachedBottom = reached;
|
||||
if (mReachedBottom && mNotReachedBottomBefore) {
|
||||
mNotReachedBottomBefore = false;
|
||||
return;
|
||||
}
|
||||
if (mReachedBottom && getListAdapter().getCount() > visibleItemCount) {
|
||||
onReachedBottom();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
onPostStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mActivityFirstCreated = false;
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
public void registerReceiver(final BroadcastReceiver receiver, final IntentFilter filter) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
activity.registerReceiver(receiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scrollToStart() {
|
||||
Utils.scrollListToTop(getListView());
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setProgressBarIndeterminateVisibility(final boolean visible) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
activity.setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelection(final int position) {
|
||||
Utils.scrollListToPosition(getListView(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean triggerRefresh() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void unregisterReceiver(final BroadcastReceiver receiver) {
|
||||
final Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
activity.unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
protected void onReachedBottom() {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.ListFragment
|
||||
import android.widget.AbsListView
|
||||
import android.widget.AbsListView.OnScrollListener
|
||||
import org.mariotaku.twidere.app.TwidereApplication
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_TAB_POSITION
|
||||
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper
|
||||
import org.mariotaku.twidere.util.SharedPreferencesWrapper
|
||||
import org.mariotaku.twidere.util.Utils
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
open class BaseListFragment : ListFragment(), OnScrollListener, RefreshScrollTopInterface {
|
||||
|
||||
@Inject
|
||||
lateinit var twitterWrapper: AsyncTwitterWrapper
|
||||
@Inject
|
||||
lateinit var preferences: SharedPreferencesWrapper
|
||||
var activityFirstCreated: Boolean = false
|
||||
private set
|
||||
var instanceStateSaved: Boolean = false
|
||||
private set
|
||||
var reachedBottom: Boolean = false
|
||||
private set
|
||||
private var notReachedBottomBefore = true
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
GeneralComponentHelper.build(context).inject(this)
|
||||
}
|
||||
|
||||
val application: TwidereApplication
|
||||
get() = TwidereApplication.getInstance(activity)
|
||||
|
||||
val contentResolver: ContentResolver?
|
||||
get() {
|
||||
val activity = activity
|
||||
if (activity != null) return activity.contentResolver
|
||||
return null
|
||||
}
|
||||
|
||||
fun getSharedPreferences(name: String, mode: Int): SharedPreferences? {
|
||||
val activity = activity
|
||||
if (activity != null) return activity.getSharedPreferences(name, mode)
|
||||
return null
|
||||
}
|
||||
|
||||
fun getSystemService(name: String): Any? {
|
||||
val activity = activity
|
||||
if (activity != null) return activity.getSystemService(name)
|
||||
return null
|
||||
}
|
||||
|
||||
val tabPosition: Int
|
||||
get() {
|
||||
val args = arguments
|
||||
return if (args != null) args.getInt(EXTRA_TAB_POSITION, -1) else -1
|
||||
}
|
||||
|
||||
fun invalidateOptionsMenu() {
|
||||
val activity = activity ?: return
|
||||
activity.invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
instanceStateSaved = savedInstanceState != null
|
||||
val lv = listView
|
||||
lv.setOnScrollListener(this)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
activityFirstCreated = true
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
activityFirstCreated = true
|
||||
}
|
||||
|
||||
fun onPostStart() {
|
||||
}
|
||||
|
||||
override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int,
|
||||
totalItemCount: Int) {
|
||||
val reached = firstVisibleItem + visibleItemCount >= totalItemCount && totalItemCount >= visibleItemCount
|
||||
|
||||
if (reachedBottom != reached) {
|
||||
reachedBottom = reached
|
||||
if (reachedBottom && notReachedBottomBefore) {
|
||||
notReachedBottomBefore = false
|
||||
return
|
||||
}
|
||||
if (reachedBottom && listAdapter.count > visibleItemCount) {
|
||||
onReachedBottom()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
onPostStart()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
activityFirstCreated = false
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun scrollToStart(): Boolean {
|
||||
Utils.scrollListToTop(listView)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun setSelection(position: Int) {
|
||||
Utils.scrollListToPosition(listView, position)
|
||||
}
|
||||
|
||||
override fun triggerRefresh(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
protected fun onReachedBottom() {
|
||||
|
||||
}
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.ExtensionsAdapter;
|
||||
import org.mariotaku.twidere.loader.ExtensionsListLoader;
|
||||
import org.mariotaku.twidere.loader.ExtensionsListLoader.ExtensionInfo;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.PermissionsManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ExtensionsListFragment extends BaseListFragment implements LoaderCallbacks<List<ExtensionInfo>> {
|
||||
|
||||
private ExtensionsAdapter mAdapter;
|
||||
private PackageManager mPackageManager;
|
||||
private PermissionsManager mPermissionsManager;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mPackageManager = getActivity().getPackageManager();
|
||||
mPermissionsManager = new PermissionsManager(getActivity());
|
||||
mAdapter = new ExtensionsAdapter(getActivity());
|
||||
setListAdapter(mAdapter);
|
||||
final ListView listView = getListView();
|
||||
listView.setOnCreateContextMenuListener(this);
|
||||
getLoaderManager().initLoader(0, null, this);
|
||||
setListShown(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<List<ExtensionInfo>> onCreateLoader(final int id, final Bundle args) {
|
||||
return new ExtensionsListLoader(getActivity(), mPackageManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(final Loader<List<ExtensionInfo>> loader, final List<ExtensionInfo> data) {
|
||||
mAdapter.setData(data);
|
||||
setListShown(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(final Loader<List<ExtensionInfo>> loader) {
|
||||
mAdapter.setData(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
|
||||
openSettings(mAdapter.getItem(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
final MenuInflater inflater = new MenuInflater(v.getContext());
|
||||
inflater.inflate(R.menu.action_extension, menu);
|
||||
final AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo;
|
||||
final ExtensionInfo extensionInfo = mAdapter.getItem(adapterMenuInfo.position);
|
||||
if (extensionInfo.pname != null && extensionInfo.settings != null) {
|
||||
final Intent intent = new Intent(INTENT_ACTION_EXTENSION_SETTINGS);
|
||||
intent.setClassName(extensionInfo.pname, extensionInfo.settings);
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.settings, mPackageManager.queryIntentActivities(intent, 0).size() == 1);
|
||||
} else {
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.settings, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
final AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
|
||||
final ExtensionInfo extensionInfo = mAdapter.getItem(adapterMenuInfo.position);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.settings: {
|
||||
openSettings(extensionInfo);
|
||||
break;
|
||||
}
|
||||
case R.id.delete: {
|
||||
uninstallExtension(extensionInfo);
|
||||
break;
|
||||
}
|
||||
case R.id.revoke: {
|
||||
mPermissionsManager.revoke(extensionInfo.pname);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean openSettings(final ExtensionInfo info) {
|
||||
final Intent intent = new Intent(INTENT_ACTION_EXTENSION_SETTINGS);
|
||||
intent.setPackage(info.pname);
|
||||
if (info.settings != null) {
|
||||
intent.setClassName(info.pname, info.settings);
|
||||
} else {
|
||||
final PackageManager pm = getActivity().getPackageManager();
|
||||
final List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
|
||||
if (activities.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final ResolveInfo resolveInfo = activities.get(0);
|
||||
intent.setClassName(info.pname, resolveInfo.activityInfo.name);
|
||||
}
|
||||
try {
|
||||
startActivity(intent);
|
||||
} catch (final Exception e) {
|
||||
Log.w(LOGTAG, e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean uninstallExtension(final ExtensionInfo info) {
|
||||
if (info == null) return false;
|
||||
final Uri packageUri = Uri.parse("package:" + info.pname);
|
||||
final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
|
||||
try {
|
||||
startActivity(uninstallIntent);
|
||||
} catch (final Exception e) {
|
||||
Log.w(LOGTAG, e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks
|
||||
import android.support.v4.content.Loader
|
||||
import android.util.Log
|
||||
import android.view.ContextMenu
|
||||
import android.view.ContextMenu.ContextMenuInfo
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo
|
||||
import android.widget.ListView
|
||||
import org.mariotaku.ktextension.setItemAvailability
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.LOGTAG
|
||||
import org.mariotaku.twidere.adapter.ExtensionsAdapter
|
||||
import org.mariotaku.twidere.constant.IntentConstants
|
||||
import org.mariotaku.twidere.loader.ExtensionsListLoader
|
||||
import org.mariotaku.twidere.loader.ExtensionsListLoader.ExtensionInfo
|
||||
import org.mariotaku.twidere.util.PermissionsManager
|
||||
|
||||
class ExtensionsListFragment : BaseListFragment(), LoaderCallbacks<List<ExtensionInfo>> {
|
||||
|
||||
private var adapter: ExtensionsAdapter? = null
|
||||
private var packageManager: PackageManager? = null
|
||||
private var permissionsManager: PermissionsManager? = null
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
packageManager = activity.packageManager
|
||||
permissionsManager = PermissionsManager(activity)
|
||||
adapter = ExtensionsAdapter(activity)
|
||||
listAdapter = adapter
|
||||
listView.setOnCreateContextMenuListener(this)
|
||||
loaderManager.initLoader(0, null, this)
|
||||
setListShown(false)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onCreateLoader(id: Int, args: Bundle): Loader<List<ExtensionInfo>> {
|
||||
return ExtensionsListLoader(activity, packageManager)
|
||||
}
|
||||
|
||||
override fun onLoadFinished(loader: Loader<List<ExtensionInfo>>, data: List<ExtensionInfo>) {
|
||||
adapter!!.setData(data)
|
||||
setListShown(true)
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<List<ExtensionInfo>>) {
|
||||
adapter!!.setData(null)
|
||||
}
|
||||
|
||||
override fun onListItemClick(l: ListView?, v: View?, position: Int, id: Long) {
|
||||
openSettings(adapter!!.getItem(position))
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo) {
|
||||
val inflater = MenuInflater(v.context)
|
||||
inflater.inflate(R.menu.action_extension, menu)
|
||||
val adapterMenuInfo = menuInfo as AdapterContextMenuInfo
|
||||
val extensionInfo = adapter!!.getItem(adapterMenuInfo.position)
|
||||
if (extensionInfo.pname != null && extensionInfo.settings != null) {
|
||||
val intent = Intent(IntentConstants.INTENT_ACTION_EXTENSION_SETTINGS)
|
||||
intent.setClassName(extensionInfo.pname, extensionInfo.settings)
|
||||
menu.setItemAvailability(R.id.settings, packageManager!!.queryIntentActivities(intent, 0).size == 1)
|
||||
} else {
|
||||
menu.setItemAvailability(R.id.settings, false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onContextItemSelected(item: MenuItem?): Boolean {
|
||||
val adapterMenuInfo = item!!.menuInfo as AdapterContextMenuInfo
|
||||
val extensionInfo = adapter!!.getItem(adapterMenuInfo.position)
|
||||
when (item.itemId) {
|
||||
R.id.settings -> {
|
||||
openSettings(extensionInfo)
|
||||
}
|
||||
R.id.delete -> {
|
||||
uninstallExtension(extensionInfo)
|
||||
}
|
||||
R.id.revoke -> {
|
||||
permissionsManager!!.revoke(extensionInfo.pname)
|
||||
adapter!!.notifyDataSetChanged()
|
||||
}
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun openSettings(info: ExtensionInfo): Boolean {
|
||||
val intent = Intent(IntentConstants.INTENT_ACTION_EXTENSION_SETTINGS)
|
||||
intent.setPackage(info.pname)
|
||||
if (info.settings != null) {
|
||||
intent.setClassName(info.pname, info.settings)
|
||||
} else {
|
||||
val pm = activity.packageManager
|
||||
val activities = pm.queryIntentActivities(intent, 0)
|
||||
if (activities.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
val resolveInfo = activities[0]
|
||||
intent.setClassName(info.pname, resolveInfo.activityInfo.name)
|
||||
}
|
||||
try {
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Log.w(LOGTAG, e)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun uninstallExtension(info: ExtensionInfo?): Boolean {
|
||||
if (info == null) return false
|
||||
val packageUri = Uri.parse("package:${info.pname}")
|
||||
val uninstallIntent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri)
|
||||
try {
|
||||
startActivity(uninstallIntent)
|
||||
} catch (e: Exception) {
|
||||
Log.w(LOGTAG, e)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
@ -1,321 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.DialogInterface.OnShowListener;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.ActionMode;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView.MultiChoiceModeListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.ArrayAdapter;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
|
||||
public class HostMappingsListFragment extends BaseListFragment implements MultiChoiceModeListener,
|
||||
OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final String EXTRA_EDIT_MODE = "edit_mode";
|
||||
private static final String EXTRA_HOST = "host";
|
||||
private static final String EXTRA_ADDRESS = "address";
|
||||
private static final String EXTRA_EXCLUDED = "excluded";
|
||||
|
||||
private ListView mListView;
|
||||
private HostMappingAdapter mAdapter;
|
||||
private SharedPreferencesWrapper mHostMapping;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
mHostMapping = SharedPreferencesWrapper.getInstance(getActivity(),
|
||||
HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
mHostMapping.registerOnSharedPreferenceChangeListener(this);
|
||||
mAdapter = new HostMappingAdapter(getActivity());
|
||||
setListAdapter(mAdapter);
|
||||
mListView = getListView();
|
||||
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||
mListView.setMultiChoiceModeListener(this);
|
||||
reloadHostMappings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
|
||||
mode.getMenuInflater().inflate(R.menu.action_multi_select_items, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
|
||||
updateTitle(mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.delete: {
|
||||
final SharedPreferences.Editor editor = mHostMapping.edit();
|
||||
final SparseBooleanArray array = mListView.getCheckedItemPositions();
|
||||
if (array == null) return false;
|
||||
for (int i = 0, size = array.size(); i < size; i++) {
|
||||
if (array.valueAt(i)) {
|
||||
editor.remove(mAdapter.getItem(i));
|
||||
}
|
||||
}
|
||||
editor.apply();
|
||||
reloadHostMappings();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mode.finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(final ActionMode mode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_host_mapping, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||
final String host = mAdapter.getItem(position);
|
||||
final String address = mAdapter.getAddress(host);
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(EXTRA_HOST, host);
|
||||
args.putString(EXTRA_ADDRESS, address);
|
||||
args.putBoolean(EXTRA_EXCLUDED, StringUtils.equals(host, address));
|
||||
args.putBoolean(EXTRA_EDIT_MODE, true);
|
||||
final DialogFragment df = new AddMappingDialogFragment();
|
||||
df.setArguments(args);
|
||||
df.show(getFragmentManager(), "add_mapping");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.add: {
|
||||
final DialogFragment df = new AddMappingDialogFragment();
|
||||
df.show(getFragmentManager(), "add_mapping");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemCheckedStateChanged(final ActionMode mode, final int position, final long id,
|
||||
final boolean checked) {
|
||||
updateTitle(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
|
||||
reloadHostMappings();
|
||||
}
|
||||
|
||||
public void reloadHostMappings() {
|
||||
if (mAdapter == null) return;
|
||||
mAdapter.reload();
|
||||
}
|
||||
|
||||
private void updateTitle(final ActionMode mode) {
|
||||
if (mListView == null || mode == null || getActivity() == null) return;
|
||||
final int count = mListView.getCheckedItemCount();
|
||||
mode.setTitle(getResources().getQuantityString(R.plurals.Nitems_selected, count, count));
|
||||
}
|
||||
|
||||
public static class AddMappingDialogFragment extends BaseDialogFragment implements OnClickListener,
|
||||
TextWatcher, OnCheckedChangeListener {
|
||||
|
||||
|
||||
private EditText mEditHost, mEditAddress;
|
||||
private CheckBox mCheckExclude;
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
updateButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
updateAddressField();
|
||||
updateButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_POSITIVE: {
|
||||
final String host = ParseUtils.parseString(mEditHost.getText());
|
||||
final String address = mCheckExclude.isChecked() ? host : ParseUtils.parseString(mEditAddress.getText());
|
||||
if (isEmpty(host) || isEmpty(address)) return;
|
||||
final SharedPreferences prefs = getContext().getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
final SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(host, address);
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setView(R.layout.dialog_host_mapping);
|
||||
builder.setTitle(R.string.add_host_mapping);
|
||||
builder.setPositiveButton(android.R.string.ok, this);
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
final AlertDialog dialog = builder.create();
|
||||
dialog.setOnShowListener(new OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialog) {
|
||||
AlertDialog alertDialog = (AlertDialog) dialog;
|
||||
mEditHost = (EditText) alertDialog.findViewById(R.id.host);
|
||||
mEditAddress = (EditText) alertDialog.findViewById(R.id.address);
|
||||
mCheckExclude = (CheckBox) alertDialog.findViewById(R.id.exclude);
|
||||
mEditHost.addTextChangedListener(AddMappingDialogFragment.this);
|
||||
mEditAddress.addTextChangedListener(AddMappingDialogFragment.this);
|
||||
mCheckExclude.setOnCheckedChangeListener(AddMappingDialogFragment.this);
|
||||
final Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
mEditHost.setEnabled(!args.getBoolean(EXTRA_EDIT_MODE, false));
|
||||
if (savedInstanceState == null) {
|
||||
mEditHost.setText(args.getCharSequence(EXTRA_HOST));
|
||||
mEditAddress.setText(args.getCharSequence(EXTRA_ADDRESS));
|
||||
mCheckExclude.setChecked(args.getBoolean(EXTRA_EXCLUDED));
|
||||
}
|
||||
}
|
||||
updateButton();
|
||||
}
|
||||
});
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||
outState.putCharSequence(EXTRA_HOST, mEditHost.getText());
|
||||
outState.putCharSequence(EXTRA_ADDRESS, mEditAddress.getText());
|
||||
outState.putCharSequence(EXTRA_EXCLUDED, mEditAddress.getText());
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
private void updateAddressField() {
|
||||
mEditAddress.setVisibility(mCheckExclude.isChecked() ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
private void updateButton() {
|
||||
final AlertDialog dialog = (AlertDialog) getDialog();
|
||||
if (dialog == null) return;
|
||||
final boolean hostValid = !isEmpty(mEditHost.getText());
|
||||
final boolean addressValid = !isEmpty(mEditAddress.getText()) || mCheckExclude.isChecked();
|
||||
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
positiveButton.setEnabled(hostValid && addressValid);
|
||||
}
|
||||
}
|
||||
|
||||
static class HostMappingAdapter extends ArrayAdapter<String> {
|
||||
|
||||
private final SharedPreferences mHostMapping;
|
||||
|
||||
public HostMappingAdapter(final Context context) {
|
||||
super(context, android.R.layout.simple_list_item_activated_2);
|
||||
mHostMapping = context.getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, final View convertView, final ViewGroup parent) {
|
||||
final View view = super.getView(position, convertView, parent);
|
||||
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
|
||||
final TextView text2 = (TextView) view.findViewById(android.R.id.text2);
|
||||
final String key = getItem(position);
|
||||
text1.setText(key);
|
||||
final String value = getAddress(key);
|
||||
if (StringUtils.equals(key, value)) {
|
||||
text2.setText(R.string.excluded);
|
||||
} else {
|
||||
text2.setText(value);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
clear();
|
||||
final Map<String, ?> all = mHostMapping.getAll();
|
||||
addAll(all.keySet());
|
||||
}
|
||||
|
||||
public String getAddress(String key) {
|
||||
return mHostMapping.getString(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.DialogInterface.OnClickListener
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.text.Editable
|
||||
import android.text.TextUtils.isEmpty
|
||||
import android.text.TextWatcher
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import android.widget.AbsListView.MultiChoiceModeListener
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.HOST_MAPPING_PREFERENCES_NAME
|
||||
import org.mariotaku.twidere.adapter.ArrayAdapter
|
||||
import org.mariotaku.twidere.util.ParseUtils
|
||||
import org.mariotaku.twidere.util.SharedPreferencesWrapper
|
||||
|
||||
class HostMappingsListFragment : BaseListFragment(), MultiChoiceModeListener, OnSharedPreferenceChangeListener {
|
||||
|
||||
private var mAdapter: HostMappingAdapter? = null
|
||||
private var mHostMapping: SharedPreferencesWrapper? = null
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mHostMapping = SharedPreferencesWrapper.getInstance(activity,
|
||||
Constants.HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
mHostMapping!!.registerOnSharedPreferenceChangeListener(this)
|
||||
mAdapter = HostMappingAdapter(activity)
|
||||
listAdapter = mAdapter
|
||||
listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
|
||||
listView.setMultiChoiceModeListener(this)
|
||||
reloadHostMappings()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.action_multi_select_items, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
updateTitle(mode)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.delete -> {
|
||||
val editor = mHostMapping!!.edit()
|
||||
val array = listView!!.checkedItemPositions ?: return false
|
||||
var i = 0
|
||||
val size = array.size()
|
||||
while (i < size) {
|
||||
if (array.valueAt(i)) {
|
||||
editor.remove(mAdapter!!.getItem(i))
|
||||
}
|
||||
i++
|
||||
}
|
||||
editor.apply()
|
||||
reloadHostMappings()
|
||||
}
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
mode.finish()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode) {
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||
inflater!!.inflate(R.menu.menu_host_mapping, menu)
|
||||
}
|
||||
|
||||
override fun onListItemClick(l: ListView?, v: View?, position: Int, id: Long) {
|
||||
val host = mAdapter!!.getItem(position)
|
||||
val address = mAdapter!!.getAddress(host)
|
||||
val args = Bundle()
|
||||
args.putString(EXTRA_HOST, host)
|
||||
args.putString(EXTRA_ADDRESS, address)
|
||||
args.putBoolean(EXTRA_EXCLUDED, StringUtils.equals(host, address))
|
||||
args.putBoolean(EXTRA_EDIT_MODE, true)
|
||||
val df = AddMappingDialogFragment()
|
||||
df.arguments = args
|
||||
df.show(fragmentManager, "add_mapping")
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
when (item!!.itemId) {
|
||||
R.id.add -> {
|
||||
val df = AddMappingDialogFragment()
|
||||
df.show(fragmentManager, "add_mapping")
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onItemCheckedStateChanged(mode: ActionMode, position: Int, id: Long,
|
||||
checked: Boolean) {
|
||||
updateTitle(mode)
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
reloadHostMappings()
|
||||
}
|
||||
|
||||
fun reloadHostMappings() {
|
||||
if (mAdapter == null) return
|
||||
mAdapter!!.reload()
|
||||
}
|
||||
|
||||
private fun updateTitle(mode: ActionMode?) {
|
||||
if (listView == null || mode == null || activity == null) return
|
||||
val count = listView!!.checkedItemCount
|
||||
mode.title = resources.getQuantityString(R.plurals.Nitems_selected, count, count)
|
||||
}
|
||||
|
||||
class AddMappingDialogFragment : BaseDialogFragment(), OnClickListener, TextWatcher, OnCheckedChangeListener {
|
||||
|
||||
|
||||
private var mEditHost: EditText? = null
|
||||
private var mEditAddress: EditText? = null
|
||||
private var mCheckExclude: CheckBox? = null
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
updateButton()
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
|
||||
updateAddressField()
|
||||
updateButton()
|
||||
}
|
||||
|
||||
override fun onClick(dialog: DialogInterface, which: Int) {
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
val host = ParseUtils.parseString(mEditHost!!.text)
|
||||
val address = if (mCheckExclude!!.isChecked) host else ParseUtils.parseString(mEditAddress!!.text)
|
||||
if (isEmpty(host) || isEmpty(address)) return
|
||||
val prefs = context.getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE)
|
||||
val editor = prefs.edit()
|
||||
editor.putString(host, address)
|
||||
editor.apply()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val context = activity
|
||||
val builder = AlertDialog.Builder(context)
|
||||
builder.setView(R.layout.dialog_host_mapping)
|
||||
builder.setTitle(R.string.add_host_mapping)
|
||||
builder.setPositiveButton(android.R.string.ok, this)
|
||||
builder.setNegativeButton(android.R.string.cancel, null)
|
||||
val dialog = builder.create()
|
||||
dialog.setOnShowListener { dialog ->
|
||||
val alertDialog = dialog as AlertDialog
|
||||
mEditHost = alertDialog.findViewById(R.id.host) as EditText?
|
||||
mEditAddress = alertDialog.findViewById(R.id.address) as EditText?
|
||||
mCheckExclude = alertDialog.findViewById(R.id.exclude) as CheckBox?
|
||||
mEditHost!!.addTextChangedListener(this@AddMappingDialogFragment)
|
||||
mEditAddress!!.addTextChangedListener(this@AddMappingDialogFragment)
|
||||
mCheckExclude!!.setOnCheckedChangeListener(this@AddMappingDialogFragment)
|
||||
val args = arguments
|
||||
if (args != null) {
|
||||
mEditHost!!.isEnabled = !args.getBoolean(EXTRA_EDIT_MODE, false)
|
||||
if (savedInstanceState == null) {
|
||||
mEditHost!!.setText(args.getCharSequence(EXTRA_HOST))
|
||||
mEditAddress!!.setText(args.getCharSequence(EXTRA_ADDRESS))
|
||||
mCheckExclude!!.isChecked = args.getBoolean(EXTRA_EXCLUDED)
|
||||
}
|
||||
}
|
||||
updateButton()
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putCharSequence(EXTRA_HOST, mEditHost!!.text)
|
||||
outState.putCharSequence(EXTRA_ADDRESS, mEditAddress!!.text)
|
||||
outState.putCharSequence(EXTRA_EXCLUDED, mEditAddress!!.text)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
private fun updateAddressField() {
|
||||
mEditAddress!!.visibility = if (mCheckExclude!!.isChecked) View.GONE else View.VISIBLE
|
||||
}
|
||||
|
||||
private fun updateButton() {
|
||||
val dialog = dialog as AlertDialog ?: return
|
||||
val hostValid = !isEmpty(mEditHost!!.text)
|
||||
val addressValid = !isEmpty(mEditAddress!!.text) || mCheckExclude!!.isChecked
|
||||
val positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE)
|
||||
positiveButton.isEnabled = hostValid && addressValid
|
||||
}
|
||||
}
|
||||
|
||||
internal class HostMappingAdapter(context: Context) : ArrayAdapter<String>(context, android.R.layout.simple_list_item_activated_2) {
|
||||
|
||||
private val mHostMapping: SharedPreferences
|
||||
|
||||
init {
|
||||
mHostMapping = context.getSharedPreferences(Constants.HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
override fun getView(position: Int, convertView: View, parent: ViewGroup): View {
|
||||
val view = super.getView(position, convertView, parent)
|
||||
val text1 = view.findViewById(android.R.id.text1) as TextView
|
||||
val text2 = view.findViewById(android.R.id.text2) as TextView
|
||||
val key = getItem(position)
|
||||
text1.text = key
|
||||
val value = getAddress(key)
|
||||
if (StringUtils.equals(key, value)) {
|
||||
text2.setText(R.string.excluded)
|
||||
} else {
|
||||
text2.text = value
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
fun reload() {
|
||||
clear()
|
||||
val all = mHostMapping.all
|
||||
addAll(all.keys)
|
||||
}
|
||||
|
||||
fun getAddress(key: String): String {
|
||||
return mHostMapping.getString(key, null)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val EXTRA_EDIT_MODE = "edit_mode"
|
||||
private val EXTRA_HOST = "host"
|
||||
private val EXTRA_ADDRESS = "address"
|
||||
private val EXTRA_EXCLUDED = "excluded"
|
||||
}
|
||||
|
||||
}
|
@ -324,7 +324,7 @@ class MessagesConversationFragment : BaseSupportFragment(), LoaderCallbacks<Curs
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu?) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.delete_all, recipient != null && Utils.isOfficialCredentials(activity, account!!))
|
||||
MenuUtils.setItemAvailability(menu, R.id.delete_all, recipient != null && Utils.isOfficialCredentials(activity, account!!))
|
||||
updateRecipientInfo()
|
||||
}
|
||||
|
||||
|
@ -1,365 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CheckResult;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.PopupMenu;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.Gravity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.twitter.Validator;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.DummyItemAdapter;
|
||||
import org.mariotaku.twidere.model.Draft;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableCredentials;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
|
||||
import org.mariotaku.twidere.model.util.ParcelableAccountUtils;
|
||||
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
|
||||
import org.mariotaku.twidere.service.BackgroundOperationService;
|
||||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
import org.mariotaku.twidere.util.EditTextEnterHandler;
|
||||
import org.mariotaku.twidere.util.LinkCreator;
|
||||
import org.mariotaku.twidere.util.MenuUtils;
|
||||
import org.mariotaku.twidere.util.TwidereBugReporter;
|
||||
import org.mariotaku.twidere.util.TwidereValidator;
|
||||
import org.mariotaku.twidere.view.ComposeEditText;
|
||||
import org.mariotaku.twidere.view.StatusTextCountView;
|
||||
import org.mariotaku.twidere.view.holder.StatusViewHolder;
|
||||
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
|
||||
|
||||
import static org.mariotaku.twidere.util.Utils.isMyRetweet;
|
||||
|
||||
public class RetweetQuoteDialogFragment extends BaseDialogFragment {
|
||||
|
||||
public static final String FRAGMENT_TAG = "retweet_quote";
|
||||
private static final boolean SHOW_PROTECTED_CONFIRM = Boolean.parseBoolean("false");
|
||||
private PopupMenu mPopupMenu;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
final Context context = builder.getContext();
|
||||
final ParcelableStatus status = getStatus();
|
||||
assert status != null;
|
||||
final ParcelableCredentials credentials = ParcelableCredentialsUtils.getCredentials(getContext(),
|
||||
status.account_key);
|
||||
assert credentials != null;
|
||||
|
||||
builder.setView(R.layout.dialog_status_quote_retweet);
|
||||
builder.setTitle(R.string.retweet_quote_confirm_title);
|
||||
builder.setPositiveButton(R.string.retweet, null);
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.setNeutralButton(R.string.quote, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final Intent intent = new Intent(INTENT_ACTION_QUOTE);
|
||||
final Menu menu = mPopupMenu.getMenu();
|
||||
final MenuItem quoteOriginalStatus = menu.findItem(R.id.quote_original_status);
|
||||
intent.putExtra(EXTRA_STATUS, status);
|
||||
intent.putExtra(EXTRA_QUOTE_ORIGINAL_STATUS, quoteOriginalStatus.isChecked());
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
final Dialog dialog = builder.create();
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialogInterface) {
|
||||
final AlertDialog dialog = (AlertDialog) dialogInterface;
|
||||
|
||||
|
||||
final View itemContent = dialog.findViewById(R.id.itemContent);
|
||||
final StatusTextCountView textCountView = (StatusTextCountView) dialog.findViewById(R.id.comment_text_count);
|
||||
final View itemMenu = dialog.findViewById(R.id.itemMenu);
|
||||
final View actionButtons = dialog.findViewById(R.id.actionButtons);
|
||||
final View commentContainer = dialog.findViewById(R.id.comment_container);
|
||||
final ComposeEditText editComment = (ComposeEditText) dialog.findViewById(R.id.edit_comment);
|
||||
final View commentMenu = dialog.findViewById(R.id.comment_menu);
|
||||
assert itemContent != null && textCountView != null && itemMenu != null
|
||||
&& actionButtons != null && commentContainer != null && editComment != null
|
||||
&& commentMenu != null;
|
||||
|
||||
final DummyItemAdapter adapter = new DummyItemAdapter(context);
|
||||
adapter.setShouldShowAccountsColor(true);
|
||||
final IStatusViewHolder holder = new StatusViewHolder(adapter, itemContent);
|
||||
holder.displayStatus(status, false, true);
|
||||
|
||||
textCountView.setMaxLength(TwidereValidator.getTextLimit(credentials));
|
||||
|
||||
itemMenu.setVisibility(View.GONE);
|
||||
actionButtons.setVisibility(View.GONE);
|
||||
itemContent.setFocusable(false);
|
||||
final boolean useQuote = useQuote(!status.user_is_protected, credentials);
|
||||
|
||||
commentContainer.setVisibility(useQuote ? View.VISIBLE : View.GONE);
|
||||
editComment.setAccountKey(status.account_key);
|
||||
|
||||
final boolean sendByEnter = preferences.getBoolean(KEY_QUICK_SEND);
|
||||
final EditTextEnterHandler enterHandler = EditTextEnterHandler.attach(editComment, new EditTextEnterHandler.EnterListener() {
|
||||
@Override
|
||||
public boolean shouldCallListener() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHitEnter() {
|
||||
final ParcelableStatus status = getStatus();
|
||||
if (status == null) return false;
|
||||
if (retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM)) {
|
||||
dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, sendByEnter);
|
||||
enterHandler.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
updateTextCount(getDialog(), s, status, credentials);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
mPopupMenu = new PopupMenu(context, commentMenu, Gravity.NO_GRAVITY,
|
||||
R.attr.actionOverflowMenuStyle, 0);
|
||||
commentMenu.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mPopupMenu.show();
|
||||
}
|
||||
});
|
||||
commentMenu.setOnTouchListener(mPopupMenu.getDragToOpenListener());
|
||||
mPopupMenu.inflate(R.menu.menu_dialog_comment);
|
||||
final Menu menu = mPopupMenu.getMenu();
|
||||
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.quote_original_status,
|
||||
status.retweet_id != null || status.quoted_id != null);
|
||||
mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.isCheckable()) {
|
||||
item.setChecked(!item.isChecked());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean dismissDialog = false;
|
||||
if (editComment.length() > 0) {
|
||||
dismissDialog = retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM);
|
||||
} else if (isMyRetweet(status)) {
|
||||
twitterWrapper.cancelRetweetAsync(status.account_key, status.id, status.my_retweet_id);
|
||||
dismissDialog = true;
|
||||
} else if (useQuote(!status.user_is_protected, credentials)) {
|
||||
dismissDialog = retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM);
|
||||
} else {
|
||||
TwidereBugReporter.logException(new IllegalStateException(status.toString()));
|
||||
}
|
||||
if (dismissDialog) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateTextCount(dialog, editComment.getText(), status, credentials);
|
||||
}
|
||||
});
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private void updateTextCount(DialogInterface dialog, CharSequence s, ParcelableStatus status, ParcelableCredentials credentials) {
|
||||
if (!(dialog instanceof AlertDialog)) return;
|
||||
final AlertDialog alertDialog = (AlertDialog) dialog;
|
||||
final Button positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
if (positiveButton == null) return;
|
||||
if (s.length() > 0) {
|
||||
positiveButton.setText(R.string.comment);
|
||||
positiveButton.setEnabled(true);
|
||||
} else if (isMyRetweet(status)) {
|
||||
positiveButton.setText(R.string.cancel_retweet);
|
||||
positiveButton.setEnabled(true);
|
||||
} else if (useQuote(false, credentials)) {
|
||||
positiveButton.setText(R.string.retweet);
|
||||
positiveButton.setEnabled(true);
|
||||
} else {
|
||||
positiveButton.setText(R.string.retweet);
|
||||
positiveButton.setEnabled(!status.user_is_protected);
|
||||
}
|
||||
final StatusTextCountView textCountView = (StatusTextCountView) alertDialog.findViewById(R.id.comment_text_count);
|
||||
assert textCountView != null;
|
||||
textCountView.setTextCount(validator.getTweetLength(s.toString()));
|
||||
}
|
||||
|
||||
private ParcelableStatus getStatus() {
|
||||
final Bundle args = getArguments();
|
||||
if (!args.containsKey(EXTRA_STATUS)) return null;
|
||||
return args.getParcelable(EXTRA_STATUS);
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
private boolean retweetOrQuote(ParcelableAccount account, ParcelableStatus status,
|
||||
boolean showProtectedConfirmation) {
|
||||
AsyncTwitterWrapper twitter = twitterWrapper;
|
||||
final Dialog dialog = getDialog();
|
||||
if (dialog == null || twitter == null) return false;
|
||||
final EditText editComment = (EditText) dialog.findViewById(R.id.edit_comment);
|
||||
if (useQuote(editComment.length() > 0, account)) {
|
||||
final Menu menu = mPopupMenu.getMenu();
|
||||
final MenuItem itemQuoteOriginalStatus = menu.findItem(R.id.quote_original_status);
|
||||
final Uri statusLink;
|
||||
final boolean quoteOriginalStatus = itemQuoteOriginalStatus.isChecked();
|
||||
|
||||
String commentText;
|
||||
final ParcelableStatusUpdate update = new ParcelableStatusUpdate();
|
||||
update.accounts = new ParcelableAccount[]{account};
|
||||
final String editingComment = String.valueOf(editComment.getText());
|
||||
switch (ParcelableAccountUtils.getAccountType(account)) {
|
||||
case ParcelableAccount.Type.FANFOU: {
|
||||
if (!status.is_quote || !quoteOriginalStatus) {
|
||||
if (status.user_is_protected && showProtectedConfirmation) {
|
||||
QuoteProtectedStatusWarnFragment.show(this, account, status);
|
||||
return false;
|
||||
}
|
||||
update.repost_status_id = status.id;
|
||||
commentText = getString(R.string.fanfou_repost_format, editingComment,
|
||||
status.user_screen_name, status.text_plain);
|
||||
} else {
|
||||
if (status.quoted_user_is_protected && showProtectedConfirmation) {
|
||||
return false;
|
||||
}
|
||||
commentText = getString(R.string.fanfou_repost_format, editingComment,
|
||||
status.quoted_user_screen_name, status.quoted_text_plain);
|
||||
update.repost_status_id = status.quoted_id;
|
||||
}
|
||||
if (commentText.length() > Validator.MAX_TWEET_LENGTH) {
|
||||
commentText = commentText.substring(0, Math.max(Validator.MAX_TWEET_LENGTH,
|
||||
editingComment.length()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (!status.is_quote || !quoteOriginalStatus) {
|
||||
statusLink = LinkCreator.getStatusWebLink(status);
|
||||
} else {
|
||||
statusLink = LinkCreator.getQuotedStatusWebLink(status);
|
||||
}
|
||||
update.attachment_url = statusLink.toString();
|
||||
commentText = editingComment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
update.text = commentText;
|
||||
update.is_possibly_sensitive = status.is_possibly_sensitive;
|
||||
BackgroundOperationService.updateStatusesAsync(getContext(), Draft.Action.QUOTE, update);
|
||||
} else {
|
||||
twitter.retweetStatusAsync(status.account_key, status.id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean useQuote(boolean preCondition, ParcelableAccount account) {
|
||||
return preCondition || ParcelableAccount.Type.FANFOU.equals(account.account_type);
|
||||
}
|
||||
|
||||
public static RetweetQuoteDialogFragment show(final FragmentManager fm, final ParcelableStatus status) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putParcelable(EXTRA_STATUS, status);
|
||||
final RetweetQuoteDialogFragment f = new RetweetQuoteDialogFragment();
|
||||
f.setArguments(args);
|
||||
f.show(fm, FRAGMENT_TAG);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
public static class QuoteProtectedStatusWarnFragment extends BaseDialogFragment implements
|
||||
DialogInterface.OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
final RetweetQuoteDialogFragment fragment = (RetweetQuoteDialogFragment) getParentFragment();
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_POSITIVE: {
|
||||
final Bundle args = getArguments();
|
||||
ParcelableAccount account = args.getParcelable(EXTRA_ACCOUNT);
|
||||
ParcelableStatus status = args.getParcelable(EXTRA_STATUS);
|
||||
if (fragment.retweetOrQuote(account, status, false)) {
|
||||
fragment.dismiss();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setMessage(R.string.quote_protected_status_warning_message);
|
||||
builder.setPositiveButton(R.string.send_anyway, this);
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public static QuoteProtectedStatusWarnFragment show(RetweetQuoteDialogFragment pf,
|
||||
ParcelableAccount account,
|
||||
ParcelableStatus status) {
|
||||
QuoteProtectedStatusWarnFragment f = new QuoteProtectedStatusWarnFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(EXTRA_ACCOUNT, account);
|
||||
args.putParcelable(EXTRA_STATUS, status);
|
||||
f.setArguments(args);
|
||||
f.show(pf.getChildFragmentManager(), "quote_protected_status_warning");
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.fragment
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.CheckResult
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.widget.PopupMenu
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import com.twitter.Validator
|
||||
import org.mariotaku.ktextension.setItemAvailability
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.adapter.DummyItemAdapter
|
||||
import org.mariotaku.twidere.constant.IntentConstants.*
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_QUICK_SEND
|
||||
import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.util.ParcelableAccountUtils
|
||||
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils
|
||||
import org.mariotaku.twidere.service.BackgroundOperationService
|
||||
import org.mariotaku.twidere.util.EditTextEnterHandler
|
||||
import org.mariotaku.twidere.util.LinkCreator
|
||||
import org.mariotaku.twidere.util.TwidereBugReporter
|
||||
import org.mariotaku.twidere.util.TwidereValidator
|
||||
import org.mariotaku.twidere.util.Utils.isMyRetweet
|
||||
import org.mariotaku.twidere.view.ComposeEditText
|
||||
import org.mariotaku.twidere.view.StatusTextCountView
|
||||
import org.mariotaku.twidere.view.holder.StatusViewHolder
|
||||
|
||||
class RetweetQuoteDialogFragment : BaseDialogFragment() {
|
||||
private var popupMenu: PopupMenu? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val builder = AlertDialog.Builder(context)
|
||||
val context = builder.context
|
||||
val status = status!!
|
||||
val credentials = ParcelableCredentialsUtils.getCredentials(getContext(),
|
||||
status.account_key)!!
|
||||
|
||||
builder.setView(R.layout.dialog_status_quote_retweet)
|
||||
builder.setTitle(R.string.retweet_quote_confirm_title)
|
||||
builder.setPositiveButton(R.string.retweet, null)
|
||||
builder.setNegativeButton(android.R.string.cancel, null)
|
||||
builder.setNeutralButton(R.string.quote) { dialog, which ->
|
||||
val intent = Intent(INTENT_ACTION_QUOTE)
|
||||
val menu = popupMenu!!.menu
|
||||
val quoteOriginalStatus = menu.findItem(R.id.quote_original_status)
|
||||
intent.putExtra(EXTRA_STATUS, status)
|
||||
intent.putExtra(EXTRA_QUOTE_ORIGINAL_STATUS, quoteOriginalStatus.isChecked)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
val dialog = builder.create()
|
||||
dialog.setOnShowListener {
|
||||
val alertDialog = it as AlertDialog
|
||||
|
||||
val itemContent = alertDialog.findViewById(R.id.itemContent)
|
||||
val textCountView = alertDialog.findViewById(R.id.comment_text_count) as StatusTextCountView?
|
||||
val itemMenu = alertDialog.findViewById(R.id.itemMenu)
|
||||
val actionButtons = alertDialog.findViewById(R.id.actionButtons)
|
||||
val commentContainer = alertDialog.findViewById(R.id.comment_container)
|
||||
val editComment = alertDialog.findViewById(R.id.edit_comment) as ComposeEditText?
|
||||
val commentMenu = alertDialog.findViewById(R.id.comment_menu)
|
||||
assert(itemContent != null && textCountView != null && itemMenu != null
|
||||
&& actionButtons != null && commentContainer != null && editComment != null
|
||||
&& commentMenu != null)
|
||||
|
||||
val adapter = DummyItemAdapter(context)
|
||||
adapter.setShouldShowAccountsColor(true)
|
||||
val holder = StatusViewHolder(adapter, itemContent!!)
|
||||
holder.displayStatus(status, false, true)
|
||||
|
||||
textCountView!!.maxLength = TwidereValidator.getTextLimit(credentials)
|
||||
|
||||
itemMenu!!.visibility = View.GONE
|
||||
actionButtons!!.visibility = View.GONE
|
||||
itemContent.isFocusable = false
|
||||
val useQuote = useQuote(!status.user_is_protected, credentials)
|
||||
|
||||
commentContainer!!.visibility = if (useQuote) View.VISIBLE else View.GONE
|
||||
editComment!!.setAccountKey(status.account_key)
|
||||
|
||||
val sendByEnter = preferences.getBoolean(KEY_QUICK_SEND)
|
||||
val enterHandler = EditTextEnterHandler.attach(editComment, object : EditTextEnterHandler.EnterListener {
|
||||
override fun shouldCallListener(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onHitEnter(): Boolean {
|
||||
if (retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM)) {
|
||||
dismiss()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}, sendByEnter)
|
||||
enterHandler.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
updateTextCount(getDialog(), s, status, credentials)
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
popupMenu = PopupMenu(context, commentMenu!!, Gravity.NO_GRAVITY,
|
||||
R.attr.actionOverflowMenuStyle, 0)
|
||||
commentMenu.setOnClickListener(View.OnClickListener { popupMenu!!.show() })
|
||||
commentMenu.setOnTouchListener(popupMenu!!.dragToOpenListener)
|
||||
popupMenu!!.inflate(R.menu.menu_dialog_comment)
|
||||
val menu = popupMenu!!.menu
|
||||
menu.setItemAvailability(R.id.quote_original_status,
|
||||
status.retweet_id != null || status.quoted_id != null)
|
||||
popupMenu!!.setOnMenuItemClickListener(PopupMenu.OnMenuItemClickListener { item ->
|
||||
if (item.isCheckable) {
|
||||
item.isChecked = !item.isChecked
|
||||
return@OnMenuItemClickListener true
|
||||
}
|
||||
false
|
||||
})
|
||||
|
||||
alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
|
||||
var dismissDialog = false
|
||||
if (editComment.length() > 0) {
|
||||
dismissDialog = retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM)
|
||||
} else if (isMyRetweet(status)) {
|
||||
twitterWrapper.cancelRetweetAsync(status.account_key, status.id, status.my_retweet_id)
|
||||
dismissDialog = true
|
||||
} else if (useQuote(!status.user_is_protected, credentials)) {
|
||||
dismissDialog = retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM)
|
||||
} else {
|
||||
TwidereBugReporter.logException(IllegalStateException(status.toString()))
|
||||
}
|
||||
if (dismissDialog) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
updateTextCount(alertDialog, editComment.text, status, credentials)
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun updateTextCount(dialog: DialogInterface, s: CharSequence, status: ParcelableStatus, credentials: ParcelableCredentials) {
|
||||
if (dialog !is AlertDialog) return
|
||||
val positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE) ?: return
|
||||
if (s.length > 0) {
|
||||
positiveButton.setText(R.string.comment)
|
||||
positiveButton.isEnabled = true
|
||||
} else if (isMyRetweet(status)) {
|
||||
positiveButton.setText(R.string.cancel_retweet)
|
||||
positiveButton.isEnabled = true
|
||||
} else if (useQuote(false, credentials)) {
|
||||
positiveButton.setText(R.string.retweet)
|
||||
positiveButton.isEnabled = true
|
||||
} else {
|
||||
positiveButton.setText(R.string.retweet)
|
||||
positiveButton.isEnabled = !status.user_is_protected
|
||||
}
|
||||
val textCountView = (dialog.findViewById(R.id.comment_text_count) as StatusTextCountView?)!!
|
||||
textCountView.textCount = validator.getTweetLength(s.toString())
|
||||
}
|
||||
|
||||
private val status: ParcelableStatus?
|
||||
get() {
|
||||
val args = arguments
|
||||
if (!args.containsKey(EXTRA_STATUS)) return null
|
||||
return args.getParcelable<ParcelableStatus>(EXTRA_STATUS)
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
private fun retweetOrQuote(account: ParcelableAccount, status: ParcelableStatus,
|
||||
showProtectedConfirmation: Boolean): Boolean {
|
||||
val twitter = twitterWrapper
|
||||
val dialog = dialog ?: return false
|
||||
val editComment = dialog.findViewById(R.id.edit_comment) as EditText
|
||||
if (useQuote(editComment.length() > 0, account)) {
|
||||
val menu = popupMenu!!.menu
|
||||
val itemQuoteOriginalStatus = menu.findItem(R.id.quote_original_status)
|
||||
val statusLink: Uri
|
||||
val quoteOriginalStatus = itemQuoteOriginalStatus.isChecked
|
||||
|
||||
var commentText: String
|
||||
val update = ParcelableStatusUpdate()
|
||||
update.accounts = arrayOf(account)
|
||||
val editingComment = editComment.text.toString()
|
||||
when (ParcelableAccountUtils.getAccountType(account)) {
|
||||
ParcelableAccount.Type.FANFOU -> {
|
||||
if (!status.is_quote || !quoteOriginalStatus) {
|
||||
if (status.user_is_protected && showProtectedConfirmation) {
|
||||
QuoteProtectedStatusWarnFragment.show(this, account, status)
|
||||
return false
|
||||
}
|
||||
update.repost_status_id = status.id
|
||||
commentText = getString(R.string.fanfou_repost_format, editingComment,
|
||||
status.user_screen_name, status.text_plain)
|
||||
} else {
|
||||
if (status.quoted_user_is_protected && showProtectedConfirmation) {
|
||||
return false
|
||||
}
|
||||
commentText = getString(R.string.fanfou_repost_format, editingComment,
|
||||
status.quoted_user_screen_name, status.quoted_text_plain)
|
||||
update.repost_status_id = status.quoted_id
|
||||
}
|
||||
if (commentText.length > Validator.MAX_TWEET_LENGTH) {
|
||||
commentText = commentText.substring(0, Math.max(Validator.MAX_TWEET_LENGTH,
|
||||
editingComment.length))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
if (!status.is_quote || !quoteOriginalStatus) {
|
||||
statusLink = LinkCreator.getStatusWebLink(status)
|
||||
} else {
|
||||
statusLink = LinkCreator.getQuotedStatusWebLink(status)
|
||||
}
|
||||
update.attachment_url = statusLink.toString()
|
||||
commentText = editingComment
|
||||
}
|
||||
}
|
||||
update.text = commentText
|
||||
update.is_possibly_sensitive = status.is_possibly_sensitive
|
||||
BackgroundOperationService.updateStatusesAsync(context, Draft.Action.QUOTE, update)
|
||||
} else {
|
||||
twitter.retweetStatusAsync(status.account_key, status.id)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun useQuote(preCondition: Boolean, account: ParcelableAccount): Boolean {
|
||||
return preCondition || ParcelableAccount.Type.FANFOU == account.account_type
|
||||
}
|
||||
|
||||
|
||||
class QuoteProtectedStatusWarnFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
|
||||
|
||||
override fun onClick(dialog: DialogInterface, which: Int) {
|
||||
val fragment = parentFragment as RetweetQuoteDialogFragment
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
val args = arguments
|
||||
val account = args.getParcelable<ParcelableAccount>(EXTRA_ACCOUNT)
|
||||
val status = args.getParcelable<ParcelableStatus>(EXTRA_STATUS)
|
||||
if (fragment.retweetOrQuote(account, status, false)) {
|
||||
fragment.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val context = activity
|
||||
val builder = AlertDialog.Builder(context)
|
||||
builder.setMessage(R.string.quote_protected_status_warning_message)
|
||||
builder.setPositiveButton(R.string.send_anyway, this)
|
||||
builder.setNegativeButton(android.R.string.cancel, null)
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun show(pf: RetweetQuoteDialogFragment,
|
||||
account: ParcelableAccount,
|
||||
status: ParcelableStatus): QuoteProtectedStatusWarnFragment {
|
||||
val f = QuoteProtectedStatusWarnFragment()
|
||||
val args = Bundle()
|
||||
args.putParcelable(EXTRA_ACCOUNT, account)
|
||||
args.putParcelable(EXTRA_STATUS, status)
|
||||
f.arguments = args
|
||||
f.show(pf.childFragmentManager, "quote_protected_status_warning")
|
||||
return f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val FRAGMENT_TAG = "retweet_quote"
|
||||
private val SHOW_PROTECTED_CONFIRM = java.lang.Boolean.parseBoolean("false")
|
||||
|
||||
fun show(fm: FragmentManager, status: ParcelableStatus): RetweetQuoteDialogFragment {
|
||||
val args = Bundle()
|
||||
args.putParcelable(EXTRA_STATUS, status)
|
||||
val f = RetweetQuoteDialogFragment()
|
||||
f.arguments = args
|
||||
f.show(fm, FRAGMENT_TAG)
|
||||
return f
|
||||
}
|
||||
}
|
||||
}
|
@ -459,7 +459,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu?) {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.current_status, adapter!!.status != null)
|
||||
MenuUtils.setItemAvailability(menu, R.id.current_status, adapter!!.status != null)
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
@ -753,7 +753,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
|
||||
val twitter = adapter.twitterWrapper
|
||||
val nameFirst = adapter.nameFirst
|
||||
|
||||
linkClickHandler.setStatus(status)
|
||||
linkClickHandler.status = status
|
||||
|
||||
if (status.retweet_id != null) {
|
||||
val retweetedBy = UserColorNameManager.decideDisplayName(status.retweet_user_nickname,
|
||||
@ -1357,11 +1357,14 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
|
||||
}
|
||||
}
|
||||
|
||||
private class DetailStatusLinkClickHandler(context: Context, manager: MultiSelectManager,
|
||||
private val adapter: StatusAdapter,
|
||||
preferences: SharedPreferencesWrapper) : StatusLinkClickHandler(context, manager, preferences) {
|
||||
private class DetailStatusLinkClickHandler(
|
||||
context: Context,
|
||||
manager: MultiSelectManager,
|
||||
private val adapter: StatusAdapter,
|
||||
preferences: SharedPreferencesWrapper
|
||||
) : StatusLinkClickHandler(context, manager, preferences) {
|
||||
|
||||
override fun onLinkClick(link: String, orig: String, accountKey: UserKey,
|
||||
override fun onLinkClick(link: String, orig: String?, accountKey: UserKey,
|
||||
extraId: Long, type: Int, sensitive: Boolean, start: Int, end: Int): Boolean {
|
||||
val current = getCurrentMedia(link, extraId.toInt())
|
||||
if (current != null && !current.open_browser) {
|
||||
|
@ -743,22 +743,22 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
||||
user.name, user.screen_name, mNameFirst)
|
||||
mentionItem.title = getString(R.string.mention_user_name, displayName)
|
||||
}
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.mention, !isMyself)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.incoming_friendships, isMyself)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.saved_searches, isMyself)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.scheduled_statuses, isMyself && MicroBlogAPIFactory.getOfficialKeyType(activity, user.account_key) == ConsumerKeyType.TWEETDECK)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.muted_users, isMyself)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.blocked_users, isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.mention, !isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.incoming_friendships, isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.saved_searches, isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.scheduled_statuses, isMyself && MicroBlogAPIFactory.getOfficialKeyType(activity, user.account_key) == ConsumerKeyType.TWEETDECK)
|
||||
MenuUtils.setItemAvailability(menu, R.id.muted_users, isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.blocked_users, isMyself)
|
||||
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.block, !isMyself)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.mute_user, !isMyself)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.report_spam, !isMyself)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.enable_retweets, !isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.block, !isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.mute_user, !isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.report_spam, !isMyself)
|
||||
MenuUtils.setItemAvailability(menu, R.id.enable_retweets, !isMyself)
|
||||
if (mAccount != null) {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.add_to_list, TextUtils.equals(ParcelableAccount.Type.TWITTER,
|
||||
MenuUtils.setItemAvailability(menu, R.id.add_to_list, TextUtils.equals(ParcelableAccount.Type.TWITTER,
|
||||
ParcelableAccountUtils.getAccountType(mAccount!!)))
|
||||
} else {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.add_to_list, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.add_to_list, false)
|
||||
}
|
||||
|
||||
val userRelationship = mRelationship
|
||||
@ -769,10 +769,10 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
||||
filterItem.isChecked = userRelationship.filtering
|
||||
}
|
||||
if (isMyself) {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.send_direct_message, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, false)
|
||||
} else {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.send_direct_message, userRelationship.can_dm)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.block, true)
|
||||
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, userRelationship.can_dm)
|
||||
MenuUtils.setItemAvailability(menu, R.id.block, true)
|
||||
val blockItem = menu.findItem(R.id.block)
|
||||
if (blockItem != null) {
|
||||
ActionIconDrawable.setMenuHighlight(blockItem, TwidereMenuInfo(userRelationship.blocking))
|
||||
@ -788,7 +788,7 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.send_direct_message, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, false)
|
||||
}
|
||||
val intent = Intent(INTENT_ACTION_EXTENSION_OPEN_USER)
|
||||
val extras = Bundle()
|
||||
|
@ -178,15 +178,15 @@ class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener, LoaderCa
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu?) {
|
||||
val userList = this.userList
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.info, userList != null)
|
||||
MenuUtils.setItemAvailability(menu, R.id.info, userList != null)
|
||||
menu!!.removeGroup(MENU_GROUP_USER_LIST_EXTENSION)
|
||||
if (userList != null) {
|
||||
val isMyList = userList.user_key == userList.account_key
|
||||
val isFollowing = userList.is_following
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.edit, isMyList)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.follow, !isMyList)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.add, isMyList)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.delete, isMyList)
|
||||
MenuUtils.setItemAvailability(menu, R.id.edit, isMyList)
|
||||
MenuUtils.setItemAvailability(menu, R.id.follow, !isMyList)
|
||||
MenuUtils.setItemAvailability(menu, R.id.add, isMyList)
|
||||
MenuUtils.setItemAvailability(menu, R.id.delete, isMyList)
|
||||
val followItem = menu.findItem(R.id.follow)
|
||||
if (isFollowing) {
|
||||
followItem.setIcon(R.drawable.ic_action_cancel)
|
||||
@ -200,10 +200,10 @@ class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener, LoaderCa
|
||||
extensionsIntent.putExtra(EXTRA_USER_LIST, userList)
|
||||
MenuUtils.addIntentToMenu(activity, menu, extensionsIntent, MENU_GROUP_USER_LIST_EXTENSION)
|
||||
} else {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.edit, false)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.follow, false)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.add, false)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.delete, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.edit, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.follow, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.add, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.delete, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,9 +73,9 @@ class UserListsFragment : ParcelableUserListsFragment() {
|
||||
val accountId = accountKey
|
||||
if (accountId == null || item == null) return
|
||||
if (accountId == userId) {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.new_user_list, true)
|
||||
MenuUtils.setItemAvailability(menu, R.id.new_user_list, true)
|
||||
} else {
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.new_user_list, Utils.isMyAccount(activity, screenName))
|
||||
MenuUtils.setItemAvailability(menu, R.id.new_user_list, Utils.isMyAccount(activity, screenName))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,11 +393,11 @@ class UserProfileEditorFragment : BaseSupportFragment(), OnSizeChangedListener,
|
||||
val account = result.extras.getParcelable<ParcelableAccount>(EXTRA_ACCOUNT)
|
||||
if (account != null) {
|
||||
val task = UpdateAccountInfoTask(activity)
|
||||
task.setParams(Pair(account, result.data))
|
||||
task.params = Pair(account, result.data)
|
||||
TaskStarter.execute(task)
|
||||
}
|
||||
}
|
||||
callback!!.executeAfterFragmentResumed { fragment ->
|
||||
callback?.executeAfterFragmentResumed { fragment ->
|
||||
val f = (fragment as UserProfileEditorFragment).fragmentManager.findFragmentByTag(DIALOG_FRAGMENT_TAG)
|
||||
if (f is DialogFragment) {
|
||||
f.dismissAllowingStateLoss()
|
||||
|
@ -192,7 +192,7 @@ public class CardPollFragment extends BaseSupportFragment implements
|
||||
return null;
|
||||
}
|
||||
};
|
||||
task.setResultHandler(CardPollFragment.this);
|
||||
task.setCallback(CardPollFragment.this);
|
||||
task.setParams(cardData);
|
||||
TaskStarter.execute(task);
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ public class BackgroundOperationService extends IntentService implements Constan
|
||||
|
||||
}
|
||||
});
|
||||
task.setResultHandler(this);
|
||||
task.setCallback(this);
|
||||
task.setParams(Pair.create(actionType, item));
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
|
@ -519,7 +519,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
}
|
||||
}
|
||||
}
|
||||
}.setResultHandler(bus));
|
||||
}.setCallback(bus));
|
||||
}
|
||||
|
||||
public void getActivitiesAboutMeAsync(final RefreshTaskParam param) {
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
|
||||
import org.mariotaku.twidere.fragment.PhishingLinkWarningDialogFragment;
|
||||
|
||||
import static org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME;
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_URI;
|
||||
import static org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_PHISHING_LINK_WARNING;
|
||||
|
||||
public class DirectMessageOnLinkClickHandler extends OnLinkClickHandler {
|
||||
|
||||
private static final String[] SHORT_LINK_SERVICES = new String[]{"bit.ly", "ow.ly", "tinyurl.com", "goo.gl",
|
||||
"k6.kz", "is.gd", "tr.im", "x.co", "weepp.ru"};
|
||||
|
||||
public DirectMessageOnLinkClickHandler(final Context context, final MultiSelectManager manager,
|
||||
SharedPreferencesWrapper preferences) {
|
||||
super(context, manager, preferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPrivateData() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openLink(final String link) {
|
||||
if (link == null || manager != null && manager.isActive()) return;
|
||||
if (!hasShortenedLinks(link)) {
|
||||
super.openLink(link);
|
||||
return;
|
||||
}
|
||||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
if (context instanceof FragmentActivity && prefs.getBoolean(KEY_PHISHING_LINK_WARNING, true)) {
|
||||
final FragmentManager fm = ((FragmentActivity) context).getSupportFragmentManager();
|
||||
final DialogFragment fragment = new PhishingLinkWarningDialogFragment();
|
||||
final Bundle args = new Bundle();
|
||||
args.putParcelable(EXTRA_URI, Uri.parse(link));
|
||||
fragment.setArguments(args);
|
||||
fragment.show(fm, "phishing_link_warning");
|
||||
} else {
|
||||
super.openLink(link);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean hasShortenedLinks(final String link) {
|
||||
for (final String shortLinkService : SHORT_LINK_SERVICES) {
|
||||
if (link.contains(shortLinkService)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_URI
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_PHISHING_LINK_WARNING
|
||||
import org.mariotaku.twidere.fragment.PhishingLinkWarningDialogFragment
|
||||
|
||||
class DirectMessageOnLinkClickHandler(context: Context, manager: MultiSelectManager,
|
||||
preferences: SharedPreferencesWrapper) : OnLinkClickHandler(context, manager, preferences) {
|
||||
|
||||
override val isPrivateData: Boolean
|
||||
get() = true
|
||||
|
||||
override fun openLink(link: String) {
|
||||
if (manager != null && manager.isActive) return
|
||||
if (!hasShortenedLinks(link)) {
|
||||
super.openLink(link)
|
||||
return
|
||||
}
|
||||
val prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
if (context is FragmentActivity && prefs.getBoolean(KEY_PHISHING_LINK_WARNING, true)) {
|
||||
val fm = context.supportFragmentManager
|
||||
val fragment = PhishingLinkWarningDialogFragment()
|
||||
val args = Bundle()
|
||||
args.putParcelable(EXTRA_URI, Uri.parse(link))
|
||||
fragment.arguments = args
|
||||
fragment.show(fm, "phishing_link_warning")
|
||||
} else {
|
||||
super.openLink(link)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun hasShortenedLinks(link: String): Boolean {
|
||||
for (shortLinkService in SHORT_LINK_SERVICES) {
|
||||
if (link.contains(shortLinkService)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val SHORT_LINK_SERVICES = arrayOf("bit.ly", "ow.ly", "tinyurl.com", "goo.gl", "k6.kz", "is.gd", "tr.im", "x.co", "weepp.ru")
|
||||
}
|
||||
}
|
@ -35,6 +35,8 @@ import android.util.Log
|
||||
import android.view.ContextMenu
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import org.mariotaku.ktextension.setItemChecked
|
||||
import org.mariotaku.ktextension.setMenuItemIcon
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.*
|
||||
@ -57,288 +59,275 @@ import org.mariotaku.twidere.util.menu.TwidereMenuInfo
|
||||
/**
|
||||
* Created by mariotaku on 15/4/12.
|
||||
*/
|
||||
class MenuUtils private constructor() : Constants {
|
||||
companion object {
|
||||
object MenuUtils {
|
||||
|
||||
fun setMenuItemAvailability(menu: Menu?, id: Int, available: Boolean) {
|
||||
if (menu == null) return
|
||||
val item = menu.findItem(id) ?: return
|
||||
item.isVisible = available
|
||||
item.isEnabled = available
|
||||
}
|
||||
fun setItemAvailability(menu: Menu?, id: Int, available: Boolean) {
|
||||
if (menu == null) return
|
||||
val item = menu.findItem(id) ?: return
|
||||
item.isVisible = available
|
||||
item.isEnabled = available
|
||||
}
|
||||
|
||||
fun setMenuItemChecked(menu: Menu?, id: Int, checked: Boolean) {
|
||||
if (menu == null) return
|
||||
val item = menu.findItem(id) ?: return
|
||||
item.isChecked = checked
|
||||
}
|
||||
fun setItemChecked(menu: Menu?, id: Int, checked: Boolean) {
|
||||
menu?.setItemChecked(id, checked);
|
||||
}
|
||||
|
||||
fun setMenuItemIcon(menu: Menu?, id: Int, @DrawableRes icon: Int) {
|
||||
if (menu == null) return
|
||||
val item = menu.findItem(id) ?: return
|
||||
item.setIcon(icon)
|
||||
}
|
||||
fun setMenuItemIcon(menu: Menu?, id: Int, @DrawableRes icon: Int) {
|
||||
menu?.setMenuItemIcon(id, icon);
|
||||
}
|
||||
|
||||
fun setMenuItemShowAsActionFlags(menu: Menu?, id: Int, flags: Int) {
|
||||
if (menu == null) return
|
||||
val item = menu.findItem(id) ?: return
|
||||
item.setShowAsActionFlags(flags)
|
||||
MenuItemCompat.setShowAsAction(item, flags)
|
||||
}
|
||||
fun setMenuItemTitle(menu: Menu?, id: Int, @StringRes icon: Int) {
|
||||
if (menu == null) return
|
||||
val item = menu.findItem(id) ?: return
|
||||
item.setTitle(icon)
|
||||
}
|
||||
|
||||
fun setMenuItemTitle(menu: Menu?, id: Int, @StringRes icon: Int) {
|
||||
if (menu == null) return
|
||||
val item = menu.findItem(id) ?: return
|
||||
item.setTitle(icon)
|
||||
}
|
||||
|
||||
@JvmOverloads fun addIntentToMenu(context: Context?, menu: Menu?, queryIntent: Intent?,
|
||||
groupId: Int = Menu.NONE) {
|
||||
if (context == null || menu == null || queryIntent == null) return
|
||||
val pm = context.packageManager
|
||||
val res = context.resources
|
||||
val density = res.displayMetrics.density
|
||||
val padding = Math.round(density * 4)
|
||||
val activities = pm.queryIntentActivities(queryIntent, 0)
|
||||
for (info in activities) {
|
||||
val intent = Intent(queryIntent)
|
||||
val icon = info.loadIcon(pm)
|
||||
intent.setClassName(info.activityInfo.packageName, info.activityInfo.name)
|
||||
val item = menu.add(groupId, Menu.NONE, Menu.NONE, info.loadLabel(pm))
|
||||
item.intent = intent
|
||||
val iw = icon.intrinsicWidth
|
||||
val ih = icon.intrinsicHeight
|
||||
if (iw > 0 && ih > 0) {
|
||||
val iconWithPadding = PaddingDrawable(icon, padding)
|
||||
iconWithPadding.setBounds(0, 0, iw, ih)
|
||||
item.icon = iconWithPadding
|
||||
} else {
|
||||
item.icon = icon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setupForStatus(context: Context,
|
||||
preferences: SharedPreferencesWrapper,
|
||||
menu: Menu,
|
||||
status: ParcelableStatus,
|
||||
twitter: AsyncTwitterWrapper) {
|
||||
val account = ParcelableCredentialsUtils.getCredentials(context,
|
||||
status.account_key) ?: return
|
||||
setupForStatus(context, preferences, menu, status, account, twitter)
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun setupForStatus(context: Context,
|
||||
preferences: SharedPreferencesWrapper,
|
||||
menu: Menu,
|
||||
status: ParcelableStatus,
|
||||
account: ParcelableCredentials,
|
||||
twitter: AsyncTwitterWrapper) {
|
||||
if (menu is ContextMenu) {
|
||||
menu.setHeaderTitle(context.getString(R.string.status_menu_title_format,
|
||||
UserColorNameManager.decideDisplayName(status.user_nickname, status.user_name,
|
||||
status.user_screen_name, preferences.getBoolean(SharedPreferenceConstants.KEY_NAME_FIRST)),
|
||||
status.text_unescaped))
|
||||
}
|
||||
val retweetHighlight = ContextCompat.getColor(context, R.color.highlight_retweet)
|
||||
val favoriteHighlight = ContextCompat.getColor(context, R.color.highlight_favorite)
|
||||
val likeHighlight = ContextCompat.getColor(context, R.color.highlight_like)
|
||||
val isMyRetweet: Boolean
|
||||
if (twitter.isCreatingRetweet(status.account_key, status.id)) {
|
||||
isMyRetweet = true
|
||||
} else if (twitter.isDestroyingStatus(status.account_key, status.id)) {
|
||||
isMyRetweet = false
|
||||
@JvmOverloads fun addIntentToMenu(context: Context?, menu: Menu?, queryIntent: Intent?,
|
||||
groupId: Int = Menu.NONE) {
|
||||
if (context == null || menu == null || queryIntent == null) return
|
||||
val pm = context.packageManager
|
||||
val res = context.resources
|
||||
val density = res.displayMetrics.density
|
||||
val padding = Math.round(density * 4)
|
||||
val activities = pm.queryIntentActivities(queryIntent, 0)
|
||||
for (info in activities) {
|
||||
val intent = Intent(queryIntent)
|
||||
val icon = info.loadIcon(pm)
|
||||
intent.setClassName(info.activityInfo.packageName, info.activityInfo.name)
|
||||
val item = menu.add(groupId, Menu.NONE, Menu.NONE, info.loadLabel(pm))
|
||||
item.intent = intent
|
||||
val iw = icon.intrinsicWidth
|
||||
val ih = icon.intrinsicHeight
|
||||
if (iw > 0 && ih > 0) {
|
||||
val iconWithPadding = PaddingDrawable(icon, padding)
|
||||
iconWithPadding.setBounds(0, 0, iw, ih)
|
||||
item.icon = iconWithPadding
|
||||
} else {
|
||||
isMyRetweet = status.retweeted || Utils.isMyRetweet(status)
|
||||
item.icon = icon
|
||||
}
|
||||
val delete = menu.findItem(R.id.delete)
|
||||
if (delete != null) {
|
||||
delete.isVisible = Utils.isMyStatus(status)
|
||||
}
|
||||
val retweet = menu.findItem(R.id.retweet)
|
||||
if (retweet != null) {
|
||||
ActionIconDrawable.setMenuHighlight(retweet, TwidereMenuInfo(isMyRetweet, retweetHighlight))
|
||||
retweet.setTitle(if (isMyRetweet) R.string.cancel_retweet else R.string.retweet)
|
||||
}
|
||||
val favorite = menu.findItem(R.id.favorite)
|
||||
if (favorite != null) {
|
||||
val isFavorite: Boolean
|
||||
if (twitter.isCreatingFavorite(status.account_key, status.id)) {
|
||||
isFavorite = true
|
||||
} else if (twitter.isDestroyingFavorite(status.account_key, status.id)) {
|
||||
isFavorite = false
|
||||
} else {
|
||||
isFavorite = status.is_favorite
|
||||
}
|
||||
val provider = MenuItemCompat.getActionProvider(favorite)
|
||||
val useStar = preferences.getBoolean(SharedPreferenceConstants.KEY_I_WANT_MY_STARS_BACK)
|
||||
if (provider is FavoriteItemProvider) {
|
||||
provider.setIsFavorite(favorite, isFavorite)
|
||||
} else {
|
||||
if (useStar) {
|
||||
val oldIcon = favorite.icon
|
||||
if (oldIcon is ActionIconDrawable) {
|
||||
val starIcon = ContextCompat.getDrawable(context, R.drawable.ic_action_star)
|
||||
favorite.icon = ActionIconDrawable(starIcon, oldIcon.defaultColor)
|
||||
} else {
|
||||
favorite.setIcon(R.drawable.ic_action_star)
|
||||
}
|
||||
ActionIconDrawable.setMenuHighlight(favorite, TwidereMenuInfo(isFavorite, favoriteHighlight))
|
||||
} else {
|
||||
ActionIconDrawable.setMenuHighlight(favorite, TwidereMenuInfo(isFavorite, likeHighlight))
|
||||
}
|
||||
}
|
||||
if (useStar) {
|
||||
favorite.setTitle(if (isFavorite) R.string.unfavorite else R.string.favorite)
|
||||
} else {
|
||||
favorite.setTitle(if (isFavorite) R.string.undo_like else R.string.like)
|
||||
}
|
||||
}
|
||||
val translate = menu.findItem(R.id.translate)
|
||||
if (translate != null) {
|
||||
val isOfficialKey = Utils.isOfficialCredentials(context, account)
|
||||
val prefs = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
setMenuItemAvailability(menu, R.id.translate, isOfficialKey)
|
||||
}
|
||||
menu.removeGroup(Constants.MENU_GROUP_STATUS_EXTENSION)
|
||||
Utils.addIntentToMenuForExtension(context, menu, Constants.MENU_GROUP_STATUS_EXTENSION, INTENT_ACTION_EXTENSION_OPEN_STATUS,
|
||||
EXTRA_STATUS, EXTRA_STATUS_JSON, status)
|
||||
val shareItem = menu.findItem(R.id.share)
|
||||
val shareProvider = MenuItemCompat.getActionProvider(shareItem)
|
||||
if (shareProvider is SupportStatusShareProvider) {
|
||||
shareProvider.status = status
|
||||
} else if (shareProvider is ShareActionProvider) {
|
||||
val shareIntent = Utils.createStatusShareIntent(context, status)
|
||||
shareProvider.setShareIntent(shareIntent)
|
||||
} else if (shareItem.hasSubMenu()) {
|
||||
val shareSubMenu = shareItem.subMenu
|
||||
val shareIntent = Utils.createStatusShareIntent(context, status)
|
||||
shareSubMenu.removeGroup(Constants.MENU_GROUP_STATUS_SHARE)
|
||||
addIntentToMenu(context, shareSubMenu, shareIntent, Constants.MENU_GROUP_STATUS_SHARE)
|
||||
} else {
|
||||
val shareIntent = Utils.createStatusShareIntent(context, status)
|
||||
val chooserIntent = Intent.createChooser(shareIntent, context.getString(R.string.share_status))
|
||||
Utils.addCopyLinkIntent(context, chooserIntent, LinkCreator.getStatusWebLink(status))
|
||||
shareItem.intent = chooserIntent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun handleStatusClick(context: Context,
|
||||
fragment: Fragment?,
|
||||
fm: FragmentManager,
|
||||
colorNameManager: UserColorNameManager,
|
||||
twitter: AsyncTwitterWrapper,
|
||||
status: ParcelableStatus,
|
||||
item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.copy -> {
|
||||
if (ClipboardUtils.setText(context, status.text_plain)) {
|
||||
Utils.showOkMessage(context, R.string.text_copied, false)
|
||||
}
|
||||
}
|
||||
R.id.retweet -> {
|
||||
if (Utils.isMyRetweet(status)) {
|
||||
twitter.cancelRetweetAsync(status.account_key,
|
||||
status.id, status.my_retweet_id)
|
||||
} else {
|
||||
twitter.retweetStatusAsync(status.account_key,
|
||||
status.id)
|
||||
}
|
||||
}
|
||||
R.id.quote -> {
|
||||
val intent = Intent(INTENT_ACTION_QUOTE)
|
||||
intent.putExtra(EXTRA_STATUS, status)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
R.id.reply -> {
|
||||
val intent = Intent(INTENT_ACTION_REPLY)
|
||||
intent.putExtra(EXTRA_STATUS, status)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
R.id.favorite -> {
|
||||
if (status.is_favorite) {
|
||||
twitter.destroyFavoriteAsync(status.account_key, status.id)
|
||||
} else {
|
||||
val provider = MenuItemCompat.getActionProvider(item)
|
||||
if (provider is FavoriteItemProvider) {
|
||||
provider.invokeItem(item,
|
||||
AbsStatusesFragment.DefaultOnLikedListener(twitter, status))
|
||||
} else {
|
||||
twitter.createFavoriteAsync(status.account_key, status.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.delete -> {
|
||||
DestroyStatusDialogFragment.show(fm, status)
|
||||
}
|
||||
R.id.add_to_filter -> {
|
||||
AddStatusFilterDialogFragment.show(fm, status)
|
||||
}
|
||||
R.id.set_color -> {
|
||||
val intent = Intent(context, ColorPickerDialogActivity::class.java)
|
||||
val color = colorNameManager.getUserColor(status.user_key)
|
||||
if (color != 0) {
|
||||
intent.putExtra(EXTRA_COLOR, color)
|
||||
}
|
||||
intent.putExtra(EXTRA_CLEAR_BUTTON, color != 0)
|
||||
intent.putExtra(EXTRA_ALPHA_SLIDER, false)
|
||||
if (fragment != null) {
|
||||
fragment.startActivityForResult(intent, REQUEST_SET_COLOR)
|
||||
} else if (context is Activity) {
|
||||
context.startActivityForResult(intent, REQUEST_SET_COLOR)
|
||||
}
|
||||
}
|
||||
R.id.clear_nickname -> {
|
||||
colorNameManager.clearUserNickname(status.user_key)
|
||||
}
|
||||
R.id.set_nickname -> {
|
||||
val nick = colorNameManager.getUserNickname(status.user_key)
|
||||
val df = SetUserNicknameDialogFragment.show(fm,
|
||||
status.user_key, nick)
|
||||
if (fragment != null) {
|
||||
df.setTargetFragment(fragment, REQUEST_SET_NICKNAME)
|
||||
}
|
||||
}
|
||||
R.id.open_with_account -> {
|
||||
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
|
||||
intent.setClass(context, AccountSelectorActivity::class.java)
|
||||
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
|
||||
intent.putExtra(EXTRA_ACCOUNT_HOST, status.user_key.host)
|
||||
if (fragment != null) {
|
||||
fragment.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
|
||||
} else if (context is Activity) {
|
||||
context.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
|
||||
}
|
||||
}
|
||||
R.id.open_in_browser -> {
|
||||
val uri = LinkCreator.getStatusWebLink(status)
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
intent.addCategory(Intent.CATEGORY_BROWSABLE)
|
||||
intent.`package` = IntentUtils.getDefaultBrowserPackage(context, uri, true)
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
intent.`package` = null
|
||||
context.startActivity(Intent.createChooser(intent,
|
||||
context.getString(R.string.open_in_browser)))
|
||||
}
|
||||
|
||||
}
|
||||
else -> {
|
||||
if (item.intent != null) {
|
||||
try {
|
||||
context.startActivity(item.intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.w(LOGTAG, e)
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun setupForStatus(context: Context,
|
||||
preferences: SharedPreferencesWrapper,
|
||||
menu: Menu,
|
||||
status: ParcelableStatus,
|
||||
twitter: AsyncTwitterWrapper) {
|
||||
val account = ParcelableCredentialsUtils.getCredentials(context,
|
||||
status.account_key) ?: return
|
||||
setupForStatus(context, preferences, menu, status, account, twitter)
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun setupForStatus(context: Context,
|
||||
preferences: SharedPreferencesWrapper,
|
||||
menu: Menu,
|
||||
status: ParcelableStatus,
|
||||
account: ParcelableCredentials,
|
||||
twitter: AsyncTwitterWrapper) {
|
||||
if (menu is ContextMenu) {
|
||||
menu.setHeaderTitle(context.getString(R.string.status_menu_title_format,
|
||||
UserColorNameManager.decideDisplayName(status.user_nickname, status.user_name,
|
||||
status.user_screen_name, preferences.getBoolean(SharedPreferenceConstants.KEY_NAME_FIRST)),
|
||||
status.text_unescaped))
|
||||
}
|
||||
val retweetHighlight = ContextCompat.getColor(context, R.color.highlight_retweet)
|
||||
val favoriteHighlight = ContextCompat.getColor(context, R.color.highlight_favorite)
|
||||
val likeHighlight = ContextCompat.getColor(context, R.color.highlight_like)
|
||||
val isMyRetweet: Boolean
|
||||
if (twitter.isCreatingRetweet(status.account_key, status.id)) {
|
||||
isMyRetweet = true
|
||||
} else if (twitter.isDestroyingStatus(status.account_key, status.id)) {
|
||||
isMyRetweet = false
|
||||
} else {
|
||||
isMyRetweet = status.retweeted || Utils.isMyRetweet(status)
|
||||
}
|
||||
val delete = menu.findItem(R.id.delete)
|
||||
if (delete != null) {
|
||||
delete.isVisible = Utils.isMyStatus(status)
|
||||
}
|
||||
val retweet = menu.findItem(R.id.retweet)
|
||||
if (retweet != null) {
|
||||
ActionIconDrawable.setMenuHighlight(retweet, TwidereMenuInfo(isMyRetweet, retweetHighlight))
|
||||
retweet.setTitle(if (isMyRetweet) R.string.cancel_retweet else R.string.retweet)
|
||||
}
|
||||
val favorite = menu.findItem(R.id.favorite)
|
||||
if (favorite != null) {
|
||||
val isFavorite: Boolean
|
||||
if (twitter.isCreatingFavorite(status.account_key, status.id)) {
|
||||
isFavorite = true
|
||||
} else if (twitter.isDestroyingFavorite(status.account_key, status.id)) {
|
||||
isFavorite = false
|
||||
} else {
|
||||
isFavorite = status.is_favorite
|
||||
}
|
||||
val provider = MenuItemCompat.getActionProvider(favorite)
|
||||
val useStar = preferences.getBoolean(SharedPreferenceConstants.KEY_I_WANT_MY_STARS_BACK)
|
||||
if (provider is FavoriteItemProvider) {
|
||||
provider.setIsFavorite(favorite, isFavorite)
|
||||
} else {
|
||||
if (useStar) {
|
||||
val oldIcon = favorite.icon
|
||||
if (oldIcon is ActionIconDrawable) {
|
||||
val starIcon = ContextCompat.getDrawable(context, R.drawable.ic_action_star)
|
||||
favorite.icon = ActionIconDrawable(starIcon, oldIcon.defaultColor)
|
||||
} else {
|
||||
favorite.setIcon(R.drawable.ic_action_star)
|
||||
}
|
||||
ActionIconDrawable.setMenuHighlight(favorite, TwidereMenuInfo(isFavorite, favoriteHighlight))
|
||||
} else {
|
||||
ActionIconDrawable.setMenuHighlight(favorite, TwidereMenuInfo(isFavorite, likeHighlight))
|
||||
}
|
||||
}
|
||||
if (useStar) {
|
||||
favorite.setTitle(if (isFavorite) R.string.unfavorite else R.string.favorite)
|
||||
} else {
|
||||
favorite.setTitle(if (isFavorite) R.string.undo_like else R.string.like)
|
||||
}
|
||||
}
|
||||
val translate = menu.findItem(R.id.translate)
|
||||
if (translate != null) {
|
||||
val isOfficialKey = Utils.isOfficialCredentials(context, account)
|
||||
val prefs = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||
setItemAvailability(menu, R.id.translate, isOfficialKey)
|
||||
}
|
||||
menu.removeGroup(Constants.MENU_GROUP_STATUS_EXTENSION)
|
||||
Utils.addIntentToMenuForExtension(context, menu, Constants.MENU_GROUP_STATUS_EXTENSION, INTENT_ACTION_EXTENSION_OPEN_STATUS,
|
||||
EXTRA_STATUS, EXTRA_STATUS_JSON, status)
|
||||
val shareItem = menu.findItem(R.id.share)
|
||||
val shareProvider = MenuItemCompat.getActionProvider(shareItem)
|
||||
if (shareProvider is SupportStatusShareProvider) {
|
||||
shareProvider.status = status
|
||||
} else if (shareProvider is ShareActionProvider) {
|
||||
val shareIntent = Utils.createStatusShareIntent(context, status)
|
||||
shareProvider.setShareIntent(shareIntent)
|
||||
} else if (shareItem.hasSubMenu()) {
|
||||
val shareSubMenu = shareItem.subMenu
|
||||
val shareIntent = Utils.createStatusShareIntent(context, status)
|
||||
shareSubMenu.removeGroup(Constants.MENU_GROUP_STATUS_SHARE)
|
||||
addIntentToMenu(context, shareSubMenu, shareIntent, Constants.MENU_GROUP_STATUS_SHARE)
|
||||
} else {
|
||||
val shareIntent = Utils.createStatusShareIntent(context, status)
|
||||
val chooserIntent = Intent.createChooser(shareIntent, context.getString(R.string.share_status))
|
||||
Utils.addCopyLinkIntent(context, chooserIntent, LinkCreator.getStatusWebLink(status))
|
||||
shareItem.intent = chooserIntent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun handleStatusClick(context: Context,
|
||||
fragment: Fragment?,
|
||||
fm: FragmentManager,
|
||||
colorNameManager: UserColorNameManager,
|
||||
twitter: AsyncTwitterWrapper,
|
||||
status: ParcelableStatus,
|
||||
item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.copy -> {
|
||||
if (ClipboardUtils.setText(context, status.text_plain)) {
|
||||
Utils.showOkMessage(context, R.string.text_copied, false)
|
||||
}
|
||||
}
|
||||
R.id.retweet -> {
|
||||
if (Utils.isMyRetweet(status)) {
|
||||
twitter.cancelRetweetAsync(status.account_key,
|
||||
status.id, status.my_retweet_id)
|
||||
} else {
|
||||
twitter.retweetStatusAsync(status.account_key,
|
||||
status.id)
|
||||
}
|
||||
}
|
||||
R.id.quote -> {
|
||||
val intent = Intent(INTENT_ACTION_QUOTE)
|
||||
intent.putExtra(EXTRA_STATUS, status)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
R.id.reply -> {
|
||||
val intent = Intent(INTENT_ACTION_REPLY)
|
||||
intent.putExtra(EXTRA_STATUS, status)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
R.id.favorite -> {
|
||||
if (status.is_favorite) {
|
||||
twitter.destroyFavoriteAsync(status.account_key, status.id)
|
||||
} else {
|
||||
val provider = MenuItemCompat.getActionProvider(item)
|
||||
if (provider is FavoriteItemProvider) {
|
||||
provider.invokeItem(item,
|
||||
AbsStatusesFragment.DefaultOnLikedListener(twitter, status))
|
||||
} else {
|
||||
twitter.createFavoriteAsync(status.account_key, status.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.delete -> {
|
||||
DestroyStatusDialogFragment.show(fm, status)
|
||||
}
|
||||
R.id.add_to_filter -> {
|
||||
AddStatusFilterDialogFragment.show(fm, status)
|
||||
}
|
||||
R.id.set_color -> {
|
||||
val intent = Intent(context, ColorPickerDialogActivity::class.java)
|
||||
val color = colorNameManager.getUserColor(status.user_key)
|
||||
if (color != 0) {
|
||||
intent.putExtra(EXTRA_COLOR, color)
|
||||
}
|
||||
intent.putExtra(EXTRA_CLEAR_BUTTON, color != 0)
|
||||
intent.putExtra(EXTRA_ALPHA_SLIDER, false)
|
||||
if (fragment != null) {
|
||||
fragment.startActivityForResult(intent, REQUEST_SET_COLOR)
|
||||
} else if (context is Activity) {
|
||||
context.startActivityForResult(intent, REQUEST_SET_COLOR)
|
||||
}
|
||||
}
|
||||
R.id.clear_nickname -> {
|
||||
colorNameManager.clearUserNickname(status.user_key)
|
||||
}
|
||||
R.id.set_nickname -> {
|
||||
val nick = colorNameManager.getUserNickname(status.user_key)
|
||||
val df = SetUserNicknameDialogFragment.show(fm,
|
||||
status.user_key, nick)
|
||||
if (fragment != null) {
|
||||
df.setTargetFragment(fragment, REQUEST_SET_NICKNAME)
|
||||
}
|
||||
}
|
||||
R.id.open_with_account -> {
|
||||
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
|
||||
intent.setClass(context, AccountSelectorActivity::class.java)
|
||||
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
|
||||
intent.putExtra(EXTRA_ACCOUNT_HOST, status.user_key.host)
|
||||
if (fragment != null) {
|
||||
fragment.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
|
||||
} else if (context is Activity) {
|
||||
context.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
|
||||
}
|
||||
}
|
||||
R.id.open_in_browser -> {
|
||||
val uri = LinkCreator.getStatusWebLink(status)
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
intent.addCategory(Intent.CATEGORY_BROWSABLE)
|
||||
intent.`package` = IntentUtils.getDefaultBrowserPackage(context, uri, true)
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
intent.`package` = null
|
||||
context.startActivity(Intent.createChooser(intent,
|
||||
context.getString(R.string.open_in_browser)))
|
||||
}
|
||||
|
||||
}
|
||||
else -> {
|
||||
if (item.intent != null) {
|
||||
try {
|
||||
context.startActivity(item.intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.w(LOGTAG, e)
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.BadParcelableException;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mariotaku.twidere.activity.WebLinkHandlerActivity;
|
||||
import org.mariotaku.twidere.annotation.Referral;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.util.ParcelableMediaUtils;
|
||||
import org.mariotaku.twidere.util.TwidereLinkify.OnLinkClickListener;
|
||||
import org.mariotaku.twidere.util.media.preview.PreviewMediaExtractor;
|
||||
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
import edu.tsinghua.hotmobi.model.LinkEvent;
|
||||
|
||||
import static org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY;
|
||||
import static org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NEW_DOCUMENT_API;
|
||||
|
||||
public class OnLinkClickHandler implements OnLinkClickListener {
|
||||
|
||||
@NonNull
|
||||
protected final Context context;
|
||||
@Nullable
|
||||
protected final MultiSelectManager manager;
|
||||
@NonNull
|
||||
protected final SharedPreferencesWrapper preferences;
|
||||
|
||||
public OnLinkClickHandler(@NonNull final Context context, @Nullable final MultiSelectManager manager,
|
||||
@NonNull SharedPreferencesWrapper preferences) {
|
||||
this.context = context;
|
||||
this.manager = manager;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLinkClick(final String link, final String orig, final UserKey accountKey,
|
||||
final long extraId, final int type, final boolean sensitive,
|
||||
final int start, final int end) {
|
||||
if (manager != null && manager.isActive()) return false;
|
||||
if (!isPrivateData()) {
|
||||
// BEGIN HotMobi
|
||||
final LinkEvent event = LinkEvent.create(context, link, type);
|
||||
HotMobiLogger.getInstance(context).log(accountKey, event);
|
||||
// END HotMobi
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TwidereLinkify.LINK_TYPE_MENTION: {
|
||||
IntentUtils.openUserProfile(context, accountKey, null, link, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.USER_MENTION);
|
||||
return true;
|
||||
}
|
||||
case TwidereLinkify.LINK_TYPE_HASHTAG: {
|
||||
IntentUtils.openTweetSearch(context, accountKey, "#" + link);
|
||||
return true;
|
||||
}
|
||||
case TwidereLinkify.LINK_TYPE_LINK_IN_TEXT: {
|
||||
if (isMedia(link, extraId)) {
|
||||
openMedia(accountKey, extraId, sensitive, link, start, end);
|
||||
} else {
|
||||
openLink(link);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case TwidereLinkify.LINK_TYPE_ENTITY_URL: {
|
||||
if (isMedia(link, extraId)) {
|
||||
openMedia(accountKey, extraId, sensitive, link, start, end);
|
||||
} else {
|
||||
final String authority = UriUtils.getAuthority(link);
|
||||
if (authority == null) {
|
||||
openLink(link);
|
||||
return true;
|
||||
}
|
||||
switch (authority) {
|
||||
case "fanfou.com": {
|
||||
if (orig != null) {
|
||||
// Process special case for fanfou
|
||||
final char ch = orig.charAt(0);
|
||||
// Extend selection
|
||||
final int length = orig.length();
|
||||
if (TwidereLinkify.isAtSymbol(ch)) {
|
||||
String id = UriUtils.getPath(link);
|
||||
if (id != null) {
|
||||
int idxOfSlash = id.indexOf('/');
|
||||
if (idxOfSlash == 0) {
|
||||
id = id.substring(1);
|
||||
}
|
||||
final String screenName = orig.substring(1, length);
|
||||
IntentUtils.openUserProfile(context, accountKey, UserKey.valueOf(id),
|
||||
screenName, null, preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.USER_MENTION);
|
||||
return true;
|
||||
}
|
||||
} else if (TwidereLinkify.isHashSymbol(ch) &&
|
||||
TwidereLinkify.isHashSymbol(orig.charAt(length - 1))) {
|
||||
IntentUtils.openSearch(context, accountKey, orig.substring(1, length - 1));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (IntentUtils.isWebLinkHandled(context, Uri.parse(link))) {
|
||||
openTwitterLink(link, accountKey);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
openLink(link);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case TwidereLinkify.LINK_TYPE_LIST: {
|
||||
final String[] mentionList = StringUtils.split(link, "/");
|
||||
if (mentionList.length != 2) {
|
||||
return false;
|
||||
}
|
||||
IntentUtils.openUserListDetails(context, accountKey, null, null, mentionList[0],
|
||||
mentionList[1]);
|
||||
return true;
|
||||
}
|
||||
case TwidereLinkify.LINK_TYPE_CASHTAG: {
|
||||
IntentUtils.openTweetSearch(context, accountKey, link);
|
||||
return true;
|
||||
}
|
||||
case TwidereLinkify.LINK_TYPE_USER_ID: {
|
||||
IntentUtils.openUserProfile(context, accountKey, UserKey.valueOf(link), null, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.USER_MENTION);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isPrivateData() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isMedia(String link, long extraId) {
|
||||
return PreviewMediaExtractor.isSupported(link);
|
||||
}
|
||||
|
||||
protected void openMedia(UserKey accountKey, long extraId, boolean sensitive, String link, int start, int end) {
|
||||
final ParcelableMedia[] media = {ParcelableMediaUtils.image(link)};
|
||||
IntentUtils.openMedia(context, accountKey, sensitive, null, media, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API));
|
||||
}
|
||||
|
||||
protected void openLink(final String link) {
|
||||
if (manager != null && manager.isActive()) return;
|
||||
final Uri uri = Uri.parse(link);
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setPackage(IntentUtils.getDefaultBrowserPackage(context, uri, true));
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
} catch (final ActivityNotFoundException e) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
protected void openTwitterLink(final String link, final UserKey accountKey) {
|
||||
if (manager != null && manager.isActive()) return;
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setClass(context, WebLinkHandlerActivity.class);
|
||||
intent.putExtra(EXTRA_ACCOUNT_KEY, accountKey);
|
||||
intent.setExtrasClassLoader(TwidereApplication.class.getClassLoader());
|
||||
if (intent.resolveActivity(context.getPackageManager()) != null) {
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
} catch (final BadParcelableException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.BadParcelableException
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger
|
||||
import edu.tsinghua.hotmobi.model.LinkEvent
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import org.mariotaku.twidere.activity.WebLinkHandlerActivity
|
||||
import org.mariotaku.twidere.annotation.Referral
|
||||
import org.mariotaku.twidere.app.TwidereApplication
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NEW_DOCUMENT_API
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.ParcelableMediaUtils
|
||||
import org.mariotaku.twidere.util.TwidereLinkify.OnLinkClickListener
|
||||
import org.mariotaku.twidere.util.media.preview.PreviewMediaExtractor
|
||||
|
||||
open class OnLinkClickHandler(
|
||||
protected val context: Context,
|
||||
protected val manager: MultiSelectManager?,
|
||||
protected val preferences: SharedPreferencesWrapper
|
||||
) : OnLinkClickListener {
|
||||
|
||||
override fun onLinkClick(link: String, orig: String?, accountKey: UserKey,
|
||||
extraId: Long, type: Int, sensitive: Boolean,
|
||||
start: Int, end: Int): Boolean {
|
||||
if (manager != null && manager.isActive) return false
|
||||
if (!isPrivateData) {
|
||||
// BEGIN HotMobi
|
||||
val event = LinkEvent.create(context, link, type)
|
||||
HotMobiLogger.getInstance(context).log(accountKey, event)
|
||||
// END HotMobi
|
||||
}
|
||||
|
||||
when (type) {
|
||||
TwidereLinkify.LINK_TYPE_MENTION -> {
|
||||
IntentUtils.openUserProfile(context, accountKey, null, link, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.USER_MENTION)
|
||||
return true
|
||||
}
|
||||
TwidereLinkify.LINK_TYPE_HASHTAG -> {
|
||||
IntentUtils.openTweetSearch(context, accountKey, "#" + link)
|
||||
return true
|
||||
}
|
||||
TwidereLinkify.LINK_TYPE_LINK_IN_TEXT -> {
|
||||
if (isMedia(link, extraId)) {
|
||||
openMedia(accountKey, extraId, sensitive, link, start, end)
|
||||
} else {
|
||||
openLink(link)
|
||||
}
|
||||
return true
|
||||
}
|
||||
TwidereLinkify.LINK_TYPE_ENTITY_URL -> {
|
||||
if (isMedia(link, extraId)) {
|
||||
openMedia(accountKey, extraId, sensitive, link, start, end)
|
||||
} else {
|
||||
val authority = UriUtils.getAuthority(link)
|
||||
if (authority == null) {
|
||||
openLink(link)
|
||||
return true
|
||||
}
|
||||
when (authority) {
|
||||
"fanfou.com" -> {
|
||||
if (orig != null) {
|
||||
// Process special case for fanfou
|
||||
val ch = orig[0]
|
||||
// Extend selection
|
||||
val length = orig.length
|
||||
if (TwidereLinkify.isAtSymbol(ch)) {
|
||||
var id = UriUtils.getPath(link)
|
||||
if (id != null) {
|
||||
val idxOfSlash = id.indexOf('/')
|
||||
if (idxOfSlash == 0) {
|
||||
id = id.substring(1)
|
||||
}
|
||||
val screenName = orig.substring(1, length)
|
||||
IntentUtils.openUserProfile(context, accountKey, UserKey.valueOf(id),
|
||||
screenName, null, preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.USER_MENTION)
|
||||
return true
|
||||
}
|
||||
} else if (TwidereLinkify.isHashSymbol(ch) && TwidereLinkify.isHashSymbol(orig[length - 1])) {
|
||||
IntentUtils.openSearch(context, accountKey, orig.substring(1, length - 1))
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
if (IntentUtils.isWebLinkHandled(context, Uri.parse(link))) {
|
||||
openTwitterLink(link, accountKey)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
openLink(link)
|
||||
}
|
||||
return true
|
||||
}
|
||||
TwidereLinkify.LINK_TYPE_LIST -> {
|
||||
val mentionList = StringUtils.split(link, "/")
|
||||
if (mentionList.size != 2) {
|
||||
return false
|
||||
}
|
||||
IntentUtils.openUserListDetails(context, accountKey, null, null, mentionList[0],
|
||||
mentionList[1])
|
||||
return true
|
||||
}
|
||||
TwidereLinkify.LINK_TYPE_CASHTAG -> {
|
||||
IntentUtils.openTweetSearch(context, accountKey, link)
|
||||
return true
|
||||
}
|
||||
TwidereLinkify.LINK_TYPE_USER_ID -> {
|
||||
IntentUtils.openUserProfile(context, accountKey, UserKey.valueOf(link), null, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
|
||||
Referral.USER_MENTION)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
protected open val isPrivateData: Boolean
|
||||
get() = false
|
||||
|
||||
protected open fun isMedia(link: String, extraId: Long): Boolean {
|
||||
return PreviewMediaExtractor.isSupported(link)
|
||||
}
|
||||
|
||||
protected open fun openMedia(accountKey: UserKey, extraId: Long, sensitive: Boolean, link: String, start: Int, end: Int) {
|
||||
val media = arrayOf(ParcelableMediaUtils.image(link))
|
||||
IntentUtils.openMedia(context, accountKey, sensitive, null, media, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API))
|
||||
}
|
||||
|
||||
protected open fun openLink(link: String) {
|
||||
if (manager != null && manager.isActive) return
|
||||
val uri = Uri.parse(link)
|
||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.`package` = IntentUtils.getDefaultBrowserPackage(context, uri, true)
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected fun openTwitterLink(link: String, accountKey: UserKey) {
|
||||
if (manager != null && manager.isActive) return
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.setClass(context, WebLinkHandlerActivity::class.java)
|
||||
intent.putExtra(EXTRA_ACCOUNT_KEY, accountKey)
|
||||
intent.setExtrasClassLoader(TwidereApplication::class.java.classLoader)
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
} catch (e: BadParcelableException) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -48,8 +48,8 @@ class StatusActionModeCallback(private val textView: TextView, private val conte
|
||||
val string = SpannableString.valueOf(textView.text)
|
||||
val spans = string.getSpans(start, end, URLSpan::class.java)
|
||||
val selectingLink = spans.size == 1 && URLUtil.isValidUrl(spans[0].url)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.copy_url, selectingLink)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.share_url, selectingLink)
|
||||
MenuUtils.setItemAvailability(menu, R.id.copy_url, selectingLink)
|
||||
MenuUtils.setItemAvailability(menu, R.id.share_url, selectingLink)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
import org.mariotaku.twidere.model.util.ParcelableMediaUtils;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/6.
|
||||
*/
|
||||
public class StatusAdapterLinkClickHandler<D> extends OnLinkClickHandler implements Constants {
|
||||
|
||||
private IStatusesAdapter<D> adapter;
|
||||
|
||||
public StatusAdapterLinkClickHandler(Context context, SharedPreferencesWrapper preferences) {
|
||||
super(context, null, preferences);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openMedia(final UserKey accountKey, final long extraId, final boolean sensitive,
|
||||
final String link, final int start, final int end) {
|
||||
if (extraId == RecyclerView.NO_POSITION) return;
|
||||
final ParcelableStatus status = adapter.getStatus((int) extraId);
|
||||
final ParcelableMedia[] media = ParcelableMediaUtils.getAllMedia(status);
|
||||
final ParcelableMedia current = StatusLinkClickHandler.findByLink(media, link);
|
||||
if (current != null && current.open_browser) {
|
||||
openLink(link);
|
||||
} else {
|
||||
final boolean newDocument = preferences.getBoolean(KEY_NEW_DOCUMENT_API);
|
||||
IntentUtils.openMedia(context, status, current, null, newDocument);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMedia(String link, long extraId) {
|
||||
if (extraId != RecyclerView.NO_POSITION) {
|
||||
final ParcelableStatus status = adapter.getStatus((int) extraId);
|
||||
final ParcelableMedia[] media = ParcelableMediaUtils.getAllMedia(status);
|
||||
final ParcelableMedia current = StatusLinkClickHandler.findByLink(media, link);
|
||||
return current != null && !current.open_browser;
|
||||
}
|
||||
return super.isMedia(link, extraId);
|
||||
}
|
||||
|
||||
public void setAdapter(IStatusesAdapter<D> adapter) {
|
||||
this.adapter = adapter;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util
|
||||
|
||||
import android.content.Context
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NEW_DOCUMENT_API
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.ParcelableMediaUtils
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/4/6.
|
||||
*/
|
||||
class StatusAdapterLinkClickHandler<D>(context: Context, preferences: SharedPreferencesWrapper) : OnLinkClickHandler(context, null, preferences), Constants {
|
||||
|
||||
private var adapter: IStatusesAdapter<D>? = null
|
||||
|
||||
override fun openMedia(accountKey: UserKey, extraId: Long, sensitive: Boolean,
|
||||
link: String, start: Int, end: Int) {
|
||||
if (extraId == RecyclerView.NO_POSITION.toLong()) return
|
||||
val status = adapter!!.getStatus(extraId.toInt())
|
||||
val media = ParcelableMediaUtils.getAllMedia(status)
|
||||
val current = StatusLinkClickHandler.findByLink(media, link)
|
||||
if (current != null && current.open_browser) {
|
||||
openLink(link)
|
||||
} else {
|
||||
val newDocument = preferences.getBoolean(KEY_NEW_DOCUMENT_API)
|
||||
IntentUtils.openMedia(context, status, current, null, newDocument)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isMedia(link: String, extraId: Long): Boolean {
|
||||
if (extraId != RecyclerView.NO_POSITION.toLong()) {
|
||||
val status = adapter!!.getStatus(extraId.toInt())
|
||||
val media = ParcelableMediaUtils.getAllMedia(status)
|
||||
val current = StatusLinkClickHandler.findByLink(media, link)
|
||||
return current != null && !current.open_browser
|
||||
}
|
||||
return super.isMedia(link, extraId)
|
||||
}
|
||||
|
||||
fun setAdapter(adapter: IStatusesAdapter<D>) {
|
||||
this.adapter = adapter
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.UserKey;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/1/23.
|
||||
*/
|
||||
public class StatusLinkClickHandler extends OnLinkClickHandler implements Constants {
|
||||
|
||||
private ParcelableStatus mStatus;
|
||||
|
||||
@Override
|
||||
protected void openMedia(final UserKey accountId, final long extraId, final boolean sensitive,
|
||||
final String link, final int start, final int end) {
|
||||
final ParcelableStatus status = mStatus;
|
||||
final ParcelableMedia current = findByLink(status.media, link);
|
||||
if (current == null || current.open_browser) {
|
||||
openLink(link);
|
||||
} else {
|
||||
IntentUtils.openMedia(context, status, current, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API));
|
||||
}
|
||||
}
|
||||
|
||||
public static ParcelableMedia findByLink(ParcelableMedia[] media, String link) {
|
||||
if (link == null || media == null) return null;
|
||||
for (ParcelableMedia mediaItem : media) {
|
||||
if (link.equals(mediaItem.media_url) || link.equals(mediaItem.url) ||
|
||||
link.equals(mediaItem.page_url) || link.equals(mediaItem.preview_url))
|
||||
return mediaItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setStatus(ParcelableStatus status) {
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
public StatusLinkClickHandler(Context context, MultiSelectManager manager, SharedPreferencesWrapper preferences) {
|
||||
super(context, manager, preferences);
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util
|
||||
|
||||
import android.content.Context
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NEW_DOCUMENT_API
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/1/23.
|
||||
*/
|
||||
open class StatusLinkClickHandler(context: Context, manager: MultiSelectManager, preferences: SharedPreferencesWrapper) : OnLinkClickHandler(context, manager, preferences), Constants {
|
||||
|
||||
var status: ParcelableStatus? = null
|
||||
|
||||
override fun openMedia(accountKey: UserKey, extraId: Long, sensitive: Boolean,
|
||||
link: String, start: Int, end: Int) {
|
||||
val status = status
|
||||
val current = findByLink(status!!.media, link)
|
||||
if (current == null || current.open_browser) {
|
||||
openLink(link)
|
||||
} else {
|
||||
IntentUtils.openMedia(context, status, current, null,
|
||||
preferences.getBoolean(KEY_NEW_DOCUMENT_API))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun findByLink(media: Array<ParcelableMedia>?, link: String?): ParcelableMedia? {
|
||||
if (link == null || media == null) return null
|
||||
for (mediaItem in media) {
|
||||
if (link == mediaItem.media_url || link == mediaItem.url ||
|
||||
link == mediaItem.page_url || link == mediaItem.preview_url)
|
||||
return mediaItem
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.ktextension
|
||||
|
||||
import android.support.v4.view.MenuItemCompat
|
||||
import android.view.Menu
|
||||
|
||||
fun Menu.setItemAvailability(id: Int, available: Boolean) {
|
||||
val item = findItem(id) ?: return
|
||||
item.isVisible = available
|
||||
item.isEnabled = available
|
||||
}
|
||||
|
||||
fun Menu.setMenuGroupAvailability(groupId: Int, available: Boolean) {
|
||||
setGroupEnabled(groupId, available)
|
||||
setGroupVisible(groupId, available)
|
||||
}
|
||||
|
||||
fun Menu.setItemChecked(id: Int, checked: Boolean) {
|
||||
findItem(id)?.isChecked = checked
|
||||
}
|
||||
|
||||
fun Menu.setMenuItemIcon(id: Int, icon: Int) {
|
||||
findItem(id)?.setIcon(icon)
|
||||
}
|
||||
|
||||
fun Menu.setMenuItemTitle(id: Int, title: Int) {
|
||||
findItem(id)?.setTitle(title)
|
||||
}
|
||||
|
||||
fun Menu.setMenuItemShowAsActionFlags(id: Int, flags: Int) {
|
||||
val item = findItem(id) ?: return
|
||||
item.setShowAsActionFlags(flags)
|
||||
MenuItemCompat.setShowAsAction(item, flags)
|
||||
}
|
@ -65,6 +65,7 @@ import org.apache.commons.lang3.ObjectUtils
|
||||
import org.mariotaku.abstask.library.AbstractTask
|
||||
import org.mariotaku.abstask.library.TaskStarter
|
||||
import org.mariotaku.commons.io.StreamUtils
|
||||
import org.mariotaku.ktextension.setItemChecked
|
||||
import org.mariotaku.twidere.BuildConfig
|
||||
import org.mariotaku.twidere.Constants.*
|
||||
import org.mariotaku.twidere.R
|
||||
@ -112,15 +113,15 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
|
||||
// Adapters
|
||||
private var mMediaPreviewAdapter: MediaPreviewAdapter? = null
|
||||
private var mAccountsAdapter: AccountIconsAdapter? = null
|
||||
private var accountsAdapter: AccountIconsAdapter? = null
|
||||
|
||||
// Data fields
|
||||
private var mRecentLocation: ParcelableLocation? = null
|
||||
private var mInReplyToStatus: ParcelableStatus? = null
|
||||
private var mMentionUser: ParcelableUser? = null
|
||||
private var mOriginalText: String? = null
|
||||
private var mIsPossiblySensitive: Boolean = false
|
||||
private var mShouldSaveAccounts: Boolean = false
|
||||
private var possiblySensitive: Boolean = false
|
||||
private var shouldSaveAccounts: Boolean = false
|
||||
private var mImageUploaderUsed: Boolean = false
|
||||
private var mStatusShortenerUsed: Boolean = false
|
||||
private var mNavigateBackPressed: Boolean = false
|
||||
@ -194,13 +195,13 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
|
||||
public override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putParcelableArray(EXTRA_ACCOUNT_KEYS, mAccountsAdapter!!.selectedAccountKeys)
|
||||
outState.putParcelableArray(EXTRA_ACCOUNT_KEYS, accountsAdapter!!.selectedAccountKeys)
|
||||
outState.putParcelableArrayList(EXTRA_MEDIA, ArrayList<Parcelable>(mediaList))
|
||||
outState.putBoolean(EXTRA_IS_POSSIBLY_SENSITIVE, mIsPossiblySensitive)
|
||||
outState.putBoolean(EXTRA_IS_POSSIBLY_SENSITIVE, possiblySensitive)
|
||||
outState.putParcelable(EXTRA_STATUS, mInReplyToStatus)
|
||||
outState.putParcelable(EXTRA_USER, mMentionUser)
|
||||
outState.putParcelable(EXTRA_DRAFT, mDraft)
|
||||
outState.putBoolean(EXTRA_SHOULD_SAVE_ACCOUNTS, mShouldSaveAccounts)
|
||||
outState.putBoolean(EXTRA_SHOULD_SAVE_ACCOUNTS, shouldSaveAccounts)
|
||||
outState.putString(EXTRA_ORIGINAL_TEXT, mOriginalText)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
@ -310,7 +311,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
R.id.toggle_sensitive -> {
|
||||
if (!hasMedia()) return false
|
||||
mIsPossiblySensitive = !mIsPossiblySensitive
|
||||
possiblySensitive = !possiblySensitive
|
||||
setMenu()
|
||||
updateTextCount()
|
||||
}
|
||||
@ -320,7 +321,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
try {
|
||||
val action = intent.action
|
||||
if (INTENT_ACTION_EXTENSION_COMPOSE == action) {
|
||||
val accountKeys = mAccountsAdapter!!.selectedAccountKeys
|
||||
val accountKeys = accountsAdapter!!.selectedAccountKeys
|
||||
intent.putExtra(EXTRA_TEXT, ParseUtils.parseString(editText.text))
|
||||
intent.putExtra(EXTRA_ACCOUNT_KEYS, accountKeys)
|
||||
if (accountKeys.size > 0) {
|
||||
@ -420,11 +421,11 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
val draft = Draft()
|
||||
|
||||
draft.action_type = getDraftAction(intent.action)
|
||||
draft.account_keys = mAccountsAdapter!!.selectedAccountKeys
|
||||
draft.account_keys = accountsAdapter!!.selectedAccountKeys
|
||||
draft.text = text
|
||||
val extra = UpdateStatusActionExtra()
|
||||
extra.inReplyToStatus = mInReplyToStatus
|
||||
extra.setIsPossiblySensitive(mIsPossiblySensitive)
|
||||
extra.setIsPossiblySensitive(possiblySensitive)
|
||||
draft.action_extras = extra
|
||||
draft.media = media
|
||||
draft.location = mRecentLocation
|
||||
@ -529,9 +530,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
linearLayoutManager.stackFromEnd = true
|
||||
accountSelector!!.layoutManager = linearLayoutManager
|
||||
accountSelector!!.itemAnimator = DefaultItemAnimator()
|
||||
mAccountsAdapter = AccountIconsAdapter(this)
|
||||
accountSelector!!.adapter = mAccountsAdapter
|
||||
mAccountsAdapter!!.setAccounts(accounts)
|
||||
accountsAdapter = AccountIconsAdapter(this)
|
||||
accountSelector!!.adapter = accountsAdapter
|
||||
accountsAdapter!!.setAccounts(accounts)
|
||||
|
||||
|
||||
val adapter = MediaPreviewAdapter(this, PreviewGridOnStartDragListener(this))
|
||||
@ -551,8 +552,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
if (savedInstanceState != null) {
|
||||
// Restore from previous saved state
|
||||
val selected = Utils.newParcelableArray(savedInstanceState.getParcelableArray(EXTRA_ACCOUNT_KEYS), UserKey.CREATOR)
|
||||
mAccountsAdapter!!.setSelectedAccountIds(*selected)
|
||||
mIsPossiblySensitive = savedInstanceState.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE)
|
||||
accountsAdapter!!.setSelectedAccountIds(*selected)
|
||||
possiblySensitive = savedInstanceState.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE)
|
||||
val mediaList = savedInstanceState.getParcelableArrayList<ParcelableMediaUpdate>(EXTRA_MEDIA)
|
||||
if (mediaList != null) {
|
||||
addMedia(mediaList)
|
||||
@ -560,7 +561,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
mInReplyToStatus = savedInstanceState.getParcelable<ParcelableStatus>(EXTRA_STATUS)
|
||||
mMentionUser = savedInstanceState.getParcelable<ParcelableUser>(EXTRA_USER)
|
||||
mDraft = savedInstanceState.getParcelable<Draft>(EXTRA_DRAFT)
|
||||
mShouldSaveAccounts = savedInstanceState.getBoolean(EXTRA_SHOULD_SAVE_ACCOUNTS)
|
||||
shouldSaveAccounts = savedInstanceState.getBoolean(EXTRA_SHOULD_SAVE_ACCOUNTS)
|
||||
mOriginalText = savedInstanceState.getString(EXTRA_ORIGINAL_TEXT)
|
||||
setLabel(intent)
|
||||
} else {
|
||||
@ -574,15 +575,15 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
handleDefaultIntent(intent)
|
||||
}
|
||||
setLabel(intent)
|
||||
val selectedAccountIds = mAccountsAdapter!!.selectedAccountKeys
|
||||
val selectedAccountIds = accountsAdapter!!.selectedAccountKeys
|
||||
if (ArrayUtils.isEmpty(selectedAccountIds)) {
|
||||
val idsInPrefs: Array<UserKey> = UserKey.arrayOf(preferences.getString(KEY_COMPOSE_ACCOUNTS, null)) ?: emptyArray()
|
||||
val intersection: Array<UserKey> = defaultAccountIds.intersect(listOf(*idsInPrefs)).toTypedArray()
|
||||
|
||||
if (intersection.isEmpty()) {
|
||||
mAccountsAdapter!!.setSelectedAccountIds(*defaultAccountIds)
|
||||
accountsAdapter!!.setSelectedAccountIds(*defaultAccountIds)
|
||||
} else {
|
||||
mAccountsAdapter!!.setSelectedAccountIds(*intersection)
|
||||
accountsAdapter!!.setSelectedAccountIds(*intersection)
|
||||
}
|
||||
}
|
||||
mOriginalText = ParseUtils.parseString(editText.text)
|
||||
@ -776,17 +777,17 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
if (intent.hasExtra(EXTRA_ACCOUNT_KEYS)) {
|
||||
val accountKeys = Utils.newParcelableArray(
|
||||
intent.getParcelableArrayExtra(EXTRA_ACCOUNT_KEYS), UserKey.CREATOR)
|
||||
mAccountsAdapter!!.setSelectedAccountIds(*accountKeys)
|
||||
accountsAdapter!!.setSelectedAccountIds(*accountKeys)
|
||||
hasAccountIds = true
|
||||
} else if (intent.hasExtra(EXTRA_ACCOUNT_KEY)) {
|
||||
val accountKey = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
|
||||
mAccountsAdapter!!.setSelectedAccountIds(accountKey)
|
||||
accountsAdapter!!.setSelectedAccountIds(accountKey)
|
||||
hasAccountIds = true
|
||||
} else {
|
||||
hasAccountIds = false
|
||||
}
|
||||
if (Intent.ACTION_SEND == action) {
|
||||
mShouldSaveAccounts = false
|
||||
shouldSaveAccounts = false
|
||||
val stream = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (stream != null) {
|
||||
val src = arrayOf(stream)
|
||||
@ -795,7 +796,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
ParcelableMedia.Type.IMAGE), false))
|
||||
}
|
||||
} else if (Intent.ACTION_SEND_MULTIPLE == action) {
|
||||
mShouldSaveAccounts = false
|
||||
shouldSaveAccounts = false
|
||||
val extraStream = intent.getParcelableArrayListExtra<Uri>(Intent.EXTRA_STREAM)
|
||||
if (extraStream != null) {
|
||||
val src = extraStream.toTypedArray()
|
||||
@ -804,7 +805,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
ParcelableMedia.Type.IMAGE), false))
|
||||
}
|
||||
} else {
|
||||
mShouldSaveAccounts = !hasAccountIds
|
||||
shouldSaveAccounts = !hasAccountIds
|
||||
val data = intent.data
|
||||
if (data != null) {
|
||||
val src = arrayOf(data)
|
||||
@ -831,14 +832,14 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
editText.setText(draft.text)
|
||||
val selectionEnd = editText.length()
|
||||
editText.setSelection(selectionEnd)
|
||||
mAccountsAdapter!!.setSelectedAccountIds(*draft.account_keys ?: emptyArray())
|
||||
accountsAdapter!!.setSelectedAccountIds(*draft.account_keys ?: emptyArray())
|
||||
if (draft.media != null) {
|
||||
addMedia(Arrays.asList(*draft.media))
|
||||
}
|
||||
mRecentLocation = draft.location
|
||||
if (draft.action_extras is UpdateStatusActionExtra) {
|
||||
val extra = draft.action_extras as UpdateStatusActionExtra?
|
||||
mIsPossiblySensitive = extra!!.isPossiblySensitive
|
||||
possiblySensitive = extra!!.isPossiblySensitive
|
||||
mInReplyToStatus = extra.inReplyToStatus
|
||||
}
|
||||
return true
|
||||
@ -899,7 +900,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
|
||||
private fun handleIntent(intent: Intent): Boolean {
|
||||
val action = intent.action ?: return false
|
||||
mShouldSaveAccounts = false
|
||||
shouldSaveAccounts = false
|
||||
mMentionUser = intent.getParcelableExtra<ParcelableUser>(EXTRA_USER)
|
||||
mInReplyToStatus = intent.getParcelableExtra<ParcelableStatus>(EXTRA_STATUS)
|
||||
when (action) {
|
||||
@ -940,7 +941,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
editText.setText(String.format("@%s ", user.screen_name))
|
||||
val selection_end = editText.length()
|
||||
editText.setSelection(selection_end)
|
||||
mAccountsAdapter!!.setSelectedAccountIds(user.account_key)
|
||||
accountsAdapter!!.setSelectedAccountIds(user.account_key)
|
||||
return true
|
||||
}
|
||||
|
||||
@ -948,7 +949,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
if (status == null) return false
|
||||
editText.setText(Utils.getQuoteStatus(this, status))
|
||||
editText.setSelection(0)
|
||||
mAccountsAdapter!!.setSelectedAccountIds(status.account_key)
|
||||
accountsAdapter!!.setSelectedAccountIds(status.account_key)
|
||||
showQuoteLabel(status)
|
||||
return true
|
||||
}
|
||||
@ -1003,16 +1004,16 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
mentions.add(mention.screen_name)
|
||||
}
|
||||
mentions.addAll(extractor!!.extractMentionedScreennames(status.quoted_text_plain))
|
||||
mentions.addAll(extractor.extractMentionedScreennames(status.quoted_text_plain))
|
||||
} else if (USER_TYPE_FANFOU_COM == status.account_key.host) {
|
||||
addFanfouHtmlToMentions(status.text_unescaped, status.spans, mentions)
|
||||
if (status.is_quote) {
|
||||
addFanfouHtmlToMentions(status.quoted_text_unescaped, status.quoted_spans, mentions)
|
||||
}
|
||||
} else {
|
||||
mentions.addAll(extractor!!.extractMentionedScreennames(status.text_plain))
|
||||
mentions.addAll(extractor.extractMentionedScreennames(status.text_plain))
|
||||
if (status.is_quote) {
|
||||
mentions.addAll(extractor!!.extractMentionedScreennames(status.quoted_text_plain))
|
||||
mentions.addAll(extractor.extractMentionedScreennames(status.quoted_text_plain))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1024,7 +1025,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
val selectionEnd = editText.length()
|
||||
editText.setSelection(selectionStart, selectionEnd)
|
||||
mAccountsAdapter!!.setSelectedAccountIds(status.account_key)
|
||||
accountsAdapter!!.setSelectedAccountIds(status.account_key)
|
||||
showReplyLabel(status)
|
||||
return true
|
||||
}
|
||||
@ -1054,7 +1055,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
editText.append("@$screenName ")
|
||||
}
|
||||
editText.setSelection(editText.length())
|
||||
mAccountsAdapter!!.setSelectedAccountIds(accountId)
|
||||
accountsAdapter!!.setSelectedAccountIds(accountId)
|
||||
mInReplyToStatus = inReplyToStatus
|
||||
return true
|
||||
}
|
||||
@ -1081,7 +1082,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
|
||||
private fun notifyAccountSelectionChanged() {
|
||||
val accounts = mAccountsAdapter!!.selectedAccounts
|
||||
val accounts = accountsAdapter!!.selectedAccounts
|
||||
setSelectedAccounts(*accounts)
|
||||
if (ArrayUtils.isEmpty(accounts)) {
|
||||
editText.setAccountKey(Utils.getDefaultAccountKey(this))
|
||||
@ -1099,9 +1100,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
|
||||
private fun saveAccountSelection() {
|
||||
if (!mShouldSaveAccounts) return
|
||||
if (!shouldSaveAccounts) return
|
||||
val editor = preferences.edit()
|
||||
editor.putString(KEY_COMPOSE_ACCOUNTS, TwidereArrayUtils.toString(mAccountsAdapter!!.selectedAccountKeys, ',', false))
|
||||
editor.putString(KEY_COMPOSE_ACCOUNTS, TwidereArrayUtils.toString(accountsAdapter!!.selectedAccountKeys, ',', false))
|
||||
editor.apply()
|
||||
}
|
||||
|
||||
@ -1115,21 +1116,21 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
* Has media & Not reply: [Take photo][Media menu][Attach location][Drafts]
|
||||
* Is reply: [Media menu][View status][Attach location][Drafts]
|
||||
*/
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.add_image, !hasMedia)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.media_menu, hasMedia)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.toggle_sensitive, hasMedia)
|
||||
MenuUtils.setMenuItemAvailability(menu, R.id.schedule, isScheduleSupported)
|
||||
MenuUtils.setItemAvailability(menu, R.id.add_image, !hasMedia)
|
||||
MenuUtils.setItemAvailability(menu, R.id.media_menu, hasMedia)
|
||||
MenuUtils.setItemAvailability(menu, R.id.toggle_sensitive, hasMedia)
|
||||
MenuUtils.setItemAvailability(menu, R.id.schedule, scheduleSupported)
|
||||
|
||||
menu.setGroupEnabled(MENU_GROUP_IMAGE_EXTENSION, hasMedia)
|
||||
menu.setGroupVisible(MENU_GROUP_IMAGE_EXTENSION, hasMedia)
|
||||
MenuUtils.setMenuItemChecked(menu, R.id.toggle_sensitive, hasMedia && mIsPossiblySensitive)
|
||||
menu.setItemChecked(R.id.toggle_sensitive, hasMedia && possiblySensitive)
|
||||
ThemeUtils.resetCheatSheet(menuBar)
|
||||
// mMenuBar.show();
|
||||
}
|
||||
|
||||
private val isScheduleSupported: Boolean
|
||||
private val scheduleSupported: Boolean
|
||||
get() {
|
||||
val accounts = mAccountsAdapter!!.selectedAccounts
|
||||
val accounts = accountsAdapter!!.selectedAccounts
|
||||
if (ArrayUtils.isEmpty(accounts)) return false
|
||||
for (account in accounts) {
|
||||
if (TwitterContentUtils.getOfficialKeyType(this, account.consumer_key, account.consumer_secret) != ConsumerKeyType.TWEETDECK) {
|
||||
@ -1173,8 +1174,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
} else {
|
||||
if (locationText!!.tag == null || location != mRecentLocation) {
|
||||
val task = DisplayPlaceNameTask(this)
|
||||
task.setParams(location)
|
||||
task.setResultHandler(locationText)
|
||||
task.params = location
|
||||
task.setCallback(locationText)
|
||||
TaskStarter.execute(task)
|
||||
}
|
||||
}
|
||||
@ -1256,7 +1257,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
val text = if (editText != null) ParseUtils.parseString(editText.text) else null
|
||||
val tweetLength = validator!!.getTweetLength(text)
|
||||
val maxLength = statusTextCount.maxLength
|
||||
if (mAccountsAdapter!!.isSelectionEmpty) {
|
||||
if (accountsAdapter!!.isSelectionEmpty) {
|
||||
editText.error = getString(R.string.no_account_selected)
|
||||
return
|
||||
} else if (!hasMedia && (TextUtils.isEmpty(text) || noReplyContent(text))) {
|
||||
@ -1270,8 +1271,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
}
|
||||
val attachLocation = preferences.getBoolean(KEY_ATTACH_LOCATION)
|
||||
val attachPreciseLocation = preferences.getBoolean(KEY_ATTACH_PRECISE_LOCATION)
|
||||
val accountKeys = mAccountsAdapter!!.selectedAccountKeys
|
||||
val isPossiblySensitive = hasMedia && mIsPossiblySensitive
|
||||
val accountKeys = accountsAdapter!!.selectedAccountKeys
|
||||
val isPossiblySensitive = hasMedia && possiblySensitive
|
||||
val update = ParcelableStatusUpdate()
|
||||
@Draft.Action val action: String
|
||||
if (mDraft != null) {
|
||||
@ -1290,8 +1291,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
update.is_possibly_sensitive = isPossiblySensitive
|
||||
BackgroundOperationService.updateStatusesAsync(this, action, update)
|
||||
if (preferences.getBoolean(KEY_NO_CLOSE_AFTER_TWEET_SENT, false) && mInReplyToStatus == null) {
|
||||
mIsPossiblySensitive = false
|
||||
mShouldSaveAccounts = true
|
||||
possiblySensitive = false
|
||||
shouldSaveAccounts = true
|
||||
mInReplyToStatus = null
|
||||
mMentionUser = null
|
||||
mDraft = null
|
||||
@ -1312,7 +1313,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
|
||||
private fun updateTextCount() {
|
||||
val text = ParseUtils.parseString(editText.text)
|
||||
val validatedCount = if (text != null) validator!!.getTweetLength(text) else 0
|
||||
val validatedCount = if (text != null) validator.getTweetLength(text) else 0
|
||||
statusTextCount.textCount = validatedCount
|
||||
}
|
||||
|
||||
@ -1326,14 +1327,14 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||
|
||||
internal class ComposeLocationListener(activity: ComposeActivity) : LocationListener {
|
||||
|
||||
val mActivityRef: WeakReference<ComposeActivity>
|
||||
val activityRef: WeakReference<ComposeActivity>
|
||||
|
||||
init {
|
||||
mActivityRef = WeakReference(activity)
|
||||
activityRef = WeakReference(activity)
|
||||
}
|
||||
|
||||
override fun onLocationChanged(location: Location) {
|
||||
val activity = mActivityRef.get() ?: return
|
||||
val activity = activityRef.get() ?: return
|
||||
activity.setRecentLocation(ParcelableLocationUtils.fromLocation(location))
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user