diff --git a/app/res/menu/detail_menu.xml b/app/res/menu/detail_menu.xml
index f2c73e473..6295a80f8 100644
--- a/app/res/menu/detail_menu.xml
+++ b/app/res/menu/detail_menu.xml
@@ -32,8 +32,8 @@
android:orderInCategory="100"
android:title="@string/Delete_activity"/>
diff --git a/app/src/org/runnerup/db/ActivityMerger.java b/app/src/org/runnerup/db/ActivityMerger.java
new file mode 100644
index 000000000..f206a7956
--- /dev/null
+++ b/app/src/org/runnerup/db/ActivityMerger.java
@@ -0,0 +1,125 @@
+package org.runnerup.db;
+
+/*
+ * Copyright (C) 2013 jonas.oreland@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import android.content.ContentValues;
+import android.database.sqlite.SQLiteDatabase;
+
+import org.runnerup.common.util.Constants;
+
+
+public class ActivityMerger implements Constants {
+ public static boolean canMerge(SQLiteDatabase db, long activityId) {
+ // previous activity must exist and be the same activity type
+ // there is a deleted flag in the DB, but it doesn't seem to be used?
+ // I deleted a previous activity (id = 50) and I successfully get the
+ // (undeleted) previous activity (id = 49)...
+ try {
+ long previousActivityId = previousActivityId(db, activityId);
+ long type = activityType(db, activityId);
+ long previousType = activityType(db, previousActivityId);
+ return type == previousType;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public static void merge(SQLiteDatabase db, long activityId) {
+ long previousActivityId = previousActivityId(db, activityId);
+
+ // update the 3 activity tables - LOCATION, LAP and ACTIVITY
+ // through this operation we re-order the new laps based on the older laps
+ // and move everything to the current activity ID
+ updateLocation(db, activityId, previousActivityId);
+ updateLap(db, activityId, previousActivityId);
+ updateActivity(db, activityId, previousActivityId);
+
+ // cleanup
+ new ActivityCleaner().recompute(db, activityId);
+ DBHelper.deleteActivity(db, previousActivityId);
+ }
+
+ private static void updateActivity(SQLiteDatabase db, long activityId, long previousActivityId) {
+ // update current activity start time with older activity start time
+ db.execSQL("UPDATE " + DB.ACTIVITY.TABLE + " SET " + DB.ACTIVITY.START_TIME + " = " + startTime(db, previousActivityId) +
+ " WHERE _id = " + activityId);
+ }
+
+ private static void updateLap(SQLiteDatabase db, long activityId, long previousActivityId) {
+ // # VERIFY THAT time IS UPDATED BY recompute IF NECESSARY
+
+ // newer activity lap numbers should continue where previousActivity laps stopped
+ // lap: old min = 0, new min = 0, old max = x, new max = y
+ long nextLap = lapMinMax(db, DB.LAP.TABLE, "MAX", previousActivityId) + 1;
+ // has this code already run? if so, don't re-run it.
+ if (lapMinMax(db, DB.LAP.TABLE, "MIN", activityId) == 0 && nextLap !=0)
+ db.execSQL("UPDATE " + DB.LAP.TABLE + " SET " + DB.LAP.LAP + "=" + DB.LAP.LAP + "+" + nextLap +
+ " WHERE " + DB.LAP.ACTIVITY + "=" + activityId);
+
+ // assign all older laps to the current activity
+ db.execSQL("UPDATE " + DB.LAP.TABLE + " SET " + DB.LAP.ACTIVITY + " = " + activityId +
+ " WHERE " + DB.LAP.ACTIVITY + " = " + previousActivityId);
+ }
+
+ private static void updateLocation(SQLiteDatabase db, long activityId, long previousActivityId) {
+ // location: set middle start/end type to pause/resume
+ ContentValues values = new ContentValues();
+ values.put(DB.LOCATION.TYPE, DB.LOCATION.TYPE_PAUSE);
+ db.update(DB.LOCATION.TABLE, values, DB.LOCATION.TYPE + "=" + DB.LOCATION.TYPE_END + " AND " + DB.LOCATION.ACTIVITY + "=" + previousActivityId, null);
+ values = new ContentValues();
+ values.put(DB.LOCATION.TYPE, DB.LOCATION.TYPE_RESUME);
+ db.update(DB.LOCATION.TABLE, values, DB.LOCATION.TYPE + "=" + DB.LOCATION.TYPE_START + " AND " + DB.LOCATION.ACTIVITY + "=" + activityId, null);
+
+ // location: newer lap numbers should continue where previousActivity laps stopped
+ long nextLap = lapMinMax(db, DB.LOCATION.TABLE, "MAX", previousActivityId) + 1;
+ // has this code already run? if so, don't re-run it.
+ if (lapMinMax(db, DB.LOCATION.TABLE, "MIN", activityId) == 0 && nextLap !=0)
+ db.execSQL("UPDATE " + DB.LOCATION.TABLE + " SET " + DB.LOCATION.LAP + "=" + DB.LOCATION.LAP + "+" + nextLap +
+ " WHERE " + DB.LOCATION.ACTIVITY + "=" + activityId);
+
+ // location: assign newer activityId to older locations
+ values = new ContentValues();
+ values.put(DB.LOCATION.ACTIVITY, activityId);
+ db.update(DB.LOCATION.TABLE, values, DB.LOCATION.ACTIVITY + "=" + previousActivityId, null);
+ }
+
+ private static long activityType(SQLiteDatabase db, long activityId) {
+ return db.compileStatement("SELECT type FROM " + DB.ACTIVITY.TABLE +
+ " WHERE _id = " + activityId).simpleQueryForLong();
+ }
+
+ private static long previousActivityId(SQLiteDatabase db, long activityId) {
+ return db.compileStatement("SELECT MAX(_id) FROM " + DB.ACTIVITY.TABLE +
+ " WHERE _id < " + activityId).simpleQueryForLong();
+ }
+
+ private static long startTime(SQLiteDatabase db, long activityId) {
+ return db.compileStatement("SELECT " + DB.ACTIVITY.START_TIME + " FROM " + DB.ACTIVITY.TABLE +
+ " WHERE _id = " + activityId).simpleQueryForLong();
+ }
+
+ private static long lapMinMax(SQLiteDatabase db, String table, String minMax, long activityId) {
+ try {
+ return db.compileStatement("SELECT " + minMax + "(" + DB.LAP.LAP + ") FROM " + table +
+ " WHERE " + DB.LAP.ACTIVITY + "=" + activityId).simpleQueryForLong();
+ } catch (Exception e) {
+ // no laps, return -1
+ return -1;
+ }
+ }
+}
diff --git a/app/src/org/runnerup/view/DetailActivity.java b/app/src/org/runnerup/view/DetailActivity.java
index 73f2e9c9b..87145f1e8 100644
--- a/app/src/org/runnerup/view/DetailActivity.java
+++ b/app/src/org/runnerup/view/DetailActivity.java
@@ -72,8 +72,8 @@
import org.runnerup.content.ActivityProvider;
import org.runnerup.content.WorkoutFileProvider;
import org.runnerup.db.ActivityCleaner;
+import org.runnerup.db.ActivityMerger;
import org.runnerup.db.DBHelper;
-import org.runnerup.db.entities.ActivityEntity;
import org.runnerup.db.entities.LocationEntity;
import org.runnerup.export.SyncManager;
import org.runnerup.export.Synchronizer;
@@ -122,7 +122,7 @@ public class DetailActivity extends FragmentActivity implements Constants {
TitleSpinner sport = null;
EditText notes = null;
- MenuItem recomputeMenuItem = null;
+ MenuItem mergeMenuItem = null;
MapView map = null;
AsyncTask loadRouteTask = null;
@@ -269,15 +269,16 @@ private void setEdit(boolean value) {
uploadButton.setEnabled(value);
WidgetUtil.setEditable(notes, value);
sport.setEnabled(value);
- if (recomputeMenuItem != null)
- recomputeMenuItem.setEnabled(value);
+ if (mergeMenuItem != null) {
+ mergeMenuItem.setEnabled(value);
+ }
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (mode == MODE_DETAILS) {
getMenuInflater().inflate(R.menu.detail_menu, menu);
- recomputeMenuItem = menu.findItem(R.id.menu_recompute_activity);
+ mergeMenuItem = menu.findItem(R.id.menu_merge_activity);
}
return true;
}
@@ -295,9 +296,26 @@ public boolean onOptionsItemSelected(MenuItem item) {
requery();
}
break;
- case R.id.menu_recompute_activity:
- new ActivityCleaner().recompute(mDB, mID);
- requery();
+ case R.id.menu_merge_activity:
+ if (ActivityMerger.canMerge(mDB, mID)) {
+ ActivityMerger.merge(mDB, mID);
+ requery();
+ fillHeaderData();
+ loadRoute();
+ } else {
+ AlertDialog.Builder builder1 = new AlertDialog.Builder(this);
+ builder1.setMessage("Previous activity must be of the same type to merge.");
+ builder1.setCancelable(true);
+ builder1.setNeutralButton("OK",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert11 = builder1.create();
+ alert11.show();
+ }
break;
case R.id.menu_share_activity:
shareActivity();
diff --git a/common/src/main/res/values-de/strings.xml b/common/src/main/res/values-de/strings.xml
index e636ded44..631ee748d 100644
--- a/common/src/main/res/values-de/strings.xml
+++ b/common/src/main/res/values-de/strings.xml
@@ -127,7 +127,7 @@
Aktivität bearbeiten
Aktivität teilen
Aktivität löschen
- Aktivität neu berechnen
+ Aktivität neu berechnen
Herzfrequenzzonen konfigurieren
Herzfrequenzzoneneinstellungen zurücksetzen
Benutzerkonten verwalten
diff --git a/common/src/main/res/values-en-rNL/strings.xml b/common/src/main/res/values-en-rNL/strings.xml
index 2499bdbae..ada2af896 100644
--- a/common/src/main/res/values-en-rNL/strings.xml
+++ b/common/src/main/res/values-en-rNL/strings.xml
@@ -125,7 +125,7 @@
Activiteit bewerken
Activiteit delen
Activiteit verwijderen
- Activiteit herberekenen
+ Activiteit herberekenen
Hartslagzones instellen
Hartslagzone instellingen verwijderen
Accounts beheren
diff --git a/common/src/main/res/values-fr/strings.xml b/common/src/main/res/values-fr/strings.xml
index e211d27dc..165e40ac1 100644
--- a/common/src/main/res/values-fr/strings.xml
+++ b/common/src/main/res/values-fr/strings.xml
@@ -127,7 +127,7 @@
Éditer la séance
Partager la séance
Supprimer la séance
- Recalculer la séance
+ Recalculer la séance
Configurer les zones de fréq. cardiaque
Supprimer les paramètres de zone de fréq. cardiaque
Gérer les comptes
diff --git a/common/src/main/res/values-it/strings.xml b/common/src/main/res/values-it/strings.xml
index c9397eae8..acaf4c08e 100644
--- a/common/src/main/res/values-it/strings.xml
+++ b/common/src/main/res/values-it/strings.xml
@@ -125,7 +125,7 @@
Modifica attività
Condividi attività
Elimina attività
- Ricalcola attività
+ Ricalcola attività
Configura zone BPM
Elimina impostazioni zona BPM
Gestisci account
diff --git a/common/src/main/res/values-ja/strings.xml b/common/src/main/res/values-ja/strings.xml
index 3a9a8c0b0..4a3bfd354 100644
--- a/common/src/main/res/values-ja/strings.xml
+++ b/common/src/main/res/values-ja/strings.xml
@@ -127,7 +127,7 @@
アクティビティを編集
アクティビティを共有
アクティビティを削除
- アクティビティを再計算
+ アクティビティを再計算
心拍数ゾーンを設定
心拍数ゾーンの設定をクリア
アカウントの管理
diff --git a/common/src/main/res/values-nl-rNL/strings.xml b/common/src/main/res/values-nl-rNL/strings.xml
index fdc95dba5..abe876ecf 100644
--- a/common/src/main/res/values-nl-rNL/strings.xml
+++ b/common/src/main/res/values-nl-rNL/strings.xml
@@ -126,7 +126,7 @@
Activiteit bewerken
Activiteit delen
Activiteit verwijderen
- Activiteit herberekenen
+ Activiteit herberekenen
Hartslagzones instellen
Hartslagzone instellingen verwijderen
Accounts beheren
diff --git a/common/src/main/res/values-nl/strings.xml b/common/src/main/res/values-nl/strings.xml
index ce310e1fd..bceefe7da 100644
--- a/common/src/main/res/values-nl/strings.xml
+++ b/common/src/main/res/values-nl/strings.xml
@@ -124,7 +124,7 @@
Activiteit bewerken
Activiteit delen
Activiteit verwijderen
- Activiteit herberekenen
+ Activiteit herberekenen
Hartslagzones instellen
Hartslagzone instellingen verwijderen
Accounts beheren
diff --git a/common/src/main/res/values-pl/strings.xml b/common/src/main/res/values-pl/strings.xml
index 407478b76..c61207f5c 100644
--- a/common/src/main/res/values-pl/strings.xml
+++ b/common/src/main/res/values-pl/strings.xml
@@ -125,7 +125,7 @@
Edytuj aktywność
Udostępnij aktywność
Usuń aktywność
- Przelicz aktywność
+ Przelicz aktywność
Ustaw strefy tętna
Wyczyść ustawienia stref tętna
Zarządzaj kontami
diff --git a/common/src/main/res/values-pt-rBR/strings.xml b/common/src/main/res/values-pt-rBR/strings.xml
index 780852c27..1d97b9e6e 100644
--- a/common/src/main/res/values-pt-rBR/strings.xml
+++ b/common/src/main/res/values-pt-rBR/strings.xml
@@ -127,7 +127,7 @@
Editar atividade
Compartilhar atividade
Excluir atividade
- Recalcular atividade
+ Recalcular atividade
Configurar zonas de frequência cardíaca
Apagar configurações da zona de frequência cardíaca
Gerenciar contas
diff --git a/common/src/main/res/values-ru/strings.xml b/common/src/main/res/values-ru/strings.xml
index 283d4a998..d9622d16b 100644
--- a/common/src/main/res/values-ru/strings.xml
+++ b/common/src/main/res/values-ru/strings.xml
@@ -126,7 +126,7 @@
Редактировать
Опубликовать
Удалить
- Пересчитать
+ Пересчитать
Настройка зон ЧСС
Очистить зоны ЧСС
Управление аккаунтами
diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml
index be70929f7..75730f4b4 100644
--- a/common/src/main/res/values/strings.xml
+++ b/common/src/main/res/values/strings.xml
@@ -127,7 +127,7 @@
Edit activity
Share activity
Delete activity
- Recompute activity
+ Merge activity
Configure heart rate zones
Clear heart rate zone settings
Manage accounts