diff options
Diffstat (limited to 'src/main/java/eu/siacs/conversations/ui')
24 files changed, 810 insertions, 718 deletions
diff --git a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java index bd2042fb..b9e5c367 100644 --- a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java +++ b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java @@ -5,7 +5,7 @@ import android.content.Intent; import android.preference.Preference; import android.util.AttributeSet; -import eu.siacs.conversations.utils.PhoneHelper; +import de.thedevstack.conversationsplus.ConversationsPlusApplication; public class AboutPreference extends Preference { public AboutPreference(final Context context, final AttributeSet attrs, final int defStyle) { @@ -26,7 +26,7 @@ public class AboutPreference extends Preference { } private void setSummary() { - setSummary("Conversations " + PhoneHelper.getVersionName(getContext())); + setSummary(ConversationsPlusApplication.getNameAndVersion()); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java index ccb3a22e..9f4a4bc3 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java @@ -6,11 +6,12 @@ import android.widget.Button; import android.widget.EditText; import android.widget.Toast; +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.utils.ui.TextViewUtil; + import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; -import eu.siacs.conversations.xmpp.jid.InvalidJidException; -import eu.siacs.conversations.xmpp.jid.Jid; public class ChangePasswordActivity extends XmppActivity implements XmppConnectionService.OnAccountPasswordChanged { @@ -26,19 +27,20 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti mCurrentPassword.requestFocus(); mCurrentPassword.setError(getString(R.string.account_status_unauthorized)); } else if (!newPassword.equals(newPasswordConfirm)) { - mNewPasswordConfirm.requestFocus(); - mNewPasswordConfirm.setError(getString(R.string.passwords_do_not_match)); + mNewPasswordConfirm.requestFocus(); + mNewPasswordConfirm.setError(getString(R.string.passwords_do_not_match)); + } else if (newPassword.isEmpty()) { + mNewPassword.requestFocus(); + mNewPassword.setError(getString(R.string.password_should_not_be_empty)); } else if (newPassword.trim().isEmpty()) { mNewPassword.requestFocus(); - mNewPassword.setError(getString(R.string.password_should_not_be_empty)); + mNewPassword.setError(getString(R.string.password_should_not_contain_only_spaces)); } else { mCurrentPassword.setError(null); mNewPassword.setError(null); mNewPasswordConfirm.setError(null); xmppConnectionService.updateAccountPasswordOnServer(mAccount, newPassword, ChangePasswordActivity.this); - mChangePasswordButton.setEnabled(false); - mChangePasswordButton.setTextColor(getSecondaryTextColor()); - mChangePasswordButton.setText(R.string.updating); + TextViewUtil.disable(mChangePasswordButton, ConversationsPlusColors.secondaryText(), R.string.updating); } } } @@ -89,9 +91,7 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti @Override public void run() { mNewPassword.setError(getString(R.string.could_not_change_password)); - mChangePasswordButton.setEnabled(true); - mChangePasswordButton.setTextColor(getPrimaryTextColor()); - mChangePasswordButton.setText(R.string.change_password); + TextViewUtil.enable(mChangePasswordButton, ConversationsPlusColors.primaryText(), R.string.change_password); } }); diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index adbb0953..dec387b6 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -38,6 +38,7 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.User; +import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnMucRosterUpdate; @@ -509,7 +510,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers account = mConversation.getAccount().getJid().toBareJid().toString(); } mAccountJid.setText(getString(R.string.using_account, account)); - mYourPhoto.setImageBitmap(avatarService().get(mConversation.getAccount(), getPixel(48))); + mYourPhoto.setImageBitmap(AvatarService.getInstance().get(mConversation.getAccount(), getPixel(48))); setTitle(mConversation.getName()); if (Config.LOCK_DOMAINS_IN_CONVERSATIONS && mConversation.getJid().getDomainpart().equals(Config.CONFERENCE_DOMAIN_LOCK)) { mFullJid.setText(mConversation.getJid().getLocalpart()); @@ -603,7 +604,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } ImageView iv = (ImageView) view.findViewById(R.id.contact_photo); - iv.setImageBitmap(avatarService().get(user, getPixel(48), false)); + iv.setImageBitmap(AvatarService.getInstance().get(user, getPixel(48), false)); membersView.addView(view); if (mConversation.getMucOptions().canInvite()) { mInviteButton.setVisibility(View.VISIBLE); diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index e4fc59fa..b11564a9 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -6,10 +6,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender.SendIntentException; -import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; -import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.Contacts; @@ -34,6 +32,8 @@ import org.openintents.openpgp.util.OpenPgpUtils; import java.security.cert.X509Certificate; import java.util.List; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; @@ -42,6 +42,7 @@ import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.ListItem; +import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.utils.CryptoHelper; @@ -220,8 +221,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd getActionBar().setDisplayHomeAsUpEnabled(true); } - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false); + this.showDynamicTags = ConversationsPlusPreferences.showDynamicTags(); } @Override @@ -369,8 +369,9 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd } else { account = contact.getAccount().getJid().toBareJid().toString(); } + contactJidTv.setOnClickListener(new ShowResourcesListDialogListener(ContactDetailsActivity.this, contact)); accountJidTv.setText(getString(R.string.using_account, account)); - badge.setImageBitmap(avatarService().get(contact, getPixel(72))); + badge.setImageBitmap(AvatarService.getInstance().get(contact, getPixel(72))); badge.setOnClickListener(this.onBadgeClick); keys.removeAllViews(); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 184b5dc6..20c4685f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -43,10 +43,15 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import de.thedevstack.android.logcat.Logging; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog; +import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener; import de.timroes.android.listview.EnhancedListView; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; +import eu.siacs.conversations.crypto.axolotl.AxolotlServiceImpl; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Blockable; @@ -61,6 +66,7 @@ import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdat import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.ui.adapter.ConversationAdapter; import eu.siacs.conversations.utils.ExceptionHelper; +import eu.siacs.conversations.utils.FileUtils; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -225,6 +231,7 @@ public class ConversationActivity extends XmppActivity return null; } listAdapter.remove(swipedConversation); + Logging.d("markRead", "EnhancedListView.OnDismissCallback.onDismiss (" + swipedConversation.getName() + ")"); xmppConnectionService.markRead(swipedConversation); final boolean formerlySelected = (getSelectedConversation() == swipedConversation); @@ -274,6 +281,7 @@ public class ConversationActivity extends XmppActivity } }); listView.enableSwipeToDismiss(); + listView.setSwipeDirection(EnhancedListView.SwipeDirection.START); listView.setSwipingLayout(R.id.swipeable_item); listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP); listView.setUndoHideDelay(5000); @@ -285,9 +293,10 @@ public class ConversationActivity extends XmppActivity } if (mContentView instanceof SlidingPaneLayout) { SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; + // Move the conversation list when sliding the selected conversation mSlidingPaneLayout.setParallaxDistance(150); - mSlidingPaneLayout - .setShadowResource(R.drawable.es_slidingpane_shadow); + // The shadow between conversation list and selected conversation + mSlidingPaneLayout.setShadowResourceLeft(R.drawable.es_slidingpane_shadow); mSlidingPaneLayout.setSliderFadeColor(0); mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() { @@ -341,7 +350,7 @@ public class ConversationActivity extends XmppActivity if (titleShouldBeName && conversation != null) { ab.setDisplayHomeAsUpEnabled(true); ab.setHomeButtonEnabled(true); - if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { + if (conversation.getMode() == Conversation.MODE_SINGLE || ConversationsPlusPreferences.useSubject()) { ab.setTitle(conversation.getName()); } else { ab.setTitle(conversation.getJid().toBareJid().toString()); @@ -444,7 +453,7 @@ public class ConversationActivity extends XmppActivity chooser = true; break; case ATTACHMENT_CHOICE_TAKE_PHOTO: - Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri(); + Uri uri = FileBackend.getTakePhotoUri(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); mPendingImageUris.clear(); @@ -505,16 +514,16 @@ public class ConversationActivity extends XmppActivity } switch (attachmentChoice) { case ATTACHMENT_CHOICE_LOCATION: - getPreferences().edit().putString("recently_used_quick_action", "location").apply(); + ConversationsPlusPreferences.applyRecentlyUsedQuickAction("location"); break; case ATTACHMENT_CHOICE_RECORD_VOICE: - getPreferences().edit().putString("recently_used_quick_action", "voice").apply(); + ConversationsPlusPreferences.applyRecentlyUsedQuickAction("voice"); break; case ATTACHMENT_CHOICE_TAKE_PHOTO: - getPreferences().edit().putString("recently_used_quick_action", "photo").apply(); + ConversationsPlusPreferences.applyRecentlyUsedQuickAction("photo"); break; case ATTACHMENT_CHOICE_CHOOSE_IMAGE: - getPreferences().edit().putString("recently_used_quick_action", "picture").apply(); + ConversationsPlusPreferences.applyRecentlyUsedQuickAction("picture"); break; } final Conversation conversation = getSelectedConversation(); @@ -830,7 +839,7 @@ public class ConversationActivity extends XmppActivity } break; case R.id.encryption_choice_axolotl: - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(conversation.getAccount()) + Log.d(Config.LOGTAG, AxolotlServiceImpl.getLogprefix(conversation.getAccount()) + "Enabled axolotl for Contact " + conversation.getContact().getJid()); conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL); item.setChecked(true); @@ -1071,7 +1080,7 @@ public class ConversationActivity extends XmppActivity public void onResume() { super.onResume(); final int theme = findTheme(); - final boolean usingEnterKey = usingEnterKey(); + final boolean usingEnterKey = ConversationsPlusPreferences.displayEnterKey(); if (this.mTheme != theme || usingEnterKey != mUsingEnterKey) { recreate(); } @@ -1156,7 +1165,6 @@ public class ConversationActivity extends XmppActivity setSelectedConversation(conversationList.get(0)); this.mConversationFragment.reInit(getSelectedConversation()); } else { - this.mConversationFragment.messageListAdapter.updatePreferences(); this.mConversationFragment.messagesView.invalidateViews(); this.mConversationFragment.setupIme(); } @@ -1318,7 +1326,7 @@ public class ConversationActivity extends XmppActivity } }; if (c.getMode() == Conversation.MODE_MULTI - || FileBackend.allFilesUnderSize(this, uris, max) + || FileUtils.allFilesUnderSize(this, uris, max) || c.getNextEncryption() == Message.ENCRYPTION_OTR) { callback.onPresenceSelected(); } else { @@ -1462,28 +1470,9 @@ public class ConversationActivity extends XmppActivity if (conversation == null) { return; } - final Toast prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_image), Toast.LENGTH_LONG); - prepareFileToast.show(); - xmppConnectionService.attachImageToConversation(conversation, uri, - new UiCallback<Message>() { - - @Override - public void userInputRequried(PendingIntent pi, Message object) { - hidePrepareFileToast(prepareFileToast); - } - - @Override - public void success(Message message) { - hidePrepareFileToast(prepareFileToast); - xmppConnectionService.sendMessage(message); - } - - @Override - public void error(int error, Message message) { - hidePrepareFileToast(prepareFileToast); - displayErrorDialog(error); - } - }); + ResizePictureUserDecisionListener userDecisionListener = new ResizePictureUserDecisionListener(this, conversation, uri, xmppConnectionService); + UserDecisionDialog userDecisionDialog = new UserDecisionDialog(this, R.string.userdecision_question_resize_picture, userDecisionListener); + userDecisionDialog.decide(ConversationsPlusPreferences.resizePicture()); } private void hidePrepareFileToast(final Toast prepareFileToast) { @@ -1543,18 +1532,6 @@ public class ConversationActivity extends XmppActivity }); } - public boolean useSendButtonToIndicateStatus() { - return getPreferences().getBoolean("send_button_status", false); - } - - public boolean indicateReceived() { - return getPreferences().getBoolean("indicate_received", false); - } - - public boolean useWhiteBackground() { - return getPreferences().getBoolean("use_white_background",false); - } - protected boolean trustKeysIfNeeded(int requestCode) { return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID); } @@ -1624,10 +1601,6 @@ public class ConversationActivity extends XmppActivity xmppConnectionService.sendUnblockRequest(conversation); } - public boolean enterIsSend() { - return getPreferences().getBoolean("enter_is_send",false); - } - @Override public void onShowErrorToast(final int resId) { runOnUiThread(new Runnable() { @@ -1637,15 +1610,4 @@ public class ConversationActivity extends XmppActivity } }); } - - public boolean highlightSelectedConversations() { - return !isConversationsOverviewHideable() || this.conversationWasSelectedByKeyboard; - } - - public void setMessagesLoaded() { - if (mConversationFragment != null) { - mConversationFragment.setMessagesLoaded(); - mConversationFragment.updateMessages(); - } - } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 1a834ae5..50002189 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -8,6 +8,7 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.os.Bundle; import android.support.annotation.Nullable; @@ -28,19 +29,27 @@ import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.ListView; +import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; +import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayout; + import net.java.otr4j.session.SessionStatus; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.UUID; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.ui.dialogs.MessageDetailsDialog; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -51,9 +60,11 @@ import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presence; +import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.http.HttpDownloadConnection; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected; @@ -61,11 +72,15 @@ import eu.siacs.conversations.ui.XmppActivity.OnValueEdited; import eu.siacs.conversations.ui.adapter.MessageAdapter; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked; +import eu.siacs.conversations.ui.listeners.ConversationSwipeRefreshListener; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jid.Jid; +import github.ankushsachdeva.emojicon.EmojiconGridView; +import github.ankushsachdeva.emojicon.EmojiconsPopup; +import github.ankushsachdeva.emojicon.emoji.Emojicon; public class ConversationFragment extends Fragment implements EditMessage.KeyboardListener { @@ -104,113 +119,19 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } }; protected ListView messagesView; + protected SwipyRefreshLayout swipeLayout; final protected List<Message> messageList = new ArrayList<>(); protected MessageAdapter messageListAdapter; private EditMessage mEditMessage; private ImageButton mSendButton; + private ImageView mEmojButton; + private View mRootView; + private EmojiconsPopup mEmojPopup; private RelativeLayout snackbar; private TextView snackbarMessage; private TextView snackbarAction; private boolean messagesLoaded = true; private Toast messageLoaderToast; - - private OnScrollListener mOnScrollListener = new OnScrollListener() { - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - // TODO Auto-generated method stub - - } - - private int getIndexOf(String uuid, List<Message> messages) { - if (uuid == null) { - return messages.size() - 1; - } - for(int i = 0; i < messages.size(); ++i) { - if (uuid.equals(messages.get(i).getUuid())) { - return i; - } else { - Message next = messages.get(i); - while(next != null && next.wasMergedIntoPrevious()) { - if (uuid.equals(next.getUuid())) { - return i; - } - next = next.next(); - } - - } - } - return 0; - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, - int visibleItemCount, int totalItemCount) { - synchronized (ConversationFragment.this.messageList) { - if (firstVisibleItem < 5 && messagesLoaded && messageList.size() > 0) { - long timestamp; - if (messageList.get(0).getType() == Message.TYPE_STATUS && messageList.size() >= 2) { - timestamp = messageList.get(1).getTimeSent(); - } else { - timestamp = messageList.get(0).getTimeSent(); - } - messagesLoaded = false; - activity.xmppConnectionService.loadMoreMessages(conversation, timestamp, new XmppConnectionService.OnMoreMessagesLoaded() { - @Override - public void onMoreMessagesLoaded(final int c, Conversation conversation) { - if (ConversationFragment.this.conversation != conversation) { - return; - } - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - final int oldPosition = messagesView.getFirstVisiblePosition(); - final Message message; - if (oldPosition < messageList.size()) { - message = messageList.get(oldPosition); - } else { - message = null; - } - String uuid = message != null ? message.getUuid() : null; - View v = messagesView.getChildAt(0); - final int pxOffset = (v == null) ? 0 : v.getTop(); - ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); - updateStatusMessages(); - messageListAdapter.notifyDataSetChanged(); - int pos = getIndexOf(uuid,messageList); - messagesView.setSelectionFromTop(pos, pxOffset); - messagesLoaded = true; - if (messageLoaderToast != null) { - messageLoaderToast.cancel(); - } - } - }); - } - - @Override - public void informUser(final int resId) { - - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - if (messageLoaderToast != null) { - messageLoaderToast.cancel(); - } - if (ConversationFragment.this.conversation != conversation) { - return; - } - messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG); - messageLoaderToast.show(); - } - }); - - } - }); - - } - } - } - }; private final int KEYCHAIN_UNLOCK_NOT_REQUIRED = 0; private final int KEYCHAIN_UNLOCK_REQUIRED = 1; private final int KEYCHAIN_UNLOCK_PENDING = 2; @@ -300,14 +221,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_CHOOSE_IMAGE); break; case CANCEL: - if (conversation != null) { - if (conversation.getCorrectingMessage() != null) { - conversation.setCorrectingMessage(null); - mEditMessage.getEditableText().clear(); - } - if (conversation.getMode() == Conversation.MODE_MULTI) { - conversation.setNextCounterpart(null); - } + if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { + conversation.setNextCounterpart(null); updateChatMsgHint(); updateSendButton(); } @@ -342,21 +257,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (body.length() == 0 || this.conversation == null) { return; } - final Message message; - if (conversation.getCorrectingMessage() == null) { - message = new Message(conversation, body, conversation.getNextEncryption()); - if (conversation.getMode() == Conversation.MODE_MULTI) { - if (conversation.getNextCounterpart() != null) { - message.setCounterpart(conversation.getNextCounterpart()); - message.setType(Message.TYPE_PRIVATE); - } + Message message = new Message(conversation, body, conversation.getNextEncryption()); + if (conversation.getMode() == Conversation.MODE_MULTI) { + if (conversation.getNextCounterpart() != null) { + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_PRIVATE); } - } else { - message = conversation.getCorrectingMessage(); - message.setBody(body); - message.setEdited(message.getUuid()); - message.setUuid(UUID.randomUUID().toString()); - conversation.setCorrectingMessage(null); } switch (conversation.getNextEncryption()) { case Message.ENCRYPTION_OTR: @@ -377,9 +283,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa public void updateChatMsgHint() { final boolean multi = conversation.getMode() == Conversation.MODE_MULTI; - if (conversation.getCorrectingMessage() != null) { - this.mEditMessage.setHint(R.string.send_corrected_message); - } else if (multi && conversation.getNextCounterpart() != null) { + if (multi && conversation.getNextCounterpart() != null) { this.mEditMessage.setHint(getString( R.string.send_private_message_to, conversation.getNextCounterpart().getResourcepart())); @@ -415,7 +319,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa public void setupIme() { if (activity == null) { return; - } else if (activity.usingEnterKey() && activity.enterIsSend()) { + } else if (activity.usingEnterKey() && ConversationsPlusPreferences.enterIsSend()) { mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE)); mEditMessage.setInputType(mEditMessage.getInputType() & (~InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)); } else if (activity.usingEnterKey()) { @@ -443,6 +347,107 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa }); mEditMessage.setOnEditorActionListener(mEditorActionListener); + // Start of emojicon + mEmojButton = (ImageView) view.findViewById(R.id.emoji_btn); + mRootView = view.findViewById(R.id.textsend); + + // Give the topmost view of your activity layout hierarchy. This will be used to measure soft keyboard height + mEmojPopup = new EmojiconsPopup(mRootView, this.getActivity()); + + //Will automatically set size according to the soft keyboard size + mEmojPopup.setSizeForSoftKeyboard(); + + //If the emoji popup is dismissed, change emojiButton to smiley icon + mEmojPopup.setOnDismissListener(new PopupWindow.OnDismissListener() { + + @Override + public void onDismiss() { + changeEmojiKeyboardIcon(mEmojButton, R.drawable.smiley); + } + }); + + //If the text keyboard closes, also dismiss the emoji popup + mEmojPopup.setOnSoftKeyboardOpenCloseListener(new EmojiconsPopup.OnSoftKeyboardOpenCloseListener() { + + @Override + public void onKeyboardOpen(int keyBoardHeight) { + + } + + @Override + public void onKeyboardClose() { + if (mEmojPopup.isShowing()) + mEmojPopup.dismiss(); + } + }); + + //On emoji clicked, add it to edittext + mEmojPopup.setOnEmojiconClickedListener(new EmojiconGridView.OnEmojiconClickedListener() { + + @Override + public void onEmojiconClicked(Emojicon emojicon) { + if (mEditMessage == null || emojicon == null) { + return; + } + + int start = mEditMessage.getSelectionStart(); + int end = mEditMessage.getSelectionEnd(); + if (start < 0) { + mEditMessage.append(emojicon.getEmoji()); + } else { + mEditMessage.getText().replace(Math.min(start, end), + Math.max(start, end), emojicon.getEmoji(), 0, + emojicon.getEmoji().length()); + } + } + }); + + //On backspace clicked, emulate the KEYCODE_DEL key event + mEmojPopup.setOnEmojiconBackspaceClickedListener(new EmojiconsPopup.OnEmojiconBackspaceClickedListener() { + + @Override + public void onEmojiconBackspaceClicked(View v) { + KeyEvent event = new KeyEvent( + 0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL); + mEditMessage.dispatchKeyEvent(event); + } + }); + + // To toggle between text keyboard and emoji keyboard keyboard(Popup) + mEmojButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + //If popup is not showing => emoji keyboard is not visible, we need to show it + if(!mEmojPopup.isShowing()){ + + //If keyboard is visible, simply show the emoji popup + if(mEmojPopup.isKeyBoardOpen()){ + mEmojPopup.showAtBottom(); + changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard); + } + + //else, open the text keyboard first and immediately after that show the emoji popup + else{ + mEditMessage.setFocusableInTouchMode(true); + mEditMessage.requestFocus(); + mEmojPopup.showAtBottomPending(); + final InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.showSoftInput(mEditMessage, InputMethodManager.SHOW_IMPLICIT); + changeEmojiKeyboardIcon(mEmojButton, R.drawable.ic_action_keyboard); + } + } + + //If popup is showing, simply dismiss it to show the undelying text keyboard + else{ + mEmojPopup.dismiss(); + } + } + }); + + // End of emojicon + mSendButton = (ImageButton) view.findViewById(R.id.textSendButton); mSendButton.setOnClickListener(this.mSendButtonListener); @@ -451,7 +456,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa snackbarAction = (TextView) view.findViewById(R.id.snackbar_action); messagesView = (ListView) view.findViewById(R.id.messages_view); - messagesView.setOnScrollListener(mOnScrollListener); messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL); messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList); messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() { @@ -506,6 +510,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa registerForContextMenu(messagesView); + // Start of swipe refresh + // New Swipe refresh + swipeLayout = (SwipyRefreshLayout) view.findViewById(R.id.swipe_refresh_container); + swipeLayout.setOnRefreshListener(new ConversationSwipeRefreshListener(messageList, swipeLayout, this, messagesView, messageListAdapter)); + // End of swipe refresh + return view; } @@ -522,10 +532,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa private void populateContextMenu(ContextMenu menu) { final Message m = this.selectedMessage; final Transferable t = m.getTransferable(); - Message relevantForCorrection = m; - while(relevantForCorrection.mergeable(relevantForCorrection.next())) { - relevantForCorrection = relevantForCorrection.next(); - } if (m.getType() != Message.TYPE_STATUS) { final boolean treatAsFile = m.getType() != Message.TYPE_TEXT && m.getType() != Message.TYPE_PRIVATE @@ -534,7 +540,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa menu.setHeaderTitle(R.string.message_options); MenuItem copyText = menu.findItem(R.id.copy_text); MenuItem retryDecryption = menu.findItem(R.id.retry_decryption); - MenuItem correctMessage = menu.findItem(R.id.correct_message); MenuItem shareWith = menu.findItem(R.id.share_with); MenuItem sendAgain = menu.findItem(R.id.send_again); MenuItem copyUrl = menu.findItem(R.id.copy_url); @@ -549,10 +554,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { retryDecryption.setVisible(true); } - if (relevantForCorrection.getType() == Message.TYPE_TEXT - && relevantForCorrection.isLastCorrectableMessage()) { - correctMessage.setVisible(true); - } if (treatAsFile || (GeoHelper.isGeoUri(m.getBody()))) { shareWith.setVisible(true); } @@ -566,7 +567,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa copyUrl.setVisible(true); } if ((m.getType() == Message.TYPE_TEXT && t == null && m.treatAsDownloadable() != Message.Decision.NEVER) - || (m.isFileOrImage() && t instanceof TransferablePlaceholder && m.hasFileOnRemoteHost())){ + || (t instanceof TransferablePlaceholder && m.hasFileOnRemoteHost())){ downloadFile.setVisible(true); downloadFile.setTitle(activity.getString(R.string.download_x_file,UIHelper.getFileDescriptionString(activity, m))); } @@ -585,15 +586,15 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { + case R.id.msg_ctx_mnu_details: + new MessageDetailsDialog(getActivity(), selectedMessage).show(); + return true; case R.id.share_with: shareWith(selectedMessage); return true; case R.id.copy_text: copyText(selectedMessage); return true; - case R.id.correct_message: - correctMessage(selectedMessage); - return true; case R.id.send_again: resendMessage(selectedMessage); return true; @@ -625,8 +626,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa shareIntent.setType("text/plain"); } else { shareIntent.putExtra(Intent.EXTRA_STREAM, - activity.xmppConnectionService.getFileBackend() - .getJingleFileUri(message)); + FileBackend.getJingleFileUri(message)); shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); String mime = message.getMimeType(); if (mime == null) { @@ -643,7 +643,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } private void copyText(Message message) { - if (activity.copyTextToClipboard(message.getMergedBody(), + if (activity.copyTextToClipboard(message.getBody(), R.string.message_text)) { Toast.makeText(activity, R.string.message_copied_to_clipboard, Toast.LENGTH_SHORT).show(); @@ -651,21 +651,19 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } private void deleteFile(Message message) { - if (activity.xmppConnectionService.getFileBackend().deleteFile(message)) { + if (FileBackend.deleteFile(message, activity.xmppConnectionService)) { message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); - activity.updateConversationList(); - updateMessages(); + activity.xmppConnectionService.updateConversationUi(); } } private void resendMessage(Message message) { if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) { - DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + DownloadableFile file = FileBackend.getFile(message); if (!file.exists()) { Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show(); message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); - activity.updateConversationList(); - updateMessages(); + activity.xmppConnectionService.updateConversationUi(); return; } } @@ -682,7 +680,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa resId = R.string.file_url; url = message.getFileParams().url.toString(); } else { - url = message.getBody().trim(); + url = message.getBody(); resId = R.string.file_url; } if (activity.copyTextToClipboard(url, resId)) { @@ -707,8 +705,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa private void retryDecryption(Message message) { message.setEncryption(Message.ENCRYPTION_PGP); - activity.updateConversationList(); - updateMessages(); + activity.xmppConnectionService.updateConversationUi(); conversation.getAccount().getPgpDecryptionService().add(message); } @@ -719,18 +716,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateSendButton(); } - private void correctMessage(Message message) { - while(message.mergeable(message.next())) { - message = message.next(); - } - this.conversation.setCorrectingMessage(message); - this.mEditMessage.getEditableText().clear(); - this.mEditMessage.getEditableText().append(message.getBody()); - - } - protected void highlightInConference(String nick) { - String oldString = mEditMessage.getText().toString().trim(); + String oldString = mEditMessage.getText().toString(); if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) { mEditMessage.getText().insert(0, nick + ": "); } else { @@ -785,7 +772,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.mEditMessage.setText(""); this.mEditMessage.append(this.conversation.getNextMessage()); this.mEditMessage.setKeyboardListener(this); - messageListAdapter.updatePreferences(); this.messagesView.setAdapter(messageListAdapter); updateMessages(); this.messagesLoaded = true; @@ -793,6 +779,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (size > 0) { messagesView.setSelection(size - 1); } + swipeLayout.setRefreshing(false); } private OnClickListener mEnableAccountListener = new OnClickListener() { @@ -1051,9 +1038,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final String text = this.mEditMessage == null ? "" : this.mEditMessage.getText().toString(); final boolean empty = text.length() == 0; final boolean conference = c.getMode() == Conversation.MODE_MULTI; - if (c.getCorrectingMessage() != null && (empty || text.equals(c.getCorrectingMessage().getBody()))) { - action = SendButtonAction.CANCEL; - } else if (conference && !c.getAccount().httpUploadAvailable()) { + if (conference && !c.getAccount().httpUploadAvailable()) { if (empty && c.getNextCounterpart() != null) { action = SendButtonAction.CANCEL; } else { @@ -1064,11 +1049,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (conference && c.getNextCounterpart() != null) { action = SendButtonAction.CANCEL; } else { - String setting = activity.getPreferences().getString("quick_action", "recent"); + String setting = ConversationsPlusPreferences.quickAction(); if (!setting.equals("none") && UIHelper.receivedLocationQuestion(conversation.getLatestMessage())) { setting = "location"; } else if (setting.equals("recent")) { - setting = activity.getPreferences().getString("recently_used_quick_action", "text"); + setting = ConversationsPlusPreferences.recentlyUsedQuickAction(); } switch (setting) { case "photo": @@ -1092,7 +1077,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa action = SendButtonAction.TEXT; } } - if (activity.useSendButtonToIndicateStatus() && c != null + if (ConversationsPlusPreferences.sendButtonStatus() && c != null && c.getAccount().getStatus() == Account.State.ONLINE) { if (c.getMode() == Conversation.MODE_SINGLE) { status = c.getContact().getMostAvailableStatus(); @@ -1106,11 +1091,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.mSendButton.setImageResource(getSendButtonImageResource(action, status)); } - protected void updateStatusMessages() { + public void updateStatusMessages() { synchronized (this.messageList) { - if (showLoadMoreMessages(conversation)) { - this.messageList.add(0, Message.createLoadMoreMessage(conversation)); - } if (conversation.getMode() == Conversation.MODE_SINGLE) { ChatState state = conversation.getIncomingChatState(); if (state == ChatState.COMPOSING) { @@ -1134,21 +1116,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } - private boolean showLoadMoreMessages(final Conversation c) { - final boolean mam = hasMamSupport(c); - final MessageArchiveService service = activity.xmppConnectionService.getMessageArchiveService(); - return mam && (c.getLastClearHistory() != 0 || (c.countMessages() == 0 && c.hasMessagesLeftOnServer() && !service.queryInProgress(c))); - } - - private boolean hasMamSupport(final Conversation c) { - if (c.getMode() == Conversation.MODE_SINGLE) { - final XmppConnection connection = c.getAccount().getXmppConnection(); - return connection != null && connection.getFeatures().mam(); - } else { - return c.getMucOptions().mamSupport(); - } - } - protected void showSnackbar(final int message, final int action, final OnClickListener clickListener) { snackbar.setVisibility(View.VISIBLE); snackbar.setOnClickListener(null); @@ -1309,7 +1276,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa @Override public boolean onEnterPressed() { - if (activity.enterIsSend()) { + if (ConversationsPlusPreferences.enterIsSend()) { sendMessage(); return true; } else { @@ -1344,13 +1311,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateSendButton(); } - @Override - public void onTextChanged() { - if (conversation != null && conversation.getCorrectingMessage() != null) { - updateSendButton(); - } - } - private int completionIndex = 0; private int lastCompletionLength = 0; private String incomplete; @@ -1417,4 +1377,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } + private void changeEmojiKeyboardIcon(ImageView iconToBeChanged, int drawableResourceId){ + iconToBeChanged.setImageResource(drawableResourceId); + } + } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 9d73290a..13fcc9a5 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -38,13 +38,18 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener; +import de.thedevstack.conversationsplus.utils.ui.TextViewUtil; + import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested; +import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; +import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; @@ -114,6 +119,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !accountInfoEdited()) { mAccount.setOption(Account.OPTION_DISABLED, false); + mAccount.setStatus(Account.State.CONNECTING); xmppConnectionService.updateAccount(mAccount); return; } @@ -239,7 +245,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } else if (mInitMode && mAccount != null && mAccount.getStatus() == Account.State.ONLINE) { if (!mFetchingAvatar) { mFetchingAvatar = true; - xmppConnectionService.checkForAvatar(mAccount, mAvatarFetchCallback); + AvatarService.getInstance().checkForAvatar(mAccount, mAvatarFetchCallback); } } else { updateSaveButton(); @@ -332,26 +338,18 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate protected void updateSaveButton() { if (accountInfoEdited() && !mInitMode) { - this.mSaveButton.setText(R.string.save); - this.mSaveButton.setEnabled(true); - this.mSaveButton.setTextColor(getPrimaryTextColor()); + TextViewUtil.enable(mSaveButton, ConversationsPlusColors.primaryText(), R.string.save); } else if (mAccount != null && (mAccount.getStatus() == Account.State.CONNECTING || mFetchingAvatar)) { - this.mSaveButton.setEnabled(false); - this.mSaveButton.setTextColor(getSecondaryTextColor()); - this.mSaveButton.setText(R.string.account_status_connecting); + TextViewUtil.disable(mSaveButton, ConversationsPlusColors.secondaryText(), R.string.account_status_connecting); } else if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !mInitMode) { - this.mSaveButton.setEnabled(true); - this.mSaveButton.setTextColor(getPrimaryTextColor()); - this.mSaveButton.setText(R.string.enable); + TextViewUtil.enable(mSaveButton, ConversationsPlusColors.primaryText(), R.string.enable); } else { - this.mSaveButton.setEnabled(true); - this.mSaveButton.setTextColor(getPrimaryTextColor()); + TextViewUtil.enable(mSaveButton, ConversationsPlusColors.primaryText()); if (!mInitMode) { if (mAccount != null && mAccount.isOnlineAndConnected()) { this.mSaveButton.setText(R.string.save); if (!accountInfoEdited()) { - this.mSaveButton.setEnabled(false); - this.mSaveButton.setTextColor(getSecondaryTextColor()); + TextViewUtil.disable(mSaveButton, ConversationsPlusColors.secondaryText()); } } else { this.mSaveButton.setText(R.string.connect); @@ -526,9 +524,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } } SharedPreferences preferences = getPreferences(); - boolean useTor = Config.FORCE_ORBOT || preferences.getBoolean("use_tor", false); - this.mShowOptions = useTor || preferences.getBoolean("show_connection_options", false); - mHostname.setHint(useTor ? R.string.hostname_or_onion : R.string.hostname_example); + this.mShowOptions = preferences.getBoolean("show_connection_options", false); this.mNamePort.setVisibility(mShowOptions ? View.VISIBLE : View.GONE); } @@ -550,9 +546,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate getActionBar().setDisplayHomeAsUpEnabled(false); getActionBar().setDisplayShowHomeEnabled(false); getActionBar().setHomeButtonEnabled(false); - } - this.mCancelButton.setEnabled(false); - this.mCancelButton.setTextColor(getSecondaryTextColor()); + } + TextViewUtil.disable(mCancelButton, ConversationsPlusColors.secondaryText()); } if (Config.DOMAIN_LOCK == null) { final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this, @@ -630,7 +625,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate if (!mInitMode) { this.mAvatar.setVisibility(View.VISIBLE); - this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72))); + this.mAvatar.setImageBitmap(AvatarService.getInstance().get(this.mAccount, getPixel(72))); } if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) { this.mRegisterNew.setVisibility(View.VISIBLE); @@ -641,6 +636,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mRegisterNew.setChecked(false); } if (this.mAccount.isOnlineAndConnected() && !this.mFetchingAvatar) { + this.findViewById(R.id.editAccountBoxes).setVisibility(View.GONE); + this.findViewById(R.id.displayAccountFrame).setVisibility(View.VISIBLE); + TextView detailsAccountJid = (TextView)this.findViewById(R.id.detailsAccountJid); + if (this.mAccount.countPresences() > 0) { + detailsAccountJid.setText(this.mAccount.getJid().toBareJid().toString() + " (" + this.mAccount.countPresences() + ")"); + detailsAccountJid.setOnClickListener(new ShowResourcesListDialogListener(EditAccountActivity.this, this.mAccount.getRoster().getContact(this.mAccount.getJid().toBareJid()))); + } else { + detailsAccountJid.setText(this.mAccount.getJid().toBareJid().toString()); + } Features features = this.mAccount.getXmppConnection().getFeatures(); this.mStats.setVisibility(View.VISIBLE); boolean showOptimizingWarning = !xmppConnectionService.getPushManagementService().available(mAccount) && isOptimizingBattery(); diff --git a/src/main/java/eu/siacs/conversations/ui/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/EditMessage.java index e3841d1d..06868a98 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditMessage.java +++ b/src/main/java/eu/siacs/conversations/ui/EditMessage.java @@ -4,11 +4,11 @@ import android.content.Context; import android.os.Handler; import android.util.AttributeSet; import android.view.KeyEvent; -import android.widget.EditText; import eu.siacs.conversations.Config; +import github.ankushsachdeva.emojicon.EmojiconEditText; -public class EditMessage extends EditText { +public class EditMessage extends EmojiconEditText { public EditMessage(Context context, AttributeSet attrs) { super(context, attrs); @@ -69,7 +69,6 @@ public class EditMessage extends EditText { this.isUserTyping = false; this.keyboardListener.onTextDeleted(); } - this.keyboardListener.onTextChanged(); } } @@ -85,7 +84,6 @@ public class EditMessage extends EditText { void onTypingStarted(); void onTypingStopped(); void onTextDeleted(); - void onTextChanged(); boolean onTabPressed(boolean repeated); } diff --git a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java index feac2c62..c83a0275 100644 --- a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -21,6 +21,8 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.Toast; +import org.openintents.openpgp.util.OpenPgpApi; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -34,8 +36,6 @@ import eu.siacs.conversations.ui.adapter.AccountAdapter; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -import org.openintents.openpgp.util.OpenPgpApi; - public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated { private final String STATE_SELECTED_ACCOUNT = "selected_account"; diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index 88645c4a..1916947b 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -4,6 +4,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.view.Menu; @@ -19,10 +20,17 @@ import android.widget.Toast; import com.soundcloud.android.crop.Crop; import java.io.File; +import java.io.FileNotFoundException; + +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.utils.ImageUtil; +import de.thedevstack.conversationsplus.utils.ui.TextViewUtil; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.AvatarService; +import eu.siacs.conversations.utils.ExifHelper; import eu.siacs.conversations.utils.FileUtils; import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.xmpp.pep.Avatar; @@ -80,9 +88,8 @@ public class PublishProfilePictureActivity extends XmppActivity { @Override public void run() { hintOrWarning.setText(errorCode); - hintOrWarning.setTextColor(getWarningTextColor()); - publishButton.setText(R.string.publish); - enablePublishButton(); + hintOrWarning.setTextColor(ConversationsPlusColors.warning()); + TextViewUtil.enable(publishButton, ConversationsPlusColors.primaryText(), R.string.publish); } }); @@ -108,9 +115,8 @@ public class PublishProfilePictureActivity extends XmppActivity { @Override public void onClick(View v) { if (avatarUri != null) { - publishButton.setText(R.string.publishing); - disablePublishButton(); - xmppConnectionService.publishAvatar(account, avatarUri, + TextViewUtil.disable(publishButton, ConversationsPlusColors.secondaryText(), R.string.publishing); + AvatarService.getInstance().publishAvatar(account, avatarUri, avatarPublication); } } @@ -190,7 +196,7 @@ public class PublishProfilePictureActivity extends XmppActivity { switch (requestCode) { case REQUEST_CHOOSE_FILE_AND_CROP: Uri source = data.getData(); - String original = FileUtils.getPath(this, source); + String original = FileUtils.getPath(source); if (original != null) { source = Uri.parse("file://"+original); } @@ -231,7 +237,7 @@ public class PublishProfilePictureActivity extends XmppActivity { if (this.avatarUri == null) { if (this.account.getAvatar() != null || this.defaultUri == null) { - this.avatar.setImageBitmap(avatarService().get(account, getPixel(192))); + this.avatar.setImageBitmap(AvatarService.getInstance().get(account, getPixel(192))); if (this.defaultUri != null) { this.avatar .setOnLongClickListener(this.backToDefaultListener); @@ -240,7 +246,7 @@ public class PublishProfilePictureActivity extends XmppActivity { } if (!support) { this.hintOrWarning - .setTextColor(getWarningTextColor()); + .setTextColor(ConversationsPlusColors.warning()); this.hintOrWarning .setText(R.string.error_publish_avatar_no_server_support); } @@ -276,27 +282,26 @@ public class PublishProfilePictureActivity extends XmppActivity { protected void loadImageIntoPreview(Uri uri) { Bitmap bm = null; try { - bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, getPixel(192)); + bm = ImageUtil.cropCenterSquare(uri, getPixel(192)); } catch (Exception e) { e.printStackTrace(); } if (bm == null) { - disablePublishButton(); - this.hintOrWarning.setTextColor(getWarningTextColor()); + TextViewUtil.disable(this.publishButton, ConversationsPlusColors.secondaryText()); + this.hintOrWarning.setTextColor(ConversationsPlusColors.warning()); this.hintOrWarning .setText(R.string.error_publish_avatar_converting); return; } this.avatar.setImageBitmap(bm); if (support) { - enablePublishButton(); - this.publishButton.setText(R.string.publish); + TextViewUtil.enable(this.publishButton, ConversationsPlusColors.primaryText(), R.string.publish); this.hintOrWarning.setText(R.string.publish_avatar_explanation); - this.hintOrWarning.setTextColor(getPrimaryTextColor()); + this.hintOrWarning.setTextColor(ConversationsPlusColors.primaryText()); } else { - disablePublishButton(); - this.hintOrWarning.setTextColor(getWarningTextColor()); + TextViewUtil.disable(this.publishButton, ConversationsPlusColors.secondaryText()); + this.hintOrWarning.setTextColor(ConversationsPlusColors.warning()); this.hintOrWarning .setText(R.string.error_publish_avatar_no_server_support); } @@ -309,16 +314,6 @@ public class PublishProfilePictureActivity extends XmppActivity { } } - protected void enablePublishButton() { - this.publishButton.setEnabled(true); - this.publishButton.setTextColor(getPrimaryTextColor()); - } - - protected void disablePublishButton() { - this.publishButton.setEnabled(false); - this.publishButton.setTextColor(getSecondaryTextColor()); - } - public void refreshUiReal() { //nothing to do. This Activity doesn't implement any listeners } diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index 750a7421..5b1978c4 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -9,6 +9,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; +import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceCategory; @@ -25,11 +26,14 @@ import java.util.List; import java.util.Locale; import de.duenndns.ssl.MemorizingTrustManager; +import de.tzur.conversations.Settings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.ExportLogsService; import eu.siacs.conversations.xmpp.XmppConnection; +import github.ankushsachdeva.emojicon.EmojiconHandler; public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener { @@ -67,14 +71,6 @@ public class SettingsActivity extends XmppActivity implements } } - if (Config.FORCE_ORBOT) { - PreferenceCategory connectionOptions = (PreferenceCategory) mSettingsFragment.findPreference("connection_options"); - PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert"); - if (connectionOptions != null) { - expert.removePreference(connectionOptions); - } - } - final Preference removeCertsPreference = mSettingsFragment.findPreference("remove_trusted_certificates"); removeCertsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override @@ -106,45 +102,42 @@ public class SettingsActivity extends XmppActivity implements } }); - dialogBuilder.setPositiveButton( - getResources().getString(R.string.dialog_manage_certs_positivebutton), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - int count = selectedItems.size(); - if (count > 0) { - for (int i = 0; i < count; i++) { - try { - Integer item = Integer.valueOf(selectedItems.get(i).toString()); - String alias = aliases.get(item); - mtm.deleteCertificate(alias); - } catch (KeyStoreException e) { - e.printStackTrace(); - displayToast("Error: " + e.getLocalizedMessage()); - } - } - if (xmppConnectionServiceBound) { - reconnectAccounts(); - } - displayToast(getResources().getQuantityString(R.plurals.toast_delete_certificates, count, count)); - } - } - }); - dialogBuilder.setNegativeButton(getResources().getString(R.string.dialog_manage_certs_negativebutton), null); - AlertDialog removeCertsDialog = dialogBuilder.create(); - removeCertsDialog.show(); - removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); - return true; - } - }); - - final Preference exportLogsPreference = mSettingsFragment.findPreference("export_logs"); - exportLogsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - hasStoragePermission(REQUEST_WRITE_LOGS); - return true; - } - }); + dialogBuilder.setPositiveButton( + getResources().getString(R.string.dialog_manage_certs_positivebutton), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + int count = selectedItems.size(); + if (count > 0) { + for (int i = 0; i < count; i++) { + try { + Integer item = Integer.valueOf(selectedItems.get(i).toString()); + String alias = aliases.get(item); + mtm.deleteCertificate(alias); + } catch (KeyStoreException e) { + e.printStackTrace(); + displayToast("Error: " + e.getLocalizedMessage()); + } + } + if (xmppConnectionServiceBound) { + reconnectAccounts(); + } + displayToast(getResources().getQuantityString(R.plurals.toast_delete_certificates, count, count)); + } + } + }); + dialogBuilder.setNegativeButton(getResources().getString(R.string.dialog_manage_certs_negativebutton), null); + AlertDialog removeCertsDialog = dialogBuilder.create(); + removeCertsDialog.show(); + removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + return true; + } + }); + // Avoid appearence of setting to enable or disable omemo in screen + Preference omemoEnabledPreference = this.mSettingsFragment.findPreference("omemo_enabled"); + PreferenceCategory otherExpertSettingsGroup = (PreferenceCategory) this.mSettingsFragment.findPreference("other_expert_settings"); + if (null != omemoEnabledPreference && null != otherExpertSettingsGroup) { + otherExpertSettingsGroup.removePreference(omemoEnabledPreference); + } } @Override @@ -157,11 +150,12 @@ public class SettingsActivity extends XmppActivity implements @Override public void onSharedPreferenceChanged(SharedPreferences preferences, String name) { final List<String> resendPresence = Arrays.asList( - "confirm_messages", + "confirm_messages_list", "xa_on_silent_mode", "away_when_screen_off", - "allow_message_correction", "treat_vibrate_as_silent"); + // need to synchronize the settings class first + Settings.synchronizeSettingsClassWithPreferences(preferences, name); if (name.equals("resource")) { String resource = preferences.getString("resource", "mobile") .toLowerCase(Locale.US); @@ -190,8 +184,10 @@ public class SettingsActivity extends XmppActivity implements } else if (name.equals("dont_trust_system_cas")) { xmppConnectionService.updateMemorizingTrustmanager(); reconnectAccounts(); - } else if (name.equals("use_tor")) { - reconnectAccounts(); + } else if ("parse_emoticons".equals(name)) { + EmojiconHandler.setParseEmoticons(Settings.PARSE_EMOTICONS); + } else if ("file_transfer_folder".equals(name)) { + FileBackend.createNoMedia(); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index 8cd017bf..6ea011f8 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -19,6 +19,10 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog; +import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener; +import de.thedevstack.conversationsplus.ui.listeners.ShareWithResizePictureUserDecisionListener; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; @@ -27,6 +31,7 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.adapter.ConversationAdapter; +import eu.siacs.conversations.utils.FileUtils; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -275,30 +280,35 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer final long max = account.getXmppConnection() .getFeatures() .getMaxHttpUploadSize(); - OnPresenceSelected callback = new OnPresenceSelected() { - @Override - public void onPresenceSelected() { - attachmentCounter.set(share.uris.size()); - if (share.image) { - share.multiple = share.uris.size() > 1; - replaceToast(getString(share.multiple ? R.string.preparing_images : R.string.preparing_image)); - for (Iterator<Uri> i = share.uris.iterator(); i.hasNext(); i.remove()) { - ShareWithActivity.this.xmppConnectionService - .attachImageToConversation(conversation, i.next(), - attachFileCallback); - } - } else { + OnPresenceSelected callback; + if (this.share.image) { + // TODO: attachementCounter should be set and decremented correctly + callback = new OnPresenceSelected() { + @Override + public void onPresenceSelected() { + ResizePictureUserDecisionListener userDecisionListener = new ShareWithResizePictureUserDecisionListener(ShareWithActivity.this, conversation, xmppConnectionService, share.uris); + UserDecisionDialog userDecisionDialog = new UserDecisionDialog(ShareWithActivity.this, R.string.userdecision_question_resize_picture, userDecisionListener); + userDecisionDialog.decide(ConversationsPlusPreferences.resizePicture()); + } + }; + } else { + attachmentCounter.set(share.uris.size()); + callback = new OnPresenceSelected() { + @Override + public void onPresenceSelected() { replaceToast(getString(R.string.preparing_file)); ShareWithActivity.this.xmppConnectionService .attachFileToConversation(conversation, share.uris.get(0), attachFileCallback); + switchToConversation(conversation, null, true); + finish(); } - } - }; + }; + } if (account.httpUploadAvailable() && ((share.image && !neverCompressPictures()) || conversation.getMode() == Conversation.MODE_MULTI - || FileBackend.allFilesUnderSize(this, share.uris, max)) + || FileUtils.allFilesUnderSize(this, share.uris, max)) && conversation.getNextEncryption() != Message.ENCRYPTION_OTR) { callback.onPresenceSelected(); } else { @@ -306,6 +316,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer } } else { switchToConversation(conversation, this.share.text, true); + finish(); } } diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 7d650e5b..a6468970 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -26,7 +26,6 @@ import android.support.v13.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.text.Editable; import android.text.TextWatcher; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; @@ -56,6 +55,8 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import de.thedevstack.android.logcat.Logging; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; @@ -192,6 +193,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_start_conversation); + this.mHideOfflineContacts = ConversationsPlusPreferences.hideOffline(); mViewPager = (ViewPager) findViewById(R.id.start_conversation_view_pager); ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); @@ -248,7 +250,6 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } }); - this.mHideOfflineContacts = getPreferences().getBoolean("hide_offline", false); } @@ -549,12 +550,13 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU new IntentIntegrator(this).initiateScan(); return true; case R.id.action_hide_offline: - mHideOfflineContacts = !item.isChecked(); - getPreferences().edit().putBoolean("hide_offline", mHideOfflineContacts).commit(); + mHideOfflineContacts = !item.isChecked(); // the item is the menu item which is displayed, the inversion here calculates the new value + ConversationsPlusPreferences.commitHideOffline(mHideOfflineContacts); if (mSearchEditText != null) { filter(mSearchEditText.getText().toString()); } - invalidateOptionsMenu(); + invalidateOptionsMenu(); // Since the selection of this item changed the checked value, the options menu is now invalid + return true; } return super.onOptionsItemSelected(item); } @@ -668,12 +670,12 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU switch (intent.getAction()) { case Intent.ACTION_SENDTO: case Intent.ACTION_VIEW: - Log.d(Config.LOGTAG, "received uri=" + intent.getData()); + Logging.d(Config.LOGTAG, "received uri=" + intent.getData()); return new Invite(intent.getData()).invite(); case NfcAdapter.ACTION_NDEF_DISCOVERED: for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) { if (message instanceof NdefMessage) { - Log.d(Config.LOGTAG, "received message=" + message); + Logging.d(Config.LOGTAG, "received message=" + message); for (NdefRecord record : ((NdefMessage) message).getRecords()) { switch (record.getTnf()) { case NdefRecord.TNF_WELL_KNOWN: @@ -705,7 +707,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU Contact contact = contacts.get(0); if (invite.getFingerprint() != null) { if (contact.addOtrFingerprint(invite.getFingerprint())) { - Log.d(Config.LOGTAG,"added new fingerprint"); + Logging.d(Config.LOGTAG,"added new fingerprint"); xmppConnectionService.syncRosterToDisk(contact.getAccount()); } } @@ -740,7 +742,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU Presence.Status s = p == null ? Presence.Status.OFFLINE : p.getStatus(); if (contact.showInRoster() && contact.match(needle) && (!this.mHideOfflineContacts - || (needle != null && !needle.trim().isEmpty()) + || (needle != null && !needle.isEmpty()) || s.compareTo(Presence.Status.OFFLINE) < 0)) { this.contacts.add(contact); } diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index cc4ba7b2..02a9823d 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -18,6 +18,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.utils.ui.TextViewUtil; + import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; @@ -159,8 +162,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE); foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE); if(hasPendingKeyFetches()) { - setFetching(); - lock(); + TextViewUtil.disable(this.mSaveButton, ConversationsPlusColors.secondaryText(), R.string.fetching_keys); } else { if (!hasForeignKeys && hasNoOtherTrustedKeys()) { keyErrorMessageCard.setVisibility(View.VISIBLE); @@ -176,7 +178,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate foreignKeys.setVisibility(View.GONE); } lockOrUnlockAsNeeded(); - setDone(); + mSaveButton.setText(R.string.done); } } @@ -303,35 +305,16 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } } - private void unlock() { - mSaveButton.setEnabled(true); - mSaveButton.setTextColor(getPrimaryTextColor()); - } - - private void lock() { - mSaveButton.setEnabled(false); - mSaveButton.setTextColor(getSecondaryTextColor()); - } - private void lockOrUnlockAsNeeded() { synchronized (this.foreignKeysToTrust) { for (Jid jid : contactJids) { Map<String, Boolean> fingerprints = foreignKeysToTrust.get(jid); if (hasNoOtherTrustedKeys(jid) && (fingerprints == null || !fingerprints.values().contains(true))) { - lock(); + TextViewUtil.disable(this.mSaveButton, ConversationsPlusColors.secondaryText()); return; } } } - unlock(); - - } - - private void setDone() { - mSaveButton.setText(getString(R.string.done)); - } - - private void setFetching() { - mSaveButton.setText(getString(R.string.fetching_keys)); + TextViewUtil.enable(this.mSaveButton, ConversationsPlusColors.primaryText()); } } diff --git a/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java b/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java index 2e415d5b..a310b6ce 100644 --- a/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java @@ -19,6 +19,9 @@ import com.google.zxing.integration.android.IntentResult; import net.java.otr4j.OtrException; import net.java.otr4j.session.Session; +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.utils.ui.TextViewUtil; + import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -379,16 +382,12 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer } protected void activateButton(Button button, int text, View.OnClickListener listener) { - button.setEnabled(true); - button.setTextColor(getPrimaryTextColor()); - button.setText(text); + TextViewUtil.enable(button, ConversationsPlusColors.primaryText(), text); button.setOnClickListener(listener); } protected void deactivateButton(Button button, int text) { - button.setEnabled(false); - button.setTextColor(getSecondaryTextColor()); - button.setText(text); + TextViewUtil.disable(button, ConversationsPlusColors.secondaryText(), text); button.setOnClickListener(null); } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 7d70b20f..29c9ee0c 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -41,7 +41,6 @@ import android.os.SystemClock; import android.preference.PreferenceManager; import android.text.InputType; import android.util.DisplayMetrics; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -50,6 +49,7 @@ import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; @@ -69,6 +69,11 @@ import java.util.Hashtable; import java.util.List; import java.util.concurrent.RejectedExecutionException; +import de.thedevstack.android.logcat.Logging; +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.utils.ImageUtil; + import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; @@ -78,10 +83,8 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presences; -import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; -import eu.siacs.conversations.ui.widget.Switch; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; @@ -102,16 +105,6 @@ public abstract class XmppActivity extends Activity { public boolean xmppConnectionServiceBound = false; protected boolean registeredListeners = false; - protected int mPrimaryTextColor; - protected int mSecondaryTextColor; - protected int mTertiaryTextColor; - protected int mPrimaryBackgroundColor; - protected int mSecondaryBackgroundColor; - protected int mColorRed; - protected int mColorOrange; - protected int mColorGreen; - protected int mPrimaryColor; - protected boolean mUseSubject = true; private DisplayMetrics metrics; @@ -359,18 +352,9 @@ public abstract class XmppActivity extends Activity { super.onCreate(savedInstanceState); metrics = getResources().getDisplayMetrics(); ExceptionHelper.init(getApplicationContext()); - mPrimaryTextColor = getResources().getColor(R.color.black87); - mSecondaryTextColor = getResources().getColor(R.color.black54); - mTertiaryTextColor = getResources().getColor(R.color.black12); - mColorRed = getResources().getColor(R.color.red800); - mColorOrange = getResources().getColor(R.color.orange500); - mColorGreen = getResources().getColor(R.color.green500); - mPrimaryColor = getResources().getColor(R.color.primary); - mPrimaryBackgroundColor = getResources().getColor(R.color.grey50); - mSecondaryBackgroundColor = getResources().getColor(R.color.grey200); this.mTheme = findTheme(); setTheme(this.mTheme); - this.mUsingEnterKey = usingEnterKey(); + this.mUsingEnterKey = ConversationsPlusPreferences.displayEnterKey(); mUseSubject = getPreferences().getBoolean("use_subject", true); final ActionBar ab = getActionBar(); if (ab!=null) { @@ -558,7 +542,7 @@ public abstract class XmppActivity extends Activity { }); } - protected void displayErrorDialog(final int errorCode) { + public void displayErrorDialog(final int errorCode) { runOnUiThread(new Runnable() { @Override @@ -743,35 +727,35 @@ public abstract class XmppActivity extends Activity { case UNTRUSTED: case TRUSTED: case TRUSTED_X509: - trustToggle.setChecked(trust.trusted(), false); + trustToggle.setChecked(trust.trusted()); trustToggle.setEnabled(!Config.X509_VERIFICATION || trust != XmppAxolotlSession.Trust.TRUSTED_X509); if (Config.X509_VERIFICATION && trust == XmppAxolotlSession.Trust.TRUSTED_X509) { trustToggle.setOnClickListener(null); } - key.setTextColor(getPrimaryTextColor()); - keyType.setTextColor(getSecondaryTextColor()); + key.setTextColor(ConversationsPlusColors.primaryText()); + keyType.setTextColor(ConversationsPlusColors.secondaryText()); break; case UNDECIDED: - trustToggle.setChecked(false, false); + trustToggle.setChecked(false); trustToggle.setEnabled(false); - key.setTextColor(getPrimaryTextColor()); - keyType.setTextColor(getSecondaryTextColor()); + key.setTextColor(ConversationsPlusColors.primaryText()); + keyType.setTextColor(ConversationsPlusColors.secondaryText()); break; case INACTIVE_UNTRUSTED: case INACTIVE_UNDECIDED: trustToggle.setOnClickListener(null); - trustToggle.setChecked(false, false); + trustToggle.setChecked(false); trustToggle.setEnabled(false); - key.setTextColor(getTertiaryTextColor()); - keyType.setTextColor(getTertiaryTextColor()); + key.setTextColor(ConversationsPlusColors.tertiaryText()); + keyType.setTextColor(ConversationsPlusColors.tertiaryText()); break; case INACTIVE_TRUSTED: case INACTIVE_TRUSTED_X509: trustToggle.setOnClickListener(null); - trustToggle.setChecked(true, false); + trustToggle.setChecked(true); trustToggle.setEnabled(false); - key.setTextColor(getTertiaryTextColor()); - keyType.setTextColor(getTertiaryTextColor()); + key.setTextColor(ConversationsPlusColors.tertiaryText()); + keyType.setTextColor(ConversationsPlusColors.tertiaryText()); break; } @@ -781,7 +765,7 @@ public abstract class XmppActivity extends Activity { keyType.setVisibility(View.GONE); } if (highlight) { - keyType.setTextColor(getResources().getColor(R.color.accent)); + keyType.setTextColor(ConversationsPlusColors.accent()); keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message)); } else { keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); @@ -943,34 +927,6 @@ public abstract class XmppActivity extends Activity { } }; - public int getTertiaryTextColor() { - return this.mTertiaryTextColor; - } - - public int getSecondaryTextColor() { - return this.mSecondaryTextColor; - } - - public int getPrimaryTextColor() { - return this.mPrimaryTextColor; - } - - public int getWarningTextColor() { - return this.mColorRed; - } - - public int getOnlineColor() { - return this.mColorGreen; - } - - public int getPrimaryBackgroundColor() { - return this.mPrimaryBackgroundColor; - } - - public int getSecondaryBackgroundColor() { - return this.mSecondaryBackgroundColor; - } - public int getPixel(int dp) { DisplayMetrics metrics = getResources().getDisplayMetrics(); return ((int) (dp * metrics.density)); @@ -1026,7 +982,7 @@ public abstract class XmppActivity extends Activity { } protected int findTheme() { - if (getPreferences().getBoolean("use_larger_font", false)) { + if (ConversationsPlusPreferences.useLargerFont()) { return R.style.ConversationsTheme_LargerText; } else { return R.style.ConversationsTheme; @@ -1055,7 +1011,7 @@ public abstract class XmppActivity extends Activity { } protected Bitmap createQrCodeBitmap(String input, int size) { - Log.d(Config.LOGTAG,"qr code requested size: "+size); + Logging.d(Config.LOGTAG,"qr code requested size: "+size); try { final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter(); final Hashtable<EncodeHintType, Object> hints = new Hashtable<>(); @@ -1071,7 +1027,7 @@ public abstract class XmppActivity extends Activity { } } final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Log.d(Config.LOGTAG,"output size: "+width+"x"+height); + Logging.d(Config.LOGTAG,"output size: "+width+"x"+height); bitmap.setPixels(pixels, 0, width, 0, 0, width, height); return bitmap; } catch (final WriterException e) { @@ -1130,24 +1086,21 @@ public abstract class XmppActivity extends Activity { } } - public AvatarService avatarService() { - return xmppConnectionService.getAvatarService(); - } - class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { private final WeakReference<ImageView> imageViewReference; - private Message message = null; + private final boolean setSize; + private Message message = null; - public BitmapWorkerTask(ImageView imageView) { + public BitmapWorkerTask(ImageView imageView, boolean setSize) { imageViewReference = new WeakReference<>(imageView); + this.setSize = setSize; } @Override protected Bitmap doInBackground(Message... params) { message = params[0]; try { - return xmppConnectionService.getFileBackend().getThumbnail( - message, (int) (metrics.density * 288), false); + return ImageUtil.getThumbnail(message, (int) (metrics.density * 288), false); } catch (FileNotFoundException e) { return null; } @@ -1160,27 +1113,35 @@ public abstract class XmppActivity extends Activity { if (imageView != null) { imageView.setImageBitmap(bitmap); imageView.setBackgroundColor(0x00000000); + if (setSize) { + imageView.setLayoutParams(new LinearLayout.LayoutParams( + bitmap.getWidth(), bitmap.getHeight())); + } } } } } - public void loadBitmap(Message message, ImageView imageView) { + public void loadBitmap(Message message, ImageView imageView, boolean setSize) { Bitmap bm; try { - bm = xmppConnectionService.getFileBackend().getThumbnail(message, - (int) (metrics.density * 288), true); + bm = ImageUtil.getThumbnail(message,(int) (metrics.density * 288), true); } catch (FileNotFoundException e) { bm = null; } + if (bm != null) { imageView.setImageBitmap(bm); imageView.setBackgroundColor(0x00000000); + if (setSize) { + imageView.setLayoutParams(new LinearLayout.LayoutParams( + bm.getWidth(), bm.getHeight())); + } } else { if (cancelPotentialWork(message, imageView)) { imageView.setBackgroundColor(0xff333333); imageView.setImageDrawable(null); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView, setSize); final AsyncDrawable asyncDrawable = new AsyncDrawable( getResources(), null, task); imageView.setImageDrawable(asyncDrawable); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java index 98250af9..55d3f5a7 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java @@ -7,16 +7,19 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CompoundButton; import android.widget.ImageView; +import android.widget.Switch; import android.widget.TextView; import java.util.List; +import de.thedevstack.conversationsplus.ConversationsPlusColors; + import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.ui.ManageAccountActivity; import eu.siacs.conversations.ui.XmppActivity; -import eu.siacs.conversations.ui.widget.Switch; public class AccountAdapter extends ArrayAdapter<Account> { @@ -43,28 +46,29 @@ public class AccountAdapter extends ArrayAdapter<Account> { } TextView statusView = (TextView) view.findViewById(R.id.account_status); ImageView imageView = (ImageView) view.findViewById(R.id.account_image); - imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48))); + imageView.setImageBitmap(AvatarService.getInstance().get(account, activity.getPixel(48))); statusView.setText(getContext().getString(account.getStatus().getReadableId())); switch (account.getStatus()) { case ONLINE: - statusView.setTextColor(activity.getOnlineColor()); + statusView.setTextColor(ConversationsPlusColors.online()); break; case DISABLED: case CONNECTING: - statusView.setTextColor(activity.getSecondaryTextColor()); + statusView.setTextColor(ConversationsPlusColors.secondaryText()); break; default: - statusView.setTextColor(activity.getWarningTextColor()); + statusView.setTextColor(ConversationsPlusColors.warning()); break; } final Switch tglAccountState = (Switch) view.findViewById(R.id.tgl_account_status); final boolean isDisabled = (account.getStatus() == Account.State.DISABLED); - tglAccountState.setChecked(!isDisabled,false); + tglAccountState.setChecked(!isDisabled); tglAccountState.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - if (b == isDisabled && activity instanceof ManageAccountActivity) { - ((ManageAccountActivity) activity).onClickTglAccountState(account,b); + // Condition compoundButton.isPressed() added because of http://stackoverflow.com/a/28219410 + if (compoundButton.isPressed() && b == isDisabled && activity instanceof ManageAccountActivity) { + ((ManageAccountActivity) activity).onClickTglAccountState(account, b); } } }); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index f5f48a26..49e35168 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -3,6 +3,7 @@ package eu.siacs.conversations.ui.adapter; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -19,10 +20,16 @@ import java.lang.ref.WeakReference; import java.util.List; import java.util.concurrent.RejectedExecutionException; +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener; +import de.tzur.conversations.Settings; import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.entities.Transferable; +import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.ui.ConversationActivity; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.utils.UIHelper; @@ -44,11 +51,12 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { view = inflater.inflate(R.layout.conversation_list_row,parent, false); } Conversation conversation = getItem(position); + // Highlight the currently selected conversation if (this.activity instanceof ConversationActivity) { - View swipeableItem = view.findViewById(R.id.swipeable_item); ConversationActivity a = (ConversationActivity) this.activity; - int c = a.highlightSelectedConversations() && conversation == a.getSelectedConversation() ? a.getSecondaryBackgroundColor() : a.getPrimaryBackgroundColor(); - swipeableItem.setBackgroundColor(c); + int c = conversation == a.getSelectedConversation() ? ConversationsPlusColors.secondaryBackground() : ConversationsPlusColors.primaryBackground(); + view.findViewById(R.id.conversationListRowContent).setBackgroundColor(c); + view.findViewById(R.id.conversationListRowFrame).setBackgroundColor(c); } TextView convName = (TextView) view.findViewById(R.id.conversation_name); if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) { @@ -61,6 +69,19 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { ImageView imagePreview = (ImageView) view.findViewById(R.id.conversation_lastimage); ImageView notificationStatus = (ImageView) view.findViewById(R.id.notification_status); + if (Settings.SHOW_ONLINE_STATUS) { + int color = ConversationsPlusColors.offline(); + if (conversation.getAccount().getStatus() == Account.State.ONLINE) { + if (conversation.getMode() == Conversation.MODE_SINGLE) { + color = UIHelper.getStatusColor(conversation.getContact().getMostAvailableStatus()); + } else if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getMucOptions().online()) { + color = ConversationsPlusColors.online(); + } + } + TextView status = (TextView) view.findViewById(R.id.status); + status.setBackgroundColor(color); + } + Message message = conversation.getLatestMessage(); if (!conversation.isRead()) { @@ -74,12 +95,23 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { || message.getTransferable().getStatus() != Transferable.STATUS_DELETED)) { mLastMessage.setVisibility(View.GONE); imagePreview.setVisibility(View.VISIBLE); - activity.loadBitmap(message, imagePreview); + activity.loadBitmap(message, imagePreview, false); } else { Pair<String,Boolean> preview = UIHelper.getMessagePreview(activity,message); mLastMessage.setVisibility(View.VISIBLE); imagePreview.setVisibility(View.GONE); - mLastMessage.setText(preview.first); + CharSequence msgText = preview.first; + String msgPrefix = null; + if (message.getStatus() == Message.STATUS_SEND + || message.getStatus() == Message.STATUS_SEND_DISPLAYED + || message.getStatus() == Message.STATUS_SEND_FAILED + || message.getStatus() == Message.STATUS_SEND_RECEIVED) { + msgPrefix = activity.getString(R.string.cplus_me); + } else if (conversation.getMode() == Conversation.MODE_MULTI) { + msgPrefix = UIHelper.getMessageDisplayName(message); + } + String lastMessagePreview = ((null == msgPrefix || msgPrefix.isEmpty()) ? "" : (msgPrefix + ": ")) + msgText; + mLastMessage.setText(lastMessagePreview); if (preview.second) { if (conversation.isRead()) { mLastMessage.setTypeface(null, Typeface.ITALIC); @@ -103,15 +135,23 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { notificationStatus.setVisibility(View.VISIBLE); notificationStatus.setImageResource(R.drawable.ic_notifications_paused_grey600_24dp); } else if (conversation.alwaysNotify()) { - notificationStatus.setVisibility(View.GONE); + notificationStatus.setImageResource(R.drawable.ic_notifications_grey600_24dp); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + notificationStatus.setVisibility(View.GONE); + } else { + notificationStatus.setVisibility(View.VISIBLE); + } } else { notificationStatus.setVisibility(View.VISIBLE); notificationStatus.setImageResource(R.drawable.ic_notifications_none_grey600_24dp); } - mTimestamp.setText(UIHelper.readableTimeDifference(activity,conversation.getLatestMessage().getTimeSent())); + mTimestamp.setText(UIHelper.readableTimeDifference(activity, message.getTimeSent())); ImageView profilePicture = (ImageView) view.findViewById(R.id.conversation_image); - loadAvatar(conversation,profilePicture); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + profilePicture.setOnLongClickListener(new ShowResourcesListDialogListener(activity, conversation.getContact())); + } + loadAvatar(conversation, profilePicture); return view; } @@ -126,7 +166,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { @Override protected Bitmap doInBackground(Conversation... params) { - return activity.avatarService().get(params[0], activity.getPixel(56)); + return AvatarService.getInstance().get(params[0], activity.getPixel(56)); } @Override @@ -143,7 +183,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { public void loadAvatar(Conversation conversation, ImageView imageView) { if (cancelPotentialWork(conversation, imageView)) { - final Bitmap bm = activity.avatarService().get(conversation, activity.getPixel(56), true); + final Bitmap bm = AvatarService.getInstance().get(conversation, activity.getPixel(56), true); if (bm != null) { imageView.setImageBitmap(bm); imageView.setBackgroundColor(0x00000000); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java index da8e3910..29d706c7 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java @@ -1,13 +1,11 @@ package eu.siacs.conversations.ui.adapter; import android.content.Context; -import android.content.SharedPreferences; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -20,8 +18,11 @@ import java.lang.ref.WeakReference; import java.util.List; import java.util.concurrent.RejectedExecutionException; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.tzur.conversations.Settings; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.ListItem; +import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.jid.Jid; @@ -45,8 +46,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { public ListItemAdapter(XmppActivity activity, List<ListItem> objects) { super(activity, 0, objects); this.activity = activity; - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); - this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false); + this.showDynamicTags = ConversationsPlusPreferences.showDynamicTags(); } @Override @@ -57,6 +57,12 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { if (view == null) { view = inflater.inflate(R.layout.contact, parent, false); } + + if (Settings.SHOW_ONLINE_STATUS) { + TextView tvStatus = (TextView) view.findViewById(R.id.contact_status); + tvStatus.setBackgroundColor(item.getStatusColor()); + } + TextView tvName = (TextView) view.findViewById(R.id.contact_display_name); TextView tvJid = (TextView) view.findViewById(R.id.contact_jid); ImageView picture = (ImageView) view.findViewById(R.id.contact_photo); @@ -106,7 +112,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { @Override protected Bitmap doInBackground(ListItem... params) { - return activity.avatarService().get(params[0], activity.getPixel(48)); + return AvatarService.getInstance().get(params[0], activity.getPixel(48)); } @Override @@ -123,7 +129,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { public void loadAvatar(ListItem item, ImageView imageView) { if (cancelPotentialWork(item, imageView)) { - final Bitmap bm = activity.avatarService().get(item,activity.getPixel(48),true); + final Bitmap bm = AvatarService.getInstance().get(item,activity.getPixel(48),true); if (bm != null) { imageView.setImageBitmap(bm); imageView.setBackgroundColor(0x00000000); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 0268097f..9d2917d5 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -38,6 +38,10 @@ import java.util.concurrent.RejectedExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import de.thedevstack.conversationsplus.ConversationsPlusApplication; +import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import eu.siacs.conversations.providers.ConversationsPlusFileProvider; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; @@ -46,6 +50,8 @@ import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message.FileParams; import eu.siacs.conversations.entities.Transferable; +import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.ui.ConversationActivity; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.GeoHelper; @@ -56,6 +62,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { private static final int SENT = 0; private static final int RECEIVED = 1; private static final int STATUS = 2; + private static final int NULL = 3; private static final Pattern XMPP_PATTERN = Pattern .compile("xmpp\\:(?:(?:[" + Patterns.GOOD_IRI_CHAR @@ -77,14 +84,11 @@ public class MessageAdapter extends ArrayAdapter<Message> { return true; } }; - private boolean mIndicateReceived = false; - private boolean mUseWhiteBackground = false; public MessageAdapter(ConversationActivity activity, List<Message> messages) { super(activity, 0, messages); this.activity = activity; metrics = getContext().getResources().getDisplayMetrics(); - updatePreferences(); } public void setOnContactPictureClicked(OnContactPictureClicked listener) { @@ -118,9 +122,9 @@ public class MessageAdapter extends ArrayAdapter<Message> { private int getMessageTextColor(boolean onDark, boolean primary) { if (onDark) { - return activity.getResources().getColor(primary ? R.color.white : R.color.white70); + return primary ? ConversationsPlusColors.primaryTextOnDark() : ConversationsPlusColors.secondaryTextOnDark(); } else { - return activity.getResources().getColor(primary ? R.color.black87 : R.color.black54); + return primary ? ConversationsPlusColors.primaryText() : ConversationsPlusColors.secondaryText(); } } @@ -132,17 +136,8 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.indicatorReceived.setVisibility(View.GONE); } - if (viewHolder.edit_indicator != null) { - if (message.edited()) { - viewHolder.edit_indicator.setVisibility(View.VISIBLE); - viewHolder.edit_indicator.setImageResource(darkBackground ? R.drawable.ic_mode_edit_white_18dp : R.drawable.ic_mode_edit_black_18dp); - viewHolder.edit_indicator.setAlpha(darkBackground ? 0.7f : 0.57f); - } else { - viewHolder.edit_indicator.setVisibility(View.GONE); - } - } boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI - && message.getMergedStatus() <= Message.STATUS_RECEIVED; + && message.getStatus() <= Message.STATUS_RECEIVED; if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getTransferable() != null) { FileParams params = message.getFileParams(); if (params.size > (1.5 * 1024 * 1024)) { @@ -154,7 +149,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { error = true; } } - switch (message.getMergedStatus()) { + switch (message.getStatus()) { case Message.STATUS_WAITING: info = getContext().getString(R.string.waiting); break; @@ -170,12 +165,12 @@ public class MessageAdapter extends ArrayAdapter<Message> { info = getContext().getString(R.string.offering); break; case Message.STATUS_SEND_RECEIVED: - if (mIndicateReceived) { + if (ConversationsPlusPreferences.indicateReceived()) { viewHolder.indicatorReceived.setVisibility(View.VISIBLE); } break; case Message.STATUS_SEND_DISPLAYED: - if (mIndicateReceived) { + if (ConversationsPlusPreferences.indicateReceived()) { viewHolder.indicatorReceived.setVisibility(View.VISIBLE); } break; @@ -190,7 +185,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { break; } if (error && type == SENT) { - viewHolder.time.setTextColor(activity.getWarningTextColor()); + viewHolder.time.setTextColor(ConversationsPlusColors.warning()); } else { viewHolder.time.setTextColor(this.getMessageTextColor(darkBackground,false)); } @@ -205,7 +200,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { message.getFingerprint()); if(trust == null || (!trust.trusted() && !trust.trustedInactive())) { - viewHolder.indicator.setColorFilter(activity.getWarningTextColor()); + viewHolder.indicator.setColorFilter(ConversationsPlusColors.warning()); viewHolder.indicator.setAlpha(1.0f); } else { viewHolder.indicator.clearColorFilter(); @@ -226,7 +221,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { } String formatedTime = UIHelper.readableTimeDifferenceFull(getContext(), - message.getMergedTimeSent()); + message.getTimeSent()); if (message.getStatus() <= Message.STATUS_RECEIVED) { if ((filesize != null) && (info != null)) { viewHolder.time.setText(formatedTime + " \u00B7 " + filesize +" \u00B7 " + info); @@ -279,19 +274,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.messageBody.setTextIsSelectable(false); } - private void displayHeartMessage(final ViewHolder viewHolder, final String body) { - if (viewHolder.download_button != null) { - viewHolder.download_button.setVisibility(View.GONE); - } - viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.VISIBLE); - viewHolder.messageBody.setIncludeFontPadding(false); - Spannable span = new SpannableString(body); - span.setSpan(new RelativeSizeSpan(4.0f), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - span.setSpan(new ForegroundColorSpan(activity.getWarningTextColor()), 0, body.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - viewHolder.messageBody.setText(span); - } - private void displayTextMessage(final ViewHolder viewHolder, final Message message, boolean darkBackground) { if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); @@ -302,10 +284,10 @@ public class MessageAdapter extends ArrayAdapter<Message> { if (message.getBody() != null) { final String nick = UIHelper.getMessageDisplayName(message); String body; - try { - body = message.getMergedBody().replaceAll("^" + Message.ME_COMMAND, nick + " "); - } catch (ArrayIndexOutOfBoundsException e) { - body = message.getMergedBody(); + if (message.hasMeCommand()) { + body = message.getBodyReplacedMeCommand(nick); + } else { + body = message.getBody(); } final SpannableString formattedBody = new SpannableString(body); int i = body.indexOf(Message.MERGE_SEPARATOR); @@ -351,26 +333,54 @@ public class MessageAdapter extends ArrayAdapter<Message> { } viewHolder.messageBody.setText(span); } - int urlCount = 0; - Matcher matcher = Patterns.WEB_URL.matcher(body); - while (matcher.find()) { - urlCount++; + int patternMatchCount = 0; + int oldAutoLinkMask = viewHolder.messageBody.getAutoLinkMask(); + + // first check if we have a match on XMPP_PATTERN so we do not have to check for EMAIL_ADDRESSES + patternMatchCount += countMatches(XMPP_PATTERN, body); + if ((Linkify.EMAIL_ADDRESSES & oldAutoLinkMask) != 0 && patternMatchCount > 0) { + oldAutoLinkMask -= Linkify.EMAIL_ADDRESSES; + } + + // count matches for all patterns + if ((Linkify.WEB_URLS & oldAutoLinkMask) != 0) { + patternMatchCount += countMatches(Patterns.WEB_URL, body); + } + if ((Linkify.EMAIL_ADDRESSES & oldAutoLinkMask) != 0) { + patternMatchCount += countMatches(Patterns.EMAIL_ADDRESS, body); } - viewHolder.messageBody.setTextIsSelectable(urlCount <= 1); + if ((Linkify.PHONE_NUMBERS & oldAutoLinkMask) != 0) { + patternMatchCount += countMatches(Patterns.PHONE, body); + } + + viewHolder.messageBody.setTextIsSelectable(patternMatchCount <= 1); viewHolder.messageBody.setAutoLinkMask(0); - Linkify.addLinks(viewHolder.messageBody, Linkify.WEB_URLS); Linkify.addLinks(viewHolder.messageBody, XMPP_PATTERN, "xmpp"); + viewHolder.messageBody.setAutoLinkMask(oldAutoLinkMask); } else { viewHolder.messageBody.setText(""); viewHolder.messageBody.setTextIsSelectable(false); } viewHolder.messageBody.setTextColor(this.getMessageTextColor(darkBackground, true)); - viewHolder.messageBody.setLinkTextColor(this.getMessageTextColor(darkBackground, true)); - viewHolder.messageBody.setHighlightColor(activity.getResources().getColor(darkBackground ? R.color.grey800 : R.color.grey500)); viewHolder.messageBody.setTypeface(null, Typeface.NORMAL); viewHolder.messageBody.setOnLongClickListener(openContextMenu); } + /** + * Counts the number of occurrences of the pattern in body. + * @param pattern the pattern to match + * @param body the body to find the pattern + * @return the number of occurrences + */ + private int countMatches(Pattern pattern, String body) { + Matcher matcher = pattern.matcher(body); + int count = 0; + while (matcher.find()) { + count++; + } + return count; + } + private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text) { viewHolder.image.setVisibility(View.GONE); @@ -425,7 +435,8 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.messageBody.setVisibility(View.GONE); viewHolder.image.setVisibility(View.VISIBLE); FileParams params = message.getFileParams(); - double target = metrics.density * 288; + //TODO: Check what value add the following lines have (compared with setting height/width in XmppActivity.loadBitmap from thumbnail after thumbnail is created) + /*double target = metrics.density * 288; int scalledW; int scalledH; if (params.width <= params.height) { @@ -437,8 +448,9 @@ public class MessageAdapter extends ArrayAdapter<Message> { } LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(scalledW, scalledH); layoutParams.setMargins(0, (int) (metrics.density * 4), 0, (int) (metrics.density * 4)); - viewHolder.image.setLayoutParams(layoutParams); - activity.loadBitmap(message, viewHolder.image); + viewHolder.image.setLayoutParams(layoutParams);*/ + //TODO Why should this be calculated by hand??? + activity.loadBitmap(message, viewHolder.image, true); viewHolder.image.setOnClickListener(new OnClickListener() { @Override @@ -449,19 +461,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.image.setOnLongClickListener(openContextMenu); } - private void loadMoreMessages(Conversation conversation) { - conversation.setLastClearHistory(0); - conversation.setHasMessagesLeftOnServer(true); - conversation.setFirstMamReference(null); - long timestamp = conversation.getLastMessageTransmitted(); - if (timestamp == 0) { - timestamp = System.currentTimeMillis(); - } - activity.setMessagesLoaded(); - activity.xmppConnectionService.getMessageArchiveService().query(conversation, 0, timestamp); - Toast.makeText(activity, R.string.fetching_history_from_server,Toast.LENGTH_LONG).show(); - } - @Override public View getView(int position, View view, ViewGroup parent) { final Message message = getItem(position); @@ -484,7 +483,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.download_button); viewHolder.indicator = (ImageView) view .findViewById(R.id.security_indicator); - viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); viewHolder.image = (ImageView) view .findViewById(R.id.message_image); viewHolder.messageBody = (TextView) view @@ -505,7 +503,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.download_button); viewHolder.indicator = (ImageView) view .findViewById(R.id.security_indicator); - viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); viewHolder.image = (ImageView) view .findViewById(R.id.message_image); viewHolder.messageBody = (TextView) view @@ -520,7 +517,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false); viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); - viewHolder.load_more_messages = (Button) view.findViewById(R.id.load_more_messages); break; default: viewHolder = null; @@ -534,31 +530,17 @@ public class MessageAdapter extends ArrayAdapter<Message> { } } - boolean darkBackground = (type == RECEIVED && (!isInValidSession || !mUseWhiteBackground)); + boolean darkBackground = (type == RECEIVED && !isInValidSession); if (type == STATUS) { - if ("LOAD_MORE".equals(message.getBody())) { - viewHolder.status_message.setVisibility(View.GONE); - viewHolder.contact_picture.setVisibility(View.GONE); - viewHolder.load_more_messages.setVisibility(View.VISIBLE); - viewHolder.load_more_messages.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - loadMoreMessages(message.getConversation()); - } - }); - } else { - viewHolder.status_message.setVisibility(View.VISIBLE); - viewHolder.contact_picture.setVisibility(View.VISIBLE); - viewHolder.load_more_messages.setVisibility(View.GONE); - if (conversation.getMode() == Conversation.MODE_SINGLE) { - viewHolder.contact_picture.setImageBitmap(activity - .avatarService().get(conversation.getContact(), - activity.getPixel(32))); - viewHolder.contact_picture.setAlpha(0.5f); - } - viewHolder.status_message.setText(message.getBody()); + viewHolder.status_message.setVisibility(View.VISIBLE); + viewHolder.contact_picture.setVisibility(View.VISIBLE); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + viewHolder.contact_picture.setImageBitmap(AvatarService.getInstance().get(conversation.getContact(), + activity.getPixel(32))); + viewHolder.contact_picture.setAlpha(0.5f); } + viewHolder.status_message.setText(message.getBody()); return view; } else { loadAvatar(message, viewHolder.contact_picture); @@ -633,8 +615,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { } else { if (GeoHelper.isGeoUri(message.getBody())) { displayLocationMessage(viewHolder,message); - } else if (message.bodyIsHeart()) { - displayHeartMessage(viewHolder, message.getBody().trim()); } else if (message.treatAsDownloadable() == Message.Decision.MUST) { try { URL url = new URL(message.getBody()); @@ -656,11 +636,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { if (type == RECEIVED) { if(isInValidSession) { - if (mUseWhiteBackground) { - viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_white); - } else { - viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received); - } viewHolder.encryption.setVisibility(View.GONE); } else { viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_warning); @@ -675,21 +650,40 @@ public class MessageAdapter extends ArrayAdapter<Message> { } public void openDownloadable(Message message) { - DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + DownloadableFile file = FileBackend.getFile(message); if (!file.exists()) { Toast.makeText(activity,R.string.file_deleted,Toast.LENGTH_SHORT).show(); return; } + boolean bInPrivateStorage = false; + if (file.getAbsolutePath().startsWith(FileBackend.getPrivateFileDirectoryPath())) { + bInPrivateStorage = true; + } Intent openIntent = new Intent(Intent.ACTION_VIEW); String mime = file.getMimeType(); if (mime == null) { mime = "*/*"; } - openIntent.setDataAndType(Uri.fromFile(file), mime); + Uri uri; + if (bInPrivateStorage) { + uri = ConversationsPlusFileProvider.createUriForPrivateFile(file); + } else { + uri = Uri.fromFile(file); + } + openIntent.setDataAndType(uri, mime); PackageManager manager = activity.getPackageManager(); List<ResolveInfo> infos = manager.queryIntentActivities(openIntent, 0); + if (bInPrivateStorage) { + for (ResolveInfo info : infos) { + ConversationsPlusApplication.getAppContext().grantUriPermission(info.activityInfo.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + } if (infos.size() == 0) { - openIntent.setDataAndType(Uri.fromFile(file),"*/*"); + openIntent.setDataAndType(uri,"*/*"); + } + if (bInPrivateStorage) { + openIntent.putExtra(Intent.EXTRA_STREAM, uri); + openIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } try { getContext().startActivity(openIntent); @@ -710,11 +704,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { Toast.makeText(activity,R.string.no_application_found_to_display_location,Toast.LENGTH_SHORT).show(); } - public void updatePreferences() { - this.mIndicateReceived = activity.indicateReceived(); - this.mUseWhiteBackground = activity.useWhiteBackground(); - } - public interface OnContactPictureClicked { void onContactPictureClicked(Message message); } @@ -735,8 +724,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { protected ImageView contact_picture; protected TextView status_message; protected TextView encryption; - public Button load_more_messages; - public ImageView edit_indicator; } class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { @@ -749,7 +736,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { @Override protected Bitmap doInBackground(Message... params) { - return activity.avatarService().get(params[0], activity.getPixel(48), isCancelled()); + return AvatarService.getInstance().get(params[0], activity.getPixel(48), isCancelled()); } @Override @@ -766,7 +753,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { public void loadAvatar(Message message, ImageView imageView) { if (cancelPotentialWork(message, imageView)) { - final Bitmap bm = activity.avatarService().get(message, activity.getPixel(48), true); + final Bitmap bm = AvatarService.getInstance().get(message, activity.getPixel(48), true); if (bm != null) { imageView.setImageBitmap(bm); imageView.setBackgroundColor(0x00000000); diff --git a/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java index 3a21ade3..cb504576 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java @@ -4,13 +4,13 @@ import android.content.Context; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import java.util.List; -import eu.siacs.conversations.Config; +import de.thedevstack.conversationsplus.ConversationsPlusColors; + import eu.siacs.conversations.R; import eu.siacs.conversations.xmpp.forms.Field; @@ -59,7 +59,7 @@ public abstract class FormFieldWrapper { int start = label.length(); int end = label.length() + 2; spannableString.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, end, 0); - spannableString.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.accent)), start, end, 0); + spannableString.setSpan(new ForegroundColorSpan(ConversationsPlusColors.accent()), start, end, 0); } return spannableString; } diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java new file mode 100644 index 00000000..08916206 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationMoreMessagesLoadedListener.java @@ -0,0 +1,143 @@ +package eu.siacs.conversations.ui.listeners; + +import android.view.View; +import android.widget.ListView; +import android.widget.Toast; + +import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayout; + +import java.util.List; + +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.ConversationActivity; +import eu.siacs.conversations.ui.ConversationFragment; +import eu.siacs.conversations.ui.adapter.MessageAdapter; + +/** + * This listener updates the UI when messages are loaded from the server. + */ +public class ConversationMoreMessagesLoadedListener implements XmppConnectionService.OnMoreMessagesLoaded { + private SwipyRefreshLayout swipeLayout; + private List<Message> messageList; + private ConversationFragment fragment; + private ListView messagesView; + private MessageAdapter messageListAdapter; + private Toast messageLoaderToast; + /* + The current loading status + */ + private boolean loadingMessages = false; + /** + * Whether the user is loading only history messages or not. + * History messages are messages which are older than the oldest in the database. + */ + private boolean loadHistory = true; + + public ConversationMoreMessagesLoadedListener(SwipyRefreshLayout swipeLayout, List<Message> messageList, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) { + this.swipeLayout = swipeLayout; + this.messageList = messageList; + this.fragment = fragment; + this.messagesView = messagesView; + this.messageListAdapter = messageListAdapter; + } + + public void setLoadHistory(boolean value) { + this.loadHistory = value; + } + + public void setLoadingInProgress() { + this.loadingMessages = true; + } + + public boolean isLoadingInProgress() { + return this.loadingMessages; + } + + @Override + public void onMoreMessagesLoaded(final int c, final Conversation conversation) { + ConversationActivity activity = (ConversationActivity) fragment.getActivity(); + // Current selected conversation is not the same the messages are loaded - skip updating message view and hide loading graphic + if (activity.getSelectedConversation() != conversation) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + swipeLayout.setRefreshing(false); + } + }); + return; + } + // No new messages are loaded + if (0 == c) { + if (this.loadHistory) { + conversation.setHasMessagesLeftOnServer(false); + } + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + swipeLayout.setRefreshing(false); + } + }); + } + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + final int oldPosition = messagesView.getFirstVisiblePosition(); // Always 0 - because loading starts always when hitting the top + String uuid = null; + boolean oldMessageListWasEmpty = messageList.isEmpty(); + if (-1 < oldPosition && messageList.size() > oldPosition) { + Message message = messageList.get(oldPosition); + uuid = message != null ? message.getUuid() : null; + } + View v = messagesView.getChildAt(0); + final int pxOffset = (v == null) ? 0 : v.getTop(); + + conversation.populateWithMessages(messageList); // This overrides the old message list + fragment.updateStatusMessages(); // This adds "messages" to the list for the status + messageListAdapter.notifyDataSetChanged(); + loadingMessages = false; // Loading of messages is finished - next query can be loaded + + int pos = getIndexOf(uuid, messageList); + + if (!oldMessageListWasEmpty) { + messagesView.setSelectionFromTop(pos, pxOffset); + } + + if (messageLoaderToast != null) { + messageLoaderToast.cancel(); + } + swipeLayout.setRefreshing(false); + } + }); + } + + @Override + public void informUser(final int resId) { + final ConversationActivity activity = (ConversationActivity) fragment.getActivity(); + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + if (messageLoaderToast != null) { + messageLoaderToast.cancel(); + } + messageLoaderToast = Toast.makeText(activity, resId, Toast.LENGTH_LONG); + messageLoaderToast.show(); + } + }); + + } + + private int getIndexOf(String uuid, List<Message> messages) { + if (uuid == null) { + return 0; + } + for (int i = 0; i < messages.size(); ++i) { + if (uuid.equals(messages.get(i).getUuid())) { + return i; + } + } + return 0; + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java new file mode 100644 index 00000000..0cbde814 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/listeners/ConversationSwipeRefreshListener.java @@ -0,0 +1,103 @@ +package eu.siacs.conversations.ui.listeners; + +import android.widget.ListView; + +import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayout; +import com.orangegangsters.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirection; + +import java.util.List; + +import de.thedevstack.android.logcat.Logging; +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.MessageArchiveService; +import eu.siacs.conversations.ui.ConversationActivity; +import eu.siacs.conversations.ui.ConversationFragment; +import eu.siacs.conversations.ui.adapter.MessageAdapter; + +/** + * This listener starts loading messages from the server. + */ +public class ConversationSwipeRefreshListener implements SwipyRefreshLayout.OnRefreshListener { + private List<Message> messageList; + private ConversationFragment fragment; + private ConversationMoreMessagesLoadedListener listener; + private SwipyRefreshLayout swipeLayout; + + public ConversationSwipeRefreshListener(List<Message> messageList, SwipyRefreshLayout swipeLayout, ConversationFragment fragment, ListView messagesView, MessageAdapter messageListAdapter) { + this.messageList = messageList; + this.fragment = fragment; + this.swipeLayout = swipeLayout; + this.listener = new ConversationMoreMessagesLoadedListener(swipeLayout, messageList, fragment, messagesView, messageListAdapter); + } + + @Override + public void onRefresh(SwipyRefreshLayoutDirection direction) { + Logging.d(Config.LOGTAG, "Refresh swipe container"); + Logging.d(Config.LOGTAG, "Refresh direction " + direction); + final ConversationActivity activity = (ConversationActivity) fragment.getActivity(); + if (activity.getSelectedConversation().getAccount().getStatus() != Account.State.DISABLED) { + synchronized (this.messageList) { + long timestamp; + if (SwipyRefreshLayoutDirection.TOP == direction) { // Load history -> messages sent/received before first message in database + if (messageList.isEmpty()) { + timestamp = System.currentTimeMillis(); + } else { + timestamp = this.messageList.get(0).getTimeSent(); // works only because of the ordering (last msg = first msg in list) + } + this.listener.setLoadHistory(true); + activity.xmppConnectionService.loadMoreMessages(activity.getSelectedConversation(), timestamp, this.listener); + } else if (SwipyRefreshLayoutDirection.BOTTOM == direction) { // load messages sent/received between last received or last session establishment and now + if (activity.getSelectedConversation().getAccount().isOnlineAndConnected()) { + Logging.d("mam", "loading missing messages from mam (last session establishing or last received message)"); + long lastSessionEstablished = this.getTimestampOfLastSessionEstablished(activity.getSelectedConversation()); + long lastReceivedMessage = this.getTimestampOfLastReceivedOrTransmittedMessage(); + long startTimestamp = Math.min(lastSessionEstablished, lastReceivedMessage); + MessageArchiveService.Query query = activity.xmppConnectionService.getMessageArchiveService().query(activity.getSelectedConversation(), startTimestamp, System.currentTimeMillis(), this.listener); + if (query != null) { + this.listener.setLoadHistory(false); + } else { + Logging.d("mam", "no query built - no messages loaded"); + this.listener.onMoreMessagesLoaded(0, activity.getSelectedConversation()); + this.listener.informUser(R.string.no_more_history_on_server); + } + this.listener.informUser(R.string.fetching_history_from_server); + } else { + this.listener.informUser(R.string.not_connected_try_again); + swipeLayout.setRefreshing(false); + } + } + } + } else { + this.listener.informUser(R.string.this_account_is_disabled); + swipeLayout.setRefreshing(false); + } + Logging.d(Config.LOGTAG, "End Refresh swipe container"); + } + + private long getTimestampOfLastReceivedOrTransmittedMessage() { + long lastReceivedOrTransmittedMessage = Long.MAX_VALUE; + if (null != this.messageList + && !this.messageList.isEmpty()) { + int lastMessageIndex = this.messageList.size() - 1; + if (0 <= lastMessageIndex && this.messageList.size() > lastMessageIndex) { + lastReceivedOrTransmittedMessage = this.messageList.get(lastMessageIndex).getTimeSent(); + } + } + + return lastReceivedOrTransmittedMessage; + } + + private long getTimestampOfLastSessionEstablished(Conversation conversation) { + long lastSessionEstablished = Long.MAX_VALUE; + if (null != conversation + && null != conversation.getAccount() + && null != conversation.getAccount().getXmppConnection()) { + lastSessionEstablished = conversation.getAccount().getXmppConnection().getLastSessionEstablished(); + } + return lastSessionEstablished; + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/widget/Switch.java b/src/main/java/eu/siacs/conversations/ui/widget/Switch.java deleted file mode 100644 index fd3b5553..00000000 --- a/src/main/java/eu/siacs/conversations/ui/widget/Switch.java +++ /dev/null @@ -1,68 +0,0 @@ -package eu.siacs.conversations.ui.widget; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.ViewConfiguration; - -import com.kyleduo.switchbutton.SwitchButton; - -public class Switch extends SwitchButton { - - private int mTouchSlop; - private int mClickTimeout; - private float mStartX; - private float mStartY; - private OnClickListener mOnClickListener; - - public Switch(Context context) { - super(context); - mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - mClickTimeout = ViewConfiguration.getPressedStateDuration() + ViewConfiguration.getTapTimeout(); - } - - public Switch(Context context, AttributeSet attrs) { - super(context, attrs); - mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - mClickTimeout = ViewConfiguration.getPressedStateDuration() + ViewConfiguration.getTapTimeout(); - } - - public Switch(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - mClickTimeout = ViewConfiguration.getPressedStateDuration() + ViewConfiguration.getTapTimeout(); - } - - @Override - public void setOnClickListener(OnClickListener onClickListener) { - this.mOnClickListener = onClickListener; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (!isEnabled()) { - float deltaX = event.getX() - mStartX; - float deltaY = event.getY() - mStartY; - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: - mStartX = event.getX(); - mStartY = event.getY(); - break; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - float time = event.getEventTime() - event.getDownTime(); - if (deltaX < mTouchSlop && deltaY < mTouchSlop && time < mClickTimeout) { - if (mOnClickListener != null) { - this.mOnClickListener.onClick(this); - } - } - break; - default: - break; - } - return true; - } - return super.onTouchEvent(event); - } -} |