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 {
applicationId "com.xabber.androiddev"
minSdkVersion 14
targetSdkVersion 21
versionCode 123
versionName '0.10.23a'
versionCode 129
versionName '0.10.30'
}
buildTypes {
......
......@@ -14,20 +14,6 @@
*/
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.PendingIntent;
import android.content.Context;
......@@ -52,6 +38,20 @@ import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.receiver.ComposingPausedReceiver;
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.
*
......@@ -260,7 +260,7 @@ public class ChatStateManager implements OnDisconnectListener,
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)
return;
updateChatState(account, user, ChatState.paused);
......
......@@ -30,8 +30,7 @@ public class ComposingPausedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ChatStateManager.getInstance().onPaused(intent, getAccount(intent),
getUser(intent));
ChatStateManager.getInstance().onPaused(getAccount(intent), getUser(intent));
}
public static Intent createIntent(Context context, String account,
......
......@@ -14,13 +14,18 @@
*/
package com.xabber.android.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import com.xabber.android.data.ActivityManager;
......@@ -192,7 +197,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
if (chatState == RoomState.unavailable) {
menu.findItem(R.id.action_join_conference).setVisible(true);
menu.findItem(R.id.action_close_chat).setVisible(true);
} else {
menu.findItem(R.id.action_invite_to_chat).setVisible(true);
......@@ -206,6 +211,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
if (abstractChat instanceof RegularChat) {
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);
......@@ -386,7 +392,7 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
private void cleatInputText(String account, String user) {
for (ChatViewerFragment chat : registeredChats) {
if (chat.isEqual(account, user)) {
chat.clearInputView();
chat.clearInputText();
}
}
}
......@@ -451,8 +457,8 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
}
private void selectPage(int position, boolean smoothScroll) {
viewPager.setCurrentItem(position, smoothScroll);
onPageSelected(position);
viewPager.setCurrentItem(position, smoothScroll);
}
private static String getAccount(Intent intent) {
......@@ -596,6 +602,8 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
@Override
public void onPageSelected(int position) {
hideKeyboard(this);
AbstractChat selectedChat = chatViewerAdapter.getChatByPageNumber(position);
isChatSelected = selectedChat != null;
......@@ -687,6 +695,49 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
insertExtraText();
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() {
......@@ -710,15 +761,24 @@ public class ChatViewer extends ManagedActivity implements OnChatChangedListener
}
@Override
public void onRecentChatSelected(AbstractChat chat) {
public void onChatSelected(AbstractChat chat) {
selectPage(chat.getAccount(), chat.getUser(), true);
}
public void selectRecentChatsPage() {
viewPager.setCurrentItem(chatViewerAdapter.getRecentChatsPosition(), true);
selectPage(null, null, false);
}
public ChatViewerAdapter getChatViewerAdapter() {
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;
import android.view.MenuItem;
import android.view.View;
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.EditText;
import android.widget.ImageButton;
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.account.AccountManager;
import com.xabber.android.data.extension.cs.ChatStateManager;
import com.xabber.android.data.message.MessageItem;
import com.xabber.android.data.message.MessageManager;
......@@ -31,12 +29,11 @@ import com.xabber.android.data.message.chat.ChatManager;
import com.xabber.android.ui.adapter.ChatMessageAdapter;
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_USER = "ARGUMENT_USER";
private TextView pageView;
private EditText inputView;
private ListView listView;
private ChatMessageAdapter chatMessageAdapter;
......@@ -46,6 +43,9 @@ public class ChatViewerFragment extends Fragment {
private String account;
private String user;
boolean isInputEmpty = true;
private ImageButton sendButton;
public static ChatViewerFragment newInstance(String account, String user) {
ChatViewerFragment fragment = new ChatViewerFragment();
......@@ -69,39 +69,21 @@ public class ChatViewerFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle 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);
chatMessageAdapter = new ChatMessageAdapter(getActivity());
chatMessageAdapter.setChat(account, user);
sendButton = (ImageButton) view.findViewById(R.id.button_send_message);
sendButton.setImageResource(R.drawable.ic_button_send_inactive_24dp);
chatMessageAdapter = new ChatMessageAdapter(getActivity(), account, user);
listView = (ListView) view.findViewById(android.R.id.list);
listView.setAdapter(chatMessageAdapter);
listView.setOnItemClickListener(this);
pageView = (TextView) view.findViewById(R.id.chat_page);
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() {
@Override
......@@ -112,32 +94,27 @@ public class ChatViewerFragment extends Fragment {
});
inputView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN
&& keyCode == KeyEvent.KEYCODE_ENTER
&& SettingsManager.chatsSendByEnter()) {
if (SettingsManager.chatsSendByEnter()
&& event.getAction() == KeyEvent.ACTION_DOWN
&& keyCode == KeyEvent.KEYCODE_ENTER) {
sendMessage();
return true;
}
return false;
}
});
inputView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
inputView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public boolean onEditorAction(TextView view, int actionId,
KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) {
sendMessage();
return true;
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
ChatStateManager.getInstance().onPaused(account, user);
}
return false;
}
});
inputView.addTextChangedListener(new TextWatcher() {
@Override
......@@ -150,35 +127,46 @@ public class ChatViewerFragment extends Fragment {
@Override
public void afterTextChanged(Editable text) {
if (skipOnTextChanges)
return;
String account = chatMessageAdapter.getAccount();
String user = chatMessageAdapter.getUser();
LogManager.i(this, "afterTextChanged");
setSendButtonColor();
if (!skipOnTextChanges) {
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
public void onResume() {
super.onResume();
((ChatViewer)getActivity()).registerChat(this);
registerForContextMenu(listView);
restoreInputState();
}
private void restoreInputState() {
public void restoreInputState() {
skipOnTextChanges = true;
inputView.setText(ChatManager.getInstance().getTypedMessage(account, user));
......@@ -186,17 +174,17 @@ public class ChatViewerFragment extends Fragment {
ChatManager.getInstance().getSelectionEnd(account, user));
skipOnTextChanges = false;
if (!inputView.getText().toString().isEmpty()) {
inputView.requestFocus();
}
}
@Override
public void onPause() {
super.onPause();
saveInputState();
((ChatViewer)getActivity()).unregisterChat(this);
unregisterForContextMenu(listView);
}
public void saveInputState() {
......@@ -205,25 +193,13 @@ public class ChatViewerFragment extends Fragment {
}
private void sendMessage() {
String text = inputView.getText().toString();
int start = 0;
int end = text.length();
String text = inputView.getText().toString().trim();
while (start < end && (text.charAt(start) == ' ' || text.charAt(start) == '\n')) {
start += 1;
}
while (start < end && (text.charAt(end - 1) == ' ' || text.charAt(end - 1) == '\n')) {
end -= 1;
}
text = text.substring(start, end);
if ("".equals(text)) {
if (text.isEmpty()) {
return;
}
skipOnTextChanges = true;
inputView.getText().clear();
skipOnTextChanges = false;
clearInputText();
sendMessage(text);
......@@ -232,8 +208,7 @@ public class ChatViewerFragment extends Fragment {
if (SettingsManager.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.always
|| (getActivity().getResources().getBoolean(R.bool.landscape)
&& SettingsManager.chatsHideKeyboard() == SettingsManager.ChatsHideKeyboard.landscape)) {
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(inputView.getWindowToken(), 0);
ChatViewer.hideKeyboard(getActivity());
}
}
......@@ -242,25 +217,27 @@ public class ChatViewerFragment extends Fragment {
updateChat();
}
private void updateView() {
chatMessageAdapter.onChange();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view,
ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, 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();
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);
}
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
......@@ -278,7 +255,7 @@ public class ChatViewerFragment extends Fragment {
return true;
case R.id.action_message_quote:
insertText("> " + message.getText() + "\n");
setInputText("> " + message.getText() + "\n");
return true;
case R.id.action_message_remove:
......@@ -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() {
updateView();
chatMessageAdapter.onChange();
}
public boolean isEqual(String account, String user) {
return this.account.equals(account) && this.user.equals(user);
}
public void setInputText(String text) {
insertText(text);
public void setInputText(String additional) {
skipOnTextChanges = true;
inputView.setText(additional);
inputView.setSelection(additional.length());
skipOnTextChanges = false;
}
public String getAccount() {
......@@ -331,8 +291,10 @@ public class ChatViewerFragment extends Fragment {
return user;
}
public void clearInputView() {
public void clearInputText() {
skipOnTextChanges = true;
inputView.getText().clear();
skipOnTextChanges = false;
}
public void scrollChat() {
......@@ -341,4 +303,11 @@ public class ChatViewerFragment extends Fragment {
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 {
super.onListItemClick(l, v, position, id);
if (null != listener) {
listener.onRecentChatSelected((AbstractChat) getListAdapter().getItem(position));
listener.onChatSelected((AbstractChat) getListAdapter().getItem(position));
}
}
public interface RecentChatFragmentInteractionListener {
public void onRecentChatSelected(AbstractChat chat);
public void onChatSelected(AbstractChat chat);
}
public void updateChats(List<AbstractChat> chats) {
......
......@@ -32,7 +32,6 @@ import android.widget.TextView;
import com.xabber.android.data.SettingsManager;
import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper;
import com.xabber.androiddev.R;
/**
......@@ -46,7 +45,6 @@ public abstract class BaseContactInflater {
final LayoutInflater layoutInflater;
final AbstractAvatarInflaterHelper avatarInflaterHelper;
/**
* Repeated shadow for drawable.
......@@ -62,7 +60,6 @@ public abstract class BaseContactInflater {
public BaseContactInflater(Activity activity) {
this.activity = activity;
layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.shadow);
shadowDrawable = new BitmapDrawable(activity.getResources(), bitmap);
......@@ -128,7 +125,6 @@ public abstract class BaseContactInflater {
if (SettingsManager.contactsShowAvatars()) {
viewHolder.avatar.setVisibility(View.VISIBLE);
viewHolder.avatar.setImageDrawable(abstractContact.getAvatarForContactList());
avatarInflaterHelper.updateAvatar(viewHolder.avatar, abstractContact);
((RelativeLayout.LayoutParams) viewHolder.panel.getLayoutParams())
.addRule(RelativeLayout.RIGHT_OF, R.id.avatar);
} else {
......
......@@ -13,7 +13,6 @@ import com.xabber.android.data.message.MessageManager;
import com.xabber.android.data.notification.NotificationManager;
import com.xabber.android.data.roster.AbstractContact;
import com.xabber.android.data.roster.RosterManager;
import com.xabber.android.ui.helper.AbstractAvatarInflaterHelper;
import com.xabber.androiddev.R;
import java.util.ArrayList;
......@@ -23,15 +22,12 @@ public class ChatListAdapter extends BaseAdapter {
private List<AbstractChat> chats;
private final AbstractAvatarInflaterHelper avatarInflaterHelper;
private final Context context;
public ChatListAdapter(Context context) {
this.context = context;
chats = new ArrayList<>();
avatarInflaterHelper = AbstractAvatarInflaterHelper.createAbstractContactInflaterHelper();
}
public void updateChats(List<AbstractChat> chats) {
......@@ -73,7 +69,6 @@ public class ChatListAdapter extends BaseAdapter {
final ImageView avatarView = (ImageView) view.findViewById(R.id.avatar);
avatarView.setImageDrawable(abstractContact.getAvatar());
avatarInflaterHelper.updateAvatar(avatarView, abstractContact);
final TextView textView = (TextView) view.findViewById(R.id.text);
......
......@@ -17,15 +17,12 @@ package com.xabber.android.ui.adapter;
import android.app.Activity;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.text.style.CharacterStyle;
import android.text.style.ImageSpan;
import android.text.style.TextAppearanceSpan;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.xabber.android.data.SettingsManager;
......@@ -56,9 +53,13 @@ import java.util.List;
*/
public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter {
private static final int TYPE_MESSAGE = 0;
private static final int TYPE_HINT = 1;
private static final int TYPE_EMPTY = 2;
private static final int VIEW_TYPE_COUNT = 5;
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 String account;
......@@ -81,21 +82,22 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
*/
private String hint;
public ChatMessageAdapter(Activity activity) {
public ChatMessageAdapter(Activity activity, String account, String user) {
this.activity = activity;
messages = Collections.emptyList();
account = null;
user = null;
this.account = account;
this.user = user;
isMUC = MUCManager.getInstance().hasRoom(account, user);
hint = null;
appearanceStyle = SettingsManager.chatsAppearanceStyle();
ChatsDivide chatsDivide = SettingsManager.chatsDivide();
if (chatsDivide == ChatsDivide.always
|| (chatsDivide == ChatsDivide.portial && !activity
.getResources().getBoolean(R.bool.landscape)))
if (chatsDivide == ChatsDivide.always || (chatsDivide == ChatsDivide.portial
&& !activity.getResources().getBoolean(R.bool.landscape))) {
divider = "\n";
else
} else {
divider = " ";
}
}
@Override
public int getCount() {
......@@ -104,11 +106,12 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
@Override
public Object getItem(int position) {
if (position < messages.size())
if (position < messages.size()) {
return messages.get(position);
else
} else {
return null;
}
}
@Override
public long getItemId(int position) {
......@@ -117,194 +120,189 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
@Override
public int getViewTypeCount() {
return 3;
return VIEW_TYPE_COUNT;
}
@Override
public int getItemViewType(int position) {
if (position < messages.size())
return TYPE_MESSAGE;
else
return hint == null ? TYPE_EMPTY : TYPE_HINT;
if (position >= messages.size()) {
return hint == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_HINT;
}
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);
MessageItem messageItem = (MessageItem) getItem(position);
if (messageItem.getAction() != null) {
return VIEW_TYPE_ACTION_MESSAGE;
}
return messageItem.isIncoming() ? VIEW_TYPE_INCOMING_MESSAGE : VIEW_TYPE_OUTGOING_MESSAGE;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int type = getItemViewType(position);
final View view;
if (type == VIEW_TYPE_EMPTY) {
if (convertView == null) {
final int resource;
if (type == TYPE_MESSAGE)
resource = R.layout.chat_viewer_message;
else if (type == TYPE_HINT)
resource = R.layout.chat_viewer_info;
else if (type == TYPE_EMPTY)
resource = R.layout.chat_viewer_empty;
else
throw new IllegalStateException();
view = activity.getLayoutInflater()
.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;
return activity.getLayoutInflater().inflate(R.layout.chat_viewer_empty, parent, false);
} else {
return convertView;
}
}
if (type == VIEW_TYPE_HINT) {
View view = convertView;
if (convertView == null) {
view = activity.getLayoutInflater().inflate(R.layout.chat_viewer_info, parent, false);
}
if (type == TYPE_HINT) {
TextView textView = ((TextView) view.findViewById(R.id.info));
textView.setText(hint);
textView.setTextAppearance(activity, R.style.ChatInfo_Warning);
return view;
}
final MessageItem messageItem = (MessageItem) getItem(position);
final String name;
final String account = messageItem.getChat().getAccount();
final String user = messageItem.getChat().getUser();
final String resource = messageItem.getResource();
final boolean incoming = messageItem.isIncoming();
if (isMUC) {
name = resource;
} else {
if (incoming)
name = RosterManager.getInstance().getName(account, user);
else
name = AccountManager.getInstance().getNickName(account);
MessageItem messageItem = (MessageItem) getItem(position);
if (type == VIEW_TYPE_ACTION_MESSAGE) {
View view = convertView;
if (convertView == null) {
view = activity.getLayoutInflater().inflate(R.layout.chat_viewer_action_message, parent, false);
}
if (incoming) {
if (view.getBackground() == null)
view.setBackgroundResource(R.drawable.chat_bg);
view.getBackground().setLevel(
AccountManager.getInstance().getColorLevel(account));
ChatAction action = messageItem.getAction();
Spannable text = Emoticons.newSpannable(
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 {
view.setBackgroundDrawable(null);
throw new IllegalStateException();
}
Spannable text = messageItem.getSpannable();
TextView textView = (TextView) view.findViewById(R.id.text);
ImageView avatarView = (ImageView) view.findViewById(R.id.avatar);
ChatAction action = messageItem.getAction();
String time = StringUtils.getSmartTimeText(messageItem.getTimestamp());
view = activity.getLayoutInflater().inflate(layoutId, parent, false);
}
setUpMessageView(messageItem, view);
return view;
}
private void setUpMessageView(MessageItem messageItem, View view) {
final boolean incoming = messageItem.isIncoming();
SpannableStringBuilder builder = new SpannableStringBuilder();
if (action == null) {
int messageResource = R.drawable.ic_message_delivered;
final String resource = messageItem.getResource();
if (!incoming) {
if (messageItem.isError())
messageResource = R.drawable.ic_message_has_error;
else if (!messageItem.isSent())
messageResource = R.drawable.ic_message_not_sent;
else if (!messageItem.isDelivered())
messageResource = R.drawable.ic_message_not_delivered;
}
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));
setStatusIcon(messageItem, view);
}
if (isMUC) {
append(builder, resource, new TextAppearanceSpan(activity, R.style.ChatHeader_Time));
append(builder, divider, new TextAppearanceSpan(activity, R.style.ChatHeader));
}
Date delayTimestamp = messageItem.getDelayTimestamp();
if (messageItem.isUnencypted()) {
append(builder,
activity.getString(R.string.otr_unencrypted_message),
new TextAppearanceSpan(activity,
R.style.ChatHeader_Delay));
append(builder, divider, new TextAppearanceSpan(activity,
R.style.ChatHeader));
append(builder, activity.getString(R.string.otr_unencrypted_message),
new TextAppearanceSpan(activity, R.style.ChatHeader_Delay));
append(builder, divider, new TextAppearanceSpan(activity, R.style.ChatHeader));
}
Spannable text = messageItem.getSpannable();
Emoticons.getSmiledText(activity.getApplication(), text);
if (messageItem.getTag() == null)
if (messageItem.getTag() == null) {
builder.append(text);
else
append(builder, text, new TextAppearanceSpan(activity,
R.style.ChatRead));
} else {
append(builder, time, new TextAppearanceSpan(activity,
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));
append(builder, text, new TextAppearanceSpan(activity, R.style.ChatRead));
}
TextView textView = (TextView) view.findViewById(R.id.message_text);
textView.setTextAppearance(activity, appearanceStyle);
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()) {
final String account = messageItem.getChat().getAccount();
final String user = messageItem.getChat().getUser();
final String resource = messageItem.getResource();
avatarView.setVisibility(View.VISIBLE);
if (!incoming
|| (isMUC && MUCManager.getInstance()
.getNickname(account, user)
.equalsIgnoreCase(resource))) {
avatarView.setImageDrawable(AvatarManager.getInstance()
.getAccountAvatar(account));
if ((isMUC && MUCManager.getInstance().getNickname(account, user).equalsIgnoreCase(resource))) {
avatarView.setImageDrawable(AvatarManager.getInstance().getAccountAvatar(account));
} else {
if (isMUC) {
if ("".equals(resource)) {
avatarView.setImageDrawable(AvatarManager.getInstance()
.getRoomAvatar(user));
avatarView.setImageDrawable(AvatarManager.getInstance().getRoomAvatar(user));
} else {
avatarView.setImageDrawable(AvatarManager.getInstance()
.getOccupantAvatar(user + "/" + resource));
avatarView.setImageDrawable(AvatarManager.getInstance().getOccupantAvatar(user + "/" + resource));
}
} else {
avatarView.setImageDrawable(AvatarManager.getInstance()
.getUserAvatar(user));
avatarView.setImageDrawable(AvatarManager.getInstance().getUserAvatar(user));
}
}
((RelativeLayout.LayoutParams) textView.getLayoutParams()).addRule(
RelativeLayout.RIGHT_OF, R.id.avatar);
} else {
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
......@@ -318,40 +316,22 @@ public class ChatMessageAdapter extends BaseAdapter implements UpdatableAdapter
* @return New hint.
*/
private String getHint() {
AccountItem accountItem = AccountManager.getInstance().getAccount(
account);
boolean online;
if (accountItem == null)
online = false;
else
online = accountItem.getState().isConnected();
final AbstractContact abstractContact = RosterManager.getInstance()
.getBestContact(account, user);
AccountItem accountItem = AccountManager.getInstance().getAccount(account);
boolean online = accountItem != null && accountItem.getState().isConnected();
final AbstractContact abstractContact = RosterManager.getInstance().getBestContact(account, user);
if (!online) {
if (abstractContact instanceof RoomContact)
if (abstractContact instanceof RoomContact) {
return activity.getString(R.string.muc_is_unavailable);
else
} else {
return activity.getString(R.string.account_is_offline);
}
} else if (!abstractContact.getStatusMode().isOnline()) {
if (abstractContact instanceof RoomContact)
if (abstractContact instanceof RoomContact) {
return activity.getString(R.string.muc_is_unavailable);
else
return activity.getString(R.string.contact_is_offline,
abstractContact.getName());
} else {
return activity.getString(R.string.contact_is_offline, abstractContact.getName());
}
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();
return null;
}
}
......@@ -32,6 +32,7 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter {
private static final int TOTAL_COUNT = 200;
private static final int OFFSET = TOTAL_COUNT / 2;
private Fragment currentFragment;
public ChatViewerAdapter(FragmentManager fragmentManager, String account, String user, FinishUpdateListener finishUpdateListener) {
super(fragmentManager);
......@@ -133,10 +134,6 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter {
return realPosition + OFFSET;
}
public int getRecentChatsPosition() {
return OFFSET;
}
public AbstractChat getChatByPageNumber(int virtualPosition) {
int realPosition = getRealPagePosition(virtualPosition);
......@@ -182,4 +179,19 @@ public class ChatViewerAdapter extends FragmentStatePagerAdapter {
public int getItemPosition(Object object) {
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;
import android.content.res.TypedArray;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.support.v7.app.ActionBar;
......@@ -30,6 +31,8 @@ public class ContactTitleActionBarInflater {
private Animation shakeAnimation = null;
private ColorDrawable defaultActionBarBackground;
public ContactTitleActionBarInflater(ActionBarActivity activity) {
this.activity = activity;
}
......@@ -39,10 +42,9 @@ public class ContactTitleActionBarInflater {
accountStatusBarColors = activity.getResources().getIntArray(R.array.account_status_bar);
ActionBar actionBar = activity.getSupportActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowCustomEnabled(true);
actionBarView = LayoutInflater.from(activity).inflate(R.layout.contact_title, null);
......@@ -55,9 +57,15 @@ public class ContactTitleActionBarInflater {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
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) {
activity.getSupportActionBar().setDisplayShowCustomEnabled(true);
activity.getSupportActionBar().setDisplayShowTitleEnabled(false);
actionBarView.setVisibility(View.VISIBLE);
......@@ -71,13 +79,15 @@ public class ContactTitleActionBarInflater {
}
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) {
window.setStatusBarColor(defaultStatusBarColor);
}
activity.getSupportActionBar().setBackgroundDrawable(null);
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
actionBarView.setVisibility(View.GONE);
activity.getSupportActionBar().setBackgroundDrawable(defaultActionBarBackground);
activity.setTitle(title);
}
......
......@@ -54,6 +54,7 @@ public class ContactTitleInflater {
titleView.setBackgroundDrawable(new ColorDrawable(accountActionBarColors[
AccountManager.getInstance().getColorLevel(abstractContact.getAccount())]));
nameView.setTextColor(activity.getResources().getColor(R.color.primary_text_default_material_dark));
nameView.setText(abstractContact.getName());
statusModeView.setImageLevel(abstractContact.getStatusMode().getStatusLevel());
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 @@
*/
package com.xabber.android.utils;
import android.content.Context;
import android.content.res.Resources;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import android.content.res.Resources;
import java.util.GregorianCalendar;
/**
* Helper class to get plural forms.
......@@ -32,7 +36,7 @@ public class StringUtils {
static {
DATE_TIME = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.SHORT);
TIME = DateFormat.getTimeInstance(DateFormat.MEDIUM);
TIME = new SimpleDateFormat("H:mm");
}
private StringUtils() {
......@@ -120,17 +124,29 @@ public class StringUtils {
* @param timeStamp
* @return String with time or with date and time depend on current time.
*/
public static String getSmartTimeText(Date timeStamp) {
if (timeStamp == null)
public static String getSmartTimeText(Context context, Date timeStamp) {
if (timeStamp == null) {
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) {
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 @@
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/ic_security_plain" 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_verified" 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_plain_18dp" android:minLevel="0" android:maxLevel="0" />
<item android:drawable="@drawable/ic_security_encrypted_18dp" android:minLevel="1" android:maxLevel="1" />
<item android:drawable="@drawable/ic_security_verified_18dp" android:minLevel="2" android:maxLevel="2" />
<item android:drawable="@drawable/ic_security_finished_18dp" 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/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 @@
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
android:id="@+id/panel"
android:layout_width="match_parent"
......
......@@ -31,7 +31,14 @@
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
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 @@
-->
<RelativeLayout
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_height="wrap_content"
android:paddingRight="4dip"
android:paddingBottom="4dip"
android:background="@drawable/chat_bg">
>
<ImageView
android:id="@+id/avatar"
android:layout_width="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"
/>
<TextView
android:id="@+id/text"
android:id="@+id/message_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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>
......@@ -16,12 +16,14 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dip"
android:padding="4dp"
android:textAppearance="@style/ChatInfo.Warning"
android:gravity="center"
android:text="info" />
</LinearLayout>
\ No newline at end of file
......@@ -12,64 +12,62 @@
You should have received a copy of the GNU General Public License,
along with this program. If not, see http://www.gnu.org/licenses/.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/chat_background_repeat"
>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="4dip"
android:layout_height="wrap_content"
android:stackFromBottom="true"
android:transcriptMode="normal"
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
android:orientation="horizontal"
android:layout_width="match_parent"
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
android:id="@+id/chat_input"
android:layout_weight="1"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
android:imeOptions="actionSend|flagNoEnterAction"
android:cursorVisible="true"
android:hint="@string/chat_input_hint"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="5"
android:scrollbars="vertical"
android:fadingEdge="vertical"
android:focusable="true"
android:descendantFocusability="beforeDescendants"
android:layout_weight="1"
/>
<Button
android:text="@string/chat_send"
android:id="@+id/chat_send"
<ImageButton
android:id="@+id/button_send_message"
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>
</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 @@
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
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
android:id="@+id/name_holder"
......@@ -22,6 +34,7 @@
android:gravity="center_vertical"
android:singleLine="true"
android:layout_weight="1"
android:textColor="@color/primary_text_default_material_dark"
android:text="name"
android:textStyle="bold" />
<LinearLayout
......@@ -35,8 +48,9 @@
android:id="@+id/security"
android:src="@drawable/ic_security"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:padding="3dp"
/>
<ImageView
......@@ -52,6 +66,7 @@
android:layout_height="match_parent"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="@color/primary_text_default_material_dark"
android:text="status"
/>
</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"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<resources>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_status.png -->
<string name="action_status_text">%1$s установил статус: %2$s</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_status.png -->
......@@ -11,7 +11,7 @@
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_account_is_offline.png -->
<string name="account_is_offline">Сообщения будут доставлены после подключения к сети</string>
<!-- 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 -->
<string name="chat_input_hint">Введите сообщение</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_switch.png -->
......@@ -109,7 +109,7 @@
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_paused.png -->
<string name="chat_state_paused">Ввел текст ...</string>
<!-- 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 -->
<string name="export_chat">Сохранить чат</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/export_chat_done.png -->
......
......@@ -11,7 +11,7 @@
<!-- 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>
<!-- 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 -->
<string name="chat_input_hint">Type your message here</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_switch.png -->
......@@ -109,7 +109,7 @@
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/chat_viewer_paused.png -->
<string name="chat_state_paused">Entered text …</string>
<!-- 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 -->
<string name="export_chat">Export chat</string>
<!-- http://dl.dropbox.com/u/1029995/com.xabber.android/export_chat_done.png -->
......
......@@ -9,19 +9,26 @@
</array>
<array name="account_action_bar">
<item>@color/teal_500</item>
<item>@color/deep_orange_500</item>
<item>@color/pink_500</item>
<item>@color/dark_purple_500</item>
<item>@color/green_500</item>
<item>@color/orange_500</item>
<item>@color/red_500</item>
<item>@color/blue_500</item>
</array>
<array name="account_status_bar">
<item>@color/teal_700</item>
<item>@color/deep_orange_700</item>
<item>@color/pink_700</item>
<item>@color/dark_purple_700</item>
<item>@color/green_700</item>
<item>@color/orange_700</item>
<item>@color/red_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>
<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>
\ No newline at end of file
......@@ -13,7 +13,7 @@
along with this program. If not, see http://www.gnu.org/licenses/.
-->
<resources>
<style name="Theme" parent="Theme.AppCompat">
<style name="Theme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="expanderGroupColor">?android:attr/textColorPrimary</item>
<item name="expanderAccountColor">?android:attr/textColorPrimaryInverse</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