package bf.io.openshop.utils; import android.app.Activity; import android.app.ProgressDialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.Browser; import android.support.design.widget.TextInputLayout; import android.text.SpannableString; import android.text.Spanned; import android.text.style.URLSpan; import android.util.DisplayMetrics; import android.view.View; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import bf.io.openshop.R; import bf.io.openshop.entities.filtr.DeserializerFilters; import bf.io.openshop.entities.filtr.Filters; import timber.log.Timber; public class Utils { private static Gson gson; private Utils() {} /** * Add specific parsing to gson * * @return new instance of {@link Gson} */ public static Gson getGsonParser() { if (gson == null) { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Filters.class, new DeserializerFilters()); gson = gsonBuilder.create(); } return gson; } /** * Generate top layer progress indicator. * * @param context activity context * @param cancelable can be progress layer canceled * @return dialog */ public static ProgressDialog generateProgressDialog(Context context, boolean cancelable) { ProgressDialog progressDialog = new ProgressDialog(context, R.style.ProgressTheme); progressDialog.setMessage(context.getString(R.string.Loading)); progressDialog.setCancelable(cancelable); return progressDialog; } /** * Check the device to make sure it has the Google Play Services APK. If * it doesn't, display a dialog that allows users to download the APK from * the Google Play Store or enable it in the device's system settings. */ public static boolean checkPlayServices(Activity activity) { GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); int resultCode = apiAvailability.isGooglePlayServicesAvailable(activity); if (resultCode != ConnectionResult.SUCCESS) { Timber.e("Google play services don't working."); if (apiAvailability.isUserResolvableError(resultCode)) { apiAvailability.getErrorDialog(activity, resultCode, 9000) .show(); } else { Timber.e("GCM - This device is not supported."); } return false; } return true; } /** * Method converts iso date string to better readable form. * * @param isoDate input iso date. Example: "2016-04-13 13:21:04". * @return processed date string. */ public static String parseDate(String isoDate) { try { String[] parts = isoDate.split("-"); String year = parts[0]; String month = parts[1]; String dayTemp = parts[2]; String[] parts2 = dayTemp.split(" "); String day = parts2[0].trim(); if (day.length() > 2) throw new RuntimeException("String with day number unexpected length."); return day + "." + month + "." + year; } catch (Exception e) { Timber.e(e, "Parsing order date created failed."); return isoDate; } } /** * Method replace ordinary {@link URLSpan} with {@link DefensiveURLSpan}. * * @param spannedText text, where link spans should be replaced. * @param activity activity for displaying problems. * @return text, where link spans are replaced. */ public static SpannableString safeURLSpanLinks(Spanned spannedText, Activity activity) { final SpannableString current = new SpannableString(spannedText); final URLSpan[] spans = current.getSpans(0, current.length(), URLSpan.class); int start, end; for (URLSpan span : spans) { start = current.getSpanStart(span); end = current.getSpanEnd(span); current.removeSpan(span); current.setSpan(new DefensiveURLSpan(span.getURL(), activity), start, end, 0); } return current; } public static int dpToPx(Context context, int dp) { return Math.round(dp * getPixelScaleFactor(context)); } public static int pxToDp(Context context, int px) { return Math.round(px / getPixelScaleFactor(context)); } private static float getPixelScaleFactor(Context context) { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); return displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT; } public static Bitmap drawableToBitmap(Drawable drawable) { if (drawable instanceof BitmapDrawable) return ((BitmapDrawable) drawable).getBitmap(); // We ask for the bounds if they have been set as they would be most // correct, then we check we are > 0 final int width = !drawable.getBounds().isEmpty() ? drawable.getBounds().width() : drawable.getIntrinsicWidth(); final int height = !drawable.getBounds().isEmpty() ? drawable.getBounds().height() : drawable.getIntrinsicHeight(); // Now we check we are > 0 final Bitmap bitmap = Bitmap.createBitmap(width <= 0 ? 1 : width, height <= 0 ? 1 : height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } /** * Method calculates the percentage discounts. * * @param context simple context. * @param price Base product price. * @param discountPrice Product price after discount. * @return percentage discount with percent symbol. */ public static String calculateDiscountPercent(Context context, double price, double discountPrice) { int percent; if (discountPrice >= price) { percent = 0; } else { percent = (int) Math.round(100 - ((discountPrice / price) * 100)); } return String.format(context.getString(R.string.format_price_discount_percents), percent); } /** * Check if textInputLayout contains editText view. If so, then set text value to the view. * * @param textInputLayout wrapper for the editText view where the text value should be set. * @param text text value to display. */ public static void setTextToInputLayout(TextInputLayout textInputLayout, String text) { if (textInputLayout != null && textInputLayout.getEditText() != null) { textInputLayout.getEditText().setText(text); } else { Timber.e("Setting text to null input wrapper, or without editText"); } } /** * Check if textInputLayout contains editText view. If so, then return text value of the view. * * @param textInputLayout wrapper for the editText view. * @return text value of the editText view. */ public static String getTextFromInputLayout(TextInputLayout textInputLayout) { if (textInputLayout != null && textInputLayout.getEditText() != null) { return textInputLayout.getEditText().getText().toString(); } else { return null; } } /** * Method checks if text input layout exist and contains some value. * If layout is empty, then show error value under the textInputLayout. * * @param textInputLayout textInputFiled for check. * @param errorValue value displayed when ext input is empty. * @return true if everything ok. */ public static boolean checkTextInputLayoutValueRequirement(TextInputLayout textInputLayout, String errorValue) { if (textInputLayout != null && textInputLayout.getEditText() != null) { String text = Utils.getTextFromInputLayout(textInputLayout); if (text == null || text.isEmpty()) { textInputLayout.setErrorEnabled(true); textInputLayout.setError(errorValue); Timber.d("Input field %s missing text.", textInputLayout.getHint()); return false; } else { textInputLayout.setErrorEnabled(false); Timber.d("Input field: %s OK.", textInputLayout.getHint()); return true; } } else { Timber.e(new RuntimeException(), "Checking null input field during order send."); return false; } } /** * URLSpan which handles bad url format exception. */ private static class DefensiveURLSpan extends URLSpan { Activity activity; public DefensiveURLSpan(String url, Activity activity) { super(url); this.activity = activity; } @Override public void onClick(View widget) { Uri uri = Uri.parse(getURL()); Context context = widget.getContext(); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); try { context.startActivity(intent); } catch (ActivityNotFoundException e) { if (activity != null && !activity.isFinishing()) { MsgUtils.showToast(activity, MsgUtils.TOAST_TYPE_MESSAGE, activity.getString(R.string.Link_is_invalid), MsgUtils.ToastLength.SHORT); Timber.e(e, "Invoked invalid web link: %s", uri); } } } } }