Skip to content

Commit

Permalink
Merge branch 'hotfix/patches'
Browse files Browse the repository at this point in the history
  • Loading branch information
codinguser committed Oct 18, 2016
2 parents 66b3d0c + 5642de8 commit d1c3103
Show file tree
Hide file tree
Showing 20 changed files with 345 additions and 122 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
Change Log
===============================================================================
Version 2.1.3 *(2016-10-20)*
----------------------------
* Fixed: Scheduled exports execute too often or not at all in some cases
* Fixed: Crash if device is rotated during first-run wizard execution
* Fixed: Negative values displayed as green on homescreen widget
* Improved: Homescreen widget now allows to select the book to use
* Improved: Update Russian translation

Version 2.1.2 *(2016-09-21)*
----------------------------
* Fixed: Scheduled exports always run daily (no matter the actual schedule)
Expand Down
6 changes: 6 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,11 @@ The following (incomplete list of) people (in no particular order) contributed (
* Terry Chung <terrywmc@gmail.com>
* Caesar Wirth <cjwirth@gmail.com>
* Alceu Rodrigues Neto <alceurneto@gmail.com>
* Carlo Zancanaro <carlo@zancanaro.id.au>
* Eric Daly <edaly@hpsnet.com>
* Weslly Oliveira <weslly99@hotmail.com>
* Felipe Morato <me@fmorato.com>
* Alceu Rodrigues Neto <alceurneto@gmail.com>
* Salama AB <aksalj@aksalj.me>

Please visit https://crowdin.com/project/gnucash-android for a more complete list of translation contributions
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ apply plugin: 'io.fabric'

def versionMajor = 2
def versionMinor = 1
def versionPatch = 2
def versionBuild = 0
def versionPatch = 3
def versionBuild = 1

def buildTime() {
def df = new SimpleDateFormat("yyyyMMdd HH:mm 'UTC'")
Expand Down
18 changes: 13 additions & 5 deletions app/src/main/java/org/gnucash/android/app/GnuCashApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public void onCreate(){
BookDbHelper bookDbHelper = new BookDbHelper(getApplicationContext());
mBooksDbAdapter = new BooksDbAdapter(bookDbHelper.getWritableDatabase());

initDatabaseAdapters();
initializeDatabaseAdapters();
setDefaultCurrencyCode(getDefaultCurrencyCode());

if (BuildConfig.DEBUG && !isRoboUnitTest())
Expand All @@ -137,7 +137,7 @@ public void onCreate(){
* Initialize database adapter singletons for use in the application
* This method should be called every time a new book is opened
*/
private static void initDatabaseAdapters() {
private static void initializeDatabaseAdapters() {
if (mDbHelper != null){ //close if open
mDbHelper.getReadableDatabase().close();
}
Expand Down Expand Up @@ -205,15 +205,23 @@ public static BooksDbAdapter getBooksDbAdapter(){
}

/**
* Loads the book with GUID {@code bookUID}
* Loads the book with GUID {@code bookUID} and opens the AccountsActivity
* @param bookUID GUID of the book to be loaded
*/
public static void loadBook(@NonNull String bookUID){
mBooksDbAdapter.setActive(bookUID);
initDatabaseAdapters();
activateBook(bookUID);
AccountsActivity.start(getAppContext());
}

/**
* Activates the book with unique identifer {@code bookUID}, and refreshes the database adapters
* @param bookUID GUID of the book to be activated
*/
public static void activateBook(@NonNull String bookUID){
mBooksDbAdapter.setActive(bookUID);
initializeDatabaseAdapters();
}

/**
* Returns the currently active database in the application
* @return Currently active {@link SQLiteDatabase}
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/org/gnucash/android/db/BookDbHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ public void onCreate(SQLiteDatabase db) {

}

/**
* Returns the database for the book
* @param bookUID GUID of the book
* @return SQLiteDatabase of the book
*/
public static SQLiteDatabase getDatabase(String bookUID){
DatabaseHelper dbHelper = new DatabaseHelper(GnuCashApplication.getAppContext(), bookUID);
return dbHelper.getWritableDatabase();
}

/**
* Inserts the book into the database
* @param db Book database
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import org.gnucash.android.ui.settings.PreferenceActivity;
import org.gnucash.android.util.TimestampHelper;

import java.util.List;

/**
* Database adapter for creating/modifying book entries
*/
Expand Down
55 changes: 42 additions & 13 deletions app/src/main/java/org/gnucash/android/model/ScheduledAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,35 +173,64 @@ public long getTimeOfLastSchedule(){
}

/**
* Computes the next time that this scheduled action is supposed to be executed
* Computes the next time that this scheduled action is supposed to be
* executed based on the execution count.
*
* <p>This method does not consider the end time, or number of times it should be run.
* It only considers when the next execution would theoretically be due</p>
* It only considers when the next execution would theoretically be due.</p>
*
* @return Next run time in milliseconds
*/
public long computeNextScheduledExecutionTime(){
int multiplier = mRecurrence.getPeriodType().getMultiplier();
//this is the last planned time for the action to occur, not the last run time
long lastActionTime = getTimeOfLastSchedule(); //mStartDate + ((mExecutionCount-1)*getPeriod());
if (lastActionTime < 0){
public long computeNextCountBasedScheduledExecutionTime(){
return computeNextScheduledExecutionTimeStartingAt(getTimeOfLastSchedule());
}

/**
* Computes the next time that this scheduled action is supposed to be
* executed based on the time of the last run.
*
* <p>This method does not consider the end time, or number of times it should be run.
* It only considers when the next execution would theoretically be due.</p>
*
* @return Next run time in milliseconds
*/
public long computeNextTimeBasedScheduledExecutionTime() {
return computeNextScheduledExecutionTimeStartingAt(getLastRunTime());
}

/**
* Computes the next time that this scheduled action is supposed to be
* executed starting at startTime.
*
* <p>This method does not consider the end time, or number of times it should be run.
* It only considers when the next execution would theoretically be due.</p>
*
* @param startTime time in milliseconds to use as start to compute the next schedule.
*
* @return Next run time in milliseconds
*/
private long computeNextScheduledExecutionTimeStartingAt(long startTime) {
if (startTime <= 0){ // has never been run
return mStartDate;
}

LocalDateTime localDate = LocalDateTime.fromDateFields(new Date(lastActionTime));
int multiplier = mRecurrence.getPeriodType().getMultiplier();
LocalDateTime nextScheduledExecution = LocalDateTime.fromDateFields(new Date(startTime));
switch (mRecurrence.getPeriodType()) {
case DAY:
localDate = localDate.plusDays(multiplier);
nextScheduledExecution = nextScheduledExecution.plusDays(multiplier);
break;
case WEEK:
localDate = localDate.plusWeeks(multiplier);
nextScheduledExecution = nextScheduledExecution.plusWeeks(multiplier);
break;
case MONTH:
localDate = localDate.plusMonths(multiplier);
nextScheduledExecution = nextScheduledExecution.plusMonths(multiplier);
break;
case YEAR:
localDate = localDate.plusYears(multiplier);
nextScheduledExecution = nextScheduledExecution.plusYears(multiplier);
break;
}
return localDate.toDate().getTime();
return nextScheduledExecution.toDate().getTime();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;

import org.gnucash.android.db.adapter.BooksDbAdapter;
import org.gnucash.android.model.Book;
import org.gnucash.android.ui.common.UxArgument;
import org.gnucash.android.ui.homescreen.WidgetConfigurationActivity;
import org.gnucash.android.ui.settings.PreferenceActivity;

/**
* {@link AppWidgetProvider} which is responsible for managing widgets on the homescreen
Expand All @@ -43,13 +46,13 @@ public void onUpdate(Context context, AppWidgetManager appWidgetManager,
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];

String accountUID = PreferenceManager
.getDefaultSharedPreferences(context)
String accountUID = PreferenceActivity.getActiveBookSharedPreferences()
.getString(UxArgument.SELECTED_ACCOUNT_UID + appWidgetId, null);
if (accountUID == null)
return;

WidgetConfigurationActivity.updateWidget(context, appWidgetId, accountUID);
WidgetConfigurationActivity.updateWidget(context, appWidgetId, accountUID,
BooksDbAdapter.getInstance().getActiveBookUID());
}
}

Expand All @@ -62,11 +65,11 @@ public void onEnabled(Context context) {
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
Editor editor = PreferenceActivity.getActiveBookSharedPreferences().edit();

for (int appWidgetId : appWidgetIds) {
editor.remove(UxArgument.SELECTED_ACCOUNT_UID + appWidgetId);
}
editor.commit();
editor.apply();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,17 @@ private static void executeScheduledEvent(ScheduledAction scheduledAction, SQLit
//the last run time is computed instead of just using "now" so that if the more than
// one period has been skipped, all intermediate transactions can be created

scheduledAction.setLastRun(System.currentTimeMillis());
//set the execution count in the object because it will be checked for the next iteration in the calling loop
scheduledAction.setExecutionCount(executionCount); //this call is important, do not remove!!
//update the last run time and execution count
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseSchema.ScheduledActionEntry.COLUMN_LAST_RUN, System.currentTimeMillis());
contentValues.put(DatabaseSchema.ScheduledActionEntry.COLUMN_EXECUTION_COUNT, executionCount);
contentValues.put(DatabaseSchema.ScheduledActionEntry.COLUMN_LAST_RUN,
scheduledAction.getLastRunTime());
contentValues.put(DatabaseSchema.ScheduledActionEntry.COLUMN_EXECUTION_COUNT,
scheduledAction.getExecutionCount());
db.update(DatabaseSchema.ScheduledActionEntry.TABLE_NAME, contentValues,
DatabaseSchema.ScheduledActionEntry.COLUMN_UID + "=?", new String[]{scheduledAction.getUID()});

//set the execution count in the object because it will be checked for the next iteration in the calling loop
scheduledAction.setExecutionCount(executionCount); //this call is important, do not remove!!
}

/**
Expand All @@ -161,26 +163,31 @@ private static void executeScheduledEvent(ScheduledAction scheduledAction, SQLit
* @return Number of times backup is executed. This should either be 1 or 0
*/
private static int executeBackup(ScheduledAction scheduledAction, SQLiteDatabase db) {
int executionCount = 0;
long now = System.currentTimeMillis();
long endTime = scheduledAction.getEndTime();

if (endTime > 0 && endTime < now)
return executionCount;

if (scheduledAction.computeNextScheduledExecutionTime() > now)
if (!shouldExecuteScheduledBackup(scheduledAction))
return 0;

ExportParams params = ExportParams.parseCsv(scheduledAction.getTag());
try {
//wait for async task to finish before we proceed (we are holding a wake lock)
new ExportAsyncTask(GnuCashApplication.getAppContext(), db).execute(params).get();
scheduledAction.setExecutionCount(++executionCount);
} catch (InterruptedException | ExecutionException e) {
Crashlytics.logException(e);
Log.e(LOG_TAG, e.getMessage());
}
return executionCount;
return 1;
}

private static boolean shouldExecuteScheduledBackup(ScheduledAction scheduledAction) {
long now = System.currentTimeMillis();
long endTime = scheduledAction.getEndTime();

if (endTime > 0 && endTime < now)
return false;

if (scheduledAction.computeNextTimeBasedScheduledExecutionTime() > now)
return false;

return true;
}

/**
Expand Down Expand Up @@ -214,7 +221,7 @@ private static int executeTransactions(ScheduledAction scheduledAction, SQLiteDa

//we may be executing scheduled action significantly after scheduled time (depending on when Android fires the alarm)
//so compute the actual transaction time from pre-known values
long transactionTime = scheduledAction.computeNextScheduledExecutionTime();
long transactionTime = scheduledAction.computeNextCountBasedScheduledExecutionTime();
while (transactionTime <= endTime) {
Transaction recurringTrxn = new Transaction(trxnTemplate, true);
recurringTrxn.setTime(transactionTime);
Expand All @@ -224,7 +231,7 @@ private static int executeTransactions(ScheduledAction scheduledAction, SQLiteDa

if (totalPlannedExecutions > 0 && executionCount >= totalPlannedExecutions)
break; //if we hit the total planned executions set, then abort
transactionTime = scheduledAction.computeNextScheduledExecutionTime();
transactionTime = scheduledAction.computeNextCountBasedScheduledExecutionTime();
}

transactionsDbAdapter.bulkAddRecords(transactions, DatabaseAdapter.UpdateMethod.insert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentView());

//if a parameter was passed to open an account within a specific book, then switch
String bookUID = getIntent().getStringExtra(UxArgument.BOOK_UID);
if (bookUID != null && !bookUID.equals(BooksDbAdapter.getInstance().getActiveBookUID())){
GnuCashApplication.activateBook(bookUID);
}

ButterKnife.bind(this);
setSupportActionBar(mToolbar);
final ActionBar actionBar = getSupportActionBar();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.gnucash.android.R;
import org.gnucash.android.app.GnuCashApplication;
import org.gnucash.android.db.adapter.AccountsDbAdapter;
import org.gnucash.android.db.adapter.BooksDbAdapter;
import org.gnucash.android.ui.account.AccountFormFragment;
import org.gnucash.android.ui.budget.BudgetAmountEditorFragment;
import org.gnucash.android.ui.budget.BudgetFormFragment;
Expand Down Expand Up @@ -57,6 +58,12 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_form);

//if a parameter was passed to open an account within a specific book, then switch
String bookUID = getIntent().getStringExtra(UxArgument.BOOK_UID);
if (bookUID != null && !bookUID.equals(BooksDbAdapter.getInstance().getActiveBookUID())){
GnuCashApplication.activateBook(bookUID);
}

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ public final class UxArgument {
*/
public static final String BUDGET_AMOUNT_LIST = "budget_amount_list";

/**
* GUID of a book which is relevant for a specific action
*/
public static final String BOOK_UID = "book_uid";

//prevent initialization of instances of this class
private UxArgument(){
//prevent even the native class from calling the ctor
Expand Down
Loading

0 comments on commit d1c3103

Please sign in to comment.