Commit 9d995fdf authored by Grigory Fedorov's avatar Grigory Fedorov

Merge branch 'feature/chat_design' into develop

Conflicts:
	app/build.gradle
	app/src/main/java/com/xabber/android/ui/ChatViewer.java
	app/src/main/java/com/xabber/android/ui/helper/ContactTitleActionBarInflater.java
parents e602df51 aae11448
...@@ -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 123 versionCode 129
versionName '0.10.23a' versionName '0.10.30'
} }
buildTypes { buildTypes {
......
...@@ -14,20 +14,6 @@ ...@@ -14,20 +14,6 @@
*/ */
package com.xabber.android.data.extension.cs; package com.xabber.android.data.extension.cs;
import java.util.Calendar;
import java.util.Map;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smackx.ChatState;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.ChatStateExtension;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
...@@ -52,6 +38,20 @@ import com.xabber.android.data.roster.RosterManager; ...@@ -52,6 +38,20 @@ import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.receiver.ComposingPausedReceiver; import com.xabber.android.receiver.ComposingPausedReceiver;
import com.xabber.xmpp.address.Jid; import com.xabber.xmpp.address.Jid;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smackx.ChatState;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.ChatStateExtension;
import java.util.Calendar;
import java.util.Map;
/** /**
* Provide information about chat state. * Provide information about chat state.
* *
...@@ -260,7 +260,7 @@ public class ChatStateManager implements OnDisconnectListener, ...@@ -260,7 +260,7 @@ public class ChatStateManager implements OnDisconnectListener,
pauseIntents.put(account, user, pendingIntent); pauseIntents.put(account, user, pendingIntent);
} }
public void onPaused(Intent intent, String account, String user) { public void onPaused(String account, String user) {
if (account == null || user == null) if (account == null || user == null)
return; return;
updateChatState(account, user, ChatState.paused); updateChatState(account, user, ChatState.paused);
......
...@@ -30,8 +30,7 @@ public class ComposingPausedReceiver extends BroadcastReceiver { ...@@ -30,8 +30,7 @@ public class ComposingPausedReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
ChatStateManager.getInstance().onPaused(intent, getAccount(intent), ChatStateManager.getInstance().onPaused(getAccount(intent), getUser(intent));
getUser(intent));
} }
public static Intent createIntent(Context context, String account, public static Intent createIntent(Context context, String account,
......
...@@ -14,13 +14,18 @@ ...@@ -14,13 +14,18 @@
*/ */
package com.xabber.android.ui; package com.xabber.android.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView; import android.widget.ImageView;
import com.xabber.android.data.ActivityManager; import com.xabber.android.data.ActivityManager;
...@@ -192,7 +197,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener ...@@ -192,7 +197,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
if (chatState == RoomState.unavailable) { if (chatState == RoomState.unavailable) {
menu.findItem(R.id.action_join_conference).setVisible(true); menu.findItem(R.id.action_join_conference).setVisible(true);
menu.findItem(R.id.action_close_chat).setVisible(true);
} else { } else {
menu.findItem(R.id.action_invite_to_chat).setVisible(true); menu.findItem(R.id.action_invite_to_chat).setVisible(true);
...@@ -206,6 +211,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener ...@@ -206,6 +211,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
if (abstractChat instanceof RegularChat) { if (abstractChat instanceof RegularChat) {
menu.findItem(R.id.action_edit_contact).setVisible(true); menu.findItem(R.id.action_edit_contact).setVisible(true);
menu.findItem(R.id.action_close_chat).setVisible(true);
SecurityLevel securityLevel = OTRManager.getInstance().getSecurityLevel(account, user); SecurityLevel securityLevel = OTRManager.getInstance().getSecurityLevel(account, user);
...@@ -386,7 +392,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener ...@@ -386,7 +392,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
private void cleatInputText(String account, String user) { private void cleatInputText(String account, String user) {
for (ChatViewerFragment chat : registeredChats) { for (ChatViewerFragment chat : registeredChats) {
if (chat.isEqual(account, user)) { if (chat.isEqual(account, user)) {
chat.clearInputView(); chat.clearInputText();
} }
} }
} }
...@@ -451,8 +457,8 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener ...@@ -451,8 +457,8 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
} }
private void selectPage(int position, boolean smoothScroll) { private void selectPage(int position, boolean smoothScroll) {
viewPager.setCurrentItem(position, smoothScroll);
onPageSelected(position); onPageSelected(position);
viewPager.setCurrentItem(position, smoothScroll);
} }
private static String getAccount(Intent intent) { private static String getAccount(Intent intent) {
...@@ -596,6 +602,8 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener ...@@ -596,6 +602,8 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
@Override @Override
public void onPageSelected(int position) { public void onPageSelected(int position) {
hideKeyboard(this);
AbstractChat selectedChat = chatViewerAdapter.getChatByPageNumber(position); AbstractChat selectedChat = chatViewerAdapter.getChatByPageNumber(position);
isChatSelected = selectedChat != null; isChatSelected = selectedChat != null;
...@@ -687,6 +695,49 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener ...@@ -687,6 +695,49 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
insertExtraText(); insertExtraText();
updateRegisteredChats(); updateRegisteredChats();
Fragment currentFragment = chatViewerAdapter.getCurrentFragment();
if (isChatSelected) {
if (!(currentFragment instanceof ChatViewerFragment)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Debug message")
.setMessage("Recent chats selected, but contact chat expected. Reselecting...")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selectPage(actionWithAccount, actionWithUser, false);
}
});
builder.create().show();
} else if (!((ChatViewerFragment) currentFragment).isEqual(actionWithAccount, actionWithUser)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Debug message")
.setMessage("Wrong contact chat selected. Reselecting...")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selectPage(actionWithAccount, actionWithUser, false);
}
});
builder.create().show();
}
} else {
if (!(currentFragment instanceof RecentChatFragment)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Debug message")
.setMessage("Contact chat selected, but recent chats expected. Reselecting...")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selectPage(null, null, false);
}
});
builder.create().show();
}
}
} }
private void insertExtraText() { private void insertExtraText() {
...@@ -710,15 +761,24 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener ...@@ -710,15 +761,24 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
} }
@Override @Override
public void onRecentChatSelected(AbstractChat chat) { public void onChatSelected(AbstractChat chat) {
selectPage(chat.getAccount(), chat.getUser(), true); selectPage(chat.getAccount(), chat.getUser(), true);
} }
public void selectRecentChatsPage() { public void selectRecentChatsPage() {
viewPager.setCurrentItem(chatViewerAdapter.getRecentChatsPosition(), true); selectPage(null, null, false);
} }
public ChatViewerAdapter getChatViewerAdapter() { public ChatViewerAdapter getChatViewerAdapter() {
return chatViewerAdapter; return chatViewerAdapter;
} }
public static void hideKeyboard(Activity activity) {
// Check if no view has focus:
View view = activity.getCurrentFocus();
if (view != null) {
InputMethodManager inputManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
} }
...@@ -14,16 +14,14 @@ import android.view.MenuInflater; ...@@ -14,16 +14,14 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView;
import com.xabber.android.data.LogManager;
import com.xabber.android.data.SettingsManager; import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.account.AccountManager;
import com.xabber.android.data.extension.cs.ChatStateManager; import com.xabber.android.data.extension.cs.ChatStateManager;
import com.xabber.android.data.message.MessageItem; import com.xabber.android.data.message.MessageItem;
import com.xabber.android.data.message.MessageManager; import com.xabber.android.data.message.MessageManager;
...@@ -31,12 +29,11 @@ import com.xabber.android.data.message.chat.ChatManager; ...@@ -31,12 +29,11 @@ import com.xabber.android.data.message.chat.ChatManager;
import com.xabber.android.ui.adapter.ChatMessageAdapter; import com.xabber.android.ui.adapter.ChatMessageAdapter;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
public class ChatViewerFragment extends Fragment { public class ChatViewerFragment extends Fragment implements AdapterView.OnItemClickListener {
public static final String ARGUMENT_ACCOUNT = "ARGUMENT_ACCOUNT"; public static final String ARGUMENT_ACCOUNT = "ARGUMENT_ACCOUNT";
public static final String ARGUMENT_USER = "ARGUMENT_USER"; public static final String ARGUMENT_USER = "ARGUMENT_USER";
private TextView pageView;
private EditText inputView; private EditText inputView;
private ListView listView; private ListView listView;
private ChatMessageAdapter chatMessageAdapter; private ChatMessageAdapter chatMessageAdapter;
...@@ -46,6 +43,9 @@ public class ChatViewerFragment extends Fragment { ...@@ -46,6 +43,9 @@ public class ChatViewerFragment extends Fragment {
private String account; private String account;
private String user; private String user;
boolean isInputEmpty = true;
private ImageButton sendButton;
public static ChatViewerFragment newInstance(String account, String user) { public static ChatViewerFragment newInstance(String account, String user) {
ChatViewerFragment fragment = new ChatViewerFragment(); ChatViewerFragment fragment = new ChatViewerFragment();
...@@ -69,39 +69,21 @@ public class ChatViewerFragment extends Fragment { ...@@ -69,39 +69,21 @@ public class ChatViewerFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState); super.onCreateView(inflater, container, savedInstanceState);
/*
Animation used to hide pages.
*/
Animation pagesHideAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.chat_page_out);
pagesHideAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
pageView.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
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()); sendButton = (ImageButton) view.findViewById(R.id.button_send_message);
chatMessageAdapter.setChat(account, user); sendButton.setImageResource(R.drawable.ic_button_send_inactive_24dp);
chatMessageAdapter = new ChatMessageAdapter(getActivity(), account, user);
listView = (ListView) view.findViewById(android.R.id.list); listView = (ListView) view.findViewById(android.R.id.list);
listView.setAdapter(chatMessageAdapter); listView.setAdapter(chatMessageAdapter);
listView.setOnItemClickListener(this);
pageView = (TextView) view.findViewById(R.id.chat_page);
inputView = (EditText) view.findViewById(R.id.chat_input); inputView = (EditText) view.findViewById(R.id.chat_input);
view.findViewById(R.id.chat_send).setOnClickListener( view.findViewById(R.id.button_send_message).setOnClickListener(
new View.OnClickListener() { new View.OnClickListener() {
@Override @Override
...@@ -112,32 +94,27 @@ public class ChatViewerFragment extends Fragment { ...@@ -112,32 +94,27 @@ public class ChatViewerFragment extends Fragment {
}); });
inputView.setOnKeyListener(new View.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) {
if (event.getAction() == KeyEvent.ACTION_DOWN if (SettingsManager.chatsSendByEnter()
&& keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN
&& SettingsManager.chatsSendByEnter()) { && keyCode == KeyEvent.KEYCODE_ENTER) {
sendMessage(); sendMessage();
return true; return true;
} }
return false; return false;
} }
}); });
inputView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
inputView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override @Override
public boolean onEditorAction(TextView view, int actionId, public void onFocusChange(View v, boolean hasFocus) {
KeyEvent event) { if (!hasFocus) {
if (actionId == EditorInfo.IME_ACTION_SEND) { ChatStateManager.getInstance().onPaused(account, user);
sendMessage();
return true;
} }
return false;
} }
}); });
inputView.addTextChangedListener(new TextWatcher() { inputView.addTextChangedListener(new TextWatcher() {
@Override @Override
...@@ -150,35 +127,46 @@ public class ChatViewerFragment extends Fragment { ...@@ -150,35 +127,46 @@ public class ChatViewerFragment extends Fragment {
@Override @Override
public void afterTextChanged(Editable text) { public void afterTextChanged(Editable text) {
if (skipOnTextChanges) LogManager.i(this, "afterTextChanged");
return;
String account = chatMessageAdapter.getAccount(); setSendButtonColor();
String user = chatMessageAdapter.getUser();
if (!skipOnTextChanges) {
ChatStateManager.getInstance().onComposing(account, user, text); ChatStateManager.getInstance().onComposing(account, user, text);
} }
}
}); });
updateView(); updateChat();
return view;
chatMessageAdapter.onChange(); }
return view; private void setSendButtonColor() {
boolean empty = inputView.getText().toString().isEmpty();
if (empty != isInputEmpty) {
isInputEmpty = empty;
if (isInputEmpty) {
sendButton.setImageResource(R.drawable.ic_button_send_inactive_24dp);
} else {
sendButton.setImageResource(R.drawable.ic_button_send);
sendButton.setImageLevel(AccountManager.getInstance().getColorLevel(account));
}
}
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
((ChatViewer)getActivity()).registerChat(this); ((ChatViewer)getActivity()).registerChat(this);
registerForContextMenu(listView);
restoreInputState(); restoreInputState();
} }
private void restoreInputState() { public void restoreInputState() {
skipOnTextChanges = true; skipOnTextChanges = true;
inputView.setText(ChatManager.getInstance().getTypedMessage(account, user)); inputView.setText(ChatManager.getInstance().getTypedMessage(account, user));
...@@ -186,17 +174,17 @@ public class ChatViewerFragment extends Fragment { ...@@ -186,17 +174,17 @@ public class ChatViewerFragment extends Fragment {
ChatManager.getInstance().getSelectionEnd(account, user)); ChatManager.getInstance().getSelectionEnd(account, user));
skipOnTextChanges = false; skipOnTextChanges = false;
if (!inputView.getText().toString().isEmpty()) {
inputView.requestFocus();
}
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
saveInputState(); saveInputState();
((ChatViewer)getActivity()).unregisterChat(this); ((ChatViewer)getActivity()).unregisterChat(this);
unregisterForContextMenu(listView);
} }
public void saveInputState() { public void saveInputState() {
...@@ -205,25 +193,13 @@ public class ChatViewerFragment extends Fragment { ...@@ -205,25 +193,13 @@ public class ChatViewerFragment extends Fragment {
} }
private void sendMessage() { private void sendMessage() {
String text = inputView.getText().toString(); String text = inputView.getText().toString().trim();
int start = 0;
int end = text.length();
while (start < end && (text.charAt(start) == ' ' || text.charAt(start) == '\n')) { if (text.isEmpty()) {
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; return;
} }
skipOnTextChanges = true; clearInputText();
inputView.getText().clear();
skipOnTextChanges = false;
sendMessage(text); sendMessage(text);
...@@ -232,8 +208,7 @@ public class ChatViewerFragment extends Fragment { ...@@ -232,8 +208,7 @@ public class ChatViewerFragment extends Fragment {
if (SettingsManager.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.always if (SettingsManager.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.always
|| (getActivity().getResources().getBoolean(R.bool.landscape) || (getActivity().getResources().getBoolean(R.bool.landscape)
&& SettingsManager.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.landscape)) { && SettingsManager.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.landscape)) {
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); ChatViewer.hideKeyboard(getActivity());
imm.hideSoftInputFromWindow(inputView.getWindowToken(), 0);
} }
} }
...@@ -242,25 +217,27 @@ public class ChatViewerFragment extends Fragment { ...@@ -242,25 +217,27 @@ public class ChatViewerFragment extends Fragment {
updateChat(); updateChat();
} }
private void updateView() {
chatMessageAdapter.onChange();
}
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View view, public void onCreateContextMenu(ContextMenu menu, View view,
ContextMenu.ContextMenuInfo menuInfo) { ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo); super.onCreateContextMenu(menu, view, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
final MessageItem message = (MessageItem) listView.getAdapter().getItem(info.position); ChatMessageAdapter chatMessageAdapter = (ChatMessageAdapter) listView.getAdapter();
int itemViewType = chatMessageAdapter.getItemViewType(info.position);
if (itemViewType == ChatMessageAdapter.VIEW_TYPE_INCOMING_MESSAGE
|| itemViewType == ChatMessageAdapter.VIEW_TYPE_OUTGOING_MESSAGE) {
MenuInflater inflater = getActivity().getMenuInflater(); MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.chat_context_menu, menu); inflater.inflate(R.menu.chat_context_menu, menu);
if (message.isError()) { if (((MessageItem) chatMessageAdapter.getItem(info.position)).isError()) {
menu.findItem(R.id.action_message_repeat).setVisible(true); menu.findItem(R.id.action_message_repeat).setVisible(true);
} }
} }
}
@Override @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(MenuItem item) {
...@@ -278,7 +255,7 @@ public class ChatViewerFragment extends Fragment { ...@@ -278,7 +255,7 @@ public class ChatViewerFragment extends Fragment {
return true; return true;
case R.id.action_message_quote: case R.id.action_message_quote:
insertText("> " + message.getText() + "\n"); setInputText("> " + message.getText() + "\n");
return true; return true;
case R.id.action_message_remove: case R.id.action_message_remove:
...@@ -291,36 +268,19 @@ public class ChatViewerFragment extends Fragment { ...@@ -291,36 +268,19 @@ public class ChatViewerFragment extends Fragment {
} }
} }
/**
* Insert additional text to the input.
*
* @param additional
*/
private void insertText(String additional) {
String source = inputView.getText().toString();
int selection = inputView.getSelectionEnd();
if (selection == -1)
selection = source.length();
else if (selection > source.length())
selection = source.length();
String before = source.substring(0, selection);
String after = source.substring(selection);
if (before.length() > 0 && !before.endsWith("\n"))
additional = "\n" + additional;
inputView.setText(before + additional + after);
inputView.setSelection(selection + additional.length());
}
public void updateChat() { public void updateChat() {
updateView(); chatMessageAdapter.onChange();
} }
public boolean isEqual(String account, String user) { public boolean isEqual(String account, String user) {
return this.account.equals(account) && this.user.equals(user); return this.account.equals(account) && this.user.equals(user);
} }
public void setInputText(String text) { public void setInputText(String additional) {
insertText(text); skipOnTextChanges = true;
inputView.setText(additional);
inputView.setSelection(additional.length());
skipOnTextChanges = false;
} }
public String getAccount() { public String getAccount() {
...@@ -331,8 +291,10 @@ public class ChatViewerFragment extends Fragment { ...@@ -331,8 +291,10 @@ public class ChatViewerFragment extends Fragment {
return user; return user;
} }
public void clearInputView() { public void clearInputText() {
skipOnTextChanges = true;
inputView.getText().clear(); inputView.getText().clear();
skipOnTextChanges = false;
} }
public void scrollChat() { public void scrollChat() {
...@@ -341,4 +303,11 @@ public class ChatViewerFragment extends Fragment { ...@@ -341,4 +303,11 @@ public class ChatViewerFragment extends Fragment {
listView.setSelection(size - 1); listView.setSelection(size - 1);
} }
} }
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
registerForContextMenu(listView);
listView.showContextMenuForChild(view);
unregisterForContextMenu(listView);
}
} }
...@@ -92,12 +92,12 @@ public class RecentChatFragment extends ListFragment { ...@@ -92,12 +92,12 @@ public class RecentChatFragment extends ListFragment {
super.onListItemClick(l, v, position, id); super.onListItemClick(l, v, position, id);
if (null != listener) { if (null != listener) {
listener.onRecentChatSelected((AbstractChat) getListAdapter().getItem(position)); listener.onChatSelected((AbstractChat) getListAdapter().getItem(position));
} }
} }
public interface RecentChatFragmentInteractionListener { public interface RecentChatFragmentInteractionListener {
public void onRecentChatSelected(AbstractChat chat); public void onChatSelected(AbstractChat chat);
} }
public void updateChats(List<AbstractChat> chats) { public void updateChats(List<AbstractChat> chats) {
......
...@@ -32,7 +32,6 @@ import android.widget.TextView; ...@@ -32,7 +32,6 @@ import android.widget.TextView;
import com.xabber.android.data.SettingsManager; import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.roster.AbstractContact; import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
/** /**
...@@ -46,7 +45,6 @@ public abstract class BaseContactInflater { ...@@ -46,7 +45,6 @@ public abstract class BaseContactInflater {
final LayoutInflater layoutInflater; final LayoutInflater layoutInflater;
final AbstractAvatarInflaterHelper avatarInflaterHelper;
/** /**
* Repeated shadow for drawable. * Repeated shadow for drawable.
...@@ -62,7 +60,6 @@ public abstract class BaseContactInflater { ...@@ -62,7 +60,6 @@ public abstract class BaseContactInflater {
public BaseContactInflater(Activity activity) { public BaseContactInflater(Activity activity) {
this.activity = activity; this.activity = activity;
layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.shadow); Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.shadow);
shadowDrawable = new BitmapDrawable(activity.getResources(), bitmap); shadowDrawable = new BitmapDrawable(activity.getResources(), bitmap);
...@@ -128,7 +125,6 @@ public abstract class BaseContactInflater { ...@@ -128,7 +125,6 @@ public abstract class BaseContactInflater {
if (SettingsManager.contactsShowAvatars()) { if (SettingsManager.contactsShowAvatars()) {
viewHolder.avatar.setVisibility(View.VISIBLE); viewHolder.avatar.setVisibility(View.VISIBLE);
viewHolder.avatar.setImageDrawable(abstractContact.getAvatarForContactList()); viewHolder.avatar.setImageDrawable(abstractContact.getAvatarForContactList());
avatarInflaterHelper.updateAvatar(viewHolder.avatar, abstractContact);
((RelativeLayout.LayoutParams) viewHolder.panel.getLayoutParams()) ((RelativeLayout.LayoutParams) viewHolder.panel.getLayoutParams())
.addRule(RelativeLayout.RIGHT_OF, R.id.avatar); .addRule(RelativeLayout.RIGHT_OF, R.id.avatar);
} else { } else {
......
...@@ -13,7 +13,6 @@ import com.xabber.android.data.message.MessageManager; ...@@ -13,7 +13,6 @@ 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.helper.AbstractAvatarInflaterHelper;
import com.xabber.androiddev.R; import com.xabber.androiddev.R;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -23,15 +22,12 @@ public class ChatListAdapter extends BaseAdapter { ...@@ -23,15 +22,12 @@ public class ChatListAdapter extends BaseAdapter {
private List<AbstractChat> chats; private List<AbstractChat> chats;
private final AbstractAvatarInflaterHelper avatarInflaterHelper;
private final Context context; private final Context context;
public ChatListAdapter(Context context) { public ChatListAdapter(Context context) {
this.context = context; this.context = context;
chats = new ArrayList<>(); chats = new ArrayList<>();
avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
} }
public void updateChats(List<AbstractChat> chats) { public void updateChats(List<AbstractChat> chats) {
...@@ -73,7 +69,6 @@ public class ChatListAdapter extends BaseAdapter { ...@@ -73,7 +69,6 @@ public class ChatListAdapter extends BaseAdapter {
final ImageView avatarView = (ImageView) view.findViewById(R.id.avatar); final ImageView avatarView = (ImageView) view.findViewById(R.id.avatar);
avatarView.setImageDrawable(abstractContact.getAvatar()); avatarView.setImageDrawable(abstractContact.getAvatar());
avatarInflaterHelper.updateAvatar(avatarView, abstractContact);
final TextView textView = (TextView) view.findViewById(R.id.text); final TextView textView = (TextView) view.findViewById(R.id.text);
......
...@@ -17,15 +17,12 @@ package com.xabber.android.ui.adapter; ...@@ -17,15 +17,12 @@ package com.xabber.android.ui.adapter;
import android.app.Activity; import android.app.Activity;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.text.style.CharacterStyle; import android.text.style.CharacterStyle;
import android.text.style.ImageSpan;
import android.text.style.TextAppearanceSpan; import android.text.style.TextAppearanceSpan;
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.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import com.xabber.android.data.SettingsManager; import com.xabber.android.data.SettingsManager;
...@@ -56,9 +53,13 @@ import java.util.List; ...@@ -56,9 +53,13 @@ import java.util.List;
*/ */
public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter { public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter {
private static final int TYPE_MESSAGE = 0; private static final int VIEW_TYPE_COUNT = 5;
private static final int TYPE_HINT = 1;
private static final int TYPE_EMPTY = 2; private static final int VIEW_TYPE_EMPTY = 0;
private static final int VIEW_TYPE_HINT = 1;
public static final int VIEW_TYPE_INCOMING_MESSAGE = 2;
public static final int VIEW_TYPE_OUTGOING_MESSAGE = 3;
private static final int VIEW_TYPE_ACTION_MESSAGE = 4;
private final Activity activity; private final Activity activity;
private String account; private String account;
...@@ -81,21 +82,22 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter ...@@ -81,21 +82,22 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
*/ */
private String hint; private String hint;
public ChatMessageAdapter(Activity activity) { public ChatMessageAdapter(Activity activity, String account, String user) {
this.activity = activity; this.activity = activity;
messages = Collections.emptyList(); messages = Collections.emptyList();
account = null; this.account = account;
user = null; this.user = user;
isMUC = MUCManager.getInstance().hasRoom(account, user);
hint = null; hint = null;
appearanceStyle = SettingsManager.chatsAppearanceStyle(); appearanceStyle = SettingsManager.chatsAppearanceStyle();
ChatsDivide chatsDivide = SettingsManager.chatsDivide(); ChatsDivide chatsDivide = SettingsManager.chatsDivide();
if (chatsDivide == ChatsDivide.always if (chatsDivide == ChatsDivide.always || (chatsDivide == ChatsDivide.portial
|| (chatsDivide == ChatsDivide.portial && !activity && !activity.getResources().getBoolean(R.bool.landscape))) {
.getResources().getBoolean(R.bool.landscape)))
divider = "\n"; divider = "\n";
else } else {
divider = " "; divider = " ";
} }
}
@Override @Override
public int getCount() { public int getCount() {
...@@ -104,11 +106,12 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter ...@@ -104,11 +106,12 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
@Override @Override
public Object getItem(int position) { public Object getItem(int position) {
if (position < messages.size()) if (position < messages.size()) {
return messages.get(position); return messages.get(position);
else } else {
return null; return null;
} }
}
@Override @Override
public long getItemId(int position) { public long getItemId(int position) {
...@@ -117,194 +120,189 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter ...@@ -117,194 +120,189 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
@Override @Override
public int getViewTypeCount() { public int getViewTypeCount() {
return 3; return VIEW_TYPE_COUNT;
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (position < messages.size()) if (position >= messages.size()) {
return TYPE_MESSAGE; return hint == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_HINT;
else
return hint == null ? TYPE_EMPTY : TYPE_HINT;
} }
private void append(SpannableStringBuilder builder, CharSequence text, MessageItem messageItem = (MessageItem) getItem(position);
CharacterStyle span) { if (messageItem.getAction() != null) {
int start = builder.length(); return VIEW_TYPE_ACTION_MESSAGE;
builder.append(text); }
builder.setSpan(span, start, start + text.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return messageItem.isIncoming() ? VIEW_TYPE_INCOMING_MESSAGE : VIEW_TYPE_OUTGOING_MESSAGE;
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
final int type = getItemViewType(position); final int type = getItemViewType(position);
final View view;
if (type == VIEW_TYPE_EMPTY) {
if (convertView == null) { if (convertView == null) {
final int resource; return activity.getLayoutInflater().inflate(R.layout.chat_viewer_empty, parent, false);
if (type == TYPE_MESSAGE) } else {
resource = R.layout.chat_viewer_message; return convertView;
else if (type == TYPE_HINT) }
resource = R.layout.chat_viewer_info; }
else if (type == TYPE_EMPTY)
resource = R.layout.chat_viewer_empty; if (type == VIEW_TYPE_HINT) {
else View view = convertView;
throw new IllegalStateException(); if (convertView == null) {
view = activity.getLayoutInflater() view = activity.getLayoutInflater().inflate(R.layout.chat_viewer_info, parent, false);
.inflate(resource, parent, false); }
if (type == TYPE_MESSAGE)
((TextView) view.findViewById(R.id.text)).setTextAppearance(
activity, appearanceStyle);
} else
view = convertView;
if (type == TYPE_EMPTY)
return view;
if (type == TYPE_HINT) {
TextView textView = ((TextView) view.findViewById(R.id.info)); TextView textView = ((TextView) view.findViewById(R.id.info));
textView.setText(hint); textView.setText(hint);
textView.setTextAppearance(activity, R.style.ChatInfo_Warning); textView.setTextAppearance(activity, R.style.ChatInfo_Warning);
return view; return view;
} }
final MessageItem messageItem = (MessageItem) getItem(position); MessageItem messageItem = (MessageItem) getItem(position);
final String name;
final String account = messageItem.getChat().getAccount(); if (type == VIEW_TYPE_ACTION_MESSAGE) {
final String user = messageItem.getChat().getUser(); View view = convertView;
final String resource = messageItem.getResource(); if (convertView == null) {
final boolean incoming = messageItem.isIncoming(); view = activity.getLayoutInflater().inflate(R.layout.chat_viewer_action_message, parent, false);
if (isMUC) {
name = resource;
} else {
if (incoming)
name = RosterManager.getInstance().getName(account, user);
else
name = AccountManager.getInstance().getNickName(account);
} }
if (incoming) {
if (view.getBackground() == null) ChatAction action = messageItem.getAction();
view.setBackgroundResource(R.drawable.chat_bg);
view.getBackground().setLevel( Spannable text = Emoticons.newSpannable(
AccountManager.getInstance().getColorLevel(account)); action.getText(activity, messageItem.getResource(), messageItem.getSpannable().toString()));
Emoticons.getSmiledText(activity.getApplication(), text);
String time = StringUtils.getSmartTimeText(activity, messageItem.getTimestamp());
((TextView)view.findViewById(R.id.action_message_text)).setText(time + ": " + text);
return view;
}
View view = convertView;
if (convertView == null) {
final int layoutId;
if (type == VIEW_TYPE_INCOMING_MESSAGE) {
layoutId = R.layout.chat_viewer_incoming_message;
} else if (type == VIEW_TYPE_OUTGOING_MESSAGE) {
layoutId = R.layout.chat_viewer_outgoing_message;
} else { } else {
view.setBackgroundDrawable(null); throw new IllegalStateException();
} }
Spannable text = messageItem.getSpannable();
TextView textView = (TextView) view.findViewById(R.id.text); view = activity.getLayoutInflater().inflate(layoutId, parent, false);
ImageView avatarView = (ImageView) view.findViewById(R.id.avatar); }
ChatAction action = messageItem.getAction();
String time = StringUtils.getSmartTimeText(messageItem.getTimestamp()); setUpMessageView(messageItem, view);
return view;
}
private void setUpMessageView(MessageItem messageItem, View view) {
final boolean incoming = messageItem.isIncoming();
SpannableStringBuilder builder = new SpannableStringBuilder(); SpannableStringBuilder builder = new SpannableStringBuilder();
if (action == null) { final String resource = messageItem.getResource();
int messageResource = R.drawable.ic_message_delivered;
if (!incoming) { if (!incoming) {
if (messageItem.isError()) setStatusIcon(messageItem, view);
messageResource = R.drawable.ic_message_has_error; }
else if (!messageItem.isSent())
messageResource = R.drawable.ic_message_not_sent; if (isMUC) {
else if (!messageItem.isDelivered()) append(builder, resource, new TextAppearanceSpan(activity, R.style.ChatHeader_Time));
messageResource = R.drawable.ic_message_not_delivered; append(builder, divider, new TextAppearanceSpan(activity, R.style.ChatHeader));
}
append(builder, " ", new ImageSpan(activity, messageResource));
append(builder, " ", new TextAppearanceSpan(activity,
R.style.ChatHeader));
append(builder, time, new TextAppearanceSpan(activity,
R.style.ChatHeader_Time));
append(builder, " ", new TextAppearanceSpan(activity,
R.style.ChatHeader));
append(builder, name, new TextAppearanceSpan(activity,
R.style.ChatHeader_Name));
append(builder, divider, new TextAppearanceSpan(activity,
R.style.ChatHeader));
Date timeStamp = messageItem.getDelayTimestamp();
if (timeStamp != null) {
String delay = activity.getString(
incoming ? R.string.chat_delay : R.string.chat_typed,
StringUtils.getSmartTimeText(timeStamp));
append(builder, delay, new TextAppearanceSpan(activity,
R.style.ChatHeader_Delay));
append(builder, divider, new TextAppearanceSpan(activity,
R.style.ChatHeader));
} }
Date delayTimestamp = messageItem.getDelayTimestamp();
if (messageItem.isUnencypted()) { if (messageItem.isUnencypted()) {
append(builder, append(builder, activity.getString(R.string.otr_unencrypted_message),
activity.getString(R.string.otr_unencrypted_message), new TextAppearanceSpan(activity, R.style.ChatHeader_Delay));
new TextAppearanceSpan(activity, append(builder, divider, new TextAppearanceSpan(activity, R.style.ChatHeader));
R.style.ChatHeader_Delay));
append(builder, divider, new TextAppearanceSpan(activity,
R.style.ChatHeader));
} }
Spannable text = messageItem.getSpannable();
Emoticons.getSmiledText(activity.getApplication(), text); Emoticons.getSmiledText(activity.getApplication(), text);
if (messageItem.getTag() == null) if (messageItem.getTag() == null) {
builder.append(text); builder.append(text);
else
append(builder, text, new TextAppearanceSpan(activity,
R.style.ChatRead));
} else { } else {
append(builder, time, new TextAppearanceSpan(activity, append(builder, text, new TextAppearanceSpan(activity, R.style.ChatRead));
R.style.ChatHeader_Time));
append(builder, " ", new TextAppearanceSpan(activity,
R.style.ChatHeader));
text = Emoticons.newSpannable(action.getText(activity, name,
text.toString()));
Emoticons.getSmiledText(activity.getApplication(), text);
append(builder, text, new TextAppearanceSpan(activity,
R.style.ChatHeader_Delay));
} }
TextView textView = (TextView) view.findViewById(R.id.message_text);
textView.setTextAppearance(activity, appearanceStyle);
textView.setText(builder); textView.setText(builder);
textView.setMovementMethod(LinkMovementMethod.getInstance()); textView.getBackground().setLevel(AccountManager.getInstance().getColorLevel(account));
String time = StringUtils.getSmartTimeText(activity, messageItem.getTimestamp());
if (delayTimestamp != null) {
String delay = activity.getString(incoming ? R.string.chat_delay : R.string.chat_typed,
StringUtils.getSmartTimeText(activity, delayTimestamp));
time += " (" + delay + ")";
}
((TextView)view.findViewById(R.id.message_time)).setText(time);
if (incoming) {
setUpAvatar(messageItem, view);
}
}
private void setStatusIcon(MessageItem messageItem, View view) {
ImageView messageStatusIcon = (ImageView) view.findViewById(R.id.message_status_icon);
messageStatusIcon.setVisibility(View.VISIBLE);
int messageIcon = R.drawable.ic_message_delivered_18dp;
if (messageItem.isError()) {
messageIcon = R.drawable.ic_message_has_error_18dp;
} else if (!messageItem.isSent()) {
messageIcon = R.drawable.ic_message_not_sent_18dp;
} else if (!messageItem.isDelivered()) {
messageStatusIcon.setVisibility(View.INVISIBLE);
}
messageStatusIcon.setImageResource(messageIcon);
}
private void append(SpannableStringBuilder builder, CharSequence text, CharacterStyle span) {
int start = builder.length();
builder.append(text);
builder.setSpan(span, start, start + text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
private void setUpAvatar(MessageItem messageItem, View view) {
ImageView avatarView = (ImageView) view.findViewById(R.id.avatar);
if (SettingsManager.chatsShowAvatars()) { if (SettingsManager.chatsShowAvatars()) {
final String account = messageItem.getChat().getAccount();
final String user = messageItem.getChat().getUser();
final String resource = messageItem.getResource();
avatarView.setVisibility(View.VISIBLE); avatarView.setVisibility(View.VISIBLE);
if (!incoming if ((isMUC && MUCManager.getInstance().getNickname(account, user).equalsIgnoreCase(resource))) {
|| (isMUC && MUCManager.getInstance() avatarView.setImageDrawable(AvatarManager.getInstance().getAccountAvatar(account));
.getNickname(account, user)
.equalsIgnoreCase(resource))) {
avatarView.setImageDrawable(AvatarManager.getInstance()
.getAccountAvatar(account));
} else { } else {
if (isMUC) { if (isMUC) {
if ("".equals(resource)) { if ("".equals(resource)) {
avatarView.setImageDrawable(AvatarManager.getInstance() avatarView.setImageDrawable(AvatarManager.getInstance().getRoomAvatar(user));
.getRoomAvatar(user));
} else { } else {
avatarView.setImageDrawable(AvatarManager.getInstance() avatarView.setImageDrawable(AvatarManager.getInstance().getOccupantAvatar(user + "/" + resource));
.getOccupantAvatar(user + "/" + resource));
} }
} else { } else {
avatarView.setImageDrawable(AvatarManager.getInstance() avatarView.setImageDrawable(AvatarManager.getInstance().getUserAvatar(user));
.getUserAvatar(user));
} }
} }
((RelativeLayout.LayoutParams) textView.getLayoutParams()).addRule(
RelativeLayout.RIGHT_OF, R.id.avatar);
} else { } else {
avatarView.setVisibility(View.GONE); avatarView.setVisibility(View.GONE);
((RelativeLayout.LayoutParams) textView.getLayoutParams()).addRule(
RelativeLayout.RIGHT_OF, 0);
}
return view;
}
public String getAccount() {
return account;
} }
public String getUser() {
return user;
}
/**
* Changes managed chat.
*
* @param account
* @param user
*/
public void setChat(String account, String user) {
this.account = account;
this.user = user;
this.isMUC = MUCManager.getInstance().hasRoom(account, user);
onChange();
} }
@Override @Override
...@@ -318,40 +316,22 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter ...@@ -318,40 +316,22 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
* @return New hint. * @return New hint.
*/ */
private String getHint() { private String getHint() {
AccountItem accountItem = AccountManager.getInstance().getAccount( AccountItem accountItem = AccountManager.getInstance().getAccount(account);
account); boolean online = accountItem != null && accountItem.getState().isConnected();
boolean online; final AbstractContact abstractContact = RosterManager.getInstance().getBestContact(account, user);
if (accountItem == null)
online = false;
else
online = accountItem.getState().isConnected();
final AbstractContact abstractContact = RosterManager.getInstance()
.getBestContact(account, user);
if (!online) { if (!online) {
if (abstractContact instanceof RoomContact) if (abstractContact instanceof RoomContact) {
return activity.getString(R.string.muc_is_unavailable); return activity.getString(R.string.muc_is_unavailable);
else } else {
return activity.getString(R.string.account_is_offline); return activity.getString(R.string.account_is_offline);
}
} else if (!abstractContact.getStatusMode().isOnline()) { } else if (!abstractContact.getStatusMode().isOnline()) {
if (abstractContact instanceof RoomContact) if (abstractContact instanceof RoomContact) {
return activity.getString(R.string.muc_is_unavailable); return activity.getString(R.string.muc_is_unavailable);
else } else {
return activity.getString(R.string.contact_is_offline, return activity.getString(R.string.contact_is_offline, abstractContact.getName());
abstractContact.getName());
} }
return null;
} }
return null;
/**
* Contact information has been changed. Renews hint and updates data if
* necessary.
*/
public void updateInfo() {
String info = getHint();
if (this.hint == info || (this.hint != null && this.hint.equals(info)))
return;
this.hint = info;
notifyDataSetChanged();
} }
} }
...@@ -32,6 +32,7 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter { ...@@ -32,6 +32,7 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter {
private static final int TOTAL_COUNT = 200; private static final int TOTAL_COUNT = 200;
private static final int OFFSET = TOTAL_COUNT / 2; private static final int OFFSET = TOTAL_COUNT / 2;
private Fragment currentFragment;
public ChatViewerAdapter(FragmentManager fragmentManager, String account, String user, FinishUpdateListener finishUpdateListener) { public ChatViewerAdapter(FragmentManager fragmentManager, String account, String user, FinishUpdateListener finishUpdateListener) {
super(fragmentManager); super(fragmentManager);
...@@ -133,10 +134,6 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter { ...@@ -133,10 +134,6 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter {
return realPosition + OFFSET; return realPosition + OFFSET;
} }
public int getRecentChatsPosition() {
return OFFSET;
}
public AbstractChat getChatByPageNumber(int virtualPosition) { public AbstractChat getChatByPageNumber(int virtualPosition) {
int realPosition = getRealPagePosition(virtualPosition); int realPosition = getRealPagePosition(virtualPosition);
...@@ -182,4 +179,19 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter { ...@@ -182,4 +179,19 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter {
public int getItemPosition(Object object) { public int getItemPosition(Object object) {
return POSITION_NONE; return POSITION_NONE;
} }
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (currentFragment instanceof ChatViewerFragment) {
((ChatViewerFragment)currentFragment).saveInputState();
}
currentFragment = (Fragment) object;
}
public Fragment getCurrentFragment() {
return currentFragment;
}
} }
\ No newline at end of file
/**
* 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.helper;
import android.widget.ImageView;
import com.xabber.android.data.Application;
import com.xabber.android.data.roster.AbstractContact;
/**
* Helper class to update avatar's contact item.
*
* @author alexander.ivanov
*/
public abstract class AbstractAvatarInflaterHelper {
/**
* Update avatar image view.
*
* @param avatar
* @param abstractContact
*/
public abstract void updateAvatar(ImageView avatar,
AbstractContact abstractContact);
/**
* @return New instance depend on whether new system contact list is
* supported.
*/
public static AbstractAvatarInflaterHelper createAbstractContactInflaterHelper() {
if (Application.getInstance().isContactsSupported())
return new AvatarInflaterHelper();
else
return new DummyAvatarInflaterHelper();
}
}
/**
* 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.helper;
import android.annotation.TargetApi;
import android.provider.ContactsContract;
import android.widget.ImageView;
import android.widget.QuickContactBadge;
import com.xabber.android.data.roster.AbstractContact;
/**
* Helper class to add quick contact badge to the inflated contact item.
*
* @author alexander.ivanov
*/
@TargetApi(5)
public class AvatarInflaterHelper extends AbstractAvatarInflaterHelper {
@Override
public void updateAvatar(ImageView avatar, AbstractContact abstractContact) {
QuickContactBadge badge = (QuickContactBadge) avatar;
badge.assignContactFromEmail(abstractContact.getUser(), true);
badge.setMode(ContactsContract.QuickContact.MODE_SMALL);
}
}
package com.xabber.android.ui.helper; package com.xabber.android.ui.helper;
import android.content.res.TypedArray;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Build; import android.os.Build;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
...@@ -30,6 +31,8 @@ public class ContactTitleActionBarInflater { ...@@ -30,6 +31,8 @@ public class ContactTitleActionBarInflater {
private Animation shakeAnimation = null; private Animation shakeAnimation = null;
private ColorDrawable defaultActionBarBackground;
public ContactTitleActionBarInflater(ActionBarActivity activity) { public ContactTitleActionBarInflater(ActionBarActivity activity) {
this.activity = activity; this.activity = activity;
} }
...@@ -39,10 +42,9 @@ public class ContactTitleActionBarInflater { ...@@ -39,10 +42,9 @@ public class ContactTitleActionBarInflater {
accountStatusBarColors = activity.getResources().getIntArray(R.array.account_status_bar); accountStatusBarColors = activity.getResources().getIntArray(R.array.account_status_bar);
ActionBar actionBar = activity.getSupportActionBar(); ActionBar actionBar = activity.getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false); actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowCustomEnabled(true);
actionBarView = LayoutInflater.from(activity).inflate(R.layout.contact_title, null); actionBarView = LayoutInflater.from(activity).inflate(R.layout.contact_title, null);
...@@ -55,9 +57,15 @@ public class ContactTitleActionBarInflater { ...@@ -55,9 +57,15 @@ public class ContactTitleActionBarInflater {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
defaultStatusBarColor = window.getStatusBarColor(); defaultStatusBarColor = window.getStatusBarColor();
} }
TypedArray a = activity.getTheme().obtainStyledAttributes(R.style.Theme, new int[] {R.attr.colorPrimary});
int attributeResourceId = a.getResourceId(0, 0);
defaultActionBarBackground = new ColorDrawable(activity.getResources().getColor(attributeResourceId));
} }
public void update(AbstractContact abstractContact) { public void update(AbstractContact abstractContact) {
activity.getSupportActionBar().setDisplayShowCustomEnabled(true);
activity.getSupportActionBar().setDisplayShowTitleEnabled(false); activity.getSupportActionBar().setDisplayShowTitleEnabled(false);
actionBarView.setVisibility(View.VISIBLE); actionBarView.setVisibility(View.VISIBLE);
...@@ -71,13 +79,15 @@ public class ContactTitleActionBarInflater { ...@@ -71,13 +79,15 @@ public class ContactTitleActionBarInflater {
} }
public void restoreDefaultTitleView(String title) { public void restoreDefaultTitleView(String title) {
activity.getSupportActionBar().setDisplayShowCustomEnabled(false);
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
actionBarView.setVisibility(View.GONE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.setStatusBarColor(defaultStatusBarColor); window.setStatusBarColor(defaultStatusBarColor);
} }
activity.getSupportActionBar().setBackgroundDrawable(null); activity.getSupportActionBar().setBackgroundDrawable(defaultActionBarBackground);
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
actionBarView.setVisibility(View.GONE);
activity.setTitle(title); activity.setTitle(title);
} }
......
...@@ -54,6 +54,7 @@ public class ContactTitleInflater { ...@@ -54,6 +54,7 @@ public class ContactTitleInflater {
titleView.setBackgroundDrawable(new ColorDrawable(accountActionBarColors[ titleView.setBackgroundDrawable(new ColorDrawable(accountActionBarColors[
AccountManager.getInstance().getColorLevel(abstractContact.getAccount())])); AccountManager.getInstance().getColorLevel(abstractContact.getAccount())]));
nameView.setTextColor(activity.getResources().getColor(R.color.primary_text_default_material_dark));
nameView.setText(abstractContact.getName()); nameView.setText(abstractContact.getName());
statusModeView.setImageLevel(abstractContact.getStatusMode().getStatusLevel()); statusModeView.setImageLevel(abstractContact.getStatusMode().getStatusLevel());
avatarView.setImageDrawable(abstractContact.getAvatar()); avatarView.setImageDrawable(abstractContact.getAvatar());
......
/**
* 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.helper;
import android.widget.ImageView;
import com.xabber.android.data.roster.AbstractContact;
/**
* This dummy implementation do nothing.
*
* @author alexander.ivanov
*/
public class DummyAvatarInflaterHelper extends AbstractAvatarInflaterHelper {
@Override
public void updateAvatar(ImageView avatar, AbstractContact abstractContact) {
}
}
...@@ -14,10 +14,14 @@ ...@@ -14,10 +14,14 @@
*/ */
package com.xabber.android.utils; package com.xabber.android.utils;
import android.content.Context;
import android.content.res.Resources;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar;
import android.content.res.Resources;
/** /**
* Helper class to get plural forms. * Helper class to get plural forms.
...@@ -32,7 +36,7 @@ public class StringUtils { ...@@ -32,7 +36,7 @@ public class StringUtils {
static { static {
DATE_TIME = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DATE_TIME = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.SHORT); DateFormat.SHORT);
TIME = DateFormat.getTimeInstance(DateFormat.MEDIUM); TIME = new SimpleDateFormat("H:mm");
} }
private StringUtils() { private StringUtils() {
...@@ -120,17 +124,29 @@ public class StringUtils { ...@@ -120,17 +124,29 @@ public class StringUtils {
* @param timeStamp * @param timeStamp
* @return String with time or with date and time depend on current time. * @return String with time or with date and time depend on current time.
*/ */
public static String getSmartTimeText(Date timeStamp) { public static String getSmartTimeText(Context context, Date timeStamp) {
if (timeStamp == null) if (timeStamp == null) {
return ""; return "";
Date date = new Date(); }
long delta = date.getTime() - timeStamp.getTime();
if (delta < 20 * 60 * 60 * 1000) // today
Calendar midnight = new GregorianCalendar();
// reset hour, minutes, seconds and millis
midnight.set(Calendar.HOUR_OF_DAY, 0);
midnight.set(Calendar.MINUTE, 0);
midnight.set(Calendar.SECOND, 0);
midnight.set(Calendar.MILLISECOND, 0);
DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(context);
if (timeStamp.getTime() > midnight.getTimeInMillis()) {
synchronized (TIME) { synchronized (TIME) {
return TIME.format(timeStamp); return timeFormat.format(timeStamp);
}
} else {
DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
return dateFormat.format(timeStamp) + " " + timeFormat.format(timeStamp);
} }
else
return getDateTimeText(timeStamp);
} }
} }
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/chat_background"
android:tileMode="repeat"
android:dither="true" />
\ 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/.
-->
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/chat_bg_1"
android:minLevel="0"
android:maxLevel="0" />
<item
android:drawable="@drawable/chat_bg_2"
android:minLevel="1"
android:maxLevel="1" />
<item
android:drawable="@drawable/chat_bg_3"
android:minLevel="2"
android:maxLevel="2" />
<item
android:drawable="@drawable/chat_bg_4"
android:minLevel="3"
android:maxLevel="3" />
</level-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_button_send_green_24dp" android:minLevel="0" android:maxLevel="0" />
<item android:drawable="@drawable/ic_button_send_orange_24dp" android:minLevel="1" android:maxLevel="1" />
<item android:drawable="@drawable/ic_button_send_red_24dp" android:minLevel="2" android:maxLevel="2" />
<item android:drawable="@drawable/ic_button_send_blue_24dp" android:minLevel="3" android:maxLevel="3" />
</level-list>
\ No newline at end of file
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
along with this program. If not, see http://www.gnu.org/licenses/. along with this program. If not, see http://www.gnu.org/licenses/.
--> -->
<level-list xmlns:android="http://schemas.android.com/apk/res/android"> <level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_security_plain" android:minLevel="0" android:maxLevel="0" /> <item android:drawable="@drawable/ic_security_plain_18dp" android:minLevel="0" android:maxLevel="0" />
<item android:drawable="@drawable/ic_security_encripted" android:minLevel="1" android:maxLevel="1" /> <item android:drawable="@drawable/ic_security_encrypted_18dp" android:minLevel="1" android:maxLevel="1" />
<item android:drawable="@drawable/ic_security_verified" android:minLevel="2" android:maxLevel="2" /> <item android:drawable="@drawable/ic_security_verified_18dp" android:minLevel="2" android:maxLevel="2" />
<item android:drawable="@drawable/ic_security_finished" android:minLevel="3" android:maxLevel="3" /> <item android:drawable="@drawable/ic_security_finished_18dp" android:minLevel="3" android:maxLevel="3" />
</level-list> </level-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/message_incoming_states_green" android:minLevel="0" android:maxLevel="0" />
<item android:drawable="@drawable/message_incoming_states_orange" android:minLevel="1" android:maxLevel="1" />
<item android:drawable="@drawable/message_incoming_states_red" android:minLevel="2" android:maxLevel="2" />
<item android:drawable="@drawable/message_incoming_states_blue" android:minLevel="3" android:maxLevel="3" />
</level-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/message_incoming_selected_blue" />
<item android:drawable="@drawable/message_incoming_blue" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/message_incoming_selected_green" />
<item android:drawable="@drawable/message_incoming_green" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/message_incoming_selected_orange" />
<item android:drawable="@drawable/message_incoming_orange" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/message_incoming_selected_red" />
<item android:drawable="@drawable/message_incoming_red" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/message_outgoing_selected" />
<item android:drawable="@drawable/message_outgoing" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:tileMode="repeat"
android:src="@drawable/notify_panel_notification_icon_bg"
/>
<?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/.
-->
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/shadow"
android:tileMode="repeat"
/>
<?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/.
-->
<QuickContactBadge
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size"
android:layout_toRightOf="@id/color"
android:src="@drawable/avatar_1_1"
/>
...@@ -29,7 +29,16 @@ ...@@ -29,7 +29,16 @@
android:layout_marginEnd="3dp" android:layout_marginEnd="3dp"
/> />
<include layout="@layout/base_contact_avatar" />
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size"
android:layout_toRightOf="@id/color"
android:src="@drawable/avatar_1_1"
/>
<RelativeLayout <RelativeLayout
android:id="@+id/panel" android:id="@+id/panel"
android:layout_width="match_parent" android:layout_width="match_parent"
......
...@@ -31,7 +31,14 @@ ...@@ -31,7 +31,14 @@
android:src="@android:color/transparent" android:src="@android:color/transparent"
/> />
<include layout="@layout/base_contact_avatar" /> <ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/avatar"
android:layout_width="@dimen/avatar_size"
android:layout_height="@dimen/avatar_size"
android:layout_toRightOf="@id/color"
android:src="@drawable/avatar_1_1"
/>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/action_message_text"
android:textAppearance="@style/ChatHeader.Delay"
android:padding="2dp"
android:gravity="center"
android:text="Message"
/>
</LinearLayout>
\ No newline at end of file
...@@ -14,27 +14,66 @@ ...@@ -14,27 +14,66 @@
--> -->
<RelativeLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/background" android:id="@+id/chat_message_incoming"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingRight="4dip" >
android:paddingBottom="4dip"
android:background="@drawable/chat_bg">
<ImageView <ImageView
android:id="@+id/avatar" android:id="@+id/avatar"
android:layout_width="32dip" android:layout_width="32dip"
android:layout_height="32dip" android:layout_height="32dip"
android:layout_marginLeft="4dip"
android:layout_marginTop="3dp"
android:layout_marginLeft="6dp"
android:layout_alignTop="@+id/message_text"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:src="@drawable/avatar_1_1" android:src="@drawable/avatar_1_1"
/> />
<TextView <TextView
android:id="@+id/text" android:id="@+id/message_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_toRightOf="@id/avatar" android:layout_toRightOf="@id/avatar"
android:paddingLeft="4dip" android:layout_toEndOf="@id/avatar"
android:minWidth="142dp"
android:paddingLeft="16dp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:paddingRight="6dp"
android:paddingEnd="6dp"
android:layout_marginLeft="6dp"
android:layout_marginStart="6dp"
android:layout_marginRight="48dp"
android:layout_marginEnd="48dp"
android:background="@drawable/message_incoming"
android:text="Some text\n line \nrgregrere"
/> />
<TextView
android:id="@+id/message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/avatar"
android:layout_toEndOf="@+id/avatar"
android:layout_below="@id/message_text"
android:paddingLeft="16dp"
android:textAppearance="@style/ChatHeader.Time"
android:textSize="10sp"
android:text="Feb 19, 2015 4:39 PM"
/>
</RelativeLayout> </RelativeLayout>
...@@ -16,12 +16,14 @@ ...@@ -16,12 +16,14 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
>
<TextView <TextView
android:id="@+id/info" android:id="@+id/info"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="4dip" android:padding="4dp"
android:textAppearance="@style/ChatInfo.Warning" android:textAppearance="@style/ChatInfo.Warning"
android:gravity="center"
android:text="info" /> android:text="info" />
</LinearLayout> </LinearLayout>
\ No newline at end of file
...@@ -12,64 +12,62 @@ ...@@ -12,64 +12,62 @@
You should have received a copy of the GNU General Public License, You should have received a copy of the GNU General Public License,
along with this program. If not, see http://www.gnu.org/licenses/. along with this program. If not, see http://www.gnu.org/licenses/.
--> -->
<LinearLayout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
> android:background="@drawable/chat_background_repeat"
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
> >
<ListView <ListView
android:id="@android:id/list" android:id="@android:id/list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="4dip"
android:stackFromBottom="true" android:stackFromBottom="true"
android:transcriptMode="normal" android:transcriptMode="normal"
android:smoothScrollbar="false" android:smoothScrollbar="false"
android:divider="@null"
android:dividerHeight="0dp"
android:layout_above="@+id/input_layout"
tools:listitem="@layout/chat_viewer_outgoing_message"
android:listSelector="@android:color/transparent"
/> />
<TextView
android:id="@+id/chat_page"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dip"
android:textSize="12sp"
android:gravity="center"
android:visibility="gone"
android:background="?android:attr/colorBackground"
android:text="@string/chat_page"
/>
</RelativeLayout>
<LinearLayout <LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="4dip"> android:id="@+id/input_layout"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:background="@color/white"
android:elevation="8dp"
>
<EditText <EditText
android:id="@+id/chat_input" android:id="@+id/chat_input"
android:layout_weight="1"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine" android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
android:imeOptions="actionSend|flagNoEnterAction"
android:cursorVisible="true" android:cursorVisible="true"
android:hint="@string/chat_input_hint" android:hint="@string/chat_input_hint"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:maxLines="5" android:maxLines="5"
android:scrollbars="vertical" android:scrollbars="vertical"
android:fadingEdge="vertical" android:fadingEdge="vertical"
android:focusable="true" android:focusable="true"
android:descendantFocusability="beforeDescendants" android:descendantFocusability="beforeDescendants"
android:layout_weight="1"
/> />
<Button
android:text="@string/chat_send" <ImageButton
android:id="@+id/chat_send" android:id="@+id/button_send_message"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
/> android:padding="8dp"
android:src="@drawable/ic_button_send"
android:background="@null"
android:contentDescription="@string/chat_send" />
</LinearLayout> </LinearLayout>
</LinearLayout>
</RelativeLayout>
<?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/.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/chat_message_incoming"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/message_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:paddingRight="16dp"
android:paddingEnd="16dp"
android:layout_marginLeft="48dp"
android:layout_marginStart="48dp"
android:layout_marginRight="6dp"
android:layout_marginEnd="6dp"
android:minWidth="160dp"
android:text="Some text\n line \nrgregrere"
android:background="@drawable/message_outgoing_states"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<TextView
android:id="@+id/message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/message_text"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:paddingRight="16dp"
android:paddingEnd="16dp"
android:textAppearance="@style/ChatHeader.Time"
android:textSize="10sp"
android:text="Feb 19, 2015 4:39 PM"
/>
<ImageView
android:id="@+id/message_status_icon"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_alignBottom="@+id/message_time"
android:layout_toLeftOf="@+id/message_time"
android:src="@drawable/ic_message_delivered_18dp"
/>
</RelativeLayout>
...@@ -5,8 +5,20 @@ ...@@ -5,8 +5,20 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:orientation="horizontal" android:orientation="horizontal"
android:background="@color/green_500"
> >
<include layout="@layout/contact_title_avatar" />
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/avatar"
android:layout_width="48dip"
android:layout_height="48dip"
android:src="@drawable/avatar_1_1"
android:layout_gravity="center_vertical"
android:layout_marginRight="4dp"
android:layout_marginEnd="4dp"
/>
<LinearLayout <LinearLayout
android:id="@+id/name_holder" android:id="@+id/name_holder"
...@@ -22,6 +34,7 @@ ...@@ -22,6 +34,7 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:singleLine="true" android:singleLine="true"
android:layout_weight="1" android:layout_weight="1"
android:textColor="@color/primary_text_default_material_dark"
android:text="name" android:text="name"
android:textStyle="bold" /> android:textStyle="bold" />
<LinearLayout <LinearLayout
...@@ -35,8 +48,9 @@ ...@@ -35,8 +48,9 @@
android:id="@+id/security" android:id="@+id/security"
android:src="@drawable/ic_security" android:src="@drawable/ic_security"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:visibility="gone" android:visibility="gone"
android:padding="3dp"
/> />
<ImageView <ImageView
...@@ -52,6 +66,7 @@ ...@@ -52,6 +66,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center_vertical" android:gravity="center_vertical"
android:singleLine="true" android:singleLine="true"
android:textColor="@color/primary_text_default_material_dark"
android:text="status" android:text="status"
/> />
</LinearLayout> </LinearLayout>
......
<?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/.
-->
<QuickContactBadge
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/avatar"
android:layout_width="48dip"
android:layout_height="48dip"
android:src="@drawable/avatar_1_1"
android:layout_gravity="center_vertical"
android:layout_marginRight="4dp"
android:layout_marginEnd="4dp"
/>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_status.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_status.png -->
<string name="action_status_text">%1$s установил статус: %2$s</string> <string name="action_status_text">%1$s установил статус: %2$s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_status.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_status.png -->
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_account_is_offline.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_account_is_offline.png -->
<string name="account_is_offline">Сообщения будут доставлены после подключения к сети</string> <string name="account_is_offline">Сообщения будут доставлены после подключения к сети</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png -->
<string name="chat_delay">Сообщение было отправлено в %s</string> <string name="chat_delay">отправлено в %s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png -->
<string name="chat_input_hint">Введите сообщение</string> <string name="chat_input_hint">Введите сообщение</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_switch.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_switch.png -->
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_paused.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_paused.png -->
<string name="chat_state_paused">Ввел текст ...</string> <string name="chat_state_paused">Ввел текст ...</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png -->
<string name="chat_typed">Сообщение было набрано в %s</string> <string name="chat_typed">набрано в %s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_option_menu_extra.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_option_menu_extra.png -->
<string name="export_chat">Сохранить чат</string> <string name="export_chat">Сохранить чат</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/export_chat_done.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/export_chat_done.png -->
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_account_is_offline.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_account_is_offline.png -->
<string name="account_is_offline">You are currently offline. Messages you send will be delivered next time you connect.</string> <string name="account_is_offline">You are currently offline. Messages you send will be delivered next time you connect.</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png -->
<string name="chat_delay">Message was sent at %s</string> <string name="chat_delay">sent at %s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png -->
<string name="chat_input_hint">Type your message here</string> <string name="chat_input_hint">Type your message here</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_switch.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_switch.png -->
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_paused.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_paused.png -->
<string name="chat_state_paused">Entered text …</string> <string name="chat_state_paused">Entered text …</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer.png -->
<string name="chat_typed">Message was entered at %s</string> <string name="chat_typed">entered at %s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_option_menu_extra.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_option_menu_extra.png -->
<string name="export_chat">Export chat</string> <string name="export_chat">Export chat</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/export_chat_done.png --> <!-- http://dl.dropbox.com/u/1029995/com.xabber.android/export_chat_done.png -->
......
...@@ -9,19 +9,26 @@ ...@@ -9,19 +9,26 @@
</array> </array>
<array name="account_action_bar"> <array name="account_action_bar">
<item>@color/teal_500</item> <item>@color/green_500</item>
<item>@color/deep_orange_500</item> <item>@color/orange_500</item>
<item>@color/pink_500</item> <item>@color/red_500</item>
<item>@color/dark_purple_500</item> <item>@color/blue_500</item>
</array> </array>
<array name="account_status_bar"> <array name="account_status_bar">
<item>@color/teal_700</item> <item>@color/green_700</item>
<item>@color/deep_orange_700</item> <item>@color/orange_700</item>
<item>@color/pink_700</item> <item>@color/red_700</item>
<item>@color/dark_purple_700</item> <item>@color/blue_700</item>
</array>
<array name="account_chat_background">
<item>@color/green_50</item>
<item>@color/orange_50</item>
<item>@color/red_50</item>
<item>@color/blue_50</item>
</array> </array>
<color name="account_disabled">@color/black_dividers</color> <color name="account_disabled">@color/black_dividers</color>
<color name="group_expander">@color/blue_grey_800</color> <color name="group_expander">@color/blue_grey_100</color>
</resources> </resources>
\ No newline at end of file
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
along with this program. If not, see http://www.gnu.org/licenses/. along with this program. If not, see http://www.gnu.org/licenses/.
--> -->
<resources> <resources>
<style name="Theme" parent="Theme.AppCompat"> <style name="Theme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="expanderGroupColor">?android:attr/textColorPrimary</item> <item name="expanderGroupColor">?android:attr/textColorPrimary</item>
<item name="expanderAccountColor">?android:attr/textColorPrimaryInverse</item> <item name="expanderAccountColor">?android:attr/textColorPrimaryInverse</item>
<item name="expanderIndicator">@drawable/expander_indicator_dark</item> <item name="expanderIndicator">@drawable/expander_indicator_dark</item>
......
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