Commit e6b453db authored by Grigory Fedorov's avatar Grigory Fedorov

Merge branch 'feature/chat' into develop

parents bcbb1c98 3871a0d0
...@@ -8,8 +8,8 @@ android { ...@@ -8,8 +8,8 @@ android {
applicationId "com.xabber.androiddev" applicationId "com.xabber.androiddev"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 21 targetSdkVersion 21
versionCode 107 versionCode 113
versionName '0.10.10' versionName '0.10.16'
} }
buildTypes { buildTypes {
...@@ -27,4 +27,5 @@ android { ...@@ -27,4 +27,5 @@ android {
dependencies { dependencies {
compile files('libs/otr4j.jar') compile files('libs/otr4j.jar')
compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.android.support:appcompat-v7:21.0.3'
compile 'com.android.support:support-v13:21.0.3'
} }
...@@ -110,16 +110,6 @@ ...@@ -110,16 +110,6 @@
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="com.xabber.android.ui.preferences.AccountList" /> android:value="com.xabber.android.ui.preferences.AccountList" />
</activity> </activity>
<activity
android:label="@string/chat_list"
android:name="com.xabber.android.ui.ChatList"
android:parentActivityName="com.xabber.android.ui.ContactList"
>
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.xabber.android.ui.ContactList" />
</activity>
<activity <activity
android:label="@string/occupant_list" android:label="@string/occupant_list"
android:name="com.xabber.android.ui.OccupantList" android:name="com.xabber.android.ui.OccupantList"
......
/**
Copyright (c) 2012 Antony Tran
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.antonyt.infiniteviewpager;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import com.xabber.android.ui.adapter.ChatViewerAdapter;
/**
* A {@link android.support.v4.view.ViewPager} that allows pseudo-infinite paging with a wrap-around effect.
*/
public class InfiniteViewPager extends ViewPager {
public static final int OFFSET = 100;
public static final int TOTAL_COUNT = 200;
public InfiniteViewPager(Context context) {
super(context);
}
public InfiniteViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setAdapter(PagerAdapter adapter) {
super.setAdapter(adapter);
// offset first element so that we can scroll to the left
setCurrentItem(0);
}
@Override
public void setCurrentItem(int item) {
// offset the current item to ensure there is space to scroll
setCurrentItem(item, false);
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
item = getOffsetAmount() + (item % getAdapter().getCount());
super.setCurrentItem(item, smoothScroll);
}
@Override
public int getCurrentItem() {
int position = super.getCurrentItem();
// Return the actual item position in the data backing InfinitePagerAdapter
return position % ((ChatViewerAdapter)getAdapter()).getRealCount();
}
private int getOffsetAmount() {
// allow for 100 back cycles from the beginning
// should be enough to create an illusion of infinity
// warning: scrolling to very high values (1,000,000+) results in
// strange drawing behaviour
return OFFSET;
}
@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
super.setOnPageChangeListener(listener);
}
}
...@@ -14,20 +14,6 @@ ...@@ -14,20 +14,6 @@
*/ */
package com.xabber.android.data.message; package com.xabber.android.data.message;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.packet.DelayInformation;
import android.database.Cursor; import android.database.Cursor;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
...@@ -45,6 +31,20 @@ import com.xabber.android.data.message.chat.ChatManager; ...@@ -45,6 +31,20 @@ import com.xabber.android.data.message.chat.ChatManager;
import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.notification.NotificationManager;
import com.xabber.xmpp.archive.SaveMode; import com.xabber.xmpp.archive.SaveMode;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.packet.DelayInformation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/** /**
* Chat instance. * Chat instance.
* *
...@@ -109,6 +109,8 @@ public abstract class AbstractChat extends BaseEntity { ...@@ -109,6 +109,8 @@ public abstract class AbstractChat extends BaseEntity {
*/ */
protected final Collection<MessageItem> sendQuery; protected final Collection<MessageItem> sendQuery;
protected Date creationTime = new Date();
protected AbstractChat(final String account, final String user) { protected AbstractChat(final String account, final String user) {
super(account, user); super(account, user);
threadId = StringUtils.randomString(12); threadId = StringUtils.randomString(12);
...@@ -120,6 +122,7 @@ public abstract class AbstractChat extends BaseEntity { ...@@ -120,6 +122,7 @@ public abstract class AbstractChat extends BaseEntity {
historyIds = new ArrayList<Long>(); historyIds = new ArrayList<Long>();
messages = new ArrayList<MessageItem>(); messages = new ArrayList<MessageItem>();
sendQuery = new ArrayList<MessageItem>(); sendQuery = new ArrayList<MessageItem>();
updateCreationTime();
Application.getInstance().runInBackground(new Runnable() { Application.getInstance().runInBackground(new Runnable() {
@Override @Override
...@@ -267,6 +270,10 @@ public abstract class AbstractChat extends BaseEntity { ...@@ -267,6 +270,10 @@ public abstract class AbstractChat extends BaseEntity {
} }
void openChat() { void openChat() {
if (!active) {
updateCreationTime();
}
active = true; active = true;
trackStatus = true; trackStatus = true;
} }
...@@ -672,4 +679,11 @@ public abstract class AbstractChat extends BaseEntity { ...@@ -672,4 +679,11 @@ public abstract class AbstractChat extends BaseEntity {
protected void onDisconnect() { protected void onDisconnect() {
} }
public Date getCreationTime() {
return creationTime;
}
public void updateCreationTime() {
creationTime.setTime(System.currentTimeMillis());
}
} }
/**
* 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;
import java.util.Collection;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import com.xabber.android.data.Application;
import com.xabber.android.data.account.OnAccountChangedListener;
import com.xabber.android.data.entity.BaseEntity;
import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.OnChatChangedListener;
import com.xabber.android.data.roster.OnContactChangedListener;
import com.xabber.android.ui.adapter.ChatListAdapter;
import com.xabber.android.ui.helper.ManagedListActivity;
import com.xabber.androiddev.R;
public class ChatList extends ManagedListActivity implements
OnAccountChangedListener, OnContactChangedListener,
OnChatChangedListener, OnItemClickListener {
private ChatListAdapter listAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isFinishing())
return;
setContentView(R.layout.list);
listAdapter = new ChatListAdapter(this);
setListAdapter(listAdapter);
getListView().setOnItemClickListener(this);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
protected void onResume() {
super.onResume();
Application.getInstance().addUIListener(OnAccountChangedListener.class,
this);
Application.getInstance().addUIListener(OnContactChangedListener.class,
this);
Application.getInstance().addUIListener(OnChatChangedListener.class,
this);
listAdapter.onChange();
}
@Override
protected void onPause() {
super.onPause();
Application.getInstance().removeUIListener(
OnAccountChangedListener.class, this);
Application.getInstance().removeUIListener(
OnContactChangedListener.class, this);
Application.getInstance().removeUIListener(OnChatChangedListener.class,
this);
}
@Override
public void onChatChanged(String account, String user, boolean incoming) {
listAdapter.onChange();
}
@Override
public void onContactsChanged(Collection<BaseEntity> addresses) {
listAdapter.onChange();
}
@Override
public void onAccountsChanged(Collection<String> accounts) {
listAdapter.onChange();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
AbstractChat abstractChat = (AbstractChat) parent.getAdapter().getItem(
position);
startActivity(ChatViewer.createIntent(this, abstractChat.getAccount(),
abstractChat.getUser()));
finish();
}
public static Intent createIntent(Context context) {
return new Intent(context, ChatList.class);
}
}
...@@ -14,44 +14,43 @@ ...@@ -14,44 +14,43 @@
*/ */
package com.xabber.android.ui; package com.xabber.android.ui;
import android.app.Fragment;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.KeyEvent; import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.View;
import com.xabber.android.data.ActivityManager; import com.xabber.android.data.ActivityManager;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.account.OnAccountChangedListener; import com.xabber.android.data.account.OnAccountChangedListener;
import com.xabber.android.data.entity.BaseEntity; import com.xabber.android.data.entity.BaseEntity;
import com.xabber.android.data.extension.archive.MessageArchiveManager; import com.xabber.android.data.extension.archive.MessageArchiveManager;
import com.xabber.android.data.extension.attention.AttentionManager; import com.xabber.android.data.extension.attention.AttentionManager;
import com.xabber.android.data.intent.EntityIntentBuilder; import com.xabber.android.data.intent.EntityIntentBuilder;
import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.message.OnChatChangedListener; import com.xabber.android.data.message.OnChatChangedListener;
import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.notification.NotificationManager;
import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.data.roster.OnContactChangedListener; import com.xabber.android.data.roster.OnContactChangedListener;
import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.adapter.ChatViewerAdapter; import com.xabber.android.ui.adapter.ChatViewerAdapter;
import com.xabber.android.ui.helper.ManagedActivity; 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 com.xabber.androiddev.R;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
/** /**
* Chat activity. * Chat activity.
* <p/> * <p/>
* Warning: {@link PageSwitcher} is to be removed and related implementation is
* to be fixed.
* *
* @author alexander.ivanov * @author alexander.ivanov
*/ */
public class ChatViewer extends ManagedActivity implements OnSelectListener, public class ChatViewer extends ManagedActivity implements OnChatChangedListener,
OnChatChangedListener, OnContactChangedListener, OnContactChangedListener, OnAccountChangedListener, ViewPager.OnPageChangeListener,
OnAccountChangedListener { ChatViewerAdapter.FinishUpdateListener, RecentChatFragment.RecentChatFragmentInteractionListener,
ChatViewerFragment.ChatViewerFragmentListener {
/** /**
* Attention request. * Attention request.
...@@ -62,93 +61,84 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener, ...@@ -62,93 +61,84 @@ 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_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 static final String SAVED_EXIT_ON_SEND = "com.xabber.android.ui.ChatViewer.EXIT_ON_SEND";
private ChatViewerAdapter chatViewerAdapter; private boolean exitOnSend;
private PageSwitcher pageSwitcher;
private String actionWithAccount; private String extraText = null;
private String actionWithUser;
private View actionWithView;
private boolean exitOnSend; ChatViewerAdapter chatViewerAdapter;
ViewPager viewPager;
Collection<ChatViewerFragment> registeredChats = new HashSet<>();
Collection<RecentChatFragment> recentChatFragments = new HashSet<>();
private String actionWithAccount = null;
private String actionWithUser = null;
private boolean isVisible;
@Override @Override
public void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (isFinishing())
if (isFinishing()) {
return; return;
}
Intent intent = getIntent(); Intent intent = getIntent();
String account = getAccount(intent); String account = getAccount(intent);
String user = getUser(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);
actionWithAccount = null;
actionWithUser = null;
actionWithView = null;
setContentView(R.layout.chat_viewer);
chatViewerAdapter = new ChatViewerAdapter(this, account, user);
pageSwitcher = (PageSwitcher) findViewById(R.id.switcher); if (hasAttention(intent)) {
pageSwitcher.setAdapter(chatViewerAdapter); AttentionManager.getInstance().removeAccountNotifications(account, user);
pageSwitcher.setOnSelectListener(this); }
if (savedInstanceState != null) { if (savedInstanceState != null) {
actionWithAccount = savedInstanceState.getString(SAVED_ACCOUNT); if (account == null || user == null) {
actionWithUser = savedInstanceState.getString(SAVED_USER); account = savedInstanceState.getString(SAVED_ACCOUNT);
user = savedInstanceState.getString(SAVED_USER);
}
exitOnSend = savedInstanceState.getBoolean(SAVED_EXIT_ON_SEND); exitOnSend = savedInstanceState.getBoolean(SAVED_EXIT_ON_SEND);
} }
if (actionWithAccount == null)
actionWithAccount = account;
if (actionWithUser == null)
actionWithUser = user;
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
selectChat(actionWithAccount, actionWithUser); setContentView(R.layout.activity_chat_viewer);
if (account != null && user != null) {
chatViewerAdapter = new ChatViewerAdapter(getFragmentManager(),
account, user, this);
} else {
chatViewerAdapter = new ChatViewerAdapter(getFragmentManager(), this);
}
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(chatViewerAdapter);
viewPager.setOnPageChangeListener(this);
selectPage(account, user, false);
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
Application.getInstance().addUIListener(OnChatChangedListener.class, Application.getInstance().addUIListener(OnChatChangedListener.class, this);
this); Application.getInstance().addUIListener(OnContactChangedListener.class, this);
Application.getInstance().addUIListener(OnContactChangedListener.class, Application.getInstance().addUIListener(OnAccountChangedListener.class, this);
this);
Application.getInstance().addUIListener(OnAccountChangedListener.class,
this);
chatViewerAdapter.onChange();
if (actionWithView != null)
chatViewerAdapter.onChatChange(actionWithView, false);
Intent intent = getIntent(); Intent intent = getIntent();
if (Intent.ACTION_SEND.equals(intent.getAction())) { if (Intent.ACTION_SEND.equals(intent.getAction())) {
String additional = intent.getStringExtra(Intent.EXTRA_TEXT); extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (additional != null) {
if (extraText != null) {
intent.removeExtra(Intent.EXTRA_TEXT); intent.removeExtra(Intent.EXTRA_TEXT);
exitOnSend = true; exitOnSend = true;
if (actionWithView != null)
chatViewerAdapter.insertText(actionWithView, additional);
} }
} }
isVisible = true;
} }
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
if (PageSwitcher.LOG)
LogManager.i(this, "onSave: " + actionWithAccount + ":"
+ actionWithUser);
outState.putString(SAVED_ACCOUNT, actionWithAccount); outState.putString(SAVED_ACCOUNT, actionWithAccount);
outState.putString(SAVED_USER, actionWithUser); outState.putString(SAVED_USER, actionWithUser);
outState.putBoolean(SAVED_EXIT_ON_SEND, exitOnSend); outState.putBoolean(SAVED_EXIT_ON_SEND, exitOnSend);
...@@ -157,15 +147,10 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener, ...@@ -157,15 +147,10 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
Application.getInstance().removeUIListener(OnChatChangedListener.class, Application.getInstance().removeUIListener(OnChatChangedListener.class, this);
this); Application.getInstance().removeUIListener(OnContactChangedListener.class, this);
Application.getInstance().removeUIListener( Application.getInstance().removeUIListener(OnAccountChangedListener.class, this);
OnContactChangedListener.class, this);
Application.getInstance().removeUIListener(
OnAccountChangedListener.class, this);
MessageManager.getInstance().removeVisibleChat(); MessageManager.getInstance().removeVisibleChat();
pageSwitcher.saveState();
isVisible = false;
} }
@Override @Override
...@@ -174,168 +159,50 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener, ...@@ -174,168 +159,50 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
if (isFinishing()) if (isFinishing())
return; return;
chatViewerAdapter.onChange();
String account = getAccount(intent); String account = getAccount(intent);
String user = getUser(intent); String user = getUser(intent);
if (account == null || user == null) { if (account == null || user == null) {
return; 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();
}
@Override selectPage(account, user, false);
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;
}
} }
@Override private void selectPage(String account, String user, boolean smoothScroll) {
public void onAccountsChanged(Collection<String> accounts) { int position = chatViewerAdapter.getPageNumber(account, user);
BaseEntity baseEntity; viewPager.setCurrentItem(position, smoothScroll);
baseEntity = (BaseEntity) pageSwitcher.getSelectedItem(); onPageSelected(position);
if (baseEntity != null && accounts.contains(baseEntity.getAccount())) {
chatViewerAdapter.onChange();
return;
}
baseEntity = (BaseEntity) pageSwitcher.getVisibleItem();
if (baseEntity != null && accounts.contains(baseEntity.getAccount())) {
chatViewerAdapter.onChange();
return;
}
} }
private boolean selectChat(String account, String user) { private static String getAccount(Intent intent) {
for (int position = 0; position < chatViewerAdapter.getCount(); position++) String value = EntityIntentBuilder.getAccount(intent);
if (((BaseEntity) chatViewerAdapter.getItem(position)).equals( if (value != null)
account, user)) { return value;
if (PageSwitcher.LOG) // Backward compatibility.
LogManager.i(this, "setSelection: " + position + ", " return intent.getStringExtra("com.xabber.android.data.account");
+ account + ":" + user);
pageSwitcher.setSelection(position);
return true;
}
if (PageSwitcher.LOG)
LogManager.i(this, "setSelection: not found, " + account + ":"
+ user);
return false;
} }
public int getChatCount() { private static String getUser(Intent intent) {
return chatViewerAdapter.getCount(); 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) { private static boolean hasAttention(Intent intent) {
return chatViewerAdapter.getPosition(account, user); return ACTION_ATTENTION.equals(intent.getAction());
} }
public static Intent createIntent(Context context, String account, public static Intent createIntent(Context context, String account,
String user) { String user) {
return new EntityIntentBuilder(context, ChatViewer.class) return new EntityIntentBuilder(context, ChatViewer.class).setAccount(account).setUser(user).build();
.setAccount(account).setUser(user).build(); }
public static Intent createIntent(Context context) {
return new EntityIntentBuilder(context, ChatViewer.class).build();
} }
public static Intent createClearTopIntent(Context context, String account, public static Intent createClearTopIntent(Context context, String account,
...@@ -372,24 +239,154 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener, ...@@ -372,24 +239,154 @@ public class ChatViewer extends ManagedActivity implements OnSelectListener,
return intent; return intent;
} }
private static String getAccount(Intent intent) { @Override
String value = EntityIntentBuilder.getAccount(intent); public void onChatChanged(final String account, final String user,
if (value != null) final boolean incoming) {
return value; for (ChatViewerFragment chat : registeredChats) {
// Backward compatibility. if (chat.isEqual(account, user)) {
return intent.getStringExtra("com.xabber.android.data.account"); chat.updateChat(incoming);
}
}
updateRegisteredRecentChatsFragments();
} }
private static String getUser(Intent intent) { @Override
String value = EntityIntentBuilder.getUser(intent); public void onContactsChanged(Collection<BaseEntity> entities) {
if (value != null) chatViewerAdapter.onChange();
return value;
// Backward compatibility. updateRegisteredChats();
return intent.getStringExtra("com.xabber.android.data.user"); updateRegisteredRecentChatsFragments();
} }
private static boolean hasAttention(Intent intent) { @Override
return ACTION_ATTENTION.equals(intent.getAction()); public void onAccountsChanged(Collection<String> accounts) {
chatViewerAdapter.onChange();
updateRegisteredChats();
updateRegisteredRecentChatsFragments();
}
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));
}
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
} }
@Override
public void onPageSelected(int position) {
AbstractChat selectedChat = chatViewerAdapter.getChatByPageNumber(position);
if (selectedChat == null) {
setTitle(getString(R.string.chat_list));
return;
}
String account = selectedChat.getAccount();
String user = selectedChat.getUser();
final AbstractContact abstractContact = RosterManager.getInstance().getBestContact(account, user);
setTitle(abstractContact.getName());
MessageManager.getInstance().setVisibleChat(account, user);
MessageArchiveManager.getInstance().requestHistory(
account, user, 0,
MessageManager.getInstance().getChat(account, user).getRequiredMessageCount());
NotificationManager.getInstance().removeMessageNotification(account, user);
actionWithAccount = account;
actionWithUser = user;
}
private void updateRegisteredChats() {
for (ChatViewerFragment chat : registeredChats) {
chat.updateChat(false);
}
}
private void updateRegisteredRecentChatsFragments() {
for (RecentChatFragment recentChatFragment : recentChatFragments) {
recentChatFragment.updateChats(chatViewerAdapter.getActiveChats());
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
public void registerChat(ChatViewerFragment chat) {
registeredChats.add(chat);
}
public void unregisterChat(ChatViewerFragment chat) {
registeredChats.remove(chat);
}
public void registerRecentChatsList(RecentChatFragment recentChatFragment) {
recentChatFragments.add(recentChatFragment);
}
public void unregisterRecentChatsList(RecentChatFragment recentChatFragment) {
recentChatFragments.remove(recentChatFragment);
}
@Override
public void onChatViewAdapterFinishUpdate() {
insertExtraText();
Fragment currentFragment = chatViewerAdapter.getCurrentFragment();
if (currentFragment instanceof ChatViewerFragment) {
((ChatViewerFragment)currentFragment).setInputFocus();
}
}
private void insertExtraText() {
if (extraText == null) {
return;
}
boolean isExtraTextInserted = false;
for (ChatViewerFragment chat : registeredChats) {
if (chat.isEqual(actionWithAccount, actionWithUser)) {
chat.setInputText(extraText);
isExtraTextInserted = true;
}
}
if (isExtraTextInserted) {
extraText = null;
}
}
@Override
public void onRecentChatSelected(AbstractChat chat) {
selectPage(chat.getAccount(), chat.getUser(), true);
}
@Override
public void onRecentChatsCalled() {
viewPager.setCurrentItem(0, true);
}
} }
package com.xabber.android.ui; package com.xabber.android.ui;
import android.app.Activity;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.os.Bundle; 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.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View; 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.ViewGroup;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.xabber.android.data.Application; import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.NetworkException; import com.xabber.android.data.NetworkException;
import com.xabber.android.data.SettingsManager; 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.archive.MessageArchiveManager;
import com.xabber.android.data.extension.attention.AttentionManager; import com.xabber.android.data.extension.attention.AttentionManager;
import com.xabber.android.data.extension.cs.ChatStateManager; import com.xabber.android.data.extension.cs.ChatStateManager;
...@@ -58,25 +50,14 @@ import com.xabber.android.ui.dialog.ChatExportDialogFragment; ...@@ -58,25 +50,14 @@ import com.xabber.android.ui.dialog.ChatExportDialogFragment;
import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper; import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper;
import com.xabber.android.ui.helper.ContactTitleInflater; import com.xabber.android.ui.helper.ContactTitleInflater;
import com.xabber.android.ui.preferences.ChatEditor; import com.xabber.android.ui.preferences.ChatEditor;
import com.xabber.android.ui.widget.PageSwitcher;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
public class ChatViewerFragment implements OnCreateContextMenuListener { public class ChatViewerFragment extends Fragment {
/** public static final String ARGUMENT_ACCOUNT = "ARGUMENT_ACCOUNT";
* Minimum number of new messages to be requested from the server side public static final String ARGUMENT_USER = "ARGUMENT_USER";
* archive.
*/
private static final int MINIMUM_MESSAGES_TO_LOAD = 10;
/** 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;
private TextView pageView; private TextView pageView;
private View titleView; private View titleView;
...@@ -84,75 +65,52 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -84,75 +65,52 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
private ListView listView; private ListView listView;
private ChatMessageAdapter chatMessageAdapter; private ChatMessageAdapter chatMessageAdapter;
/** private boolean skipOnTextChanges;
* Whether pages are shown.
*/
private boolean pagesShown;
/**
* Animation used to hide pages.
*/
private Animation pagesHideAnimation;
/** /**
* Animation used for incoming message notification. * Animation used for incoming message notification.
*/ */
private Animation shakeAnimation; private Animation shakeAnimation;
private Handler handler; private AbstractAvatarInflaterHelper avatarInflaterHelper;
/** private String account;
* Runnable called to hide pages. private String user;
*/
private final Runnable pagesHideRunnable = new Runnable() {
@Override
public void run() {
handler.removeCallbacks(this);
pageView.startAnimation(pagesHideAnimation);
}
};
private final FragmentActivity activity; private ChatViewerFragmentListener listener;
private final View view; public static ChatViewerFragment newInstance(String account, String user) {
ChatViewerFragment fragment = new ChatViewerFragment();
public ChatViewerFragment(FragmentActivity activity) { Bundle arguments = new Bundle();
this.activity = activity; arguments.putString(ARGUMENT_ACCOUNT, account);
onCreate(null); arguments.putString(ARGUMENT_USER, user);
view = onCreateView(activity.getLayoutInflater(), null, null); fragment.setArguments(arguments);
return fragment;
} }
private FragmentActivity getActivity() { @Override
return activity; public void onCreate(Bundle savedInstanceState) {
} super.onCreate(savedInstanceState);
private String getString(int resId, Object... formatArgs) { Bundle args = getArguments();
return activity.getString(resId, formatArgs); account = args.getString(ARGUMENT_ACCOUNT, null);
} user = args.getString(ARGUMENT_USER, null);
private void registerForContextMenu(View view) { avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
view.setOnCreateContextMenuListener(this);
} }
public View getView() { @Override
return view; public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
} super.onCreateView(inflater, container, savedInstanceState);
public void onCreate(Bundle savedInstanceState) { shakeAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.shake);
// super.onCreate(savedInstanceState);
avatarInflaterHelper = AbstractAvatarInflaterHelper
.createAbstractContactInflaterHelper();
handler = new Handler();
pagesShown = false;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, /*
Bundle savedInstanceState) { Animation used to hide pages.
shakeAnimation = AnimationUtils.loadAnimation(getActivity(), */
R.anim.shake); Animation pagesHideAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.chat_page_out);
pagesHideAnimation = AnimationUtils.loadAnimation(getActivity(), pagesHideAnimation.setAnimationListener(new Animation.AnimationListener() {
R.anim.chat_page_out);
pagesHideAnimation.setAnimationListener(new AnimationListener() {
@Override @Override
public void onAnimationStart(Animation animation) { public void onAnimationStart(Animation animation) {
...@@ -168,17 +126,21 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -168,17 +126,21 @@ 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()); chatMessageAdapter = new ChatMessageAdapter(getActivity());
chatMessageAdapter.setChat(account, user);
listView = (ListView) view.findViewById(android.R.id.list);
listView.setAdapter(chatMessageAdapter);
pageView = (TextView) view.findViewById(R.id.chat_page); pageView = (TextView) view.findViewById(R.id.chat_page);
titleView = view.findViewById(R.id.title); titleView = view.findViewById(R.id.title);
inputView = (EditText) view.findViewById(R.id.chat_input); inputView = (EditText) view.findViewById(R.id.chat_input);
listView = (ListView) view.findViewById(android.R.id.list);
listView.setAdapter(chatMessageAdapter);
view.findViewById(R.id.chat_send).setOnClickListener( view.findViewById(R.id.chat_send).setOnClickListener(
new OnClickListener() { new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
...@@ -186,7 +148,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -186,7 +148,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
} }
}); });
titleView.setOnClickListener(new OnClickListener() { titleView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
...@@ -196,7 +158,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -196,7 +158,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
} }
}); });
inputView.setOnKeyListener(new OnKeyListener() { inputView.setOnKeyListener(new View.OnKeyListener() {
@Override @Override
public boolean onKey(View view, int keyCode, KeyEvent event) { public boolean onKey(View view, int keyCode, KeyEvent event) {
...@@ -210,7 +172,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -210,7 +172,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
} }
}); });
inputView.setOnEditorActionListener(new OnEditorActionListener() { inputView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override @Override
public boolean onEditorAction(TextView view, int actionId, public boolean onEditorAction(TextView view, int actionId,
...@@ -226,13 +188,11 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -226,13 +188,11 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
inputView.addTextChangedListener(new TextWatcher() { inputView.addTextChangedListener(new TextWatcher() {
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, public void onTextChanged(CharSequence s, int start, int before, int count) {
int count) {
} }
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, public void beforeTextChanged(CharSequence s, int start, int count, int after) {
int after) {
} }
@Override @Override
...@@ -245,16 +205,141 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -245,16 +205,141 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
} }
}); });
registerForContextMenu(listView);
setHasOptionsMenu(true);
updateView();
chatMessageAdapter.onChange();
return view; return view;
}
@Override
public void onResume() {
super.onResume();
((ChatViewer)getActivity()).registerChat(this);
registerForContextMenu(listView);
restoreInputState();
}
private void restoreInputState() {
skipOnTextChanges = true;
inputView.setText(ChatManager.getInstance().getTypedMessage(account, user));
inputView.setSelection(ChatManager.getInstance().getSelectionStart(account, user),
ChatManager.getInstance().getSelectionEnd(account, user));
skipOnTextChanges = false;
}
@Override
public void onPause() {
super.onPause();
saveInputState();
((ChatViewer)getActivity()).unregisterChat(this);
unregisterForContextMenu(listView);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
listener = (ChatViewerFragmentListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement ChatViewerFragmentListener");
}
}
@Override
public void onDetach() {
listener = null;
super.onDetach();
}
public void saveInputState() {
ChatManager.getInstance().setTyped(account, user, inputView.getText().toString(),
inputView.getSelectionStart(), inputView.getSelectionEnd());
}
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.getText().clear();
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) {
MessageManager.getInstance().sendMessage(account, user, text);
updateChat(false);
}
private void updateView() {
chatMessageAdapter.onChange();
final AbstractContact abstractContact = RosterManager.getInstance().getBestContact(account, user);
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 account = chatMessageAdapter.getAccount();
final String user = chatMessageAdapter.getUser(); final String user = chatMessageAdapter.getUser();
AbstractChat abstractChat = MessageManager.getInstance().getChat(account, user); 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 (abstractChat != null && abstractChat instanceof RoomChat) {
if (((RoomChat) abstractChat).getState() == RoomState.unavailable) { if (((RoomChat) abstractChat).getState() == RoomState.unavailable) {
...@@ -276,7 +361,13 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -276,7 +361,13 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
menu.findItem(R.id.action_edit_contact).setVisible(true) menu.findItem(R.id.action_edit_contact).setVisible(true)
.setIntent(ContactEditor.createIntent(getActivity(), account, user)); .setIntent(ContactEditor.createIntent(getActivity(), account, user));
} }
menu.findItem(R.id.action_chat_list).setIntent(ChatList.createIntent(getActivity())); menu.findItem(R.id.action_chat_list).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
listener.onRecentChatsCalled();
return true;
}
});
menu.findItem(R.id.action_chat_settings) menu.findItem(R.id.action_chat_settings)
.setIntent(ChatEditor.createIntent(getActivity(), account, user)); .setIntent(ChatEditor.createIntent(getActivity(), account, user));
...@@ -288,7 +379,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -288,7 +379,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
MessageManager.getInstance().requestToLoadLocalHistory(account, user); MessageManager.getInstance().requestToLoadLocalHistory(account, user);
MessageArchiveManager.getInstance() MessageArchiveManager.getInstance()
.requestHistory(account, user, MINIMUM_MESSAGES_TO_LOAD, 0); .requestHistory(account, user, MINIMUM_MESSAGES_TO_LOAD, 0);
onChatChange(false); updateChat(false);
return true; return true;
} }
}); });
...@@ -331,7 +422,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -331,7 +422,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
new MenuItem.OnMenuItemClickListener() { new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
inputView.setText(""); inputView.getText().clear();
return true; return true;
} }
}); });
...@@ -342,7 +433,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -342,7 +433,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
MessageManager.getInstance() MessageManager.getInstance()
.clearHistory(account, user); .clearHistory(account, user);
onChatChange(false); updateChat(false);
return false; return false;
} }
}); });
...@@ -352,10 +443,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -352,10 +443,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
ChatExportDialogFragment ChatExportDialogFragment.newInstance(account, user).show(getActivity().getFragmentManager(), "CHAT_EXPORT");
.newInstance(account, user)
.show(getActivity().getSupportFragmentManager(),
"CHAT_EXPORT");
return true; return true;
} }
...@@ -379,7 +467,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -379,7 +467,7 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
abstractChat.getUser()); abstractChat.getUser());
if (securityLevel == SecurityLevel.plain) { if (securityLevel == SecurityLevel.plain) {
menu.findItem(R.id.action_start_encryption).setVisible(true) menu.findItem(R.id.action_start_encryption).setVisible(true)
.setEnabled(SettingsManager.securityOtrMode() != SecurityOtrMode.disabled) .setEnabled(SettingsManager.securityOtrMode() != SettingsManager.SecurityOtrMode.disabled)
.setOnMenuItemClickListener( .setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() { new MenuItem.OnMenuItemClickListener() {
...@@ -446,160 +534,59 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -446,160 +534,59 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
&& ((RoomChat) abstractChat).getState() == RoomState.available) && ((RoomChat) abstractChat).getState() == RoomState.available)
menu.findItem(R.id.action_list_of_occupants).setVisible(true).setIntent( menu.findItem(R.id.action_list_of_occupants).setVisible(true).setIntent(
OccupantList.createIntent(getActivity(), account, user)); OccupantList.createIntent(getActivity(), account, user));
return true;
} }
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View view, public void onCreateContextMenu(ContextMenu menu, View view,
ContextMenuInfo menuInfo) { ContextMenu.ContextMenuInfo menuInfo) {
// super.onCreateContextMenu(menu, view, menuInfo); super.onCreateContextMenu(menu, view, menuInfo);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
final MessageItem message = (MessageItem) listView.getAdapter() final MessageItem message = (MessageItem) listView.getAdapter().getItem(info.position);
.getItem(info.position);
if (message != null && message.getAction() != null)
return;
if (message.isError()) {
menu.add(R.string.message_repeat).setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
@Override MenuInflater inflater = getActivity().getMenuInflater();
public boolean onMenuItemClick(MenuItem item) { inflater.inflate(R.menu.chat_context_menu, menu);
sendMessage(message.getText());
return true;
}
}); if (message.isError()) {
menu.findItem(R.id.action_message_repeat).setVisible(true);
} }
menu.add(R.string.message_quote).setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
insertText("> " + message.getText() + "\n");
return true;
}
});
menu.add(R.string.message_copy).setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
((ClipboardManager) getActivity().getSystemService(
Context.CLIPBOARD_SERVICE)).setText(message
.getSpannable());
return true;
}
});
menu.add(R.string.message_remove).setOnMenuItemClickListener(
new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
MessageManager.getInstance().removeMessage(message);
onChatChange(false);
return true;
}
});
} }
public void setChat(AbstractChat chat) { @Override
final String account = chat.getAccount(); public boolean onContextItemSelected(MenuItem item) {
final String user = chat.getUser(); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
final AbstractContact abstractContact = RosterManager.getInstance() final MessageItem message = (MessageItem) listView.getAdapter().getItem(info.position);
.getBestContact(account, user);
if (chat.equals(chatMessageAdapter.getAccount(), switch (item.getItemId()) {
chatMessageAdapter.getUser())) { case R.id.action_message_repeat:
chatMessageAdapter.updateInfo(); sendMessage(message.getText());
} else { return true;
if (chatMessageAdapter.getAccount() != null
&& chatMessageAdapter.getUser() != null) case R.id.action_message_copy:
saveState(); ((ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE))
if (PageSwitcher.LOG) .setPrimaryClip(ClipData.newPlainText(message.getSpannable(), message.getSpannable()));
LogManager.i(this, "Load " + chatMessageAdapter.getUser() return true;
+ " in " + chatMessageAdapter.getAccount());
skipOnTextChanges = true; case R.id.action_message_quote:
inputView.setText(ChatManager.getInstance().getTypedMessage( insertText("> " + message.getText() + "\n");
account, user)); return true;
inputView.setSelection(
ChatManager.getInstance().getSelectionStart(account, user), case R.id.action_message_remove:
ChatManager.getInstance().getSelectionEnd(account, user)); MessageManager.getInstance().removeMessage(message);
skipOnTextChanges = false; updateChat(false);
chatMessageAdapter.setChat(account, user); return true;
listView.setAdapter(listView.getAdapter());
} default:
return super.onContextItemSelected(item);
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. * Insert additional text to the input.
* *
* @param additional * @param additional
*/ */
public void insertText(String additional) { private void insertText(String additional) {
String source = inputView.getText().toString(); String source = inputView.getText().toString();
int selection = inputView.getSelectionEnd(); int selection = inputView.getSelectionEnd();
if (selection == -1) if (selection == -1)
...@@ -614,38 +601,35 @@ public class ChatViewerFragment implements OnCreateContextMenuListener { ...@@ -614,38 +601,35 @@ public class ChatViewerFragment implements OnCreateContextMenuListener {
inputView.setSelection(selection + additional.length()); inputView.setSelection(selection + additional.length());
} }
private void sendMessage() { public void updateChat(boolean incomingMessage) {
String text = inputView.getText().toString(); if (incomingMessage) {
int start = 0; titleView.findViewById(R.id.name_holder).startAnimation(shakeAnimation);
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);
} }
updateView();
} }
private void sendMessage(String text) { public boolean isEqual(String account, String user) {
final String account = chatMessageAdapter.getAccount(); return this.account.equals(account) && this.user.equals(user);
final String user = chatMessageAdapter.getUser();
MessageManager.getInstance().sendMessage(account, user, text);
onChatChange(false);
} }
public void setInputFocus() {
inputView.requestFocus();
}
public void setInputText(String text) {
insertText(text);
}
public String getAccount() {
return account;
}
public String getUser() {
return user;
}
public interface ChatViewerFragmentListener {
public void onRecentChatsCalled();
}
} }
...@@ -171,8 +171,8 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O ...@@ -171,8 +171,8 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O
text); text);
return; return;
} }
AccountChooseDialogFragment.newInstance(bareAddress, text).show( AccountChooseDialogFragment.newInstance(bareAddress, text)
getSupportFragmentManager(), "OPEN_WITH_ACCOUNT"); .show(getFragmentManager(), "OPEN_WITH_ACCOUNT");
} }
/** /**
...@@ -240,15 +240,14 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O ...@@ -240,15 +240,14 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O
if (SettingsManager.bootCount() > 2 if (SettingsManager.bootCount() > 2
&& !SettingsManager.connectionStartAtBoot() && !SettingsManager.connectionStartAtBoot()
&& !SettingsManager.startAtBootSuggested()) && !SettingsManager.startAtBootSuggested())
StartAtBootDialogFragment.newInstance().show( StartAtBootDialogFragment.newInstance().show(getFragmentManager(), "START_AT_BOOT");
getSupportFragmentManager(), "START_AT_BOOT");
if (!SettingsManager.contactIntegrationSuggested() if (!SettingsManager.contactIntegrationSuggested()
&& Application.getInstance().isContactsSupported()) { && Application.getInstance().isContactsSupported()) {
if (AccountManager.getInstance().getAllAccounts().isEmpty()) if (AccountManager.getInstance().getAllAccounts().isEmpty())
SettingsManager.setContactIntegrationSuggested(); SettingsManager.setContactIntegrationSuggested();
else else
ContactIntegrationDialogFragment.newInstance().show( ContactIntegrationDialogFragment.newInstance().show(
getSupportFragmentManager(), "CONTACT_INTEGRATION"); getFragmentManager(), "CONTACT_INTEGRATION");
} }
} }
} }
...@@ -284,7 +283,7 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O ...@@ -284,7 +283,7 @@ public class ContactList extends ManagedActivity implements OnChoosedListener, O
startActivity(MUCEditor.createIntent(this)); startActivity(MUCEditor.createIntent(this));
return true; return true;
case R.id.action_chat_list: case R.id.action_chat_list:
startActivity(ChatList.createIntent(this)); startActivity(ChatViewer.createIntent(this));
return true; return true;
case R.id.action_settings: case R.id.action_settings:
startActivity(PreferenceEditor.createIntent(this)); startActivity(PreferenceEditor.createIntent(this));
......
...@@ -14,10 +14,6 @@ ...@@ -14,10 +14,6 @@
*/ */
package com.xabber.android.ui; package com.xabber.android.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
...@@ -34,6 +30,10 @@ import com.xabber.android.ui.dialog.GroupAddDialogFragment.OnGroupAddConfirmed; ...@@ -34,6 +30,10 @@ import com.xabber.android.ui.dialog.GroupAddDialogFragment.OnGroupAddConfirmed;
import com.xabber.android.ui.helper.ManagedListActivity; import com.xabber.android.ui.helper.ManagedListActivity;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/** /**
* Manage list of selected groups. * Manage list of selected groups.
* *
...@@ -146,8 +146,7 @@ public abstract class GroupListActivity extends ManagedListActivity implements ...@@ -146,8 +146,7 @@ public abstract class GroupListActivity extends ManagedListActivity implements
} }
private void showGroupAddDialog() { private void showGroupAddDialog() {
GroupAddDialogFragment.newInstance(getGroups()).show( GroupAddDialogFragment.newInstance(getGroups()).show(getFragmentManager(), "GROUP-ADD");
getSupportFragmentManager(), "GROUP-ADD");
} }
@Override @Override
......
package com.xabber.android.ui;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.Toast;
import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.ui.adapter.ChatListAdapter;
import com.xabber.androiddev.R;
import java.util.List;
public class RecentChatFragment extends ListFragment {
private RecentChatFragmentInteractionListener listener;
private List<AbstractChat> initialChats = null;
public static RecentChatFragment newInstance() {
return new RecentChatFragment();
}
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public RecentChatFragment() {
}
public void setInitialChats(List<AbstractChat> initialChats) {
this.initialChats = initialChats;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ChatListAdapter(getActivity()));
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
listener = (RecentChatFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement RecentChatFragmentInteractionListener");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (initialChats != null) {
((ChatListAdapter) getListAdapter()).updateChats(initialChats);
initialChats = null;
}
if (getListAdapter().isEmpty()) {
Activity activity = getActivity();
Toast.makeText(activity, R.string.chat_list_is_empty, Toast.LENGTH_LONG).show();
activity.finish();
}
return inflater.inflate(R.layout.list, container, false);
}
@Override
public void onResume() {
super.onResume();
((ChatViewer)getActivity()).registerRecentChatsList(this);
}
@Override
public void onPause() {
super.onPause();
((ChatViewer)getActivity()).unregisterRecentChatsList(this);
}
@Override
public void onDetach() {
listener = null;
super.onDetach();
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (null != listener) {
listener.onRecentChatSelected((AbstractChat) getListAdapter().getItem(position));
}
}
public interface RecentChatFragmentInteractionListener {
public void onRecentChatSelected(AbstractChat chat);
}
public void updateChats(List<AbstractChat> chats) {
((ChatListAdapter) getListAdapter()).updateChats(chats);
}
}
/**
* 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; package com.xabber.android.ui.adapter;
import java.util.ArrayList; import android.content.Context;
import java.util.Collections; import android.view.LayoutInflater;
import android.app.Activity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.notification.NotificationManager; import com.xabber.android.data.notification.NotificationManager;
import com.xabber.android.data.roster.AbstractContact; import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.data.roster.RosterManager; import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.ChatList;
import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper; import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
/** import java.util.ArrayList;
* Adapter for {@link ChatList}. import java.util.List;
*
* @author alexander.ivanov
*/
public class ChatListAdapter extends BaseAdapter implements UpdatableAdapter {
private final Activity activity; public class ChatListAdapter extends BaseAdapter {
private final ArrayList<AbstractChat> abstractChats; private List<AbstractChat> chats;
private final AbstractAvatarInflaterHelper avatarInflaterHelper; private final AbstractAvatarInflaterHelper avatarInflaterHelper;
public ChatListAdapter(Activity activity) { private final Context context;
this.activity = activity;
abstractChats = new ArrayList<AbstractChat>();
avatarInflaterHelper = AbstractAvatarInflaterHelper public ChatListAdapter(Context context) {
.createAbstractContactInflaterHelper(); this.context = context;
chats = new ArrayList<>();
avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
} }
@Override public void updateChats(List<AbstractChat> chats) {
public void onChange() { this.chats.clear();
abstractChats.clear(); this.chats.addAll(chats);
abstractChats.addAll(MessageManager.getInstance().getActiveChats());
Collections.sort(abstractChats, ChatComparator.CHAT_COMPARATOR);
if (abstractChats.size() == 0) {
Toast.makeText(activity, R.string.chat_list_is_empty,
Toast.LENGTH_LONG).show();
activity.finish();
return;
}
notifyDataSetChanged(); notifyDataSetChanged();
} }
@Override @Override
public int getCount() { public int getCount() {
return abstractChats.size(); return chats.size();
} }
@Override @Override
public Object getItem(int position) { public Object getItem(int position) {
return abstractChats.get(position); return chats.get(position);
} }
@Override @Override
...@@ -87,33 +59,32 @@ public class ChatListAdapter extends BaseAdapter implements UpdatableAdapter { ...@@ -87,33 +59,32 @@ public class ChatListAdapter extends BaseAdapter implements UpdatableAdapter {
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
final View view; final View view;
if (convertView == null) { if (convertView == null) {
view = activity.getLayoutInflater().inflate( view = LayoutInflater.from(context).inflate(R.layout.chat_list_item, parent, false);
R.layout.chat_list_item, parent, false);
} else { } else {
view = convertView; view = convertView;
} }
final AbstractChat abstractChat = (AbstractChat) getItem(position); final AbstractChat abstractChat = (AbstractChat) getItem(position);
final AbstractContact abstractContact = RosterManager.getInstance() final AbstractContact abstractContact = RosterManager.getInstance()
.getBestContact(abstractChat.getAccount(), .getBestContact(abstractChat.getAccount(), abstractChat.getUser());
abstractChat.getUser());
final ImageView colorView = (ImageView) view.findViewById(R.id.color); ((TextView) view.findViewById(R.id.name)).setText(abstractContact.getName());
((ImageView) view.findViewById(R.id.color)).setImageLevel(abstractContact.getColorLevel());
final ImageView avatarView = (ImageView) view.findViewById(R.id.avatar); final ImageView avatarView = (ImageView) view.findViewById(R.id.avatar);
final TextView nameView = (TextView) view.findViewById(R.id.name);
final TextView textView = (TextView) view.findViewById(R.id.text);
colorView.setImageLevel(abstractContact.getColorLevel());
avatarView.setImageDrawable(abstractContact.getAvatar()); avatarView.setImageDrawable(abstractContact.getAvatar());
avatarInflaterHelper.updateAvatar(avatarView, abstractContact); avatarInflaterHelper.updateAvatar(avatarView, abstractContact);
nameView.setText(abstractContact.getName());
final TextView textView = (TextView) view.findViewById(R.id.text);
String statusText = MessageManager.getInstance().getLastText( String statusText = MessageManager.getInstance().getLastText(
abstractContact.getAccount(), abstractContact.getUser()); abstractContact.getAccount(), abstractContact.getUser());
textView.setText(statusText); textView.setText(statusText);
boolean newMessages = NotificationManager.getInstance() boolean newMessages = NotificationManager.getInstance()
.getNotificationMessageCount(abstractChat.getAccount(), .getNotificationMessageCount(abstractChat.getAccount(), abstractChat.getUser()) > 0;
abstractChat.getUser()) > 0; textView.setTextAppearance(context, newMessages ? R.style.ChatList_Notification
textView.setTextAppearance(activity,
newMessages ? R.style.ChatList_Notification
: R.style.ChatList_Normal); : R.style.ChatList_Normal);
return view; return view;
} }
} }
...@@ -14,11 +14,6 @@ ...@@ -14,11 +14,6 @@
*/ */
package com.xabber.android.ui.adapter; 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.app.Activity;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
...@@ -49,6 +44,11 @@ import com.xabber.android.utils.Emoticons; ...@@ -49,6 +44,11 @@ import com.xabber.android.utils.Emoticons;
import com.xabber.android.utils.StringUtils; import com.xabber.android.utils.StringUtils;
import com.xabber.androiddev.R; 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. * Adapter for the list of messages in the chat.
* *
...@@ -309,8 +309,7 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter ...@@ -309,8 +309,7 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
@Override @Override
public void onChange() { public void onChange() {
messages = new ArrayList<MessageItem>(MessageManager.getInstance() messages = new ArrayList<>(MessageManager.getInstance().getMessages(account, user));
.getMessages(account, user));
hint = getHint(); hint = getHint();
notifyDataSetChanged(); 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; package com.xabber.android.ui.adapter;
import java.util.ArrayList;
import java.util.Collection;
import android.support.v4.app.FragmentActivity; import android.app.Fragment;
import android.view.Menu; import android.app.FragmentManager;
import android.view.View; import android.support.v13.app.FragmentStatePagerAdapter;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter;
import com.xabber.android.data.entity.BaseEntity; import com.antonyt.infiniteviewpager.InfiniteViewPager;
import com.xabber.android.data.message.AbstractChat; import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.MessageManager;
import com.xabber.android.ui.ChatViewerFragment; import com.xabber.android.ui.ChatViewerFragment;
import com.xabber.android.ui.RecentChatFragment;
import com.xabber.xmpp.address.Jid; import com.xabber.xmpp.address.Jid;
/** import java.util.ArrayList;
* Adapter for the list of chat pages. import java.util.Collections;
* import java.util.Comparator;
* @author alexander.ivanov
*/
public class ChatViewerAdapter extends BaseAdapter implements SaveStateAdapter,
UpdatableAdapter {
private final FragmentActivity activity; public class ChatViewerAdapter extends FragmentStatePagerAdapter implements UpdatableAdapter {
/** /**
* Intent sent while opening chat activity. * Intent sent while opening chat activity.
*/ */
private final AbstractChat intent; private final AbstractChat intent;
/**
* Position to insert intent.
*/
private final int intentPosition;
private ArrayList<AbstractChat> activeChats; private ArrayList<AbstractChat> activeChats;
public ChatViewerAdapter(FragmentActivity activity, String account, private FinishUpdateListener finishUpdateListener;
String user) {
this.activity = activity; private Fragment currentFragment;
activeChats = new ArrayList<AbstractChat>();
intent = MessageManager.getInstance().getOrCreateChat(account, public ChatViewerAdapter(FragmentManager fragmentManager, String account, String user, FinishUpdateListener finishUpdateListener) {
Jid.getBareAddress(user)); super(fragmentManager);
Collection<? extends BaseEntity> activeChats = MessageManager this.finishUpdateListener = finishUpdateListener;
.getInstance().getActiveChats();
if (activeChats.contains(intent)) activeChats = new ArrayList<>(MessageManager.getInstance().getActiveChats());
intentPosition = -1; intent = MessageManager.getInstance().getOrCreateChat(account, Jid.getBareAddress(user));
else
intentPosition = activeChats.size(); if (!activeChats.contains(intent)) {
intent.updateCreationTime();
}
onChange(); onChange();
} }
@Override public ChatViewerAdapter(FragmentManager fragmentManager, FinishUpdateListener finishUpdateListener) {
public int getCount() { super(fragmentManager);
return activeChats.size(); this.finishUpdateListener = finishUpdateListener;
activeChats = new ArrayList<>(MessageManager.getInstance().getActiveChats());
intent = null;
onChange();
} }
@Override @Override
public Object getItem(int position) { public int getCount() {
return activeChats.get(position); // warning: scrolling to very high values (1,000,000+) results in
// strange drawing behaviour
return InfiniteViewPager.TOTAL_COUNT;
} }
@Override public int getRealCount() {
public long getItemId(int position) { return activeChats.size() + 1;
return position;
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public Fragment getItem(int virtualPagePosition) {
View view;
final AbstractChat chat = (AbstractChat) getItem(position); int chatIndex;
ChatViewerFragment fragment; int realPosition = virtualPagePosition % getRealCount();
if (convertView == null) {
fragment = new ChatViewerFragment(activity); if (realPosition == 0) {
view = fragment.getView(); RecentChatFragment activeChatFragment = RecentChatFragment.newInstance();
view.setTag(fragment); activeChatFragment.setInitialChats(activeChats);
return activeChatFragment;
} else { } else {
view = convertView; chatIndex = realPosition -1;
fragment = (ChatViewerFragment) view.getTag();
} }
fragment.setChat(chat);
return view; AbstractChat chat = activeChats.get(chatIndex);
return ChatViewerFragment.newInstance(chat.getAccount(), chat.getUser());
} }
@Override @Override
public void saveState(View view) { public void onChange() {
((ChatViewerFragment) view.getTag()).saveState(); activeChats = new ArrayList<>(MessageManager.getInstance().getActiveChats());
if (intent != null && !activeChats.contains(intent)) {
activeChats.add(intent);
}
Collections.sort(activeChats, new Comparator<AbstractChat>() {
@Override
public int compare(AbstractChat lhs, AbstractChat rhs) {
return lhs.getCreationTime().compareTo(rhs.getCreationTime());
}
});
notifyDataSetChanged();
} }
@Override public int getPageNumber(String account, String user) {
public void hidePages(View view) { for (int position = 0; position < activeChats.size(); position++) {
((ChatViewerFragment) view.getTag()).hidePages(); if (activeChats.get(position).equals(account, user)) {
return position + 1;
}
}
return 0;
} }
@Override public AbstractChat getChatByPageNumber(int virtualPosition) {
public void showPages(View view) { int realPosition = virtualPosition % getRealCount();
((ChatViewerFragment) view.getTag()).showPages();
int chatIndex = realPosition - 1;
if (chatIndex < 0) {
return null;
}
return activeChats.get(chatIndex);
} }
/** @Override
* Must be called on changes in chat (message sent, received, etc.). public void startUpdate(ViewGroup container) {
*/ if (currentFragment instanceof ChatViewerFragment) {
public void onChatChange(View view, boolean incomingMessage) { ((ChatViewerFragment)currentFragment).saveInputState();
((ChatViewerFragment) view.getTag()).onChatChange(incomingMessage); }
super.startUpdate(container);
} }
/** @Override
* Must be called on changes in chat (message sent, received, etc.). public void finishUpdate(ViewGroup container) {
*/ super.finishUpdate(container);
public void onPrepareOptionsMenu(View view, Menu menu) {
((ChatViewerFragment) view.getTag()).onPrepareOptionsMenu(menu); finishUpdateListener.onChatViewAdapterFinishUpdate();
} }
public void insertText(View view, String text) { public interface FinishUpdateListener {
((ChatViewerFragment) view.getTag()).insertText(text); public void onChatViewAdapterFinishUpdate();
} }
@Override @Override
public void onChange() { public void setPrimaryItem(ViewGroup container, int position, Object object) {
activeChats = new ArrayList<AbstractChat>(MessageManager.getInstance() if (getCurrentFragment() != object) {
.getActiveChats()); currentFragment = ((Fragment) object);
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();
super.setPrimaryItem(container, position, object);
} }
public int getPosition(String account, String user) { public Fragment getCurrentFragment() {
for (int position = 0; position < activeChats.size(); position++) return currentFragment;
if (activeChats.get(position).equals(account, user))
return position;
return -1;
} }
} public ArrayList<AbstractChat> getActiveChats() {
return activeChats;
}
}
\ No newline at end of file
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
*/ */
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import java.util.ArrayList;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.app.Dialog; import android.app.Dialog;
import android.app.DialogFragment;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import java.util.ArrayList;
/** /**
* Base dialog fragment. * Base dialog fragment.
......
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import java.util.ArrayList;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.app.DialogFragment;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
import android.support.v4.app.DialogFragment;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
...@@ -14,6 +12,8 @@ import com.xabber.android.data.roster.RosterContact; ...@@ -14,6 +12,8 @@ import com.xabber.android.data.roster.RosterContact;
import com.xabber.android.data.roster.RosterManager; import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.adapter.AccountChooseAdapter; import com.xabber.android.ui.adapter.AccountChooseAdapter;
import java.util.ArrayList;
public class AccountChooseDialogFragment extends AbstractDialogFragment { public class AccountChooseDialogFragment extends AbstractDialogFragment {
private static final String USER = "USER"; private static final String USER = "USER";
......
...@@ -14,14 +14,12 @@ ...@@ -14,14 +14,12 @@
*/ */
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import java.io.File;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.app.DialogFragment;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.support.v4.app.DialogFragment;
import android.view.View; import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
...@@ -34,6 +32,8 @@ import com.xabber.android.data.message.MessageManager; ...@@ -34,6 +32,8 @@ import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.roster.RosterManager; import com.xabber.android.data.roster.RosterManager;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import java.io.File;
public class ChatExportDialogFragment extends ConfirmDialogFragment { public class ChatExportDialogFragment extends ConfirmDialogFragment {
private static final String ACCOUNT = "ACCOUNT"; private static final String ACCOUNT = "ACCOUNT";
...@@ -45,8 +45,7 @@ public class ChatExportDialogFragment extends ConfirmDialogFragment { ...@@ -45,8 +45,7 @@ public class ChatExportDialogFragment extends ConfirmDialogFragment {
* @return * @return
*/ */
public static DialogFragment newInstance(String account, String user) { public static DialogFragment newInstance(String account, String user) {
return new ChatExportDialogFragment().putAgrument(ACCOUNT, account) return new ChatExportDialogFragment().putAgrument(ACCOUNT, account).putAgrument(USER, user);
.putAgrument(USER, user);
} }
private String account; private String account;
......
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder; 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.Application;
import com.xabber.android.data.NetworkException; import com.xabber.android.data.NetworkException;
......
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder; 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.SettingsManager;
import com.xabber.android.data.account.AccountManager; import com.xabber.android.data.account.AccountManager;
......
...@@ -14,17 +14,17 @@ ...@@ -14,17 +14,17 @@
*/ */
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import java.util.ArrayList;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment; import android.app.DialogFragment;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Toast; import android.widget.Toast;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import java.util.ArrayList;
public class GroupAddDialogFragment extends ConfirmDialogFragment { public class GroupAddDialogFragment extends ConfirmDialogFragment {
private static final String GROUPS = "GROUPS"; private static final String GROUPS = "GROUPS";
......
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder; 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.Application;
import com.xabber.android.data.NetworkException; import com.xabber.android.data.NetworkException;
......
...@@ -16,7 +16,7 @@ package com.xabber.android.ui.dialog; ...@@ -16,7 +16,7 @@ package com.xabber.android.ui.dialog;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AlertDialog.Builder; import android.app.AlertDialog.Builder;
import android.support.v4.app.DialogFragment; import android.app.DialogFragment;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Toast; import android.widget.Toast;
......
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder; 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.account.AccountManager;
import com.xabber.android.data.extension.muc.MUCManager; import com.xabber.android.data.extension.muc.MUCManager;
......
package com.xabber.android.ui.dialog; package com.xabber.android.ui.dialog;
import android.app.AlertDialog.Builder; 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.SettingsManager;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
......
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
*/ */
package com.xabber.android.ui.helper; package com.xabber.android.ui.helper;
import org.jivesoftware.smackx.ChatState;
import android.app.Activity; import android.app.Activity;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
...@@ -24,7 +22,6 @@ import android.graphics.Shader.TileMode; ...@@ -24,7 +22,6 @@ import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
...@@ -34,6 +31,8 @@ import com.xabber.android.data.roster.AbstractContact; ...@@ -34,6 +31,8 @@ import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.utils.Emoticons; import com.xabber.android.utils.Emoticons;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import org.jivesoftware.smackx.ChatState;
/** /**
* Helper class to update <code>contact_title.xml</code>. * Helper class to update <code>contact_title.xml</code>.
* *
...@@ -51,47 +50,53 @@ public class ContactTitleInflater { ...@@ -51,47 +50,53 @@ public class ContactTitleInflater {
*/ */
public static void updateTitle(View titleView, final Activity activity, public static void updateTitle(View titleView, final Activity activity,
AbstractContact abstractContact) { AbstractContact abstractContact) {
final TypedArray typedArray = activity final TypedArray typedArray = activity.obtainStyledAttributes(R.styleable.ContactList);
.obtainStyledAttributes(R.styleable.ContactList);
final Drawable titleAccountBackground = typedArray final Drawable titleAccountBackground = typedArray
.getDrawable(R.styleable.ContactList_titleAccountBackground); .getDrawable(R.styleable.ContactList_titleAccountBackground);
typedArray.recycle(); typedArray.recycle();
final TextView nameView = (TextView) titleView.findViewById(R.id.name); final TextView nameView = (TextView) titleView.findViewById(R.id.name);
final ImageView avatarView = (ImageView) titleView final ImageView avatarView = (ImageView) titleView.findViewById(R.id.avatar);
.findViewById(R.id.avatar); final ImageView statusModeView = (ImageView) titleView.findViewById(R.id.status_mode);
final ImageView statusModeView = (ImageView) titleView final TextView statusTextView = (TextView) titleView.findViewById(R.id.status_text);
.findViewById(R.id.status_mode);
final TextView statusTextView = (TextView) titleView
.findViewById(R.id.status_text);
final View shadowView = titleView.findViewById(R.id.shadow); final View shadowView = titleView.findViewById(R.id.shadow);
titleView.setBackgroundDrawable(titleAccountBackground); titleView.setBackgroundDrawable(titleAccountBackground);
nameView.setText(abstractContact.getName()); nameView.setText(abstractContact.getName());
statusModeView.setImageLevel(abstractContact.getStatusMode() statusModeView.setImageLevel(abstractContact.getStatusMode().getStatusLevel());
.getStatusLevel()); titleView.getBackground().setLevel(AccountManager.getInstance().getColorLevel(
titleView.getBackground().setLevel(
AccountManager.getInstance().getColorLevel(
abstractContact.getAccount())); abstractContact.getAccount()));
avatarView.setImageDrawable(abstractContact.getAvatar()); avatarView.setImageDrawable(abstractContact.getAvatar());
setStatusText(activity, abstractContact, statusTextView);
final Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.shadow);
final BitmapDrawable shadowDrawable = new BitmapDrawable(bitmap);
shadowDrawable.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
shadowView.setBackgroundDrawable(shadowDrawable);
if (abstractContact.isConnected()) {
shadowView.setVisibility(View.GONE);
} else {
shadowView.setVisibility(View.VISIBLE);
}
}
private static void setStatusText(Activity activity, AbstractContact abstractContact,
TextView statusTextView) {
ChatState chatState = ChatStateManager.getInstance().getChatState( ChatState chatState = ChatStateManager.getInstance().getChatState(
abstractContact.getAccount(), abstractContact.getUser()); abstractContact.getAccount(), abstractContact.getUser());
final CharSequence statusText; final CharSequence statusText;
if (chatState == ChatState.composing) if (chatState == ChatState.composing) {
statusText = activity.getString(R.string.chat_state_composing); statusText = activity.getString(R.string.chat_state_composing);
else if (chatState == ChatState.paused) } else if (chatState == ChatState.paused) {
statusText = activity.getString(R.string.chat_state_paused); statusText = activity.getString(R.string.chat_state_paused);
else } else {
statusText = Emoticons.getSmiledText(activity, statusText = Emoticons.getSmiledText(activity, abstractContact.getStatusText());
abstractContact.getStatusText()); }
statusTextView.setText(statusText); statusTextView.setText(statusText);
final Bitmap bitmap = BitmapFactory.decodeResource(
activity.getResources(), R.drawable.shadow);
final BitmapDrawable shadowDrawable = new BitmapDrawable(bitmap);
shadowDrawable.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);
shadowView.setBackgroundDrawable(shadowDrawable);
if (abstractContact.isConnected())
shadowView.setVisibility(View.GONE);
else
shadowView.setVisibility(View.VISIBLE);
} }
} }
...@@ -33,11 +33,9 @@ import com.xabber.android.data.roster.AbstractContact; ...@@ -33,11 +33,9 @@ import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.data.roster.GroupManager; import com.xabber.android.data.roster.GroupManager;
import com.xabber.android.data.roster.PresenceManager; import com.xabber.android.data.roster.PresenceManager;
import com.xabber.android.data.roster.ShowOfflineMode; 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.ChatViewer;
import com.xabber.android.ui.ContactAdd; import com.xabber.android.ui.ContactAdd;
import com.xabber.android.ui.ContactEditor; import com.xabber.android.ui.ContactEditor;
import com.xabber.android.ui.preferences.ContactViewer;
import com.xabber.android.ui.MUCEditor; import com.xabber.android.ui.MUCEditor;
import com.xabber.android.ui.StatusEditor; import com.xabber.android.ui.StatusEditor;
import com.xabber.android.ui.adapter.UpdatableAdapter; import com.xabber.android.ui.adapter.UpdatableAdapter;
...@@ -45,6 +43,8 @@ import com.xabber.android.ui.dialog.ContactDeleteDialogFragment; ...@@ -45,6 +43,8 @@ import com.xabber.android.ui.dialog.ContactDeleteDialogFragment;
import com.xabber.android.ui.dialog.GroupDeleteDialogFragment; import com.xabber.android.ui.dialog.GroupDeleteDialogFragment;
import com.xabber.android.ui.dialog.GroupRenameDialogFragment; import com.xabber.android.ui.dialog.GroupRenameDialogFragment;
import com.xabber.android.ui.dialog.MUCDeleteDialogFragment; 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; import com.xabber.androiddev.R;
/** /**
...@@ -84,7 +84,7 @@ public class ContextMenuHelper { ...@@ -84,7 +84,7 @@ public class ContextMenuHelper {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
MUCDeleteDialogFragment.newInstance(account, user) MUCDeleteDialogFragment.newInstance(account, user)
.show(activity.getSupportFragmentManager(), .show(activity.getFragmentManager(),
"MUC_DELETE"); "MUC_DELETE");
return true; return true;
} }
...@@ -131,8 +131,7 @@ public class ContextMenuHelper { ...@@ -131,8 +131,7 @@ public class ContextMenuHelper {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
ContactDeleteDialogFragment.newInstance(account, ContactDeleteDialogFragment.newInstance(account,
user).show( user).show(activity.getFragmentManager(),
activity.getSupportFragmentManager(),
"CONTACT_DELETE"); "CONTACT_DELETE");
return true; return true;
} }
...@@ -225,8 +224,7 @@ public class ContextMenuHelper { ...@@ -225,8 +224,7 @@ public class ContextMenuHelper {
account == GroupManager.NO_ACCOUNT ? null account == GroupManager.NO_ACCOUNT ? null
: account, : account,
group == GroupManager.NO_GROUP ? null group == GroupManager.NO_GROUP ? null
: group).show( : group).show(activity.getFragmentManager(),
activity.getSupportFragmentManager(),
"GROUP_RENAME"); "GROUP_RENAME");
return true; return true;
} }
...@@ -241,9 +239,7 @@ public class ContextMenuHelper { ...@@ -241,9 +239,7 @@ public class ContextMenuHelper {
.newInstance( .newInstance(
account == GroupManager.NO_ACCOUNT ? null account == GroupManager.NO_ACCOUNT ? null
: account, group) : account, group)
.show(activity .show(activity.getFragmentManager(), "GROUP_DELETE");
.getSupportFragmentManager(),
"GROUP_DELETE");
return true; 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();
}
}
<?xml version="1.0" encoding="utf-8"?>
<com.antonyt.infiniteviewpager.InfiniteViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/.
-->
<com.xabber.android.ui.widget.PageSwitcher
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/switcher"
/>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_message_repeat"
android:visible="false"
android:title="@string/message_repeat" />
<item android:id="@+id/action_message_quote"
android:title="@string/message_quote" />
<item android:id="@+id/action_message_copy"
android:title="@string/message_copy" />
<item android:id="@+id/action_message_remove"
android:title="@string/message_remove" />
</menu>
\ No newline at end of file
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