From 990a35c47500c6a3f4292d41450a5f6cb689c7b1 Mon Sep 17 00:00:00 2001 From: steckbrief Date: Wed, 11 Jan 2017 14:47:25 +0100 Subject: Custom toast view added --- art/ic_toast.svg | 229 +++++++++++++++++++ art/ic_toast_error.svg | 247 +++++++++++++++++++++ art/render.rb | 2 + .../utils/ui/ConversationsPlusToast.java | 101 +++++++++ src/main/res/drawable-hdpi/ic_toast.png | Bin 0 -> 1708 bytes src/main/res/drawable-hdpi/ic_toast_error.png | Bin 0 -> 1764 bytes src/main/res/layout/cplus_toast_container.xml | 22 ++ 7 files changed, 601 insertions(+) create mode 100644 art/ic_toast.svg create mode 100644 art/ic_toast_error.svg create mode 100644 src/main/java/de/thedevstack/conversationsplus/utils/ui/ConversationsPlusToast.java create mode 100644 src/main/res/drawable-hdpi/ic_toast.png create mode 100644 src/main/res/drawable-hdpi/ic_toast_error.png create mode 100644 src/main/res/layout/cplus_toast_container.xml diff --git a/art/ic_toast.svg b/art/ic_toast.svg new file mode 100644 index 00000000..7bf2c515 --- /dev/null +++ b/art/ic_toast.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/art/ic_toast_error.svg b/art/ic_toast_error.svg new file mode 100644 index 00000000..7f6e8c1e --- /dev/null +++ b/art/ic_toast_error.svg @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + diff --git a/art/render.rb b/art/render.rb index b4f84769..1520e958 100755 --- a/art/render.rb +++ b/art/render.rb @@ -13,6 +13,8 @@ resolutions = { images = { 'conversations_baloon.svg' => ['ic_launcher', 48], 'conversations_mono.svg' => ['ic_notification', 24], + 'ic_toast.svg' => ['ic_toast', 24], + 'ic_toast_error.svg' => ['ic_toast_error', 24], 'ic_received_indicator.svg' => ['ic_received_indicator', 12], 'ic_send_text_offline.svg' => ['ic_send_text_offline', 36], 'ic_send_text_online.svg' => ['ic_send_text_online', 36], diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/ui/ConversationsPlusToast.java b/src/main/java/de/thedevstack/conversationsplus/utils/ui/ConversationsPlusToast.java new file mode 100644 index 00000000..3576d1cd --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/utils/ui/ConversationsPlusToast.java @@ -0,0 +1,101 @@ +package de.thedevstack.conversationsplus.utils.ui; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.support.annotation.StringRes; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.Toast; + +import de.thedevstack.conversationsplus.ConversationsPlusApplication; +import de.thedevstack.conversationsplus.R; + +/** + * Wrapper for custom styled Toasts for Conversations+. + */ +public final class ConversationsPlusToast { + + /** + * Creates an error toast with text and duration + * @param text + * @param duration + */ + public static void makeErrorToast(final CharSequence text, final int duration) { + Handler toastHandler = new Handler(Looper.getMainLooper()); + toastHandler.post(new ConversationsPlusToast.ToastRunnable(text, duration, true)); + } + + /** + * Creates an error toast with text from resource and duration + * @param resId + * @param duration + */ + public static void makeErrorToast(@StringRes int resId, int duration) { + makeErrorToast(ConversationsPlusApplication.getAppContext().getString(resId), duration); + } + + /** + * Creates an toast with text and duration + * @param text + * @param duration + */ + public static void makeToast(final CharSequence text, final int duration) { + Handler toastHandler = new Handler(Looper.getMainLooper()); + toastHandler.post(new ConversationsPlusToast.ToastRunnable(text, duration)); + } + + /** + * Creates an toast with text from resource and duration + * @param resId + * @param duration + */ + public static void makeToast(@StringRes int resId, int duration) { + makeToast(ConversationsPlusApplication.getAppContext().getString(resId), duration); + } + + private ConversationsPlusToast() { + // avoid instantiation - helper class + } + + /** + * Runnable to show the toast in an UI thread. + */ + static class ToastRunnable implements Runnable { + private boolean showErrorToast = false; + private CharSequence text; + private int duration; + + public ToastRunnable(CharSequence text, int duration, boolean isError) { + this.showErrorToast = isError; + this.text = text; + this.duration = duration; + } + + public ToastRunnable(CharSequence text, int duration) { + this.text = text; + this.duration = duration; + } + + @Override + public void run() { + Context applicationContext = ConversationsPlusApplication.getAppContext(); + LayoutInflater inflater = LayoutInflater.from(applicationContext); + View layout = inflater.inflate(R.layout.cplus_toast_container, null); + + TextViewUtil.setText(layout, R.id.cplus_toast_txt, text); + + if (this.showErrorToast) { + // Set image view to error icon + ImageView iv = (ImageView) layout.findViewById(R.id.cplus_toast_icon); + iv.setImageResource(R.drawable.ic_toast_error); + } + + Toast toast = new Toast(applicationContext); + toast.setDuration(duration); + toast.setView(layout); + toast.show(); + } + } +} diff --git a/src/main/res/drawable-hdpi/ic_toast.png b/src/main/res/drawable-hdpi/ic_toast.png new file mode 100644 index 00000000..fd5d1d8b Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_toast.png differ diff --git a/src/main/res/drawable-hdpi/ic_toast_error.png b/src/main/res/drawable-hdpi/ic_toast_error.png new file mode 100644 index 00000000..31de0901 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_toast_error.png differ diff --git a/src/main/res/layout/cplus_toast_container.xml b/src/main/res/layout/cplus_toast_container.xml new file mode 100644 index 00000000..f2aa09e3 --- /dev/null +++ b/src/main/res/layout/cplus_toast_container.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file -- cgit v1.2.3 From 563fcfa77580292a7ff2360eea20553743bd0ae7 Mon Sep 17 00:00:00 2001 From: steckbrief Date: Wed, 11 Jan 2017 14:49:07 +0100 Subject: Generic view util added to change the visibility of subclasses of View --- .../conversationsplus/utils/ui/TextViewUtil.java | 4 +-- .../conversationsplus/utils/ui/ViewUtil.java | 39 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/thedevstack/conversationsplus/utils/ui/ViewUtil.java diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/ui/TextViewUtil.java b/src/main/java/de/thedevstack/conversationsplus/utils/ui/TextViewUtil.java index a775dad6..27a269f2 100644 --- a/src/main/java/de/thedevstack/conversationsplus/utils/ui/TextViewUtil.java +++ b/src/main/java/de/thedevstack/conversationsplus/utils/ui/TextViewUtil.java @@ -5,9 +5,9 @@ import android.view.View; import android.widget.TextView; /** - * Created by steckbrief on 29.03.2016. + * */ -public final class TextViewUtil { +public final class TextViewUtil extends ViewUtil { public static void setText(View parentView, int textViewId, CharSequence text) { TextView tv = (TextView) parentView.findViewById(textViewId); diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/ui/ViewUtil.java b/src/main/java/de/thedevstack/conversationsplus/utils/ui/ViewUtil.java new file mode 100644 index 00000000..77422587 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/utils/ui/ViewUtil.java @@ -0,0 +1,39 @@ +package de.thedevstack.conversationsplus.utils.ui; + +import android.support.annotation.IdRes; +import android.view.View; + +/** + * Created by steckbrief on 11.01.2017. + */ + +public class ViewUtil { + + public static T visible(View parentView, @IdRes int textViewId) { + T tv = (T) parentView.findViewById(textViewId); + if (null != tv) { + tv.setVisibility(View.VISIBLE); + } + + return tv; + } + + public static T invisible(View parentView, @IdRes int textViewId) { + T tv = (T) parentView.findViewById(textViewId); + if (null != tv) { + tv.setVisibility(View.INVISIBLE); + } + + return tv; + } + + public static T gone(View parentView, @IdRes int textViewId) { + T tv = (T) parentView.findViewById(textViewId); + if (null != tv) { + tv.setVisibility(View.GONE); + } + + return tv; + } + +} -- cgit v1.2.3 From 0a9bba28616e594279cd659ec2eb57da2074b3cd Mon Sep 17 00:00:00 2001 From: steckbrief Date: Wed, 11 Jan 2017 14:55:53 +0100 Subject: Improved error handling for filetransfer:http:delete, Check for httpupload feature available extended to include filetransfer:http as well, method to check if http upload is available moved from data class 'Account' to 'AccountUtil' --- .../conversationsplus/entities/Account.java | 8 --- .../services/XmppConnectionService.java | 6 +- .../http/delete/DeleteRemoteFileService.java | 16 +++-- .../http/delete/DeleteTokenReceived.java | 10 +++ .../http/upload/HttpUploadFileTransferService.java | 26 +++++--- .../conversationsplus/ui/ConversationActivity.java | 5 +- .../conversationsplus/ui/ConversationFragment.java | 7 +-- .../conversationsplus/ui/ShareWithActivity.java | 5 +- .../ui/adapter/MessageAdapter.java | 17 +++--- .../conversationsplus/utils/AccountUtil.java | 34 +++++++++++ .../thedevstack/conversationsplus/utils/Xmlns.java | 3 - .../conversationsplus/xmpp/XmppConnection.java | 71 +++++++++++++++------- .../xmpp/utils/ErrorIqPacketExceptionHelper.java | 29 +++++---- src/main/res/values/strings.xml | 2 + 14 files changed, 160 insertions(+), 79 deletions(-) create mode 100644 src/main/java/de/thedevstack/conversationsplus/utils/AccountUtil.java diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Account.java b/src/main/java/de/thedevstack/conversationsplus/entities/Account.java index 2ee76504..1c7ad288 100644 --- a/src/main/java/de/thedevstack/conversationsplus/entities/Account.java +++ b/src/main/java/de/thedevstack/conversationsplus/entities/Account.java @@ -56,14 +56,6 @@ public class Account extends AbstractEntity { public static final int OPTION_USECOMPRESSION = 3; public final HashSet> inProgressDiscoFetches = new HashSet<>(); - public boolean httpUploadAvailable(long filesize) { - return xmppConnection != null && xmppConnection.getFeatures().httpUpload(filesize); - } - - public boolean httpUploadAvailable() { - return httpUploadAvailable(0); - } - public void setDisplayName(String displayName) { this.displayName = displayName; } diff --git a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java index 83cefc80..ee0ee14a 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java @@ -38,7 +38,6 @@ import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; import java.math.BigInteger; -import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -53,11 +52,11 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -import de.duenndns.ssl.MemorizingTrustManager; import de.thedevstack.android.logcat.Logging; import de.thedevstack.conversationsplus.ConversationsPlusApplication; import de.thedevstack.conversationsplus.ConversationsPlusPreferences; import de.thedevstack.conversationsplus.services.filetransfer.FileTransferManager; +import de.thedevstack.conversationsplus.utils.AccountUtil; import de.thedevstack.conversationsplus.utils.ImageUtil; import de.thedevstack.conversationsplus.utils.MessageUtil; import de.thedevstack.conversationsplus.utils.UiUpdateHelper; @@ -85,7 +84,6 @@ import de.thedevstack.conversationsplus.entities.TransferablePlaceholder; import de.thedevstack.conversationsplus.generator.IqGenerator; import de.thedevstack.conversationsplus.generator.MessageGenerator; import de.thedevstack.conversationsplus.generator.PresenceGenerator; -import de.thedevstack.conversationsplus.http.HttpConnectionManager; import de.thedevstack.conversationsplus.parser.IqParser; import de.thedevstack.conversationsplus.parser.MessageParser; import de.thedevstack.conversationsplus.parser.PresenceParser; @@ -1080,7 +1078,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } else { for (Conversation conversation : getConversations()) { if (conversation.getMode() == Conversation.MODE_SINGLE - || conversation.getAccount().httpUploadAvailable()) { + || AccountUtil.isHttpUploadAvailable(conversation.getAccount())) { list.add(conversation); } } diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java index eb9f1b04..2085cf4b 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java @@ -31,12 +31,16 @@ public class DeleteRemoteFileService implements SimpleUserDecisionCallback { path = this.message.getFileParams().getUrl(); } - DeleteRemoteFile remoteFile = new DeleteRemoteFile(path, this.message); - Account account = this.message.getConversation().getAccount(); - Jid host = account.getXmppConnection().findDiscoItemByFeature(FileTransferHttp.NAMESPACE); - IqPacket request = FileTransferHttpDeleteSlotRequestPacketGenerator.generate(host, path); - MessageUtil.setAndSaveFileStatus(this.message, FileStatus.DELETING); - XmppSendUtil.sendIqPacket(account, request, new DeleteTokenReceived(remoteFile)); + if (null != path) { + DeleteRemoteFile remoteFile = new DeleteRemoteFile(path, this.message); + Account account = this.message.getConversation().getAccount(); + Jid host = account.getXmppConnection().findDiscoItemByFeature(FileTransferHttp.NAMESPACE); + if (null != host) { + IqPacket request = FileTransferHttpDeleteSlotRequestPacketGenerator.generate(host, path); + MessageUtil.setAndSaveFileStatus(this.message, FileStatus.DELETING); + XmppSendUtil.sendIqPacket(account, request, new DeleteTokenReceived(remoteFile)); + } + } } } diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteTokenReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteTokenReceived.java index 186454e4..83a250de 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteTokenReceived.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteTokenReceived.java @@ -1,16 +1,21 @@ package de.thedevstack.conversationsplus.services.filetransfer.http.delete; +import android.widget.Toast; + import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import de.thedevstack.android.logcat.Logging; +import de.thedevstack.conversationsplus.R; import de.thedevstack.conversationsplus.entities.Account; import de.thedevstack.conversationsplus.enums.FileStatus; import de.thedevstack.conversationsplus.http.HttpClient; import de.thedevstack.conversationsplus.utils.MessageUtil; +import de.thedevstack.conversationsplus.utils.ui.ConversationsPlusToast; import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived; +import de.thedevstack.conversationsplus.xmpp.exceptions.ServiceUnavailableException; import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException; import de.thedevstack.conversationsplus.xmpp.filetransfer.http.delete.DeleteSlotPacketParser; import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; @@ -81,6 +86,11 @@ public class DeleteTokenReceived implements OnIqPacketReceived { } catch (XmppException e) { Logging.e("filetransfer.http.delete", "Error while trying to get the delete token: " + e.getMessage()); + int messageResId = R.string.cplus_remote_file_delete_failed; + if (e instanceof ServiceUnavailableException) { + messageResId = R.string.cplus_remote_file_delete_service_unavailable; + } + ConversationsPlusToast.makeErrorToast(messageResId, Toast.LENGTH_LONG); MessageUtil.setAndSaveFileStatus(remoteFile.getMessage(), FileStatus.DELETE_FAILED); } } diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java index 6b19cd5f..f0bb438d 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java @@ -13,8 +13,10 @@ import de.thedevstack.conversationsplus.persistance.FileBackend; import de.thedevstack.conversationsplus.services.AbstractConnectionManager; import de.thedevstack.conversationsplus.services.FileTransferService; import de.thedevstack.conversationsplus.services.filetransfer.AbstractFileTransferService; +import de.thedevstack.conversationsplus.utils.AccountUtil; import de.thedevstack.conversationsplus.utils.MessageUtil; import de.thedevstack.conversationsplus.utils.XmppSendUtil; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; import de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload.HttpUpload; import de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload.HttpUploadRequestSlotPacketGenerator; import de.thedevstack.conversationsplus.xmpp.jid.Jid; @@ -62,19 +64,29 @@ public class HttpUploadFileTransferService extends AbstractFileTransferService i file.setExpectedSize(inputStreamAndExpectedSize.second); Logging.d("httpupload", "Requesting upload slot for file upload"); - Jid host = account.getXmppConnection().findDiscoItemByFeature(HttpUpload.NAMESPACE); - IqPacket request = HttpUploadRequestSlotPacketGenerator.generate(host, file.getName(), file.getSize(), file.getMimeType()); - XmppSendUtil.sendIqPacket(account, request, new HttpUploadSlotRequestReceived(entity)); - MessageUtil.markMessage(message, Message.STATUS_UNSEND); + Jid host = this.getHost(account); + if (null != host) { + IqPacket request = HttpUploadRequestSlotPacketGenerator.generate(host, file.getName(), file.getSize(), file.getMimeType()); + XmppSendUtil.sendIqPacket(account, request, new HttpUploadSlotRequestReceived(entity)); + MessageUtil.markMessage(message, Message.STATUS_UNSEND); - Logging.d("httpupload", "Upload slot for file upload requested"); - started = true; + Logging.d("httpupload", "Upload slot for file upload requested"); + started = true; + } } catch (FileNotFoundException e) { Logging.e("httpupload", "Could not find file, exception message: " + e.getMessage()); } return started; } + private Jid getHost(Account account) { + Jid host = account.getXmppConnection().findDiscoItemByFeature(FileTransferHttp.NAMESPACE); + if (null == host) { + host = account.getXmppConnection().findDiscoItemByFeature(HttpUpload.NAMESPACE); + } + return host; + } + /** * Checks whether a message can be sent using this service or not. * @@ -87,6 +99,6 @@ public class HttpUploadFileTransferService extends AbstractFileTransferService i && null != message.getConversation() && null != message.getConversation().getAccount() && null != message.getFileParams() - && message.getConversation().getAccount().httpUploadAvailable(message.getFileParams().getSize()); + && AccountUtil.isHttpUploadAvailable(message.getConversation().getAccount(), message.getFileParams().getSize()); } } diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java index ac9c2766..bca0851a 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import de.thedevstack.android.logcat.Logging; +import de.thedevstack.conversationsplus.utils.AccountUtil; import de.timroes.android.listview.EnhancedListView; import de.thedevstack.conversationsplus.Config; @@ -422,7 +423,7 @@ public class ConversationActivity extends XmppActivity } if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) { menuContactDetails.setVisible(false); - menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating()); + menuAttach.setVisible(AccountUtil.isHttpUploadAvailable(getSelectedConversation().getAccount()) && getSelectedConversation().getMucOptions().participating()); menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite()); menuSecure.setVisible((Config.supportOpenPgp() || Config.supportOmemo()) && Config.multipleEncryptionChoices()); //only if pgp is supported we have a choice } else { @@ -493,7 +494,7 @@ public class ConversationActivity extends XmppActivity } } }; - if ((account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) && encryption != Message.ENCRYPTION_OTR) { + if ((AccountUtil.isHttpUploadAvailable(account) || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) && encryption != Message.ENCRYPTION_OTR) { conversation.setNextCounterpart(null); callback.onPresenceSelected(); } else { diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java index aad15f51..157e6dc3 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java @@ -69,8 +69,7 @@ import de.thedevstack.conversationsplus.ui.adapter.MessageAdapter.OnContactPictu import de.thedevstack.conversationsplus.ui.adapter.MessageAdapter.OnContactPictureLongClicked; import de.thedevstack.conversationsplus.ui.listeners.ConversationSwipeRefreshListener; import de.thedevstack.conversationsplus.ui.listeners.DeleteFileCallback; -import de.thedevstack.conversationsplus.ui.listeners.SimpleUserDecisionCallback; -import de.thedevstack.conversationsplus.ui.listeners.UserDecisionListener; +import de.thedevstack.conversationsplus.utils.AccountUtil; import de.thedevstack.conversationsplus.utils.GeoHelper; import de.thedevstack.conversationsplus.utils.MessageUtil; import de.thedevstack.conversationsplus.utils.UIHelper; @@ -578,7 +577,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa deleteFile.setVisible(true); deleteFile.setTitle(activity.getString(R.string.delete_x_file,UIHelper.getFileDescriptionString(activity, m))); } - if (m.isHttpUploaded() && MessageUtil.isMessageSent(m)) { + if (m.isHttpUploaded() && MessageUtil.isMessageSent(m) && AccountUtil.isFileTransferHttpAvailable(m.getConversation().getAccount())) { MenuItem deleteRemoteFile = menu.findItem(R.id.msg_ctx_menu_delete_remote_file); deleteRemoteFile.setVisible(true); } @@ -1038,7 +1037,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 (conference && !c.getAccount().httpUploadAvailable()) { + if (conference && !AccountUtil.isHttpUploadAvailable(c.getAccount())) { if (empty && c.getNextCounterpart() != null) { action = SendButtonAction.CANCEL; } else { diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ShareWithActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/ShareWithActivity.java index 28e8beb8..8852212b 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/ShareWithActivity.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/ShareWithActivity.java @@ -15,7 +15,6 @@ import android.widget.Toast; import java.net.URLConnection; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -28,9 +27,9 @@ import de.thedevstack.conversationsplus.R; import de.thedevstack.conversationsplus.entities.Account; import de.thedevstack.conversationsplus.entities.Conversation; import de.thedevstack.conversationsplus.entities.Message; -import de.thedevstack.conversationsplus.persistance.FileBackend; import de.thedevstack.conversationsplus.services.XmppConnectionService; import de.thedevstack.conversationsplus.ui.adapter.ConversationAdapter; +import de.thedevstack.conversationsplus.utils.AccountUtil; import de.thedevstack.conversationsplus.utils.ConversationUtil; import de.thedevstack.conversationsplus.utils.FileUtils; import de.thedevstack.conversationsplus.xmpp.jid.InvalidJidException; @@ -307,7 +306,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer } }; } - if (account.httpUploadAvailable() + if (AccountUtil.isHttpUploadAvailable(account) && (conversation.getMode() == Conversation.MODE_MULTI || FileUtils.allFilesUnderSize(this, share.uris, max)) && conversation.getNextEncryption() != Message.ENCRYPTION_OTR) { diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java index ac8fba0a..a6bdec69 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java @@ -57,6 +57,8 @@ import de.thedevstack.conversationsplus.utils.CryptoHelper; import de.thedevstack.conversationsplus.utils.GeoHelper; import de.thedevstack.conversationsplus.utils.MessageUtil; import de.thedevstack.conversationsplus.utils.UIHelper; +import de.thedevstack.conversationsplus.utils.ui.TextViewUtil; +import de.thedevstack.conversationsplus.utils.ui.ViewUtil; public class MessageAdapter extends ArrayAdapter { @@ -605,8 +607,7 @@ public class MessageAdapter extends ArrayAdapter { ViewHolder viewHolder = new ViewHolder(view); if (SENT == type || RECEIVED == type) { - viewHolder.message_box = (LinearLayout) view.findViewById(R.id.message_box); - viewHolder.message_box.setVisibility(View.VISIBLE); + viewHolder.message_box = ViewUtil.visible(view, R.id.message_box); viewHolder.indicator = (ImageView) view.findViewById(R.id.security_indicator); viewHolder.messageBody = (TextView) view.findViewById(R.id.message_body); viewHolder.time = (TextView) view.findViewById(R.id.message_time); @@ -618,17 +619,17 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.image = (ImageView) view.findViewById(R.id.message_image); } if (RECEIVED == type) { // Extra block as preparation for new /me representation - viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); - viewHolder.contact_picture.setVisibility(View.VISIBLE); + viewHolder.contact_picture = ViewUtil.visible(view, R.id.message_photo); } if (RECEIVED == type) { viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption); } if (STATUS == type) { - viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); - viewHolder.contact_picture.setVisibility(View.VISIBLE); - viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); - viewHolder.status_message.setVisibility(View.VISIBLE); + viewHolder.contact_picture = ViewUtil.visible(view, R.id.message_photo); + viewHolder.status_message = TextViewUtil.visible(view, R.id.status_message); + } + if (SENT == type) { + viewHolder.remoteFileStatus = TextViewUtil.visible(view, R.id.remote_file_status); } view.setTag(viewHolder); diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/AccountUtil.java b/src/main/java/de/thedevstack/conversationsplus/utils/AccountUtil.java new file mode 100644 index 00000000..0ea434f7 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/utils/AccountUtil.java @@ -0,0 +1,34 @@ +package de.thedevstack.conversationsplus.utils; + +import de.thedevstack.conversationsplus.entities.Account; + +/** + * Utility class to work with accounts. + */ +public final class AccountUtil { + + public static boolean isHttpUploadAvailable(Account account, long filesize) { + return null != account + && null != account.getXmppConnection() + && null != account.getXmppConnection().getFeatures() + && account.getXmppConnection().getFeatures().httpUpload(filesize); + } + + public static boolean isHttpUploadAvailable(Account account) { + return null != account + && null != account.getXmppConnection() + && null != account.getXmppConnection().getFeatures() + && account.getXmppConnection().getFeatures().httpUpload(0); + } + + public static boolean isFileTransferHttpAvailable(Account account) { + return null != account + && null != account.getXmppConnection() + && null != account.getXmppConnection().getFeatures() + && account.getXmppConnection().getFeatures().hasFeatureFileTransferHttp(0); + } + + private AccountUtil() { + // avoid instantiation of utility class + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/Xmlns.java b/src/main/java/de/thedevstack/conversationsplus/utils/Xmlns.java index 35adf6ec..80718dec 100644 --- a/src/main/java/de/thedevstack/conversationsplus/utils/Xmlns.java +++ b/src/main/java/de/thedevstack/conversationsplus/utils/Xmlns.java @@ -1,11 +1,8 @@ package de.thedevstack.conversationsplus.utils; -import de.thedevstack.conversationsplus.Config; - public final class Xmlns { public static final String BLOCKING = "urn:xmpp:blocking"; public static final String ROSTER = "jabber:iq:roster"; public static final String REGISTER = "jabber:iq:register"; public static final String BYTE_STREAMS = "http://jabber.org/protocol/bytestreams"; - public static final String HTTP_UPLOAD = "urn:xmpp:http:upload"; } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java index c5a8fe3b..1082e19f 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java @@ -71,6 +71,8 @@ import de.thedevstack.conversationsplus.xml.Element; import de.thedevstack.conversationsplus.xml.Tag; import de.thedevstack.conversationsplus.xml.TagWriter; import de.thedevstack.conversationsplus.xml.XmlReader; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload.HttpUpload; import de.thedevstack.conversationsplus.xmpp.forms.Data; import de.thedevstack.conversationsplus.xmpp.forms.Field; import de.thedevstack.conversationsplus.xmpp.jid.InvalidJidException; @@ -1534,35 +1536,62 @@ public class XmppConnection implements Runnable { this.blockListRequested = value; } + public boolean hasFeatureFileTransferHttp(long filesize) { + if (Config.DISABLE_HTTP_UPLOAD) { + return false; + } else { + List> items = findDiscoItemsByFeature(FileTransferHttp.NAMESPACE); + if (items.size() > 0) { + long maxsize = this.parseMaxHttpUploadSize(items.get(0), FileTransferHttp.NAMESPACE); + return filesize <= maxsize; + } else { + return false; + } + } + } + public boolean httpUpload(long filesize) { if (Config.DISABLE_HTTP_UPLOAD) { return false; } else { - List> items = findDiscoItemsByFeature(Xmlns.HTTP_UPLOAD); - if (items.size() > 0) { - try { - long maxsize = Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Xmlns.HTTP_UPLOAD, "max-file-size")); - return filesize <= maxsize; - } catch (Exception e) { - return true; - } - } else { - return false; - } + if (hasFeatureFileTransferHttp(filesize)) { + return true; + } else { + List> items = findDiscoItemsByFeature(HttpUpload.NAMESPACE); + if (items.size() > 0) { + long maxsize = this.parseMaxHttpUploadSize(items.get(0), HttpUpload.NAMESPACE); + return filesize <= maxsize; + } else { + return false; + } + } } } + private long parseMaxHttpUploadSize(Entry item, String namespace) { + long maxsize = Long.MAX_VALUE; + if (null != item && null != namespace) { + try { + maxsize = Long.parseLong(item.getValue().getExtendedDiscoInformation(namespace, "max-file-size")); + } catch (Exception e) { + // Suppress exception + } + } + return maxsize; + } + public long getMaxHttpUploadSize() { - List> items = findDiscoItemsByFeature(Xmlns.HTTP_UPLOAD); - if (items.size() > 0) { - try { - return Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Xmlns.HTTP_UPLOAD, "max-file-size")); - } catch (Exception e) { - return -1; - } - } else { - return -1; - } + List> items = findDiscoItemsByFeature(HttpUpload.NAMESPACE); + if (items.size() > 0) { + long maxsize = this.parseMaxHttpUploadSize(items.get(0), HttpUpload.NAMESPACE); + if (Long.MAX_VALUE == maxsize) { // For code compatibility - legacy behavior returns -1 in case of no max-file-size + return -1; + } else { + return maxsize; + } + } else { + return -1; + } } } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java index f02d8d46..bcc5e9dd 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java @@ -14,20 +14,23 @@ import de.thedevstack.conversationsplus.xmpp.exceptions.UndefinedConditionExcept public final class ErrorIqPacketExceptionHelper { private final static String ERROR_NAMESPACE = "urn:ietf:params:xml:ns:xmpp-stanzas"; - public static void throwIqErrorException(Element packet) throws IqPacketErrorException { - if (hasErrorElement(packet, "bad-request")) { - throw new BadRequestIqErrorException(packet, getErrorText(packet)); + public static void throwIqErrorException(Element errorIqPacket) throws IqPacketErrorException { + Element packet = IqPacketParser.findChild(errorIqPacket, "error", "jabber:client"); + if (null != packet) { + if (hasErrorElement(packet, "bad-request")) { + throw new BadRequestIqErrorException(errorIqPacket, getErrorText(packet)); + } + if (hasErrorElement(packet, "service-unavailable")) { + throw new ServiceUnavailableException(errorIqPacket, getErrorText(packet)); + } + if (hasErrorElement(packet, "internal-server-error")) { + throw new InternalServerErrorException(errorIqPacket, getErrorText(packet)); + } + if (hasErrorElement(packet, "undefined-condition")) { + throw new UndefinedConditionException(errorIqPacket, getErrorText(packet)); + } } - if (hasErrorElement(packet, "service-unavailable")) { - throw new ServiceUnavailableException(packet, getErrorText(packet)); - } - if (hasErrorElement(packet, "internal-server-error")) { - throw new InternalServerErrorException(packet, getErrorText(packet)); - } - if (hasErrorElement(packet, "undefined-condition")) { - throw new UndefinedConditionException(packet, getErrorText(packet)); - } - throw new IqPacketErrorException(packet, "Unknown error packet."); + throw new IqPacketErrorException(errorIqPacket, "Unknown error packet."); } private static boolean hasErrorElement(Element packet, String elementName) { diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index b4b4d2c5..251db18e 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -682,4 +682,6 @@ No file on remote host Original Filename Open + Remote File Deletion Service currently unavailable. Please try again later. + Failed to delete remote file. -- cgit v1.2.3 From cd633f13b8d7327e47994bb5a000f0c0b7089e7f Mon Sep 17 00:00:00 2001 From: steckbrief Date: Wed, 11 Jan 2017 15:12:53 +0100 Subject: Formatting of remote file status adjusted --- .../de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java | 4 ++-- src/main/res/layout/message_sent.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java index a6bdec69..79ab3bc3 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java @@ -238,9 +238,9 @@ public class MessageAdapter extends ArrayAdapter { FileStatus fileStatus = message.getFileParams().getFileStatus(); if (fileStatus == FileStatus.DELETE_FAILED || fileStatus == FileStatus.DELETED || fileStatus == FileStatus.DELETING) { viewHolder.remoteFileStatus.setVisibility(View.VISIBLE); - viewHolder.remoteFileStatus.setTypeface(null, Typeface.ITALIC); switch (fileStatus) { case DELETE_FAILED: + TextViewUtil.setColor(viewHolder.remoteFileStatus, R.color.error); viewHolder.remoteFileStatus.setText(R.string.remote_filestatus_delete_failed); break; case DELETED: @@ -629,7 +629,7 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.status_message = TextViewUtil.visible(view, R.id.status_message); } if (SENT == type) { - viewHolder.remoteFileStatus = TextViewUtil.visible(view, R.id.remote_file_status); + viewHolder.remoteFileStatus = TextViewUtil.gone(view, R.id.remote_file_status); } view.setTag(viewHolder); diff --git a/src/main/res/layout/message_sent.xml b/src/main/res/layout/message_sent.xml index f59c51f3..8bda9c8f 100644 --- a/src/main/res/layout/message_sent.xml +++ b/src/main/res/layout/message_sent.xml @@ -117,7 +117,7 @@ android:textColor="@color/secondaryText" android:textSize="?attr/TextSizeInfo" android:visibility="gone" - android:textStyle="italic"/> + android:textStyle="normal|italic"/> -- cgit v1.2.3