Commit a5d5b4aa authored by Grigory Fedorov's avatar Grigory Fedorov

First more or less working implementation of cycle chat scrolling.

antonyt/InfiniteViewPager used partially.
parent 3b7e164a
/**
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. Should be used with an {@link
* InfinitePagerAdapter}.
*/
public class InfiniteViewPager extends ViewPager {
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 ((ChatViewerAdapter) getAdapter()).getRealCount() * 100;
}
@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
super.setOnPageChangeListener(listener);
}
}
......@@ -68,7 +68,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
ViewPager viewPager;
Collection<CurrentUpdatableChat> registeredChats = new HashSet<>();
Collection<ChatViewerFragment> registeredChats = new HashSet<>();
private String actionWithAccount = null;
private String actionWithUser = null;
......@@ -253,35 +253,17 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
@Override
public void onChatChanged(final String account, final String user,
final boolean incoming) {
LogManager.i(this, "updateChat account: " + account + ", user: " + user);
chatViewerAdapter.onChange();
for (CurrentUpdatableChat chat : registeredChats) {
if (chat.isEqual(account, user)) {
chat.updateChat(incoming);
}
}
}
@Override
public void onContactsChanged(Collection<BaseEntity> entities) {
chatViewerAdapter.onChange();
for (CurrentUpdatableChat chat : registeredChats) {
chat.updateChat(false);
}
}
@Override
public void onAccountsChanged(Collection<String> accounts) {
chatViewerAdapter.onChange();
for (CurrentUpdatableChat chat : registeredChats) {
chat.updateChat(false);
}
}
void onSent() {
......@@ -307,9 +289,11 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
@Override
public void onPageSelected(int position) {
LogManager.i(this, "onPageSelected: " + position);
int realCount = chatViewerAdapter.getRealCount();
AbstractChat chat = chatViewerAdapter.getChat(position);
int virtualPosition = position % realCount;
AbstractChat chat = chatViewerAdapter.getChat(virtualPosition);
String account = chat.getAccount();
String user = chat.getUser();
......@@ -320,8 +304,6 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
}
private void onChatSelected(String account, String user) {
LogManager.i(this, "onChatSelected. account: " + account + "; user: " + user);
actionWithAccount = account;
actionWithUser = user;
......@@ -340,21 +322,20 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
@Override
public void onPageScrollStateChanged(int state) {
}
public void registerChat(CurrentUpdatableChat chat) {
public void registerChat(ChatViewerFragment chat) {
registeredChats.add(chat);
}
public void unregisterChat(CurrentUpdatableChat chat) {
public void unregisterChat(ChatViewerFragment chat) {
registeredChats.remove(chat);
}
@Override
public void onChatViewAdapterFinishUpdate() {
for (CurrentUpdatableChat chat : registeredChats) {
for (ChatViewerFragment chat : registeredChats) {
if (chat.isEqual(actionWithAccount, actionWithUser)) {
chat.setInputFocus();
......@@ -365,11 +346,4 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
}
}
}
public interface CurrentUpdatableChat {
public void updateChat(final boolean incoming);
public boolean isEqual(String account, String user);
public void setInputFocus();
public void setInputText(String text);
}
}
......@@ -26,7 +26,6 @@ import android.widget.ListView;
import android.widget.TextView;
import com.xabber.android.data.Application;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.NetworkException;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.extension.archive.MessageArchiveManager;
......@@ -52,10 +51,7 @@ import com.xabber.android.ui.helper.ContactTitleInflater;
import com.xabber.android.ui.preferences.ChatEditor;
import com.xabber.androiddev.R;
public class ChatViewerFragment extends Fragment implements ChatViewer.CurrentUpdatableChat {
public static final String ARGUMENT_ACCOUNT = "ARGUMENT_ACCOUNT";
public static final String ARGUMENT_USER = "ARGUMENT_USER";
public class ChatViewerFragment extends Fragment {
private static final int MINIMUM_MESSAGES_TO_LOAD = 10;
......@@ -77,35 +73,29 @@ public class ChatViewerFragment extends Fragment implements ChatViewer.CurrentUp
private String account;
private String user;
public static ChatViewerFragment newInstance(String account, String user) {
ChatViewerFragment fragment = new ChatViewerFragment();
private int activeChatIndex;
private ActiveChatProvider activeChatProvider;
Bundle arguments = new Bundle();
arguments.putString(ARGUMENT_ACCOUNT, account);
arguments.putString(ARGUMENT_USER, user);
fragment.setArguments(arguments);
return fragment;
public static ChatViewerFragment newInstance() {
return new ChatViewerFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
}
Bundle args = getArguments();
account = args.getString(ARGUMENT_ACCOUNT, null);
user = args.getString(ARGUMENT_USER, null);
LogManager.i(this, "onCreate. user: " + user);
public void setActiveChat(ActiveChatProvider activeChatProvider, int activeChatIndex) {
this.activeChatProvider = activeChatProvider;
this.activeChatIndex = activeChatIndex;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
LogManager.i(this, "onCreateView. user: " + user);
updateUserAndAccount();
shakeAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.shake);
......@@ -133,7 +123,6 @@ public class ChatViewerFragment extends Fragment implements ChatViewer.CurrentUp
View view = inflater.inflate(R.layout.chat_viewer_item, container, false);
chatMessageAdapter = new ChatMessageAdapter(getActivity());
chatMessageAdapter.setChat(account, user);
listView = (ListView) view.findViewById(android.R.id.list);
listView.setAdapter(chatMessageAdapter);
......@@ -219,12 +208,16 @@ public class ChatViewerFragment extends Fragment implements ChatViewer.CurrentUp
}
private void updateUserAndAccount() {
AbstractChat activeChat = activeChatProvider.getActiveChat(activeChatIndex);
user = activeChat.getUser();
account = activeChat.getAccount();
}
@Override
public void onResume() {
super.onResume();
LogManager.i(this, "onResume. user: " + user);
((ChatViewer)getActivity()).registerChat(this);
registerForContextMenu(listView);
......@@ -302,6 +295,10 @@ public class ChatViewerFragment extends Fragment implements ChatViewer.CurrentUp
}
private void updateView() {
updateUserAndAccount();
chatMessageAdapter.setChat(account, user);
final AbstractContact abstractContact = RosterManager.getInstance().getBestContact(account, user);
ContactTitleInflater.updateTitle(titleView, getActivity(), abstractContact);
......@@ -586,28 +583,29 @@ public class ChatViewerFragment extends Fragment implements ChatViewer.CurrentUp
inputView.setSelection(selection + additional.length());
}
@Override
public void updateChat(boolean incomingMessage) {
if (incomingMessage) {
titleView.findViewById(R.id.name_holder).startAnimation(shakeAnimation);
}
updateUserAndAccount();
updateMessages();
updateView();
}
@Override
public boolean isEqual(String account, String user) {
return this.account.equals(account) && this.user.equals(user);
}
@Override
public void setInputFocus() {
inputView.requestFocus();
}
@Override
public void setInputText(String text) {
insertText(text);
}
public interface ActiveChatProvider {
public AbstractChat getActiveChat(int index);
}
}
......@@ -6,7 +6,6 @@ import android.app.FragmentManager;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.view.ViewGroup;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.message.AbstractChat;
import com.xabber.android.data.message.MessageManager;
import com.xabber.android.ui.ChatViewerFragment;
......@@ -16,18 +15,14 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class ChatViewerAdapter extends FragmentStatePagerAdapter implements UpdatableAdapter {
public class ChatViewerAdapter extends FragmentStatePagerAdapter implements UpdatableAdapter,
ChatViewerFragment.ActiveChatProvider {
/**
* Intent sent while opening chat activity.
*/
private final AbstractChat intent;
/**
* Position to insert intent.
*/
// private final int intentPosition;
private ArrayList<AbstractChat> activeChats;
private FinishUpdateListener finishUpdateListener;
......@@ -47,19 +42,45 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter implements Upda
@Override
public int getCount() {
return activeChats.size();
// warning: scrolling to very high values (1,000,000+) results in
// strange drawing behaviour
return Integer.MAX_VALUE;
}
public int getRealCount() {
int realCount = activeChats.size();
if (realCount == 1) {
return 4;
} else if (realCount == 2 || realCount == 3) {
return realCount * 2;
} else {
return realCount;
}
}
@Override
public Fragment getItem(int i) {
int position = i % activeChats.size();
AbstractChat abstractChat = getChat(i);
return ChatViewerFragment.newInstance(abstractChat.getAccount(), abstractChat.getUser());
ChatViewerFragment chatViewerFragment = ChatViewerFragment.newInstance();
chatViewerFragment.setActiveChat(this, position);
return chatViewerFragment;
}
public AbstractChat getChat(int i) {
return activeChats.get(i);
int realCount = activeChats.size();
int position;
if (realCount == 1) {
position = 0;
} else if (realCount == 2 || realCount == 3) {
position = i % realCount;
} else {
position = i;
}
return activeChats.get(position);
}
@Override
......@@ -81,8 +102,6 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter implements Upda
}
public int getPosition(String account, String user) {
LogManager.i(this, "getPosition: " + account + " : " + user);
for (int position = 0; position < activeChats.size(); position++) {
if (activeChats.get(position).equals(account, user)) {
return position;
......@@ -92,18 +111,23 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter implements Upda
return -1;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
}
@Override
public void finishUpdate(ViewGroup container) {
super.finishUpdate(container);
finishUpdateListener.onChatViewAdapterFinishUpdate();
}
@Override
public AbstractChat getActiveChat(int index) {
return getChat(index);
}
public interface FinishUpdateListener {
public void onChatViewAdapterFinishUpdate();
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
<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">
</android.support.v4.view.ViewPager>
\ No newline at end of file
android:layout_height="match_parent"/>
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