mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
First version of sync feature
This commit is contained in:
@@ -39,6 +39,7 @@ dependencies {
|
|||||||
compile 'com.github.paolorotolo:appintro:3.4.0'
|
compile 'com.github.paolorotolo:appintro:3.4.0'
|
||||||
compile 'org.apmem.tools:layouts:1.10@aar'
|
compile 'org.apmem.tools:layouts:1.10@aar'
|
||||||
compile 'com.opencsv:opencsv:3.7'
|
compile 'com.opencsv:opencsv:3.7'
|
||||||
|
compile 'com.github.nkzawa:socket.io-client:0.3.0'
|
||||||
compile project(':libs:drag-sort-listview:library')
|
compile project(':libs:drag-sort-listview:library')
|
||||||
compile files('libs/ActiveAndroid.jar')
|
compile files('libs/ActiveAndroid.jar')
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="HabitsApplication"
|
android:name="HabitsApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|||||||
@@ -20,30 +20,37 @@
|
|||||||
package org.isoron.uhabits;
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
import android.app.backup.BackupManager;
|
import android.app.backup.BackupManager;
|
||||||
|
import android.appwidget.AppWidgetManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.isoron.uhabits.commands.Command;
|
import org.isoron.uhabits.commands.Command;
|
||||||
import org.isoron.uhabits.helpers.ColorHelper;
|
import org.isoron.uhabits.helpers.ColorHelper;
|
||||||
import org.isoron.uhabits.helpers.UIHelper;
|
import org.isoron.uhabits.helpers.UIHelper;
|
||||||
|
import org.isoron.uhabits.models.Checkmark;
|
||||||
import java.util.LinkedList;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.tasks.BaseTask;
|
||||||
|
import org.isoron.uhabits.widgets.CheckmarkWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.FrequencyWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.HistoryWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.ScoreWidgetProvider;
|
||||||
|
import org.isoron.uhabits.widgets.StreakWidgetProvider;
|
||||||
|
|
||||||
abstract public class BaseActivity extends AppCompatActivity implements Thread.UncaughtExceptionHandler
|
abstract public class BaseActivity extends AppCompatActivity implements Thread.UncaughtExceptionHandler
|
||||||
{
|
{
|
||||||
private static int MAX_UNDO_LEVEL = 15;
|
|
||||||
|
|
||||||
private LinkedList<Command> undoList;
|
|
||||||
private LinkedList<Command> redoList;
|
|
||||||
private Toast toast;
|
private Toast toast;
|
||||||
|
private SyncManager sync;
|
||||||
|
|
||||||
Thread.UncaughtExceptionHandler androidExceptionHandler;
|
Thread.UncaughtExceptionHandler androidExceptionHandler;
|
||||||
|
|
||||||
@@ -57,38 +64,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
|
|||||||
androidExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
androidExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||||
Thread.setDefaultUncaughtExceptionHandler(this);
|
Thread.setDefaultUncaughtExceptionHandler(this);
|
||||||
|
|
||||||
undoList = new LinkedList<>();
|
sync = new SyncManager(this);
|
||||||
redoList = new LinkedList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void executeCommand(Command command, Long refreshKey)
|
|
||||||
{
|
|
||||||
executeCommand(command, false, refreshKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void undo()
|
|
||||||
{
|
|
||||||
if (undoList.isEmpty())
|
|
||||||
{
|
|
||||||
showToast(R.string.toast_nothing_to_undo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Command last = undoList.pop();
|
|
||||||
redoList.push(last);
|
|
||||||
last.undo();
|
|
||||||
showToast(last.getUndoStringId());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void redo()
|
|
||||||
{
|
|
||||||
if (redoList.isEmpty())
|
|
||||||
{
|
|
||||||
showToast(R.string.toast_nothing_to_redo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Command last = redoList.pop();
|
|
||||||
executeCommand(last, false, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showToast(Integer stringId)
|
public void showToast(Integer stringId)
|
||||||
@@ -99,27 +75,29 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
|
|||||||
toast.show();
|
toast.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void executeCommand(final Command command, Boolean clearRedoStack, final Long refreshKey)
|
public void executeCommand(final Command command, final Long refreshKey)
|
||||||
{
|
{
|
||||||
undoList.push(command);
|
executeCommand(command, refreshKey, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (undoList.size() > MAX_UNDO_LEVEL) undoList.removeLast();
|
public void executeCommand(final Command command, final Long refreshKey,
|
||||||
if (clearRedoStack) redoList.clear();
|
final boolean shouldBroadcast)
|
||||||
|
{
|
||||||
new AsyncTask<Void, Void, Void>()
|
new BaseTask()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params)
|
protected void doInBackground()
|
||||||
{
|
{
|
||||||
|
Log.d("BaseActivity", "Executing command");
|
||||||
command.execute();
|
command.execute();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void aVoid)
|
protected void onPostExecute(Void aVoid)
|
||||||
{
|
{
|
||||||
BaseActivity.this.onPostExecuteCommand(refreshKey);
|
BaseActivity.this.onPostExecuteCommand(command, refreshKey);
|
||||||
BackupManager.dataChanged("org.isoron.uhabits");
|
BackupManager.dataChanged("org.isoron.uhabits");
|
||||||
|
if(shouldBroadcast) sync.postCommand(command);
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
|
||||||
@@ -127,6 +105,19 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
|
|||||||
showToast(command.getExecuteStringId());
|
showToast(command.getExecuteStringId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onPostExecuteCommand(Command command, Long refreshKey)
|
||||||
|
{
|
||||||
|
new BaseTask()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void doInBackground()
|
||||||
|
{
|
||||||
|
dismissNotifications(BaseActivity.this);
|
||||||
|
updateWidgets(BaseActivity.this);
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
protected void setupSupportActionBar(boolean homeButtonEnabled)
|
protected void setupSupportActionBar(boolean homeButtonEnabled)
|
||||||
{
|
{
|
||||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
@@ -144,10 +135,6 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
|
|||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPostExecuteCommand(Long refreshKey)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uncaughtException(Thread thread, Throwable ex)
|
public void uncaughtException(Thread thread, Throwable ex)
|
||||||
{
|
{
|
||||||
@@ -201,4 +188,39 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
|
|||||||
view = findViewById(R.id.headerShadow);
|
view = findViewById(R.id.headerShadow);
|
||||||
if(view != null) view.setVisibility(View.GONE);
|
if(view != null) view.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy()
|
||||||
|
{
|
||||||
|
sync.close();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dismissNotifications(Context context)
|
||||||
|
{
|
||||||
|
for(Habit h : Habit.getHabitsWithReminder())
|
||||||
|
{
|
||||||
|
if(h.checkmarks.getTodayValue() != Checkmark.UNCHECKED)
|
||||||
|
HabitBroadcastReceiver.dismissNotification(context, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateWidgets(Context context)
|
||||||
|
{
|
||||||
|
updateWidgets(context, CheckmarkWidgetProvider.class);
|
||||||
|
updateWidgets(context, HistoryWidgetProvider.class);
|
||||||
|
updateWidgets(context, ScoreWidgetProvider.class);
|
||||||
|
updateWidgets(context, StreakWidgetProvider.class);
|
||||||
|
updateWidgets(context, FrequencyWidgetProvider.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateWidgets(Context context, Class providerClass)
|
||||||
|
{
|
||||||
|
ComponentName provider = new ComponentName(context, providerClass);
|
||||||
|
Intent intent = new Intent(context, providerClass);
|
||||||
|
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||||
|
int ids[] = AppWidgetManager.getInstance(context).getAppWidgetIds(provider);
|
||||||
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
|
||||||
|
context.sendBroadcast(intent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,7 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits;
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
@@ -40,18 +38,12 @@ import android.support.v7.app.ActionBar;
|
|||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.commands.Command;
|
||||||
import org.isoron.uhabits.fragments.ListHabitsFragment;
|
import org.isoron.uhabits.fragments.ListHabitsFragment;
|
||||||
import org.isoron.uhabits.helpers.DateHelper;
|
import org.isoron.uhabits.helpers.DateHelper;
|
||||||
import org.isoron.uhabits.helpers.ReminderHelper;
|
import org.isoron.uhabits.helpers.ReminderHelper;
|
||||||
import org.isoron.uhabits.helpers.UIHelper;
|
import org.isoron.uhabits.helpers.UIHelper;
|
||||||
import org.isoron.uhabits.models.Checkmark;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
import org.isoron.uhabits.tasks.BaseTask;
|
|
||||||
import org.isoron.uhabits.widgets.CheckmarkWidgetProvider;
|
|
||||||
import org.isoron.uhabits.widgets.FrequencyWidgetProvider;
|
|
||||||
import org.isoron.uhabits.widgets.HistoryWidgetProvider;
|
|
||||||
import org.isoron.uhabits.widgets.ScoreWidgetProvider;
|
|
||||||
import org.isoron.uhabits.widgets.StreakWidgetProvider;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -122,7 +114,6 @@ public class MainActivity extends BaseActivity
|
|||||||
}.execute();
|
}.execute();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showTutorial()
|
private void showTutorial()
|
||||||
{
|
{
|
||||||
Boolean firstRun = prefs.getBoolean("pref_first_run", true);
|
Boolean firstRun = prefs.getBoolean("pref_first_run", true);
|
||||||
@@ -263,47 +254,10 @@ public class MainActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostExecuteCommand(Long refreshKey)
|
public void onPostExecuteCommand(Command command, Long refreshKey)
|
||||||
{
|
{
|
||||||
listHabitsFragment.onPostExecuteCommand(refreshKey);
|
listHabitsFragment.onPostExecuteCommand(refreshKey);
|
||||||
|
super.onPostExecuteCommand(command, refreshKey);
|
||||||
new BaseTask()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected void doInBackground()
|
|
||||||
{
|
|
||||||
dismissNotifications(MainActivity.this);
|
|
||||||
updateWidgets(MainActivity.this);
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dismissNotifications(Context context)
|
|
||||||
{
|
|
||||||
for(Habit h : Habit.getHabitsWithReminder())
|
|
||||||
{
|
|
||||||
if(h.checkmarks.getTodayValue() != Checkmark.UNCHECKED)
|
|
||||||
HabitBroadcastReceiver.dismissNotification(context, h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updateWidgets(Context context)
|
|
||||||
{
|
|
||||||
updateWidgets(context, CheckmarkWidgetProvider.class);
|
|
||||||
updateWidgets(context, HistoryWidgetProvider.class);
|
|
||||||
updateWidgets(context, ScoreWidgetProvider.class);
|
|
||||||
updateWidgets(context, StreakWidgetProvider.class);
|
|
||||||
updateWidgets(context, FrequencyWidgetProvider.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void updateWidgets(Context context, Class providerClass)
|
|
||||||
{
|
|
||||||
ComponentName provider = new ComponentName(context, providerClass);
|
|
||||||
Intent intent = new Intent(context, providerClass);
|
|
||||||
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
|
||||||
int ids[] = AppWidgetManager.getInstance(context).getAppWidgetIds(provider);
|
|
||||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
|
|
||||||
context.sendBroadcast(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -331,4 +285,6 @@ public class MainActivity extends BaseActivity
|
|||||||
|
|
||||||
listHabitsFragment.showImportDialog();
|
listHabitsFragment.showImportDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
151
app/src/main/java/org/isoron/uhabits/SyncManager.java
Normal file
151
app/src/main/java/org/isoron/uhabits/SyncManager.java
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker 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.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.isoron.uhabits;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.github.nkzawa.emitter.Emitter;
|
||||||
|
import com.github.nkzawa.socketio.client.IO;
|
||||||
|
import com.github.nkzawa.socketio.client.Socket;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.commands.Command;
|
||||||
|
import org.isoron.uhabits.commands.ToggleRepetitionCommand;
|
||||||
|
import org.isoron.uhabits.helpers.DatabaseHelper;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class SyncManager
|
||||||
|
{
|
||||||
|
public static final String EXECUTE_COMMAND = "executeCommand";
|
||||||
|
public static final String POST_COMMAND = "postCommand";
|
||||||
|
public static final String SYNC_SERVER_URL = "http://10.0.2.2:4000";
|
||||||
|
|
||||||
|
private static String GROUP_KEY = "sEBY3poXHFH7EyB43V2JoQUNEtBjMgdD";
|
||||||
|
private static String CLIENT_KEY;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Socket socket;
|
||||||
|
private BaseActivity activity;
|
||||||
|
private LinkedList<Command> outbox;
|
||||||
|
|
||||||
|
public SyncManager(BaseActivity activity)
|
||||||
|
{
|
||||||
|
this.activity = activity;
|
||||||
|
outbox = new LinkedList<>();
|
||||||
|
CLIENT_KEY = DatabaseHelper.getRandomId();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket = IO.socket(SYNC_SERVER_URL);
|
||||||
|
socket.connect();
|
||||||
|
socket.on(Socket.EVENT_CONNECT, new OnConnectListener());
|
||||||
|
socket.on(EXECUTE_COMMAND, new OnExecuteCommandListener());
|
||||||
|
}
|
||||||
|
catch (URISyntaxException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postCommand(Command command)
|
||||||
|
{
|
||||||
|
JSONObject msg = command.toJSON();
|
||||||
|
if(msg != null)
|
||||||
|
{
|
||||||
|
socket.emit(POST_COMMAND, msg.toString());
|
||||||
|
outbox.add(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OnConnectListener implements Emitter.Listener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void call(Object... args)
|
||||||
|
{
|
||||||
|
JSONObject authMsg = buildAuthMessage();
|
||||||
|
socket.emit("auth", authMsg.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject buildAuthMessage()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("group_key", GROUP_KEY);
|
||||||
|
json.put("client_key", CLIENT_KEY);
|
||||||
|
json.put("version", BuildConfig.VERSION_NAME);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
catch (JSONException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OnExecuteCommandListener implements Emitter.Listener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void call(Object... args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
executeCommand(args[0]);
|
||||||
|
}
|
||||||
|
catch (JSONException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeCommand(Object arg) throws JSONException
|
||||||
|
{
|
||||||
|
Log.d("SyncManager", String.format("Received command: %s", arg.toString()));
|
||||||
|
JSONObject root = new JSONObject(arg.toString());
|
||||||
|
if(root.getString("command").equals("ToggleRepetition"))
|
||||||
|
{
|
||||||
|
Command received = ToggleRepetitionCommand.fromJSON(root);
|
||||||
|
if(received == null) throw new RuntimeException("received is null");
|
||||||
|
|
||||||
|
for(Command pending : outbox)
|
||||||
|
{
|
||||||
|
if(pending.getId().equals(received.getId()))
|
||||||
|
{
|
||||||
|
outbox.remove(pending);
|
||||||
|
Log.d("SyncManager", "Received command discarded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.executeCommand(received, null, false);
|
||||||
|
Log.d("SyncManager", "Received command executed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,25 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.commands;
|
package org.isoron.uhabits.commands;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.helpers.DatabaseHelper;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public abstract class Command
|
public abstract class Command
|
||||||
{
|
{
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
public Command()
|
||||||
|
{
|
||||||
|
id = DatabaseHelper.getRandomId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Command(String id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void execute();
|
public abstract void execute();
|
||||||
|
|
||||||
public abstract void undo();
|
public abstract void undo();
|
||||||
@@ -34,4 +51,12 @@ public abstract class Command
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public JSONObject toJSON() { return null; }
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,23 +19,35 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.commands;
|
package org.isoron.uhabits.commands;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class ToggleRepetitionCommand extends Command
|
public class ToggleRepetitionCommand extends Command
|
||||||
{
|
{
|
||||||
private Long offset;
|
private final Long timestamp;
|
||||||
private Habit habit;
|
private final Habit habit;
|
||||||
|
|
||||||
public ToggleRepetitionCommand(Habit habit, long offset)
|
public ToggleRepetitionCommand(String id, Habit habit, long timestamp)
|
||||||
{
|
{
|
||||||
this.offset = offset;
|
super(id);
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.habit = habit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ToggleRepetitionCommand(Habit habit, long timestamp)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this.timestamp = timestamp;
|
||||||
this.habit = habit;
|
this.habit = habit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute()
|
public void execute()
|
||||||
{
|
{
|
||||||
habit.repetitions.toggle(offset);
|
habit.repetitions.toggle(timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -43,4 +55,39 @@ public class ToggleRepetitionCommand extends Command
|
|||||||
{
|
{
|
||||||
execute();
|
execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public JSONObject toJSON()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JSONObject root = new JSONObject();
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
root.put("id", getId());
|
||||||
|
root.put("command", "ToggleRepetition");
|
||||||
|
data.put("habit", habit.getId());
|
||||||
|
data.put("timestamp", timestamp);
|
||||||
|
root.put("data", data);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
catch (JSONException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static Command fromJSON(JSONObject json) throws JSONException
|
||||||
|
{
|
||||||
|
String id = json.getString("id");
|
||||||
|
JSONObject data = (JSONObject) json.get("data");
|
||||||
|
Long habitId = data.getLong("habit");
|
||||||
|
Long timestamp = data.getLong("timestamp");
|
||||||
|
|
||||||
|
Habit habit = Habit.get(habitId);
|
||||||
|
if(habit == null) return null;
|
||||||
|
|
||||||
|
return new ToggleRepetitionCommand(id, habit, timestamp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,9 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class DatabaseHelper
|
public class DatabaseHelper
|
||||||
{
|
{
|
||||||
@@ -71,6 +73,11 @@ public class DatabaseHelper
|
|||||||
out.write(buffer, 0, numBytes);
|
out.write(buffer, 0, numBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getRandomId()
|
||||||
|
{
|
||||||
|
return new BigInteger(130, new Random()).toString(32);
|
||||||
|
}
|
||||||
|
|
||||||
public interface Command
|
public interface Command
|
||||||
{
|
{
|
||||||
void execute();
|
void execute();
|
||||||
|
|||||||
Reference in New Issue
Block a user