Commit 68946a30 authored by Grigory Fedorov's avatar Grigory Fedorov

ChatViewer and ChatViewerFragment rewritten. ChatViewerAdapter removed. No scroll chat for now.

Dialogs do not use support libraries.
parent bcbb1c98
......@@ -17,9 +17,6 @@ package com.xabber.android.ui;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import com.xabber.android.data.ActivityManager;
import com.xabber.android.data.Application;
......@@ -33,10 +30,7 @@ import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.message.OnChatChangedListener;
import com.xabber.android.data.notification.NotificationManager;
import com.xabber.android.data.roster.OnContactChangedListener;
import com.xabber.android.ui.adapter.ChatViewerAdapter;
import com.xabber.android.ui.helper.ManagedActivity;
import com.xabber.android.ui.widget.PageSwitcher;
import com.xabber.android.ui.widget.PageSwitcher.OnSelectListener;
import com.xabber.androiddev.R;
import java.util.Collection;
......@@ -44,14 +38,11 @@ import java.util.Collection;
/**
* Chat activity.
* <p/>
* Warning: {@link PageSwitcher} is to be removed and related implementation is
* to be fixed.
*
* @author alexander.ivanov
*/
public class ChatViewer extends ManagedActivity implements OnSelectListener,
OnChatChangedListener, OnContactChangedListener,
OnAccountChangedListener {
public class ChatViewer extends ManagedActivity implements OnChatChangedListener,
OnContactChangedListener, OnAccountChangedListener {
/**
* Attention request.
......@@ -62,60 +53,57 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
private static final String SAVED_USER = "com.xabber.android.ui.ChatViewer.SAVED_USER";
private static final String SAVED_EXIT_ON_SEND = "com.xabber.android.ui.ChatViewer.EXIT_ON_SEND";
private ChatViewerAdapter chatViewerAdapter;
private PageSwitcher pageSwitcher;
private String actionWithAccount;
private String actionWithUser;
private View actionWithView;
private boolean exitOnSend;
private boolean isVisible;
@Override
public void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isFinishing())
if (isFinishing()) {
return;
}
Intent intent = getIntent();
String account = getAccount(intent);
String user = getUser(intent);
if (PageSwitcher.LOG)
LogManager.i(this, "Intent: " + account + ":" + user);
if (account == null || user == null) {
Application.getInstance().onError(R.string.ENTRY_IS_NOT_FOUND);
finish();
return;
}
if (hasAttention(intent))
AttentionManager.getInstance().removeAccountNotifications(account,
user);
if (hasAttention(intent)) {
AttentionManager.getInstance().removeAccountNotifications(account, user);
}
actionWithAccount = null;
actionWithUser = null;
actionWithView = null;
setContentView(R.layout.chat_viewer);
chatViewerAdapter = new ChatViewerAdapter(this, account, user);
pageSwitcher = (PageSwitcher) findViewById(R.id.switcher);
pageSwitcher.setAdapter(chatViewerAdapter);
pageSwitcher.setOnSelectListener(this);
setContentView(R.layout.activity_preferences);
if (savedInstanceState != null) {
actionWithAccount = savedInstanceState.getString(SAVED_ACCOUNT);
actionWithUser = savedInstanceState.getString(SAVED_USER);
exitOnSend = savedInstanceState.getBoolean(SAVED_EXIT_ON_SEND);
}
if (actionWithAccount == null)
if (actionWithAccount == null) {
actionWithAccount = account;
if (actionWithUser == null)
}
if (actionWithUser == null) {
actionWithUser = user;
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
selectChat(actionWithAccount, actionWithUser);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.preferences_activity_container,
ChatViewerFragment.newInstance(actionWithAccount, actionWithUser)).commit();
}
}
@Override
......@@ -127,28 +115,26 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
this);
Application.getInstance().addUIListener(OnAccountChangedListener.class,
this);
chatViewerAdapter.onChange();
if (actionWithView != null)
chatViewerAdapter.onChatChange(actionWithView, false);
((ChatViewerFragment)getFragmentManager()
.findFragmentById(R.id.preferences_activity_container)).onChange();
Intent intent = getIntent();
if (Intent.ACTION_SEND.equals(intent.getAction())) {
String additional = intent.getStringExtra(Intent.EXTRA_TEXT);
if (additional != null) {
intent.removeExtra(Intent.EXTRA_TEXT);
exitOnSend = true;
if (actionWithView != null)
chatViewerAdapter.insertText(actionWithView, additional);
}
}
isVisible = true;
update();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (PageSwitcher.LOG)
LogManager.i(this, "onSave: " + actionWithAccount + ":"
+ actionWithUser);
LogManager.i(this, "onSave: " + actionWithAccount + ":" + actionWithUser);
outState.putString(SAVED_ACCOUNT, actionWithAccount);
outState.putString(SAVED_USER, actionWithUser);
outState.putBoolean(SAVED_EXIT_ON_SEND, exitOnSend);
......@@ -164,8 +150,6 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
Application.getInstance().removeUIListener(
OnAccountChangedListener.class, this);
MessageManager.getInstance().removeVisibleChat();
pageSwitcher.saveState();
isVisible = false;
}
@Override
......@@ -179,163 +163,40 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
if (account == null || user == null) {
return;
}
if (hasAttention(intent))
AttentionManager.getInstance().removeAccountNotifications(account,
user);
chatViewerAdapter.onChange();
if (!selectChat(account, user))
Application.getInstance().onError(R.string.ENTRY_IS_NOT_FOUND);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.clear();
chatViewerAdapter.onPrepareOptionsMenu(actionWithView, menu);
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
close();
return false;
}
return super.onKeyDown(keyCode, event);
}
void close() {
finish();
if (!Intent.ACTION_SEND.equals(getIntent().getAction())) {
ActivityManager.getInstance().clearStack(false);
if (!ActivityManager.getInstance().hasContactList(this))
startActivity(ContactList.createIntent(this));
}
}
void onSent() {
if (exitOnSend)
close();
}
@Override
public void onSelect() {
BaseEntity contactItem = (BaseEntity) pageSwitcher.getSelectedItem();
actionWithAccount = contactItem.getAccount();
actionWithUser = contactItem.getUser();
if (PageSwitcher.LOG)
LogManager.i(this, "onSelect: " + actionWithAccount + ":"
+ actionWithUser);
actionWithView = pageSwitcher.getSelectedView();
if (isVisible)
MessageManager.getInstance().setVisibleChat(actionWithAccount,
actionWithUser);
MessageArchiveManager.getInstance().requestHistory(
actionWithAccount,
actionWithUser,
0,
MessageManager.getInstance()
.getChat(actionWithAccount, actionWithUser)
.getRequiredMessageCount());
NotificationManager.getInstance().removeMessageNotification(
actionWithAccount, actionWithUser);
}
@Override
public void onUnselect() {
actionWithAccount = null;
actionWithUser = null;
actionWithView = null;
if (PageSwitcher.LOG)
LogManager.i(this, "onUnselect");
}
@Override
public void onChatChanged(final String account, final String user,
final boolean incoming) {
BaseEntity baseEntity;
baseEntity = (BaseEntity) pageSwitcher.getSelectedItem();
if (baseEntity != null && baseEntity.equals(account, user)) {
chatViewerAdapter.onChatChange(pageSwitcher.getSelectedView(),
incoming);
return;
}
baseEntity = (BaseEntity) pageSwitcher.getVisibleItem();
if (baseEntity != null && baseEntity.equals(account, user)) {
chatViewerAdapter.onChatChange(pageSwitcher.getVisibleView(),
incoming);
return;
}
// Search for chat in adapter.
final int count = chatViewerAdapter.getCount();
for (int index = 0; index < count; index++)
if (((BaseEntity) chatViewerAdapter.getItem(index)).equals(account,
user))
return;
// New chat.
chatViewerAdapter.onChange();
}
actionWithAccount = account;
actionWithUser = user;
@Override
public void onContactsChanged(Collection<BaseEntity> entities) {
BaseEntity baseEntity;
baseEntity = (BaseEntity) pageSwitcher.getSelectedItem();
if (baseEntity != null && entities.contains(baseEntity)) {
chatViewerAdapter.onChange();
return;
}
baseEntity = (BaseEntity) pageSwitcher.getVisibleItem();
if (baseEntity != null && entities.contains(baseEntity)) {
chatViewerAdapter.onChange();
return;
}
}
if (hasAttention(intent))
AttentionManager.getInstance().removeAccountNotifications(account, user);
@Override
public void onAccountsChanged(Collection<String> accounts) {
BaseEntity baseEntity;
baseEntity = (BaseEntity) pageSwitcher.getSelectedItem();
if (baseEntity != null && accounts.contains(baseEntity.getAccount())) {
chatViewerAdapter.onChange();
return;
}
baseEntity = (BaseEntity) pageSwitcher.getVisibleItem();
if (baseEntity != null && accounts.contains(baseEntity.getAccount())) {
chatViewerAdapter.onChange();
return;
}
getFragmentManager().beginTransaction().replace(R.id.preferences_activity_container,
ChatViewerFragment.newInstance(actionWithAccount, actionWithUser)).commit();
}
private boolean selectChat(String account, String user) {
for (int position = 0; position < chatViewerAdapter.getCount(); position++)
if (((BaseEntity) chatViewerAdapter.getItem(position)).equals(
account, user)) {
if (PageSwitcher.LOG)
LogManager.i(this, "setSelection: " + position + ", "
+ account + ":" + user);
pageSwitcher.setSelection(position);
return true;
}
if (PageSwitcher.LOG)
LogManager.i(this, "setSelection: not found, " + account + ":"
+ user);
return false;
private static String getAccount(Intent intent) {
String value = EntityIntentBuilder.getAccount(intent);
if (value != null)
return value;
// Backward compatibility.
return intent.getStringExtra("com.xabber.android.data.account");
}
public int getChatCount() {
return chatViewerAdapter.getCount();
private static String getUser(Intent intent) {
String value = EntityIntentBuilder.getUser(intent);
if (value != null)
return value;
// Backward compatibility.
return intent.getStringExtra("com.xabber.android.data.user");
}
public int getChatPosition(String account, String user) {
return chatViewerAdapter.getPosition(account, user);
private static boolean hasAttention(Intent intent) {
return ACTION_ATTENTION.equals(intent.getAction());
}
public static Intent createIntent(Context context, String account,
String user) {
return new EntityIntentBuilder(context, ChatViewer.class)
.setAccount(account).setUser(user).build();
return new EntityIntentBuilder(context, ChatViewer.class).setAccount(account).setUser(user).build();
}
public static Intent createClearTopIntent(Context context, String account,
......@@ -372,24 +233,59 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
return intent;
}
private static String getAccount(Intent intent) {
String value = EntityIntentBuilder.getAccount(intent);
if (value != null)
return value;
// Backward compatibility.
return intent.getStringExtra("com.xabber.android.data.account");
@Override
public void onChatChanged(final String account, final String user,
final boolean incoming) {
update();
((ChatViewerFragment)getFragmentManager()
.findFragmentById(R.id.preferences_activity_container)).onChatChange(incoming);
}
private static String getUser(Intent intent) {
String value = EntityIntentBuilder.getUser(intent);
if (value != null)
return value;
// Backward compatibility.
return intent.getStringExtra("com.xabber.android.data.user");
@Override
public void onContactsChanged(Collection<BaseEntity> entities) {
update();
((ChatViewerFragment)getFragmentManager()
.findFragmentById(R.id.preferences_activity_container)).onChange();
}
private static boolean hasAttention(Intent intent) {
return ACTION_ATTENTION.equals(intent.getAction());
@Override
public void onAccountsChanged(Collection<String> accounts) {
update();
((ChatViewerFragment)getFragmentManager()
.findFragmentById(R.id.preferences_activity_container)).onChange();
}
void onSent() {
if (exitOnSend) {
close();
}
}
void close() {
finish();
if (!Intent.ACTION_SEND.equals(getIntent().getAction())) {
ActivityManager.getInstance().clearStack(false);
if (!ActivityManager.getInstance().hasContactList(this)) {
startActivity(ContactList.createIntent(this));
}
}
}
void update() {
MessageManager.getInstance().setVisibleChat(actionWithAccount, actionWithUser);
MessageArchiveManager.getInstance().requestHistory(
actionWithAccount,
actionWithUser,
0,
MessageManager.getInstance()
.getChat(actionWithAccount, actionWithUser)
.getRequiredMessageCount());
NotificationManager.getInstance().removeMessageNotification(
actionWithAccount, actionWithUser);
}
}
package com.xabber.android.ui;
import android.app.Fragment;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.text.ClipboardManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.view.View.OnKeyListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.NetworkException;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.SettingsManager.ChatsHideKeyboard;
import com.xabber.android.data.SettingsManager.SecurityOtrMode;
import com.xabber.android.data.extension.archive.MessageArchiveManager;
import com.xabber.android.data.extension.attention.AttentionManager;
import com.xabber.android.data.extension.cs.ChatStateManager;
......@@ -58,101 +49,60 @@ import com.xabber.android.ui.dialog.ChatExportDialogFragment;
import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper;
import com.xabber.android.ui.helper.ContactTitleInflater;
import com.xabber.android.ui.preferences.ChatEditor;
import com.xabber.android.ui.widget.PageSwitcher;
import com.xabber.androiddev.R;
public class ChatViewerFragment implements OnCreateContextMenuListener {
/**
* Minimum number of new messages to be requested from the server side
* archive.
*/
private static final int MINIMUM_MESSAGES_TO_LOAD = 10;
/**
* Delay before hide pages.
*/
private static final long PAGES_HIDDER_DELAY = 1000;
private AbstractAvatarInflaterHelper avatarInflaterHelper;
private boolean skipOnTextChanges;
public class ChatViewerFragment extends Fragment {
public static final String ARGUMENT_ACCOUNT = "ARGUMENT_ACCOUNT";
public static final String ARGUMENT_USER = "ARGUMENT_USER";
private TextView pageView;
private View titleView;
private EditText inputView;
private ListView listView;
private ChatMessageAdapter chatMessageAdapter;
/**
* Whether pages are shown.
*/
private boolean pagesShown;
/**
* Animation used to hide pages.
*/
private Animation pagesHideAnimation;
private boolean skipOnTextChanges;
/**
* Animation used for incoming message notification.
*/
private Animation shakeAnimation;
private Handler handler;
/**
* Runnable called to hide pages.
*/
private final Runnable pagesHideRunnable = new Runnable() {
@Override
public void run() {
handler.removeCallbacks(this);
pageView.startAnimation(pagesHideAnimation);
}
};
private AbstractAvatarInflaterHelper avatarInflaterHelper;
private final FragmentActivity activity;
private static final int MINIMUM_MESSAGES_TO_LOAD = 10;
private String account;
private String user;
private final View view;
public ChatViewerFragment(FragmentActivity activity) {
this.activity = activity;
onCreate(null);
view = onCreateView(activity.getLayoutInflater(), null, null);
}
public static ChatViewerFragment newInstance(String account, String user) {
ChatViewerFragment fragment = new ChatViewerFragment();
private FragmentActivity getActivity() {
return activity;
Bundle args = new Bundle();
args.putString(ARGUMENT_ACCOUNT, account);
args.putString(ARGUMENT_USER, user);
fragment.setArguments(args);
return fragment;
}
private String getString(int resId, Object... formatArgs) {
return activity.getString(resId, formatArgs);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
private void registerForContextMenu(View view) {
view.setOnCreateContextMenuListener(this);
avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
}
public View getView() {
return view;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
public void onCreate(Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
avatarInflaterHelper = AbstractAvatarInflaterHelper
.createAbstractContactInflaterHelper();
handler = new Handler();
pagesShown = false;
}
shakeAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.shake);
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
shakeAnimation = AnimationUtils.loadAnimation(getActivity(),
R.anim.shake);
pagesHideAnimation = AnimationUtils.loadAnimation(getActivity(),
R.anim.chat_page_out);
pagesHideAnimation.setAnimationListener(new AnimationListener() {
/*
Animation used to hide pages.
*/
Animation pagesHideAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.chat_page_out);
pagesHideAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
......@@ -168,8 +118,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
}
});
View view = inflater.inflate(R.layout.chat_viewer_item, container,
false);
View view = inflater.inflate(R.layout.chat_viewer_item, container, false);
chatMessageAdapter = new ChatMessageAdapter(getActivity());
pageView = (TextView) view.findViewById(R.id.chat_page);
titleView = view.findViewById(R.id.title);
......@@ -178,7 +127,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
listView.setAdapter(chatMessageAdapter);
view.findViewById(R.id.chat_send).setOnClickListener(
new OnClickListener() {
new View.OnClickListener() {
@Override
public void onClick(View v) {
......@@ -186,7 +135,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
}
});
titleView.setOnClickListener(new OnClickListener() {
titleView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
......@@ -196,7 +145,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
}
});
inputView.setOnKeyListener(new OnKeyListener() {
inputView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int keyCode, KeyEvent event) {
......@@ -210,7 +159,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
}
});
inputView.setOnEditorActionListener(new OnEditorActionListener() {
inputView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView view, int actionId,
......@@ -246,15 +195,107 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
});
registerForContextMenu(listView);
Bundle args = getArguments();
account = args.getString(ARGUMENT_ACCOUNT, null);
user = args.getString(ARGUMENT_USER, null);
setHasOptionsMenu(true);
setChat(account, user);
chatMessageAdapter.onChange();
return view;
}
private void sendMessage() {
String text = inputView.getText().toString();
int start = 0;
int end = text.length();
while (start < end
&& (text.charAt(start) == ' ' || text.charAt(start) == '\n'))
start += 1;
while (start < end
&& (text.charAt(end - 1) == ' ' || text.charAt(end - 1) == '\n'))
end -= 1;
text = text.substring(start, end);
if ("".equals(text))
return;
skipOnTextChanges = true;
inputView.setText("");
skipOnTextChanges = false;
sendMessage(text);
((ChatViewer) getActivity()).onSent();
if (SettingsManager.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.always
|| (getActivity().getResources().getBoolean(R.bool.landscape) && SettingsManager
.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.landscape)) {
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(inputView.getWindowToken(), 0);
}
}
private void sendMessage(String text) {
final String account = chatMessageAdapter.getAccount();
final String user = chatMessageAdapter.getUser();
MessageManager.getInstance().sendMessage(account, user, text);
onChatChange(false);
}
public void onChatChange(boolean incomingMessage) {
if (incomingMessage) {
titleView.findViewById(R.id.name_holder).startAnimation(
shakeAnimation);
}
setChat(account, user);
chatMessageAdapter.onChange();
}
public void onChange() {
setChat(account, user);
chatMessageAdapter.onChange();
}
public void setChat(String account, String user) {
final AbstractContact abstractContact = RosterManager.getInstance()
.getBestContact(account, user);
LogManager.i(this, "setChat " + chatMessageAdapter.getUser() + " in " + chatMessageAdapter.getAccount());
skipOnTextChanges = true;
inputView.setText(ChatManager.getInstance().getTypedMessage(account, user));
inputView.setSelection(ChatManager.getInstance().getSelectionStart(account, user),
ChatManager.getInstance().getSelectionEnd(account, user));
skipOnTextChanges = false;
chatMessageAdapter.setChat(account, user);
listView.setAdapter(listView.getAdapter());
ContactTitleInflater.updateTitle(titleView, getActivity(), abstractContact);
avatarInflaterHelper.updateAvatar((ImageView) titleView.findViewById(R.id.avatar), abstractContact);
SecurityLevel securityLevel = OTRManager.getInstance().getSecurityLevel(account, user);
SettingsManager.SecurityOtrMode securityOtrMode = SettingsManager.securityOtrMode();
ImageView securityView = (ImageView) titleView
.findViewById(R.id.security);
if (securityLevel == SecurityLevel.plain
&& (securityOtrMode == SettingsManager.SecurityOtrMode.disabled
|| securityOtrMode == SettingsManager.SecurityOtrMode.manual)) {
securityView.setVisibility(View.GONE);
} else {
securityView.setVisibility(View.VISIBLE);
securityView.setImageLevel(securityLevel.getImageLevel());
}
}
public boolean onPrepareOptionsMenu(Menu menu) {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
final String account = chatMessageAdapter.getAccount();
final String user = chatMessageAdapter.getUser();
AbstractChat abstractChat = MessageManager.getInstance().getChat(account, user);
getActivity().getMenuInflater().inflate(R.menu.chat, menu);
inflater.inflate(R.menu.chat, menu);
if (abstractChat != null && abstractChat instanceof RoomChat) {
if (((RoomChat) abstractChat).getState() == RoomState.unavailable) {
......@@ -352,10 +393,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
@Override
public boolean onMenuItemClick(MenuItem item) {
ChatExportDialogFragment
.newInstance(account, user)
.show(getActivity().getSupportFragmentManager(),
"CHAT_EXPORT");
ChatExportDialogFragment.newInstance(account, user).show(getActivity().getFragmentManager(), "CHAT_EXPORT");
return true;
}
......@@ -379,7 +417,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
abstractChat.getUser());
if (securityLevel == SecurityLevel.plain) {
menu.findItem(R.id.action_start_encryption).setVisible(true)
.setEnabled(SettingsManager.securityOtrMode() != SecurityOtrMode.disabled)
.setEnabled(SettingsManager.securityOtrMode() != SettingsManager.SecurityOtrMode.disabled)
.setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
......@@ -446,20 +484,19 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
&& ((RoomChat) abstractChat).getState() == RoomState.available)
menu.findItem(R.id.action_list_of_occupants).setVisible(true).setIntent(
OccupantList.createIntent(getActivity(), account, user));
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view,
ContextMenuInfo menuInfo) {
// super.onCreateContextMenu(menu, view, menuInfo);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
final MessageItem message = (MessageItem) listView.getAdapter().getItem(info.position);
final MessageItem message = (MessageItem) listView.getAdapter()
.getItem(info.position);
if (message != null && message.getAction() != null)
if (message == null || message.getAction() == null) {
return;
}
if (message.isError()) {
menu.add(R.string.message_repeat).setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
......@@ -507,93 +544,6 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
});
}
public void setChat(AbstractChat chat) {
final String account = chat.getAccount();
final String user = chat.getUser();
final AbstractContact abstractContact = RosterManager.getInstance()
.getBestContact(account, user);
if (chat.equals(chatMessageAdapter.getAccount(),
chatMessageAdapter.getUser())) {
chatMessageAdapter.updateInfo();
} else {
if (chatMessageAdapter.getAccount() != null
&& chatMessageAdapter.getUser() != null)
saveState();
if (PageSwitcher.LOG)
LogManager.i(this, "Load " + chatMessageAdapter.getUser()
+ " in " + chatMessageAdapter.getAccount());
skipOnTextChanges = true;
inputView.setText(ChatManager.getInstance().getTypedMessage(
account, user));
inputView.setSelection(
ChatManager.getInstance().getSelectionStart(account, user),
ChatManager.getInstance().getSelectionEnd(account, user));
skipOnTextChanges = false;
chatMessageAdapter.setChat(account, user);
listView.setAdapter(listView.getAdapter());
}
pageView.setText(getString(
R.string.chat_page,
((ChatViewer) getActivity()).getChatPosition(account, user) + 1,
((ChatViewer) getActivity()).getChatCount()));
ContactTitleInflater.updateTitle(titleView, getActivity(),
abstractContact);
avatarInflaterHelper.updateAvatar(
(ImageView) titleView.findViewById(R.id.avatar),
abstractContact);
SecurityLevel securityLevel = OTRManager.getInstance()
.getSecurityLevel(chat.getAccount(), chat.getUser());
SecurityOtrMode securityOtrMode = SettingsManager.securityOtrMode();
ImageView securityView = (ImageView) titleView
.findViewById(R.id.security);
if (securityLevel == SecurityLevel.plain
&& (securityOtrMode == SecurityOtrMode.disabled || securityOtrMode == SecurityOtrMode.manual)) {
securityView.setVisibility(View.GONE);
} else {
securityView.setVisibility(View.VISIBLE);
securityView.setImageLevel(securityLevel.getImageLevel());
}
}
public void saveState() {
if (PageSwitcher.LOG)
LogManager.i(this, "Save " + chatMessageAdapter.getUser() + " in "
+ chatMessageAdapter.getAccount());
ChatManager.getInstance().setTyped(chatMessageAdapter.getAccount(),
chatMessageAdapter.getUser(), inputView.getText().toString(),
inputView.getSelectionStart(), inputView.getSelectionEnd());
}
public void onChatChange(boolean incomingMessage) {
if (incomingMessage)
titleView.findViewById(R.id.name_holder).startAnimation(
shakeAnimation);
chatMessageAdapter.onChange();
}
/**
* Show pages.
*/
public void showPages() {
if (pagesShown)
return;
pagesShown = true;
handler.removeCallbacks(pagesHideRunnable);
pageView.clearAnimation();
pageView.setVisibility(View.VISIBLE);
}
/**
* Requests pages to be hiden in future.
*/
public void hidePages() {
if (!pagesShown)
return;
pagesShown = false;
handler.postDelayed(pagesHideRunnable, PAGES_HIDDER_DELAY);
}
/**
* Insert additional text to the input.
*
......@@ -613,39 +563,4 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
inputView.setText(before + additional + after);
inputView.setSelection(selection + additional.length());
}
private void sendMessage() {
String text = inputView.getText().toString();
int start = 0;
int end = text.length();
while (start < end
&& (text.charAt(start) == ' ' || text.charAt(start) == '\n'))
start += 1;
while (start < end
&& (text.charAt(end - 1) == ' ' || text.charAt(end - 1) == '\n'))
end -= 1;
text = text.substring(start, end);
if ("".equals(text))
return;
skipOnTextChanges = true;
inputView.setText("");
skipOnTextChanges = false;
sendMessage(text);
((ChatViewer) getActivity()).onSent();
if (SettingsManager.chatsHideKeyboard() == ChatsHideKeyboard.always
|| (getActivity().getResources().getBoolean(R.bool.landscape) && SettingsManager
.chatsHideKeyboard() == ChatsHideKeyboard.landscape)) {
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(inputView.getWindowToken(), 0);
}
}
private void sendMessage(String text) {
final String account = chatMessageAdapter.getAccount();
final String user = chatMessageAdapter.getUser();
MessageManager.getInstance().sendMessage(account, user, text);
onChatChange(false);
}
}
......@@ -171,8 +171,8 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O
text);
return;
}
AccountChooseDialogFragment.newInstance(bareAddress, text).show(
getSupportFragmentManager(), "OPEN_WITH_ACCOUNT");
AccountChooseDialogFragment.newInstance(bareAddress, text)
.show(getFragmentManager(), "OPEN_WITH_ACCOUNT");
}
/**
......@@ -240,15 +240,14 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O
if (SettingsManager.bootCount() > 2
&& !SettingsManager.connectionStartAtBoot()
&& !SettingsManager.startAtBootSuggested())
StartAtBootDialogFragment.newInstance().show(
getSupportFragmentManager(), "START_AT_BOOT");
StartAtBootDialogFragment.newInstance().show(getFragmentManager(), "START_AT_BOOT");
if (!SettingsManager.contactIntegrationSuggested()
&& Application.getInstance().isContactsSupported()) {
if (AccountManager.getInstance().getAllAccounts().isEmpty())
SettingsManager.setContactIntegrationSuggested();
else
ContactIntegrationDialogFragment.newInstance().show(
getSupportFragmentManager(), "CONTACT_INTEGRATION");
getFragmentManager(), "CONTACT_INTEGRATION");
}
}
}
......
......@@ -14,10 +14,6 @@
*/
package com.xabber.android.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
......@@ -34,6 +30,10 @@ import com.xabber.android.ui.dialog.GroupAddDialogFragment.OnGroupAddConfirmed;
import com.xabber.android.ui.helper.ManagedListActivity;
import com.xabber.androiddev.R;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/**
* Manage list of selected groups.
*
......@@ -146,8 +146,7 @@ public abstract class GroupListActivity extends ManagedListActivity implements
}
private void showGroupAddDialog() {
GroupAddDialogFragment.newInstance(getGroups()).show(
getSupportFragmentManager(), "GROUP-ADD");
GroupAddDialogFragment.newInstance(getGroups()).show(getFragmentManager(), "GROUP-ADD");
}
@Override
......
......@@ -14,11 +14,6 @@
*/
package com.xabber.android.ui.adapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import android.app.Activity;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
......@@ -49,6 +44,11 @@ import com.xabber.android.utils.Emoticons;
import com.xabber.android.utils.StringUtils;
import com.xabber.androiddev.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* Adapter for the list of messages in the chat.
*
......@@ -309,7 +309,7 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
@Override
public void onChange() {
messages = new ArrayList<MessageItem>(MessageManager.getInstance()
messages = new ArrayList<>(MessageManager.getInstance()
.getMessages(account, user));
hint = getHint();
notifyDataSetChanged();
......
/**
* Copyright (c) 2013, Redsolution LTD. All rights reserved.
*
* This file is part of Xabber project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License, Version 3.
*
* Xabber 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 com.xabber.android.ui.adapter;
import java.util.ArrayList;
import java.util.Collection;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import com.xabber.android.data.entity.BaseEntity;
import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.MessageManager;
import com.xabber.android.ui.ChatViewerFragment;
import com.xabber.xmpp.address.Jid;
/**
* Adapter for the list of chat pages.
*
* @author alexander.ivanov
*/
public class ChatViewerAdapter extends BaseAdapter implements SaveStateAdapter,
UpdatableAdapter {
private final FragmentActivity activity;
/**
* Intent sent while opening chat activity.
*/
private final AbstractChat intent;
/**
* Position to insert intent.
*/
private final int intentPosition;
private ArrayList<AbstractChat> activeChats;
public ChatViewerAdapter(FragmentActivity activity, String account,
String user) {
this.activity = activity;
activeChats = new ArrayList<AbstractChat>();
intent = MessageManager.getInstance().getOrCreateChat(account,
Jid.getBareAddress(user));
Collection<? extends BaseEntity> activeChats = MessageManager
.getInstance().getActiveChats();
if (activeChats.contains(intent))
intentPosition = -1;
else
intentPosition = activeChats.size();
onChange();
}
@Override
public int getCount() {
return activeChats.size();
}
@Override
public Object getItem(int position) {
return activeChats.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
final AbstractChat chat = (AbstractChat) getItem(position);
ChatViewerFragment fragment;
if (convertView == null) {
fragment = new ChatViewerFragment(activity);
view = fragment.getView();
view.setTag(fragment);
} else {
view = convertView;
fragment = (ChatViewerFragment) view.getTag();
}
fragment.setChat(chat);
return view;
}
@Override
public void saveState(View view) {
((ChatViewerFragment) view.getTag()).saveState();
}
@Override
public void hidePages(View view) {
((ChatViewerFragment) view.getTag()).hidePages();
}
@Override
public void showPages(View view) {
((ChatViewerFragment) view.getTag()).showPages();
}
/**
* Must be called on changes in chat (message sent, received, etc.).
*/
public void onChatChange(View view, boolean incomingMessage) {
((ChatViewerFragment) view.getTag()).onChatChange(incomingMessage);
}
/**
* Must be called on changes in chat (message sent, received, etc.).
*/
public void onPrepareOptionsMenu(View view, Menu menu) {
((ChatViewerFragment) view.getTag()).onPrepareOptionsMenu(menu);
}
public void insertText(View view, String text) {
((ChatViewerFragment) view.getTag()).insertText(text);
}
@Override
public void onChange() {
activeChats = new ArrayList<AbstractChat>(MessageManager.getInstance()
.getActiveChats());
if (intentPosition != -1) {
int index = activeChats.indexOf(intent);
AbstractChat chat;
if (index == -1)
chat = intent;
else
chat = activeChats.remove(index);
activeChats.add(Math.min(intentPosition, activeChats.size()), chat);
}
notifyDataSetChanged();
}
public int getPosition(String account, String user) {
for (int position = 0; position < activeChats.size(); position++)
if (activeChats.get(position).equals(account, user))
return position;
return -1;
}
}
......@@ -14,13 +14,13 @@
*/
package com.xabber.android.ui.dialog;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.DialogFragment;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import java.util.ArrayList;
/**
* Base dialog fragment.
......
package com.xabber.android.ui.dialog;
import java.util.ArrayList;
import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.view.ViewGroup;
......@@ -14,6 +12,8 @@ import com.xabber.android.data.roster.RosterContact;
import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.adapter.AccountChooseAdapter;
import java.util.ArrayList;
public class AccountChooseDialogFragment extends AbstractDialogFragment {
private static final String USER = "USER";
......
......@@ -14,14 +14,12 @@
*/
package com.xabber.android.ui.dialog;
import java.io.File;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.DialogFragment;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
......@@ -34,6 +32,8 @@ import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.roster.RosterManager;
import com.xabber.androiddev.R;
import java.io.File;
public class ChatExportDialogFragment extends ConfirmDialogFragment {
private static final String ACCOUNT = "ACCOUNT";
......@@ -45,8 +45,7 @@ public class ChatExportDialogFragment extends ConfirmDialogFragment {
* @return
*/
public static DialogFragment newInstance(String account, String user) {
return new ChatExportDialogFragment().putAgrument(ACCOUNT, account)
.putAgrument(USER, user);
return new ChatExportDialogFragment().putAgrument(ACCOUNT, account).putAgrument(USER, user);
}
private String account;
......
package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment;
import android.app.DialogFragment;
import com.xabber.android.data.Application;
import com.xabber.android.data.NetworkException;
......
package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment;
import android.app.DialogFragment;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.account.AccountManager;
......
......@@ -14,17 +14,17 @@
*/
package com.xabber.android.ui.dialog;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment;
import android.app.DialogFragment;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.xabber.androiddev.R;
import java.util.ArrayList;
public class GroupAddDialogFragment extends ConfirmDialogFragment {
private static final String GROUPS = "GROUPS";
......
package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment;
import android.app.DialogFragment;
import com.xabber.android.data.Application;
import com.xabber.android.data.NetworkException;
......
......@@ -16,7 +16,7 @@ package com.xabber.android.ui.dialog;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment;
import android.app.DialogFragment;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
......
package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment;
import android.app.DialogFragment;
import com.xabber.android.data.account.AccountManager;
import com.xabber.android.data.extension.muc.MUCManager;
......
package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment;
import android.app.DialogFragment;
import com.xabber.android.data.SettingsManager;
import com.xabber.androiddev.R;
......
......@@ -14,8 +14,6 @@
*/
package com.xabber.android.ui.helper;
import org.jivesoftware.smackx.ChatState;
import android.app.Activity;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
......@@ -24,7 +22,6 @@ import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
......@@ -34,6 +31,8 @@ import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.utils.Emoticons;
import com.xabber.androiddev.R;
import org.jivesoftware.smackx.ChatState;
/**
* Helper class to update <code>contact_title.xml</code>.
*
......@@ -61,8 +60,7 @@ public class ContactTitleInflater {
.findViewById(R.id.avatar);
final ImageView statusModeView = (ImageView) titleView
.findViewById(R.id.status_mode);
final TextView statusTextView = (TextView) titleView
.findViewById(R.id.status_text);
final TextView statusTextView = (TextView) titleView.findViewById(R.id.status_text);
final View shadowView = titleView.findViewById(R.id.shadow);
titleView.setBackgroundDrawable(titleAccountBackground);
nameView.setText(abstractContact.getName());
......
......@@ -33,11 +33,9 @@ import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.data.roster.GroupManager;
import com.xabber.android.data.roster.PresenceManager;
import com.xabber.android.data.roster.ShowOfflineMode;
import com.xabber.android.ui.preferences.AccountEditor;
import com.xabber.android.ui.ChatViewer;
import com.xabber.android.ui.ContactAdd;
import com.xabber.android.ui.ContactEditor;
import com.xabber.android.ui.preferences.ContactViewer;
import com.xabber.android.ui.MUCEditor;
import com.xabber.android.ui.StatusEditor;
import com.xabber.android.ui.adapter.UpdatableAdapter;
......@@ -45,6 +43,8 @@ import com.xabber.android.ui.dialog.ContactDeleteDialogFragment;
import com.xabber.android.ui.dialog.GroupDeleteDialogFragment;
import com.xabber.android.ui.dialog.GroupRenameDialogFragment;
import com.xabber.android.ui.dialog.MUCDeleteDialogFragment;
import com.xabber.android.ui.preferences.AccountEditor;
import com.xabber.android.ui.preferences.ContactViewer;
import com.xabber.androiddev.R;
/**
......@@ -84,7 +84,7 @@ public class ContextMenuHelper {
@Override
public boolean onMenuItemClick(MenuItem item) {
MUCDeleteDialogFragment.newInstance(account, user)
.show(activity.getSupportFragmentManager(),
.show(activity.getFragmentManager(),
"MUC_DELETE");
return true;
}
......@@ -131,8 +131,7 @@ public class ContextMenuHelper {
@Override
public boolean onMenuItemClick(MenuItem item) {
ContactDeleteDialogFragment.newInstance(account,
user).show(
activity.getSupportFragmentManager(),
user).show(activity.getFragmentManager(),
"CONTACT_DELETE");
return true;
}
......@@ -225,8 +224,7 @@ public class ContextMenuHelper {
account == GroupManager.NO_ACCOUNT ? null
: account,
group == GroupManager.NO_GROUP ? null
: group).show(
activity.getSupportFragmentManager(),
: group).show(activity.getFragmentManager(),
"GROUP_RENAME");
return true;
}
......@@ -241,9 +239,7 @@ public class ContextMenuHelper {
.newInstance(
account == GroupManager.NO_ACCOUNT ? null
: account, group)
.show(activity
.getSupportFragmentManager(),
"GROUP_DELETE");
.show(activity.getFragmentManager(), "GROUP_DELETE");
return true;
}
});
......
/**
* Copyright (c) 2013, Redsolution LTD. All rights reserved.
*
* This file is part of Xabber project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License, Version 3.
*
* Xabber 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 com.xabber.android.ui.widget;
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.ListView;
import android.widget.Scroller;
import com.xabber.android.data.LogManager;
import com.xabber.android.ui.adapter.SaveStateAdapter;
import com.xabber.androiddev.R;
/**
* Widget to switch between chat pages.
* <p/>
* Warning: This class is to be replaced.
*
* @author alexander.ivanov
*/
public class PageSwitcher extends ViewGroup {
public static final boolean LOG = false;
/**
* Distance a touch can wander before we think the user is scrolling.
*/
private final int touchSlop;
private final DataSetObserver dataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
dataChanged = true;
requestLayout();
}
@Override
public void onInvalidated() {
dataChanged = true;
requestLayout();
}
};
private boolean dataChanged;
private SaveStateAdapter adapter;
private int widthMeasureSpec;
private int heightMeasureSpec;
/**
* User is currently dragging this view.
*/
private boolean isBeingDragged;
/**
* Drag was interrupted.
*/
private boolean dragWasCanceled;
/**
* Position of down touch.
*/
private float touchX;
/**
* Initial scroll position.
*/
private int initialScrollX;
/**
* {@link Scroller#isFinished()} is <code>false</code> when being flung.
*/
private final Scroller scroller;
/**
* The listener that receives notifications when an item is selected,
* unselected or removed.
*/
private OnSelectListener onSelectListener;
/**
* Selected position in adapter. Can be incorrect while {@link #dataChanged}
* is <code>true</code> .
*/
private int selectedPosition;
private View selectedView;
/**
* Previous selected object (before data changes).
*/
private Object previousSelectedObject;
/**
* Visible but not selected position.
*/
private int visiblePosition;
/**
* Visible but not selected view.
*/
private View visibleView;
/**
* Previous visible object (before data changes).
*/
private Object previousVisibleObject;
public PageSwitcher(Context context, AttributeSet attrs) {
super(context, attrs);
touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
dataChanged = true;
adapter = null;
widthMeasureSpec = 0;
heightMeasureSpec = 0;
isBeingDragged = false;
dragWasCanceled = false;
touchX = 0;
initialScrollX = 0;
scroller = new Scroller(getContext());
onSelectListener = null;
selectedPosition = 0;
selectedView = null;
previousSelectedObject = null;
visiblePosition = 0;
visibleView = null;
previousVisibleObject = null;
}
/**
* Sets adapter. Request update and set initial selected position.
*
* @param adapter
*/
public void setAdapter(SaveStateAdapter adapter) {
if (adapter == null)
throw new IllegalStateException();
if (this.adapter != null)
this.adapter.unregisterDataSetObserver(dataSetObserver);
this.adapter = adapter;
this.adapter.registerDataSetObserver(dataSetObserver);
// dataChanged will be set in setSelection().
setSelection(0);
}
/**
* @return Assigned adapter.
*/
public Adapter getAdapter() {
return adapter;
}
/**
* Register a callback to be invoked when an item in this View has been
* selected, unselected or removed.
*
* @param listener The callback that will run
*/
public void setOnSelectListener(OnSelectListener listener) {
onSelectListener = listener;
}
public OnSelectListener getOnSelectListener() {
return onSelectListener;
}
/**
* @return Selected position in adapter.
*/
public int getSelectedItemPosition() {
if (adapter == null)
throw new IllegalStateException();
return selectedPosition;
}
/**
* @return Selected item in adapter or <code>null</code> if there is no
* elements.
*/
public Object getSelectedItem() {
if (adapter == null)
throw new IllegalStateException();
if (selectedPosition < 0 || selectedPosition >= adapter.getCount())
return null;
else
return adapter.getItem(selectedPosition);
}
/**
* @return Visible item from adapter or <code>null</code> if there is no
* visible elements (selected element still can exists).
*/
public Object getVisibleItem() {
if (adapter == null)
throw new IllegalStateException();
if (visiblePosition < 0 || visiblePosition >= adapter.getCount())
return null;
else
return adapter.getItem(visiblePosition);
}
/**
* @return Selected view.
*/
public View getSelectedView() {
if (adapter == null)
throw new IllegalStateException();
return selectedView;
}
/**
* @return Visible view.
*/
public View getVisibleView() {
if (adapter == null)
throw new IllegalStateException();
return visibleView;
}
/**
* @return number of items or zero if adapter is <code>null</code> .
*/
private int getCount() {
return adapter == null ? 0 : adapter.getCount();
}
/**
* Returns correct position.
*
* @param position
* @return value between <code>0</code> and <code>count - 1</code>.
*/
private int correntPosition(int position) {
final int count = getCount();
if (position >= count)
return 0;
if (position < 0)
return count - 1;
return position;
}
/**
* Gets view.
*
* @param position in adapter.
* @param x position in layout.
* @param convertView previous view.
* @param update whether we need force update underlying view.
* @param layout whether we need to update layout (remeasure).
* @return
*/
private View getView(int position, int x, View convertView, boolean update,
boolean layout) {
final View view;
if (convertView == null) {
if (LOG)
LogManager.i(this, "new view");
view = adapter.getView(position, null, this);
} else if (update) {
if (LOG)
LogManager.i(this, "update view");
view = adapter.getView(position, convertView, this);
} else {
view = convertView;
}
if (view != convertView) {
if (LOG)
LogManager.i(this, "init view");
LayoutParams layoutParams = view.getLayoutParams();
if (layoutParams == null)
layoutParams = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
addViewInLayout(view, 0, layoutParams, true);
}
if (update || layout || view.getLeft() != x) {
if (LOG)
LogManager.i(this, "layout view");
// We must measure ListView after update to show items.
measureChild(view, widthMeasureSpec, heightMeasureSpec);
view.layout(x, 0, x + view.getMeasuredWidth(),
view.getMeasuredHeight());
}
return view;
}
/**
* Updates scrolling, creates views if necessary .
*
* @param layout whether we need to update layout (remeasure).
*/
private void update(boolean layout) {
// Process data change.
final int count = getCount();
if (dataChanged) {
if (previousSelectedObject != null)
for (int position = 0; position < count; position++)
if (adapter.getItem(position)
.equals(previousSelectedObject)) {
selectedPosition = position;
if (LOG)
LogManager.i(this, "Found selected position: "
+ selectedPosition);
break;
}
selectedPosition = correntPosition(selectedPosition);
}
// Process scrolling.
final int width = getWidth();
int scrollX = getScrollX();
if (width != 0) {
while (scrollX >= width) {
scrollX -= width;
initialScrollX -= width;
selectedPosition = correntPosition(selectedPosition + 1);
if (LOG)
LogManager.i(this, "scrollX >= width: " + selectedPosition);
}
while (scrollX <= -width) {
scrollX += width;
initialScrollX += width;
selectedPosition = correntPosition(selectedPosition - 1);
if (LOG)
LogManager
.i(this, "scrollX <= -width: " + selectedPosition);
}
}
// Process low count.
if (count < 2) {
if (LOG)
LogManager.i(this, "count < 2");
dragWasCanceled = true;
isBeingDragged = false;
if (!scroller.isFinished())
scroller.abortAnimation();
if (scrollX != 0)
scrollX = 0;
}
// Store focus.
final View focus;
if (selectedView != null)
focus = selectedView.findFocus();
else
focus = null;
// Process selected view.
if (count == 0) {
if (LOG)
LogManager.i(this, "count == 0");
selectedPosition = -1;
if (selectedView != null) {
if (onSelectListener != null)
onSelectListener.onUnselect();
adapter.saveState(selectedView);
removeViewInLayout(selectedView);
selectedView = null;
// We must invalidate to update view.
invalidate();
}
} else {
if (LOG)
LogManager.i(this, "count > 0");
// Exchange visible and selected views and previous objects.
final Object selectedObject = adapter.getItem(selectedPosition);
final boolean exchange = previousSelectedObject != null
&& previousVisibleObject != null
&& !previousSelectedObject.equals(selectedObject)
&& previousVisibleObject.equals(selectedObject);
if (exchange) {
Object tempObject = previousSelectedObject;
previousSelectedObject = previousVisibleObject;
previousVisibleObject = tempObject;
View view = selectedView;
selectedView = visibleView;
visibleView = view;
}
// Update view.
final boolean update = dataChanged
|| previousSelectedObject == null
|| !previousSelectedObject.equals(selectedObject);
selectedView = getView(selectedPosition, 0, selectedView, update,
layout);
previousSelectedObject = selectedObject;
if (update || exchange)
if (onSelectListener != null)
onSelectListener.onSelect();
// Enable focusable.
if (selectedView instanceof ViewGroup)
((ViewGroup) selectedView)
.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
else
selectedView.setFocusable(true);
}
// Process visible (not selected) view.
if (count < 2) {
if (LOG)
LogManager.i(this, "count < 2 || scrollX == 0");
visiblePosition = -1;
if (visibleView != null) {
adapter.saveState(visibleView);
removeViewInLayout(visibleView);
visibleView = null;
}
} else {
// Calculate position.
final int visibleX;
if (scrollX > 0) {
if (LOG)
LogManager.i(this, "scrollX > 0");
visiblePosition = correntPosition(selectedPosition + 1);
visibleX = width;
} else {
if (LOG)
LogManager.i(this, "scrollX < 0");
visiblePosition = correntPosition(selectedPosition - 1);
visibleX = -width;
}
// Update view.
final Object visibleObject = adapter.getItem(visiblePosition);
final boolean update = dataChanged || previousVisibleObject == null
|| !previousVisibleObject.equals(visibleObject);
visibleView = getView(visiblePosition, visibleX, visibleView,
update, layout);
previousVisibleObject = visibleObject;
// Disable focusable.
if (visibleView instanceof ViewGroup)
((ViewGroup) visibleView)
.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
else
visibleView.setFocusable(false);
}
// Restore focus by ID.
if (selectedView != null) {
View target;
if (focus == null || focus.getId() == View.NO_ID)
target = null;
else
target = selectedView.findViewById(focus.getId());
if (target == null)
target = selectedView.findViewById(R.id.chat_input);
target.requestFocus();
}
if (scrollX == 0) {
if (LOG)
LogManager.i(this, "Scroll X == 0");
if (visibleView != null)
adapter.hidePages(visibleView);
if (selectedView != null)
adapter.hidePages(selectedView);
} else {
if (LOG)
LogManager.i(this, "Scroll X != 0");
if (visibleView != null)
adapter.showPages(visibleView);
if (selectedView != null)
adapter.showPages(selectedView);
}
super.scrollTo(scrollX, 0);
dataChanged = false;
}
/**
* Save state of views. Must be called on activity pause.
*/
public void saveState() {
if (visibleView != null)
adapter.saveState(visibleView);
if (selectedView != null)
adapter.saveState(selectedView);
}
/**
* Selects an item. Immediately scroll to this position.
*
* @param position
*/
public void setSelection(int position) {
if (adapter == null)
throw new IllegalStateException();
dataChanged = true;
isBeingDragged = false;
dragWasCanceled = true;
if (!scroller.isFinished())
scroller.abortAnimation();
if (getScrollX() != 0 || getScrollY() != 0)
super.scrollTo(0, 0);
previousSelectedObject = null;
selectedPosition = position;
if (LOG)
LogManager.i(this, "setSelection: " + selectedPosition);
update(false);
if (selectedView == null)
return;
ListView listView = (ListView) selectedView
.findViewById(android.R.id.list);
listView.setAdapter(listView.getAdapter());
}
/**
* Stop any movements.
*/
public void stopMovement() {
isBeingDragged = false;
dragWasCanceled = true;
if (!scroller.isFinished())
scroller.abortAnimation();
if (getScrollX() != 0 || getScrollY() != 0)
super.scrollTo(0, 0);
update(false);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
this.widthMeasureSpec = widthMeasureSpec;
this.heightMeasureSpec = heightMeasureSpec;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
if (LOG)
LogManager.i(this, "onLayout");
update(true);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (getCount() <= 1) {
isBeingDragged = false;
dragWasCanceled = true;
return false;
}
final int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN)
dragWasCanceled = false;
if (dragWasCanceled)
return false;
final float x = event.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
touchX = x;
initialScrollX = getScrollX();
if (!scroller.isFinished()) {
scroller.abortAnimation();
isBeingDragged = true;
} else {
isBeingDragged = false;
}
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(x - touchX) > touchSlop)
isBeingDragged = true;
// requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
break;
}
return isBeingDragged;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (getCount() <= 1)
dragWasCanceled = true;
if (dragWasCanceled)
return false;
final int action = event.getAction();
final float x = event.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(x - touchX) > touchSlop)
isBeingDragged = true;
if (isBeingDragged) {
if (LOG)
LogManager.i(this, "onTouchEvent - MOVE");
scrollTo((int) (touchX - x) + initialScrollX, 0);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (isBeingDragged) {
final int scroll = getScrollX();
final int width = getWidth();
final int center = width / 2;
final int target;
if (scroll > center) {
target = width;
} else if (scroll < -center) {
target = -width;
} else {
target = 0;
}
scroller.startScroll(scroll, 0, target - scroll, 0);
invalidate();
}
isBeingDragged = false;
break;
}
return true;
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
if (scroller.getCurrX() == scroller.getFinalX()
&& scroller.getCurrY() == scroller.getFinalY())
scroller.abortAnimation();
if (LOG)
LogManager.i(this, "computeScroll");
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
@Override
public void scrollTo(int x, int y) {
if (LOG)
LogManager.i(this, "scrollTo: " + x + "," + y);
super.scrollTo(x, y);
update(false);
}
public interface OnSelectListener {
/**
* Callback method to be invoked when an item has been selected.
*/
void onSelect();
/**
* Callback method to be invoked when an item has been unselected.
*/
void onUnselect();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment