* Rules are interceptors which are executed for each test method and will run before
* any of your setup code in the {@link Before @Before} method.
diff --git a/app/src/androidTest/java/org/gnucash/android/test/ui/TransactionsActivityTest.java b/app/src/androidTest/java/org/gnucash/android/test/ui/TransactionsActivityTest.java
index 6821e4ca2..4395e7386 100644
--- a/app/src/androidTest/java/org/gnucash/android/test/ui/TransactionsActivityTest.java
+++ b/app/src/androidTest/java/org/gnucash/android/test/ui/TransactionsActivityTest.java
@@ -43,6 +43,7 @@
import org.gnucash.android.model.TransactionType;
import org.gnucash.android.receivers.TransactionRecorder;
import org.gnucash.android.test.ui.util.DisableAnimationsRule;
+import org.gnucash.android.test.ui.util.GnucashAndroidTestRunner;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.settings.PreferenceActivity;
import org.gnucash.android.ui.transaction.TransactionFormFragment;
@@ -57,7 +58,6 @@
import java.math.BigDecimal;
import java.text.NumberFormat;
-import java.util.Currency;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -76,7 +76,6 @@
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@RunWith(AndroidJUnit4.class)
@@ -135,7 +134,7 @@ public TransactionsActivityTest() {
@BeforeClass
public static void prepareTestCase(){
Context context = GnuCashApplication.getAppContext();
- AccountsActivityTest.preventFirstRunDialogs(context);
+ GnucashAndroidTestRunner.preventFirstRunDialogs(context);
mSplitsDbAdapter = SplitsDbAdapter.getInstance();
mTransactionsDbAdapter = TransactionsDbAdapter.getInstance();
diff --git a/app/src/androidTest/java/org/gnucash/android/test/ui/util/GnucashAndroidTestRunner.java b/app/src/androidTest/java/org/gnucash/android/test/ui/util/GnucashAndroidTestRunner.java
index 40d9691bb..393e6b0c5 100644
--- a/app/src/androidTest/java/org/gnucash/android/test/ui/util/GnucashAndroidTestRunner.java
+++ b/app/src/androidTest/java/org/gnucash/android/test/ui/util/GnucashAndroidTestRunner.java
@@ -16,13 +16,20 @@
package org.gnucash.android.test.ui.util;
+import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
-import android.support.multidex.MultiDex;
+import android.preference.PreferenceManager;
import android.support.test.runner.AndroidJUnitRunner;
import android.util.Log;
+import com.kobakei.ratethisapp.RateThisApp;
+
+import org.gnucash.android.R;
+import org.gnucash.android.ui.account.AccountsActivity;
+
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -35,6 +42,25 @@ public class GnucashAndroidTestRunner extends AndroidJUnitRunner{
private static final float DISABLED = 0.0f;
private static final float DEFAULT = 1.0f;
+ /**
+ * Prevents the first-run dialogs (Whats new, Create accounts etc) from being displayed when testing
+ * @param context Application context
+ */
+ public static void preventFirstRunDialogs(Context context) {
+ AccountsActivity.rateAppConfig = new RateThisApp.Config(10000, 10000);
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
+
+ //do not show first run dialog
+ editor.putBoolean(context.getString(R.string.key_first_run), false);
+ editor.putInt(AccountsActivity.LAST_OPEN_TAB_INDEX, AccountsActivity.INDEX_TOP_LEVEL_ACCOUNTS_FRAGMENT);
+
+ //do not show "What's new" dialog
+ String minorVersion = context.getString(R.string.app_minor_version);
+ int currentMinor = Integer.parseInt(minorVersion);
+ editor.putInt(context.getString(R.string.key_previous_minor_version), currentMinor);
+ editor.commit();
+ }
+
@Override
public void onCreate(Bundle args) {
super.onCreate(args);
diff --git a/app/src/main/java/org/gnucash/android/db/DatabaseHelper.java b/app/src/main/java/org/gnucash/android/db/DatabaseHelper.java
index c079a7eb6..9d4762ef3 100644
--- a/app/src/main/java/org/gnucash/android/db/DatabaseHelper.java
+++ b/app/src/main/java/org/gnucash/android/db/DatabaseHelper.java
@@ -20,11 +20,9 @@
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
-import android.widget.Toast;
import com.crashlytics.android.Crashlytics;
-import org.gnucash.android.app.GnuCashApplication;
import org.gnucash.android.model.Commodity;
import org.xml.sax.SAXException;
@@ -264,7 +262,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
Log.i(LOG_TAG, "Upgrading database from version "
+ oldVersion + " to " + newVersion);
- Toast.makeText(GnuCashApplication.getAppContext(), "Upgrading GnuCash database", Toast.LENGTH_SHORT).show();
+ //TODO: Find way to show a progress dialog for long running db upgrades
/*
* NOTE: In order to modify the database, create a new static method in the MigrationHelper class
* called upgradeDbToVersion<#>, e.g. int upgradeDbToVersion10(SQLiteDatabase) in order to upgrade to version 10.
@@ -278,9 +276,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
while(oldVersion < newVersion){
try {
Method method = MigrationHelper.class.getDeclaredMethod("upgradeDbToVersion" + (oldVersion+1), SQLiteDatabase.class);
- Object result = method.invoke(null, db);
- oldVersion = Integer.parseInt(result.toString());
-
+ oldVersion = (int) method.invoke(null, db);
} catch (NoSuchMethodException e) {
String msg = String.format("Database upgrade method upgradeToVersion%d(SQLiteDatabase) definition not found ", newVersion);
Log.e(LOG_TAG, msg, e);
@@ -356,7 +352,7 @@ private void createDatabaseTables(SQLiteDatabase db) {
db.execSQL(createBudgetAmountUidIndex);
try {
- MigrationHelper.importCommodities(db);
+ MigrationHelper.importCommodities(db, true);
} catch (SAXException | ParserConfigurationException | IOException e) {
Log.e(LOG_TAG, "Error loading currencies into the database");
e.printStackTrace();
diff --git a/app/src/main/java/org/gnucash/android/db/DatabaseSchema.java b/app/src/main/java/org/gnucash/android/db/DatabaseSchema.java
index f3dcbeaf8..eb689affe 100644
--- a/app/src/main/java/org/gnucash/android/db/DatabaseSchema.java
+++ b/app/src/main/java/org/gnucash/android/db/DatabaseSchema.java
@@ -39,7 +39,7 @@ public class DatabaseSchema {
* Version number of database containing accounts and transactions info.
* With any change to the database schema, this number must increase
*/
- public static final int DATABASE_VERSION = 15;
+ public static final int DATABASE_VERSION = 17;
/**
* Name of the database
diff --git a/app/src/main/java/org/gnucash/android/db/MigrationHelper.java b/app/src/main/java/org/gnucash/android/db/MigrationHelper.java
index 5acc1d74a..f56b72eb8 100644
--- a/app/src/main/java/org/gnucash/android/db/MigrationHelper.java
+++ b/app/src/main/java/org/gnucash/android/db/MigrationHelper.java
@@ -235,7 +235,7 @@ public void run() {
/**
* Imports commodities into the database from XML resource file
*/
- static void importCommodities(SQLiteDatabase db) throws SAXException, ParserConfigurationException, IOException {
+ static void importCommodities(SQLiteDatabase db, boolean deleteExisting) throws SAXException, ParserConfigurationException, IOException {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
@@ -246,7 +246,7 @@ static void importCommodities(SQLiteDatabase db) throws SAXException, ParserConf
/** Create handler to handle XML Tags ( extends DefaultHandler ) */
- CommoditiesXmlHandler handler = new CommoditiesXmlHandler(db);
+ CommoditiesXmlHandler handler = new CommoditiesXmlHandler(db, deleteExisting);
xr.setContentHandler(handler);
xr.parse(new InputSource(bos));
@@ -264,7 +264,7 @@ public static int upgradeDbToVersion2(SQLiteDatabase db) {
" ADD COLUMN double_account_uid varchar(255)";
//introducing sub accounts
- Log.i(DatabaseHelper.LOG_TAG, "Adding column for parent accounts");
+ Log.i(LOG_TAG, "Adding column for parent accounts");
String addParentAccountSql = "ALTER TABLE " + AccountEntry.TABLE_NAME +
" ADD COLUMN " + AccountEntry.COLUMN_PARENT_ACCOUNT_UID + " varchar(255)";
@@ -273,7 +273,7 @@ public static int upgradeDbToVersion2(SQLiteDatabase db) {
//update account types to GnuCash account types
//since all were previously CHECKING, now all will be CASH
- Log.i(DatabaseHelper.LOG_TAG, "Converting account types to GnuCash compatible types");
+ Log.i(LOG_TAG, "Converting account types to GnuCash compatible types");
ContentValues cv = new ContentValues();
cv.put(SplitEntry.COLUMN_TYPE, AccountType.CASH.toString());
db.update(AccountEntry.TABLE_NAME, cv, null, null);
@@ -495,7 +495,7 @@ static int upgradeDbToVersion7(SQLiteDatabase db) {
* @return New database version (8) if upgrade successful, old version (7) if unsuccessful
*/
static int upgradeDbToVersion8(SQLiteDatabase db) {
- Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 8");
+ Log.i(LOG_TAG, "Upgrading database to version 8");
int oldVersion = 7;
new File(Exporter.LEGACY_BASE_FOLDER_PATH + "/backups/").mkdirs();
new File(Exporter.LEGACY_BASE_FOLDER_PATH + "/exports/").mkdirs();
@@ -505,7 +505,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
db.beginTransaction();
try {
- Log.i(DatabaseHelper.LOG_TAG, "Creating scheduled actions table");
+ Log.i(LOG_TAG, "Creating scheduled actions table");
db.execSQL("CREATE TABLE " + ScheduledActionEntry.TABLE_NAME + " ("
+ ScheduledActionEntry._ID + " integer primary key autoincrement, "
+ ScheduledActionEntry.COLUMN_UID + " varchar(255) not null UNIQUE, "
@@ -525,7 +525,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
//==============================BEGIN TABLE MIGRATIONS ========================================
- Log.i(DatabaseHelper.LOG_TAG, "Migrating accounts table");
+ Log.i(LOG_TAG, "Migrating accounts table");
// backup transaction table
db.execSQL("ALTER TABLE " + AccountEntry.TABLE_NAME + " RENAME TO " + AccountEntry.TABLE_NAME + "_bak");
// create new transaction table
@@ -577,7 +577,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
+ " FROM " + AccountEntry.TABLE_NAME + "_bak;"
);
- Log.i(DatabaseHelper.LOG_TAG, "Migrating transactions table");
+ Log.i(LOG_TAG, "Migrating transactions table");
// backup transaction table
db.execSQL("ALTER TABLE " + TransactionEntry.TABLE_NAME + " RENAME TO " + TransactionEntry.TABLE_NAME + "_bak");
// create new transaction table
@@ -618,7 +618,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
+ " FROM " + TransactionEntry.TABLE_NAME + "_bak;"
);
- Log.i(DatabaseHelper.LOG_TAG, "Migrating splits table");
+ Log.i(LOG_TAG, "Migrating splits table");
// backup split table
db.execSQL("ALTER TABLE " + SplitEntry.TABLE_NAME + " RENAME TO " + SplitEntry.TABLE_NAME + "_bak");
// create new split table
@@ -668,7 +668,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
//TransactionsDbAdapter transactionsDbAdapter = new TransactionsDbAdapter(db, splitsDbAdapter);
//AccountsDbAdapter accountsDbAdapter = new AccountsDbAdapter(db,transactionsDbAdapter);
- Log.i(DatabaseHelper.LOG_TAG, "Creating default root account if none exists");
+ Log.i(LOG_TAG, "Creating default root account if none exists");
ContentValues contentValues = new ContentValues();
//assign a root account to all accounts which had null as parent except ROOT (top-level accounts)
String rootAccountUID;
@@ -706,7 +706,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
contentValues.put(AccountEntry.COLUMN_PARENT_ACCOUNT_UID, rootAccountUID);
db.update(AccountEntry.TABLE_NAME, contentValues, AccountEntry.COLUMN_PARENT_ACCOUNT_UID + " IS NULL AND " + AccountEntry.COLUMN_TYPE + " != ?", new String[]{"ROOT"});
- Log.i(DatabaseHelper.LOG_TAG, "Migrating existing recurring transactions");
+ Log.i(LOG_TAG, "Migrating existing recurring transactions");
cursor = db.query(TransactionEntry.TABLE_NAME + "_bak", null, "recurrence_period > 0", null, null, null, null);
long lastRun = System.currentTimeMillis();
while (cursor.moveToNext()){
@@ -753,7 +753,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
cursor.close();
//auto-balance existing splits
- Log.i(DatabaseHelper.LOG_TAG, "Auto-balancing existing transaction splits");
+ Log.i(LOG_TAG, "Auto-balancing existing transaction splits");
cursor = db.query(
TransactionEntry.TABLE_NAME + " , " + SplitEntry.TABLE_NAME + " ON "
+ TransactionEntry.TABLE_NAME + "." + TransactionEntry.COLUMN_UID + "=" + SplitEntry.TABLE_NAME + "." + SplitEntry.COLUMN_TRANSACTION_UID
@@ -830,7 +830,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
cursor.close();
}
- Log.i(DatabaseHelper.LOG_TAG, "Dropping temporary migration tables");
+ Log.i(LOG_TAG, "Dropping temporary migration tables");
db.execSQL("DROP TABLE " + SplitEntry.TABLE_NAME + "_bak");
db.execSQL("DROP TABLE " + AccountEntry.TABLE_NAME + "_bak");
db.execSQL("DROP TABLE " + TransactionEntry.TABLE_NAME + "_bak");
@@ -861,7 +861,7 @@ static int upgradeDbToVersion8(SQLiteDatabase db) {
* @throws RuntimeException if the default commodities could not be imported
*/
static int upgradeDbToVersion9(SQLiteDatabase db){
- Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 9");
+ Log.i(LOG_TAG, "Upgrading database to version 9");
int oldVersion = 8;
db.beginTransaction();
@@ -883,9 +883,9 @@ static int upgradeDbToVersion9(SQLiteDatabase db){
+ "' ON " + CommodityEntry.TABLE_NAME + "(" + CommodityEntry.COLUMN_UID + ")");
try {
- importCommodities(db);
+ importCommodities(db, true);
} catch (SAXException | ParserConfigurationException | IOException e) {
- Log.e(DatabaseHelper.LOG_TAG, "Error loading currencies into the database", e);
+ Log.e(LOG_TAG, "Error loading currencies into the database", e);
Crashlytics.logException(e);
throw new RuntimeException(e);
}
@@ -1092,7 +1092,7 @@ static int upgradeDbToVersion9(SQLiteDatabase db){
* @return 10 if upgrade was successful, 9 otherwise
*/
static int upgradeDbToVersion10(SQLiteDatabase db){
- Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 9");
+ Log.i(LOG_TAG, "Upgrading database to version 9");
int oldVersion = 9;
db.beginTransaction();
@@ -1145,7 +1145,7 @@ static int upgradeDbToVersion10(SQLiteDatabase db){
* @return 11 if upgrade was successful, 10 otherwise
*/
static int upgradeDbToVersion11(SQLiteDatabase db){
- Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 9");
+ Log.i(LOG_TAG, "Upgrading database to version 9");
int oldVersion = 10;
db.beginTransaction();
@@ -1241,7 +1241,7 @@ static int upgradeDbToVersion12(SQLiteDatabase db){
* @return New database version, 13 if migration succeeds, 11 otherwise
*/
static int upgradeDbToVersion13(SQLiteDatabase db){
- Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 13");
+ Log.i(LOG_TAG, "Upgrading database to version 13");
int oldVersion = 12;
db.beginTransaction();
@@ -1552,7 +1552,7 @@ private static void moveDirectory(File srcDir, File dstDir) throws IOException {
* @return New database version
*/
public static int upgradeDbToVersion14(SQLiteDatabase db){
- Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 14");
+ Log.i(LOG_TAG, "Upgrading database to version 14");
int oldDbVersion = 13;
File backupFolder = new File(Exporter.BASE_FOLDER_PATH);
backupFolder.mkdir();
@@ -1585,7 +1585,7 @@ public void run() {
}
/**
- * Upgrades the database to version 14.
+ * Upgrades the database to version 15.
*
This migration makes the following changes to the database:
*
*
Fixes accounts referencing a default transfer account that no longer
@@ -1593,10 +1593,10 @@ public void run() {
*
*
* @param db SQLite database to be upgraded
- * @return New database version, 14 if migration succeeds, 13 otherwise
+ * @return New database version, 15 if migration succeeds, 14 otherwise
*/
static int upgradeDbToVersion15(SQLiteDatabase db) {
- Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 15");
+ Log.i(LOG_TAG, "Upgrading database to version 15");
int dbVersion = 14;
db.beginTransaction();
@@ -1628,4 +1628,51 @@ static int upgradeDbToVersion15(SQLiteDatabase db) {
rescheduleServiceAlarm();
return dbVersion;
}
+
+ /**
+ * Upgrades the database to version 16.
+ *
This migration makes the following changes to the database:
+ *
+ *
Update the commodities table (see #731)
+ *
+ *
+ * @param db SQLite database to be upgraded
+ * @return New database version, 16 if migration succeeds, 15 otherwise
+ */
+ static int upgradeDbToVersion16(SQLiteDatabase db) {
+ Log.i(LOG_TAG, "Upgrading database to version 16");
+ int dbVersion = 15;
+
+ try {
+ importCommodities(db, false);
+ dbVersion = 16;
+ } catch (SAXException | ParserConfigurationException | IOException e) {
+ Log.e(LOG_TAG, "Error loading currencies into the database", e);
+ Crashlytics.logException(e);
+ }
+
+ return dbVersion;
+ }
+
+ /**
+ * Upgrades the database to version 17.
+ * This migration updates the foreign keys to the commodities in the splits table
+ * after a previous migration which overwrote the db table for commodities, rendering
+ * all foreign keys to commodity GUIDs invalid.
+ *
+ * @param db SQLite database to be upgraded
+ * @return New database version, 16 if migration succeeds, 15 otherwise
+ */
+ static int upgradeDbToVersion17(SQLiteDatabase db) {
+ Log.i(LOG_TAG, "Upgrading database to version 17");
+ int dbVersion = 16;
+
+ db.beginTransaction();
+ db.execSQL("UPDATE accounts SET commodity_uid = (SELECT uid FROM commodities WHERE mnemonic = accounts.currency_code)");
+ db.execSQL("UPDATE transactions SET commodity_uid = (SELECT uid FROM commodities WHERE commodities.mnemonic = transactions.currency_code)");
+
+ db.endTransaction();
+
+ return dbVersion + 1;
+ }
}
diff --git a/app/src/main/java/org/gnucash/android/db/adapter/AccountsDbAdapter.java b/app/src/main/java/org/gnucash/android/db/adapter/AccountsDbAdapter.java
index e19138306..1b73586f2 100644
--- a/app/src/main/java/org/gnucash/android/db/adapter/AccountsDbAdapter.java
+++ b/app/src/main/java/org/gnucash/android/db/adapter/AccountsDbAdapter.java
@@ -59,6 +59,7 @@
* @author Oleksandr Tyshkovets
*/
public class AccountsDbAdapter extends DatabaseAdapter {
+
/**
* Separator used for account name hierarchies between parent and child accounts
*/
@@ -71,7 +72,14 @@ public class AccountsDbAdapter extends DatabaseAdapter {
*/
public static final String ROOT_ACCOUNT_FULL_NAME = " ";
- /**
+ /**
+ * Where clause to get non hidden nor root account
+ */
+ public static final String WHERE_NOT_HIDDEN_AND_NOT_ROOT_ACCOUNT =
+ AccountEntry.COLUMN_HIDDEN + " = 0 AND " + AccountEntry.COLUMN_TYPE + " != ?";
+
+
+ /**
* Transactions database adapter for manipulating transactions associated with accounts
*/
private final TransactionsDbAdapter mTransactionsAdapter;
@@ -702,15 +710,20 @@ public Cursor fetchAllRecords(){
* GnuCash ROOT accounts and hidden accounts will not be included in the result set.
* @return {@link Cursor} to all account records
*/
- public Cursor fetchAllRecordsOrderedByFullName(){
- Log.v(LOG_TAG, "Fetching all accounts from db");
- String selection = AccountEntry.COLUMN_HIDDEN + " = 0 AND " + AccountEntry.COLUMN_TYPE + " != ?" ;
+ public Cursor fetchAllRecordsOrderedByFullName() {
+
+ Log.v(LOG_TAG,
+ "Fetching all accounts from db");
+
+ String selection = AccountEntry.COLUMN_HIDDEN + " = 0 AND " + AccountEntry.COLUMN_TYPE + " != ?";
+
return mDb.query(AccountEntry.TABLE_NAME,
- null,
- selection,
- new String[]{AccountType.ROOT.name()},
- null, null,
- AccountEntry.COLUMN_FULL_NAME + " ASC");
+ null,
+ selection,
+ new String[]{AccountType.ROOT.name()},
+ null,
+ null,
+ AccountEntry.COLUMN_FULL_NAME + " ASC");
}
/**
@@ -728,8 +741,12 @@ public Cursor fetchAccounts(@Nullable String where, @Nullable String[] whereArgs
Log.v(LOG_TAG, "Fetching all accounts from db where " + where + " order by " + orderBy);
return mDb.query(AccountEntry.TABLE_NAME,
- null, where, whereArgs, null, null,
- orderBy);
+ null,
+ where,
+ whereArgs,
+ null,
+ null,
+ orderBy);
}
/**
@@ -740,10 +757,16 @@ public Cursor fetchAccounts(@Nullable String where, @Nullable String[] whereArgs
* @return Cursor set of accounts which fulfill where
*/
public Cursor fetchAccountsOrderedByFullName(String where, String[] whereArgs) {
+
Log.v(LOG_TAG, "Fetching all accounts from db where " + where);
+
return mDb.query(AccountEntry.TABLE_NAME,
- null, where, whereArgs, null, null,
- AccountEntry.COLUMN_FULL_NAME + " ASC");
+ null,
+ where,
+ whereArgs,
+ null,
+ null,
+ AccountEntry.COLUMN_FULL_NAME + " ASC");
}
/**
@@ -754,13 +777,37 @@ public Cursor fetchAccountsOrderedByFullName(String where, String[] whereArgs) {
* @param whereArgs where args
* @return Cursor set of accounts which fulfill where
*/
- public Cursor fetchAccountsOrderedByFavoriteAndFullName(String where, String[] whereArgs) {
- Log.v(LOG_TAG, "Fetching all accounts from db where " + where + " order by Favorite then Name");
+ public Cursor fetchAccountsOrderedByFavoriteAndFullName(String where,
+ String[] whereArgs) {
+
+ Log.v(LOG_TAG,
+ "Fetching all accounts from db where " + where + " order by Favorite then Name");
+
return mDb.query(AccountEntry.TABLE_NAME,
- null, where, whereArgs, null, null,
- AccountEntry.COLUMN_FAVORITE + " DESC, " + AccountEntry.COLUMN_FULL_NAME + " ASC");
+ null,
+ where,
+ whereArgs,
+ null,
+ null,
+ AccountEntry.COLUMN_FAVORITE + " DESC, " + AccountEntry.COLUMN_FULL_NAME + " ASC");
}
+ /**
+ * Returns a Cursor set of all Accounts
+ *
+ *
This method returns the favorite accounts first, sorted by name, and then the other accounts,
+ * sorted by name.
+ *
+ * @return Cursor set of all accounts
+ */
+ public Cursor fetchAccountsOrderedByFavoriteAndFullName() {
+
+ return fetchAccountsOrderedByFavoriteAndFullName(WHERE_NOT_HIDDEN_AND_NOT_ROOT_ACCOUNT,
+ new String[]{AccountType.ROOT.name()});
+ }
+
+
+
/**
* Returns the balance of an account while taking sub-accounts into consideration
* @return Account Balance of an account including sub-accounts
@@ -929,12 +976,18 @@ public Cursor fetchSubAccounts(String accountUID) {
*/
public Cursor fetchTopLevelAccounts() {
//condition which selects accounts with no parent, whose UID is not ROOT and whose type is not ROOT
- return fetchAccounts("(" + AccountEntry.COLUMN_PARENT_ACCOUNT_UID + " IS NULL OR "
- + AccountEntry.COLUMN_PARENT_ACCOUNT_UID + " = ?) AND "
- + AccountEntry.COLUMN_HIDDEN + " = 0 AND "
- + AccountEntry.COLUMN_TYPE + " != ?",
- new String[]{getOrCreateGnuCashRootAccountUID(), AccountType.ROOT.name()},
- AccountEntry.COLUMN_NAME + " ASC");
+ return fetchAccounts("("
+ + AccountEntry.COLUMN_PARENT_ACCOUNT_UID
+ + " IS NULL OR "
+ + AccountEntry.COLUMN_PARENT_ACCOUNT_UID
+ + " = ?) AND "
+ + AccountEntry.COLUMN_HIDDEN
+ + " = 0 AND "
+ + AccountEntry.COLUMN_TYPE
+ + " != ?",
+ new String[]{getOrCreateGnuCashRootAccountUID(),
+ AccountType.ROOT.name()},
+ AccountEntry.COLUMN_NAME + " ASC");
}
/**
@@ -1215,22 +1268,33 @@ public static String getOpeningBalanceAccountFullName(){
* @return Android resource ID representing the color which can be directly set to a view
*/
public static int getActiveAccountColorResource(@NonNull String accountUID) {
+
AccountsDbAdapter accountsDbAdapter = getInstance();
- String colorCode = null;
- int iColor = -1;
+ String colorCode = null;
+ int iColor = -1;
+
String parentAccountUID = accountUID;
- while (parentAccountUID != null ) {
+ while (parentAccountUID != null) {
+
colorCode = accountsDbAdapter.getAccountColorCode(accountsDbAdapter.getID(parentAccountUID));
+
if (colorCode != null) {
iColor = Color.parseColor(colorCode);
break;
}
+
+ // Climb to parent account
parentAccountUID = accountsDbAdapter.getParentAccountUID(parentAccountUID);
}
if (colorCode == null) {
- iColor = GnuCashApplication.getAppContext().getResources().getColor(R.color.theme_primary);
+ // No color has been found defined in any ancestor
+
+ // Use default theme color
+ iColor = GnuCashApplication.getAppContext()
+ .getResources()
+ .getColor(R.color.theme_primary);
}
return iColor;
diff --git a/app/src/main/java/org/gnucash/android/db/adapter/DatabaseAdapter.java b/app/src/main/java/org/gnucash/android/db/adapter/DatabaseAdapter.java
index ccaa4e18c..d146e6b0c 100644
--- a/app/src/main/java/org/gnucash/android/db/adapter/DatabaseAdapter.java
+++ b/app/src/main/java/org/gnucash/android/db/adapter/DatabaseAdapter.java
@@ -556,10 +556,14 @@ public long getID(@NonNull String uid){
* @throws IllegalArgumentException if the record ID does not exist in the database
*/
public String getUID(long id){
+
Cursor cursor = mDb.query(mTableName,
- new String[]{DatabaseSchema.CommonColumns.COLUMN_UID},
- DatabaseSchema.CommonColumns._ID + " = " + id,
- null, null, null, null);
+ new String[]{DatabaseSchema.CommonColumns.COLUMN_UID},
+ DatabaseSchema.CommonColumns._ID + " = " + id,
+ null,
+ null,
+ null,
+ null);
String uid = null;
try {
diff --git a/app/src/main/java/org/gnucash/android/export/csv/CsvTransactionsExporter.java b/app/src/main/java/org/gnucash/android/export/csv/CsvTransactionsExporter.java
index f0d082e6e..f298cd201 100644
--- a/app/src/main/java/org/gnucash/android/export/csv/CsvTransactionsExporter.java
+++ b/app/src/main/java/org/gnucash/android/export/csv/CsvTransactionsExporter.java
@@ -96,11 +96,10 @@ public List generateExport() throws ExporterException {
* Write splits to CSV format
* @param splits Splits to be written
*/
- private void writeSplitsToCsv(@NonNull List splits, @NonNull CsvWriter writer) throws IOException {
+ private void writeSplitsToCsv(@NonNull List splits, @NonNull CsvWriter writer,
+ Map accountNames, Map accountFullNames) throws IOException {
int index = 0;
- Map uidAccountMap = new HashMap<>();
-
for (Split split : splits) {
if (index++ > 0){ // the first split is on the same line as the transactions. But after that, we
writer.write("" + mCsvSeparator + mCsvSeparator + mCsvSeparator + mCsvSeparator
@@ -108,18 +107,22 @@ private void writeSplitsToCsv(@NonNull List splits, @NonNull CsvWriter wr
}
writer.writeToken(split.getMemo());
- //cache accounts so that we do not have to go to the DB each time
String accountUID = split.getAccountUID();
- Account account;
- if (uidAccountMap.containsKey(accountUID)) {
- account = uidAccountMap.get(accountUID);
+
+ // Cache account names
+ String fullName, name;
+ if (accountNames.containsKey(accountUID)) {
+ fullName = accountFullNames.get(accountUID);
+ name = accountNames.get(accountUID);
} else {
- account = mAccountsDbAdapter.getRecord(accountUID);
- uidAccountMap.put(accountUID, account);
+ fullName = mAccountsDbAdapter.getAccountFullName(accountUID);
+ name = mAccountsDbAdapter.getAccountName(accountUID);
+ accountFullNames.put(accountUID, fullName);
+ accountNames.put(accountUID, name);
}
- writer.writeToken(account.getFullName());
- writer.writeToken(account.getName());
+ writer.writeToken(fullName);
+ writer.writeToken(name);
String sign = split.getType() == TransactionType.CREDIT ? "-" : "";
writer.writeToken(sign + split.getQuantity().formattedString());
@@ -143,6 +146,8 @@ private void generateExport(final CsvWriter csvWriter) throws ExporterException
}
csvWriter.newLine();
+ Map nameCache = new HashMap<>();
+ Map fullNameCache = new HashMap<>();
Cursor cursor = mTransactionsDbAdapter.fetchTransactionsModifiedSince(mExportParams.getExportStartTime());
Log.d(LOG_TAG, String.format("Exporting %d transactions to CSV", cursor.getCount()));
@@ -159,7 +164,7 @@ private void generateExport(final CsvWriter csvWriter) throws ExporterException
csvWriter.writeToken("CURRENCY::" + transaction.getCurrencyCode());
csvWriter.writeToken(null); // Void Reason
csvWriter.writeToken(null); // Action
- writeSplitsToCsv(transaction.getSplits(), csvWriter);
+ writeSplitsToCsv(transaction.getSplits(), csvWriter, nameCache, fullNameCache);
}
PreferencesHelper.setLastExportTime(TimestampHelper.getTimestampFromNow());
diff --git a/app/src/main/java/org/gnucash/android/importer/CommoditiesXmlHandler.java b/app/src/main/java/org/gnucash/android/importer/CommoditiesXmlHandler.java
index 977328fa6..0cc9b84b4 100644
--- a/app/src/main/java/org/gnucash/android/importer/CommoditiesXmlHandler.java
+++ b/app/src/main/java/org/gnucash/android/importer/CommoditiesXmlHandler.java
@@ -15,9 +15,11 @@
*/
package org.gnucash.android.importer;
+import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import org.gnucash.android.app.GnuCashApplication;
+import org.gnucash.android.db.DatabaseSchema;
import org.gnucash.android.db.adapter.CommoditiesDbAdapter;
import org.gnucash.android.db.adapter.DatabaseAdapter;
import org.gnucash.android.model.Commodity;
@@ -44,17 +46,23 @@ public class CommoditiesXmlHandler extends DefaultHandler {
* List of commodities parsed from the XML file.
* They will be all added to db at once at the end of the document
*/
- private List mCommodities;
+ private List mCommodities = new ArrayList<>();
+
+ private boolean deleteExisting;
private CommoditiesDbAdapter mCommoditiesDbAdapter;
- public CommoditiesXmlHandler(SQLiteDatabase db){
+ public CommoditiesXmlHandler(SQLiteDatabase db, boolean deleteExisting){
+ initAdapter(db);
+ this.deleteExisting = deleteExisting;
+ }
+
+ private void initAdapter(SQLiteDatabase db) {
if (db == null){
mCommoditiesDbAdapter = GnuCashApplication.getCommoditiesDbAdapter();
} else {
mCommoditiesDbAdapter = new CommoditiesDbAdapter(db);
}
- mCommodities = new ArrayList<>();
}
@Override
@@ -82,6 +90,25 @@ public void startElement(String uri, String localName, String qName, Attributes
@Override
public void endDocument() throws SAXException {
- mCommoditiesDbAdapter.bulkAddRecords(mCommodities, DatabaseAdapter.UpdateMethod.insert);
+ if (this.deleteExisting){
+ mCommoditiesDbAdapter.deleteAllRecords();
+ mCommoditiesDbAdapter.bulkAddRecords(mCommodities, DatabaseAdapter.UpdateMethod.insert);
+ } else {
+ List existingCurrencyCodes = new ArrayList<>();
+
+ try(Cursor cursor = mCommoditiesDbAdapter.fetchAllRecords()) {
+ while (cursor.moveToNext()) {
+ String code = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseSchema.CommodityEntry.COLUMN_MNEMONIC));
+ existingCurrencyCodes.add(code);
+ }
+ }
+ for (Commodity commodity : mCommodities) {
+ if (existingCurrencyCodes.contains(commodity.getCurrencyCode())){
+ mCommoditiesDbAdapter.addRecord(commodity, DatabaseAdapter.UpdateMethod.update);
+ } else {
+ mCommoditiesDbAdapter.addRecord(commodity, DatabaseAdapter.UpdateMethod.insert);
+ }
+ }
+ }
}
}
diff --git a/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java b/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java
index 35d5f3e7b..b027e78f4 100644
--- a/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java
@@ -67,6 +67,8 @@
import org.gnucash.android.ui.colorpicker.ColorSquare;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.settings.PreferenceActivity;
+import org.gnucash.android.ui.util.AccountUtils;
+import org.gnucash.android.ui.util.widget.searchablespinner.SearchableSpinnerView;
import org.gnucash.android.util.CommoditiesCursorAdapter;
import org.gnucash.android.util.QualifiedAccountNameCursorAdapter;
@@ -135,6 +137,14 @@ public class AccountFormFragment extends Fragment {
*/
private String mAccountUID = null;
+ /**
+ * Spinner for the account type
+ *
+ * @see org.gnucash.android.model.AccountType
+ */
+ @BindView(R.id.input_account_type_spinner)
+ Spinner mAccountTypeSpinner;
+
/**
* Cursor which will hold set of eligible parent accounts
*/
@@ -155,7 +165,8 @@ public class AccountFormFragment extends Fragment {
/**
* Spinner for parent account list
*/
- @BindView(R.id.input_parent_account) Spinner mParentAccountSpinner;
+ @BindView(R.id.input_parent_account)
+ SearchableSpinnerView mParentAccountSpinner;
/**
* Checkbox which activates the parent account spinner when selected
@@ -163,12 +174,6 @@ public class AccountFormFragment extends Fragment {
*/
@BindView(R.id.checkbox_parent_account) CheckBox mParentCheckBox;
- /**
- * Spinner for the account type
- * @see org.gnucash.android.model.AccountType
- */
- @BindView(R.id.input_account_type_spinner) Spinner mAccountTypeSpinner;
-
/**
* Checkbox for activating the default transfer account spinner
*/
@@ -177,7 +182,8 @@ public class AccountFormFragment extends Fragment {
/**
* Spinner for selecting the default transfer account
*/
- @BindView(R.id.input_default_transfer_account) Spinner mDefaultTransferAccountSpinner;
+ @BindView(R.id.input_default_transfer_account)
+ SearchableSpinnerView mDefaultTransferAccountSpinner;
/**
* Account description input text view
@@ -286,7 +292,9 @@ public void onNothingSelected(AdapterView> adapterView) {
});
- mParentAccountSpinner.setEnabled(false);
+ mParentAccountSpinner.setTitle(getString(R.string.select_account));
+
+ mParentAccountSpinner.setEnabled(false);
mParentCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@@ -296,6 +304,8 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
+ mDefaultTransferAccountSpinner.setTitle(getString(R.string.select_account));
+
mDefaultTransferAccountSpinner.setEnabled(false);
mDefaultTransferAccountCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
@@ -322,8 +332,8 @@ public void onClick(View view) {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- CommoditiesCursorAdapter commoditiesAdapter = new CommoditiesCursorAdapter(
- getActivity(), android.R.layout.simple_spinner_item);
+ CommoditiesCursorAdapter commoditiesAdapter = new CommoditiesCursorAdapter(getActivity(),
+ android.R.layout.simple_spinner_item);
commoditiesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mCurrencySpinner.setAdapter(commoditiesAdapter);
@@ -569,21 +579,24 @@ public boolean onOptionsItemSelected(MenuItem item) {
/**
* Initializes the default transfer account spinner with eligible accounts
*/
- private void loadDefaultTransferAccountList(){
- String condition = DatabaseSchema.AccountEntry.COLUMN_UID + " != '" + mAccountUID + "' " //when creating a new account mAccountUID is null, so don't use whereArgs
- + " AND " + DatabaseSchema.AccountEntry.COLUMN_PLACEHOLDER + "=0"
- + " AND " + DatabaseSchema.AccountEntry.COLUMN_HIDDEN + "=0"
- + " AND " + DatabaseSchema.AccountEntry.COLUMN_TYPE + " != ?";
+ private void loadDefaultTransferAccountList() {
+
+ // Get Accounts that are not hidden, nor Placeholder, nor root Account, nor the edited Account itself
+ String where = AccountUtils.getTransfertAccountWhereClause(mAccountUID);
- Cursor defaultTransferAccountCursor = mAccountsDbAdapter.fetchAccountsOrderedByFullName(condition,
- new String[]{AccountType.ROOT.name()});
+ Cursor defaultTransferAccountCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName(where,
+ null);
if (mDefaultTransferAccountSpinner.getCount() <= 0) {
setDefaultTransferAccountInputsVisible(false);
}
mDefaultTransferAccountCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(),
- defaultTransferAccountCursor);
+ defaultTransferAccountCursor,
+ where,
+ null,
+ R.layout.account_spinner_dropdown_item);
+
mDefaultTransferAccountSpinner.setAdapter(mDefaultTransferAccountCursorAdapter);
}
@@ -592,41 +605,102 @@ private void loadDefaultTransferAccountList(){
* The allowed parent accounts depends on the account type
* @param accountType AccountType of account whose allowed parent list is to be loaded
*/
- private void loadParentAccountList(AccountType accountType){
- String condition = DatabaseSchema.SplitEntry.COLUMN_TYPE + " IN ("
- + getAllowedParentAccountTypes(accountType) + ") AND " + DatabaseSchema.AccountEntry.COLUMN_HIDDEN + "!=1 ";
-
- if (mAccount != null){ //if editing an account
- mDescendantAccountUIDs = mAccountsDbAdapter.getDescendantAccountUIDs(mAccount.getUID(), null, null);
- String rootAccountUID = mAccountsDbAdapter.getOrCreateGnuCashRootAccountUID();
- List descendantAccountUIDs = new ArrayList<>(mDescendantAccountUIDs);
- if (rootAccountUID != null)
- descendantAccountUIDs.add(rootAccountUID);
- // limit cyclic account hierarchies.
- condition += " AND (" + DatabaseSchema.AccountEntry.COLUMN_UID + " NOT IN ( '"
- + TextUtils.join("','", descendantAccountUIDs) + "','" + mAccountUID + "' ) )";
+ private void loadParentAccountList(AccountType accountType) {
+
+ //
+ // Build SQL request
+ //
+
+ String where = DatabaseSchema.SplitEntry.COLUMN_TYPE
+ + " IN ("
+ + getAllowedParentAccountTypes(accountType)
+ + ") AND "
+ + DatabaseSchema.AccountEntry.COLUMN_HIDDEN
+ + "!=1 ";
+
+ if (mAccount != null) {
+ // An Account is defined
+
+ //
+ // Get descendant Accounts
+ //
+
+ // Get descendant Accounts UIDs
+ mDescendantAccountUIDs = mAccountsDbAdapter.getDescendantAccountUIDs(mAccount.getUID(),
+ null,
+ null);
+
+ // Clone descendant Account UIDs
+ List accountUIDsToExclude = new ArrayList<>(mDescendantAccountUIDs);
+
+ // Get root Account UID
+ String rootAccountUID = mAccountsDbAdapter.getOrCreateGnuCashRootAccountUID();
+
+ if (rootAccountUID != null) {
+
+ // Add root account to descendants
+ accountUIDsToExclude.add(rootAccountUID);
+ }
+
+ // Exclude Accounts to Exclude and edited Account itself
+ where += " AND ("
+ + DatabaseSchema.AccountEntry.COLUMN_UID
+ + " NOT IN ( '"
+ + TextUtils.join("','",
+ accountUIDsToExclude)
+ + "','"
+ + mAccountUID
+ + "' ) )";
}
//if we are reloading the list, close the previous cursor first
- if (mParentAccountCursor != null)
+ if (mParentAccountCursor != null) {
mParentAccountCursor.close();
+ }
+
+ mParentAccountCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName(where,
+ null);
+
+ //
+ // ?
+ //
- mParentAccountCursor = mAccountsDbAdapter.fetchAccountsOrderedByFullName(condition, null);
final View view = getView();
assert view != null;
- if (mParentAccountCursor.getCount() <= 0){
+
+ if (mParentAccountCursor.getCount() <= 0) {
+ // No parent account
+
mParentCheckBox.setChecked(false); //disable before hiding, else we can still read it when saving
- view.findViewById(R.id.layout_parent_account).setVisibility(View.GONE);
- view.findViewById(R.id.label_parent_account).setVisibility(View.GONE);
+
+ view.findViewById(R.id.layout_parent_account)
+ .setVisibility(View.GONE);
+
+ view.findViewById(R.id.label_parent_account)
+ .setVisibility(View.GONE);
+
} else {
- view.findViewById(R.id.layout_parent_account).setVisibility(View.VISIBLE);
- view.findViewById(R.id.label_parent_account).setVisibility(View.VISIBLE);
+ // There are potential parent accounts
+
+ view.findViewById(R.id.layout_parent_account)
+ .setVisibility(View.VISIBLE);
+
+ view.findViewById(R.id.label_parent_account)
+ .setVisibility(View.VISIBLE);
}
- mParentAccountCursorAdapter = new QualifiedAccountNameCursorAdapter(
- getActivity(), mParentAccountCursor);
- mParentAccountSpinner.setAdapter(mParentAccountCursorAdapter);
- }
+ //
+ // Build CursorAdapter
+ //
+
+ mParentAccountCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(),
+ mParentAccountCursor,
+ where,
+ null,
+ R.layout.account_spinner_dropdown_item);
+
+ mParentAccountSpinner.setAdapter(mParentAccountCursorAdapter);
+ }
/**
* Returns a comma separated list of account types which can be parent accounts for the specified type.
diff --git a/app/src/main/java/org/gnucash/android/ui/account/AccountsActivity.java b/app/src/main/java/org/gnucash/android/ui/account/AccountsActivity.java
index 846330af8..629f350c4 100644
--- a/app/src/main/java/org/gnucash/android/ui/account/AccountsActivity.java
+++ b/app/src/main/java/org/gnucash/android/ui/account/AccountsActivity.java
@@ -37,6 +37,7 @@
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.preference.PreferenceManager;
import android.util.Log;
@@ -268,6 +269,15 @@ public void onClick(View v) {
});
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setSubtitle(BooksDbAdapter.getInstance().getActiveBookDisplayName());
+ }
+ }
+
@Override
protected void onStart() {
super.onStart();
@@ -323,18 +333,33 @@ public void setCurrentTab(){
*
Also handles displaying the What's New dialog
*/
private void init() {
- PreferenceManager.setDefaultValues(this, BooksDbAdapter.getInstance().getActiveBookUID(),
- Context.MODE_PRIVATE, R.xml.fragment_transaction_preferences, true);
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean firstRun = prefs.getBoolean(getString(R.string.key_first_run), true);
+ PreferenceManager.setDefaultValues(this,
+ BooksDbAdapter.getInstance()
+ .getActiveBookUID(),
+ Context.MODE_PRIVATE,
+ R.xml.fragment_transaction_preferences,
+ true);
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean firstRun = prefs.getBoolean(getString(R.string.key_first_run),
+ true);
if (firstRun){
startActivity(new Intent(GnuCashApplication.getAppContext(), FirstRunWizardActivity.class));
- //default to using double entry and save the preference explicitly
+ // Default Preference to using double entry and save the preference explicitly
prefs.edit().putBoolean(getString(R.string.key_use_double_entry), true).apply();
+
+ // Default preference to open keyboard in account searchable spinners
+ prefs.edit().putBoolean(getString(R.string.key_shall_open_keyboard_in_account_searchable_spinner), false).apply();
+
+ // Default preference to use colors in account lists
+ prefs.edit().putBoolean(getString(R.string.key_use_color_in_account_list),true).apply();
+
+ // Finish Activity
finish();
+
return;
}
diff --git a/app/src/main/java/org/gnucash/android/ui/account/AccountsListFragment.java b/app/src/main/java/org/gnucash/android/ui/account/AccountsListFragment.java
index a83ab10bc..0d3d47c54 100644
--- a/app/src/main/java/org/gnucash/android/ui/account/AccountsListFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/account/AccountsListFragment.java
@@ -25,7 +25,6 @@
import android.database.Cursor;
import android.graphics.Color;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
@@ -433,19 +432,24 @@ public AccountsCursorLoader(Context context, String filter){
@Override
public Cursor loadInBackground() {
+
mDatabaseAdapter = AccountsDbAdapter.getInstance();
Cursor cursor;
- if (mFilter != null){
- cursor = ((AccountsDbAdapter)mDatabaseAdapter)
- .fetchAccounts(DatabaseSchema.AccountEntry.COLUMN_HIDDEN + "= 0 AND "
- + DatabaseSchema.AccountEntry.COLUMN_NAME + " LIKE '%" + mFilter + "%'",
- null, null);
+ if (mFilter != null) {
+ cursor = ((AccountsDbAdapter) mDatabaseAdapter).fetchAccounts(DatabaseSchema.AccountEntry.COLUMN_HIDDEN
+ + "= 0 AND "
+ + DatabaseSchema.AccountEntry.COLUMN_NAME
+ + " LIKE '%"
+ + mFilter
+ + "%'",
+ null,
+ null);
} else {
- if (mParentAccountUID != null && mParentAccountUID.length() > 0)
+ if (mParentAccountUID != null && mParentAccountUID.length() > 0) {
cursor = ((AccountsDbAdapter) mDatabaseAdapter).fetchSubAccounts(mParentAccountUID);
- else {
- switch (this.mDisplayMode){
+ } else {
+ switch (this.mDisplayMode) {
case RECENT:
cursor = ((AccountsDbAdapter) mDatabaseAdapter).fetchRecentAccounts(10);
break;
@@ -461,8 +465,9 @@ public Cursor loadInBackground() {
}
- if (cursor != null)
+ if (cursor != null) {
registerContentObserver(cursor);
+ }
return cursor;
}
}
diff --git a/app/src/main/java/org/gnucash/android/ui/report/ReportType.java b/app/src/main/java/org/gnucash/android/ui/report/ReportType.java
index d9887e1db..f88cf45b6 100644
--- a/app/src/main/java/org/gnucash/android/ui/report/ReportType.java
+++ b/app/src/main/java/org/gnucash/android/ui/report/ReportType.java
@@ -39,28 +39,36 @@
public enum ReportType {
PIE_CHART(0), BAR_CHART(1), LINE_CHART(2), TEXT(3), NONE(4);
+ // #872 Use a list to be sure of the sort order which is not guaranted with a hashmap keys
+ List mReportNames = null;
+
Map mReportTypeMap = new HashMap<>();
+
int mValue = 4;
+ /**
+ * Constructor
+ *
+ * @param index
+ */
ReportType(int index){
+
mValue = index;
+
Context context = GnuCashApplication.getAppContext();
- switch (index){
- case 0:
- mReportTypeMap.put(context.getString(R.string.title_pie_chart), PieChartFragment.class);
- break;
- case 1:
- mReportTypeMap.put(context.getString(R.string.title_bar_chart), StackedBarChartFragment.class);
- break;
- case 2:
- mReportTypeMap.put(context.getString(R.string.title_cash_flow_report), CashFlowLineChartFragment.class);
- break;
- case 3:
- mReportTypeMap.put(context.getString(R.string.title_balance_sheet_report), BalanceSheetFragment.class);
- break;
- case 4:
- break;
- }
+
+ // #872 Fill the map with all the items, in order to fill the Report Toolbar Spinner
+ mReportTypeMap.put(context.getString(R.string.title_pie_chart),
+ PieChartFragment.class);
+
+ mReportTypeMap.put(context.getString(R.string.title_bar_chart),
+ StackedBarChartFragment.class);
+
+ mReportTypeMap.put(context.getString(R.string.title_cash_flow_report),
+ CashFlowLineChartFragment.class);
+
+ mReportTypeMap.put(context.getString(R.string.title_balance_sheet_report),
+ BalanceSheetFragment.class);
}
/**
@@ -83,8 +91,54 @@ public enum ReportType {
}
}
+ public static ReportType getReportType(final String name) {
+
+ Context context = GnuCashApplication.getAppContext();
+
+ if (name.equals(context.getString(R.string.title_pie_chart))) {
+
+ return PIE_CHART;
+
+ } else if (name.equals(context.getString(R.string.title_bar_chart))) {
+
+ return BAR_CHART;
+
+ } else if (name.equals(context.getString(R.string.title_cash_flow_report))) {
+
+ return LINE_CHART;
+
+ } else if (name.equals(context.getString(R.string.title_balance_sheet_report))) {
+
+ return TEXT;
+
+ } else {
+
+ return NONE;
+ }
+ }
+
public List getReportNames(){
- return new ArrayList<>(mReportTypeMap.keySet());
+
+ Context context = GnuCashApplication.getAppContext();
+
+ if (mReportNames == null) {
+ //
+
+ //
+ mReportNames = new ArrayList();
+
+ mReportNames.add(context.getString(R.string.title_pie_chart));
+ mReportNames.add(context.getString(R.string.title_bar_chart));
+ mReportNames.add(context.getString(R.string.title_cash_flow_report));
+ mReportNames.add(context.getString(R.string.title_balance_sheet_report));
+
+ } else {
+ // n' pas
+
+ // RAF
+ }
+
+ return mReportNames;
}
public BaseReportFragment getFragment(String name){
diff --git a/app/src/main/java/org/gnucash/android/ui/report/ReportsActivity.java b/app/src/main/java/org/gnucash/android/ui/report/ReportsActivity.java
index d8750a9a8..e2c478218 100644
--- a/app/src/main/java/org/gnucash/android/ui/report/ReportsActivity.java
+++ b/app/src/main/java/org/gnucash/android/ui/report/ReportsActivity.java
@@ -32,10 +32,12 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.DatePicker;
import android.widget.Spinner;
+import android.widget.TextView;
import org.gnucash.android.R;
import org.gnucash.android.app.GnuCashApplication;
@@ -76,9 +78,12 @@ public class ReportsActivity extends BaseDrawerActivity implements AdapterView.O
};
private static final String STATE_REPORT_TYPE = "STATE_REPORT_TYPE";
- @BindView(R.id.time_range_spinner) Spinner mTimeRangeSpinner;
- @BindView(R.id.report_account_type_spinner) Spinner mAccountTypeSpinner;
- @BindView(R.id.toolbar_spinner) Spinner mReportTypeSpinner;
+ @BindView(R.id.time_range_spinner)
+ Spinner mTimeRangeSpinner;
+ @BindView(R.id.report_account_type_spinner)
+ Spinner mAccountTypeSpinner;
+ @BindView(R.id.toolbar_spinner)
+ Spinner mReportsToolbarSpinner;
private TransactionsDbAdapter mTransactionsDbAdapter;
private AccountType mAccountType = AccountType.EXPENSE;
@@ -202,14 +207,64 @@ public void updateReportTypeSpinner(ReportType reportType, String reportName) {
mReportType = reportType;
ActionBar actionBar = getSupportActionBar();
assert actionBar != null;
- ArrayAdapter arrayAdapter = new ArrayAdapter<>(actionBar.getThemedContext(),
- android.R.layout.simple_list_item_1,
- mReportType.getReportNames());
+
+ ArrayAdapter arrayAdapter = new ArrayAdapter(actionBar.getThemedContext(),
+ R.layout.toolbar_spinner_selected_item,
+ mReportType.getReportNames()) {
+ /**
+ * @param position
+ * @param convertView
+ * @param parent
+ *
+ * @return
+ */
+ @Override
+ public View getView(final int position,
+ final View convertView,
+ final ViewGroup parent) {
+
+ View view = super.getView(position,
+ convertView,
+ parent);
+
+ if (parent.getId() != R.id.toolbar_spinner) {
+ // Parent view is not the Toolbar Spinner
+
+ //
+ // Set item text color according to Report's type
+ //
+
+ TextView reportTextView = (TextView) view.findViewById(android.R.id.text1);
+
+ if (reportTextView != null) {
+ //
+
+ String reportName = (String) getItem(position);
+
+ final ReportType reportType = ReportType.getReportType(reportName);
+
+ reportTextView.setTextColor(getResources().getColor(reportType.getTitleColor()));
+
+ } else {
+ // n' pas
+
+ // RAF
+ }
+
+ } else {
+ // Parent view is the Toolbar
+
+ // NTD (White by default)
+ }
+
+ return view;
+ }
+ };
mSkipNextReportTypeSelectedRun = true; //selection event will be fired again
- mReportTypeSpinner.setAdapter(arrayAdapter);
- mReportTypeSpinner.setSelection(arrayAdapter.getPosition(reportName));
- mReportTypeSpinner.setOnItemSelectedListener(mReportTypeSelectedListener);
+ mReportsToolbarSpinner.setAdapter(arrayAdapter);
+ mReportsToolbarSpinner.setSelection(arrayAdapter.getPosition(reportName));
+ mReportsToolbarSpinner.setOnItemSelectedListener(mReportTypeSelectedListener);
toggleToolbarTitleVisibility();
@@ -220,9 +275,9 @@ public void toggleToolbarTitleVisibility() {
assert actionBar != null;
if (mReportType == ReportType.NONE){
- mReportTypeSpinner.setVisibility(View.GONE);
+ mReportsToolbarSpinner.setVisibility(View.GONE);
} else {
- mReportTypeSpinner.setVisibility(View.VISIBLE);
+ mReportsToolbarSpinner.setVisibility(View.VISIBLE);
}
actionBar.setDisplayShowTitleEnabled(mReportType == ReportType.NONE);
}
diff --git a/app/src/main/java/org/gnucash/android/ui/report/barchart/StackedBarChartFragment.java b/app/src/main/java/org/gnucash/android/ui/report/barchart/StackedBarChartFragment.java
index 5556c7896..ef501ea3f 100644
--- a/app/src/main/java/org/gnucash/android/ui/report/barchart/StackedBarChartFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/report/barchart/StackedBarChartFragment.java
@@ -81,7 +81,7 @@ public class StackedBarChartFragment extends BaseReportFragment {
@Override
public int getTitle() {
- return R.string.title_cash_flow_report;
+ return R.string.title_bar_chart;
}
@Override
diff --git a/app/src/main/java/org/gnucash/android/ui/settings/GeneralPreferenceFragment.java b/app/src/main/java/org/gnucash/android/ui/settings/GeneralPreferenceFragment.java
index db07e2753..027a1e731 100644
--- a/app/src/main/java/org/gnucash/android/ui/settings/GeneralPreferenceFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/settings/GeneralPreferenceFragment.java
@@ -57,6 +57,7 @@ public class GeneralPreferenceFragment extends PreferenceFragmentCompat implemen
@Override
public void onCreatePreferences(Bundle bundle, String s) {
+
addPreferencesFromResource(R.xml.fragment_general_preferences);
}
@@ -107,24 +108,77 @@ public boolean onPreferenceClick(Preference preference) {
}
@Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (preference.getKey().equals(getString(R.string.key_enable_passcode))) {
+ public boolean onPreferenceChange(Preference preference,
+ Object newValue) {
+
+ //
+ // Set Preference : enable_passcode
+ //
+
+ if (preference.getKey()
+ .equals(getString(R.string.key_enable_passcode))) {
+
if ((Boolean) newValue) {
- startActivityForResult(new Intent(getActivity(), PasscodePreferenceActivity.class),
- GeneralPreferenceFragment.PASSCODE_REQUEST_CODE);
+
+ startActivityForResult(new Intent(getActivity(),
+ PasscodePreferenceActivity.class),
+ GeneralPreferenceFragment.PASSCODE_REQUEST_CODE);
+
} else {
- Intent passIntent = new Intent(getActivity(), PasscodeLockScreenActivity.class);
- passIntent.putExtra(UxArgument.DISABLE_PASSCODE, UxArgument.DISABLE_PASSCODE);
- startActivityForResult(passIntent, GeneralPreferenceFragment.REQUEST_DISABLE_PASSCODE);
+
+ Intent passIntent = new Intent(getActivity(),
+ PasscodeLockScreenActivity.class);
+ passIntent.putExtra(UxArgument.DISABLE_PASSCODE,
+ UxArgument.DISABLE_PASSCODE);
+ startActivityForResult(passIntent,
+ GeneralPreferenceFragment.REQUEST_DISABLE_PASSCODE);
}
}
- if (preference.getKey().equals(getString(R.string.key_use_account_color))) {
+ //
+ // Set Preference : use_color_in_reports
+ //
+
+ if (preference.getKey()
+ .equals(getString(R.string.key_use_account_color))) {
+
+ getPreferenceManager().getSharedPreferences()
+ .edit()
+ .putBoolean(getString(R.string.key_use_account_color),
+ Boolean.valueOf(newValue.toString()))
+ .commit();
+ }
+
+ //
+ // Set Preference : key_account_searchable_spinner_openkeyboard
+ //
+
+ if (preference.getKey()
+ .equals(getString(R.string.key_shall_open_keyboard_in_account_searchable_spinner))) {
+
+ // Store the new value of the Preference
+ getPreferenceManager().getSharedPreferences()
+ .edit()
+ .putBoolean(getString(R.string.key_shall_open_keyboard_in_account_searchable_spinner),
+ Boolean.valueOf(newValue.toString()))
+ .commit();
+ }
+
+ //
+ // Set Preference : use_color_in_account_list
+ //
+
+ if (preference.getKey()
+ .equals(getString(R.string.key_use_color_in_account_list))) {
+
+ // Store the new value of the Preference
getPreferenceManager().getSharedPreferences()
- .edit()
- .putBoolean(getString(R.string.key_use_account_color), Boolean.valueOf(newValue.toString()))
- .commit();
+ .edit()
+ .putBoolean(getString(R.string.key_use_color_in_account_list),
+ Boolean.valueOf(newValue.toString()))
+ .commit();
}
+
return true;
}
diff --git a/app/src/main/java/org/gnucash/android/ui/transaction/ScheduledActionsListFragment.java b/app/src/main/java/org/gnucash/android/ui/transaction/ScheduledActionsListFragment.java
index 01f25340e..abf75287d 100644
--- a/app/src/main/java/org/gnucash/android/ui/transaction/ScheduledActionsListFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/transaction/ScheduledActionsListFragment.java
@@ -25,6 +25,7 @@
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
@@ -78,6 +79,7 @@ public class ScheduledActionsListFragment extends ListFragment implements
* Logging tag
*/
protected static final String TAG = "ScheduledActionFragment";
+ private static final String FRAGMENT_ACTION_KEY = "action_key";
private TransactionsDbAdapter mTransactionsDbAdapter;
private SimpleCursorAdapter mCursorAdapter;
@@ -175,6 +177,10 @@ public static Fragment getInstance(ScheduledAction.ActionType actionType){
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if(savedInstanceState != null && savedInstanceState.containsKey(FRAGMENT_ACTION_KEY)) {
+ mActionType = (ScheduledAction.ActionType) savedInstanceState.getSerializable(FRAGMENT_ACTION_KEY);
+ }
+
mTransactionsDbAdapter = TransactionsDbAdapter.getInstance();
switch (mActionType){
case TRANSACTION:
@@ -641,5 +647,10 @@ public Cursor loadInBackground() {
}
}
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putSerializable(FRAGMENT_ACTION_KEY, mActionType);
+ super.onSaveInstanceState(outState);
+ }
}
diff --git a/app/src/main/java/org/gnucash/android/ui/transaction/SplitEditorFragment.java b/app/src/main/java/org/gnucash/android/ui/transaction/SplitEditorFragment.java
index 1494b16c7..d2fc1b86f 100644
--- a/app/src/main/java/org/gnucash/android/ui/transaction/SplitEditorFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/transaction/SplitEditorFragment.java
@@ -60,6 +60,7 @@
import org.gnucash.android.ui.common.FormActivity;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.transaction.dialog.TransferFundsDialogFragment;
+import org.gnucash.android.ui.util.AccountUtils;
import org.gnucash.android.ui.util.widget.CalculatorEditText;
import org.gnucash.android.ui.util.widget.CalculatorKeyboard;
import org.gnucash.android.ui.util.widget.TransactionTypeSwitch;
@@ -197,13 +198,23 @@ public boolean onOptionsItemSelected(MenuItem item) {
* @return Returns the split view which was added
*/
private View addSplitView(Split split){
+
LayoutInflater layoutInflater = getActivity().getLayoutInflater();
- View splitView = layoutInflater.inflate(R.layout.item_split_entry, mSplitsLinearLayout, false);
- mSplitsLinearLayout.addView(splitView,0);
- SplitViewHolder viewHolder = new SplitViewHolder(splitView, split);
- splitView.setTag(viewHolder);
- mSplitItemViewList.add(splitView);
- return splitView;
+
+ View splitEntryView = layoutInflater.inflate(R.layout.item_split_entry,
+ mSplitsLinearLayout,
+ false);
+
+ // Respect sort list order
+ mSplitsLinearLayout.addView(splitEntryView);
+
+ SplitViewHolder viewHolder = new SplitViewHolder(splitEntryView,
+ split);
+ splitEntryView.setTag(viewHolder);
+
+ mSplitItemViewList.add(splitEntryView);
+
+ return splitEntryView;
}
/**
@@ -216,11 +227,12 @@ private void initArgs() {
mAccountUID = ((FormActivity) getActivity()).getCurrentAccountUID();
mBaseAmount = new BigDecimal(args.getString(UxArgument.AMOUNT_STRING));
- String conditions = "("
+ String where = "("
+ DatabaseSchema.AccountEntry.COLUMN_HIDDEN + " = 0 AND "
+ DatabaseSchema.AccountEntry.COLUMN_PLACEHOLDER + " = 0"
+ ")";
- mCursor = mAccountsDbAdapter.fetchAccountsOrderedByFullName(conditions, null);
+ mCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName(where, null);
+
mCommodity = CommoditiesDbAdapter.getInstance().getCommodity(mAccountsDbAdapter.getCurrencyCode(mAccountUID));
}
@@ -228,13 +240,20 @@ private void initArgs() {
* Holds a split item view and binds the items in it
*/
class SplitViewHolder implements OnTransferFundsListener{
- @BindView(R.id.input_split_memo) EditText splitMemoEditText;
- @BindView(R.id.input_split_amount) CalculatorEditText splitAmountEditText;
- @BindView(R.id.btn_remove_split) ImageView removeSplitButton;
- @BindView(R.id.input_accounts_spinner) Spinner accountsSpinner;
- @BindView(R.id.split_currency_symbol) TextView splitCurrencyTextView;
- @BindView(R.id.split_uid) TextView splitUidTextView;
- @BindView(R.id.btn_split_type) TransactionTypeSwitch splitTypeSwitch;
+ @BindView(R.id.split_currency_symbol)
+ TextView splitCurrencyTextView;
+ @BindView(R.id.input_split_amount)
+ CalculatorEditText splitAmountEditText;
+ @BindView(R.id.btn_split_type)
+ TransactionTypeSwitch splitTypeSwitch;
+ @BindView(R.id.btn_remove_split)
+ ImageView removeSplitButton;
+ @BindView(R.id.input_accounts_spinner)
+ Spinner accountsSpinner;
+ @BindView(R.id.input_split_memo)
+ EditText splitMemoEditText;
+ @BindView(R.id.split_uid)
+ TextView splitUidTextView;
View splitView;
Money quantity;
@@ -267,8 +286,13 @@ public void onClick(View view) {
updateTransferAccountsList(accountsSpinner);
splitCurrencyTextView.setText(mCommodity.getSymbol());
+
+ // Set an amount formatting listener
splitTypeSwitch.setAmountFormattingListener(splitAmountEditText, splitCurrencyTextView);
+
+ // Switch on/off according to amount signum
splitTypeSwitch.setChecked(mBaseAmount.signum() > 0);
+
splitUidTextView.setText(BaseModel.generateUID());
if (split != null) {
@@ -340,7 +364,15 @@ private void setSelectedTransferAccount(long accountId, final Spinner accountsSp
* Only accounts with the same currency can be transferred to
*/
private void updateTransferAccountsList(Spinner transferAccountSpinner){
- mCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(), mCursor);
+
+ // In Splits, an account is allowed to appear many times, therefore there is no restriction on uid
+ String where = AccountUtils.getTransfertAccountWhereClause(null);
+
+ mCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(),
+ mCursor,
+ where,
+ null);
+
transferAccountSpinner.setAdapter(mCursorAdapter);
}
@@ -422,12 +454,17 @@ public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
@Override
public void afterTextChanged(Editable editable) {
+
+
BigDecimal imbalance = BigDecimal.ZERO;
for (View splitItem : mSplitItemViewList) {
SplitViewHolder viewHolder = (SplitViewHolder) splitItem.getTag();
+
BigDecimal amount = viewHolder.getAmountValue().abs();
+
long accountId = viewHolder.accountsSpinner.getSelectedItemId();
+
boolean hasDebitNormalBalance = AccountsDbAdapter.getInstance()
.getAccountType(accountId).hasDebitNormalBalance();
@@ -436,16 +473,20 @@ public void afterTextChanged(Editable editable) {
imbalance = imbalance.add(amount);
else
imbalance = imbalance.subtract(amount);
+
} else {
if (hasDebitNormalBalance)
imbalance = imbalance.subtract(amount);
else
imbalance = imbalance.add(amount);
+
}
}
- TransactionsActivity.displayBalance(mImbalanceTextView, new Money(imbalance, mCommodity));
+ TransactionsActivity.displayBalance(mImbalanceTextView,
+ new Money(imbalance,
+ mCommodity));
}
}
diff --git a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionDetailActivity.java b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionDetailActivity.java
index 44771f872..e498ae4cd 100644
--- a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionDetailActivity.java
+++ b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionDetailActivity.java
@@ -25,6 +25,7 @@
import org.gnucash.android.ui.common.FormActivity;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.passcode.PasscodeLockActivity;
+import org.gnucash.android.ui.util.AccountUtils;
import java.text.DateFormat;
import java.util.Date;
@@ -99,15 +100,30 @@ class SplitAmountViewHolder {
View itemView;
- public SplitAmountViewHolder(View view, Split split){
+ public SplitAmountViewHolder(View view,
+ Split split) {
+
itemView = view;
- ButterKnife.bind(this, view);
+
+ ButterKnife.bind(this,
+ view);
AccountsDbAdapter accountsDbAdapter = AccountsDbAdapter.getInstance();
+
accountName.setText(accountsDbAdapter.getAccountFullName(split.getAccountUID()));
- Money quantity = split.getFormattedQuantity();
- TextView balanceView = quantity.isNegative() ? splitDebit : splitCredit;
- TransactionsActivity.displayBalance(balanceView, quantity);
+
+ // Set color according to Account
+ AccountUtils.setAccountTextColor(accountName,
+ split.getAccountUID());
+
+
+ Money quantity = split.getFormattedQuantity();
+ TextView balanceView = quantity.isNegative()
+ ? splitDebit
+ : splitCredit;
+
+ TransactionsActivity.displayBalance(balanceView,
+ quantity);
}
}
diff --git a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionFormFragment.java b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionFormFragment.java
index ad9f36e03..1203d43fc 100644
--- a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionFormFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionFormFragment.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
@@ -46,7 +47,6 @@
import android.widget.EditText;
import android.widget.FilterQueryProvider;
import android.widget.ImageView;
-import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
@@ -78,10 +78,13 @@
import org.gnucash.android.ui.homescreen.WidgetConfigurationActivity;
import org.gnucash.android.ui.settings.PreferenceActivity;
import org.gnucash.android.ui.transaction.dialog.TransferFundsDialogFragment;
+import org.gnucash.android.ui.util.AccountUtils;
import org.gnucash.android.ui.util.RecurrenceParser;
import org.gnucash.android.ui.util.RecurrenceViewClickListener;
import org.gnucash.android.ui.util.widget.CalculatorEditText;
import org.gnucash.android.ui.util.widget.TransactionTypeSwitch;
+import org.gnucash.android.ui.util.widget.searchablespinner.SearchableSpinnerView;
+import org.gnucash.android.util.KeyboardUtils;
import org.gnucash.android.util.QualifiedAccountNameCursorAdapter;
import java.math.BigDecimal;
@@ -96,6 +99,9 @@
import butterknife.BindView;
import butterknife.ButterKnife;
+import static org.gnucash.android.R.id.secondary_text;
+import static org.gnucash.android.util.QualifiedAccountNameCursorAdapter.hideFavoriteAccountStarIcon;
+
/**
* Fragment for creating or editing transactions
* @author Ngewi Fet
@@ -180,7 +186,8 @@ public class TransactionFormFragment extends Fragment implements
/**
* Spinner for selecting the transfer account
*/
- @BindView(R.id.input_transfer_account_spinner) Spinner mTransferAccountSpinner;
+ @BindView(R.id.input_transfer_account_spinner)
+ SearchableSpinnerView mTransferAccountSearchableSpinnerView;
/**
* Checkbox indicating if this transaction should be saved as a template or not
@@ -251,26 +258,35 @@ public class TransactionFormFragment extends Fragment implements
* Create the view and retrieve references to the UI elements
*/
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_transaction_form, container, false);
- ButterKnife.bind(this, v);
+ public View onCreateView(LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View v = inflater.inflate(R.layout.fragment_transaction_form,
+ container,
+ false);
+
+ ButterKnife.bind(this,
+ v);
+
mAmountEditText.bindListeners(mKeyboardView);
+
mOpenSplitEditor.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+
openSplitEditor();
}
});
return v;
- }
+ }
/**
* Starts the transfer of funds from one currency to another
*/
private void startTransferFunds() {
Commodity fromCommodity = Commodity.getInstance((mTransactionsDbAdapter.getAccountCurrencyCode(mAccountUID)));
- long id = mTransferAccountSpinner.getSelectedItemId();
+ long id = mTransferAccountSearchableSpinnerView.getSelectedItemId();
String targetCurrencyCode = mAccountsDbAdapter.getCurrencyCode(mAccountsDbAdapter.getUID(id));
if (fromCommodity.equals(Commodity.getInstance(targetCurrencyCode))
@@ -296,7 +312,9 @@ public void onConfigurationChanged(Configuration newConfig) {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
+
super.onActivityCreated(savedInstanceState);
+
setHasOptionsMenu(true);
SharedPreferences sharedPrefs = PreferenceActivity.getActiveBookSharedPreferences();
@@ -318,9 +336,17 @@ public void onActivityCreated(Bundle savedInstanceState) {
}
setListeners();
+
+ //
+ // mTransferAccountSearchableSpinnerView
+ //
+
//updateTransferAccountsList must only be called after initializing mAccountsDbAdapter
updateTransferAccountsList();
- mTransferAccountSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+ mTransferAccountSearchableSpinnerView.setTitle(getString(R.string.select_account));
+
+ mTransferAccountSearchableSpinnerView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
/**
* Flag for ignoring first call to this listener.
* The first call is during layout, but we want it called only in response to user interaction
@@ -328,29 +354,43 @@ public void onActivityCreated(Bundle savedInstanceState) {
boolean userInteraction = false;
@Override
- public void onItemSelected(AdapterView> adapterView, View view, int position, long id) {
- removeFavoriteIconFromSelectedView((TextView) view);
+ public void onItemSelected(AdapterView> adapterView,
+ View spinnerSelectedItemView,
+ int position,
+ long id) {
+
+ hideFavoriteAccountStarIcon(spinnerSelectedItemView);
+
+ if (mSplitsList.size() == 2) {
+ //when handling simple transfer to one account
- if (mSplitsList.size() == 2) { //when handling simple transfer to one account
for (Split split : mSplitsList) {
+
if (!split.getAccountUID().equals(mAccountUID)) {
- split.setAccountUID(mAccountsDbAdapter.getUID(id));
+
+ final String accountUID = mAccountsDbAdapter.getUID(id);
+
+ split.setAccountUID(accountUID);
+
+ //
+ // Set Account Color
+ //
+
+ TextView accountFullNameTextView = (TextView) spinnerSelectedItemView.findViewById(android.R.id.text1);
+
+ AccountUtils.setAccountTextColor(accountFullNameTextView,
+ accountUID);
}
// else case is handled when saving the transactions
}
}
+
if (!userInteraction) {
userInteraction = true;
return;
}
- startTransferFunds();
- }
- // Removes the icon from view to avoid visual clutter
- private void removeFavoriteIconFromSelectedView(TextView view) {
- if (view != null) {
- view.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
+ startTransferFunds();
}
@Override
@@ -367,11 +407,18 @@ public void onNothingSelected(AdapterView> adapterView) {
actionBar.setTitle(R.string.title_add_transaction);
initalizeViews();
initTransactionNameAutocomplete();
+
} else {
actionBar.setTitle(R.string.title_edit_transaction);
- initializeViewsWithTransaction();
+ initializeViewsWithTransaction();
mEditMode = true;
- }
+ }
+
+ // Set Focus onto Amount at first
+// mDescriptionEditText.clearFocus();
+ KeyboardUtils.hideKeyboard(mDescriptionEditText,
+ 200);
+ mAmountEditText.requestFocus();
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}
@@ -387,16 +434,28 @@ public DropDownCursorAdapter(Context context, int layout, Cursor c, String[] fro
}
@Override
- public void bindView(View view, Context context, Cursor cursor) {
- super.bindView(view, context, cursor);
+ public void bindView(View view,
+ Context context,
+ Cursor cursor) {
+
+ super.bindView(view,
+ context,
+ cursor);
+
String transactionUID = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseSchema.TransactionEntry.COLUMN_UID));
- Money balance = TransactionsDbAdapter.getInstance().getBalance(transactionUID, mAccountUID);
+
+ Money balance = TransactionsDbAdapter.getInstance()
+ .getBalance(transactionUID,
+ mAccountUID);
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseSchema.TransactionEntry.COLUMN_TIMESTAMP));
- String dateString = DateUtils.formatDateTime(getActivity(), timestamp,
- DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR);
+ String dateString = DateUtils.formatDateTime(getActivity(),
+ timestamp,
+ DateUtils.FORMAT_SHOW_WEEKDAY
+ | DateUtils.FORMAT_SHOW_DATE
+ | DateUtils.FORMAT_SHOW_YEAR);
- TextView secondaryTextView = (TextView) view.findViewById(R.id.secondary_text);
+ TextView secondaryTextView = (TextView) view.findViewById(secondary_text);
secondaryTextView.setText(balance.formattedString() + " on " + dateString); //TODO: Extract string
}
}
@@ -585,18 +644,24 @@ private void initalizeViews() {
* Only accounts with the same currency can be transferred to
*/
private void updateTransferAccountsList(){
- String conditions = "(" + DatabaseSchema.AccountEntry.COLUMN_UID + " != ?"
- + " AND " + DatabaseSchema.AccountEntry.COLUMN_TYPE + " != ?"
- + " AND " + DatabaseSchema.AccountEntry.COLUMN_PLACEHOLDER + " = 0"
- + ")";
+
+ // Get Accounts that are not hidden, nor Placeholder, nor root Account, nor the Account itself
+ String where = AccountUtils.getTransfertAccountWhereClause(mAccountUID);
if (mCursor != null) {
mCursor.close();
}
- mCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName(conditions, new String[]{mAccountUID, AccountType.ROOT.name()});
- mAccountCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(), mCursor);
- mTransferAccountSpinner.setAdapter(mAccountCursorAdapter);
+ mCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName(where,
+ null);
+
+ mAccountCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(),
+ mCursor,
+ where,
+ null,
+ R.layout.account_spinner_dropdown_item);
+
+ mTransferAccountSearchableSpinnerView.setAdapter(mAccountCursorAdapter);
}
/**
@@ -692,10 +757,13 @@ public void onClick(View v) {
* @param accountId Database ID of the transfer account
*/
private void setSelectedTransferAccount(long accountId){
- int position = mAccountCursorAdapter.getPosition(mAccountsDbAdapter.getUID(accountId));
+
+ final String accountUID = mAccountsDbAdapter.getUID(accountId);
+
+ int position = mAccountCursorAdapter.getPosition(accountUID);
if (position >= 0)
- mTransferAccountSpinner.setSelection(position);
- }
+ mTransferAccountSearchableSpinnerView.setSelection(position);
+ }
/**
* Returns a list of splits based on the input in the transaction form.
@@ -766,7 +834,7 @@ private List extractSplitsFromView(){
private @NonNull String getTransferAccountUID() {
String transferAcctUID;
if (mUseDoubleEntry) {
- long transferAcctId = mTransferAccountSpinner.getSelectedItemId();
+ long transferAcctId = mTransferAccountSearchableSpinnerView.getSelectedItemId();
transferAcctUID = mAccountsDbAdapter.getUID(transferAcctId);
} else {
Commodity baseCommodity = mAccountsDbAdapter.getRecord(mAccountUID).getCommodity();
@@ -823,7 +891,7 @@ private boolean isMultiCurrencyTransaction(){
if (!mUseDoubleEntry)
return false;
- String transferAcctUID = mAccountsDbAdapter.getUID(mTransferAccountSpinner.getSelectedItemId());
+ String transferAcctUID = mAccountsDbAdapter.getUID(mTransferAccountSearchableSpinnerView.getSelectedItemId());
String currencyCode = mAccountsDbAdapter.getAccountCurrencyCode(mAccountUID);
String transferCurrencyCode = mAccountsDbAdapter.getCurrencyCode(transferAcctUID);
@@ -949,7 +1017,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
if (mAmountEditText.getValue() == null) {
Toast.makeText(getActivity(), R.string.toast_transanction_amount_required, Toast.LENGTH_SHORT).show();
}
- if (mUseDoubleEntry && mTransferAccountSpinner.getCount() == 0){
+ if (mUseDoubleEntry && mTransferAccountSearchableSpinnerView.getCount() == 0){
Toast.makeText(getActivity(),
R.string.toast_disable_double_entry_to_save_transaction,
Toast.LENGTH_LONG).show();
@@ -969,7 +1037,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
*/
private boolean canSave(){
return (mUseDoubleEntry && mAmountEditText.isInputValid()
- && mTransferAccountSpinner.getCount() > 0)
+ && mTransferAccountSearchableSpinnerView.getCount() > 0)
|| (!mUseDoubleEntry && mAmountEditText.isInputValid());
}
diff --git a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsActivity.java b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsActivity.java
index fb4ba91ef..4475f7203 100644
--- a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsActivity.java
+++ b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsActivity.java
@@ -18,8 +18,10 @@
package org.gnucash.android.ui.transaction;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
+import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Build;
@@ -40,7 +42,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
@@ -50,6 +51,7 @@
import org.gnucash.android.db.adapter.AccountsDbAdapter;
import org.gnucash.android.db.adapter.TransactionsDbAdapter;
import org.gnucash.android.model.Account;
+import org.gnucash.android.model.AccountType;
import org.gnucash.android.model.Money;
import org.gnucash.android.ui.account.AccountsActivity;
import org.gnucash.android.ui.account.AccountsListFragment;
@@ -59,6 +61,7 @@
import org.gnucash.android.ui.common.Refreshable;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.util.AccountBalanceTask;
+import org.gnucash.android.ui.util.widget.searchablespinner.SearchableSpinnerView;
import org.gnucash.android.util.QualifiedAccountNameCursorAdapter;
import org.joda.time.LocalDate;
@@ -68,6 +71,8 @@
import butterknife.BindView;
+import static org.gnucash.android.util.QualifiedAccountNameCursorAdapter.hideFavoriteAccountStarIcon;
+
/**
* Activity for displaying, creating and editing transactions
* @author Ngewi Fet
@@ -78,7 +83,7 @@ public class TransactionsActivity extends BaseDrawerActivity implements
/**
* Logging tag
*/
- protected static final String TAG = "TransactionsActivity";
+ protected static final String LOG_TAG = "TransactionsActivity";
/**
* ViewPager index for sub-accounts fragment
@@ -111,16 +116,17 @@ public class TransactionsActivity extends BaseDrawerActivity implements
*/
private Cursor mAccountsCursor = null;
- @BindView(R.id.pager) ViewPager mViewPager;
- @BindView(R.id.toolbar_spinner) Spinner mToolbarSpinner;
- @BindView(R.id.tab_layout) TabLayout mTabLayout;
- @BindView(R.id.transactions_sum) TextView mSumTextView;
- @BindView(R.id.fab_create_transaction) FloatingActionButton mCreateFloatingButton;
+ @BindView(R.id.pager) ViewPager mViewPager;
+ @BindView(R.id.toolbar_spinner)
+ SearchableSpinnerView mToolbarSpinner;
+ @BindView(R.id.tab_layout) TabLayout mTabLayout;
+ @BindView(R.id.transactions_sum) TextView mSumTextView;
+ @BindView(R.id.fab_create_transaction)FloatingActionButton mCreateFloatingButton;
private SparseArray mFragmentPageReferenceMap = new SparseArray<>();
/**
- * Flag for determining is the currently displayed account is a placeholder account or not.
+ * Flag for determining if the currently displayed account is a placeholder account or not.
* This will determine if the transactions tab is displayed or not
*/
private boolean mIsPlaceholderAccount;
@@ -128,10 +134,18 @@ public class TransactionsActivity extends BaseDrawerActivity implements
private AdapterView.OnItemSelectedListener mTransactionListNavigationListener = new AdapterView.OnItemSelectedListener() {
@Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ public void onItemSelected(AdapterView> parent, View spinnerSelectedItemView, int position, long id) {
+
mAccountUID = mAccountsDbAdapter.getUID(id);
- getIntent().putExtra(UxArgument.SELECTED_ACCOUNT_UID, mAccountUID); //update the intent in case the account gets rotated
- mIsPlaceholderAccount = mAccountsDbAdapter.isPlaceholderAccount(mAccountUID);
+ getIntent().putExtra(UxArgument.SELECTED_ACCOUNT_UID,
+ getCurrentAccountUID()); //update the intent in case the account gets rotated
+
+ //
+ // Show Transaction Page if not a PlaceHolder, hide otherwise
+ //
+
+ mIsPlaceholderAccount = mAccountsDbAdapter.isPlaceholderAccount(getCurrentAccountUID());
+
if (mIsPlaceholderAccount){
if (mTabLayout.getTabCount() > 1) {
mPagerAdapter.notifyDataSetChanged();
@@ -143,10 +157,11 @@ public void onItemSelected(AdapterView> parent, View view, int position, long
mTabLayout.addTab(mTabLayout.newTab().setText(R.string.section_header_transactions));
}
}
- if (view != null) {
- // Hide the favorite icon of the selected account to avoid clutter
- ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
+
+ // Hide star in ToolBar Spinner
+// TextView text1 = (TextView) selectedItemView.findViewById(android.R.id.text1);
+ hideFavoriteAccountStarIcon(spinnerSelectedItemView );
+
//refresh any fragments in the tab with the new account UID
refresh();
}
@@ -157,6 +172,16 @@ public void onNothingSelected(AdapterView> parent) {
}
};
+ private DialogInterface.OnClickListener mSearchableSpinnerPositiveBtnOnClickListener = new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+
+ // NTD
+ }
+ };
+
private PagerAdapter mPagerAdapter;
@@ -229,7 +254,8 @@ public int getCount() {
private AccountsListFragment prepareSubAccountsListFragment(){
AccountsListFragment subAccountsListFragment = new AccountsListFragment();
Bundle args = new Bundle();
- args.putString(UxArgument.PARENT_ACCOUNT_UID, mAccountUID);
+ args.putString(UxArgument.PARENT_ACCOUNT_UID,
+ getCurrentAccountUID());
subAccountsListFragment.setArguments(args);
return subAccountsListFragment;
}
@@ -238,12 +264,17 @@ private AccountsListFragment prepareSubAccountsListFragment(){
* Creates and initializes fragment for displaying transactions
* @return {@link TransactionsListFragment} initialized with the current account transactions
*/
- private TransactionsListFragment prepareTransactionsListFragment(){
+ private TransactionsListFragment prepareTransactionsListFragment() {
+
TransactionsListFragment transactionsListFragment = new TransactionsListFragment();
- Bundle args = new Bundle();
- args.putString(UxArgument.SELECTED_ACCOUNT_UID, mAccountUID);
+ Bundle args = new Bundle();
+ args.putString(UxArgument.SELECTED_ACCOUNT_UID,
+ getCurrentAccountUID());
transactionsListFragment.setArguments(args);
- Log.i(TAG, "Opening transactions for account: " + mAccountUID);
+
+ Log.i(LOG_TAG,
+ "Opening transactions for account: " + getCurrentAccountUID());
+
return transactionsListFragment;
}
}
@@ -260,13 +291,15 @@ public void refresh(String accountUID) {
if (mPagerAdapter != null)
mPagerAdapter.notifyDataSetChanged();
- new AccountBalanceTask(mSumTextView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mAccountUID);
+ new AccountBalanceTask(mSumTextView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
+ getCurrentAccountUID());
}
@Override
public void refresh(){
- refresh(mAccountUID);
+
+ refresh(getCurrentAccountUID());
setTitleIndicatorColor();
}
@@ -282,6 +315,7 @@ public int getTitleRes() {
@Override
protected void onCreate(Bundle savedInstanceState) {
+
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayShowTitleEnabled(false);
@@ -289,7 +323,11 @@ protected void onCreate(Bundle savedInstanceState) {
mAccountUID = getIntent().getStringExtra(UxArgument.SELECTED_ACCOUNT_UID);
mAccountsDbAdapter = AccountsDbAdapter.getInstance();
- mIsPlaceholderAccount = mAccountsDbAdapter.isPlaceholderAccount(mAccountUID);
+ //
+ // Add Tranbsaction Page
+ //
+
+ mIsPlaceholderAccount = mAccountsDbAdapter.isPlaceholderAccount(getCurrentAccountUID());
mTabLayout.addTab(mTabLayout.newTab().setText(R.string.section_header_subaccounts));
if (!mIsPlaceholderAccount) {
@@ -320,8 +358,9 @@ public void onTabReselected(TabLayout.Tab tab) {
});
//if there are no transactions, and there are sub-accounts, show the sub-accounts
- if (TransactionsDbAdapter.getInstance().getTransactionsCount(mAccountUID) == 0
- && mAccountsDbAdapter.getSubAccountCount(mAccountUID) > 0){
+ if (TransactionsDbAdapter.getInstance()
+ .getTransactionsCount(getCurrentAccountUID()) == 0
+ && mAccountsDbAdapter.getSubAccountCount(getCurrentAccountUID()) > 0) {
mViewPager.setCurrentItem(INDEX_SUB_ACCOUNTS_FRAGMENT);
} else {
mViewPager.setCurrentItem(INDEX_TRANSACTIONS_FRAGMENT);
@@ -335,13 +374,14 @@ public void onClick(View v) {
Intent addAccountIntent = new Intent(TransactionsActivity.this, FormActivity.class);
addAccountIntent.setAction(Intent.ACTION_INSERT_OR_EDIT);
addAccountIntent.putExtra(UxArgument.FORM_TYPE, FormActivity.FormType.ACCOUNT.name());
- addAccountIntent.putExtra(UxArgument.PARENT_ACCOUNT_UID, mAccountUID);
+ addAccountIntent.putExtra(UxArgument.PARENT_ACCOUNT_UID,
+ getCurrentAccountUID());
startActivityForResult(addAccountIntent, AccountsActivity.REQUEST_EDIT_ACCOUNT);
;
break;
case INDEX_TRANSACTIONS_FRAGMENT:
- createNewTransaction(mAccountUID);
+ createNewTransaction(getCurrentAccountUID());
break;
}
@@ -359,7 +399,8 @@ protected void onResume() {
* Sets the color for the ViewPager title indicator to match the account color
*/
private void setTitleIndicatorColor() {
- int iColor = AccountsDbAdapter.getActiveAccountColorResource(mAccountUID);
+
+ int iColor = AccountsDbAdapter.getActiveAccountColorResource(getCurrentAccountUID());
mTabLayout.setBackgroundColor(iColor);
@@ -374,40 +415,51 @@ private void setTitleIndicatorColor() {
* Set up action bar navigation list and listener callbacks
*/
private void setupActionBarNavigation() {
+
+ //
// set up spinner adapter for navigation list
+ //
+
if (mAccountsCursor != null) {
mAccountsCursor.close();
}
- mAccountsCursor = mAccountsDbAdapter.fetchAllRecordsOrderedByFullName();
+ mAccountsCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName();
+
+ SpinnerAdapter qualifiedAccountNameCursorAdapter = new QualifiedAccountNameCursorAdapter(getSupportActionBar().getThemedContext(),
+ getAccountsCursor(),
+ AccountsDbAdapter.WHERE_NOT_HIDDEN_AND_NOT_ROOT_ACCOUNT,
+ new String[]{AccountType.ROOT.name()},
+ R.layout.toolbar_spinner_selected_item);
- SpinnerAdapter mSpinnerAdapter = new QualifiedAccountNameCursorAdapter(
- getSupportActionBar().getThemedContext(), mAccountsCursor, R.layout.account_spinner_item);
+ mToolbarSpinner.setAdapter(qualifiedAccountNameCursorAdapter);
- mToolbarSpinner.setAdapter(mSpinnerAdapter);
mToolbarSpinner.setOnItemSelectedListener(mTransactionListNavigationListener);
+
+ mToolbarSpinner.setTitle(getString(R.string.select_account));
+
+ // The "positive" button act as a Cancel button
+ mToolbarSpinner.setPositiveButton(getString(R.string.alert_dialog_cancel),
+ mSearchableSpinnerPositiveBtnOnClickListener);
+
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- updateNavigationSelection();
+ selectCurrentAccountInToolbarSpinner();
}
/**
* Updates the action bar navigation list selection to that of the current account
* whose transactions are being displayed/manipulated
*/
- public void updateNavigationSelection() {
- // set the selected item in the spinner
- int i = 0;
- Cursor accountsCursor = mAccountsDbAdapter.fetchAllRecordsOrderedByFullName();
- while (accountsCursor.moveToNext()) {
- String uid = accountsCursor.getString(accountsCursor.getColumnIndexOrThrow(DatabaseSchema.AccountEntry.COLUMN_UID));
- if (mAccountUID.equals(uid)) {
- mToolbarSpinner.setSelection(i);
- break;
- }
- ++i;
- }
+ public void selectCurrentAccountInToolbarSpinner() {
+
+ Cursor accountsCursor = mAccountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName();
+
+ SearchableSpinnerView.selectSpinnerAccount(accountsCursor,
+ getCurrentAccountUID(),
+ mToolbarSpinner);
+
accountsCursor.close();
- }
+ }
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
@@ -416,7 +468,8 @@ public boolean onPrepareOptionsMenu(Menu menu) {
if (favoriteAccountMenuItem == null) //when the activity is used to edit a transaction
return super.onPrepareOptionsMenu(menu);
- boolean isFavoriteAccount = AccountsDbAdapter.getInstance().isFavoriteAccount(mAccountUID);
+ boolean isFavoriteAccount = AccountsDbAdapter.getInstance()
+ .isFavoriteAccount(getCurrentAccountUID());
int favoriteIcon = isFavoriteAccount ? R.drawable.ic_star_white_24dp : R.drawable.ic_star_border_white_24dp;
favoriteAccountMenuItem.setIcon(favoriteIcon);
@@ -432,8 +485,8 @@ public boolean onOptionsItemSelected(MenuItem item) {
case R.id.menu_favorite_account:
AccountsDbAdapter accountsDbAdapter = AccountsDbAdapter.getInstance();
- long accountId = accountsDbAdapter.getID(mAccountUID);
- boolean isFavorite = accountsDbAdapter.isFavoriteAccount(mAccountUID);
+ long accountId = accountsDbAdapter.getID(getCurrentAccountUID());
+ boolean isFavorite = accountsDbAdapter.isFavoriteAccount(getCurrentAccountUID());
//toggle favorite preference
accountsDbAdapter.updateAccount(accountId, DatabaseSchema.AccountEntry.COLUMN_FAVORITE, isFavorite ? "0" : "1");
supportInvalidateOptionsMenu();
@@ -442,7 +495,8 @@ public boolean onOptionsItemSelected(MenuItem item) {
case R.id.menu_edit_account:
Intent editAccountIntent = new Intent(this, FormActivity.class);
editAccountIntent.setAction(Intent.ACTION_INSERT_OR_EDIT);
- editAccountIntent.putExtra(UxArgument.SELECTED_ACCOUNT_UID, mAccountUID);
+ editAccountIntent.putExtra(UxArgument.SELECTED_ACCOUNT_UID,
+ getCurrentAccountUID());
editAccountIntent.putExtra(UxArgument.FORM_TYPE, FormActivity.FormType.ACCOUNT.name());
startActivityForResult(editAccountIntent, AccountsActivity.REQUEST_EDIT_ACCOUNT);
return true;
@@ -465,7 +519,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
@Override
protected void onDestroy() {
super.onDestroy();
- mAccountsCursor.close();
+ getAccountsCursor().close();
}
/**
@@ -476,6 +530,11 @@ public String getCurrentAccountUID(){
return mAccountUID;
}
+ public Cursor getAccountsCursor() {
+
+ return mAccountsCursor;
+ }
+
/**
* Display the balance of a transaction in a text view and format the text color to match the sign of the amount
* @param balanceTextView {@link android.widget.TextView} where balance is to be displayed
@@ -528,7 +587,8 @@ public void createNewTransaction(String accountUID) {
public void editTransaction(String transactionUID){
Intent createTransactionIntent = new Intent(this.getApplicationContext(), FormActivity.class);
createTransactionIntent.setAction(Intent.ACTION_INSERT_OR_EDIT);
- createTransactionIntent.putExtra(UxArgument.SELECTED_ACCOUNT_UID, mAccountUID);
+ createTransactionIntent.putExtra(UxArgument.SELECTED_ACCOUNT_UID,
+ getCurrentAccountUID());
createTransactionIntent.putExtra(UxArgument.SELECTED_TRANSACTION_UID, transactionUID);
createTransactionIntent.putExtra(UxArgument.FORM_TYPE, FormActivity.FormType.TRANSACTION.name());
startActivity(createTransactionIntent);
diff --git a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsListFragment.java b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsListFragment.java
index 9ea0847e9..3f718f69e 100644
--- a/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsListFragment.java
+++ b/app/src/main/java/org/gnucash/android/ui/transaction/TransactionsListFragment.java
@@ -58,6 +58,7 @@
import org.gnucash.android.ui.homescreen.WidgetConfigurationActivity;
import org.gnucash.android.ui.settings.PreferenceActivity;
import org.gnucash.android.ui.transaction.dialog.BulkMoveDialogFragment;
+import org.gnucash.android.ui.util.AccountUtils;
import org.gnucash.android.ui.util.CursorRecyclerAdapter;
import org.gnucash.android.ui.util.widget.EmptyRecyclerView;
import org.gnucash.android.util.BackupManager;
@@ -164,8 +165,13 @@ public void refresh(){
@Override
public void onResume() {
+
super.onResume();
- ((TransactionsActivity)getActivity()).updateNavigationSelection();
+
+ // Select Current Account in Toolbar
+ ((TransactionsActivity)getActivity()).selectCurrentAccountInToolbarSpinner();
+
+ // Refresh Transaction List according to currently selected Account in Toolbar Spinner
refresh();
}
@@ -299,6 +305,11 @@ public void onClick(View v) {
for (Split split : splits) {
if (!split.getAccountUID().equals(mAccountUID)) {
text = AccountsDbAdapter.getInstance().getFullyQualifiedAccountName(split.getAccountUID());
+
+ // Set color according to Account
+ AccountUtils.setAccountTextColor(holder.secondaryText,
+ split.getAccountUID());
+
break;
}
}
@@ -308,6 +319,7 @@ public void onClick(View v) {
text = splits.size() + " splits";
}
holder.secondaryText.setText(text);
+
holder.transactionDate.setText(dateText);
holder.editTransaction.setOnClickListener(new View.OnClickListener() {
diff --git a/app/src/main/java/org/gnucash/android/ui/util/AccountUtils.java b/app/src/main/java/org/gnucash/android/ui/util/AccountUtils.java
new file mode 100644
index 000000000..b2e8c48a9
--- /dev/null
+++ b/app/src/main/java/org/gnucash/android/ui/util/AccountUtils.java
@@ -0,0 +1,93 @@
+package org.gnucash.android.ui.util;
+
+import android.support.v7.preference.PreferenceManager;
+import android.widget.TextView;
+
+import org.gnucash.android.R;
+import org.gnucash.android.db.DatabaseSchema;
+import org.gnucash.android.db.adapter.AccountsDbAdapter;
+import org.gnucash.android.model.AccountType;
+
+/**
+ * Utilities for Accounts UI
+ *
+ * @author JeanGarf
+ */
+public class AccountUtils {
+
+ /**
+ * Set text color according to account one
+ * if preference about using colors in account list is true
+ *
+ * @param accountTextView
+ * View containing text field to colorize
+ *
+ * @param accountUID
+ * Account UID
+ */
+ public static void setAccountTextColor(final TextView accountTextView,
+ final String accountUID) {
+
+ if (accountTextView != null) {
+ // accountTextView is not null
+
+ // Get Preference about using colors in account list
+ boolean prefShallUseColorInAccountList = PreferenceManager.getDefaultSharedPreferences(accountTextView.getContext())
+ .getBoolean(accountTextView.getContext()
+ .getString(R.string.key_use_color_in_account_list),
+ true);
+
+ if (prefShallUseColorInAccountList) {
+ // Want to use colors for Accounts
+
+ // Get Account color
+ int iColor = AccountsDbAdapter.getActiveAccountColorResource(accountUID);
+
+ // Override color
+ accountTextView.setTextColor(iColor);
+
+ } else {
+ // Do not want to use colors for Accounts
+
+ // NTD
+ }
+
+ } else {
+ // accountTextView is null
+
+ // RAF
+ }
+ }
+
+ /**
+ * Build the where clause to select Accounts allowed for Transfer
+ * for the given accountUID
+ *
+ * @param accountUID
+ * The account UID for which we want to collect account allowed for transfer
+ * May be null (to allow all non special accounts)
+ *
+ * @return
+ * the where clause
+ *
+ * @author JeanGarf
+ */
+ public static String getTransfertAccountWhereClause(final String accountUID) {
+
+ return "("
+ + DatabaseSchema.AccountEntry.COLUMN_UID
+ + " != '"
+ + ((accountUID != null) ? accountUID : "")
+ + "' AND "
+ + DatabaseSchema.AccountEntry.COLUMN_TYPE
+ + " != '"
+ + AccountType.ROOT.name()
+ + "' AND "
+ + DatabaseSchema.AccountEntry.COLUMN_PLACEHOLDER
+ + " = 0"
+ + " AND "
+ + DatabaseSchema.AccountEntry.COLUMN_HIDDEN
+ + " = 0"
+ + ")";
+ }
+}
diff --git a/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/ItemContainingTextFilter.java b/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/ItemContainingTextFilter.java
new file mode 100644
index 000000000..c927e4c97
--- /dev/null
+++ b/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/ItemContainingTextFilter.java
@@ -0,0 +1,171 @@
+package org.gnucash.android.ui.util.widget.searchablespinner;
+
+import android.widget.Filter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Generic filter that filters (it modifies it) the given list
+ * to retain items whose item contains a text to search
+ *
+ * The isFoundInItem() method can be overridden to change the search criteria
+ * The default search criteria consist to find the lower case text to search in
+ * the lower case of the item.toString()
+ *
+ * @author JeanGarf
+ */
+public class ItemContainingTextFilter
+ extends Filter {
+
+ /**
+ * Copy of original all items list
+ */
+ private List mOriginalNonFilteredItemsList;
+
+ /**
+ * Pointer on Adapter's item list (which will be filtered)
+ */
+ private List mAdaptersItemsList;
+
+ /**
+ * Constructor
+ */
+ public ItemContainingTextFilter(final List adaptersItemsList) {
+
+ // Store a pointer to adapter's item list
+ setAdaptersItemsList(adaptersItemsList);
+
+ // Create a second list which won't be filtered to store the original non filtered items
+ setOriginalNonFilteredItemsList(new ArrayList<>(adaptersItemsList));
+ }
+
+
+ /**
+ * Build filtered results, which is a structure containing
+ * filtered items (whose text contains textToSearch)
+ * count of filtered items
+ *
+ * @param textToSearch
+ * text to search (in item.toString()), to retain item
+ *
+ * @return structure containing filtered items and count
+ */
+ @Override
+ protected FilterResults performFiltering(CharSequence textToSearch) {
+
+ final FilterResults filterResults = new FilterResults();
+
+ // Create a new list to store filtered items (the list points to the same items as the original's one, but not all the
+ // items
+ final List filteredItems = new ArrayList();
+
+ if (textToSearch == null || textToSearch.length() == 0) {
+ // Nothing to search
+
+ // Create a new List pointing on the same items as the original one
+ // in order not to alter the original non filtered items list
+ filteredItems.addAll(getOriginalNonFilteredItemsList());
+
+ } else {
+ // There is something to search
+
+ //
+ // Filter original items list
+ //
+
+ final int count = getOriginalNonFilteredItemsList().size();
+
+ for (int i = 0; i < count; i++) {
+
+ // Get item from original non filtered list
+ final T_ITEM item = getOriginalNonFilteredItemsList().get(i);
+
+ final boolean isFoundInItem = isFoundInItem(textToSearch,
+ item);
+
+ if (isFoundInItem) {
+ // It matches
+
+ // Add it to filtered list
+ filteredItems.add(item);
+
+ } else {
+ // It does not match
+
+ // NTD
+ }
+ } // for
+
+ }
+
+ filterResults.values = filteredItems;
+ filterResults.count = filteredItems.size();
+
+ return filterResults;
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint,
+ FilterResults filteredResults) {
+
+ // Replace Adapter's items list with the filtered list
+ getAdaptersItemsList().clear();
+ getAdaptersItemsList().addAll((List) filteredResults.values);
+ }
+
+ //
+ // Methods to be overridden
+ //
+
+ /**
+ * Return true if textToSearch has been found in item
+ *
+ * In this default implementation, the text is found if the lower case
+ * textToSearch is found in the lower case of the item.toString() string
+ *
+ * @param textToSearch
+ * @param item
+ *
+ * @return
+ * Return true if textToSearch has been found in item
+ */
+ protected boolean isFoundInItem(final CharSequence textToSearch,
+ final T_ITEM item) {
+
+ // get the item.toString()
+ final String itemTextLowerCase = item.toString()
+ .toLowerCase();
+
+ final String textToSearchLowerCase = textToSearch.toString()
+ .toLowerCase();
+
+ // First match against the whole, non-splitted value
+ return itemTextLowerCase.contains(textToSearchLowerCase);
+ }
+
+ //
+ // Getters/Setters
+ //
+
+
+ protected List getOriginalNonFilteredItemsList() {
+
+ return mOriginalNonFilteredItemsList;
+ }
+
+ protected void setOriginalNonFilteredItemsList(final List originalNonFilteredItemsList) {
+
+ mOriginalNonFilteredItemsList = originalNonFilteredItemsList;
+ }
+
+ protected List getAdaptersItemsList() {
+
+ return mAdaptersItemsList;
+ }
+
+ protected void setAdaptersItemsList(final List adaptersItemsList) {
+
+ mAdaptersItemsList = adaptersItemsList;
+ }
+}
diff --git a/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/SearchableListDialogFragment.java b/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/SearchableListDialogFragment.java
new file mode 100644
index 000000000..988643811
--- /dev/null
+++ b/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/SearchableListDialogFragment.java
@@ -0,0 +1,617 @@
+package org.gnucash.android.ui.util.widget.searchablespinner;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.SearchManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+import android.support.v7.preference.PreferenceManager;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.ListView;
+import android.widget.SearchView;
+
+import org.gnucash.android.R;
+import org.gnucash.android.util.KeyboardUtils;
+import org.gnucash.android.util.QualifiedAccountNameCursorAdapter;
+
+import java.io.Serializable;
+
+/**
+ * Pop-up that display a ListView with a search text field
+ *
+ * @author JeanGarf
+ */
+public class SearchableListDialogFragment
+ extends DialogFragment
+ implements SearchView.OnQueryTextListener,
+ SearchView.OnCloseListener,
+ Filter.FilterListener {
+
+ /**
+ * Logging tag
+ */
+ protected static final String LOG_TAG = "SearchLstDlgFragment";
+
+ public static final String KEY_ACCOUNT_UID = "key_accountUID";
+ public static final String KEY_ACCOUNT_SIMPLE_NAME = "key_accountName";
+ public static final String KEY_ACCOUNT_FULL_NAME = "key_accountFullName";
+ public static final String KEY_PARENT_ACCOUNT_FULL_NAME = "key_parentAccountFullName";
+ public static final String KEY_IS_FAVORITE_ACCOUNT = "key_isFavoriteAccount";
+
+ /**
+ * Listener to call when user clicks on an item
+ *
+ * @param
+ * item Type
+ */
+ public interface OnSearchableItemClickedListener
+ extends Serializable {
+
+ void onSearchableListItemClicked(T_ITEM item);
+ }
+
+ /**
+ * Listener to call when Search text change
+ */
+ public interface OnSearchTextChangedListener {
+ void onSearchTextChanged(String strText);
+ }
+
+ //
+ // Parent SearchableSpinnerView
+ //
+
+ private SearchableSpinnerView _parentSearchableSpinnerView;
+
+ //
+ // Dialog
+ //
+
+ // Dialog Title
+ private String mStrTitle;
+
+ // Search Edit text zone
+ private SearchView mSearchTextEditView;
+
+ // Item list
+ ListView mListView;
+
+ // Bottom right button to close the pop-up
+ private String mStrPositiveButtonText;
+
+ //
+ // ListView Adapter
+ //
+
+ // Adapter for the mListView
+ private BaseAdapter mListViewAdapter;
+
+ //
+ // Listeners
+ //
+
+ private OnSearchTextChangedListener mOnSearchTextChangedListener;
+
+ private OnSearchableItemClickedListener mOnSearchableListItemClickedListener;
+
+ private DialogInterface.OnClickListener mOnPositiveBtnClickListener;
+
+ private DialogInterface.OnCancelListener mOnCancelListener;
+
+ // true if dismiss dialog has already been requested
+ private boolean mIsDismissing;
+
+
+ /**
+ * Constructor
+ */
+ public SearchableListDialogFragment() {
+
+ }
+
+ /**
+ * Factory
+ *
+ * @return
+ */
+ public static SearchableListDialogFragment makeInstance(SearchableSpinnerView parentSearchableSpinnerView) {
+
+ SearchableListDialogFragment searchableListDialogFragment = new SearchableListDialogFragment();
+
+ // Store a link to the Parent SearchableSpinnerView which holds the CursorAdapter
+ searchableListDialogFragment.setParentSearchableSpinnerView(parentSearchableSpinnerView);
+
+ return searchableListDialogFragment;
+ }
+
+ //
+ // Event handlers
+ //
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+
+ super.onCreate(savedInstanceState);
+
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ ViewGroup container,
+ Bundle savedInstanceState) {
+
+ return super.onCreateView(inflater,
+ container,
+ savedInstanceState);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+ // Getting the layout inflater to inflate the view in an alert dialog.
+ LayoutInflater inflater = LayoutInflater.from(getActivity());
+
+ // Crash on orientation change #7
+ // Change Start
+ // Description: As the instance was re initializing to null on rotating the device,
+ // getting the instance from the saved instance
+ if (null != savedInstanceState) {
+ setOnSearchableListItemClickListener((OnSearchableItemClickedListener) savedInstanceState.getSerializable("item"));
+ }
+ // Change End
+
+ //
+ // Prepare the searchableListView
+ //
+
+ // Instantiate the searchableListView from XML
+ View searchableListRootView = inflater.inflate(R.layout.searchable_list_dialog,
+ null);
+
+ // Configure the searchableListView
+ configureView(searchableListRootView);
+
+ //
+ // Create dialog builder
+ //
+
+ AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
+
+ // Indicate to put the searchableListView in the alertDialog
+ alertDialogBuilder.setView(searchableListRootView);
+
+ // Title
+
+ String strTitle = mStrTitle == null
+ ? "Select Item"
+ : mStrTitle;
+
+ alertDialogBuilder.setTitle(strTitle);
+
+ // Positive Button
+
+ String strPositiveButton = mStrPositiveButtonText == null
+ ? "CLOSE"
+ : mStrPositiveButtonText;
+
+ alertDialogBuilder.setPositiveButton(strPositiveButton,
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(final DialogInterface dialog,
+ final int which) {
+
+ // Dismiss dialog
+ dismissDialog();
+
+ if (mOnPositiveBtnClickListener != null) {
+ //
+
+ // Call listener
+ mOnPositiveBtnClickListener.onClick(dialog,
+ which);
+
+ } else {
+ // n' pas
+
+ // RAF
+ }
+ }
+ });
+
+ //
+ // Create searchableListDialog
+ //
+
+ final AlertDialog searchableListDialog = alertDialogBuilder.create();
+
+ return searchableListDialog;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+
+ if (getListView().isTextFilterEnabled()) {
+ // Filtering is enabled
+
+ //
+ //
+ // Start List filtering Thread
+ //
+
+ final Filterable listViewCursorAdapter = (Filterable) getListView().getAdapter();
+
+ if (TextUtils.isEmpty(s)) {
+
+
+ // Force filtering with null string to get the full account list
+
+ listViewCursorAdapter.getFilter()
+ .filter(null,
+ this);
+
+ } else {
+
+ // Perform filtering
+
+ // Do not use this, because it makes a big black square appears when typing text
+ // getListView().setFilterText(s);
+
+ // instead, use this
+ listViewCursorAdapter.getFilter()
+ .filter(s,
+ this);
+ }
+
+ } else {
+ // Filtering is enabled n' pas
+
+ // RAF
+ }
+
+ //
+ // Call Search Text Change Listener
+ //
+
+ if (mOnSearchTextChangedListener != null) {
+
+ // Call Listener
+ mOnSearchTextChangedListener.onSearchTextChanged(s);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+
+ mSearchTextEditView.clearFocus();
+
+ return true;
+ }
+
+ @Override
+ public void onFilterComplete(final int count) {
+
+ if (count > 0) {
+ // There are filtered items
+
+ getListViewAdapter().notifyDataSetChanged();
+
+ } else {
+ // There is none filtered items
+
+ getListViewAdapter().notifyDataSetInvalidated();
+ }
+ }
+
+ // Crash on orientation change #7
+ // Change Start
+ // Description: Saving the instance of searchable item instance.
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+
+ outState.putSerializable("item",
+ getOnSearchableListItemClickedListener());
+ super.onSaveInstanceState(outState);
+ }
+ // Change End
+
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+
+ dismissDialog();
+
+ if (mOnCancelListener != null) {
+ // There is a listener
+
+ // Call listener
+ mOnCancelListener.onCancel(dialog);
+
+ } else {
+ // There is no listener
+
+ // RAF
+ }
+ }
+
+ @Override
+ public boolean onClose() {
+
+ return false;
+ }
+
+ @Override
+ public void onPause() {
+
+ super.onPause();
+ dismiss();
+ }
+
+ //
+ // local methods
+ //
+
+ private void configureView(View searchableListRootView) {
+
+ mIsDismissing = false;
+
+ //
+ // Search Edit text
+ //
+
+ mSearchTextEditView = (SearchView) searchableListRootView.findViewById(R.id.search);
+
+ SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
+
+ mSearchTextEditView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
+ // mSearchTextEditView.setIconifiedByDefault(false); // Already done in xml
+ mSearchTextEditView.setOnQueryTextListener(this);
+ mSearchTextEditView.setOnCloseListener(this);
+
+ // Get Preference about opening keyboard, default to false
+ boolean prefShallOpenKeyboard = PreferenceManager.getDefaultSharedPreferences(getActivity())
+ .getBoolean(getString(R.string.key_shall_open_keyboard_in_account_searchable_spinner),
+ false);
+
+ if (prefShallOpenKeyboard) {
+ // Want to open keyboard
+
+ // Set Focus on searchTextEditView to open cursor
+ mSearchTextEditView.setFocusable(true);
+ mSearchTextEditView.requestFocus();
+
+ } else {
+ // Do not want to open keyboard
+
+ // Clear Focus
+ mSearchTextEditView.clearFocus();
+
+ //
+ // Hide keyboard after 500ms to let keyboard appeared before hiding it
+ //
+
+ KeyboardUtils.hideKeyboard(mSearchTextEditView,
+ 500);
+ }
+
+ //
+ // Items list
+ //
+
+ setListView((ListView) searchableListRootView.findViewById(R.id.listItems));
+
+ // Use the parent spinner view adapter for the list view
+ setListViewAdapter((BaseAdapter) getParentSearchableSpinnerView().getAdapter());
+
+ if (getListViewAdapter() != null) {
+
+ if (QualifiedAccountNameCursorAdapter.class.isAssignableFrom(getListViewAdapter().getClass())) {
+ // The parentSpinnerAdapter is a QualifiedAccountNameCursorAdapter
+
+ QualifiedAccountNameCursorAdapter parentCursorAdapter = (QualifiedAccountNameCursorAdapter) getListViewAdapter();
+
+ //
+ // Put temporarily DropDownItemLayout in selectedItemView,
+ // because ListView use only selectedItemView for list item
+ //
+
+ parentCursorAdapter.setViewResource(parentCursorAdapter.getSpinnerDropDownItemLayout());
+
+ } else {
+ // The parentSpinnerAdapter is another kind of Adapter
+
+ // NTD
+ }
+
+// //
+// // Register a Listener to close dialog if there is only one item remaining in the filtered list, and select it
+// // automatically
+// //
+//
+// getListViewAdapter().registerDataSetObserver(new DataSetObserver() {
+//
+// @Override
+// public void onChanged() {
+//
+// if (getListViewAdapter().getCount() == 1) {
+// // only one account
+//
+// dismissDialog();
+//
+// final T_ITEM item = (T_ITEM) getListViewAdapter().getItem(0);
+//
+// // Simulate a onSearchableListItemClicked
+// getOnSearchableListItemClickedListener().onSearchableListItemClicked(item);
+//
+// } else {
+// // only one account n' pas
+//
+// // RAF
+// }
+//
+// }
+// });
+
+ // On item click listener
+ getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView> parent,
+ View view,
+ int position,
+ long id) {
+
+ dismissDialog();
+
+ final T_ITEM item = (T_ITEM) getListViewAdapter().getItem(position);
+
+ // Call Listener
+ getOnSearchableListItemClickedListener().onSearchableListItemClicked(item);
+ }
+ });
+
+ //
+ // Attach the adapter to the list
+ //
+
+ getListView().setAdapter(getListViewAdapter());
+
+ // Enable filtering based on search text field
+ getListView().setTextFilterEnabled(true);
+ }
+
+ // Simulate an empty search text field to build the full accounts list
+ onQueryTextChange(null);
+ }
+
+ protected void dismissDialog() {
+
+ if (!mIsDismissing) {
+ // It is the first time dismissing has been requested
+
+ // Avoid infinite looping
+ mIsDismissing = true;
+
+ //
+ // Restore original Spinner Selected Item Layout
+ //
+
+ if (QualifiedAccountNameCursorAdapter.class.isAssignableFrom(getParentSearchableSpinnerView().getAdapter()
+ .getClass())) {
+ // The Adapter is a QualifiedAccountNameCursorAdapter
+
+ QualifiedAccountNameCursorAdapter parentCursorAdapter = (QualifiedAccountNameCursorAdapter) getParentSearchableSpinnerView().getAdapter();
+
+ parentCursorAdapter.setViewResource(parentCursorAdapter.getSpinnerSelectedItemLayout());
+
+ // Refresh spinner selected item using spinner selected item layout
+ parentCursorAdapter.notifyDataSetChanged();
+
+ } else {
+ // The Adapter is not a QualifiedAccountNameCursorAdapter
+
+ // NTD
+ }
+
+ //
+ // Hide keyboard
+ //
+
+ KeyboardUtils.hideKeyboard(mSearchTextEditView);
+
+ //
+ // Close Dialog
+ //
+
+ getDialog().dismiss();
+
+ } else {
+ // Dismissing has already been requested
+
+ // NTD
+ }
+ }
+
+ //
+ // Getters / Setters
+ //
+
+ protected SearchableSpinnerView getParentSearchableSpinnerView() {
+
+ return _parentSearchableSpinnerView;
+ }
+
+ protected void setParentSearchableSpinnerView(SearchableSpinnerView parentSearchableSpinnerView) {
+
+ _parentSearchableSpinnerView = parentSearchableSpinnerView;
+ }
+
+ protected ListView getListView() {
+
+ return mListView;
+ }
+
+ protected void setListView(final ListView listView) {
+
+ this.mListView = listView;
+ }
+
+ protected BaseAdapter getListViewAdapter() {
+
+ return mListViewAdapter;
+ }
+
+ protected void setListViewAdapter(final BaseAdapter listViewAdapter) {
+
+ mListViewAdapter = listViewAdapter;
+ }
+
+ protected void setTitle(String strTitle) {
+
+ mStrTitle = strTitle;
+ }
+
+ protected void setPositiveButtonText(String strPositiveButtonText) {
+
+ mStrPositiveButtonText = strPositiveButtonText;
+ }
+
+ protected void setPositiveButtonClickListener(DialogInterface.OnClickListener onClickListener) {
+
+ mOnPositiveBtnClickListener = onClickListener;
+ }
+
+ protected void setOnSearchableListItemClickListener(OnSearchableItemClickedListener onSearchableListItemClickedListener) {
+
+ this.mOnSearchableListItemClickedListener = onSearchableListItemClickedListener;
+ }
+
+ protected OnSearchableItemClickedListener getOnSearchableListItemClickedListener() {
+
+ return mOnSearchableListItemClickedListener;
+ }
+
+ protected void setOnCancelListener(DialogInterface.OnCancelListener onCancelListener) {
+
+ this.mOnCancelListener = onCancelListener;
+ }
+
+ protected void setOnSearchTextChangedListener(OnSearchTextChangedListener onSearchTextChangedListener) {
+
+ this.mOnSearchTextChangedListener = onSearchTextChangedListener;
+ }
+
+
+}
diff --git a/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/SearchableSpinnerView.java b/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/SearchableSpinnerView.java
new file mode 100644
index 000000000..8d853486b
--- /dev/null
+++ b/app/src/main/java/org/gnucash/android/ui/util/widget/searchablespinner/SearchableSpinnerView.java
@@ -0,0 +1,270 @@
+package org.gnucash.android.ui.util.widget.searchablespinner;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.DialogInterface;
+import android.database.Cursor;
+import android.support.v4.widget.CursorAdapter;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+
+import org.gnucash.android.db.DatabaseSchema;
+import org.gnucash.android.util.QualifiedAccountNameCursorAdapter;
+
+/**
+ * Spinner that open a dialog box with text search criteria
+ * to filter the item list
+ *
+ * @param
+ * Type of an item
+ *
+ * * @author JeanGarf
+ */
+public class SearchableSpinnerView
+ extends android.support.v7.widget.AppCompatSpinner
+ implements View.OnTouchListener,
+ SearchableListDialogFragment.OnSearchableItemClickedListener {
+
+ /**
+ * Logging tag
+ */
+ protected static final String LOG_TAG = "SearchableSpinnerView";
+
+ // Embedded DialogFragment
+ private SearchableListDialogFragment mSearchableListDialogFragment;
+
+ public SearchableSpinnerView(Context context) {
+
+ super(context);
+
+ init();
+ }
+
+ public SearchableSpinnerView(Context context,
+ AttributeSet attrs) {
+
+ super(context,
+ attrs);
+
+ //
+ // Init
+ //
+
+ init();
+ }
+
+ public SearchableSpinnerView(Context context,
+ AttributeSet attrs,
+ int defStyleAttr) {
+
+ super(context,
+ attrs,
+ defStyleAttr);
+
+ init();
+ }
+
+ private void init() {
+
+ // Create Dialog instance
+ setSearchableListDialogFragment(SearchableListDialogFragment.makeInstance(this));
+
+ // S'abonner aux clicks sur un item
+ getSearchableListDialogFragment().setOnSearchableListItemClickListener(this);
+
+ // S'abonner aux évènements onTouch
+ setOnTouchListener(this);
+ }
+
+ //
+ // Listeners
+ //
+
+ @Override
+ public boolean onTouch(View v,
+ MotionEvent event) {
+
+ boolean handled = false;
+
+ if (getSearchableListDialogFragment() != null) {
+ // There is a DialogFragment defined
+
+ handled = true;
+
+ if (getSearchableListDialogFragment().isAdded()) {
+ // dialog is already visible
+
+ // NTD
+
+ } else {
+ // dialog is not visible
+
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ // User has just clicked on the spinner
+
+ // Display SearchableListDialogFragment
+ getSearchableListDialogFragment().show(scanForActivity(getContext()).getFragmentManager(),
+ "LOG_TAG");
+ }
+ }
+
+ } else {
+ // There is no DialogFragment defined
+
+ // NTD
+ }
+
+ return handled;
+ }
+
+ private Activity scanForActivity(Context context) {
+
+ if (context == null) {
+ return null;
+
+ } else if (context instanceof Activity) {
+ return (Activity) context;
+
+ } else if (context instanceof ContextWrapper) {
+ return scanForActivity(((ContextWrapper) context).getBaseContext());
+ }
+
+ return null;
+ }
+
+ @Override
+ public void onSearchableListItemClicked(T_ITEM item) {
+
+ if (CursorAdapter.class.isAssignableFrom(getAdapter().getClass())) {
+ // The Adapter is a CursorAdapter
+
+ final Cursor cursor = (Cursor) item;
+
+ String accountUID = cursor.getString(cursor.getColumnIndex(DatabaseSchema.AccountEntry.COLUMN_UID));
+
+ selectSpinnerAccount(cursor,
+ accountUID,
+ this);
+
+ } else if (getAdapter() instanceof ArrayAdapter) {
+ // The Adapter is a ListAdapter
+
+ setSelection(((ArrayAdapter) getAdapter()).getPosition(item));
+
+ } else {
+
+ throw new IllegalArgumentException("SearchableSpinnerView can only handle ArrayAdapter and CursorAdapter");
+ }
+ }
+
+ /**
+ *
+ * @param accountsCursor
+ * @param accountUID
+ * @param spinnerView
+ */
+ public static void selectSpinnerAccount(Cursor accountsCursor,
+ final String accountUID,
+ final Spinner spinnerView) {
+
+ //
+ // set the selected item in the spinner
+ //
+
+ int spinnerSelectedPosition = 0;
+ boolean found = false;
+
+ for (accountsCursor.moveToFirst(); !accountsCursor.isAfterLast(); accountsCursor.moveToNext()) {
+
+ String uid = accountsCursor.getString(accountsCursor.getColumnIndexOrThrow(DatabaseSchema.AccountEntry.COLUMN_UID));
+ String accountFullName = accountsCursor.getString(accountsCursor.getColumnIndexOrThrow(DatabaseSchema.AccountEntry.COLUMN_FULL_NAME));
+
+ if (accountUID.equals(uid)) {
+ // Found
+
+ Log.d(LOG_TAG,
+ "Account found in current Cursor for ("
+ + accountUID
+ + ") => ("
+ + accountFullName
+ + "), position ("
+ + spinnerSelectedPosition
+ + ")");
+
+ // Set Spinner selection
+ spinnerView.setSelection(spinnerSelectedPosition);
+
+ found = true;
+ break;
+ }
+
+ ++spinnerSelectedPosition;
+
+ } // for
+
+ if (found) {
+ // Account has found
+
+ // NTD
+
+ } else {
+ // Account has not been found
+
+ // Log message
+ Log.e(LOG_TAG,
+ "No Account found in current Cursor for (" + accountUID + ")");
+ }
+ }
+
+ //
+ // Getters/Setters
+ //
+
+
+ protected SearchableListDialogFragment getSearchableListDialogFragment() {
+
+ return mSearchableListDialogFragment;
+ }
+
+ protected void setSearchableListDialogFragment(final SearchableListDialogFragment searchableListDialogFragment) {
+
+ mSearchableListDialogFragment = searchableListDialogFragment;
+ }
+
+ public void setTitle(String strTitle) {
+
+ getSearchableListDialogFragment().setTitle(strTitle);
+ }
+
+ public void setPositiveButton(String strPositiveButtonText,
+ DialogInterface.OnClickListener onPositiveBtnClickListener) {
+
+ getSearchableListDialogFragment().setPositiveButtonText(strPositiveButtonText);
+
+ getSearchableListDialogFragment().setPositiveButtonClickListener(onPositiveBtnClickListener);
+ }
+
+
+ public void setOnSearchTextChangedListener(SearchableListDialogFragment.OnSearchTextChangedListener onSearchTextChangedListener) {
+
+ getSearchableListDialogFragment().setOnSearchTextChangedListener(onSearchTextChangedListener);
+ }
+
+ /**
+ * Register a callback to be invoked when an item in this AdapterView has
+ * been selected.
+ *
+ * @param listener The callback that will run
+ */
+ public void setOnCancelListener(DialogInterface.OnCancelListener listener) {
+
+ getSearchableListDialogFragment().setOnCancelListener(listener);
+ }
+
+}
diff --git a/app/src/main/java/org/gnucash/android/util/CommoditiesCursorAdapter.java b/app/src/main/java/org/gnucash/android/util/CommoditiesCursorAdapter.java
index 03f16608c..41b59e6c1 100644
--- a/app/src/main/java/org/gnucash/android/util/CommoditiesCursorAdapter.java
+++ b/app/src/main/java/org/gnucash/android/util/CommoditiesCursorAdapter.java
@@ -35,11 +35,16 @@
*/
public class CommoditiesCursorAdapter extends SimpleCursorAdapter {
- public CommoditiesCursorAdapter(Context context, @LayoutRes int itemLayoutResource) {
- super(context, itemLayoutResource,
- CommoditiesDbAdapter.getInstance().fetchAllRecords(DatabaseSchema.CommodityEntry.COLUMN_MNEMONIC + " ASC"),
- new String[]{DatabaseSchema.CommodityEntry.COLUMN_FULLNAME},
- new int[] {android.R.id.text1}, 0);
+ public CommoditiesCursorAdapter(Context context,
+ @LayoutRes int itemLayoutResource) {
+
+ super(context,
+ itemLayoutResource,
+ CommoditiesDbAdapter.getInstance()
+ .fetchAllRecords(DatabaseSchema.CommodityEntry.COLUMN_MNEMONIC + " ASC"),
+ new String[]{DatabaseSchema.CommodityEntry.COLUMN_FULLNAME},
+ new int[]{android.R.id.text1},
+ 0);
}
@Override
diff --git a/app/src/main/java/org/gnucash/android/util/KeyboardUtils.java b/app/src/main/java/org/gnucash/android/util/KeyboardUtils.java
new file mode 100644
index 000000000..2894d5076
--- /dev/null
+++ b/app/src/main/java/org/gnucash/android/util/KeyboardUtils.java
@@ -0,0 +1,54 @@
+package org.gnucash.android.util;
+
+import android.content.Context;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+/**
+ * Created by JeanGarf on 2020-02-01.
+ */
+public class KeyboardUtils {
+
+ /**
+ * Hide keyboard
+ *
+ * @param editTextView
+ */
+ public static void hideKeyboard(final View editTextView) {
+
+ //
+ // Hide keyboard
+ //
+
+ InputMethodManager keyboard = (InputMethodManager) editTextView.getContext()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ keyboard.hideSoftInputFromWindow(editTextView.getWindowToken(),
+ 0);
+ }
+
+ /**
+ * Hide keyboard after a delay
+ *
+ * @param editTextView
+ * @param delay
+ */
+ public static void hideKeyboard(final View editTextView,
+ final long delay) {
+
+// editTextView.requestFocus();
+
+ // Delay the keyboard hiding
+ editTextView.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+
+ // Hide keyboard
+ hideKeyboard(editTextView);
+ }
+ },
+ delay);
+ }
+
+
+}
diff --git a/app/src/main/java/org/gnucash/android/util/QualifiedAccountNameCursorAdapter.java b/app/src/main/java/org/gnucash/android/util/QualifiedAccountNameCursorAdapter.java
index 77bc86674..888027c8e 100644
--- a/app/src/main/java/org/gnucash/android/util/QualifiedAccountNameCursorAdapter.java
+++ b/app/src/main/java/org/gnucash/android/util/QualifiedAccountNameCursorAdapter.java
@@ -21,13 +21,19 @@
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v4.widget.SimpleCursorAdapter;
-import android.text.TextUtils;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FilterQueryProvider;
import android.widget.TextView;
import org.gnucash.android.R;
import org.gnucash.android.db.DatabaseSchema;
import org.gnucash.android.db.adapter.AccountsDbAdapter;
+import org.gnucash.android.ui.util.AccountUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
* Cursor adapter which looks up the fully qualified account name and returns that instead of just the simple name.
@@ -35,60 +41,436 @@
*
* @author Ngewi Fet
*/
-public class QualifiedAccountNameCursorAdapter extends SimpleCursorAdapter {
+public class QualifiedAccountNameCursorAdapter
+ extends SimpleCursorAdapter {
/**
- * Initialize the Cursor adapter for account names using default spinner views
- * @param context Application context
- * @param cursor Cursor to accounts
+ * Removes the icon from view to avoid visual clutter
+ *
+ * @param spinnerView
+ */
+ public static void hideFavoriteAccountStarIcon(View spinnerView) {
+
+ TextView textViewWithStarIcon = (TextView) spinnerView.findViewById(R.id.text2);
+
+ if (textViewWithStarIcon != null) {
+
+ textViewWithStarIcon.setCompoundDrawablesWithIntrinsicBounds(0,
+ 0,
+ 0,
+ 0);
+ }
+ }
+
+ // Layout of the selected spinner item (the one with down arrow)
+ private int mSpinnerSelectedItemLayout;
+
+ // Layout of items in the drop down list
+ private int mSpinnerDropDownItemLayout;
+
+ // Clause WHERE du Cursor (in order to be replayed by the item filter)
+ private String mCursorWhere;
+ private String[] mCursorWhereArgs;
+
+ /**
+ * Overloaded constructor. Specifies the view to use for displaying selected spinner text
+ *
+ * @param context
+ * Application context
+ * @param cursor
+ * Cursor to account data
+ * @param spinnerSelectedItemLayout
+ * Layout resource for selected item text
*/
- public QualifiedAccountNameCursorAdapter(Context context, Cursor cursor) {
- super(context, android.R.layout.simple_spinner_item, cursor,
- new String[]{DatabaseSchema.AccountEntry.COLUMN_FULL_NAME},
- new int[]{android.R.id.text1}, 0);
- setDropDownViewResource(R.layout.account_spinner_dropdown_item);
+ public QualifiedAccountNameCursorAdapter(Context context,
+ Cursor cursor,
+ String cursorWhere,
+ String[] cursorWhereArgs,
+ @LayoutRes int spinnerSelectedItemLayout,
+ @LayoutRes int spinnerDropDownItemLayout
+ ) {
+
+ super(context,
+ spinnerSelectedItemLayout,// Layout of the selected spinner item
+ cursor,
+ new String[]{DatabaseSchema.AccountEntry.COLUMN_FULL_NAME,
+ DatabaseSchema.AccountEntry.COLUMN_NAME},
+ new int[]{android.R.id.text1,
+ R.id.text2},
+ 0);
+
+ // Store layout of each item in the open drop down of the spinner
+ setSpinnerSelectedItemLayout(spinnerSelectedItemLayout);
+
+ // Store layout of each item in the open drop down of the spinner
+ setSpinnerDropDownItemLayout(spinnerDropDownItemLayout);
+
+ // Store the WHERE clause associated with the Cursor
+ setCursorWhere(cursorWhere);
+ setCursorWhereArgs(cursorWhereArgs);
+
+ // Define filter
+ setFilterQueryProvider(new FilterQueryProvider() {
+
+ public Cursor runQuery(CharSequence constraint) {
+
+ //
+ // Add %constraint% at the end of the whereArgs
+ //
+
+ // Convert WhereArgs into List
+ final String[] cursorWhereArgs = getCursorWhereArgs();
+ final List whereArgsAsList = (cursorWhereArgs != null)
+ ? new ArrayList(Arrays.asList(cursorWhereArgs))
+ : new ArrayList();
+
+ // Add the %constraint% for the LIKE added in the where clause
+ whereArgsAsList.add("%" + ((constraint != null)
+ ? constraint.toString()
+ : "") + "%");
+
+ // Convert List into WhereArgs
+ final String[] whereArgs = whereArgsAsList.toArray(new String[whereArgsAsList.size()]);
+
+
+ //
+ // Run the original query but constrained with full account name containing constraint
+ //
+
+ final AccountsDbAdapter accountsDbAdapter = AccountsDbAdapter.getInstance();
+
+ final String where = ((getCursorWhere() != null)
+ ? getCursorWhere() + " AND "
+ : "")
+ + DatabaseSchema.AccountEntry.COLUMN_FULL_NAME
+ + " LIKE ?";
+
+ final Cursor accountsCursor = accountsDbAdapter.fetchAccountsOrderedByFavoriteAndFullName(where,
+ whereArgs);
+
+ return accountsCursor;
+ }
+ });
}
/**
* Overloaded constructor. Specifies the view to use for displaying selected spinner text
- * @param context Application context
- * @param cursor Cursor to account data
- * @param selectedSpinnerItem Layout resource for selected item text
+ *
+ * @param context
+ * Application context
+ * @param cursor
+ * Cursor to account data
+ * @param selectedSpinnerItemLayout
+ * Layout resource for selected item text
*/
- public QualifiedAccountNameCursorAdapter(Context context, Cursor cursor,
- @LayoutRes int selectedSpinnerItem) {
- super(context, selectedSpinnerItem, cursor,
- new String[]{DatabaseSchema.AccountEntry.COLUMN_FULL_NAME},
- new int[]{android.R.id.text1}, 0);
- setDropDownViewResource(R.layout.account_spinner_dropdown_item);
+ public QualifiedAccountNameCursorAdapter(Context context,
+ Cursor cursor,
+ String cursorWhere,
+ String[] cursorWhereArgs,
+ @LayoutRes int selectedSpinnerItemLayout) {
+
+ this(context,
+ cursor,
+ cursorWhere,
+ cursorWhereArgs,
+ selectedSpinnerItemLayout, // Layout of the closed spinner item
+ R.layout.account_spinner_dropdown_item_2lines
+ );
}
+ /**
+ * Initialize the Cursor adapter for account names using default spinner views
+ *
+ * @param context
+ * Application context
+ * @param cursor
+ * Cursor to accounts
+ */
+ public QualifiedAccountNameCursorAdapter(Context context,
+ Cursor cursor,
+ String cursorWhere,
+ String[] cursorWhereArgs) {
+
+ this(context,
+ cursor,
+ cursorWhere,
+ cursorWhereArgs,
+ android.R.layout.simple_spinner_item // Layout of the closed spinner item
+ );
+ }
+
+ /**
+ * Initialize the Cursor adapter for account names using default spinner views
+ *
+ * @param context
+ * Application context
+ * @param cursor
+ * Cursor to accounts
+ */
+ public QualifiedAccountNameCursorAdapter(Context context,
+ Cursor cursor) {
+
+ this(context,
+ cursor,
+ null,
+ null
+ );
+ }
+
+ //
+ // Overrides
+ //
+
+
@Override
- public void bindView(View view, Context context, Cursor cursor) {
- super.bindView(view, context, cursor);
- TextView textView = (TextView) view.findViewById(android.R.id.text1);
- textView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
+ public View getView(final int position,
+ final View convertView,
+ final ViewGroup parent) {
+
+ View view = super.getView(position,
+ convertView,
+ parent);
+
+ Cursor cursor = getCursor();
+
+ if (parent.getId() != R.id.toolbar_spinner) {
+ // Parent view is not the Toolbar Spinner
+
+ //
+ // Set Account Color
+ //
+
+ String accountUID = cursor.getString(cursor.getColumnIndex(DatabaseSchema.AccountEntry.COLUMN_UID));
+
+ setTextColorAccordingToAccountUID(view,
+ accountUID);
+
+ } else {
+ // Parent view is the Toolbar Spinner
+
+ // NTD (White by default)
+ }
+
+ //
+ // Put Parent Account Full Name in text3
+ //
+
+ TextView parentAccountFullNameTextView = (TextView) view.findViewById(R.id.text3);
+
+ if (parentAccountFullNameTextView != null) {
+ // The field exists
+
+ String accountFullName = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseSchema.AccountEntry.COLUMN_FULL_NAME));
+
+ // Get Parent account Full Name
+ String parentAccountFullName = getParentAccountFullName(accountFullName);
+
+ // Display Parent Account Full Name
+ parentAccountFullNameTextView.setText(parentAccountFullName);
+
+ } else {
+ // The field does not exist
+
+ // NTD
+ }
+
+ //
+ // Add or not Favorite Star Icon
+ //
Integer isFavorite = cursor.getInt(cursor.getColumnIndex(DatabaseSchema.AccountEntry.COLUMN_FAVORITE));
- if(isFavorite == 0) {
- textView.setCompoundDrawablesWithIntrinsicBounds(0,0,0,0);
+
+ displayFavoriteAccountStarIcon(view,
+ isFavorite);
+
+ return view;
+ }
+
+ /**
+ * To avoid "attempt to re-open an already-closed object" exception
+ * due to use of runQuery()
+ *
+ * See
+ * https://stackoverflow.com/questions/17458251/android-attempt-to-re-open-an-already-closed-object-sqlitequery-using-loaderm
+ *
+ * @param cursor
+ */
+ @Override
+ public void changeCursor(final Cursor cursor) {
+
+ // Do not close cursor
+ super.swapCursor(cursor);
+ }
+
+ //
+ // Local methods
+ //
+
+ /**
+ * Extract parent account full name
+ *
+ * @param accountFullName
+ * Account full name
+ *
+ * @return parent account full name
+ */
+ String getParentAccountFullName(final String accountFullName) {
+
+ String parentAccountFullName;
+
+ // Look for last separator
+ int index = accountFullName.lastIndexOf(AccountsDbAdapter.ACCOUNT_NAME_SEPARATOR);
+
+ if (index > 0) {
+ // An account separator has been found
+
+ // parent full name is before the account separator
+ parentAccountFullName = accountFullName.substring(0,
+ index);
+
+ } else {
+ // No account separator has been found
+
+ // Do not display anything for parent
+ parentAccountFullName = "";
+ }
+ return parentAccountFullName;
+ }
+
+ /**
+ * Set text color according to account one
+ *
+ * @param view
+ * View containing text field to colorize
+ * @param accountUID
+ * Account UID
+ */
+ void setTextColorAccordingToAccountUID(final View view,
+ final String accountUID) {
+
+ //
+ // Set color on text1 (selected spinner item)
+ //
+
+ TextView simpleAccountNameTextView = (TextView) view.findViewById(android.R.id.text1);
+
+ AccountUtils.setAccountTextColor(simpleAccountNameTextView,
+ accountUID);
+
+ //
+ // Set color on text2
+ //
+
+ simpleAccountNameTextView = (TextView) view.findViewById(R.id.text2);
+
+ AccountUtils.setAccountTextColor(simpleAccountNameTextView,
+ accountUID);
+ }
+
+ /**
+ * Display or hide star icon according to favorite account status
+ *
+ * @param spinnerSelectedItemView
+ * @param isFavoriteAccount
+ */
+ void displayFavoriteAccountStarIcon(View spinnerSelectedItemView,
+ Integer isFavoriteAccount) {
+
+ TextView simpleAccountNameTextView = (TextView) spinnerSelectedItemView.findViewById(R.id.text2);
+
+ if (simpleAccountNameTextView != null) {
+ // The field exists
+
+ if (isFavoriteAccount == 0) {
+ // It is not a Favorite account
+
+ // Hide Favorite Account Star
+ hideFavoriteAccountStarIcon(spinnerSelectedItemView);
+
+ } else {
+ // It is a Favorite account
+
+ // Display Favorite Account Star
+ simpleAccountNameTextView.setCompoundDrawablesWithIntrinsicBounds(0,
+ 0,
+ R.drawable.ic_star_black_18dp,
+ 0);
+ }
+
} else {
- textView.setCompoundDrawablesWithIntrinsicBounds(0,0,R.drawable.ic_star_black_18dp,0);
+ // The field does not exists
+
+ // NTD
}
}
/**
* Returns the position of a given account in the adapter
- * @param accountUID GUID of the account
+ *
+ * @param accountUID
+ * GUID of the account
+ *
* @return Position of the account or -1 if the account is not found
*/
- public int getPosition(@NonNull String accountUID){
- long accountId = AccountsDbAdapter.getInstance().getID(accountUID);
+ public int getPosition(@NonNull String accountUID) {
+
+ long accountId = AccountsDbAdapter.getInstance()
+ .getID(accountUID);
+
for (int pos = 0; pos < getCount(); pos++) {
- if (getItemId(pos) == accountId){
+
+ if (getItemId(pos) == accountId) {
return pos;
}
}
+
return -1;
}
+
+ //
+ // Getters/Setters
+ //
+
+ String getCursorWhere() {
+
+ return mCursorWhere;
+ }
+
+ protected void setCursorWhere(final String cursorWhere) {
+
+ mCursorWhere = cursorWhere;
+ }
+
+ String[] getCursorWhereArgs() {
+
+ return mCursorWhereArgs;
+ }
+
+ protected void setCursorWhereArgs(final String[] cursorWhereArgs) {
+
+ mCursorWhereArgs = cursorWhereArgs;
+ }
+
+ public int getSpinnerSelectedItemLayout() {
+
+ return mSpinnerSelectedItemLayout;
+ }
+
+ public void setSpinnerSelectedItemLayout(int spinnerSelectedItemLayout) {
+
+ mSpinnerSelectedItemLayout = spinnerSelectedItemLayout;
+ }
+
+ public int getSpinnerDropDownItemLayout() {
+
+ return mSpinnerDropDownItemLayout;
+ }
+
+ public void setSpinnerDropDownItemLayout(int spinnerDropDownItemLayout) {
+
+ mSpinnerDropDownItemLayout = spinnerDropDownItemLayout;
+
+ setDropDownViewResource(getSpinnerDropDownItemLayout());
+ }
+
}
diff --git a/app/src/main/res/layout/account_spinner_dropdown_item.xml b/app/src/main/res/layout/account_spinner_dropdown_item.xml
index c32bfdc6a..6d53e5d7e 100644
--- a/app/src/main/res/layout/account_spinner_dropdown_item.xml
+++ b/app/src/main/res/layout/account_spinner_dropdown_item.xml
@@ -15,10 +15,8 @@
limitations under the License.
-->
\ No newline at end of file
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/dropdownListPreferredItemHeight"
+ style="?android:attr/spinnerDropDownItemStyle"
+/>
\ No newline at end of file
diff --git a/app/src/main/res/layout/account_spinner_dropdown_item_2lines.xml b/app/src/main/res/layout/account_spinner_dropdown_item_2lines.xml
new file mode 100644
index 000000000..74e8572e2
--- /dev/null
+++ b/app/src/main/res/layout/account_spinner_dropdown_item_2lines.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_transaction_detail.xml b/app/src/main/res/layout/activity_transaction_detail.xml
index 66a50ed96..f0a2d3739 100644
--- a/app/src/main/res/layout/activity_transaction_detail.xml
+++ b/app/src/main/res/layout/activity_transaction_detail.xml
@@ -41,6 +41,8 @@
@@ -132,10 +132,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false" />
-
+ android:layout_height="wrap_content"
+ />
-
diff --git a/app/src/main/res/layout/fragment_report_summary.xml b/app/src/main/res/layout/fragment_report_summary.xml
index dfb9ab9dd..20c239edf 100644
--- a/app/src/main/res/layout/fragment_report_summary.xml
+++ b/app/src/main/res/layout/fragment_report_summary.xml
@@ -49,7 +49,7 @@ limitations under the License.
android:layout_weight="1"
android:drawableLeft="@drawable/ic_trending_up_white_24dp"
android:drawableStart="@drawable/ic_trending_up_white_24dp"
- android:text="@string/title_line_chart"/>
+ android:text="@string/title_cash_flow_report"/>
+ android:text="@string/title_balance_sheet_report"/>
diff --git a/app/src/main/res/layout/fragment_split_editor.xml b/app/src/main/res/layout/fragment_split_editor.xml
index 60f428ece..69f371d50 100644
--- a/app/src/main/res/layout/fragment_split_editor.xml
+++ b/app/src/main/res/layout/fragment_split_editor.xml
@@ -29,7 +29,7 @@ limitations under the License.
@@ -37,7 +37,7 @@ limitations under the License.
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="right|center_vertical"
tools:text="$200"/>
diff --git a/app/src/main/res/layout/fragment_transaction_form.xml b/app/src/main/res/layout/fragment_transaction_form.xml
index a011a6df4..0ba15f7bd 100644
--- a/app/src/main/res/layout/fragment_transaction_form.xml
+++ b/app/src/main/res/layout/fragment_transaction_form.xml
@@ -100,11 +100,13 @@
-
+ />
diff --git a/app/src/main/res/layout/item_split_entry.xml b/app/src/main/res/layout/item_split_entry.xml
index 90fa38150..38c4054f5 100644
--- a/app/src/main/res/layout/item_split_entry.xml
+++ b/app/src/main/res/layout/item_split_entry.xml
@@ -20,6 +20,7 @@ limitations under the License.
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
+
+
+
+
+
+
+
+
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dialog_padding"
+ android:layout_marginLeft="10dp"
+ android:layout_marginBottom="@dimen/dialog_padding"
+ >
+
-
-
-
-
-
+
+
diff --git a/app/src/main/res/layout/searchable_list_dialog.xml b/app/src/main/res/layout/searchable_list_dialog.xml
new file mode 100644
index 000000000..e93fbcbb9
--- /dev/null
+++ b/app/src/main/res/layout/searchable_list_dialog.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/account_spinner_item.xml b/app/src/main/res/layout/toolbar_spinner_selected_item.xml
similarity index 80%
rename from app/src/main/res/layout/account_spinner_item.xml
rename to app/src/main/res/layout/toolbar_spinner_selected_item.xml
index 485d7d26b..1e3914b7c 100644
--- a/app/src/main/res/layout/account_spinner_item.xml
+++ b/app/src/main/res/layout/toolbar_spinner_selected_item.xml
@@ -16,10 +16,10 @@
-->
\ No newline at end of file
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:gravity="center|left"
+ style="?android:attr/spinnerItemStyle"
+ android:textAlignment="inherit"
+ android:textColor="@color/bpWhite"
+ />
\ No newline at end of file
diff --git a/app/src/main/res/layout/toolbar_with_spinner.xml b/app/src/main/res/layout/toolbar_with_spinner.xml
index b823bc1fb..5bc4707cd 100644
--- a/app/src/main/res/layout/toolbar_with_spinner.xml
+++ b/app/src/main/res/layout/toolbar_with_spinner.xml
@@ -32,9 +32,13 @@
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
tools:showIn="@layout/activity_form">
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/raw-hr/default_accounts.gnucash b/app/src/main/res/raw-hr/default_accounts.gnucash
new file mode 100644
index 000000000..5dadf8a71
--- /dev/null
+++ b/app/src/main/res/raw-hr/default_accounts.gnucash
@@ -0,0 +1,889 @@
+
+
+1
+60
+
+ ISO4217
+ HRK
+
+ currency
+
+
+
+ template
+ template
+ template
+ template
+ 1
+
+
+ Root Account
+ 5341c3d89c4a4163ba2cd13a0f521033
+ ROOT
+
+ ISO4217
+ HRK
+
+ 100
+
+
+ Rashod
+ 235ba33cbfbb45b18a14ef690c65a8f0
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Rashod
+
+
+ color
+ #D13E29
+
+
+ placeholder
+ true
+
+
+ 5341c3d89c4a4163ba2cd13a0f521033
+
+
+ Osiguranje
+ 9892b814fe2a442ba344af98862e5c49
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Osiguranje
+
+
+ placeholder
+ true
+
+
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Osiguranje kućanstva
+ 0efe6e487ce149fe9d8d2f6fa6c92838
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Osiguranje stvari kućanstva
+ 9892b814fe2a442ba344af98862e5c49
+
+
+ Osiguranje imovine
+ bb3bfe896d7048ecb76a3c453888bfb0
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Osiguranje kuće, stana, apartmana
+ 9892b814fe2a442ba344af98862e5c49
+
+
+ Zdravstveno osiguranje
+ e17cc50365084a538b69ff308ae2f7f5
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Zdravstveno osiguranje
+ 9892b814fe2a442ba344af98862e5c49
+
+
+ Stanovanje
+ ab80c55c11ea4d37b27ee84ed27b3878
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Troškovi stanovanja
+
+
+ placeholder
+ true
+
+
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Najamnina
+ c9803aa724ad41c6864992b4167339da
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Najamnina
+ ab80c55c11ea4d37b27ee84ed27b3878
+
+
+ Režije
+ 8254099c5c8a4454ae394e5853cc558a
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Režije
+
+
+ placeholder
+ true
+
+
+ ab80c55c11ea4d37b27ee84ed27b3878
+
+
+ Plin
+ 8755f7661cf34377ae596daac3df8167
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Plin
+ 8254099c5c8a4454ae394e5853cc558a
+
+
+ Struja
+ e871041f3aaa4a91afac7c32f7dee6f5
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Struja
+ 8254099c5c8a4454ae394e5853cc558a
+
+
+ Voda
+ 2d5605f4bf674a868d58299f1b42e634
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Voda
+ 8254099c5c8a4454ae394e5853cc558a
+
+
+ Grijanje
+ 1b32c949e760400ca39170dbe0e7aeaf
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Grijanje
+ 8254099c5c8a4454ae394e5853cc558a
+
+
+ Čistoća
+ 528973ad80764a8e9cf1c3e7467b5409
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Čistoća
+ 8254099c5c8a4454ae394e5853cc558a
+
+
+ Komunalna naknada
+ a7f6651f9cf34e2ab31ea164d949ea4a
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Komunalna naknada
+ 8254099c5c8a4454ae394e5853cc558a
+
+
+ Pričuva
+ 55e82a78bd8d49afb58aa4cec4878f3d
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Pričuva
+ 8254099c5c8a4454ae394e5853cc558a
+
+
+ Telekomunikacija
+ 15599741f6414e5bacf6a721123054ce
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Telekomunikacija
+
+
+ placeholder
+ true
+
+
+ ab80c55c11ea4d37b27ee84ed27b3878
+
+
+ Televizija
+ 85e284fe8ab74fff844cd37e89ad9701
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ RTV pretplata
+ 15599741f6414e5bacf6a721123054ce
+
+
+ Internet
+ f79d94ab9d014a20a0e00ebce765539a
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Internet
+ 15599741f6414e5bacf6a721123054ce
+
+
+ Telefon
+ d3b95f1b45a84594b513414cfdfe5a34
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Telefon/Mobitel
+ 15599741f6414e5bacf6a721123054ce
+
+
+ Mrežne usluge
+ cc27256b8391480c95158df6bf86681c
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Mrežne usluge
+ 15599741f6414e5bacf6a721123054ce
+
+
+ Obrazovanje
+ 0a136f6f18af49d7bc9e189da49745eb
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Obrazovanje
+
+
+ placeholder
+ true
+
+
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Pretplate
+ ce6ec9b02ae7459aa182b0d866ed7e10
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Pretplate, npr. na časopise
+ 0a136f6f18af49d7bc9e189da49745eb
+
+
+ Knjige
+ 11420c5117c7474d98465f3282288638
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Knjige
+ 0a136f6f18af49d7bc9e189da49745eb
+
+
+ Uredski materijal
+ e3dbccbd84b14ae095a66df282ab937f
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Uredski materijal
+ 0a136f6f18af49d7bc9e189da49745eb
+
+
+ Odjeća i obuća
+ c5e2ae12932548c8b7999597bb487e4e
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Odjeća i obuća
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Namirnice
+ 07c603cdb09e462983f4c3ce61beb10c
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Namirnice
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Lijekovi
+ 1f649ce81ee9422f87f09822dcb279e6
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Lijekovi
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Razni troškovi
+ 6b118c004de94d319777f315aac31590
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Razni troškovi
+
+
+ placeholder
+ true
+
+
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Bankovne naknade
+ dc31044a0a1f43179ab9917caacb8005
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Bankovne naknade
+ 6b118c004de94d319777f315aac31590
+
+
+ Razno
+ 12781eaa4a744c0890d43ebecf3ac02b
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Neodređeni troškovi
+ 6b118c004de94d319777f315aac31590
+
+
+ Izlasci
+ 77a047c799b841f8a1723d3b0bb82dbd
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Koncerti, kino, kafići i sl.
+ 6b118c004de94d319777f315aac31590
+
+
+ Putovanja
+ 23f06146e1004ee2abca2711b049d19c
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Putovanja, ljetovanje, skijanje
+ 6b118c004de94d319777f315aac31590
+
+
+ Sport
+ 05fec015e7464e139c63824f48d11d40
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Sport
+ 6b118c004de94d319777f315aac31590
+
+
+ Porezi
+ 874c3bdc5ce649b38526ede38511c6aa
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Porezi i prirezi
+
+
+ placeholder
+ true
+
+
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Ostali porezi
+ f5f8b06aab9d4e7ab45562b70ff0f38d
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Ostali porezi
+ 874c3bdc5ce649b38526ede38511c6aa
+
+
+ Kamate
+ 397a362bb1854eb282c81b1c55c8c8ed
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Kamate
+
+
+ placeholder
+ true
+
+
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Kamate na kredit
+ 8e830a56bfd74bf794d3daa0ee4d2e89
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Kamate na kredit
+ 397a362bb1854eb282c81b1c55c8c8ed
+
+
+ Prijevoz
+ d76be66cd8c74163aa32d78cdf1a8f43
+ EXPENSE
+
+ ISO4217
+ HRK
+
+ 100
+ Javni prijevoz
+ 235ba33cbfbb45b18a14ef690c65a8f0
+
+
+ Imovina
+ 8238aeea37da4e83b2e6ebda9a154fed
+ ASSET
+
+ ISO4217
+ HRK
+
+ 100
+ Imovina
+
+
+ color
+ #1469EB
+
+
+ placeholder
+ true
+
+
+ 5341c3d89c4a4163ba2cd13a0f521033
+
+
+ Trenutačna imovina
+ 2f65659c8f0a40d5bfacdbc6e97385b2
+ ASSET
+
+ ISO4217
+ HRK
+
+ 100
+ Trenutačna imovina
+
+
+ placeholder
+ true
+
+
+ 8238aeea37da4e83b2e6ebda9a154fed
+
+
+ Žiro račun
+ dbc38ec576cb4698be83e2d3b9a069de
+ BANK
+
+ ISO4217
+ HRK
+
+ 100
+ Žiro račun
+ 2f65659c8f0a40d5bfacdbc6e97385b2
+
+
+ Štedni račun
+ 9c2956c914c24b479c516aa51abc45f3
+ BANK
+
+ ISO4217
+ HRK
+
+ 100
+ Štedni račun
+ 2f65659c8f0a40d5bfacdbc6e97385b2
+
+
+ Gotovina
+ 16d490a3ee704af6b561ae27a5c94b08
+ CASH
+
+ ISO4217
+ HRK
+
+ 100
+ Gotovina
+ 2f65659c8f0a40d5bfacdbc6e97385b2
+
+
+ Tekući račun
+ 870388eb4aeb44aab610dfdfb64e5923
+ BANK
+
+ ISO4217
+ HRK
+
+ 100
+ Tekući račun
+ 2f65659c8f0a40d5bfacdbc6e97385b2
+
+
+ Obveze
+ d06b88ced55b447ca3855c5f45c2ce61
+ LIABILITY
+
+ ISO4217
+ HRK
+
+ 100
+ Obveze
+
+
+ color
+ #B304AD
+
+
+ placeholder
+ true
+
+
+ 5341c3d89c4a4163ba2cd13a0f521033
+
+
+ Kreditna kartica
+ 5bd303fbe2e34d94abd6875f14585779
+ CREDIT
+
+ ISO4217
+ HRK
+
+ 100
+ Kreditna kartica
+ d06b88ced55b447ca3855c5f45c2ce61
+
+
+ Krediti
+ ed98b81a714e45278dc67dfdd4af2feb
+ LIABILITY
+
+ ISO4217
+ HRK
+
+ 100
+ Krediti/zajmovi
+
+
+ placeholder
+ true
+
+
+ d06b88ced55b447ca3855c5f45c2ce61
+
+
+ Kredit
+ 72cc954449654b15885e64c8acf5d580
+ LIABILITY
+
+ ISO4217
+ HRK
+
+ 100
+ Kredit
+ ed98b81a714e45278dc67dfdd4af2feb
+
+
+ Prihod
+ d7d12700fe634492a94167d2027b6b20
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Prihod
+
+
+ color
+ #1B4F15
+
+
+ placeholder
+ true
+
+
+ 5341c3d89c4a4163ba2cd13a0f521033
+
+
+ Dohodak
+ 8c785ba89f1e42518bd7305abd0a49ca
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Dohodak
+
+
+ placeholder
+ true
+
+
+ d7d12700fe634492a94167d2027b6b20
+
+
+ Osobni dohodak
+ d6afbd8f3f10454e93a0f19012fe62d8
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Osobni dohodak
+ 8c785ba89f1e42518bd7305abd0a49ca
+
+
+ Dodaci
+ e9b8d2ff282647ce8a28a54d59d067e1
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Dodaci, bonusi, dnevnica i sl.
+ 8c785ba89f1e42518bd7305abd0a49ca
+
+
+ Ostalo
+ 443ecfc3f1f04e59af9858403790dfcb
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Ostali prihodi
+ d7d12700fe634492a94167d2027b6b20
+
+
+ Kamate
+ fa2021c3387f49fdad88a82368c4c14b
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Prihod od kamata
+
+
+ placeholder
+ true
+
+
+ d7d12700fe634492a94167d2027b6b20
+
+
+ Kamate po žiro računu
+ be1b142eefef4ec3978fae9294287148
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Kamate po žiro računu
+ fa2021c3387f49fdad88a82368c4c14b
+
+
+ Kamate po štednom računu
+ 33d293b2094c4d688614c00ad4921060
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Kamate po štednom računu
+ fa2021c3387f49fdad88a82368c4c14b
+
+
+ Kamate po tekućem računu
+ 2027ae3a6f62439a994c98ac58a71d84
+ INCOME
+
+ ISO4217
+ HRK
+
+ 100
+ Kamate po tekućem računu
+ fa2021c3387f49fdad88a82368c4c14b
+
+
+ Kapital
+ 3892e7fc9d6d41e8b1d03f152f6b782f
+ EQUITY
+
+ ISO4217
+ HRK
+
+ 100
+ Kapital
+
+
+ color
+ #EE8600
+
+
+ placeholder
+ true
+
+
+ 5341c3d89c4a4163ba2cd13a0f521033
+
+
+ Početni saldo
+ 944896a235b64f18966397d346300c01
+ EQUITY
+
+ ISO4217
+ HRK
+
+ 100
+ Početni saldo
+ 3892e7fc9d6d41e8b1d03f152f6b782f
+
+
+
diff --git a/app/src/main/res/raw/iso_4217_currencies.xml b/app/src/main/res/raw/iso_4217_currencies.xml
index 27a93a61b..f128c063a 100644
--- a/app/src/main/res/raw/iso_4217_currencies.xml
+++ b/app/src/main/res/raw/iso_4217_currencies.xml
@@ -35,7 +35,7 @@
Sort order by ISO codes for simpler maintainance
- File source: https://github.com/Gnucash/gnucash/blob/master/src/engine/iso-4217-currencies.xml
+ File source: https://github.com/Gnucash/gnucash/blob/master/libgnucash/engine/iso-4217-currencies.xml
-->
@@ -1774,7 +1774,7 @@
exchange-code="480"
parts-per-unit="100"
smallest-fraction="100"
- local-symbol="R"
+ local-symbol="₨"
/>
@@ -2161,7 +2161,7 @@
exchange-code="643"
parts-per-unit="100"
smallest-fraction="100"
- local-symbol="руб"
+ local-symbol="₽"
/>
@@ -2981,7 +2981,7 @@
exchange-code="nil"
parts-per-unit="1000000"
smallest-fraction="1000000"
- local-symbol="XBT"
+ local-symbol="₿"
/>
@@ -3037,4 +3037,19 @@
smallest-fraction="1000000"
local-symbol=""
/>
+
+
diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml
index f593b1675..7ccf20003 100644
--- a/app/src/main/res/values-ar-rSA/strings.xml
+++ b/app/src/main/res/values-ar-rSA/strings.xml
@@ -16,58 +16,58 @@
limitations under the License.
-->
- إنشاء حساب
- تعديل الحساب
- إضافة حركة جديدة لحساب
- عرض تفاصيل الحساب
- لا توجد حسابات للعرض
- اسم الحساب
- إلغاء
- حفظ
- اختبار
- أدخل رمز المرور
- رمز المرور خطأ؛ من فضلك حاول مُجددًا
- إعداد رمز المرور
- الرجاء تأكيد كلمة المرور الخاصة بك
- تأكيد رمز المرور غير صحيح. الرجاء المحاولة مرة أخرى
- الوصف
- المبلغ
- معاملة جديدة
- لا معاملات لعرض
- الخصم
- الائتمان
- الحسابات
- المعاملات
- حذف
- حذف
- إلغاء
- تم حذف الحساب
- تأكيد الحذف
- تحرير المعاملات
- إضافة ملاحظة
- %1$d محدد
- الرصيد:
- التصدير إلى:
- تصدير المعاملات
- بشكل افتراضي، سيتم تصدير المعاملات الجديدة فقط منذ آخر تصدير. حدد هذا الخيار لتصدير جميع المعاملات
- خطأ في تصدير ملف %1$s
- تصدير
- حذف الحركات بعد التصدير
- سيتم حذف كافة المعاملات المصدرة عند اكتمال التصدير
- إعدادات
+ Create Account
+ Edit Account
+ Add a new transaction to an account
+ View account details
+ No accounts to display
+ Account name
+ Cancel
+ Save
+ Test
+ Enter Passcode
+ Wrong passcode, please try again
+ Passcode set
+ Please confirm your passcode
+ Invalid passcode confirmation. Please try again
+ Description
+ Amount
+ New transaction
+ No transactions to display
+ DEBIT
+ CREDIT
+ Accounts
+ Transactions
+ Delete
+ Delete
+ Cancel
+ Account deleted
+ Confirm delete
+ Edit Transaction
+ Add note
+ %1$d selected
+ Balance:
+ Export To:
+ Export Transactions
+ By default, only new transactions since last export will be exported. Check this option to export all transactions
+ Error exporting %1$s file
+ Export
+ Delete transactions after export
+ All exported transactions will be deleted when exporting is completed
+ Settings
- حفظ باسم…
+ Save As…DropboxownCloud
- إرسال إلى…
+ Send to…
- نقل
- نقل %1$d معاملات
+ Move
+ Move %1$d transaction(s)Destination AccountCannot move transactions.\nThe destination account uses a different currency from origin account
- عام
- حول
- اختار عملة إفتراضية
+ General
+ About
+ Choose default currencyDefault currencyDefault currency to assign to new accountsEnables recording transactions in GnuCash for Android
@@ -124,9 +124,9 @@
- Multiple bug fixes and improvements\n
Dismiss
- أدخل مبلغ لحفظ الحركة
- حدث خطأ أثناء استيراد حسابات GnuCash
- تم إستيراد حسابات GnuCash بنجاح
+ Enter an amount to save the transaction
+ An error occurred while importing the GnuCash accounts
+ GnuCash Accounts successfully importedImport account structure exported from GnuCash desktopImport GnuCash XMLDelete all accounts in the database. All transactions will be deleted as
diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml
index cf674c732..49f40617d 100644
--- a/app/src/main/res/values-el-rGR/strings.xml
+++ b/app/src/main/res/values-el-rGR/strings.xml
@@ -206,10 +206,10 @@
MemoSpendReceive
- Ανάληψη
- Κατάθεση
- Πληρωμή
- Χρέωση
+ Withdrawal
+ Deposit
+ Payment
+ ChargeDecreaseIncreaseIncome
@@ -217,8 +217,8 @@
ExpenseBillInvoice
- Αγορά
- Πώληση
+ Buy
+ SellΑρχικά υπόλοιπαΚαθαρή ΘέσηEnable to save the current account balance (before deleting transactions) as new opening balance after deleting transactions
@@ -228,14 +228,14 @@
Generates separate QIF files per currencyImbalance:Add split
- Αγαπημένο
+ FavoriteNavigation drawer openedNavigation drawer closed
- Αναφορές
+ ReportsPie ChartLine ChartBar Chart
- Προτιμήσεις αναφοράς
+ Report PreferencesAccount color in reportsUse account color in the bar/pie chartOrder by size
diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml
index a6dddb325..1d8d70660 100644
--- a/app/src/main/res/values-es-rMX/strings.xml
+++ b/app/src/main/res/values-es-rMX/strings.xml
@@ -52,7 +52,7 @@
Por defecto solo las nuevas transacciones desde la última exportación serán exportadas. Seleccione esta opción para exportar todas las transaccionesError exportando datos %1$sExportar
- Borrar transacciones después de exportar
+ Borrar transacciones despues de exportarTodas las transacciones exportadas serán borradas cuando la exportación haya terminadoAjustes
@@ -226,7 +226,7 @@
Mostrar leyendaMostrar etiquetasMostrar porcentaje
- Mostrar líneas de media
+ Mostar lineas de mediaAgrupar porciones pequeñasDatos del gráfico no disponiblesTotal
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index e83540caf..994bd4661 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -38,7 +38,7 @@
ABONOCuentasTransacciones
- Borrar
+ BORRARBorrarCancelarCuenta borrada
@@ -226,7 +226,7 @@
Mostrar leyendaMostrar etiquetasMostrar porcentaje
- Mostrar líneas de media
+ Mostar lineas de mediaAgrupar porciones pequeñasDatos del gráfico no disponiblesTotal
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 9ab498501..b63ecc5d3 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -186,7 +186,7 @@
Un nouveau livre sera ouvert avec les comptes courants par défaut\n\n Vos comptes et opérations actuels ne seront pas modifiés !Transactions planifiéesSelectionnez une destination pour l\'export
- Memo
+ Memo (Cliquez pour ajouter)DépenserRecevoirRetrait
@@ -446,4 +446,10 @@
Sélectionnez la destination une fois l\'exportation terminéeExporter dans le dossier \'/Apps/GnuCash Android/\' sur DropboxPréférences
+ Préférences d\'ergonomie
+ Selectionner un Compte
+ Utiliser les couleurs dans les listes de Comptes
+ Utiliser les couleurs dans les listes de Comptes et les listes de Transactions
+ Afficher le Clavier lors de l\'ouverture d\'une liste de Compte avec champ de Recherche
+ Afficher le Clavier dans les listes de Compte avec champ de Recherche
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
new file mode 100644
index 000000000..3e7ff0211
--- /dev/null
+++ b/app/src/main/res/values-hr/strings.xml
@@ -0,0 +1,501 @@
+
+
+
+
+ Stvori konto
+ Uredi konto
+ Dodaj novu transakciju jednom kontu
+ Prikaži detalje konta
+ Nema konta
+ Ime konta
+ Odustani
+ Spremi
+ Ispitaj
+ Unesi lozinku
+ Kriva lozinka, pokušaj ponovo
+ Lozinka je postavljena
+ Potvrdi lozinku
+ Nevaljana potvrda lozinke. Pokušaj ponovo
+ Opis
+ Iznos
+ Nova transakcija
+ Nema transakcija
+ DUGUJE
+ POTRAŽUJE
+ Konti
+ Transakcije
+ Izbriši
+ Izbriši
+ Odustani
+ Konto je izbrisan
+ Potvrdi brisanje
+ Uredi transakciju
+ Dodaj napomenu
+ Odabrano: %1$d
+ Saldo:
+ Izvezi u:
+ Izvezi transakcije
+ Standardno se izvoze samo nove transakcije, učinjene nakon zadnjeg izvoza. Uključi ovu opciju za izvoz svih transakcija
+ Greška prilikom izvoza datoteke %1$s
+ Izvezi
+ Izbriši transakcije nakon izvoza
+ Sve izvezene transakcije će biti izbrisane nakon završetka izvoza
+ Postavke
+
+ Spremi pod …
+ Dropbox
+ ownCloud
+ Pošalji na …
+
+ Premjesti
+ Premjesti %1$d transakcije(a)
+ Odredišni konto
+ Prijenos transakcije nije moguć.\nOdredišni konto koristi drugačiju valutu od izvornog konta
+ Općenito
+ O programu
+ Odaberi standardnu valutu
+ Standardna valuta
+ Standardna valuta za nova konta
+ Omogućava spremanje transakcija u GnuCash za Android
+ Omogućava stvaranje konta u GnuCashu za Android
+ Tvoji GnuCash podaci
+ Čitaj i promijeni GnuCash podatke
+ Spremi transakcije u GnuCashu
+ Stvori transakcije u GnuCashu
+ Prikaži konto
+ Sakrij saldo konta u alatnom bloku
+ Stvori konta
+ U GnuCashu nema konta.\nStvori konto prije dodavanja alatnog bloka
+ Licenca
+ Apache License v2.0. Za detalje, klikni
+ Opće postavke
+ Odaberi konto
+ Nema transakcija za izvoz
+ Postavke za lozinku
+ Aktiviraj lozinku
+ Promijeni lozinku
+ O programu GnuCash
+ GnuCash Android %1$s izvoz
+ GnuCash Android izvoz iz
+ Transakcije
+ Postavke za transakcije
+ Postavke za konta
+ Standardna vrsta transakcije
+ Standardno korištena vrsta transakcije, POTRAŽUJE ili DUGUJE
+
+ POTRAŽUJE
+ DUGUJE
+
+ Zaista želiš izbrisati SVE transakcije?
+ Zaista želiš izbrisati ovu transakciju?
+ Izvoz
+ Izvezi sve transakcije
+ Izbriši izvezene transakcije
+ Standardna e-pošta za izvoz
+ Standardna adresa e-pošte, na koju se šalju datoteke izvoza. Adresu možeš promijeniti i prilikom izvoza.
+ Sve transakcije će se prenijeti s jednog konta na drugi konto
+ Aktiviraj dvojno knjigovodstvo
+ Saldo
+ Za stvaranje konta, unesi ime konta
+ Valuta
+ Matični konto
+ Koristi XML OFX zaglavlje
+ Aktiviraj ovu opciju za izvoz u neki drugi program, koji nije desktop verzija GnuCasha
+ Što je novo
+ - Podržava format za CSV-izvoz \n
+ - Poboljšana kompatibilnost s datotekama desktop verzije GnuCasha\n
+ - Ograničavanje slobodnog mjesta za sigurnosne kopije \n
+ - Razne ispravke grešaka i poboljšanja\n
+ Odbaci
+ Za spremanje transakcije, unesi iznos
+ Došlo je do greške prilikom uvoza GnuCash konta
+ GnuCash konti su uspješno uvezeni
+ Uvezi kontni plan iz GnuCash XML-a
+ Uvezi GnuCash XML
+ Izbriši sva konta iz baze podataka. Istovremeno se brišu sve transakcije.
+
+
+ Izbriši sva konta
+ Konti
+ Svi konti su uspješno izbrisani
+ Zaista želiš izbrisati sva konta i sve transakcije?\n\n
+ Ovo je nepovratna operacija!
+
+ Izbrisat će se sve transakcije svih konta!
+ Izbriši sve transakcije
+ Sve transakcije su uspješno izbrisane!
+ Uvoz konta
+ Transakcije
+ Podkonta
+ Traži
+ Standardni format za izvoz
+ Format koji će se standardno koristiti za izvoz transakcija
+ Ponavljanje
+
+ Debalans
+ Izvoz transakcija
+ Nema ponavljajućih transakcija.
+ Ponavljajuće transakcije su uspješno izbrisane
+ Rezervirani konto
+ Standardni konto za prijenos
+
+ %d podkonto
+ %d podkonta
+ %d podkonta
+
+
+ GOTOVINA
+ BANKA
+ KREDITNA KARTICA
+ IMOVINA
+ OBVEZE
+ PRIHOD
+ RASHOD
+ DUGOVANJA
+ POTRAŽIVANJA
+ KAPITAL
+ VALUTA
+ DIONICE
+ INVESTICIJSKI FOND
+ TRGOVANJE
+
+
+ CSV
+ QIF
+ OFX
+ XML
+
+
+ Odaberi boju
+
+
+ Boja i vrsta konta
+ Izbriši podkonta
+ Nedavna
+ Favoriti
+ Sva
+ Stvara standardnu, u GnuCashu često korištenu strukturu konta
+ Stvori standardna konta
+ Otvorit će se nova knjiga sa standardnim kontima\n\nTvoji postojeći konti i transakcije se neće dirati!
+ Transakcije
+ Odaberi odredište za izvoz
+ Zabilješka
+ Izdatak
+ Primitak
+ Isplata
+ Uplata
+ Plaćanje
+ Terećenje
+ Smanjenje
+ Povećanje
+ Prihod
+ Popust
+ Rashod
+ Ulazni račun
+ izlazni račun
+ Kupovina
+ Prodaja
+ Početni saldo
+ Kapital
+ Aktiviraj, kako bi se trenutačni saldo konta preuzeo kao novi početni saldo nakon brisanja transakcija
+
+ Spremi početni saldo konta
+ OFX ne pordžava dvojno knjigovodstvo
+ Za svaku valutu stvara pojedinačnu QIF datoteku
+ Debalans:
+ Dodaj podjelu
+ Favorit
+ Navigacijska traka je otvorena
+ Navigacijska traka je zatvorena
+ Izvještaji
+ Kružni dijagram
+ Linijski dijagram
+ Stupčani dijagram
+ Postavke za izvještaje
+ Boja konta u izvještajima
+ Koristi boje konta u stupčanom/kružnom dijagramu
+ Razvrstaj prema veličini
+ Prikaži legendu
+ Prikaži oznake
+ Prikaži postotke
+ Prikaži linije prosjeka
+ Grupiraj manje odsječke
+ Nema podataka za izradu dijagrama
+ Ukupno
+ Ostali
+ Postotak za odabranu vrijednost u odnosu na ukupni iznos
+ Postotak za odabranu vrijednost u odnosu na iznos trenutačnog složenog stupca
+ Spremi kao predložak
+ Ovaj konto sadržava transakcije. \nŠto želiš uraditi s tim transakcijama?
+ Ovaj konto sadržava podkonta. \nŠto želiš uraditi s tim podkontima?
+ Izbriši transakcije
+ Za spremanje transakcije, stvori i odredi konto za prijenos ILI deaktiviraj dvojno knjigovodstvo u postavkama
+ Stvori termine
+ Učitaj sigurnosnu kopiju …
+ Stvori sigurnosnu kopiju i izvezi
+ Aktiviraj DropBox
+ Aktiviraj ownCloud
+ Sigurnosna kopija
+ Aktiviraj izvoz u DropBox
+ Aktiviraj izvoz u ownCloud
+ Postavke za sigurnosnu kopiju
+ Stvori sigurnosnu kopiju
+ Stvori sigurnosnu kopiju aktivne knjige
+ Učitaj najnoviju sigurnosnu kopiju aktivne knjige
+ Sigurnosna kopija je uspješno stvorena
+ Sigurnosna kopija nije stvorena
+ Izvozi sva konta i sve transakcije
+ Instaliraj upravitelja datotekama za odabir datoteka
+ Odaberi sigurnosnu kopiju, koju želiš ponovo učitati
+ Favoriti
+ Otvori …
+ Izvještaji
+ Izvezi …
+ Postavke
+ Korisničko ime
+ Lozinka
+ owncloud
+ https://
+ OC server nije nađen
+ OC korisničko ime/lozinka ne valja
+ Nevaljani slovni znakovi: \\ < > : \" | * ?
+ OC server je u redu
+ OC korisničko ime/lozinka je u redu
+ Dir ime je u redu
+
+ Svaki sat
+ Svaka %d sata
+ Svakih %d sati
+
+
+ Dnevno
+ Svaka %d dana
+ Svakih %d dana
+
+
+ Tjedno
+ Svaka %d tjedna
+ Svakih %d tjedana
+
+
+ Mjesečno
+ Svaka %d mjeseca
+ Svakih %d mjeseci
+
+
+ Godišnje
+ Svake %d godine
+ Svakih %d godina
+
+ Aktiviraj dnevnik urušavanja programa
+ Automatski šalji informacije o aplikacijskim greškama razvijateljima.
+ Format
+ Unesi staru lozinku
+ Unesi novu lozinku
+ Izvozi
+ Nema terminiranih izvoza
+ Stvori terminirane izvoze
+ Izvezeno u: %1$s
+ Legenda je pre dugačka
+ Opis konta
+ Nema nedavno korištenih konta
+ Nema favoriziranih konta
+ Terminirane radnje
+ "Završeno. Zadnje izvođenje %1$s"
+ Sljedeće
+ Gotovo
+ Standardna valuta
+ Postavke konta
+ Odaberi valutu
+ Opcije za feedback
+ Stvori standardna konta
+ Uvezi moja konta
+ Dozvoli da ja to obavim
+ Ostalo …
+ Automatski pošalji izvještaj o urušavanju programa
+ Deaktiviraj izvještavanje o urušavanju programa
+ Natrag
+ Postavi GnuCash
+ Dobro došla, dobro došao u GnuCash
+ Prije nego što kreneš s radom, \nnajprije namjesti par stvari\n\nZa nastavak, pritisni Sljedeće
+ Uređivač podjela
+ Prije spremanja, provjeri da sve stavke podjele imaju valjani iznos!
+ Nevaljani izraz!
+ Terminirana ponavljajuća transakcija
+ Prenesi sredstva
+
+ Za prikaz detalja, odaberi jedan odsječak
+ Razdoblje:
+ Iz:
+ U:
+ Za prijenos sredstava, zadaj konvertiranu vrijednost ili tečaj
+ Tečaj
+ Dohvati tečaj
+ Konvertirani iznos
+ Bilanca
+ Rashod zadnjih tri mjeseca
+ Ukupno imovina
+ Ukupno obveze
+ Neto vrijednost
+ Imovina
+ Obveze
+ Kapital
+ Premjesti u:
+ Grupiraj po
+ Mjesecu
+ Kvartalu
+ Godini
+ Bilanca
+ Ukupno:
+ Google+ zajednica
+ Prevedi GnuCash
+ Izmijeni ideje, diskutiraj o promjenama ili prijavi greške
+ Prevodi ili ispravljaj prijevode na CrowdIn
+ Nema kompatibilne aplikacije za prihvaćanje izvezenih transakcija!
+ Premjesti …
+ Dupliciraj
+ Novčani tijek
+ Proračuni
+ Aktiviraj kompaktni prikaz
+ Aktiviraj stalni prikaz kompaktnog popisa transakcija
+ Nevaljani tečaj
+ npr. 1 %1$s = x.xx %2$s
+ Nevaljani iznos
+
+ Tekući mjesec
+ Zadnja 3 mjeseca
+ Zadnjih 6 mjeseci
+ Zadnjih 12 mjeseci
+ Svo vrijeme
+ Proizvoljno razdoblje …
+
+
+ 1
+
+
+ 2
+ ABC
+ 3
+ DEF
+ 4
+ GHI
+ 5
+ JKL
+ 6
+ MNO
+ 7
+ PQRS
+ 8
+ TUV
+ 9
+ WXYZ
+ 0
+ +
+ Upravljaj knjigama
+ Upravljaj knjigama …
+ Za prikaz detalja, odaberi bilo koji dio dijagrama
+ Potvrdi brisanje knjige
+ Svi konti i sve transakcije ove knjige će biti izbrisane!
+ Izbriši knjigu
+ Zadnji izvoz:
+ Aktiviraj sinkronizaciju
+ Nova knjiga
+ Odabrana transakcija nije podijeljena i ne može se otvoriti
+ Broj podjela: %1$d
+ u %1$s
+
+ %d konto
+ %d konta
+ %d konti
+
+
+ %d transakcija
+ %d transakcije
+ %d transakcija
+
+
+ RASHOD
+ PRIHOD
+
+ Spoji se s Google Drive
+ Spajanje s Google Drive nije moguće
+ Unesi iznos u podjelu
+ vanjska usluga
+ Aktualiziraj ponavljanja terminiranih transakcija
+ Od
+ Svo vrijeme
+ Preporuči na Play Store stranici
+ do %1$s
+ na %1$s
+ %1$d puta
+ Kompaktni prikaz
+ Knjiga %1$d
+ nikad
+ Preimenuj knjigu
+ Preimenuj
+ Preimenuj
+ Odaberi sigurnosnu kopiju
+ Odaberi datoteku za spremanje sigurnosne kopije
+ Potvrdi ponovo učitavanje sigurnosne kopije
+ Otvorit će se nova knjiga sa sadržajem ove sigurnosne kopije. Želiš li nastaviti?
+ Učitaj sigurnosnu kopiju
+ Nema sigurnosnih kopija
+ Ne postoje sigurnosne kopije, koje bi se mogle učitati.
+
+ gnucash_android_backup.gnca
+ Odaberi odredište nakon što izvoz završi.
+ Izvezi u Dropbox mapu pod „/Apps/GnuCash Android/„
+ Postavke
+ Da, želim
+ export_accounts_csv_key
+ Izvezi sva konta (bez transakcija) u CSV
+ Izvezi kao CSV
+ Razdvojnik
+ Izvezi transakcije kao CSV
+
+ Datum
+ ID transakcije
+ Broj
+ Opis
+ Napomene
+ Roba/Valuta
+ Razlog storniranja
+ Radnja
+ Zabilješka
+ Cjelokupno ime konta
+ Ime konta
+ Iznos s oznakom
+ Numerički iznos
+ Uskladi
+ Datum usklađivanja
+ Tečaj/cijena
+
+
+ Vrsta
+ Cjelokupno ime
+ Ime
+ Šifra
+ Opis
+ Boja
+ Napomene
+ robam
+ roban
+ Skriveno
+ Porez
+ Rezervirano mjesto
+
+
diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml
index 8f9d8d940..32e24d46f 100644
--- a/app/src/main/res/values-in-rID/strings.xml
+++ b/app/src/main/res/values-in-rID/strings.xml
@@ -20,15 +20,15 @@
Ubah AkunTambah transaksi baru ke akunLihat rincian akun
- Tak ada akun untuk ditampilkan
+ Tidak ada akun untuk ditampilkanNama akunBatalSimpan
- Uji coba
- Masukkan sandi
- Sandi salah, silakan coba lagi
- Sandi dibuat
- Harap konfirmasi sandi Anda
+ Tes
+ Masukkan Kode akses
+ Kode akses salah, silakan coba lagi
+ Kode akses dibuat
+ Harap konfirmasi kode akses AndaKonfirmasi kode akses tidak valid. Silakan cobalagiDeskripsiJumlah
@@ -183,7 +183,7 @@
SemuaBuat struktur akun yang paling sering digunakan di GnuCash secara defaultBuat akun default
- Sebuah buku baru akan dibuka dengan akun default\n\nakun dan transaksi Anda saat ini tidak akan diubah!
+ A new book will be opened with the default accounts\n\nYour current accounts and transactions will not be modified!TransaksiPilih tujuan untuk eksporMemo
@@ -209,13 +209,10 @@
OFX tidak mendukung transaksi double-entryMenghasilkan file QIF terpisah per mata uangTidak seimbang:
- Tambahkan split
-
+ Add splitFavorit
- Laci navigasi dibuka
-
- Laci navigasi tertutup
-
+ Navigation drawer opened
+ Navigation drawer closedLaporanBagan PaiBagan Garis
@@ -250,8 +247,7 @@
Pengaturan CadanganMembuat CadanganBuat cadangan dari pembukuan yang aktif
- Pulihkan cadangan terbaru buku aktif
-
+ Restore most recent backup of active bookPencadangan berhasilPencadangan gagalEkspor seluruh akun dan transaksi
@@ -267,15 +263,13 @@
owncloudhttps://Server OC tidak ditemukan
- Username / kata kunci OC tidak valid
-
+ OC username/password invalidKarakter tidak valid: \\ < > : \" | * ? Server OC OK
- OC username / password OK
-
+ OC username/password OKNama Dir OK
- Per jam
+ Every %d hoursSetiap %d hari
@@ -319,11 +313,9 @@
KembaliPengaturan GnuCashSelamat datang di GnuCash
- Sebelum Anda menyelam, \nlmari kita siapkan beberapa hal yang pertama \n\n Untuk melanjutkan, tekan Next
- Editor split
-
- Periksa apakah semua split memiliki jumlah yang valid sebelum menyimpannya!
- !
+ Before you dive in, \nlet\'s setup a few things first\n\nTo continue, press Next
+ Split Editor
+ Check that all splits have valid amounts before saving!Ekspresi yang tidak valid!Transaksi berulang yang dijadwalkanTransfer Dana
@@ -332,53 +324,46 @@
Periode:Dari:Ke:
- Berikan nilai tukar atau nilai tukar yang dikonversi untuk mentransfer dana
-
- Kurs
-
- Ambil kutipan
-
- Jumlah yang Dikonversi
-
- Lembar
-
- Biaya untuk 3 bulan terakhir
-
- Total aset
- Jumlah kewajiban
- Kekayaan Bersih
- Aset
- Kewajiban
- Ekuitas
- Pindah ke:
- Kelompok dengan
- Bulan
- Kuartal
- Tahun
- Neraca keuangan
-
- Jumlah:
- Komunitas Google+
- Menerjemahkan GnuCash
- Berbagi ide-ide, mendiskusikan perubahan atau melaporkan masalah
- Menerjemahkan atau bukti dibaca pada CrowdIn
- Tidak ada aplikasi yang kompatibel untuk menerima transaksi diekspor!
- Bergerak…
- Duplikat
- Arus Tunai
- Anggaran
- Mengaktifkan tampilan kompak
- Memungkinkan untuk selalu menggunakan tampilan kompak untuk daftar transaksi
- Edit nilai tukar
- misalnya 1 %1$s = x.xx %2$s
- Nominal tidak sah
+ Provide either the converted amount or exchange rate in order to transfer funds
+ Exchange rate
+ Fetch quote
+ Converted Amount
+ Sheet
+ Expenses for last 3 months
+ Total Assets
+ Total Liabilities
+ Net Worth
+ Assets
+ Liabilities
+ Equity
+ Move to:
+ Group By
+ Month
+ Quarter
+ Year
+ Balance Sheet
+ Total:
+ Google+ Community
+ Translate GnuCash
+ Share ideas, discuss changes or report problems
+ Translate or proof-read on CrowdIn
+ No compatible apps to receive the exported transactions!
+ Move…
+ Duplicate
+ Cash Flow
+ Budgets
+ Enable compact view
+ Enable to always use compact view for transactions list
+ Invalid exchange rate
+ e.g. 1 %1$s = x.xx %2$s
+ Invalid amount
- Bulan berjalan
- 3 bulan terakhir
- 6 bulan terakhir
- 12 bulan terakhir
- Sepanjang waktu
- Rentang ubahsuai…
+ Current month
+ Last 3 months
+ Last 6 months
+ Last 12 months
+ All time
+ Custom range…1
@@ -402,61 +387,55 @@
WXYZ0+
- Mengelola buku
- Mengelola buku…
- Memilih bagian dari tabel untuk melihat rincian
- Konfirmasi penghapusan
- Semua account dan transaksi dalam buku ini akan dihapus!
- Menghapus buku
- Terakhir Diekspor Di:
- Mengaktifkan sinkronisasi
- Buku baru
- Transaksi dipilih telah ada perpecahan dan tidak dapat dibuka
- perpecahan %1$d
- di %1$s
+ Manage Books
+ Manage Books…
+ Select any part of the chart to view details
+ Confirm delete Book
+ All accounts and transactions in this book will be deleted!
+ Delete Book
+ Last Exported:
+ Enable Sync
+ New Book
+ The selected transaction has no splits and cannot be opened
+ %1$d splits
+ in %1$s
- %d sub-akun
+ %d accounts
- transaksi%d
+ %d transactions
- PENGELUARAN
- PENDAPATAN
+ EXPENSE
+ INCOME
- Hubungakan ke Google play
- Tidak dapat tersambung ke server
- Masukkan jumlah
- layanan Eksternal
- Diperbarui transaksi berkala jadwal
- Sejak
- Sepanjang waktu
- Merekomendasikan di Play Store
- sampai %1$s
- di %1$s
- untuk %1$d kali
- Tampilan Sederhana
- Buku %1$d
- tdk pernah
- Mengubah nama buku
- Ubah Nama
- Ubah Nama
- Pilih file backup
- Pilih file untuk backup otomatis
-
- Yakin memulihkan dari backup
- Sebuah buku baru akan dibuka dengan isi backup ini. Apakah Anda ingin melanjutkan?
- ?
- Mengembalikan
- Backup tidak ditemukan
- Tidak ada file cadangan yang ada untuk dipulihkan
-
+ Connected to Google Drive
+ Unable to connect to Google Drive
+ Please enter an amount to split
+ external service
+ Updated transaction recurring schedule
+ Since
+ All time
+ Recommend in Play Store
+ until %1$s
+ on %1$s
+ for %1$d times
+ Compact View
+ Book %1$d
+ never
+ Rename Book
+ Rename
+ Rename
+ Select backup file
+ Select a file for automatic backups
+ Confirm restore from backup
+ A new book will be opened with the contents of this backup. Do you wish to proceed?
+ Restore
+ No backups found
+ There are no existing backup files to restore from
- gnucash_android_backup.gnca
-
- Pilih tujuan setelah ekspor selesai
-
- Ekspor ke folder \'/ Apps / GnuCash Android /\' di Dropbox
-
- Preferensi
+ gnucash_android_backup.gnca
+ Select the destination after export is complete
+ Export to \'/Apps/GnuCash Android/\' folder on Dropbox
+ Preferences
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 37681f758..2f3bfca4f 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -138,7 +138,7 @@
Todas as transações apagadas com sucesso!Importando contasTransações
- Subcontas
+ Sub-ContasProcurarFormato de Exportação padrãoFormato de arquivo a ser usado por padrão ao exportar transações
@@ -151,8 +151,8 @@
Conta não editávelConta para transferências padrão
- %d subconta
- %d subconta
+ %d sub-conta
+ %d sub-contasDINHEIRO
@@ -180,9 +180,9 @@
Cor de conta & Tipo
- Apagar subcontas
+ Apagar sub-contasRecentes
- Favoritas
+ FavoritosTodasCria uma estrutura de contas GnuCash padrãoCria contas padrão
@@ -222,8 +222,8 @@
Gráfico de LinhasGráfico de BarrasPreferências de relatórios
- Cor da conta nos relatórios
- Use cor da conta no gráfico de barras/linhas
+ Côr da conta nos relatórios
+ Use côr da conta no gráfico de barras/linhasOrdenar por tamanhoAlterna visibilidade da legendaAlterna visibilidade das etiquetas
@@ -428,7 +428,7 @@ Neste processo não serão recolhidas informações do utilizador!Agenda recorrente de transação atualizadaDesdeDesde o início
- Recomendar na Play Store
+ Recomendado na Play Storeaté %1$sem %1$spor %1$d vezes
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
index eedcb017a..fed5df41b 100644
--- a/app/src/main/res/values-pt-rPT/strings.xml
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -428,7 +428,7 @@ Neste processo não serão recolhidas informações do utilizador!Transação atualizada agendamento recorrenteDesdeTodo o tempo
- Recomendar na Play Store
+ Recomendado na Play Storedesde%1$sna %1$spor %1$d vezes
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 1b625cc34..9ba4502df 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -154,7 +154,6 @@
%d дочерний счёт%d шт. дочерних счетов
- %d sub-accounts%d шт. дочерних счетов
@@ -225,7 +224,7 @@
ГрафикГистограммаНастройки отчётов
- Цвет счёта в отчётах
+ Цвет счёта в отчётыхИспользовать цвет счёта в отчётахОтсортировать по размеруПоказать легенду
@@ -278,31 +277,26 @@
Каждый часКаждые %d часа
- Every %d hoursКаждые %d часовЕжедневноКаждые %d дня
- Every %d daysКаждые %d днейЕженедельноКаждые %d недели
- Every %d weeksКаждые %d недельЕжемесячноКаждые %d месяца
- Every %d monthsКаждые %d месяцевЕжегодноКаждые %d года
- Every %d yearsКаждые %d летЗаписывать отказы программы
@@ -335,7 +329,7 @@
НазадНастройка GnuCashДобро пожаловать в GnuCash
- Прежде, чем вы начнёте,\nдавайте настроим некоторые вещи.\n\nДля продолжения нажмите «Далее».
+ Прежде, чем вы начныте,\nдавайте настроим некоторые вещи.\n\nДля продолжения нажмите «Далее».Редактор разбиенияПроверьте, что все части корректно распределены перед сохранением!Неверное выражение!
@@ -347,7 +341,7 @@
С:До:Заполните или обменянную сумму или курс обмена
- Курс обмена
+ EКурс обменаПолучить котировкиОбмененная суммаСводка
@@ -424,13 +418,11 @@
%d счета%d счета
- %d accounts%d счетов%d транзакция%d транзакции
- %d transactions%d транзакций
@@ -457,7 +449,7 @@
Выберите файл резервной копииВыберите файл для автоматического резервного копированияПодтвердите восстановление из резервной копии
- Новая книга будет открыта с содержанием этой резервной копии. Хотите продолжить?
+ Новая книга будет открыта с содержанием этой резервной копии. Вы хотите продолжить?ВосстановитьРезервные копии не найденыНет существующих файлов резервных копий для восстановления
diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml
index 71645393c..be8308fd5 100644
--- a/app/src/main/res/values-sv-rSE/strings.xml
+++ b/app/src/main/res/values-sv-rSE/strings.xml
@@ -20,7 +20,7 @@
Redigera kontoLägg till en transaktion till ett kontoVisa kontodetaljer
- Inga konton att visa
+ Det finns inga konton att visaKontonamnAvbrytSpara
@@ -33,7 +33,7 @@
BeskrivningBeloppLägg till transaktion
- Inga transaktioner att visa
+ Det finns inga transaktioner att visaDEBITKREDITKonton
@@ -79,7 +79,7 @@
Visa kontoDölja kontosaldo i widgetSkapa konton
- Inga konton finns i GnuCash.\nSkapa ett konto innan du lägger till en gränssnittskomponent
+ Inga konton finns i GnuCash.\nSkapa ett konto innan du lägger till en widgetLicensApache License v2.0. Klicka för DetaljerAllmänna inställningar
@@ -293,7 +293,7 @@
Ange din gamla lösenkodAnge din nya lösenkodExporter
- Inga schemalagda exporter att visa
+ Ingen schemalagda exporter att VisaSkapa exportschemaExporterades till: %1$sFörklaringen är för lång
@@ -391,8 +391,8 @@
WXYZ0+
- Hantera bokföringar
- Hantera bokföringar…
+ Hantera böcker
+ Hantera böcker…Välj någon del av diagrammet för att visa detaljerBekräfta radera bokföringAlla konton och transaktioner i denna bokföring kommer att raderas!
@@ -400,7 +400,7 @@
Senast exporterad:Aktivera synkroniseringNy bokföring
- Valda transaktionen har inga delningar och kan inte öppnas
+ Valda transaktionen har ingen delningar och kan inte öppnas%1$d delari %1$s
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 8b502ea05..70dd0e16b 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -18,9 +18,9 @@
新增科目編輯科目
- 在科目中新增交易
+ 给科目添加交易檢視帳戶詳細資訊
- 沒有科目可顯示
+ 没有要显示的科目科目名稱取消存檔
@@ -59,7 +59,7 @@
另存為…DropboxownCloud
- 傳送到…
+ Send to…移動移動 %1$d 交易
@@ -78,7 +78,7 @@
建立會計科目顯示科目名字小工具中隱藏帳戶餘額
- 建立科目
+ 创建科目GnuCash裡還没有會計科目信息。\n使用小部件前需要添加會計科目授權許可Apache License v2.0,點擊查看詳细(將打開網頁)。
@@ -125,7 +125,7 @@
知道了輸入金額才能保存交易
- 匯入GnuCash科目時發生錯誤。
+ 匯入GnuCash科目时發生錯誤。GnuCash科目資料匯入完成。匯入從GnuCash桌面版匯出的科目設置匯入GnuCash科目
@@ -177,7 +177,7 @@
XML
- 選擇顏色
+ 选择一种颜色科目顏色和類型
@@ -187,7 +187,8 @@
所有建立通用的科目結構建立預設科目
- 這將用預設科目來建立新的帳簿\n\n目前擁有的科目與交易不會受影響
+ 将会创建新的账簿附带默认的科目
+现在这个账簿不会受到影响交易選擇儲存的位置描述
@@ -196,7 +197,7 @@
提款存款付款
- 費用
+ 费用減少增加收入
@@ -220,10 +221,10 @@
報表圓形圖折線圖
- 長條圖
+ 橫條圖報表設置用不同顏色区分科目
- 在圓餅圖中使用科目的顏色
+ 在饼图中使用科目的颜色按數量排序顯示圖例顯示標籤
@@ -266,20 +267,20 @@
密碼ownCloudhttps://
- 沒有找到 ownCloud 伺服器
+ 伺服器找不到。帳號/密碼無效無效字元: \\ < > : \" | * ? OC server OKOC username/password OKDir name OK
- 每 %d 個小時
+ Every %d hours每 %d 天
- 每 %d 週
+ 每 %d 周每 %d 月
@@ -311,13 +312,13 @@ No user-identifiable information will be collected as part of this process!
選擇幣種回饋選項建立預設科目
- 匯入科目
+ 汇入科目稍后处理其他...自動發送故障報告禁用崩潰報告後退
- 設定GnuCash
+ 设置GnuCash歡迎來到GnuCash在使用之前,需 \n要设置几个参数\n\n请点击“下一步”繼續拆分交易
@@ -343,7 +344,7 @@ No user-identifiable information will be collected as part of this process!
負債財產淨值移動至
- 分組方式
+ 分组方式月季度年
@@ -352,13 +353,13 @@ No user-identifiable information will be collected as part of this process!
Google+ 社群翻譯GnuCash在Google+上提交问题和建议
- 在CrowdIn上協助翻譯或校對GnuCash
+ 帮忙翻譯或校對( CrowdIn)没有合适的应用接收汇出的文档移動...複製現金流預算
- 啟用緊湊視圖
+ 啟用紧凑視圖交易清單總是啟用緊湊視圖匯率不正確例如 1 %1$s = x.xx %2$s
@@ -393,23 +394,23 @@ No user-identifiable information will be collected as part of this process!
WXYZ0+
- 管理帳簿
- 管理帳簿…
+ 管理帐簿
+ 管理帐簿選擇該圖表以查看詳細資訊的任何部分確認删除
- 帳簿中所有科目和交易都將被刪除 !
- 删除帳簿
+ 帐簿中所有科目和交易都將被刪除 !
+ 删除帐簿最後匯出︰啟用同步新建帐簿选择的交易没有拆分%1$d 项分割
- 於 %1$s
+ 于 %1$s
- %d 個科目
+ %d个科目
- %d 個交易
+ %d个交易費用
@@ -419,29 +420,29 @@ No user-identifiable information will be collected as part of this process!
無法連線到伺服器請輸入要拆分的金額外部服務
- 排程交易已經更新
+ 排程交易已经更新自從全部時間在 Play Store 推薦直到%1$s在%1$s
- %1$d 次
- 緊湊視圖
- 帳簿 %1$d
- 從未
- 重新命名帳簿
- 重新命名
- 重新命名
- 選擇備份檔
- 選擇自動備份時用的檔案
- 確認恢復備份
- 將以這個備份的內容新建一本帳簿。確定要繼續?
- 恢復
- 沒有找到備份
- 沒有能恢復的備份
+ for %1$d times
+ 紧凑视图
+ 账簿 %1$d
+ never
+ Rename Book
+ Rename
+ Rename
+ Select backup file
+ Select a file for automatic backups
+ Confirm restore from backup
+ A new book will be opened with the contents of this backup. Do you wish to proceed?
+ Restore
+ No backups found
+ There are no existing backup files to restore from
- gnucash_android_備份.gnca
- 匯出後再選擇目的地
- 匯出到 Dropbox 上的 \'/Apps/GnuCash Android/\' 資料夾
- 偏好設定
+ gnucash_android_backup.gnca
+ Select the destination after export is complete
+ Export to \'/Apps/GnuCash Android/\' folder on Dropbox
+ Preferences
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 958872756..04364df24 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -19,4 +19,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml
index 39cae7266..7400588d6 100644
--- a/app/src/main/res/values/donottranslate.xml
+++ b/app/src/main/res/values/donottranslate.xml
@@ -31,6 +31,8 @@
google_drive_app_folderenable_crashlyticsuse_account_color
+ key_use_color_in_account_list
+ key_shall_open_keyboard_in_account_searchable_spinnerlast_export_destinationuse_compact_listprefs_header_general
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4ef7ae17e..98fa0c783 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -196,7 +196,7 @@
A new book will be opened with the default accounts\n\nYour current accounts and transactions will not be modified!TransactionsSelect destination for export
- Memo
+ Memo (Click to add)SpendReceiveWithdrawal
@@ -500,4 +500,14 @@
TaxPlaceholder
+ Select Account
+
+ User Interface Preferences
+
+ Use colors in Account Lists
+ Use colors in Account Lists and in Transaction Lists
+
+ Show keyboard in Searchable Account List
+ Show keyboard when opening a Searchable Account List
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index a67c2f893..b513d86be 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -16,9 +16,34 @@
-->
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 81e3aecf4..86ceb1925 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -17,7 +17,9 @@
-->
+