/*
* Copyright (C) 2012-2016 The Android Money Manager Ex Project Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.money.manager.ex.core;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.view.LayoutInflater;
import android.view.View;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.money.manager.ex.Constants;
import com.money.manager.ex.MoneyManagerApplication;
import com.money.manager.ex.R;
import com.money.manager.ex.database.MmxOpenHelper;
import com.money.manager.ex.domainmodel.Payee;
import com.money.manager.ex.settings.AppSettings;
import com.money.manager.ex.utils.MmxDatabaseUtils;
import com.money.manager.ex.utils.MmxFileUtils;
import java.io.File;
import java.text.DateFormatSymbols;
import java.text.Normalizer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Locale;
import javax.inject.Inject;
import dagger.Lazy;
import timber.log.Timber;
public class Core {
@Inject
public Core(Context context) {
super();
this.mContext = context;
// .getApplicationContext() == null ? context.getApplicationContext() : context;
MoneyManagerApplication.getApp().iocComponent.inject(this);
}
private Context mContext;
@Inject Lazy<MmxOpenHelper> openHelper;
@Inject Lazy<AppSettings> appSettingsLazy;
/**
* Show alert dialog.
* @param textResourceId id of string to display as a message
*/
public void alert(int textResourceId) {
alert(Constants.NOT_SET, textResourceId);
}
public void alert(int title, int text) {
if (title == Constants.NOT_SET) {
title = R.string.attention;
}
new MaterialDialog.Builder(getContext())
.icon(new UIHelper(getContext()).getIcon(GoogleMaterial.Icon.gmd_warning))
.title(title)
.content(text)
.positiveText(android.R.string.ok)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
}
})
.show();
}
/**
* Backup current database
* @return new File database backup
*/
public File backupDatabase() {
File database = new File(MoneyManagerApplication.getDatabasePath(getContext()));
if (!database.exists()) return null;
//create folder to copy database
MmxDatabaseUtils dbUtils = new MmxDatabaseUtils(getContext());
File folderOutput = new File(dbUtils.getDefaultDatabaseDirectory());
//take a folder of database
ArrayList<File> filesFromCopy = new ArrayList<>();
//add current database
filesFromCopy.add(database);
//get file journal
File folder = database.getParentFile();
if (folder != null) {
for (File file : folder.listFiles()) {
if (file.getName().startsWith(database.getName()) && !database.getName().equals(file.getName())) {
filesFromCopy.add(file);
}
}
}
//copy all files
for (int i = 0; i < filesFromCopy.size(); i++) {
try {
MmxFileUtils.copy(filesFromCopy.get(i), new File(folderOutput + "/" + filesFromCopy.get(i).getName()));
} catch (Exception e) {
Timber.e(e, "backing up the database");
return null;
}
}
return new File(folderOutput + "/" + filesFromCopy.get(0).getName());
}
// public String getAppVersionBuild() {
// return Integer.toString(getAppVersionCode());
// }
/**
* Get a versioncode of the application.
* @return application version name
*/
public int getAppVersionCode() {
try {
PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(
getContext().getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
Timber.e(e, "getting app version build number");
return 0;
}
}
public String getAppVersionName() {
try {
return getContext().getPackageManager()
.getPackageInfo(getContext().getPackageName(), 0)
.versionName;
} catch (PackageManager.NameNotFoundException e) {
Timber.e(e, "getting app version name");
}
return "n/a";
}
public Context getContext() {
return mContext;
}
/**
* Method, which returns the last payee used
* @return last payee used
*/
public Payee getLastPayeeUsed() {
// MmxOpenHelper helper = MmxOpenHelper.getInstance(getContext());
Payee payee = null;
String sql =
"SELECT C.TransID, C.TransDate, C.PAYEEID, P.PAYEENAME, P.CATEGID, P.SUBCATEGID " +
"FROM CHECKINGACCOUNT_V1 C " +
"INNER JOIN PAYEE_V1 P ON C.PAYEEID = P.PAYEEID " +
"WHERE C.TransCode <> 'Transfer' " +
"ORDER BY C.TransDate DESC, C.TransId DESC " +
"LIMIT 1";
Cursor cursor = openHelper.get().getReadableDatabase().rawQuery(sql, null);
// check if cursor can be open
if (cursor != null && cursor.moveToFirst()) {
payee = new Payee();
// payee.setPayeeId(cursor.getInt(cursor.getColumnIndex(Payee.PAYEEID)));
// payee.setPayeeName(cursor.getString(cursor.getColumnIndex(Payee.PAYEENAME)));
// payee.setCategId(cursor.getInt(cursor.getColumnIndex(Payee.CATEGID)));
// payee.setSubCategId(cursor.getInt(cursor.getColumnIndex(Payee.SUBCATEGID)));
payee.loadFromCursor(cursor);
cursor.close();
}
//close database
//helper.close();
return payee;
}
/**
* Return arrays of month formatted and localized
* @return arrays of months
*/
public String[] getListMonths() {
return new DateFormatSymbols().getMonths();
}
public String getDefaultSystemDateFormat() {
Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat) SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT, locale);
String pattern = sdf.toLocalizedPattern();
// replace date
if (pattern.contains("dd")) {
pattern = pattern.replace("dd", "%d");
} else {
pattern = pattern.replace("d", "%d");
}
// replace month
if (pattern.contains("MM")) {
pattern = pattern.replace("MM", "%m");
} else {
pattern = pattern.replace("M", "%m");
}
// replace year
pattern = pattern.replace("yyyy", "%Y");
pattern = pattern.replace("yy", "%y");
// check if exists in format definition
boolean found = false;
String[] availableDateFormats = getContext().getResources().getStringArray(R.array.date_format_mask);
for (int i = 0; i < availableDateFormats.length; i++) {
if (pattern.equals(availableDateFormats[i])) {
found = true;
break;
}
}
return found
? pattern
: null;
}
public int getColourFromAttribute(int attribute) {
TypedArray ta = getAttributeValue(attribute);
int result = ta.getColor(0, Color.TRANSPARENT);
ta.recycle();
return result;
}
/**
* This method allows to highlight in bold the content of a search string
* @param search string
* @param originalText string where to find
* @return CharSequence modified
*/
public CharSequence highlight(String search, String originalText) {
if (TextUtils.isEmpty(search))
return originalText;
// ignore case and accents
// the same thing should have been done for the search text
String normalizedText = Normalizer.normalize(originalText, Normalizer.Form.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "").toLowerCase();
int start = normalizedText.indexOf(search.toLowerCase());
if (start < 0) {
// not found, nothing to to
return originalText;
} else {
// highlight each appearance in the original text
// while searching in normalized text
Spannable highlighted = new SpannableString(originalText);
while (start >= 0) {
int spanStart = Math.min(start, originalText.length());
int spanEnd = Math.min(start + search.length(), originalText.length());
highlighted.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), spanStart,
spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = normalizedText.indexOf(search, spanEnd);
}
return highlighted;
}
}
/**
* Function that determines if the application is running on tablet
* @return true if running on the tablet, otherwise false
*/
public boolean isTablet() {
int layout = getContext().getResources().getConfiguration().screenLayout;
return ((layout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) ||
((layout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE);
}
/**
* Resolves the id attribute in color
* @param attr id attribute
* @return color
*/
public int resolveColorAttribute(int attr) {
// Resources.Theme currentTheme = mContext.getTheme();
// return mContext.getResources().getColor(resolveAttribute(attr), currentTheme);
//return mContext.getResources().getColor(resolveAttribute(attr));
UIHelper uiHelper = new UIHelper(getContext());
return ContextCompat.getColor(getContext(), uiHelper.resolveAttribute(attr));
}
public boolean isToDisplayChangelog() {
int currentVersionCode = getAppVersionCode();
int lastVersionCode = PreferenceManager.getDefaultSharedPreferences(getContext())
.getInt(getContext().getString(R.string.pref_last_version_key), Constants.NOT_SET);
return lastVersionCode != currentVersionCode;
}
/**
* Method, which allows you to change the language of the application on the fly.
* @param languageToLoad language to load for the locale
* @return and indicator whether the operation was successful
* Ref: http://stackoverflow.com/questions/22402491/android-change-and-set-default-locale-within-the-app
*/
public boolean setAppLocale(String languageToLoad) {
try {
setAppLocale_Internal(languageToLoad);
} catch (Exception e) {
Timber.e(e, "changing app locale");
return false;
}
return true;
}
private void setAppLocale_Internal(String languageToLoad) {
Locale locale;
if (!TextUtils.isEmpty(languageToLoad)) {
locale = new Locale(languageToLoad);
// locale = Locale.forLanguageTag(languageToLoad);
} else {
locale = Locale.getDefault();
}
// http://developer.android.com/reference/java/util/Locale.html#setDefault%28java.util.Locale%29
// Locale.setDefault(locale);
// change locale of the configuration
Resources resources = getContext().getResources();
Configuration config = resources.getConfiguration();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
config.locale = locale;
} else {
config.setLocale(locale);
}
// set new locale
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
public boolean showChangelog() {
// create changelog layout
View view = LayoutInflater.from(getContext()).inflate(R.layout.changelog_layout, null);
// show changelog dialog
new MaterialDialog.Builder(getContext())
.cancelable(false)
.title(R.string.changelog)
.customView(view, true)
.neutralText(android.R.string.ok)
.onNeutral(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
}
})
.build().show();
// mark as seen
int currentVersionCode = getAppVersionCode();
PreferenceManager.getDefaultSharedPreferences(getContext()).edit()
.putInt(getContext().getString(R.string.pref_last_version_key), currentVersionCode)
.apply();
return true;
}
// public int getColourFromStyledAttribute(int attribute) {
// int[] attrs = { attribute };
// TypedArray ta = getContext().obtainStyledAttributes(getContext().getTheme(), attrs);
// }
// public int getColourFromThemeAttribute(int attribute) {
// TypedValue typedValue = new TypedValue();
// getContext().getTheme().resolveAttribute(attribute, typedValue, true);
// return typedValue.resourceId;
// }
// private
private TypedArray getAttributeValue(int attribute) {
// TypedValue typedValue = new TypedValue();
// context.getTheme().resolveAttribute(attribute, typedValue, true);
// return typedValue;
// int[] arrayAttributes = new int[] { attribute };
// TypedArray typedArray = context.obtainStyledAttributes(arrayAttributes);
// int value = typedArray.getColor(0, context.getResources().getColor(R.color.abBackground));
// typedArray.recycle();
// Create an array of the attributes we want to resolve
// using values from a theme
int[] attrs = new int[] { attribute /* index 0 */};
// Obtain the styled attributes. 'themedContext' is a context with a
// theme, typically the current Activity (i.e. 'this')
TypedArray ta = getContext().obtainStyledAttributes(attrs);
// To get the value of the 'listItemBackground' attribute that was
// set in the theme used in 'themedContext'. The parameter is the index
// of the attribute in the 'attrs' array. The returned Drawable
// is what you are after
// Drawable drawableFromTheme = ta.getDrawable(0 /* index */);
// Finally, free the resources used by TypedArray
// ta.recycle();
return ta;
}
}