mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Update SyncManager
This commit is contained in:
@@ -25,7 +25,7 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
debug {
|
||||
testCoverageEnabled = true
|
||||
testCoverageEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.models.sqlite.*;
|
||||
import org.isoron.uhabits.notifications.*;
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.sync.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
@@ -74,6 +75,8 @@ public interface AppComponent
|
||||
|
||||
ReminderScheduler getReminderScheduler();
|
||||
|
||||
SyncManager getSyncManager();
|
||||
|
||||
TaskRunner getTaskRunner();
|
||||
|
||||
WidgetPreferences getWidgetPreferences();
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.activities.*;
|
||||
import org.isoron.uhabits.activities.habits.list.model.*;
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.sync.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
/**
|
||||
@@ -46,6 +47,8 @@ public class ListHabitsActivity extends BaseActivity
|
||||
|
||||
private MidnightTimer midnightTimer;
|
||||
|
||||
private SyncManager syncManager;
|
||||
|
||||
public ListHabitsComponent getListHabitsComponent()
|
||||
{
|
||||
return component;
|
||||
@@ -81,6 +84,7 @@ public class ListHabitsActivity extends BaseActivity
|
||||
rootView.setController(controller, selectionMenu);
|
||||
|
||||
midnightTimer = component.getMidnightTimer();
|
||||
syncManager = app.getComponent().getSyncManager();
|
||||
|
||||
setScreen(screen);
|
||||
controller.onStartup();
|
||||
@@ -89,6 +93,7 @@ public class ListHabitsActivity extends BaseActivity
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
syncManager.stopListening();
|
||||
midnightTimer.onPause();
|
||||
screen.onDettached();
|
||||
adapter.cancelRefresh();
|
||||
@@ -102,6 +107,7 @@ public class ListHabitsActivity extends BaseActivity
|
||||
screen.onAttached();
|
||||
rootView.postInvalidate();
|
||||
midnightTimer.onResume();
|
||||
syncManager.startListening();
|
||||
|
||||
if (prefs.getTheme() == ThemeSwitcher.THEME_DARK &&
|
||||
prefs.isPureBlackEnabled() != pureBlack)
|
||||
|
||||
@@ -133,6 +133,7 @@ public class ListHabitsScreen extends BaseScreen
|
||||
public void onCommandExecuted(@NonNull Command command,
|
||||
@Nullable Long refreshKey)
|
||||
{
|
||||
if(command.isRemote()) return;
|
||||
showMessage(command.getExecuteStringId());
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,13 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
Context appContext = getContext().getApplicationContext();
|
||||
if(appContext instanceof HabitsApplication)
|
||||
{
|
||||
HabitsApplication app = (HabitsApplication) appContext;
|
||||
prefs = app.getComponent().getPreferences();
|
||||
}
|
||||
|
||||
setResultOnPreferenceClick("importData", RESULT_IMPORT_DATA);
|
||||
setResultOnPreferenceClick("exportCSV", RESULT_EXPORT_CSV);
|
||||
setResultOnPreferenceClick("exportDB", RESULT_EXPORT_DB);
|
||||
@@ -68,13 +75,21 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
setResultOnPreferenceClick("bugReport", RESULT_BUG_REPORT);
|
||||
|
||||
updateRingtoneDescription();
|
||||
updateSync();
|
||||
}
|
||||
|
||||
Context appContext = getContext().getApplicationContext();
|
||||
if(appContext instanceof HabitsApplication)
|
||||
{
|
||||
HabitsApplication app = (HabitsApplication) appContext;
|
||||
prefs = app.getComponent().getPreferences();
|
||||
}
|
||||
private void updateSync()
|
||||
{
|
||||
if(prefs == null) return;
|
||||
boolean enabled = prefs.isSyncFeatureEnabled();
|
||||
|
||||
Preference syncKey = findPreference("pref_sync_key");
|
||||
syncKey.setSummary(prefs.getSyncKey());
|
||||
syncKey.setVisible(enabled);
|
||||
|
||||
Preference syncAddress = findPreference("pref_sync_address");
|
||||
syncAddress.setSummary(prefs.getSyncAddress());
|
||||
syncAddress.setVisible(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,6 +142,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
String key)
|
||||
{
|
||||
BackupManager.dataChanged("org.isoron.uhabits");
|
||||
updateSync();
|
||||
}
|
||||
|
||||
private void setResultOnPreferenceClick(String key, final int result)
|
||||
|
||||
@@ -39,14 +39,18 @@ public abstract class Command
|
||||
{
|
||||
private String id;
|
||||
|
||||
private boolean isRemote;
|
||||
|
||||
public Command()
|
||||
{
|
||||
id = DatabaseUtils.getRandomId();
|
||||
isRemote = false;
|
||||
}
|
||||
|
||||
public Command(String id)
|
||||
{
|
||||
this.id = id;
|
||||
isRemote = false;
|
||||
}
|
||||
|
||||
public abstract void execute();
|
||||
@@ -71,6 +75,16 @@ public abstract class Command
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isRemote()
|
||||
{
|
||||
return isRemote;
|
||||
}
|
||||
|
||||
public void setRemote(boolean remote)
|
||||
{
|
||||
isRemote = remote;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public JSONObject toJson()
|
||||
{
|
||||
|
||||
@@ -26,12 +26,15 @@ import com.google.gson.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.json.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
public class CommandParser
|
||||
{
|
||||
private HabitList habitList;
|
||||
|
||||
private ModelFactory modelFactory;
|
||||
|
||||
@Inject
|
||||
public CommandParser(@NonNull HabitList habitList,
|
||||
@NonNull ModelFactory modelFactory)
|
||||
{
|
||||
|
||||
@@ -95,9 +95,9 @@ public class CreateRepetitionCommand extends Command
|
||||
@NonNull
|
||||
public String event = "CreateRep";
|
||||
|
||||
public long habitId;
|
||||
public long habit;
|
||||
|
||||
public long timestamp;
|
||||
public long repTimestamp;
|
||||
|
||||
public int value;
|
||||
|
||||
@@ -107,18 +107,18 @@ public class CreateRepetitionCommand extends Command
|
||||
Long habitId = command.habit.getId();
|
||||
if(habitId == null) throw new RuntimeException("Habit not saved");
|
||||
|
||||
this.habitId = habitId;
|
||||
this.timestamp = command.timestamp;
|
||||
this.habit = habitId;
|
||||
this.repTimestamp = command.timestamp;
|
||||
this.value = command.value;
|
||||
}
|
||||
|
||||
public CreateRepetitionCommand toCommand(@NonNull HabitList habitList)
|
||||
{
|
||||
Habit h = habitList.getById(habitId);
|
||||
Habit h = habitList.getById(habit);
|
||||
if(h == null) throw new HabitNotFoundException();
|
||||
|
||||
CreateRepetitionCommand command;
|
||||
command = new CreateRepetitionCommand(h, timestamp, value);
|
||||
command = new CreateRepetitionCommand(h, repTimestamp, value);
|
||||
command.setId(id);
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -73,9 +73,9 @@ public class ToggleRepetitionCommand extends Command
|
||||
@NonNull
|
||||
public String event = "Toggle";
|
||||
|
||||
public long habitId;
|
||||
public long habit;
|
||||
|
||||
public long timestamp;
|
||||
public long repTimestamp;
|
||||
|
||||
public Record(@NonNull ToggleRepetitionCommand command)
|
||||
{
|
||||
@@ -83,17 +83,17 @@ public class ToggleRepetitionCommand extends Command
|
||||
Long habitId = command.habit.getId();
|
||||
if(habitId == null) throw new RuntimeException("Habit not saved");
|
||||
|
||||
this.timestamp = command.timestamp;
|
||||
this.habitId = habitId;
|
||||
this.repTimestamp = command.timestamp;
|
||||
this.habit = habitId;
|
||||
}
|
||||
|
||||
public ToggleRepetitionCommand toCommand(@NonNull HabitList habitList)
|
||||
{
|
||||
Habit h = habitList.getById(habitId);
|
||||
Habit h = habitList.getById(habit);
|
||||
if(h == null) throw new HabitNotFoundException();
|
||||
|
||||
ToggleRepetitionCommand command;
|
||||
command = new ToggleRepetitionCommand(h, timestamp);
|
||||
command = new ToggleRepetitionCommand(h, repTimestamp);
|
||||
command.setId(id);
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.util.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
import static android.R.attr.*;
|
||||
import static org.isoron.uhabits.models.Checkmark.*;
|
||||
|
||||
/**
|
||||
@@ -328,7 +327,7 @@ public class Habit
|
||||
|
||||
public boolean isNumerical()
|
||||
{
|
||||
return type == NUMBER_HABIT;
|
||||
return data.type == NUMBER_HABIT;
|
||||
}
|
||||
|
||||
public HabitData getData()
|
||||
|
||||
@@ -77,6 +77,26 @@ public class Preferences
|
||||
}
|
||||
}
|
||||
|
||||
public String getSyncAddress()
|
||||
{
|
||||
return prefs.getString("pref_sync_address", "https://sync.loophabits.org:4000");
|
||||
}
|
||||
|
||||
public String getSyncClientId()
|
||||
{
|
||||
String id = prefs.getString("pref_sync_client_id", "");
|
||||
if(!id.isEmpty()) return id;
|
||||
|
||||
id = UUID.randomUUID().toString();
|
||||
prefs.edit().putString("pref_sync_client_id", id).apply();
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isSyncFeatureEnabled()
|
||||
{
|
||||
return prefs.getBoolean("pref_feature_sync", false);
|
||||
}
|
||||
|
||||
public void setDefaultOrder(HabitList.Order order)
|
||||
{
|
||||
prefs.edit().putString("pref_default_order", order.name()).apply();
|
||||
@@ -117,7 +137,7 @@ public class Preferences
|
||||
|
||||
public long getLastSync()
|
||||
{
|
||||
return prefs.getLong("lastSync", 0);
|
||||
return prefs.getLong("last_sync", 0);
|
||||
}
|
||||
|
||||
public void setLastSync(long timestamp)
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.util.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.commands.*;
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.json.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -36,6 +35,7 @@ import java.security.cert.Certificate;
|
||||
import java.security.cert.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.inject.*;
|
||||
import javax.net.ssl.*;
|
||||
|
||||
import io.socket.client.*;
|
||||
@@ -44,7 +44,7 @@ import io.socket.emitter.*;
|
||||
|
||||
import static io.socket.client.Socket.*;
|
||||
|
||||
public class SyncManager
|
||||
public class SyncManager implements CommandRunner.Listener
|
||||
{
|
||||
public static final String EVENT_AUTH = "auth";
|
||||
|
||||
@@ -58,12 +58,9 @@ public class SyncManager
|
||||
|
||||
public static final String EVENT_POST_EVENT = "postEvent";
|
||||
|
||||
public static final String SYNC_SERVER_URL =
|
||||
"https://sync.loophabits.org:4000";
|
||||
private String clientId;
|
||||
|
||||
private static String CLIENT_ID;
|
||||
|
||||
private static String GROUP_KEY;
|
||||
private String groupKey;
|
||||
|
||||
@NonNull
|
||||
private Socket socket;
|
||||
@@ -84,7 +81,8 @@ public class SyncManager
|
||||
|
||||
private CommandParser commandParser;
|
||||
|
||||
public SyncManager(@NonNull Context context,
|
||||
@Inject
|
||||
public SyncManager(@AppContext @NonNull Context context,
|
||||
@NonNull Preferences prefs,
|
||||
@NonNull CommandRunner commandRunner,
|
||||
@NonNull CommandParser commandParser)
|
||||
@@ -97,15 +95,16 @@ public class SyncManager
|
||||
pendingConfirmation = new LinkedList<>();
|
||||
pendingEmit = Event.getAll();
|
||||
|
||||
GROUP_KEY = prefs.getSyncKey();
|
||||
CLIENT_ID = DatabaseUtils.getRandomId();
|
||||
groupKey = prefs.getSyncKey();
|
||||
clientId = prefs.getSyncClientId();
|
||||
String serverURL = prefs.getSyncAddress();
|
||||
|
||||
Log.d("SyncManager", CLIENT_ID);
|
||||
Log.d("SyncManager", clientId);
|
||||
|
||||
try
|
||||
{
|
||||
IO.setDefaultSSLContext(getCACertSSLContext());
|
||||
socket = IO.socket(SYNC_SERVER_URL);
|
||||
socket = IO.socket(serverURL);
|
||||
logSocketEvent(socket, EVENT_CONNECT, "Connected");
|
||||
logSocketEvent(socket, EVENT_CONNECT_TIMEOUT, "Connect timeout");
|
||||
logSocketEvent(socket, EVENT_CONNECTING, "Connecting...");
|
||||
@@ -124,8 +123,6 @@ public class SyncManager
|
||||
socket.on(EVENT_EXECUTE_EVENT, new OnExecuteCommandListener());
|
||||
socket.on(EVENT_AUTH_OK, new OnAuthOKListener());
|
||||
socket.on(EVENT_FETCH_OK, new OnFetchOKListener());
|
||||
|
||||
socket.connect();
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
@@ -133,14 +130,12 @@ public class SyncManager
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
@Override
|
||||
public void onCommandExecuted(@NonNull Command command,
|
||||
@Nullable Long refreshKey)
|
||||
{
|
||||
socket.off();
|
||||
socket.close();
|
||||
}
|
||||
if(command.isRemote()) return;
|
||||
|
||||
public void postCommand(Command command)
|
||||
{
|
||||
JSONObject msg = command.toJson();
|
||||
Long now = new Date().getTime();
|
||||
Event e = new Event(command.getId(), now, msg.toString());
|
||||
@@ -152,6 +147,21 @@ public class SyncManager
|
||||
if (readyToEmit) emitPending();
|
||||
}
|
||||
|
||||
public void startListening()
|
||||
{
|
||||
if(!prefs.isSyncFeatureEnabled()) return;
|
||||
if(groupKey.isEmpty()) return;
|
||||
|
||||
socket.connect();
|
||||
commandRunner.addListener(this);
|
||||
}
|
||||
|
||||
public void stopListening()
|
||||
{
|
||||
commandRunner.removeListener(this);
|
||||
socket.close();
|
||||
}
|
||||
|
||||
private void emitPending()
|
||||
{
|
||||
try
|
||||
@@ -200,7 +210,13 @@ public class SyncManager
|
||||
|
||||
private void logSocketEvent(Socket socket, String event, final String msg)
|
||||
{
|
||||
socket.on(event, args -> Log.i("SyncManager", msg));
|
||||
socket.on(event, args ->
|
||||
{
|
||||
Log.i("SyncManager", msg);
|
||||
for (Object o : args)
|
||||
if (o instanceof SocketIOException)
|
||||
((SocketIOException) o).printStackTrace();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateLastSync(Long timestamp)
|
||||
@@ -249,8 +265,8 @@ public class SyncManager
|
||||
try
|
||||
{
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("groupKey", GROUP_KEY);
|
||||
json.put("clientId", CLIENT_ID);
|
||||
json.put("groupKey", groupKey);
|
||||
json.put("clientId", clientId);
|
||||
json.put("version", BuildConfig.VERSION_NAME);
|
||||
return json;
|
||||
}
|
||||
@@ -292,6 +308,8 @@ public class SyncManager
|
||||
private void executeCommand(JSONObject root) throws JSONException
|
||||
{
|
||||
Command received = commandParser.parse(root);
|
||||
received.setRemote(true);
|
||||
|
||||
for (Event e : pendingConfirmation)
|
||||
{
|
||||
if (e.serverId.equals(received.getId()))
|
||||
|
||||
@@ -147,10 +147,18 @@
|
||||
android:key="pref_feature_numerical_habits"
|
||||
android:title="Enable numerical habits"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="pref_feature_sync"
|
||||
android:title="Enable cloud sync"/>
|
||||
|
||||
<EditTextPreference
|
||||
android:key="pref_sync_address"
|
||||
android:title="Sync server address"/>
|
||||
|
||||
<EditTextPreference
|
||||
android:key="pref_sync_key"
|
||||
android:title="Sync: group key"
|
||||
android:summary="%s"/>
|
||||
android:title="Sync key"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user