diff --git a/CHANGELOG.md b/CHANGELOG.md
index e976b8d35..ae915a9f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+### 1.8.9 (Nov 18, 2020)
+
+* Remove INTERNET permission
+* Manage exceptions for when activities don't exist to handle intents (#181)
+* MemoryHabitList: Inherit parent's order (#598)
+* Remove notification groups; revert to default system behavior
+* Remove SyncManager and Internet permission
+
### 1.8.8 (June 21, 2020)
* Make small changes to the habit scheduling algorithm, so that "1 time every x days" habits work more predictably.
diff --git a/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivity.java b/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivity.java
index 2dea22e50..3baabd315 100644
--- a/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivity.java
+++ b/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivity.java
@@ -126,4 +126,18 @@ abstract public class BaseActivity extends AppCompatActivity
super.onResume();
if(screen != null) screen.reattachDialogs();
}
+
+ @Override
+ public void startActivity(Intent intent)
+ {
+ try
+ {
+ super.startActivity(intent);
+ }
+ catch (ActivityNotFoundException e)
+ {
+ if (this.screen != null)
+ this.screen.showMessage(R.string.activity_not_found);
+ }
+ }
}
diff --git a/android/android-base/src/main/res/values/strings.xml b/android/android-base/src/main/res/values/strings.xml
new file mode 100644
index 000000000..032239605
--- /dev/null
+++ b/android/android-base/src/main/res/values/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ No app was found to support this action
+
\ No newline at end of file
diff --git a/android/gradle.properties b/android/gradle.properties
index 9c35b1506..87e3585af 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
-VERSION_CODE = 51
-VERSION_NAME = 1.8.8
+VERSION_CODE = 52
+VERSION_NAME = 1.8.9
MIN_SDK_VERSION = 21
TARGET_SDK_VERSION = 29
diff --git a/android/uhabits-android/src/main/AndroidManifest.xml b/android/uhabits-android/src/main/AndroidManifest.xml
index 0c298306b..14fd19687 100644
--- a/android/uhabits-android/src/main/AndroidManifest.xml
+++ b/android/uhabits-android/src/main/AndroidManifest.xml
@@ -25,8 +25,6 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplicationComponent.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplicationComponent.java
index 8c110ab26..cc5e55b20 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplicationComponent.java
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/HabitsApplicationComponent.java
@@ -34,7 +34,6 @@ import org.isoron.uhabits.core.ui.screens.habits.list.*;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.intents.*;
import org.isoron.uhabits.receivers.*;
-import org.isoron.uhabits.sync.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.widgets.*;
@@ -81,8 +80,6 @@ public interface HabitsApplicationComponent
ReminderController getReminderController();
- SyncManager getSyncManager();
-
TaskRunner getTaskRunner();
WidgetPreferences getWidgetPreferences();
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java
index 049f6e319..7f9430b7b 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java
@@ -155,8 +155,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
// Temporarily disable this; we now always ask
findPreference("reminderSound").setVisible(false);
findPreference("pref_snooze_interval").setVisible(false);
-
- updateSync();
}
private void updateWeekdayPreference()
@@ -183,7 +181,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
}
if (key.equals("pref_first_weekday")) updateWeekdayPreference();
BackupManager.dataChanged("org.isoron.uhabits");
- updateSync();
}
private void setResultOnPreferenceClick(String key, final int result)
@@ -218,24 +215,4 @@ public class SettingsFragment extends PreferenceFragmentCompat
Preference ringtonePreference = findPreference("reminderSound");
ringtonePreference.setSummary(ringtoneName);
}
-
- private void updateSync()
- {
- if (prefs == null) return;
- boolean enabled = prefs.isSyncEnabled();
-
- Preference syncKey = findPreference("pref_sync_key");
- if (syncKey != null)
- {
- syncKey.setSummary(prefs.getSyncKey());
- syncKey.setVisible(enabled);
- }
-
- Preference syncAddress = findPreference("pref_sync_address");
- if (syncAddress != null)
- {
- syncAddress.setSummary(prefs.getSyncAddress());
- syncAddress.setVisible(enabled);
- }
- }
}
\ No newline at end of file
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
index 3c1b9c220..bd2d33c50 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt
@@ -51,7 +51,6 @@ class AndroidNotificationTray
Log.d("AndroidNotificationTray", msg)
}
-
override fun removeNotification(id: Int) {
val manager = NotificationManagerCompat.from(context)
manager.cancel(id)
@@ -63,8 +62,6 @@ class AndroidNotificationTray
timestamp: Timestamp,
reminderTime: Long) {
val notificationManager = NotificationManagerCompat.from(context)
- //val summary = buildSummary(habit, reminderTime)
- //notificationManager.notify(Int.MAX_VALUE, summary)
val notification = buildNotification(habit, reminderTime, timestamp)
createAndroidNotificationChannel(context)
try {
@@ -109,7 +106,7 @@ class AndroidNotificationTray
.addAction(removeRepetitionAction)
val defaultText = context.getString(R.string.default_reminder_question)
- val builder = NotificationCompat.Builder(context, REMINDERS_CHANNEL_ID)
+ val builder = Builder(context, REMINDERS_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(habit.name)
.setContentText(if(habit.description.isBlank()) defaultText else habit.description)
@@ -121,7 +118,6 @@ class AndroidNotificationTray
.setWhen(reminderTime)
.setShowWhen(true)
.setOngoing(preferences.shouldMakeNotificationsSticky())
- .setGroup("group" + habit.getId())
if (!disableSound)
builder.setSound(ringtoneManager.getURI())
@@ -139,18 +135,6 @@ class AndroidNotificationTray
return builder.build()
}
- private fun buildSummary(habit: Habit,
- reminderTime: Long): Notification {
- return NotificationCompat.Builder(context, REMINDERS_CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_notification)
- .setContentTitle(context.getString(R.string.app_name))
- .setWhen(reminderTime)
- .setShowWhen(true)
- .setGroup("group" + habit.getId())
- .setGroupSummary(true)
- .build()
- }
-
companion object {
private const val REMINDERS_CHANNEL_ID = "REMINDERS"
fun createAndroidNotificationChannel(context: Context) {
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ConnectivityReceiver.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ConnectivityReceiver.kt
deleted file mode 100644
index 0f861ae57..000000000
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ConnectivityReceiver.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 Álinson Santos Xavier
- *
- * 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 .
- */
-
-package org.isoron.uhabits.receivers
-
-import android.content.*
-import android.content.Context.*
-import android.net.*
-import org.isoron.uhabits.*
-
-class ConnectivityReceiver : BroadcastReceiver() {
- override fun onReceive(context: Context?, intent: Intent?) {
- if (context == null || intent == null) return
- val app = context.applicationContext as HabitsApplication
- val networkInfo = (context.getSystemService(CONNECTIVITY_SERVICE)
- as ConnectivityManager).activeNetworkInfo
- val isConnected = (networkInfo != null) &&
- networkInfo.isConnectedOrConnecting
- val syncManager = app.component.syncManager
- syncManager.onNetworkStatusChanged(isConnected)
- }
-}
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java
index c13d62d2d..e5dec0218 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java
@@ -26,7 +26,6 @@ import org.isoron.uhabits.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.widgets.*;
import org.isoron.uhabits.intents.*;
-import org.isoron.uhabits.sync.*;
import dagger.*;
@@ -68,9 +67,6 @@ public class WidgetReceiver extends BroadcastReceiver
Log.i(TAG, String.format("Received intent: %s", intent.toString()));
- if (prefs.isSyncEnabled())
- context.startService(new Intent(context, SyncService.class));
-
try
{
IntentParser.CheckmarkIntentData data;
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/Event.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/Event.java
deleted file mode 100644
index 3d15d0d3e..000000000
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/Event.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016 Álinson Santos Xavier
- *
- * 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 .
- */
-
-package org.isoron.uhabits.sync;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.isoron.uhabits.core.database.*;
-
-@Table(name = "Events")
-public class Event
-{
- @Nullable
- @Column
- public Long id;
-
- @NonNull
- @Column(name = "timestamp")
- public Long timestamp;
-
- @NonNull
- @Column(name = "message")
- public String message;
-
- @NonNull
- @Column(name = "server_id")
- public String serverId;
-
- public Event()
- {
- timestamp = 0L;
- message = "";
- serverId = "";
- }
-
- public Event(@NonNull String serverId, long timestamp, @NonNull String message)
- {
- this.serverId = serverId;
- this.timestamp = timestamp;
- this.message = message;
- }
-}
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/SyncManager.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/SyncManager.java
deleted file mode 100644
index 88fecb6bf..000000000
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/SyncManager.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2016 Álinson Santos Xavier
- *
- * 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 .
- */
-
-package org.isoron.uhabits.sync;
-
-import android.util.*;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.isoron.androidbase.*;
-import org.isoron.uhabits.BuildConfig;
-import org.isoron.uhabits.core.*;
-import org.isoron.uhabits.core.commands.*;
-import org.isoron.uhabits.core.database.*;
-import org.isoron.uhabits.core.preferences.*;
-import org.isoron.uhabits.database.*;
-import org.isoron.uhabits.utils.*;
-import org.json.*;
-
-import java.net.*;
-import java.util.*;
-
-import javax.inject.*;
-
-import io.socket.client.*;
-import io.socket.client.Socket;
-import io.socket.emitter.*;
-
-import static io.socket.client.Socket.EVENT_CONNECT;
-import static io.socket.client.Socket.EVENT_CONNECTING;
-import static io.socket.client.Socket.EVENT_CONNECT_ERROR;
-import static io.socket.client.Socket.EVENT_CONNECT_TIMEOUT;
-import static io.socket.client.Socket.EVENT_DISCONNECT;
-import static io.socket.client.Socket.EVENT_PING;
-import static io.socket.client.Socket.EVENT_PONG;
-import static io.socket.client.Socket.EVENT_RECONNECT;
-import static io.socket.client.Socket.EVENT_RECONNECT_ATTEMPT;
-import static io.socket.client.Socket.EVENT_RECONNECT_ERROR;
-import static io.socket.client.Socket.EVENT_RECONNECT_FAILED;
-
-@AppScope
-public class SyncManager implements CommandRunner.Listener
-{
- public static final String EVENT_AUTH = "auth";
-
- public static final String EVENT_AUTH_OK = "authOK";
-
- public static final String EVENT_EXECUTE_EVENT = "execute";
-
- public static final String EVENT_FETCH = "fetch";
-
- public static final String EVENT_FETCH_OK = "fetchOK";
-
- public static final String EVENT_POST_EVENT = "postEvent";
-
- @NonNull
- private String clientId;
-
- @NonNull
- private String groupKey;
-
- @NonNull
- private Socket socket;
-
- @NonNull
- private LinkedList pendingConfirmation;
-
- @NonNull
- private LinkedList pendingEmit;
-
- private boolean readyToEmit = false;
-
- @NonNull
- private final Preferences prefs;
-
- @NonNull
- private CommandRunner commandRunner;
-
- @NonNull
- private CommandParser commandParser;
-
- private boolean isListening;
-
- private SSLContextProvider sslProvider;
-
- private final Repository repository;
-
- @Inject
- public SyncManager(@NonNull SSLContextProvider sslProvider,
- @NonNull Preferences prefs,
- @NonNull CommandRunner commandRunner,
- @NonNull CommandParser commandParser)
- {
- Log.i("SyncManager", this.toString());
-
- this.sslProvider = sslProvider;
- this.prefs = prefs;
- this.commandRunner = commandRunner;
- this.commandParser = commandParser;
- this.isListening = false;
-
- repository = new Repository<>(Event.class,
- new AndroidDatabase(DatabaseUtils.openDatabase()));
- pendingConfirmation = new LinkedList<>();
- pendingEmit = new LinkedList<>(repository.findAll("order by timestamp"));
-
- groupKey = prefs.getSyncKey();
- clientId = prefs.getSyncClientId();
- String serverURL = prefs.getSyncAddress();
-
- Log.d("SyncManager", clientId);
- connect(serverURL);
- }
-
- @Override
- public void onCommandExecuted(@NonNull Command command,
- @Nullable Long refreshKey)
- {
- if (command.isRemote()) return;
-
- JSONObject msg = toJSONObject(command.toJson());
- Long now = new Date().getTime();
- Event e = new Event(command.getId(), now, msg.toString());
- repository.save(e);
-
- Log.i("SyncManager", "Adding to outbox: " + msg.toString());
-
- pendingEmit.add(e);
- if (readyToEmit) emitPending();
- }
-
- public void onNetworkStatusChanged(boolean isConnected)
- {
- if (!isListening) return;
- if (isConnected) socket.connect();
- else socket.disconnect();
- }
-
- public void startListening()
- {
- if (!prefs.isSyncEnabled()) return;
- if (groupKey.isEmpty()) return;
- if (isListening) return;
-
- isListening = true;
- socket.connect();
- commandRunner.addListener(this);
- }
-
- public void stopListening()
- {
- if (!isListening) return;
-
- commandRunner.removeListener(this);
- socket.close();
- isListening = false;
- }
-
- private void connect(String serverURL)
- {
- try
- {
- IO.setDefaultSSLContext(sslProvider.getCACertSSLContext());
- socket = IO.socket(serverURL);
-
- logSocketEvent(socket, EVENT_CONNECT, "Connected");
- logSocketEvent(socket, EVENT_CONNECT_TIMEOUT, "Connect timeout");
- logSocketEvent(socket, EVENT_CONNECTING, "Connecting...");
- logSocketEvent(socket, EVENT_CONNECT_ERROR, "Connect error");
- logSocketEvent(socket, EVENT_DISCONNECT, "Disconnected");
- logSocketEvent(socket, EVENT_RECONNECT, "Reconnected");
- logSocketEvent(socket, EVENT_RECONNECT_ATTEMPT, "Reconnecting...");
- logSocketEvent(socket, EVENT_RECONNECT_ERROR, "Reconnect error");
- logSocketEvent(socket, EVENT_RECONNECT_FAILED, "Reconnect failed");
- logSocketEvent(socket, EVENT_DISCONNECT, "Disconnected");
- logSocketEvent(socket, EVENT_PING, "Ping");
- logSocketEvent(socket, EVENT_PONG, "Pong");
-
- socket.on(EVENT_CONNECT, new OnConnectListener());
- socket.on(EVENT_DISCONNECT, new OnDisconnectListener());
- socket.on(EVENT_EXECUTE_EVENT, new OnExecuteCommandListener());
- socket.on(EVENT_AUTH_OK, new OnAuthOKListener());
- socket.on(EVENT_FETCH_OK, new OnFetchOKListener());
- }
- catch (URISyntaxException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- private void emitPending()
- {
- try
- {
- for (Event e : pendingEmit)
- {
- Log.i("SyncManager", "Emitting: " + e.message);
- socket.emit(EVENT_POST_EVENT, new JSONObject(e.message));
- pendingConfirmation.add(e);
- }
-
- pendingEmit.clear();
- }
- catch (JSONException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- private void logSocketEvent(Socket socket, String event, final String msg)
- {
- socket.on(event, args ->
- {
- Log.i("SyncManager", msg);
- for (Object o : args)
- if (o instanceof SocketIOException)
- ((SocketIOException) o).printStackTrace();
- });
- }
-
- private JSONObject toJSONObject(String json)
- {
- try
- {
- return new JSONObject(json);
- }
- catch (JSONException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- private void updateLastSync(Long timestamp)
- {
- prefs.setLastSync(timestamp + 1);
- }
-
- private class OnAuthOKListener implements Emitter.Listener
- {
- @Override
- public void call(Object... args)
- {
- Log.i("SyncManager", "Auth OK");
- Log.i("SyncManager", "Requesting commands since last sync");
-
- Long lastSync = prefs.getLastSync();
- socket.emit(EVENT_FETCH, buildFetchMessage(lastSync));
- }
-
- private JSONObject buildFetchMessage(Long lastSync)
- {
- try
- {
- JSONObject json = new JSONObject();
- json.put("since", lastSync);
- return json;
- }
- catch (JSONException e)
- {
- throw new RuntimeException(e);
- }
- }
- }
-
- private class OnConnectListener implements Emitter.Listener
- {
- @Override
- public void call(Object... args)
- {
- Log.i("SyncManager", "Sending auth message");
- socket.emit(EVENT_AUTH, buildAuthMessage());
- }
-
- private JSONObject buildAuthMessage()
- {
- try
- {
- JSONObject json = new JSONObject();
- json.put("groupKey", groupKey);
- json.put("clientId", clientId);
- json.put("version", BuildConfig.VERSION_NAME);
- return json;
- }
- catch (JSONException e)
- {
- throw new RuntimeException(e);
- }
- }
- }
-
- private class OnDisconnectListener implements Emitter.Listener
- {
- @Override
- public void call(Object... args)
- {
- readyToEmit = false;
- for (Event e : pendingConfirmation) pendingEmit.add(e);
- pendingConfirmation.clear();
- }
- }
-
- private class OnExecuteCommandListener implements Emitter.Listener
- {
- @Override
- public void call(Object... args)
- {
- try
- {
- Log.d("SyncManager",
- String.format("Received command: %s", args[0].toString()));
- JSONObject root = new JSONObject(args[0].toString());
- updateLastSync(root.getLong("timestamp"));
- executeCommand(root);
- }
- catch (JSONException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- private void executeCommand(JSONObject root) throws JSONException
- {
- Command received = commandParser.parse(root.toString());
- received.setRemote(true);
-
- for (Event e : pendingConfirmation)
- {
- if (e.serverId.equals(received.getId()))
- {
- Log.i("SyncManager", "Pending command confirmed");
- pendingConfirmation.remove(e);
- repository.remove(e);
- return;
- }
- }
-
- Log.d("SyncManager", "Executing received command");
- commandRunner.execute(received, null);
- }
- }
-
- private class OnFetchOKListener implements Emitter.Listener
- {
- @Override
- public void call(Object... args)
- {
- try
- {
- Log.i("SyncManager", "Fetch OK");
-
- JSONObject json = (JSONObject) args[0];
- updateLastSync(json.getLong("timestamp"));
-
- emitPending();
- readyToEmit = true;
- }
- catch (JSONException e)
- {
- throw new RuntimeException(e);
- }
- }
- }
-}
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/SyncService.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/SyncService.java
deleted file mode 100644
index 12adf46f2..000000000
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/sync/SyncService.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2016 Álinson Santos Xavier
- *
- * 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 .
- */
-
-package org.isoron.uhabits.sync;
-
-import android.app.*;
-import android.content.*;
-import android.net.*;
-import android.os.*;
-import androidx.core.app.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.core.preferences.*;
-import org.isoron.uhabits.receivers.*;
-
-public class SyncService extends Service implements Preferences.Listener
-{
- private SyncManager syncManager;
-
- private Preferences prefs;
-
- private ConnectivityReceiver connectivityReceiver;
-
- public SyncService()
- {
- }
-
- @Override
- public IBinder onBind(Intent intent)
- {
- return null;
- }
-
- @Override
- public void onCreate()
- {
- Intent notificationIntent = new Intent(this, SyncService.class);
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
-
- Notification notification = new NotificationCompat.Builder(this)
- .setContentTitle("Loop Habit Tracker")
- .setContentText("Sync service running")
- .setSmallIcon(R.drawable.ic_notification)
- .setPriority(NotificationCompat.PRIORITY_MIN)
- .setContentIntent(pendingIntent)
- .build();
-
- startForeground(99999, notification);
-
- connectivityReceiver = new ConnectivityReceiver();
- IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
- this.registerReceiver(connectivityReceiver, filter);
-
- HabitsApplication app = (HabitsApplication) getApplicationContext();
- syncManager = app.getComponent().getSyncManager();
- syncManager.startListening();
-
- prefs = app.getComponent().getPreferences();
- prefs.addListener(this);
- }
-
- @Override
- public void onSyncFeatureChanged()
- {
- if(!prefs.isSyncEnabled()) stopSelf();
- }
-
- @Override
- public void onDestroy()
- {
- unregisterReceiver(connectivityReceiver);
- syncManager.stopListening();
- }
-}
diff --git a/android/uhabits-android/src/main/play/release-notes/en-US/alpha.txt b/android/uhabits-android/src/main/play/release-notes/en-US/alpha.txt
index 6cb4c5aa1..59075b54b 100644
--- a/android/uhabits-android/src/main/play/release-notes/en-US/alpha.txt
+++ b/android/uhabits-android/src/main/play/release-notes/en-US/alpha.txt
@@ -1,10 +1,10 @@
-1.8.8
-* Small tweaks to the habit scheduling algorithm
-* Fix some crashes
+1.8.9
+* Remove unused permissions
+* Notification bundling
1.8:
* New bar chart showing number of repetitions performed each week, month or year
* Performing habits on irregular weekdays will no longer break your streak
-* More colors to choose from (now 20 in total)
+* More colors
* Customize how transparent the widgets are
* Customize the first day of the week
* Yes/No buttons on notifications
diff --git a/android/uhabits-android/src/main/res/xml/preferences.xml b/android/uhabits-android/src/main/res/xml/preferences.xml
index 032dda1d7..2d24e2863 100644
--- a/android/uhabits-android/src/main/res/xml/preferences.xml
+++ b/android/uhabits-android/src/main/res/xml/preferences.xml
@@ -190,22 +190,6 @@
android:title="Enable widget stacks"
app:iconSpaceReserved="false" />
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java
index 80a6d514a..1833f25a2 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/memory/MemoryHabitList.java
@@ -55,6 +55,7 @@ public class MemoryHabitList extends HabitList
super(matcher);
this.parent = parent;
this.comparator = comparator;
+ this.order = parent.order;
parent.getObservable().addListener(this::loadFromParent);
loadFromParent();
}
diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitListTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitListTest.java
index 206caafe6..0165aa222 100644
--- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitListTest.java
+++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitListTest.java
@@ -31,8 +31,7 @@ import static junit.framework.TestCase.assertFalse;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.isoron.uhabits.core.models.HabitList.Order.*;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.*;
@SuppressWarnings("JavaDoc")
public class HabitListTest extends BaseUnitTest
@@ -211,6 +210,17 @@ public class HabitListTest extends BaseUnitTest
habitList.reorder(h1, h2);
}
+ @Test
+ public void testOrder_inherit()
+ {
+ habitList.setOrder(BY_COLOR);
+ HabitList filteredList = habitList.getFiltered(new HabitMatcherBuilder()
+ .setArchivedAllowed(false)
+ .setCompletedAllowed(false)
+ .build());
+ assertEquals(filteredList.getOrder(), BY_COLOR);
+ }
+
@Test
public void testWriteCSV() throws IOException
{