diff --git a/.gitignore b/.gitignore
index 8b44c8900..9ad9f8ab3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
*.class
*.dex
*.iml
+*.local
*.local.*
*.swp
*.trace
@@ -22,3 +23,5 @@ gen/
local.properties
crowdin.yaml
local
+tmp/
+secret/
diff --git a/README.md b/README.md
index 244743f0e..f01eed0ea 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,17 @@
# Loop Habit Tracker
-
-
+
+
-
Loop is a simple Android app that helps you create and maintain good habits,
allowing you to achieve your long-term goals. Detailed graphs and statistics
@@ -15,8 +19,8 @@ show you how your habits improved over time. It is completely ad-free and open
source.
-
-
+
+
## Screenshots
@@ -84,7 +88,7 @@ contribute, even if you are not a software developer.
* **Translate the app into your own language.** If you are not a native English
speaker, and would like to see the app translated into your own language,
- please join our [open translation project at POEditor][poedit]. If the translation
+ please join our [open translation project][poedit]. If the translation
is already completed, you are also very welcome to join and proofread it.
* **Write some code.** If you are an Android developer, you are very welcome to
@@ -121,7 +125,7 @@ contribute, even if you are not a software developer.
[screen4th]: screenshots/thumbs/uhabits4.png
[screen5th]: screenshots/thumbs/uhabits5.png
[screen6th]: screenshots/thumbs/uhabits6.png
-[poedit]: https://poeditor.com/join/project/8DWX5pfjS0
+[poedit]: http://translate.loophabits.org
[playstore]: https://play.google.com/store/apps/details?id=org.isoron.uhabits
[releases]: https://github.com/iSoron/uhabits/releases
[fdroid]: http://f-droid.org/app/org.isoron.uhabits
diff --git a/android-base/.gitignore b/android-base/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/android-base/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/android-base/build.gradle b/android-base/build.gradle
new file mode 100644
index 000000000..128998dd4
--- /dev/null
+++ b/android-base/build.gradle
@@ -0,0 +1,46 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion COMPILE_SDK_VERSION as Integer
+ buildToolsVersion BUILD_TOOLS_VERSION
+
+ defaultConfig {
+ minSdkVersion MIN_SDK_VERSION as Integer
+ targetSdkVersion TARGET_SDK_VERSION as Integer
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation "com.google.dagger:dagger:$DAGGER_VERSION"
+ implementation "com.android.support:design:$SUPPORT_LIBRARY_VERSION"
+ implementation "com.android.support:appcompat-v7:$SUPPORT_LIBRARY_VERSION"
+ implementation "org.apache.commons:commons-lang3:3.5"
+
+ annotationProcessor "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
+ androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
+ androidTestImplementation "com.google.dagger:dagger:$DAGGER_VERSION"
+ testAnnotationProcessor "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
+ testImplementation "junit:junit:4.12"
+
+ androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+
+
+}
diff --git a/android-base/proguard-rules.pro b/android-base/proguard-rules.pro
new file mode 100644
index 000000000..2d5885450
--- /dev/null
+++ b/android-base/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /gemini-b/opt/android-sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/android-base/src/main/AndroidManifest.xml b/android-base/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..dff4e0297
--- /dev/null
+++ b/android-base/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/app/src/main/java/org/isoron/uhabits/activities/BaseSystem.java b/android-base/src/main/java/org/isoron/androidbase/AndroidBugReporter.java
similarity index 71%
rename from app/src/main/java/org/isoron/uhabits/activities/BaseSystem.java
rename to android-base/src/main/java/org/isoron/androidbase/AndroidBugReporter.java
index bacf911b3..e50e2b04d 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/BaseSystem.java
+++ b/android-base/src/main/java/org/isoron/androidbase/AndroidBugReporter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Álinson Santos Xavier
+ * Copyright (C) 2017 Álinson Santos Xavier
*
* This file is part of Loop Habit Tracker.
*
@@ -17,75 +17,32 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase;
import android.content.*;
import android.os.*;
import android.support.annotation.*;
import android.view.*;
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.utils.*;
-
import java.io.*;
-import java.lang.Process;
+import java.text.*;
import java.util.*;
import javax.inject.*;
-/**
- * Base class for all systems class in the application.
- *
- * Classes derived from BaseSystem are responsible for handling events and
- * sending requests to the Android operating system. Examples include capturing
- * a bug report, obtaining device information, or requesting runtime
- * permissions.
- */
-@ActivityScope
-public class BaseSystem
+public class AndroidBugReporter
{
- private Context context;
+ private final Context context;
@Inject
- public BaseSystem(@ActivityContext Context context)
+ public AndroidBugReporter(@NonNull @AppContext Context context)
{
this.context = context;
}
/**
- * Captures a bug report and saves it to a file in the SD card.
- *
- * The contents of the file are generated by the method {@link
- * #getBugReport()}. The file is saved in the apps's external private
- * storage.
- *
- * @return the generated file.
- * @throws IOException when I/O errors occur.
- */
- @NonNull
- public File dumpBugReportToFile() throws IOException
- {
- String date =
- DateFormats.getBackupDateFormat().format(DateUtils.getLocalTime());
-
- if (context == null) throw new RuntimeException(
- "application context should not be null");
- File dir = FileUtils.getFilesDir(context, "Logs");
- if (dir == null) throw new IOException("log dir should not be null");
-
- File logFile =
- new File(String.format("%s/Log %s.txt", dir.getPath(), date));
- FileWriter output = new FileWriter(logFile);
- output.write(getBugReport());
- output.close();
-
- return logFile;
- }
-
- /**
- * Captures and returns a bug report.
- *
- * The bug report contains some device information and the logcat.
+ * Captures and returns a bug report. The bug report contains some device
+ * information and the logcat.
*
* @return a String containing the bug report.
* @throws IOException when any I/O error occur.
@@ -103,13 +60,39 @@ public class BaseSystem
return log;
}
+ public String getDeviceInfo()
+ {
+ if (context == null) return "null context\n";
+
+ WindowManager wm =
+ (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+
+ return
+ String.format("App Version Name: %s\n", BuildConfig.VERSION_NAME) +
+ String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE) +
+ String.format("OS Version: %s (%s)\n",
+ System.getProperty("os.version"), Build.VERSION.INCREMENTAL) +
+ String.format("OS API Level: %s\n", Build.VERSION.SDK) +
+ String.format("Device: %s\n", Build.DEVICE) +
+ String.format("Model (Product): %s (%s)\n", Build.MODEL,
+ Build.PRODUCT) +
+ String.format("Manufacturer: %s\n", Build.MANUFACTURER) +
+ String.format("Other tags: %s\n", Build.TAGS) +
+ String.format("Screen Width: %s\n",
+ wm.getDefaultDisplay().getWidth()) +
+ String.format("Screen Height: %s\n",
+ wm.getDefaultDisplay().getHeight()) +
+ String.format("External storage state: %s\n\n",
+ Environment.getExternalStorageState());
+ }
+
public String getLogcat() throws IOException
{
int maxLineCount = 250;
StringBuilder builder = new StringBuilder();
String[] command = new String[]{ "logcat", "-d" };
- Process process = Runtime.getRuntime().exec(command);
+ java.lang.Process process = Runtime.getRuntime().exec(command);
InputStreamReader in = new InputStreamReader(process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(in);
@@ -132,29 +115,41 @@ public class BaseSystem
return builder.toString();
}
- private String getDeviceInfo()
+ /**
+ * Captures a bug report and saves it to a file in the SD card.
+ *
+ * The contents of the file are generated by the method {@link
+ * #getBugReport()}. The file is saved in the apps's external private
+ * storage.
+ *
+ * @return the generated file.
+ * @throws IOException when I/O errors occur.
+ */
+ @NonNull
+ public void dumpBugReportToFile()
{
- if (context == null) return "null context\n";
+ try
+ {
- WindowManager wm =
- (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ String date =
+ new SimpleDateFormat("yyyy-MM-dd HHmmss", Locale.US).format(
+ new Date());
- return
- String.format("App Version Name: %s\n", BuildConfig.VERSION_NAME) +
- String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE) +
- String.format("OS Version: %s (%s)\n",
- System.getProperty("os.version"), Build.VERSION.INCREMENTAL) +
- String.format("OS API Level: %s\n", Build.VERSION.SDK) +
- String.format("Device: %s\n", Build.DEVICE) +
- String.format("Model (Product): %s (%s)\n", Build.MODEL,
- Build.PRODUCT) +
- String.format("Manufacturer: %s\n", Build.MANUFACTURER) +
- String.format("Other tags: %s\n", Build.TAGS) +
- String.format("Screen Width: %s\n",
- wm.getDefaultDisplay().getWidth()) +
- String.format("Screen Height: %s\n",
- wm.getDefaultDisplay().getHeight()) +
- String.format("External storage state: %s\n\n",
- Environment.getExternalStorageState());
+ if (context == null) throw new IllegalStateException();
+
+ File dir = new AndroidDirFinder(context).getFilesDir("Logs");
+ if (dir == null)
+ throw new IOException("log dir should not be null");
+
+ File logFile =
+ new File(String.format("%s/Log %s.txt", dir.getPath(), date));
+ FileWriter output = new FileWriter(logFile);
+ output.write(getBugReport());
+ output.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
}
}
diff --git a/app/src/main/java/org/isoron/uhabits/HabitLogger.java b/android-base/src/main/java/org/isoron/androidbase/AndroidDirFinder.java
similarity index 51%
rename from app/src/main/java/org/isoron/uhabits/HabitLogger.java
rename to android-base/src/main/java/org/isoron/androidbase/AndroidDirFinder.java
index fb781c273..3e40aed4d 100644
--- a/app/src/main/java/org/isoron/uhabits/HabitLogger.java
+++ b/android-base/src/main/java/org/isoron/androidbase/AndroidDirFinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Álinson Santos Xavier
+ * Copyright (C) 2017 Álinson Santos Xavier
*
* This file is part of Loop Habit Tracker.
*
@@ -17,38 +17,42 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits;
+package org.isoron.androidbase;
+import android.content.*;
import android.support.annotation.*;
+import android.support.v4.content.*;
import android.util.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
+import org.isoron.androidbase.utils.*;
-import java.text.*;
-import java.util.*;
+import java.io.*;
import javax.inject.*;
-@AppScope
-public class HabitLogger
+public class AndroidDirFinder
{
+ @NonNull
+ private Context context;
+
@Inject
- public HabitLogger()
+ public AndroidDirFinder(@NonNull @AppContext Context context)
{
-
+ this.context = context;
}
- public void logReminderScheduled(@NonNull Habit habit,
- @NonNull Long reminderTime)
+ @Nullable
+ public File getFilesDir(@Nullable String relativePath)
{
- int min = Math.min(3, habit.getName().length());
- String name = habit.getName().substring(0, min);
-
- DateFormat df = DateFormats.getBackupDateFormat();
- String time = df.format(new Date(reminderTime));
-
- Log.i("ReminderHelper",
- String.format("Setting alarm (%s): %s", time, name));
+ File externalFilesDirs[] =
+ ContextCompat.getExternalFilesDirs(context, null);
+ if (externalFilesDirs == null)
+ {
+ Log.e("BaseSystem",
+ "getFilesDir: getExternalFilesDirs returned null");
+ return null;
+ }
+
+ return FileUtils.getDir(externalFilesDirs, relativePath);
}
}
diff --git a/app/src/main/java/org/isoron/uhabits/AppContext.java b/android-base/src/main/java/org/isoron/androidbase/AppContext.java
similarity index 96%
rename from app/src/main/java/org/isoron/uhabits/AppContext.java
rename to android-base/src/main/java/org/isoron/androidbase/AppContext.java
index ebd0aab10..d7521e26d 100644
--- a/app/src/main/java/org/isoron/uhabits/AppContext.java
+++ b/android-base/src/main/java/org/isoron/androidbase/AppContext.java
@@ -17,7 +17,7 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits;
+package org.isoron.androidbase;
import java.lang.annotation.*;
diff --git a/app/src/main/java/org/isoron/uhabits/AppModule.java b/android-base/src/main/java/org/isoron/androidbase/AppContextModule.java
similarity index 89%
rename from app/src/main/java/org/isoron/uhabits/AppModule.java
rename to android-base/src/main/java/org/isoron/androidbase/AppContextModule.java
index c5aa66c70..c166a89d8 100644
--- a/app/src/main/java/org/isoron/uhabits/AppModule.java
+++ b/android-base/src/main/java/org/isoron/androidbase/AppContextModule.java
@@ -17,18 +17,18 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits;
+package org.isoron.androidbase;
import android.content.*;
import dagger.*;
@Module
-public class AppModule
+public class AppContextModule
{
private final Context context;
- public AppModule(@AppContext Context context)
+ public AppContextModule(@AppContext Context context)
{
this.context = context;
}
diff --git a/android-base/src/main/java/org/isoron/androidbase/BaseExceptionHandler.java b/android-base/src/main/java/org/isoron/androidbase/BaseExceptionHandler.java
new file mode 100644
index 000000000..3a04b8b4f
--- /dev/null
+++ b/android-base/src/main/java/org/isoron/androidbase/BaseExceptionHandler.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 Á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.androidbase;
+
+import android.support.annotation.*;
+
+import org.isoron.androidbase.activities.*;
+
+public class BaseExceptionHandler implements Thread.UncaughtExceptionHandler
+{
+ @Nullable
+ private Thread.UncaughtExceptionHandler originalHandler;
+
+ @NonNull
+ private BaseActivity activity;
+
+ public BaseExceptionHandler(@NonNull BaseActivity activity)
+ {
+ this.activity = activity;
+ originalHandler = Thread.getDefaultUncaughtExceptionHandler();
+ }
+
+ @Override
+ public void uncaughtException(@Nullable Thread thread,
+ @Nullable Throwable ex)
+ {
+ if (ex == null) return;
+
+ try
+ {
+ ex.printStackTrace();
+ new AndroidBugReporter(activity).dumpBugReportToFile();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+// if (ex.getCause() instanceof InconsistentDatabaseException)
+// {
+// HabitsApplication app = (HabitsApplication) activity.getApplication();
+// HabitList habits = app.getComponent().getHabitList();
+// habits.repair();
+// System.exit(0);
+// }
+
+ if (originalHandler != null)
+ originalHandler.uncaughtException(thread, ex);
+ }
+}
diff --git a/android-base/src/main/java/org/isoron/androidbase/SSLContextProvider.java b/android-base/src/main/java/org/isoron/androidbase/SSLContextProvider.java
new file mode 100644
index 000000000..c488bbc16
--- /dev/null
+++ b/android-base/src/main/java/org/isoron/androidbase/SSLContextProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 Á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.androidbase;
+
+import android.content.*;
+import android.support.annotation.*;
+
+import org.isoron.androidbase.*;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.*;
+
+import javax.inject.*;
+import javax.net.ssl.*;
+
+public class SSLContextProvider
+{
+ private Context context;
+
+ @Inject
+ public SSLContextProvider(@NonNull @AppContext Context context)
+ {
+ this.context = context;
+ }
+
+ public SSLContext getCACertSSLContext()
+ {
+ try
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ InputStream caInput = context.getAssets().open("cacert.pem");
+ Certificate ca = cf.generateCertificate(caInput);
+
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(null, null);
+ ks.setCertificateEntry("ca", ca);
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(ks);
+
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ ctx.init(null, tmf.getTrustManagers(), null);
+
+ return ctx;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/ActivityContext.java b/android-base/src/main/java/org/isoron/androidbase/activities/ActivityContext.java
similarity index 95%
rename from app/src/main/java/org/isoron/uhabits/activities/ActivityContext.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/ActivityContext.java
index c75c28dae..5749c4ecc 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/ActivityContext.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/ActivityContext.java
@@ -17,7 +17,7 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase.activities;
import java.lang.annotation.*;
diff --git a/app/src/androidTest/java/org/isoron/uhabits/AndroidTestComponent.java b/android-base/src/main/java/org/isoron/androidbase/activities/ActivityContextModule.java
similarity index 70%
rename from app/src/androidTest/java/org/isoron/uhabits/AndroidTestComponent.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/ActivityContextModule.java
index 55a756d92..af7e26442 100644
--- a/app/src/androidTest/java/org/isoron/uhabits/AndroidTestComponent.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/ActivityContextModule.java
@@ -17,20 +17,26 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits;
+package org.isoron.androidbase.activities;
-
-import org.isoron.uhabits.models.sqlite.*;
-import org.isoron.uhabits.tasks.*;
+import android.content.*;
import dagger.*;
-@AppScope
-@Component(modules = {
- AppModule.class, SingleThreadTaskRunner.class, SQLModelFactory.class
-})
-public interface AndroidTestComponent extends AppComponent
+@Module
+public class ActivityContextModule
{
+ private Context context;
+ public ActivityContextModule(Context context)
+ {
+ this.context = context;
+ }
+ @Provides
+ @ActivityContext
+ public Context getContext()
+ {
+ return context;
+ }
}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/ActivityScope.java b/android-base/src/main/java/org/isoron/androidbase/activities/ActivityScope.java
similarity index 95%
rename from app/src/main/java/org/isoron/uhabits/activities/ActivityScope.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/ActivityScope.java
index 3d02e80ae..82dad3ce9 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/ActivityScope.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/ActivityScope.java
@@ -17,7 +17,7 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase.activities;
import javax.inject.*;
diff --git a/app/src/main/java/org/isoron/uhabits/activities/BaseActivity.java b/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivity.java
similarity index 59%
rename from app/src/main/java/org/isoron/uhabits/activities/BaseActivity.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/BaseActivity.java
index 311749159..fae8c82ba 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/BaseActivity.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivity.java
@@ -17,7 +17,7 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase.activities;
import android.content.*;
import android.os.*;
@@ -25,12 +25,10 @@ import android.support.annotation.*;
import android.support.v7.app.*;
import android.view.*;
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.habits.list.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.*;
+import org.isoron.androidbase.*;
-import static android.R.anim.*;
+import static android.R.anim.fade_in;
+import static android.R.anim.fade_out;
/**
* Base class for all activities in the application.
@@ -41,28 +39,19 @@ import static android.R.anim.*;
* {@link BaseScreen}.
*
* A BaseActivity also installs an {@link java.lang.Thread.UncaughtExceptionHandler}
- * to the main thread that logs the exception to the disk before the application
- * crashes.
+ * to the main thread. By default, this handler is an instance of
+ * BaseExceptionHandler, which logs the exception to the disk before the application
+ * crashes. To the default handler, you should override the method
+ * getExceptionHandler.
*/
abstract public class BaseActivity extends AppCompatActivity
- implements Thread.UncaughtExceptionHandler
{
@Nullable
private BaseMenu baseMenu;
- @Nullable
- private Thread.UncaughtExceptionHandler androidExceptionHandler;
-
@Nullable
private BaseScreen screen;
- private ActivityComponent component;
-
- public ActivityComponent getComponent()
- {
- return component;
- }
-
@Override
public boolean onCreateOptionsMenu(@Nullable Menu menu)
{
@@ -80,13 +69,13 @@ abstract public class BaseActivity extends AppCompatActivity
return baseMenu.onItemSelected(item);
}
- public void restartWithFade()
+ public void restartWithFade(Class> cls)
{
- new Handler().postDelayed(() -> {
- Intent intent = new Intent(this, ListHabitsActivity.class);
+ new Handler().postDelayed(() ->
+ {
finish();
overridePendingTransition(fade_in, fade_out);
- startActivity(intent);
+ startActivity(new Intent(this, cls));
}, 500); // HACK: Let the menu disappear first
}
@@ -111,35 +100,6 @@ abstract public class BaseActivity extends AppCompatActivity
dialog.show();
}
- @Override
- public void uncaughtException(@Nullable Thread thread,
- @Nullable Throwable ex)
- {
- if (ex == null) return;
-
- try
- {
- ex.printStackTrace();
- new BaseSystem(this).dumpBugReportToFile();
- }
- catch (Exception e)
- {
- // ignored
- }
-
- if (ex.getCause() instanceof InconsistentDatabaseException)
- {
- HabitsApplication app = (HabitsApplication) getApplication();
- HabitList habits = app.getComponent().getHabitList();
- habits.repair();
- System.exit(0);
- }
-
- if (androidExceptionHandler != null)
- androidExceptionHandler.uncaughtException(thread, ex);
- else System.exit(1);
- }
-
@Override
protected void onActivityResult(int request, int result, Intent data)
{
@@ -151,18 +111,18 @@ abstract public class BaseActivity extends AppCompatActivity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
+ Thread.setDefaultUncaughtExceptionHandler(getExceptionHandler());
+ }
- androidExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
- Thread.setDefaultUncaughtExceptionHandler(this);
-
- HabitsApplication app = (HabitsApplication) getApplicationContext();
-
- component = DaggerActivityComponent
- .builder()
- .activityModule(new ActivityModule(this))
- .appComponent(app.getComponent())
- .build();
+ protected Thread.UncaughtExceptionHandler getExceptionHandler()
+ {
+ return new BaseExceptionHandler(this);
+ }
- component.getThemeSwitcher().apply();
+ @Override
+ protected void onResume()
+ {
+ super.onResume();
+ if(screen != null) screen.reattachDialogs();
}
}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/ActivityModule.java b/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivityModule.java
similarity index 76%
rename from app/src/main/java/org/isoron/uhabits/activities/ActivityModule.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/BaseActivityModule.java
index dcf743241..96e5ec476 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/ActivityModule.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/BaseActivityModule.java
@@ -17,31 +17,22 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
-
-import android.content.*;
+package org.isoron.androidbase.activities;
import dagger.*;
@Module
-public class ActivityModule
+public class BaseActivityModule
{
private BaseActivity activity;
- public ActivityModule(BaseActivity activity)
+ public BaseActivityModule(BaseActivity activity)
{
this.activity = activity;
}
@Provides
- public BaseActivity getActivity()
- {
- return activity;
- }
-
- @Provides
- @ActivityContext
- public Context getContext()
+ public BaseActivity getBaseActivity()
{
return activity;
}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/BaseMenu.java b/android-base/src/main/java/org/isoron/androidbase/activities/BaseMenu.java
similarity index 87%
rename from app/src/main/java/org/isoron/uhabits/activities/BaseMenu.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/BaseMenu.java
index f9d7bf077..7cba01ddc 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/BaseMenu.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/BaseMenu.java
@@ -17,13 +17,11 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase.activities;
import android.support.annotation.*;
import android.view.*;
-import javax.annotation.*;
-
/**
* Base class for all the menus in the application.
*
@@ -41,6 +39,12 @@ public abstract class BaseMenu
this.activity = activity;
}
+ @NonNull
+ public BaseActivity getActivity()
+ {
+ return activity;
+ }
+
/**
* Declare that the menu has changed, and should be recreated.
*/
@@ -64,14 +68,13 @@ public abstract class BaseMenu
/**
* Called when the menu is first displayed.
*
- * This method cannot be overridden. The application should override the
- * methods onCreate(Menu) and getMenuResourceId instead.
+ * This method should not be overridden. The application should override
+ * the methods onCreate(Menu) and getMenuResourceId instead.
*
* @param inflater a menu inflater, for creating the menu
* @param menu the menu that is being created.
*/
- public final void onCreate(@NonNull MenuInflater inflater,
- @NonNull Menu menu)
+ public void onCreate(@NonNull MenuInflater inflater, @NonNull Menu menu)
{
menu.clear();
inflater.inflate(getMenuResourceId(), menu);
@@ -94,6 +97,6 @@ public abstract class BaseMenu
*
* @return id of the menu resource.
*/
- @Resource
+ @MenuRes
protected abstract int getMenuResourceId();
}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/BaseRootView.java b/android-base/src/main/java/org/isoron/androidbase/activities/BaseRootView.java
similarity index 65%
rename from app/src/main/java/org/isoron/uhabits/activities/BaseRootView.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/BaseRootView.java
index af3867ead..21c0322f7 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/BaseRootView.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/BaseRootView.java
@@ -17,20 +17,19 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase.activities;
import android.content.*;
import android.support.annotation.*;
-import android.support.v4.content.res.*;
import android.support.v7.widget.Toolbar;
import android.view.*;
import android.widget.*;
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.utils.*;
+import org.isoron.androidbase.*;
+import org.isoron.androidbase.utils.*;
-import static android.os.Build.VERSION.*;
-import static android.os.Build.VERSION_CODES.*;
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.LOLLIPOP;
/**
* Base class for all root views in the application.
@@ -42,36 +41,42 @@ import static android.os.Build.VERSION_CODES.*;
*/
public abstract class BaseRootView extends FrameLayout
{
+ @NonNull
private final Context context;
- private final BaseActivity activity;
+ protected boolean shouldDisplayHomeAsUp = false;
- private final ThemeSwitcher themeSwitcher;
+ @Nullable
+ private BaseScreen screen;
- public BaseRootView(Context context)
+ public BaseRootView(@NonNull Context context)
{
super(context);
this.context = context;
- activity = (BaseActivity) context;
- themeSwitcher = activity.getComponent().getThemeSwitcher();
}
public boolean getDisplayHomeAsUp()
{
- return false;
+ return shouldDisplayHomeAsUp;
+ }
+
+ public void setDisplayHomeAsUp(boolean b)
+ {
+ shouldDisplayHomeAsUp = b;
}
@NonNull
- public abstract Toolbar getToolbar();
+ public Toolbar getToolbar()
+ {
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ if (toolbar == null) throw new RuntimeException(
+ "Your BaseRootView should have a " +
+ "toolbar with id R.id.toolbar");
+ return toolbar;
+ }
public int getToolbarColor()
{
- if (SDK_INT < LOLLIPOP && !themeSwitcher.isNightMode())
- {
- return ResourcesCompat.getColor(context.getResources(),
- R.color.grey_900, context.getTheme());
- }
-
StyledResources res = new StyledResources(context);
return res.getColor(R.attr.colorPrimary);
}
@@ -86,7 +91,18 @@ public abstract class BaseRootView extends FrameLayout
if (view != null) view.setVisibility(GONE);
view = findViewById(R.id.headerShadow);
- if(view != null) view.setVisibility(GONE);
+ if (view != null) view.setVisibility(GONE);
}
}
+
+ public void onAttachedToScreen(BaseScreen screen)
+ {
+ this.screen = screen;
+ }
+
+ @Nullable
+ public BaseScreen getScreen()
+ {
+ return screen;
+ }
}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/BaseScreen.java b/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.java
similarity index 94%
rename from app/src/main/java/org/isoron/uhabits/activities/BaseScreen.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.java
index 64621414c..f135a6e62 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/BaseScreen.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.java
@@ -17,7 +17,7 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase.activities;
import android.content.*;
import android.graphics.*;
@@ -33,14 +33,14 @@ import android.support.v7.widget.Toolbar;
import android.view.*;
import android.widget.*;
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.utils.*;
+import org.isoron.androidbase.*;
+import org.isoron.androidbase.utils.*;
import java.io.*;
-import static android.os.Build.VERSION.*;
-import static android.os.Build.VERSION_CODES.*;
-import static android.support.v4.content.FileProvider.*;
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.LOLLIPOP;
+import static android.support.v4.content.FileProvider.getUriForFile;
/**
* Base class for all screens in the application.
@@ -51,8 +51,6 @@ import static android.support.v4.content.FileProvider.*;
*/
public class BaseScreen
{
- public static final int REQUEST_CREATE_DOCUMENT = 1;
-
protected BaseActivity activity;
@Nullable
@@ -61,13 +59,28 @@ public class BaseScreen
@Nullable
private BaseSelectionMenu selectionMenu;
- private Snackbar snackbar;
+ protected Snackbar snackbar;
public BaseScreen(@NonNull BaseActivity activity)
{
this.activity = activity;
}
+ @Deprecated
+ public static int getDefaultActionBarColor(Context context)
+ {
+ if (SDK_INT < LOLLIPOP)
+ {
+ return ResourcesCompat.getColor(context.getResources(),
+ R.color.grey_900, context.getTheme());
+ }
+ else
+ {
+ StyledResources res = new StyledResources(context);
+ return res.getColor(R.attr.colorPrimary);
+ }
+ }
+
@Deprecated
public static void setupActionBarColor(@NonNull AppCompatActivity activity,
int color)
@@ -83,7 +96,6 @@ public class BaseScreen
actionBar.setDisplayHomeAsUpEnabled(true);
-
ColorDrawable drawable = new ColorDrawable(color);
actionBar.setBackgroundDrawable(drawable);
@@ -102,21 +114,6 @@ public class BaseScreen
}
}
- @Deprecated
- public static int getDefaultActionBarColor(Context context)
- {
- if (SDK_INT < LOLLIPOP)
- {
- return ResourcesCompat.getColor(context.getResources(),
- R.color.grey_900, context.getTheme());
- }
- else
- {
- StyledResources res = new StyledResources(context);
- return res.getColor(R.attr.colorPrimary);
- }
- }
-
/**
* Notifies the screen that its contents should be updated.
*/
@@ -130,7 +127,8 @@ public class BaseScreen
{
if (rootView == null) return;
- activity.runOnUiThread(() -> {
+ activity.runOnUiThread(() ->
+ {
Toolbar toolbar = rootView.getToolbar();
activity.setSupportActionBar(toolbar);
ActionBar actionBar = activity.getSupportActionBar();
@@ -159,6 +157,15 @@ public class BaseScreen
{
}
+
+ /**
+ * Called after activity has been recreated, and the dialogs should be
+ * reattached to their controllers.
+ */
+ public void reattachDialogs()
+ {
+ }
+
/**
* Sets the menu to be shown by this screen.
*
@@ -182,7 +189,7 @@ public class BaseScreen
this.rootView = rootView;
activity.setContentView(rootView);
if (rootView == null) return;
-
+ rootView.onAttachedToScreen(this);
invalidateToolbar();
}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/BaseSelectionMenu.java b/android-base/src/main/java/org/isoron/androidbase/activities/BaseSelectionMenu.java
similarity index 90%
rename from app/src/main/java/org/isoron/uhabits/activities/BaseSelectionMenu.java
rename to android-base/src/main/java/org/isoron/androidbase/activities/BaseSelectionMenu.java
index a5c7f5cca..87396e216 100644
--- a/app/src/main/java/org/isoron/uhabits/activities/BaseSelectionMenu.java
+++ b/android-base/src/main/java/org/isoron/androidbase/activities/BaseSelectionMenu.java
@@ -17,7 +17,7 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.activities;
+package org.isoron.androidbase.activities;
import android.support.annotation.*;
import android.support.v7.view.ActionMode;
@@ -59,16 +59,16 @@ public abstract class BaseSelectionMenu
/**
* Called when the menu is first displayed.
*
- * This method cannot be overridden. The application should override the
- * methods onCreate(Menu) and getMenuResourceId instead.
+ * This method should not be overridden. The application should override
+ * the methods onCreate(Menu) and getMenuResourceId instead.
*
* @param inflater a menu inflater, for creating the menu
* @param mode the action mode associated with this menu.
* @param menu the menu that is being created.
*/
- public final void onCreate(@NonNull MenuInflater inflater,
- @NonNull ActionMode mode,
- @NonNull Menu menu)
+ public void onCreate(@NonNull MenuInflater inflater,
+ @NonNull ActionMode mode,
+ @NonNull Menu menu)
{
this.actionMode = mode;
inflater.inflate(getResourceId(), menu);
diff --git a/app/src/main/java/org/isoron/uhabits/utils/ColorUtils.java b/android-base/src/main/java/org/isoron/androidbase/utils/ColorUtils.java
similarity index 51%
rename from app/src/main/java/org/isoron/uhabits/utils/ColorUtils.java
rename to android-base/src/main/java/org/isoron/androidbase/utils/ColorUtils.java
index 25434bacc..58199d2dd 100644
--- a/app/src/main/java/org/isoron/uhabits/utils/ColorUtils.java
+++ b/android-base/src/main/java/org/isoron/androidbase/utils/ColorUtils.java
@@ -17,80 +17,12 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.utils;
+package org.isoron.androidbase.utils;
-import android.content.*;
import android.graphics.*;
-import android.util.*;
public abstract class ColorUtils
{
- public static String CSV_PALETTE[] = {
- "#D32F2F", // 0 red
- "#E64A19", // 1 orange
- "#F9A825", // 2 yellow
- "#AFB42B", // 3 light green
- "#388E3C", // 4 dark green
- "#00897B", // 5 teal
- "#00ACC1", // 6 cyan
- "#039BE5", // 7 blue
- "#5E35B1", // 8 deep purple
- "#8E24AA", // 9 purple
- "#D81B60", // 10 pink
- "#303030", // 11 dark grey
- "#aaaaaa" // 12 light grey
- };
-
- public static int colorToPaletteIndex(Context context, int color)
- {
- StyledResources res = new StyledResources(context);
- int[] palette = res.getPalette();
-
- for (int k = 0; k < palette.length; k++)
- if (palette[k] == color) return k;
-
- return -1;
- }
-
- public static int getAndroidTestColor(int index)
- {
- int palette[] = {
- Color.parseColor("#D32F2F"), // 0 red
- Color.parseColor("#E64A19"), // 1 orange
- Color.parseColor("#F9A825"), // 2 yellow
- Color.parseColor("#AFB42B"), // 3 light green
- Color.parseColor("#388E3C"), // 4 dark green
- Color.parseColor("#00897B"), // 5 teal
- Color.parseColor("#00ACC1"), // 6 cyan
- Color.parseColor("#039BE5"), // 7 blue
- Color.parseColor("#5E35B1"), // 8 deep purple
- Color.parseColor("#8E24AA"), // 9 purple
- Color.parseColor("#D81B60"), // 10 pink
- Color.parseColor("#303030"), // 11 dark grey
- Color.parseColor("#aaaaaa") // 12 light grey
- };
-
- return palette[index];
- }
-
- public static int getColor(Context context, int paletteColor)
- {
- if (context == null)
- throw new IllegalArgumentException("Context is null");
-
- StyledResources res = new StyledResources(context);
- int palette[] = res.getPalette();
- if (paletteColor < 0 || paletteColor >= palette.length)
- {
- Log.w("ColorHelper",
- String.format("Invalid color: %d. Returning default.",
- paletteColor));
- paletteColor = 0;
- }
-
- return palette[paletteColor];
- }
-
public static int mixColors(int color1, int color2, float amount)
{
final byte ALPHA_CHANNEL = 24;
diff --git a/app/src/main/java/org/isoron/uhabits/utils/FileUtils.java b/android-base/src/main/java/org/isoron/androidbase/utils/FileUtils.java
similarity index 74%
rename from app/src/main/java/org/isoron/uhabits/utils/FileUtils.java
rename to android-base/src/main/java/org/isoron/androidbase/utils/FileUtils.java
index 4cee13ac3..59ca4a9b4 100644
--- a/app/src/main/java/org/isoron/uhabits/utils/FileUtils.java
+++ b/android-base/src/main/java/org/isoron/androidbase/utils/FileUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Álinson Santos Xavier
+ * Copyright (C) 2017 Álinson Santos Xavier
*
* This file is part of Loop Habit Tracker.
*
@@ -17,16 +17,12 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.utils;
+package org.isoron.androidbase.utils;
-import android.content.*;
import android.os.*;
import android.support.annotation.*;
-import android.support.v4.content.*;
import android.util.*;
-import org.isoron.uhabits.*;
-
import java.io.*;
public abstract class FileUtils
@@ -54,8 +50,8 @@ public abstract class FileUtils
}
@Nullable
- private static File getDir(@NonNull File potentialParentDirs[],
- @Nullable String relativePath)
+ public static File getDir(@NonNull File potentialParentDirs[],
+ @Nullable String relativePath)
{
if (relativePath == null) relativePath = "";
@@ -69,7 +65,7 @@ public abstract class FileUtils
if (chosenDir == null)
{
- Log.e("DatabaseHelper",
+ Log.e("FileUtils",
"getDir: all potential parents are null or non-writable");
return null;
}
@@ -78,7 +74,7 @@ public abstract class FileUtils
String.format("%s/%s/", chosenDir.getAbsolutePath(), relativePath));
if (!dir.exists() && !dir.mkdirs())
{
- Log.e("DatabaseHelper",
+ Log.e("FileUtils",
"getDir: chosen dir does not exist and cannot be created");
return null;
}
@@ -86,22 +82,6 @@ public abstract class FileUtils
return dir;
}
- @Nullable
- public static File getFilesDir(@NonNull Context context, @Nullable String relativePath)
- {
- File externalFilesDirs[] =
- ContextCompat.getExternalFilesDirs(context, null);
-
- if (externalFilesDirs == null)
- {
- Log.e("DatabaseHelper",
- "getFilesDir: getExternalFilesDirs returned null");
- return null;
- }
-
- return getDir(externalFilesDirs, relativePath);
- }
-
@Nullable
public static File getSDCardDir(@Nullable String relativePath)
{
diff --git a/app/src/main/java/org/isoron/uhabits/utils/InterfaceUtils.java b/android-base/src/main/java/org/isoron/androidbase/utils/InterfaceUtils.java
similarity index 55%
rename from app/src/main/java/org/isoron/uhabits/utils/InterfaceUtils.java
rename to android-base/src/main/java/org/isoron/androidbase/utils/InterfaceUtils.java
index 8fdc5fc9f..e1fea418b 100644
--- a/app/src/main/java/org/isoron/uhabits/utils/InterfaceUtils.java
+++ b/android-base/src/main/java/org/isoron/androidbase/utils/InterfaceUtils.java
@@ -17,29 +17,42 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.utils;
+package org.isoron.androidbase.utils;
import android.content.*;
import android.content.res.*;
import android.graphics.*;
+import android.support.annotation.*;
import android.support.v4.view.*;
import android.util.*;
import android.view.*;
+import android.widget.*;
public abstract class InterfaceUtils
{
private static Typeface fontAwesome;
+ @Nullable
+ private static Float fixedResolution = null;
+
+ public static void setFixedResolution(@NonNull Float f)
+ {
+ fixedResolution = f;
+ }
+
public static Typeface getFontAwesome(Context context)
{
- if(fontAwesome == null)
- fontAwesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
+ if(fontAwesome == null) fontAwesome =
+ Typeface.createFromAsset(context.getAssets(),
+ "fontawesome-webfont.ttf");
return fontAwesome;
}
public static float dpToPixels(Context context, float dp)
{
+ if(fixedResolution != null) return dp * fixedResolution;
+
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);
@@ -47,11 +60,40 @@ public abstract class InterfaceUtils
public static float spToPixels(Context context, float sp)
{
+ if(fixedResolution != null) return sp * fixedResolution;
+
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, metrics);
}
+ public static float getDimension(Context context, int id)
+ {
+ float dim = context.getResources().getDimension(id);
+ if (fixedResolution == null) return dim;
+ else
+ {
+ DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ float actualDensity = dm.density;
+ return dim / actualDensity * fixedResolution;
+ }
+ }
+
+ public static void setupEditorAction(@NonNull ViewGroup parent,
+ @NonNull TextView.OnEditorActionListener listener)
+ {
+ for (int i = 0; i < parent.getChildCount(); i++)
+ {
+ View child = parent.getChildAt(i);
+
+ if (child instanceof ViewGroup)
+ setupEditorAction((ViewGroup) child, listener);
+
+ if (child instanceof TextView)
+ ((TextView) child).setOnEditorActionListener(listener);
+ }
+ }
+
public static boolean isLayoutRtl(View view)
{
return ViewCompat.getLayoutDirection(view) ==
diff --git a/app/src/main/java/org/isoron/uhabits/utils/StyledResources.java b/android-base/src/main/java/org/isoron/androidbase/utils/StyledResources.java
similarity index 87%
rename from app/src/main/java/org/isoron/uhabits/utils/StyledResources.java
rename to android-base/src/main/java/org/isoron/androidbase/utils/StyledResources.java
index 1297f8962..d15766f95 100644
--- a/app/src/main/java/org/isoron/uhabits/utils/StyledResources.java
+++ b/android-base/src/main/java/org/isoron/androidbase/utils/StyledResources.java
@@ -17,14 +17,14 @@
* with this program. If not, see .
*/
-package org.isoron.uhabits.utils;
+package org.isoron.androidbase.utils;
import android.content.*;
import android.content.res.*;
import android.graphics.drawable.*;
import android.support.annotation.*;
-import org.isoron.uhabits.*;
+import org.isoron.androidbase.*;
public class StyledResources
{
@@ -51,6 +51,15 @@ public class StyledResources
return bool;
}
+ public int getDimension(@AttrRes int attrId)
+ {
+ TypedArray ta = getTypedArray(attrId);
+ int dim = ta.getDimensionPixelSize(0, 0);
+ ta.recycle();
+
+ return dim;
+ }
+
public int getColor(@AttrRes int attrId)
{
TypedArray ta = getTypedArray(attrId);
@@ -80,13 +89,13 @@ public class StyledResources
public int[] getPalette()
{
- int resourceId = getStyleResource(R.attr.palette);
+ int resourceId = getResource(R.attr.palette);
if (resourceId < 0) throw new RuntimeException("resource not found");
return context.getResources().getIntArray(resourceId);
}
- int getStyleResource(@AttrRes int attrId)
+ public int getResource(@AttrRes int attrId)
{
TypedArray ta = getTypedArray(attrId);
int resourceId = ta.getResourceId(0, -1);
diff --git a/android-base/src/main/res/values/base.xml b/android-base/src/main/res/values/base.xml
new file mode 100644
index 000000000..c22a13fad
--- /dev/null
+++ b/android-base/src/main/res/values/base.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/android-base/src/main/res/values/material_colors.xml
similarity index 77%
rename from app/src/main/res/values/colors.xml
rename to android-base/src/main/res/values/material_colors.xml
index 29616a09e..ab9f783d7 100644
--- a/app/src/main/res/values/colors.xml
+++ b/android-base/src/main/res/values/material_colors.xml
@@ -1,97 +1,5 @@
-
-
-
- @color/red_700
- @color/deep_orange_700
- @color/yellow_800
- @color/lime_700
- @color/green_700
- @color/teal_600
- @color/cyan_600
- @color/light_blue_600
- @color/deep_purple_600
- @color/purple_600
- @color/pink_600
- @color/grey_800
- @color/grey_500
-
-
-
- @color/red_200
- @color/deep_orange_200
- @color/yellow_200
- @color/lime_200
- @color/green_A200
- @color/teal_200
- @color/cyan_200
- @color/light_blue_200
- @color/deep_purple_200
- @color/purple_200
- @color/pink_200
- @color/grey_100
- @color/grey_500
-
-
-
- @color/red_800
- @color/deep_orange_800
- @color/yellow_800
- @color/lime_800
- @color/green_700
- @color/teal_700
- @color/cyan_700
- @color/light_blue_700
- @color/deep_purple_700
- @color/purple_700
- @color/pink_700
- @color/black_aa
- @color/black_aa
-
-
-
- #f2f2f2
- #cccccc
- #8c8c8c
- #000000
- #cccccc
- #8c8c8c
- #00000000
- #7f000000
- #33b5e5
- #c1e8f7
- #33999999
- #0099cc
- #ff999999
- #999999
- #f2f2f2
- #ffd1d2d4
- #888888
- #888888
-
-
- #ff3333
- #853333
- #404040
- #363636
- #808080
-
-
#FFEBEE#FFCDD2#EF9A9A
diff --git a/android-pickers/.gitignore b/android-pickers/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/android-pickers/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/android-pickers/build.gradle b/android-pickers/build.gradle
new file mode 100644
index 000000000..fc75627d8
--- /dev/null
+++ b/android-pickers/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion COMPILE_SDK_VERSION as Integer
+ buildToolsVersion BUILD_TOOLS_VERSION
+
+ defaultConfig {
+ minSdkVersion MIN_SDK_VERSION as Integer
+ targetSdkVersion TARGET_SDK_VERSION as Integer
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation "com.android.support:appcompat-v7:$SUPPORT_LIBRARY_VERSION"
+}
diff --git a/android-pickers/proguard-rules.pro b/android-pickers/proguard-rules.pro
new file mode 100644
index 000000000..2d5885450
--- /dev/null
+++ b/android-pickers/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /gemini-b/opt/android-sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/android-pickers/src/main/AndroidManifest.xml b/android-pickers/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..c8e4c8bd3
--- /dev/null
+++ b/android-pickers/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/app/src/main/java/com/android/colorpicker/ColorPickerDialog.java b/android-pickers/src/main/java/com/android/colorpicker/ColorPickerDialog.java
similarity index 94%
rename from app/src/main/java/com/android/colorpicker/ColorPickerDialog.java
rename to android-pickers/src/main/java/com/android/colorpicker/ColorPickerDialog.java
index 114c5fed5..1060faf5b 100644
--- a/app/src/main/java/com/android/colorpicker/ColorPickerDialog.java
+++ b/android-pickers/src/main/java/com/android/colorpicker/ColorPickerDialog.java
@@ -16,18 +16,15 @@
package com.android.colorpicker;
-import android.app.Activity;
-import android.app.Dialog;
-import android.os.Bundle;
+import android.app.*;
+import android.os.*;
import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatDialogFragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ProgressBar;
+import android.support.v7.app.*;
+import android.view.*;
+import android.widget.*;
-import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
-
-import org.isoron.uhabits.R;
+import com.android.*;
+import com.android.colorpicker.ColorPickerSwatch.*;
/**
* A dialog which takes in as input an array of palette and creates a palette allowing the user to
diff --git a/app/src/main/java/com/android/colorpicker/ColorPickerPalette.java b/android-pickers/src/main/java/com/android/colorpicker/ColorPickerPalette.java
similarity index 94%
rename from app/src/main/java/com/android/colorpicker/ColorPickerPalette.java
rename to android-pickers/src/main/java/com/android/colorpicker/ColorPickerPalette.java
index add5ba86e..0e7102ad9 100644
--- a/app/src/main/java/com/android/colorpicker/ColorPickerPalette.java
+++ b/android-pickers/src/main/java/com/android/colorpicker/ColorPickerPalette.java
@@ -16,18 +16,14 @@
package com.android.colorpicker;
-import org.isoron.uhabits.R;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TableLayout;
-import android.widget.TableRow;
-
-import com.android.colorpicker.ColorPickerSwatch.OnColorSelectedListener;
+import android.content.*;
+import android.content.res.*;
+import android.util.*;
+import android.view.*;
+import android.widget.*;
+
+import com.android.*;
+import com.android.colorpicker.ColorPickerSwatch.*;
/**
* A color picker custom view which creates an grid of color squares. The number of squares per
diff --git a/app/src/main/java/com/android/colorpicker/ColorPickerSwatch.java b/android-pickers/src/main/java/com/android/colorpicker/ColorPickerSwatch.java
similarity index 91%
rename from app/src/main/java/com/android/colorpicker/ColorPickerSwatch.java
rename to android-pickers/src/main/java/com/android/colorpicker/ColorPickerSwatch.java
index fb15a84ab..a7598ca3b 100644
--- a/app/src/main/java/com/android/colorpicker/ColorPickerSwatch.java
+++ b/android-pickers/src/main/java/com/android/colorpicker/ColorPickerSwatch.java
@@ -16,14 +16,12 @@
package com.android.colorpicker;
-import org.isoron.uhabits.R;
+import android.content.*;
+import android.graphics.drawable.*;
+import android.view.*;
+import android.widget.*;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
+import com.android.*;
/**
* Creates a circular swatch of a specified color. Adds a checkmark if marked as checked.
diff --git a/app/src/main/java/com/android/colorpicker/ColorStateDrawable.java b/android-pickers/src/main/java/com/android/colorpicker/ColorStateDrawable.java
similarity index 100%
rename from app/src/main/java/com/android/colorpicker/ColorStateDrawable.java
rename to android-pickers/src/main/java/com/android/colorpicker/ColorStateDrawable.java
diff --git a/app/src/main/java/com/android/colorpicker/HsvColorComparator.java b/android-pickers/src/main/java/com/android/colorpicker/HsvColorComparator.java
similarity index 100%
rename from app/src/main/java/com/android/colorpicker/HsvColorComparator.java
rename to android-pickers/src/main/java/com/android/colorpicker/HsvColorComparator.java
diff --git a/app/src/main/java/com/android/datetimepicker/AccessibleLinearLayout.java b/android-pickers/src/main/java/com/android/datetimepicker/AccessibleLinearLayout.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/AccessibleLinearLayout.java
rename to android-pickers/src/main/java/com/android/datetimepicker/AccessibleLinearLayout.java
diff --git a/app/src/main/java/com/android/datetimepicker/AccessibleTextView.java b/android-pickers/src/main/java/com/android/datetimepicker/AccessibleTextView.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/AccessibleTextView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/AccessibleTextView.java
diff --git a/app/src/main/java/com/android/datetimepicker/HapticFeedbackController.java b/android-pickers/src/main/java/com/android/datetimepicker/HapticFeedbackController.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/HapticFeedbackController.java
rename to android-pickers/src/main/java/com/android/datetimepicker/HapticFeedbackController.java
diff --git a/app/src/main/java/com/android/datetimepicker/Utils.java b/android-pickers/src/main/java/com/android/datetimepicker/Utils.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/Utils.java
rename to android-pickers/src/main/java/com/android/datetimepicker/Utils.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/AccessibleDateAnimator.java b/android-pickers/src/main/java/com/android/datetimepicker/date/AccessibleDateAnimator.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/date/AccessibleDateAnimator.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/AccessibleDateAnimator.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/DatePickerController.java b/android-pickers/src/main/java/com/android/datetimepicker/date/DatePickerController.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/date/DatePickerController.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/DatePickerController.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java b/android-pickers/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java
similarity index 94%
rename from app/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java
index b6581ecf9..dd4e06942 100644
--- a/app/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/date/DatePickerDialog.java
@@ -16,36 +16,23 @@
package com.android.datetimepicker.date;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Locale;
-
-import org.isoron.uhabits.R;
-
-import android.animation.ObjectAnimator;
-import android.app.Activity;
-import android.app.DialogFragment;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.datetimepicker.HapticFeedbackController;
-import com.android.datetimepicker.Utils;
-import com.android.datetimepicker.date.MonthAdapter.CalendarDay;
+import android.animation.*;
+import android.app.*;
+import android.content.res.*;
+import android.os.*;
+import android.text.format.*;
+import android.util.*;
+import android.view.*;
+import android.view.View.*;
+import android.view.animation.*;
+import android.widget.*;
+
+import com.android.*;
+import com.android.datetimepicker.*;
+import com.android.datetimepicker.date.MonthAdapter.*;
+
+import java.text.*;
+import java.util.*;
/**
* Dialog allowing users to select a date.
diff --git a/app/src/main/java/com/android/datetimepicker/date/DayPickerView.java b/android-pickers/src/main/java/com/android/datetimepicker/date/DayPickerView.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/date/DayPickerView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/DayPickerView.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/MonthAdapter.java b/android-pickers/src/main/java/com/android/datetimepicker/date/MonthAdapter.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/date/MonthAdapter.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/MonthAdapter.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/MonthView.java b/android-pickers/src/main/java/com/android/datetimepicker/date/MonthView.java
similarity index 95%
rename from app/src/main/java/com/android/datetimepicker/date/MonthView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/MonthView.java
index 8b5defab2..eff8b8186 100644
--- a/app/src/main/java/com/android/datetimepicker/date/MonthView.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/date/MonthView.java
@@ -16,37 +16,25 @@
package com.android.datetimepicker.date;
-import java.security.InvalidParameterException;
-import java.util.Calendar;
+import android.content.*;
+import android.content.res.*;
+import android.graphics.*;
+import android.graphics.Paint.*;
+import android.os.*;
+import android.support.v4.view.*;
+import android.support.v4.view.accessibility.*;
+import android.support.v4.widget.*;
+import android.text.format.*;
+import android.view.*;
+import android.view.accessibility.*;
+
+import com.android.*;
+import com.android.datetimepicker.*;
+import com.android.datetimepicker.date.MonthAdapter.*;
+
+import java.security.*;
+import java.util.*;
import java.util.Formatter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-
-import org.isoron.uhabits.R;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.Paint.Style;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.android.datetimepicker.Utils;
-import com.android.datetimepicker.date.MonthAdapter.CalendarDay;
/**
* A calendar-like view displaying a specified month and the appropriate selectable day numbers
diff --git a/app/src/main/java/com/android/datetimepicker/date/SimpleDayPickerView.java b/android-pickers/src/main/java/com/android/datetimepicker/date/SimpleDayPickerView.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/date/SimpleDayPickerView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/SimpleDayPickerView.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/SimpleMonthAdapter.java b/android-pickers/src/main/java/com/android/datetimepicker/date/SimpleMonthAdapter.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/date/SimpleMonthAdapter.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/SimpleMonthAdapter.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/SimpleMonthView.java b/android-pickers/src/main/java/com/android/datetimepicker/date/SimpleMonthView.java
similarity index 100%
rename from app/src/main/java/com/android/datetimepicker/date/SimpleMonthView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/SimpleMonthView.java
diff --git a/app/src/main/java/com/android/datetimepicker/date/TextViewWithCircularIndicator.java b/android-pickers/src/main/java/com/android/datetimepicker/date/TextViewWithCircularIndicator.java
similarity index 89%
rename from app/src/main/java/com/android/datetimepicker/date/TextViewWithCircularIndicator.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/TextViewWithCircularIndicator.java
index 64d6404e7..148f2faf2 100644
--- a/app/src/main/java/com/android/datetimepicker/date/TextViewWithCircularIndicator.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/date/TextViewWithCircularIndicator.java
@@ -16,16 +16,14 @@
package com.android.datetimepicker.date;
-import org.isoron.uhabits.R;
+import android.content.*;
+import android.content.res.*;
+import android.graphics.*;
+import android.graphics.Paint.*;
+import android.util.*;
+import android.widget.*;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.Paint.Style;
-import android.util.AttributeSet;
-import android.widget.TextView;
+import com.android.*;
/**
* A text view which, when pressed or activated, displays a blue circle around the text.
diff --git a/app/src/main/java/com/android/datetimepicker/date/YearPickerView.java b/android-pickers/src/main/java/com/android/datetimepicker/date/YearPickerView.java
similarity index 89%
rename from app/src/main/java/com/android/datetimepicker/date/YearPickerView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/date/YearPickerView.java
index 5abc4ca1a..b2c33f6b5 100644
--- a/app/src/main/java/com/android/datetimepicker/date/YearPickerView.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/date/YearPickerView.java
@@ -16,24 +16,18 @@
package com.android.datetimepicker.date;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.isoron.uhabits.R;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.StateListDrawable;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.android.datetimepicker.date.DatePickerDialog.OnDateChangedListener;
+import android.content.*;
+import android.content.res.*;
+import android.graphics.drawable.*;
+import android.view.*;
+import android.view.accessibility.*;
+import android.widget.*;
+import android.widget.AdapterView.*;
+
+import com.android.*;
+import com.android.datetimepicker.date.DatePickerDialog.*;
+
+import java.util.*;
/**
* Displays a selectable list of years.
diff --git a/app/src/main/java/com/android/datetimepicker/time/AmPmCirclesView.java b/android-pickers/src/main/java/com/android/datetimepicker/time/AmPmCirclesView.java
similarity index 95%
rename from app/src/main/java/com/android/datetimepicker/time/AmPmCirclesView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/time/AmPmCirclesView.java
index 993ea0c91..f310a1d85 100644
--- a/app/src/main/java/com/android/datetimepicker/time/AmPmCirclesView.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/time/AmPmCirclesView.java
@@ -16,20 +16,17 @@
package com.android.datetimepicker.time;
-import java.text.DateFormatSymbols;
+import android.content.*;
+import android.content.res.*;
+import android.graphics.*;
+import android.graphics.Paint.*;
+import android.util.*;
+import android.view.*;
-import org.isoron.uhabits.R;
+import com.android.*;
+import com.android.datetimepicker.*;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.Typeface;
-import android.util.Log;
-import android.view.View;
-
-import com.android.datetimepicker.Utils;
+import java.text.*;
/**
* Draw the two smaller AM and PM circles next to where the larger circle will be.
diff --git a/app/src/main/java/com/android/datetimepicker/time/CircleView.java b/android-pickers/src/main/java/com/android/datetimepicker/time/CircleView.java
similarity index 94%
rename from app/src/main/java/com/android/datetimepicker/time/CircleView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/time/CircleView.java
index bd0ccc99c..1765bff93 100644
--- a/app/src/main/java/com/android/datetimepicker/time/CircleView.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/time/CircleView.java
@@ -16,14 +16,14 @@
package com.android.datetimepicker.time;
-import org.isoron.uhabits.R;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.util.Log;
-import android.view.View;
+
+import android.content.*;
+import android.content.res.*;
+import android.graphics.*;
+import android.util.*;
+import android.view.*;
+
+import com.android.*;
/**
* Draws a simple white circle on which the numbers will be drawn.
diff --git a/app/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java b/android-pickers/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java
similarity index 97%
rename from app/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java
rename to android-pickers/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java
index 3ada25315..265b98cf8 100644
--- a/app/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/time/RadialPickerLayout.java
@@ -16,30 +16,20 @@
package com.android.datetimepicker.time;
-import org.isoron.uhabits.R;
-
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.os.Handler;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.FrameLayout;
-
-import com.android.datetimepicker.HapticFeedbackController;
+import android.animation.*;
+import android.annotation.*;
+import android.content.*;
+import android.content.res.*;
+import android.os.*;
+import android.text.format.*;
+import android.util.*;
+import android.view.*;
+import android.view.View.*;
+import android.view.accessibility.*;
+import android.widget.*;
+
+import com.android.*;
+import com.android.datetimepicker.*;
/**
* The primary layout to hold the circular picker, and the am/pm buttons. This view well measure
diff --git a/app/src/main/java/com/android/datetimepicker/time/RadialSelectorView.java b/android-pickers/src/main/java/com/android/datetimepicker/time/RadialSelectorView.java
similarity index 97%
rename from app/src/main/java/com/android/datetimepicker/time/RadialSelectorView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/time/RadialSelectorView.java
index 1ccf511c1..48e4385b5 100644
--- a/app/src/main/java/com/android/datetimepicker/time/RadialSelectorView.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/time/RadialSelectorView.java
@@ -16,21 +16,16 @@
package com.android.datetimepicker.time;
-import org.isoron.uhabits.R;
-
-import android.animation.Keyframe;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.util.Log;
-import android.view.View;
-
-import com.android.datetimepicker.Utils;
+import android.animation.*;
+import android.animation.ValueAnimator.*;
+import android.content.*;
+import android.content.res.*;
+import android.graphics.*;
+import android.util.*;
+import android.view.*;
+
+import com.android.*;
+import com.android.datetimepicker.*;
/**
* View to show what number is selected. This will draw a blue circle over the number, with a blue
diff --git a/app/src/main/java/com/android/datetimepicker/time/RadialTextsView.java b/android-pickers/src/main/java/com/android/datetimepicker/time/RadialTextsView.java
similarity index 96%
rename from app/src/main/java/com/android/datetimepicker/time/RadialTextsView.java
rename to android-pickers/src/main/java/com/android/datetimepicker/time/RadialTextsView.java
index e6a99a657..a944901bf 100644
--- a/app/src/main/java/com/android/datetimepicker/time/RadialTextsView.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/time/RadialTextsView.java
@@ -16,21 +16,16 @@
package com.android.datetimepicker.time;
-import org.isoron.uhabits.R;
-
-import android.animation.Keyframe;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.Typeface;
-import android.util.Log;
-import android.view.View;
+import android.animation.*;
+import android.animation.ValueAnimator.*;
+import android.content.*;
+import android.content.res.*;
+import android.graphics.*;
+import android.graphics.Paint.*;
+import android.util.*;
+import android.view.*;
+
+import com.android.*;
/**
* A view to show a series of numbers in a circular pattern.
diff --git a/app/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java b/android-pickers/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java
similarity index 97%
rename from app/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java
rename to android-pickers/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java
index 8f22206f4..0bbb741e2 100644
--- a/app/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java
+++ b/android-pickers/src/main/java/com/android/datetimepicker/time/TimePickerDialog.java
@@ -16,37 +16,25 @@
package com.android.datetimepicker.time;
-import java.text.DateFormatSymbols;
-import java.util.ArrayList;
-import java.util.Locale;
-
-import org.isoron.uhabits.R;
-
-import android.animation.ObjectAnimator;
-import android.annotation.SuppressLint;
+import android.animation.*;
+import android.annotation.*;
+import android.app.ActionBar.*;
import android.app.*;
-import android.app.ActionBar;
-import android.app.ActionBar.LayoutParams;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.os.Bundle;
+import android.content.*;
+import android.content.res.*;
+import android.os.*;
import android.support.v7.app.*;
-import android.util.Log;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnKeyListener;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import com.android.datetimepicker.HapticFeedbackController;
-import com.android.datetimepicker.Utils;
-import com.android.datetimepicker.time.RadialPickerLayout.OnValueSelectedListener;
+import android.util.*;
+import android.view.*;
+import android.view.View.*;
+import android.widget.*;
+
+import com.android.*;
+import com.android.datetimepicker.*;
+import com.android.datetimepicker.time.RadialPickerLayout.*;
+
+import java.text.*;
+import java.util.*;
/**
* Dialog to set a time.
diff --git a/app/src/main/res/color/date_picker_selector.xml b/android-pickers/src/main/res/color/date_picker_selector.xml
similarity index 100%
rename from app/src/main/res/color/date_picker_selector.xml
rename to android-pickers/src/main/res/color/date_picker_selector.xml
diff --git a/app/src/main/res/color/date_picker_year_selector.xml b/android-pickers/src/main/res/color/date_picker_year_selector.xml
similarity index 100%
rename from app/src/main/res/color/date_picker_year_selector.xml
rename to android-pickers/src/main/res/color/date_picker_year_selector.xml
diff --git a/app/src/main/res/drawable-hdpi/ic_colorpicker_swatch_selected.png b/android-pickers/src/main/res/drawable-hdpi/ic_colorpicker_swatch_selected.png
similarity index 100%
rename from app/src/main/res/drawable-hdpi/ic_colorpicker_swatch_selected.png
rename to android-pickers/src/main/res/drawable-hdpi/ic_colorpicker_swatch_selected.png
diff --git a/app/src/main/res/drawable-mdpi/ic_colorpicker_swatch_selected.png b/android-pickers/src/main/res/drawable-mdpi/ic_colorpicker_swatch_selected.png
similarity index 100%
rename from app/src/main/res/drawable-mdpi/ic_colorpicker_swatch_selected.png
rename to android-pickers/src/main/res/drawable-mdpi/ic_colorpicker_swatch_selected.png
diff --git a/app/src/main/res/drawable-xhdpi/ic_colorpicker_swatch_selected.png b/android-pickers/src/main/res/drawable-xhdpi/ic_colorpicker_swatch_selected.png
similarity index 100%
rename from app/src/main/res/drawable-xhdpi/ic_colorpicker_swatch_selected.png
rename to android-pickers/src/main/res/drawable-xhdpi/ic_colorpicker_swatch_selected.png
diff --git a/app/src/main/res/drawable/color_picker_swatch.xml b/android-pickers/src/main/res/drawable/color_picker_swatch.xml
similarity index 100%
rename from app/src/main/res/drawable/color_picker_swatch.xml
rename to android-pickers/src/main/res/drawable/color_picker_swatch.xml
diff --git a/app/src/main/res/drawable/done_background_color.xml b/android-pickers/src/main/res/drawable/done_background_color.xml
similarity index 100%
rename from app/src/main/res/drawable/done_background_color.xml
rename to android-pickers/src/main/res/drawable/done_background_color.xml
diff --git a/app/src/main/res/drawable/done_background_color_dark.xml b/android-pickers/src/main/res/drawable/done_background_color_dark.xml
similarity index 100%
rename from app/src/main/res/drawable/done_background_color_dark.xml
rename to android-pickers/src/main/res/drawable/done_background_color_dark.xml
diff --git a/app/src/main/res/layout/color_picker_dialog.xml b/android-pickers/src/main/res/layout/color_picker_dialog.xml
similarity index 100%
rename from app/src/main/res/layout/color_picker_dialog.xml
rename to android-pickers/src/main/res/layout/color_picker_dialog.xml
diff --git a/app/src/main/res/layout/color_picker_swatch.xml b/android-pickers/src/main/res/layout/color_picker_swatch.xml
similarity index 100%
rename from app/src/main/res/layout/color_picker_swatch.xml
rename to android-pickers/src/main/res/layout/color_picker_swatch.xml
diff --git a/app/src/main/res/layout/date_picker_dialog.xml b/android-pickers/src/main/res/layout/date_picker_dialog.xml
similarity index 100%
rename from app/src/main/res/layout/date_picker_dialog.xml
rename to android-pickers/src/main/res/layout/date_picker_dialog.xml
diff --git a/app/src/main/res/layout/date_picker_done_button.xml b/android-pickers/src/main/res/layout/date_picker_done_button.xml
similarity index 100%
rename from app/src/main/res/layout/date_picker_done_button.xml
rename to android-pickers/src/main/res/layout/date_picker_done_button.xml
diff --git a/app/src/main/res/layout/date_picker_header_view.xml b/android-pickers/src/main/res/layout/date_picker_header_view.xml
similarity index 100%
rename from app/src/main/res/layout/date_picker_header_view.xml
rename to android-pickers/src/main/res/layout/date_picker_header_view.xml
diff --git a/app/src/main/res/layout/date_picker_selected_date.xml b/android-pickers/src/main/res/layout/date_picker_selected_date.xml
similarity index 100%
rename from app/src/main/res/layout/date_picker_selected_date.xml
rename to android-pickers/src/main/res/layout/date_picker_selected_date.xml
diff --git a/app/src/main/res/layout/date_picker_view_animator.xml b/android-pickers/src/main/res/layout/date_picker_view_animator.xml
similarity index 100%
rename from app/src/main/res/layout/date_picker_view_animator.xml
rename to android-pickers/src/main/res/layout/date_picker_view_animator.xml
diff --git a/app/src/main/res/layout/time_header_label.xml b/android-pickers/src/main/res/layout/time_header_label.xml
similarity index 100%
rename from app/src/main/res/layout/time_header_label.xml
rename to android-pickers/src/main/res/layout/time_header_label.xml
diff --git a/app/src/main/res/layout/time_picker_dialog.xml b/android-pickers/src/main/res/layout/time_picker_dialog.xml
similarity index 100%
rename from app/src/main/res/layout/time_picker_dialog.xml
rename to android-pickers/src/main/res/layout/time_picker_dialog.xml
diff --git a/app/src/main/res/layout/year_label_text_view.xml b/android-pickers/src/main/res/layout/year_label_text_view.xml
similarity index 100%
rename from app/src/main/res/layout/year_label_text_view.xml
rename to android-pickers/src/main/res/layout/year_label_text_view.xml
diff --git a/app/src/main/res/values/pickers.xml b/android-pickers/src/main/res/values/pickers.xml
similarity index 55%
rename from app/src/main/res/values/pickers.xml
rename to android-pickers/src/main/res/values/pickers.xml
index c396c2747..d658216c9 100644
--- a/app/src/main/res/values/pickers.xml
+++ b/android-pickers/src/main/res/values/pickers.xml
@@ -24,16 +24,36 @@
8dip4dip
- 0.82
- 0.85
- 0.16
- 0.19
- 0.81
- 0.60
- 0.83
- 0.17
- 0.14
- 0.11
+
+ 0.82
+
+
+ 0.85
+
+
+ 0.16
+
+
+ 0.19
+
+
+ 0.81
+
+
+ 0.60
+
+
+ 0.83
+
+
+ 0.17
+
+
+ 0.14
+
+
+ 0.11
+ 60sp-30dp
@@ -64,8 +84,8 @@
64dp22sp
- Color %1$d
- Color %1$d selected
+ Color %1$d
+ Color %1$d selectedHours circular slider
@@ -74,11 +94,56 @@
Year listSelect month and daySelect year
- %1$s selected
- %1$s deleted
+ %1$s selected
+ %1$s deleted--:sans-serifsans-serifsans-serif
+
+
+ #f2f2f2
+ #cccccc
+ #8c8c8c
+ #000000
+ #cccccc
+ #8c8c8c
+ #00000000
+ #7f000000
+ #33b5e5
+ #c1e8f7
+ #33999999
+ #0099cc
+ #ff999999
+ #999999
+ #f2f2f2
+ #ffd1d2d4
+ #888888
+ #888888
+ #ffffff
+ #000000
+
+
+ #ff3333
+ #853333
+ #404040
+ #363636
+ #808080
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android-pickers/src/main/res/values/strings.xml b/android-pickers/src/main/res/values/strings.xml
new file mode 100644
index 000000000..9e6581a37
--- /dev/null
+++ b/android-pickers/src/main/res/values/strings.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt
deleted file mode 100644
index 363b143b7..000000000
--- a/app/proguard-rules.txt
+++ /dev/null
@@ -1,3 +0,0 @@
--dontwarn java.beans.**
--dontwarn java.lang.**
--dontobfuscate
\ No newline at end of file
diff --git a/app/src/androidTest/assets/icon.png b/app/src/androidTest/assets/icon.png
deleted file mode 100644
index 7907954db..000000000
Binary files a/app/src/androidTest/assets/icon.png and /dev/null differ
diff --git a/app/src/androidTest/assets/pull_failed b/app/src/androidTest/assets/pull_failed
deleted file mode 100755
index 8a3238df7..000000000
--- a/app/src/androidTest/assets/pull_failed
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-P=/sdcard/Android/data/org.isoron.uhabits/cache/Failed/
-
-adb pull $P Failed/
-adb shell rm -r $P
diff --git a/app/src/androidTest/assets/views/common/FrequencyChart/render.png b/app/src/androidTest/assets/views/common/FrequencyChart/render.png
deleted file mode 100644
index 70ec73c84..000000000
Binary files a/app/src/androidTest/assets/views/common/FrequencyChart/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/FrequencyChart/renderDifferentSize.png b/app/src/androidTest/assets/views/common/FrequencyChart/renderDifferentSize.png
deleted file mode 100644
index 7dd7a684c..000000000
Binary files a/app/src/androidTest/assets/views/common/FrequencyChart/renderDifferentSize.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/FrequencyChart/renderTransparent.png b/app/src/androidTest/assets/views/common/FrequencyChart/renderTransparent.png
deleted file mode 100644
index 70ec73c84..000000000
Binary files a/app/src/androidTest/assets/views/common/FrequencyChart/renderTransparent.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/HistoryChart/render.png b/app/src/androidTest/assets/views/common/HistoryChart/render.png
deleted file mode 100644
index fabd5891e..000000000
Binary files a/app/src/androidTest/assets/views/common/HistoryChart/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/HistoryChart/renderDataOffset.png b/app/src/androidTest/assets/views/common/HistoryChart/renderDataOffset.png
deleted file mode 100644
index 0fee4e308..000000000
Binary files a/app/src/androidTest/assets/views/common/HistoryChart/renderDataOffset.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/HistoryChart/renderDifferentSize.png b/app/src/androidTest/assets/views/common/HistoryChart/renderDifferentSize.png
deleted file mode 100644
index e2a08b0d7..000000000
Binary files a/app/src/androidTest/assets/views/common/HistoryChart/renderDifferentSize.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/HistoryChart/renderTransparent.png b/app/src/androidTest/assets/views/common/HistoryChart/renderTransparent.png
deleted file mode 100644
index b7be74220..000000000
Binary files a/app/src/androidTest/assets/views/common/HistoryChart/renderTransparent.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/RingView/renderDifferentParams.png b/app/src/androidTest/assets/views/common/RingView/renderDifferentParams.png
deleted file mode 100644
index 87874ba92..000000000
Binary files a/app/src/androidTest/assets/views/common/RingView/renderDifferentParams.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/ScoreChart/render.png b/app/src/androidTest/assets/views/common/ScoreChart/render.png
deleted file mode 100644
index 4f606e5e9..000000000
Binary files a/app/src/androidTest/assets/views/common/ScoreChart/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/ScoreChart/renderDataOffset.png b/app/src/androidTest/assets/views/common/ScoreChart/renderDataOffset.png
deleted file mode 100644
index a6eab96e6..000000000
Binary files a/app/src/androidTest/assets/views/common/ScoreChart/renderDataOffset.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/ScoreChart/renderDifferentSize.png b/app/src/androidTest/assets/views/common/ScoreChart/renderDifferentSize.png
deleted file mode 100644
index 8eb052d73..000000000
Binary files a/app/src/androidTest/assets/views/common/ScoreChart/renderDifferentSize.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/ScoreChart/renderMonthly.png b/app/src/androidTest/assets/views/common/ScoreChart/renderMonthly.png
deleted file mode 100644
index 75f74d515..000000000
Binary files a/app/src/androidTest/assets/views/common/ScoreChart/renderMonthly.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/ScoreChart/renderTransparent.png b/app/src/androidTest/assets/views/common/ScoreChart/renderTransparent.png
deleted file mode 100644
index 0b7f70a7e..000000000
Binary files a/app/src/androidTest/assets/views/common/ScoreChart/renderTransparent.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/ScoreChart/renderYearly.png b/app/src/androidTest/assets/views/common/ScoreChart/renderYearly.png
deleted file mode 100644
index d186ceefc..000000000
Binary files a/app/src/androidTest/assets/views/common/ScoreChart/renderYearly.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/StreakChart/render.png b/app/src/androidTest/assets/views/common/StreakChart/render.png
deleted file mode 100644
index 4bab05b52..000000000
Binary files a/app/src/androidTest/assets/views/common/StreakChart/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/StreakChart/renderSmallSize.png b/app/src/androidTest/assets/views/common/StreakChart/renderSmallSize.png
deleted file mode 100644
index 00eb8daa6..000000000
Binary files a/app/src/androidTest/assets/views/common/StreakChart/renderSmallSize.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/common/StreakChart/renderTransparent.png b/app/src/androidTest/assets/views/common/StreakChart/renderTransparent.png
deleted file mode 100644
index 4bab05b52..000000000
Binary files a/app/src/androidTest/assets/views/common/StreakChart/renderTransparent.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_explicit_check.png b/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_explicit_check.png
deleted file mode 100644
index 1f53b9ae5..000000000
Binary files a/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_explicit_check.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_implicit_check.png b/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_implicit_check.png
deleted file mode 100644
index 2570ca857..000000000
Binary files a/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_implicit_check.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_unchecked.png b/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_unchecked.png
deleted file mode 100644
index 841cc20e0..000000000
Binary files a/app/src/androidTest/assets/views/habits/list/CheckmarkButtonView/render_unchecked.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/list/CheckmarkPanelView/render.png b/app/src/androidTest/assets/views/habits/list/CheckmarkPanelView/render.png
deleted file mode 100644
index 00b87e88e..000000000
Binary files a/app/src/androidTest/assets/views/habits/list/CheckmarkPanelView/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/list/HabitCardView/render.png b/app/src/androidTest/assets/views/habits/list/HabitCardView/render.png
deleted file mode 100644
index 9144a5077..000000000
Binary files a/app/src/androidTest/assets/views/habits/list/HabitCardView/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/list/HabitCardView/render_changed.png b/app/src/androidTest/assets/views/habits/list/HabitCardView/render_changed.png
deleted file mode 100644
index 4533ccec4..000000000
Binary files a/app/src/androidTest/assets/views/habits/list/HabitCardView/render_changed.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/list/HabitCardView/render_selected.png b/app/src/androidTest/assets/views/habits/list/HabitCardView/render_selected.png
deleted file mode 100644
index 97b15373d..000000000
Binary files a/app/src/androidTest/assets/views/habits/list/HabitCardView/render_selected.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/show/FrequencyCard/render.png b/app/src/androidTest/assets/views/habits/show/FrequencyCard/render.png
deleted file mode 100644
index 1e050904c..000000000
Binary files a/app/src/androidTest/assets/views/habits/show/FrequencyCard/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/show/HistoryCard/render.png b/app/src/androidTest/assets/views/habits/show/HistoryCard/render.png
deleted file mode 100644
index 7cde393d2..000000000
Binary files a/app/src/androidTest/assets/views/habits/show/HistoryCard/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/show/OverviewCard/render.png b/app/src/androidTest/assets/views/habits/show/OverviewCard/render.png
deleted file mode 100644
index d3f6cb13c..000000000
Binary files a/app/src/androidTest/assets/views/habits/show/OverviewCard/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/show/ScoreCard/render.png b/app/src/androidTest/assets/views/habits/show/ScoreCard/render.png
deleted file mode 100644
index e604ba958..000000000
Binary files a/app/src/androidTest/assets/views/habits/show/ScoreCard/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/show/StreakCard/render.png b/app/src/androidTest/assets/views/habits/show/StreakCard/render.png
deleted file mode 100644
index eca454e71..000000000
Binary files a/app/src/androidTest/assets/views/habits/show/StreakCard/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/habits/show/SubtitleCard/render.png b/app/src/androidTest/assets/views/habits/show/SubtitleCard/render.png
deleted file mode 100644
index 7e17a10b3..000000000
Binary files a/app/src/androidTest/assets/views/habits/show/SubtitleCard/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png b/app/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png
deleted file mode 100644
index 9f497ed59..000000000
Binary files a/app/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png b/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png
deleted file mode 100644
index 1437a510b..000000000
Binary files a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/implicitly_checked.png b/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/implicitly_checked.png
deleted file mode 100644
index 97fdcbd19..000000000
Binary files a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/implicitly_checked.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png b/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png
deleted file mode 100644
index bcc1fcf9b..000000000
Binary files a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/unchecked.png b/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/unchecked.png
deleted file mode 100644
index 2f64db223..000000000
Binary files a/app/src/androidTest/assets/views/widgets/CheckmarkWidgetView/unchecked.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/FrequencyWidget/render.png b/app/src/androidTest/assets/views/widgets/FrequencyWidget/render.png
deleted file mode 100644
index d32b9b837..000000000
Binary files a/app/src/androidTest/assets/views/widgets/FrequencyWidget/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/HistoryWidget/render.png b/app/src/androidTest/assets/views/widgets/HistoryWidget/render.png
deleted file mode 100644
index ce30793a7..000000000
Binary files a/app/src/androidTest/assets/views/widgets/HistoryWidget/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/ScoreWidget/render.png b/app/src/androidTest/assets/views/widgets/ScoreWidget/render.png
deleted file mode 100644
index 382bb867d..000000000
Binary files a/app/src/androidTest/assets/views/widgets/ScoreWidget/render.png and /dev/null differ
diff --git a/app/src/androidTest/assets/views/widgets/StreakWidget/render.png b/app/src/androidTest/assets/views/widgets/StreakWidget/render.png
deleted file mode 100644
index 7aa31f345..000000000
Binary files a/app/src/androidTest/assets/views/widgets/StreakWidget/render.png and /dev/null differ
diff --git a/app/src/androidTest/java/org/isoron/uhabits/BaseViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/BaseViewTest.java
deleted file mode 100644
index f01b0f969..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/BaseViewTest.java
+++ /dev/null
@@ -1,246 +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;
-
-import android.graphics.*;
-import android.os.*;
-import android.support.annotation.*;
-import android.view.*;
-import android.widget.*;
-
-import org.isoron.uhabits.utils.*;
-import org.isoron.uhabits.widgets.*;
-
-import java.io.*;
-
-import static android.view.View.MeasureSpec.*;
-import static junit.framework.Assert.*;
-
-public class BaseViewTest extends BaseAndroidTest
-{
- protected static final double DEFAULT_SIMILARITY_CUTOFF = 0.09;
-
- public static final int HISTOGRAM_BIN_SIZE = 8;
-
- private double similarityCutoff;
-
- @Override
- public void setUp()
- {
- super.setUp();
- similarityCutoff = DEFAULT_SIMILARITY_CUTOFF;
- }
-
- protected void assertRenders(View view, String expectedImagePath)
- throws IOException
- {
- StringBuilder errorMessage = new StringBuilder();
- expectedImagePath = getVersionedViewAssetPath(expectedImagePath);
-
- if (view.isLayoutRequested()) measureView(view, view.getMeasuredWidth(),
- view.getMeasuredHeight());
-
- view.setDrawingCacheEnabled(true);
- view.buildDrawingCache();
- Bitmap actual = view.getDrawingCache();
- Bitmap expected = getBitmapFromAssets(expectedImagePath);
-
- int width = actual.getWidth();
- int height = actual.getHeight();
- Bitmap scaledExpected =
- Bitmap.createScaledBitmap(expected, width, height, true);
-
- double distance;
- boolean similarEnough = true;
-
- if ((distance = compareHistograms(getHistogram(actual),
- getHistogram(scaledExpected))) > similarityCutoff)
- {
- similarEnough = false;
- errorMessage.append(String.format(
- "Rendered image has wrong histogram (distance=%f). ",
- distance));
- }
-
- if (!similarEnough)
- {
- saveBitmap(expectedImagePath, ".expected", scaledExpected);
- String path = saveBitmap(expectedImagePath, "", actual);
- errorMessage.append(
- String.format("Actual rendered image saved to %s", path));
- fail(errorMessage.toString());
- }
-
- expected.recycle();
- scaledExpected.recycle();
- }
-
- @NonNull
- protected FrameLayout convertToView(BaseWidget widget,
- int width,
- int height)
- {
- widget.setDimensions(
- new WidgetDimensions(width, height, width, height));
- FrameLayout view = new FrameLayout(targetContext);
- RemoteViews remoteViews = widget.getPortraitRemoteViews();
- view.addView(remoteViews.apply(targetContext, view));
- measureView(view, width, height);
- return view;
- }
-
- protected int dpToPixels(int dp)
- {
- return (int) InterfaceUtils.dpToPixels(targetContext, dp);
- }
-
- protected void measureView(View view, int width, int height)
- {
- int specWidth = makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
- int specHeight = makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
-
- view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
- view.measure(specWidth, specHeight);
- view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
- }
-
- protected void setSimilarityCutoff(double similarityCutoff)
- {
- this.similarityCutoff = similarityCutoff;
- }
-
- protected void skipAnimation(View view)
- {
- ViewPropertyAnimator animator = view.animate();
- animator.setDuration(0);
- animator.start();
- }
-
- protected void tap(GestureDetector.OnGestureListener view, int x, int y)
- throws InterruptedException
- {
- long now = SystemClock.uptimeMillis();
- MotionEvent e =
- MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, dpToPixels(x),
- dpToPixels(y), 0);
- view.onSingleTapUp(e);
- e.recycle();
- }
-
- private double compareHistograms(int[][] actualHistogram,
- int[][] expectedHistogram)
- {
- long diff = 0;
- long total = 0;
-
- for (int i = 0; i < 256 / HISTOGRAM_BIN_SIZE; i++)
- {
- diff += Math.abs(actualHistogram[0][i] - expectedHistogram[0][i]);
- diff += Math.abs(actualHistogram[1][i] - expectedHistogram[1][i]);
- diff += Math.abs(actualHistogram[2][i] - expectedHistogram[2][i]);
- diff += Math.abs(actualHistogram[3][i] - expectedHistogram[3][i]);
-
- total += actualHistogram[0][i];
- total += actualHistogram[1][i];
- total += actualHistogram[2][i];
- total += actualHistogram[3][i];
- }
-
- return (double) diff / total / 2;
- }
-
- private Bitmap getBitmapFromAssets(String path) throws IOException
- {
- InputStream stream = testContext.getAssets().open(path);
- return BitmapFactory.decodeStream(stream);
- }
-
- private int[][] getHistogram(Bitmap bitmap)
- {
- int histogram[][] = new int[4][256 / HISTOGRAM_BIN_SIZE];
-
- for (int x = 0; x < bitmap.getWidth(); x++)
- {
- for (int y = 0; y < bitmap.getHeight(); y++)
- {
- int color = bitmap.getPixel(x, y);
- int[] argb = new int[]{
- (color >> 24) & 0xff, //alpha
- (color >> 16) & 0xff, //red
- (color >> 8) & 0xff, //green
- (color) & 0xff //blue
- };
-
- histogram[0][argb[0] / HISTOGRAM_BIN_SIZE]++;
- histogram[1][argb[1] / HISTOGRAM_BIN_SIZE]++;
- histogram[2][argb[2] / HISTOGRAM_BIN_SIZE]++;
- histogram[3][argb[3] / HISTOGRAM_BIN_SIZE]++;
- }
- }
-
- return histogram;
- }
-
- private String getVersionedViewAssetPath(String path)
- {
- String result = null;
-
- if (android.os.Build.VERSION.SDK_INT >= 21)
- {
- try
- {
- String vpath = "views-v21/" + path;
- testContext.getAssets().open(vpath);
- result = vpath;
- }
- catch (IOException e)
- {
- // ignored
- }
- }
-
- if (result == null) result = "views/" + path;
-
- return result;
- }
-
- private String saveBitmap(String filename, String suffix, Bitmap bitmap)
- throws IOException
- {
- File dir = FileUtils.getSDCardDir("test-screenshots");
- if (dir == null) dir = FileUtils.getFilesDir(targetContext,"test-screenshots");
- if (dir == null) throw new RuntimeException(
- "Could not find suitable dir for screenshots");
-
- filename = filename.replaceAll("\\.png$", suffix + ".png");
- String absolutePath =
- String.format("%s/%s", dir.getAbsolutePath(), filename);
-
- File parent = new File(absolutePath).getParentFile();
- if (!parent.exists() && !parent.mkdirs()) throw new RuntimeException(
- String.format("Could not create dir: %s",
- parent.getAbsolutePath()));
-
- FileOutputStream out = new FileOutputStream(absolutePath);
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
-
- return absolutePath;
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonViewTest.java
deleted file mode 100644
index 53c5fbeeb..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonViewTest.java
+++ /dev/null
@@ -1,187 +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.activities.habits.list.views;
-
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import java.io.*;
-import java.util.concurrent.*;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class CheckmarkButtonViewTest extends BaseViewTest
-{
- public static final String PATH = "habits/list/CheckmarkButtonView/";
-
- private CountDownLatch latch;
-
- private CheckmarkButtonView view;
-
- @Override
- @Before
- public void setUp()
- {
- super.setUp();
- setSimilarityCutoff(0.015f);
-
- latch = new CountDownLatch(1);
- view = new CheckmarkButtonView(targetContext);
- view.setValue(Checkmark.UNCHECKED);
- view.setColor(ColorUtils.getAndroidTestColor(5));
-
- measureView(view, dpToPixels(40), dpToPixels(40));
- }
-
- @Test
- public void testRender_explicitCheck() throws Exception
- {
- view.setValue(Checkmark.CHECKED_EXPLICITLY);
- assertRendersCheckedExplicitly();
- }
-
- @Test
- public void testRender_implicitCheck() throws Exception
- {
- view.setValue(Checkmark.CHECKED_IMPLICITLY);
- assertRendersCheckedImplicitly();
- }
-
- @Test
- public void testRender_unchecked() throws Exception
- {
- view.setValue(Checkmark.UNCHECKED);
- assertRendersUnchecked();
- }
-
- protected void assertRendersCheckedExplicitly() throws IOException
- {
- assertRenders(view, PATH + "render_explicit_check.png");
- }
-
- protected void assertRendersCheckedImplicitly() throws IOException
- {
- assertRenders(view, PATH + "render_implicit_check.png");
- }
-
- protected void assertRendersUnchecked() throws IOException
- {
- assertRenders(view, PATH + "render_unchecked.png");
- }
-
-// @Test
-// public void testLongClick() throws Exception
-// {
-// setOnToggleListener();
-// view.performLongClick();
-// waitForLatch();
-// assertRendersCheckedExplicitly();
-// }
-//
-// @Test
-// public void testClick_withShortToggle_fromUnchecked() throws Exception
-// {
-// Preferences.getInstance().setShortToggleEnabled(true);
-// view.setValue(Checkmark.UNCHECKED);
-// setOnToggleListenerAndPerformClick();
-// assertRendersCheckedExplicitly();
-// }
-//
-// @Test
-// public void testClick_withShortToggle_fromChecked() throws Exception
-// {
-// Preferences.getInstance().setShortToggleEnabled(true);
-// view.setValue(Checkmark.CHECKED_EXPLICITLY);
-// setOnToggleListenerAndPerformClick();
-// assertRendersUnchecked();
-// }
-//
-// @Test
-// public void testClick_withShortToggle_withoutListener() throws Exception
-// {
-// Preferences.getInstance().setShortToggleEnabled(true);
-// view.setValue(Checkmark.CHECKED_EXPLICITLY);
-// view.setController(null);
-// view.performClick();
-// assertRendersUnchecked();
-// }
-//
-// protected void setOnToggleListenerAndPerformClick() throws InterruptedException
-// {
-// setOnToggleListener();
-// view.performClick();
-// waitForLatch();
-// }
-//
-// @Test
-// public void testClick_withoutShortToggle() throws Exception
-// {
-// Preferences.getInstance().setShortToggleEnabled(false);
-// setOnInvalidToggleListener();
-// view.performClick();
-// waitForLatch();
-// assertRendersUnchecked();
-// }
-
-// protected void setOnInvalidToggleListener()
-// {
-// view.setController(new CheckmarkButtonView.Controller()
-// {
-// @Override
-// public void onToggleCheckmark(CheckmarkButtonView view, long timestamp)
-// {
-// fail();
-// }
-//
-// @Override
-// public void onInvalidToggle(CheckmarkButtonView v)
-// {
-// assertThat(v, equalTo(view));
-// latch.countDown();
-// }
-// });
-// }
-
-// protected void setOnToggleListener()
-// {
-// view.setController(new CheckmarkButtonView.Controller()
-// {
-// @Override
-// public void onToggleCheckmark(CheckmarkButtonView v, long t)
-// {
-// assertThat(v, equalTo(view));
-// assertThat(t, equalTo(DateUtils.getStartOfToday()));
-// latch.countDown();
-// }
-//
-// @Override
-// public void onInvalidToggle(CheckmarkButtonView view)
-// {
-// fail();
-// }
-// });
-// }
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.java
deleted file mode 100644
index 30e225a7a..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.java
+++ /dev/null
@@ -1,98 +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.activities.habits.list.views;
-
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.*;
-
-import org.isoron.uhabits.models.Checkmark;
-import org.isoron.uhabits.models.Habit;
-import org.isoron.uhabits.BaseViewTest;
-import org.isoron.uhabits.utils.ColorUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class CheckmarkPanelViewTest extends BaseViewTest
-{
- public static final String PATH = "habits/list/CheckmarkPanelView/";
-
- private CountDownLatch latch;
- private CheckmarkPanelView view;
- private int checkmarks[];
-
- @Override
- @Before
- public void setUp()
- {
- super.setUp();
- setSimilarityCutoff(0.03f);
- prefs.setShouldReverseCheckmarks(false);
-
- Habit habit = fixtures.createEmptyHabit();
-
- latch = new CountDownLatch(1);
- checkmarks = new int[]{
- Checkmark.CHECKED_EXPLICITLY, Checkmark.UNCHECKED,
- Checkmark.CHECKED_IMPLICITLY, Checkmark.CHECKED_EXPLICITLY};
-
- view = new CheckmarkPanelView(targetContext);
- view.setHabit(habit);
- view.setCheckmarkValues(checkmarks);
- view.setButtonCount(4);
- view.setColor(ColorUtils.getAndroidTestColor(7));
-
- measureView(view, dpToPixels(200), dpToPixels(200));
- }
-
-// protected void waitForLatch() throws InterruptedException
-// {
-// assertTrue("Latch timeout", latch.await(1, TimeUnit.SECONDS));
-// }
-
- @Test
- public void testRender() throws Exception
- {
- assertRenders(view, PATH + "render.png");
- }
-
-// @Test
-// public void testToggleCheckmark_withLeftToRight() throws Exception
-// {
-// setToggleListener();
-// view.getButton(1).performToggle();
-// waitForLatch();
-// }
-//
-// @Test
-// public void testToggleCheckmark_withReverseCheckmarks() throws Exception
-// {
-// prefs.setShouldReverseCheckmarks(true);
-// view.setCheckmarkValues(checkmarks); // refresh after preference change
-//
-// setToggleListener();
-// view.getButton(2).performToggle();
-// waitForLatch();
-// }
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HabitCardViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HabitCardViewTest.java
deleted file mode 100644
index 2ca386e18..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HabitCardViewTest.java
+++ /dev/null
@@ -1,91 +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.activities.habits.list.views;
-
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import static org.mockito.Mockito.mock;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class HabitCardViewTest extends BaseViewTest
-{
- private HabitCardView view;
-
- public static final String PATH = "habits/list/HabitCardView/";
-
- private HabitCardView.Controller controller;
-
- private Habit habit;
-
- @Override
- public void setUp()
- {
- super.setUp();
- setTheme(R.style.AppBaseTheme);
-
- habit = fixtures.createLongHabit();
- CheckmarkList checkmarks = habit.getCheckmarks();
-
- long today = DateUtils.getStartOfToday();
- long day = DateUtils.millisecondsInOneDay;
- int[] values = checkmarks.getValues(today - 5 * day, today);
-
- controller = mock(HabitCardView.Controller.class);
-
- view = new HabitCardView(targetContext);
- view.setHabit(habit);
- view.setCheckmarkValues(values);
- view.setSelected(false);
- view.setScore(habit.getScores().getTodayValue());
- view.setController(controller);
- measureView(view, dpToPixels(400), dpToPixels(50));
- }
-
- @Test
- public void testRender() throws Exception
- {
- assertRenders(view, PATH + "render.png");
- }
-
- @Test
- public void testRender_selected() throws Exception
- {
- view.setSelected(true);
- measureView(view, dpToPixels(400), dpToPixels(50));
- assertRenders(view, PATH + "render_selected.png");
- }
-
- @Test
- public void testChangeModel() throws Exception
- {
- habit.setName("Wake up early");
- habit.setColor(2);
- habit.getObservable().notifyListeners();
- assertRenders(view, PATH + "render_changed.png");
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/espresso/HabitMatchers.java b/app/src/androidTest/java/org/isoron/uhabits/espresso/HabitMatchers.java
deleted file mode 100644
index b3fae7c1b..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/espresso/HabitMatchers.java
+++ /dev/null
@@ -1,100 +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.espresso;
-
-import android.preference.Preference;
-import android.view.View;
-import android.widget.Adapter;
-import android.widget.AdapterView;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-import org.isoron.uhabits.models.Habit;
-
-public class HabitMatchers
-{
- public static Matcher withName(final String name)
- {
- return new TypeSafeMatcher()
- {
- @Override
- public boolean matchesSafely(Habit habit)
- {
- return habit.getName().equals(name);
- }
-
- @Override
- public void describeTo(Description description)
- {
- description.appendText("name should be ").appendText(name);
- }
-
- @Override
- public void describeMismatchSafely(Habit habit, Description description)
- {
- description.appendText("was ").appendText(habit.getName());
- }
- };
- }
-
- public static Matcher containsHabit(final Matcher matcher)
- {
- return new TypeSafeMatcher()
- {
- @Override
- protected boolean matchesSafely(View view)
- {
- Adapter adapter = ((AdapterView) view).getAdapter();
- for (int i = 0; i < adapter.getCount(); i++)
- if (matcher.matches(adapter.getItem(i))) return true;
-
- return false;
- }
-
- @Override
- public void describeTo(Description description)
- {
- description.appendText("with class name: ");
- matcher.describeTo(description);
- }
- };
- }
-
- public static Matcher> isPreferenceWithText(final String text)
- {
- return (Matcher>) new BaseMatcher()
- {
- @Override
- public boolean matches(Object o)
- {
- if(!(o instanceof Preference)) return false;
- return o.toString().contains(text);
- }
-
- @Override
- public void describeTo(Description description)
- {
- description.appendText(String.format("is preference with text '%s'", text));
- }
- };
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/espresso/HabitViewActions.java b/app/src/androidTest/java/org/isoron/uhabits/espresso/HabitViewActions.java
deleted file mode 100644
index 156e3bea8..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/espresso/HabitViewActions.java
+++ /dev/null
@@ -1,131 +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.espresso;
-
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
-import android.support.test.espresso.action.GeneralLocation;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Tap;
-import android.support.test.espresso.matcher.ViewMatchers;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import org.hamcrest.Matcher;
-import org.isoron.uhabits.R;
-
-import java.security.InvalidParameterException;
-import java.util.Random;
-
-public class HabitViewActions
-{
- public static ViewAction toggleAllCheckmarks()
- {
- final GeneralClickAction clickAction =
- new GeneralClickAction(Tap.LONG, GeneralLocation.CENTER, Press.FINGER);
-
- return new ViewAction()
- {
- @Override
- public Matcher getConstraints()
- {
- return ViewMatchers.isDisplayed();
- }
-
- @Override
- public String getDescription()
- {
- return "toggleAllCheckmarks";
- }
-
- @Override
- public void perform(UiController uiController, View view)
- {
- if (view.getId() != R.id.checkmarkPanel)
- throw new InvalidParameterException("View must have id llButtons");
-
- LinearLayout llButtons = (LinearLayout) view;
- int count = llButtons.getChildCount();
-
- for (int i = 0; i < count; i++)
- {
- TextView tvButton = (TextView) llButtons.getChildAt(i);
- clickAction.perform(uiController, tvButton);
- }
- }
- };
- }
-
- public static ViewAction clickAt(final int x, final int y)
- {
- return new GeneralClickAction(Tap.SINGLE, new CoordinatesProvider()
- {
- @Override
- public float[] calculateCoordinates(View view)
- {
- int[] locations = new int[2];
- view.getLocationOnScreen(locations);
-
- final float locationX = locations[0] + x;
- final float locationY = locations[1] + y;
-
- return new float[]{locationX, locationY};
- }
- }, Press.FINGER);
- }
-
- public static ViewAction clickAtRandomLocations(final int count)
- {
- return new ViewAction()
- {
- @Override
- public Matcher getConstraints()
- {
- return ViewMatchers.isDisplayed();
- }
-
- @Override
- public String getDescription()
- {
- return "clickAtRandomLocations";
- }
-
- @Override
- public void perform(UiController uiController, View view)
- {
- int width = view.getWidth();
- int height = view.getHeight();
- Random random = new Random();
-
- for(int i = 0; i < count; i++)
- {
- int x = random.nextInt(width);
- int y = random.nextInt(height);
-
- ViewAction action = clickAt(x, y);
- action.perform(uiController, view);
- }
- }
- };
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/espresso/MainActivityActions.java b/app/src/androidTest/java/org/isoron/uhabits/espresso/MainActivityActions.java
deleted file mode 100644
index c03e9c9db..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/espresso/MainActivityActions.java
+++ /dev/null
@@ -1,199 +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.espresso;
-
-import android.support.test.espresso.*;
-import android.support.test.espresso.contrib.*;
-
-import org.hamcrest.*;
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.models.*;
-
-import java.util.*;
-
-import static android.support.test.espresso.Espresso.*;
-import static android.support.test.espresso.Espresso.pressBack;
-import static android.support.test.espresso.action.ViewActions.*;
-import static android.support.test.espresso.assertion.ViewAssertions.*;
-import static android.support.test.espresso.matcher.RootMatchers.*;
-import static android.support.test.espresso.matcher.ViewMatchers.Visibility.*;
-import static android.support.test.espresso.matcher.ViewMatchers.*;
-import static org.hamcrest.Matchers.*;
-
-public class MainActivityActions
-{
- public static String addHabit()
- {
- return addHabit(false);
- }
-
- public static String addHabit(boolean openDialogs)
- {
- String name = "New Habit " + new Random().nextInt(1000000);
- String description = "Did you perform your new habit today?";
- String num = "4";
- String den = "8";
-
- onView(withId(R.id.actionAdd)).perform(click());
-
- typeHabitData(name, description, num, den);
-
- if (openDialogs)
- {
- onView(withId(R.id.buttonPickColor)).perform(click());
- pressBack();
- onView(withId(R.id.tvReminderTime)).perform(click());
- onView(withText("Done")).perform(click());
- onView(withId(R.id.tvReminderDays)).perform(click());
- onView(withText("OK")).perform(click());
- }
-
- onView(withId(R.id.buttonSave)).perform(click());
-
- onData(Matchers.allOf(is(instanceOf(Habit.class)),
- HabitMatchers.withName(name))).onChildView(withId(R.id.label));
-
- return name;
- }
-
- public static void assertHabitExists(String name)
- {
- List names = new LinkedList<>();
- names.add(name);
- assertHabitsExist(names);
- }
-
- public static void assertHabitsDontExist(List names)
- {
- for (String name : names)
- onView(withId(R.id.listView)).check(matches(Matchers.not(
- HabitMatchers.containsHabit(HabitMatchers.withName(name)))));
- }
-
- public static void assertHabitsExist(List names)
- {
- for (String name : names)
- onData(Matchers.allOf(is(instanceOf(Habit.class)),
- HabitMatchers.withName(name))).check(matches(isDisplayed()));
- }
-
- private static void clickHiddenMenuItem(int stringId)
- {
- try
- {
- // Try the ActionMode overflow menu first
- onView(allOf(withContentDescription("More options"), withParent(
- withParent(withClassName(containsString("Action")))))).perform(
- click());
- }
- catch (Exception e1)
- {
- // Try the toolbar overflow menu
- onView(allOf(withContentDescription("More options"), withParent(
- withParent(withClassName(containsString("Toolbar")))))).perform(
- click());
- }
-
- onView(withText(stringId)).perform(click());
- }
-
- public static void clickMenuItem(int stringId)
- {
- try
- {
- onView(withText(stringId)).perform(click());
- }
- catch (Exception e1)
- {
- try
- {
- onView(withContentDescription(stringId)).perform(click());
- }
- catch (Exception e2)
- {
- clickHiddenMenuItem(stringId);
- }
- }
- }
-
- public static void clickSettingsItem(String text)
- {
- onView(withClassName(containsString("RecyclerView"))).perform(
- RecyclerViewActions.actionOnItem(
- hasDescendant(withText(containsString(text))), click()));
- }
-
- public static void deleteHabit(String name)
- {
- deleteHabits(Collections.singletonList(name));
- }
-
- public static void deleteHabits(List names)
- {
- selectHabits(names);
- clickMenuItem(R.string.delete);
- onView(withText("OK")).perform(click());
- assertHabitsDontExist(names);
- }
-
- public static void selectHabit(String name)
- {
- selectHabits(Collections.singletonList(name));
- }
-
- public static void selectHabits(List names)
- {
- boolean first = true;
- for (String name : names)
- {
- onData(Matchers.allOf(is(instanceOf(Habit.class)),
- HabitMatchers.withName(name)))
- .onChildView(withId(R.id.label))
- .perform(first ? longClick() : click());
-
- first = false;
- }
- }
-
- public static void typeHabitData(String name,
- String description,
- String num,
- String den)
- {
- onView(withId(R.id.tvName)).perform(replaceText(name));
- onView(withId(R.id.tvDescription)).perform(replaceText(description));
-
- try
- {
- onView(allOf(withId(R.id.sFrequency),
- withEffectiveVisibility(VISIBLE))).perform(click());
- onData(allOf(instanceOf(String.class), startsWith("Custom")))
- .inRoot(isPlatformPopup())
- .perform(click());
- }
- catch (NoMatchingViewException e)
- {
- // ignored
- }
-
- onView(withId(R.id.tvFreqNum)).perform(replaceText(num));
- onView(withId(R.id.tvFreqDen)).perform(replaceText(den));
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/espresso/MainTest.java b/app/src/androidTest/java/org/isoron/uhabits/espresso/MainTest.java
deleted file mode 100644
index ea31c54c7..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/espresso/MainTest.java
+++ /dev/null
@@ -1,317 +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.espresso;
-
-import android.app.*;
-import android.content.*;
-import android.support.test.*;
-import android.support.test.espresso.*;
-import android.support.test.espresso.intent.rule.*;
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import org.hamcrest.*;
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.activities.habits.list.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import java.util.*;
-
-import static android.support.test.espresso.Espresso.*;
-import static android.support.test.espresso.Espresso.pressBack;
-import static android.support.test.espresso.action.ViewActions.*;
-import static android.support.test.espresso.assertion.ViewAssertions.*;
-import static android.support.test.espresso.intent.Intents.*;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.*;
-import static android.support.test.espresso.matcher.ViewMatchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.isoron.uhabits.espresso.HabitViewActions.*;
-import static org.isoron.uhabits.espresso.MainActivityActions.*;
-import static org.isoron.uhabits.espresso.ShowHabitActivityActions.*;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class MainTest
-{
- private SystemHelper sys;
-
- @Rule
- public IntentsTestRule activityRule =
- new IntentsTestRule<>(ListHabitsActivity.class);
-
- @Before
- public void setup()
- {
- Context context =
- InstrumentationRegistry.getInstrumentation().getContext();
- sys = new SystemHelper(context);
- sys.disableAllAnimations();
- sys.acquireWakeLock();
- sys.unlockScreen();
-
- Instrumentation.ActivityResult okResult =
- new Instrumentation.ActivityResult(Activity.RESULT_OK,
- new Intent());
-
- intending(hasAction(equalTo(Intent.ACTION_SEND))).respondWith(okResult);
- intending(hasAction(equalTo(Intent.ACTION_SENDTO))).respondWith(
- okResult);
- intending(hasAction(equalTo(Intent.ACTION_VIEW))).respondWith(okResult);
-
- skipTutorial();
- }
-
- public void skipTutorial()
- {
- try
- {
- for (int i = 0; i < 10; i++)
- onView(allOf(withClassName(endsWith("AppCompatImageButton")),
- isDisplayed())).perform(click());
- }
- catch (NoMatchingViewException e)
- {
- // ignored
- }
- }
-
- @After
- public void tearDown()
- {
- sys.releaseWakeLock();
- }
-
- /**
- * User opens menu, clicks about, sees about screen.
- */
- @Test
- public void testAbout()
- {
- clickMenuItem(R.string.about);
- onView(isRoot()).perform(swipeUp());
- }
-
- /**
- * User creates a habit, toggles a bunch of checkmarks, clicks the habit to
- * open the statistics screen, scrolls down to some views, then scrolls the
- * views backwards and forwards in time.
- */
- @Test
- public void testAddHabitAndViewStats() throws InterruptedException
- {
- String name = addHabit(true);
-
- onData(Matchers.allOf(is(instanceOf(Habit.class)),
- HabitMatchers.withName(name)))
- .onChildView(withId(R.id.checkmarkPanel))
- .perform(toggleAllCheckmarks());
-
- Thread.sleep(1200);
-
- onData(Matchers.allOf(is(instanceOf(Habit.class)),
- HabitMatchers.withName(name)))
- .onChildView(withId(R.id.label))
- .perform(click());
-
- onView(withId(R.id.scoreView)).perform(scrollTo(), swipeRight());
-
- onView(withId(R.id.frequencyChart)).perform(scrollTo(), swipeRight());
- }
-
- /**
- * User opens the app, clicks the add button, types some bogus information,
- * tries to save, dialog displays an error.
- */
- @Test
- public void testAddInvalidHabit()
- {
- onView(withId(R.id.actionAdd)).perform(click());
-
- typeHabitData("", "", "15", "7");
-
- onView(withId(R.id.buttonSave)).perform(click());
- onView(withId(R.id.tvName)).check(matches(isDisplayed()));
- }
-
- /**
- * User opens the app, creates some habits, selects them, archives them,
- * select 'show archived' on the menu, selects the previously archived
- * habits and then deletes them.
- */
- @Test
- public void testArchiveHabits()
- {
- List names = new LinkedList<>();
-
- for (int i = 0; i < 3; i++)
- names.add(addHabit());
-
- selectHabits(names);
-
- clickMenuItem(R.string.archive);
- assertHabitsDontExist(names);
-
- clickMenuItem(R.string.hide_archived);
-
- assertHabitsExist(names);
- selectHabits(names);
- clickMenuItem(R.string.unarchive);
-
- clickMenuItem(R.string.hide_archived);
-
- assertHabitsExist(names);
- deleteHabits(names);
- }
-
- /**
- * User creates a habit, selects the habit, clicks edit button, changes some
- * information about the habit, click save button, sees changes on the main
- * window, selects habit again, changes color, then deletes the habit.
- */
- @Test
- public void testEditHabit()
- {
- String name = addHabit();
-
- onData(Matchers.allOf(is(instanceOf(Habit.class)),
- HabitMatchers.withName(name)))
- .onChildView(withId(R.id.label))
- .perform(longClick());
-
- clickMenuItem(R.string.edit);
-
- String modifiedName = "Modified " + new Random().nextInt(10000);
- typeHabitData(modifiedName, "", "1", "1");
-
- onView(withId(R.id.buttonSave)).perform(click());
-
- assertHabitExists(modifiedName);
-
- selectHabit(modifiedName);
- clickMenuItem(R.string.color_picker_default_title);
- pressBack();
-
- deleteHabit(modifiedName);
- }
-
- /**
- * User creates a habit, opens statistics page, clicks button to edit
- * history, adds some checkmarks, closes dialog, sees the modified history
- * calendar.
- */
- @Test
- public void testEditHistory()
- {
- String name = addHabit();
-
- onData(Matchers.allOf(is(instanceOf(Habit.class)),
- HabitMatchers.withName(name)))
- .onChildView(withId(R.id.label))
- .perform(click());
-
- openHistoryEditor();
- onView(withClassName(endsWith("HabitHistoryView"))).perform(
- clickAtRandomLocations(20));
-
- pressBack();
- onView(withId(R.id.historyChart)).perform(scrollTo(), swipeRight(),
- swipeLeft());
- }
-
- /**
- * User creates a habit, opens settings, clicks export as CSV, is asked what
- * activity should handle the file.
- */
- @Test
- public void testExportCSV()
- {
- addHabit();
- clickMenuItem(R.string.settings);
- clickSettingsItem("Export as CSV");
- intended(hasAction(Intent.ACTION_SEND));
- }
-
- /**
- * User creates a habit, exports full backup, deletes the habit, restores
- * backup, sees that the previously created habit has appeared back.
- */
- @Test
- public void testExportImportDB()
- {
- String name = addHabit();
-
- clickMenuItem(R.string.settings);
-
- String date =
- DateFormats.getBackupDateFormat().format(DateUtils.getLocalTime());
- date = date.substring(0, date.length() - 2);
-
- clickSettingsItem("Export full backup");
- intended(hasAction(Intent.ACTION_SEND));
-
- deleteHabit(name);
-
- clickMenuItem(R.string.settings);
- clickSettingsItem("Import data");
-
- onData(
- allOf(is(instanceOf(String.class)), startsWith("Backups"))).perform(
- click());
-
- onData(
- allOf(is(instanceOf(String.class)), containsString(date))).perform(
- click());
-
- selectHabit(name);
- }
-
- /**
- * User opens the settings and generates a bug report.
- */
- @Test
- public void testGenerateBugReport()
- {
- clickMenuItem(R.string.settings);
- clickSettingsItem("Generate bug report");
- intended(hasAction(Intent.ACTION_SEND));
- }
-
- /**
- * User opens menu, clicks Help, sees website.
- */
- @Test
- public void testHelp()
- {
- clickMenuItem(R.string.help);
- intended(hasAction(Intent.ACTION_VIEW));
- }
-
- /**
- * User opens menu, clicks settings, sees settings screen.
- */
- @Test
- public void testSettings()
- {
- clickMenuItem(R.string.settings);
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/espresso/SystemHelper.java b/app/src/androidTest/java/org/isoron/uhabits/espresso/SystemHelper.java
deleted file mode 100644
index 6fb12fede..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/espresso/SystemHelper.java
+++ /dev/null
@@ -1,124 +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.espresso;
-
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.IBinder;
-import android.os.PowerManager;
-import android.support.test.runner.AndroidJUnitRunner;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-
-public final class SystemHelper extends AndroidJUnitRunner
-{
- private static final String ANIMATION_PERMISSION = "android.permission.SET_ANIMATION_SCALE";
- private static final float DISABLED = 0.0f;
- private static final float DEFAULT = 1.0f;
-
- private final Context context;
- private PowerManager.WakeLock wakeLock;
-
- SystemHelper(Context context)
- {
- this.context = context;
- }
-
- void acquireWakeLock()
- {
- PowerManager power = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- wakeLock = power.newWakeLock(PowerManager.FULL_WAKE_LOCK |
- PowerManager.ACQUIRE_CAUSES_WAKEUP |
- PowerManager.ON_AFTER_RELEASE, getClass().getSimpleName());
- wakeLock.acquire();
- }
-
- void releaseWakeLock()
- {
- if(wakeLock != null)
- wakeLock.release();
- }
-
- void unlockScreen()
- {
- Log.i("SystemHelper", "Trying to unlock screen");
- try
- {
- KeyguardManager mKeyGuardManager =
- (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
- KeyguardManager.KeyguardLock mLock = mKeyGuardManager.newKeyguardLock("lock");
- mLock.disableKeyguard();
- Log.e("SystemHelper", "Successfully unlocked screen");
- } catch (Exception e)
- {
- Log.e("SystemHelper", "Could not unlock screen");
- e.printStackTrace();
- }
- }
-
- void disableAllAnimations()
- {
- Log.i("SystemHelper", "Trying to disable animations");
- int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION);
- if (permStatus == PackageManager.PERMISSION_GRANTED) setSystemAnimationsScale(DISABLED);
- else Log.e("SystemHelper", "Permission denied");
-
- }
-
- void enableAllAnimations()
- {
- int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION);
- if (permStatus == PackageManager.PERMISSION_GRANTED)
- {
- setSystemAnimationsScale(DEFAULT);
- }
- }
-
- private void setSystemAnimationsScale(float animationScale)
- {
- try
- {
- Class> windowManagerStubClazz = Class.forName("android.view.IWindowManager$Stub");
- Method asInterface =
- windowManagerStubClazz.getDeclaredMethod("asInterface", IBinder.class);
- Class> serviceManagerClazz = Class.forName("android.os.ServiceManager");
- Method getService = serviceManagerClazz.getDeclaredMethod("getService", String.class);
- Class> windowManagerClazz = Class.forName("android.view.IWindowManager");
- Method setAnimationScales =
- windowManagerClazz.getDeclaredMethod("setAnimationScales", float[].class);
- Method getAnimationScales = windowManagerClazz.getDeclaredMethod("getAnimationScales");
-
- IBinder windowManagerBinder = (IBinder) getService.invoke(null, "window");
- Object windowManagerObj = asInterface.invoke(null, windowManagerBinder);
- float[] currentScales = (float[]) getAnimationScales.invoke(windowManagerObj);
- for (int i = 0; i < currentScales.length; i++)
- currentScales[i] = animationScale;
-
- setAnimationScales.invoke(windowManagerObj, new Object[]{currentScales});
- Log.i("SystemHelper", "All animations successfully disabled");
- }
- catch (Exception e)
- {
- Log.e("SystemHelper", "Could not change animation scale to " + animationScale + " :'(");
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/org/isoron/uhabits/models/HabitListTest.java b/app/src/androidTest/java/org/isoron/uhabits/models/HabitListTest.java
deleted file mode 100644
index 92f71a3f4..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/models/HabitListTest.java
+++ /dev/null
@@ -1,240 +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.models;
-
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import org.hamcrest.*;
-import org.isoron.uhabits.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import java.io.*;
-import java.util.*;
-
-import static junit.framework.Assert.*;
-import static org.hamcrest.CoreMatchers.*;
-import static org.hamcrest.MatcherAssert.*;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.isoron.uhabits.models.HabitList.Order.*;
-
-@SuppressWarnings("JavaDoc")
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class HabitListTest extends BaseAndroidTest
-{
- private ArrayList habitsArray;
-
- private HabitList activeHabits;
-
- private HabitList reminderHabits;
-
- @Override
- public void setUp()
- {
- super.setUp();
- habitList.removeAll();
-
- habitsArray = new ArrayList<>();
-
- for (int i = 0; i < 10; i++)
- {
- Habit habit = fixtures.createEmptyHabit((long) i);
- habitsArray.add(habit);
-
- if (i % 3 == 0)
- habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
-
- habitList.update(habit);
- }
-
- habitsArray.get(0).setArchived(true);
- habitsArray.get(1).setArchived(true);
- habitsArray.get(4).setArchived(true);
- habitsArray.get(7).setArchived(true);
-
- activeHabits = habitList.getFiltered(new HabitMatcherBuilder().build());
-
- reminderHabits = habitList.getFiltered(new HabitMatcherBuilder()
- .setArchivedAllowed(true)
- .setReminderRequired(true)
- .build());
- }
-
- @Test
- public void test_size()
- {
- assertThat(habitList.size(), equalTo(10));
- }
-
- @Test
- public void test_countActive()
- {
- assertThat(activeHabits.size(), equalTo(6));
- }
-
- @Test
- public void test_getByPosition()
- {
- assertThat(habitList.getByPosition(0), equalTo(habitsArray.get(0)));
- assertThat(habitList.getByPosition(3), equalTo(habitsArray.get(3)));
- assertThat(habitList.getByPosition(9), equalTo(habitsArray.get(9)));
-
- assertThat(activeHabits.getByPosition(0), equalTo(habitsArray.get(2)));
- }
-
- @Test
- public void test_getHabitsWithReminder()
- {
- assertThat(reminderHabits.size(), equalTo(4));
- assertThat(reminderHabits.getByPosition(1),
- equalTo(habitsArray.get(3)));
- }
-
- @Test
- public void test_get_withInvalidId()
- {
- assertThat(habitList.getById(100L), is(nullValue()));
- }
-
- @Test
- public void test_get_withValidId()
- {
- Habit habit1 = habitsArray.get(0);
- Habit habit2 = habitList.getById(habit1.getId());
- assertThat(habit1, equalTo(habit2));
- }
-
- @Test
- public void test_reorder()
- {
- int operations[][] = {
- { 5, 2 }, { 3, 7 }, { 4, 4 }, { 3, 2 }
- };
-
- int expectedPosition[][] = {
- { 0, 1, 3, 4, 5, 2, 6, 7, 8, 9 },
- { 0, 1, 7, 3, 4, 2, 5, 6, 8, 9 },
- { 0, 1, 7, 3, 4, 2, 5, 6, 8, 9 },
- { 0, 1, 7, 2, 4, 3, 5, 6, 8, 9 },
- };
-
- for (int i = 0; i < operations.length; i++)
- {
- int from = operations[i][0];
- int to = operations[i][1];
-
- Habit fromHabit = habitList.getByPosition(from);
- Habit toHabit = habitList.getByPosition(to);
- habitList.reorder(fromHabit, toHabit);
-
- int actualPositions[] = new int[10];
-
- for (int j = 0; j < 10; j++)
- {
- Habit h = habitList.getById(j);
- assertNotNull(h);
- actualPositions[j] = habitList.indexOf(h);
- }
-
- assertThat(actualPositions, equalTo(expectedPosition[i]));
- }
- }
-
- @Test
- public void test_writeCSV() throws IOException
- {
- habitList.removeAll();
-
- Habit h1 = fixtures.createEmptyHabit();
- h1.setName("Meditate");
- h1.setDescription("Did you meditate this morning?");
- h1.setFrequency(Frequency.DAILY);
- h1.setColor(3);
-
- Habit h2 = fixtures.createEmptyHabit();
- h2.setName("Wake up early");
- h2.setDescription("Did you wake up before 6am?");
- h2.setFrequency(new Frequency(2, 3));
- h2.setColor(5);
-
- habitList.update(h1);
- habitList.update(h2);
-
- String expectedCSV =
- "Position,Name,Description,NumRepetitions,Interval,Color\n" +
- "001,Meditate,Did you meditate this morning?,1,1,#AFB42B\n" +
- "002,Wake up early,Did you wake up before 6am?,2,3,#00897B\n";
-
- StringWriter writer = new StringWriter();
- habitList.writeCSV(writer);
-
- MatcherAssert.assertThat(writer.toString(), equalTo(expectedCSV));
- }
-
- @Test
- public void test_ordering()
- {
- habitList.removeAll();
-
- Habit h3 = fixtures.createEmptyHabit();
- h3.setName("C Habit");
- h3.setColor(0);
- habitList.update(h3);
-
- Habit h1 = fixtures.createEmptyHabit();
- h1.setName("A Habit");
- h1.setColor(2);
- habitList.update(h1);
-
- Habit h4 = fixtures.createEmptyHabit();
- h4.setName("D Habit");
- h4.setColor(1);
- habitList.update(h4);
-
- Habit h2 = fixtures.createEmptyHabit();
- h2.setName("B Habit");
- h2.setColor(2);
- habitList.update(h2);
-
- habitList.setOrder(BY_POSITION);
- assertThat(habitList.getByPosition(0), equalTo(h3));
- assertThat(habitList.getByPosition(1), equalTo(h1));
- assertThat(habitList.getByPosition(2), equalTo(h4));
- assertThat(habitList.getByPosition(3), equalTo(h2));
-
- habitList.setOrder(BY_NAME);
- assertThat(habitList.getByPosition(0), equalTo(h1));
- assertThat(habitList.getByPosition(1), equalTo(h2));
- assertThat(habitList.getByPosition(2), equalTo(h3));
- assertThat(habitList.getByPosition(3), equalTo(h4));
-
- habitList.remove(h1);
- habitList.add(h1);
- assertThat(habitList.getByPosition(0), equalTo(h1));
-
- habitList.setOrder(BY_COLOR);
- assertThat(habitList.getByPosition(0), equalTo(h3));
- assertThat(habitList.getByPosition(1), equalTo(h4));
- assertThat(habitList.getByPosition(2), equalTo(h1));
- assertThat(habitList.getByPosition(3), equalTo(h2));
- }
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/HabitRecordTest.java b/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/HabitRecordTest.java
deleted file mode 100644
index d701056df..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/HabitRecordTest.java
+++ /dev/null
@@ -1,87 +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.models.sqlite;
-
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.records.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import static org.hamcrest.MatcherAssert.*;
-import static org.hamcrest.core.IsEqual.*;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class HabitRecordTest extends BaseAndroidTest
-{
- @Override
- public void setUp()
- {
- super.setUp();
-
- Habit h = component.getModelFactory().buildHabit();
- h.setName("Hello world");
- h.setId(1000L);
-
- HabitRecord record = new HabitRecord();
- record.copyFrom(h);
- record.position = 0;
- record.save(1000L);
- }
-
- @Test
- public void testCopyFrom()
- {
- Habit habit = component.getModelFactory().buildHabit();
- habit.setName("Hello world");
- habit.setDescription("Did you greet the world today?");
- habit.setColor(1);
- habit.setArchived(true);
- habit.setFrequency(Frequency.THREE_TIMES_PER_WEEK);
- habit.setReminder(new Reminder(8, 30, WeekdayList.EVERY_DAY));
- habit.setId(1000L);
-
- HabitRecord rec = new HabitRecord();
- rec.copyFrom(habit);
-
- assertThat(rec.name, equalTo(habit.getName()));
- assertThat(rec.description, equalTo(habit.getDescription()));
- assertThat(rec.color, equalTo(habit.getColor()));
- assertThat(rec.archived, equalTo(1));
- assertThat(rec.freqDen, equalTo(7));
- assertThat(rec.freqNum, equalTo(3));
-
- Reminder reminder = habit.getReminder();
- assertThat(rec.reminderDays, equalTo(reminder.getDays().toInteger()));
- assertThat(rec.reminderHour, equalTo(reminder.getHour()));
- assertThat(rec.reminderMin, equalTo(reminder.getMinute()));
-
- habit.setReminder(null);
- rec.copyFrom(habit);
-
- assertThat(rec.reminderMin, equalTo(null));
- assertThat(rec.reminderHour, equalTo(null));
- assertThat(rec.reminderDays, equalTo(0));
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteCheckmarkListTest.java b/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteCheckmarkListTest.java
deleted file mode 100644
index 45efec5e7..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteCheckmarkListTest.java
+++ /dev/null
@@ -1,162 +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.models.sqlite;
-
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import com.activeandroid.query.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.records.*;
-import org.isoron.uhabits.utils.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import java.util.*;
-
-import static org.hamcrest.MatcherAssert.*;
-import static org.hamcrest.Matchers.*;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class SQLiteCheckmarkListTest extends BaseAndroidTest
-{
- private Habit habit;
-
- private CheckmarkList checkmarks;
-
- private long today;
-
- private long day;
-
- @Override
- public void setUp()
- {
- super.setUp();
-
- habit = fixtures.createLongHabit();
- checkmarks = habit.getCheckmarks();
- checkmarks.getToday(); // compute checkmarks
-
- today = DateUtils.getStartOfToday();
- day = DateUtils.millisecondsInOneDay;
- }
-
- @Test
- public void testAdd()
- {
- checkmarks.invalidateNewerThan(0);
-
- List list = new LinkedList<>();
- list.add(new Checkmark(0, 0));
- list.add(new Checkmark(1, 1));
- list.add(new Checkmark(2, 2));
-
- checkmarks.add(list);
-
- List records = getAllRecords();
- assertThat(records.size(), equalTo(3));
- assertThat(records.get(0).timestamp, equalTo(2L));
- }
-
- @Test
- public void testGetByInterval()
- {
- long from = today - 10 * day;
- long to = today - 3 * day;
-
- List list = checkmarks.getByInterval(from, to);
- assertThat(list.size(), equalTo(8));
-
- assertThat(list.get(0).getTimestamp(), equalTo(today - 3 * day));
- assertThat(list.get(3).getTimestamp(), equalTo(today - 6 * day));
- assertThat(list.get(7).getTimestamp(), equalTo(today - 10 * day));
- }
-
- @Test
- public void testGetByInterval_withLongInterval()
- {
- long from = today - 200 * day;
- long to = today;
-
- List list = checkmarks.getByInterval(from, to);
- assertThat(list.size(), equalTo(201));
- }
-
- @Test
- public void testInvalidateNewerThan()
- {
- List records = getAllRecords();
- assertThat(records.size(), equalTo(121));
-
- checkmarks.invalidateNewerThan(today - 20 * day);
-
- records = getAllRecords();
- assertThat(records.size(), equalTo(100));
- assertThat(records.get(0).timestamp, equalTo(today - 21 * day));
- }
-
- @Test
- public void testFixRecords() throws Exception
- {
- long day = DateUtils.millisecondsInOneDay;
- long from = DateUtils.getStartOfToday();
- long to = from + 5 * day;
-
- List original, actual, expected;
- HabitRecord habit = new HabitRecord();
-
- original = new ArrayList<>();
- original.add(new CheckmarkRecord(habit, from + 8*day, 2));
- original.add(new CheckmarkRecord(habit, from + 5*day, 0));
- original.add(new CheckmarkRecord(habit, from + 4*day, 0));
- original.add(new CheckmarkRecord(habit, from + 4*day, 2));
- original.add(new CheckmarkRecord(habit, from + 3*day, 2));
- original.add(new CheckmarkRecord(habit, from + 2*day, 1));
- original.add(new CheckmarkRecord(habit, from + 2*day + 100, 1));
- original.add(new CheckmarkRecord(habit, from, 0));
- original.add(new CheckmarkRecord(habit, from, 2));
- original.add(new CheckmarkRecord(habit, from - day, 2));
-
- actual = SQLiteCheckmarkList.fixRecords(original, habit, from, to);
-
- expected = new ArrayList<>();
- expected.add(new CheckmarkRecord(habit, from + 5*day, 0));
- expected.add(new CheckmarkRecord(habit, from + 4*day, 2));
- expected.add(new CheckmarkRecord(habit, from + 3*day, 2));
- expected.add(new CheckmarkRecord(habit, from + 2*day, 1));
- expected.add(new CheckmarkRecord(habit, from + day, 0));
- expected.add(new CheckmarkRecord(habit, from, 2));
-
- assertThat(actual, equalTo(expected));
- }
-
- private List getAllRecords()
- {
- return new Select()
- .from(CheckmarkRecord.class)
- .where("habit = ?", habit.getId())
- .orderBy("timestamp desc")
- .execute();
- }
-
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteHabitListTest.java b/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteHabitListTest.java
deleted file mode 100644
index 5308fc61c..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteHabitListTest.java
+++ /dev/null
@@ -1,177 +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.models.sqlite;
-
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import com.activeandroid.query.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.records.*;
-import org.junit.*;
-import org.junit.rules.*;
-import org.junit.runner.*;
-
-import java.util.*;
-
-import static junit.framework.Assert.*;
-import static org.hamcrest.MatcherAssert.*;
-import static org.hamcrest.core.IsEqual.*;
-
-@SuppressWarnings("JavaDoc")
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class SQLiteHabitListTest extends BaseAndroidTest
-{
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- private SQLiteHabitList habitList;
-
- private ModelFactory modelFactory;
-
- @Override
- public void setUp()
- {
- super.setUp();
- this.habitList = (SQLiteHabitList) super.habitList;
- fixtures.purgeHabits(habitList);
-
- modelFactory = component.getModelFactory();
-
- for (int i = 0; i < 10; i++)
- {
- Habit h = modelFactory.buildHabit();
- h.setName("habit " + i);
- h.setId((long) i);
- if (i % 2 == 0) h.setArchived(true);
-
- HabitRecord record = new HabitRecord();
- record.copyFrom(h);
- record.position = i;
- record.save(i);
- }
- }
-
- @Test
- public void testAdd_withDuplicate()
- {
- Habit habit = modelFactory.buildHabit();
- habitList.add(habit);
- exception.expect(IllegalArgumentException.class);
- habitList.add(habit);
- }
-
- @Test
- public void testAdd_withId()
- {
- Habit habit = modelFactory.buildHabit();
- habit.setName("Hello world with id");
- habit.setId(12300L);
-
- habitList.add(habit);
- assertThat(habit.getId(), equalTo(12300L));
-
- HabitRecord record = getRecord(12300L);
- assertNotNull(record);
- assertThat(record.name, equalTo(habit.getName()));
- }
-
- @Test
- public void testAdd_withoutId()
- {
- Habit habit = modelFactory.buildHabit();
- habit.setName("Hello world");
- assertNull(habit.getId());
-
- habitList.add(habit);
- assertNotNull(habit.getId());
-
- HabitRecord record = getRecord(habit.getId());
- assertNotNull(record);
- assertThat(record.name, equalTo(habit.getName()));
- }
-
- @Test
- public void testSize()
- {
- assertThat(habitList.size(), equalTo(10));
- }
-
- @Test
- public void testGetAll_withArchived()
- {
- List habits = habitList.toList();
- assertThat(habits.size(), equalTo(10));
- assertThat(habits.get(3).getName(), equalTo("habit 3"));
- }
-
- @Test
- public void testGetById()
- {
- Habit h1 = habitList.getById(0);
- assertNotNull(h1);
- assertThat(h1.getName(), equalTo("habit 0"));
-
- Habit h2 = habitList.getById(0);
- assertNotNull(h2);
- assertThat(h1, equalTo(h2));
- }
-
- @Test
- public void testGetById_withInvalid()
- {
- long invalidId = 9183792001L;
- Habit h1 = habitList.getById(invalidId);
- assertNull(h1);
- }
-
- @Test
- public void testGetByPosition()
- {
- Habit h = habitList.getByPosition(5);
- assertNotNull(h);
- assertThat(h.getName(), equalTo("habit 5"));
- }
-
- @Test
- public void testIndexOf()
- {
- Habit h1 = habitList.getByPosition(5);
- assertNotNull(h1);
- assertThat(habitList.indexOf(h1), equalTo(5));
-
- Habit h2 = modelFactory.buildHabit();
- assertThat(habitList.indexOf(h2), equalTo(-1));
-
- h2.setId(1000L);
- assertThat(habitList.indexOf(h2), equalTo(-1));
- }
-
- private HabitRecord getRecord(long id)
- {
- return new Select()
- .from(HabitRecord.class)
- .where("id = ?", id)
- .executeSingle();
- }
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteRepetitionListTest.java b/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteRepetitionListTest.java
deleted file mode 100644
index 992c1e673..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteRepetitionListTest.java
+++ /dev/null
@@ -1,143 +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.models.sqlite;
-
-import android.support.annotation.*;
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import com.activeandroid.query.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.records.*;
-import org.isoron.uhabits.utils.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import java.util.*;
-
-import static org.hamcrest.MatcherAssert.*;
-import static org.hamcrest.Matchers.*;
-import static org.hamcrest.core.IsNot.not;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class SQLiteRepetitionListTest extends BaseAndroidTest
-{
- private Habit habit;
-
- private long today;
-
- private RepetitionList repetitions;
-
- private long day;
-
- @Override
- public void setUp()
- {
- super.setUp();
-
- habit = fixtures.createLongHabit();
- repetitions = habit.getRepetitions();
- today = DateUtils.getStartOfToday();
- day = DateUtils.millisecondsInOneDay;
- }
-
- @Test
- public void testAdd()
- {
- RepetitionRecord record = getByTimestamp(today + day);
- assertThat(record, is(nullValue()));
-
- Repetition rep = new Repetition(today + day);
- habit.getRepetitions().add(rep);
-
- record = getByTimestamp(today + day);
- assertThat(record, is(not(nullValue())));
- }
-
- @Test
- public void testGetByInterval()
- {
- List reps =
- repetitions.getByInterval(today - 10 * day, today);
-
- assertThat(reps.size(), equalTo(8));
- assertThat(reps.get(0).getTimestamp(), equalTo(today - 10 * day));
- assertThat(reps.get(4).getTimestamp(), equalTo(today - 5 * day));
- assertThat(reps.get(5).getTimestamp(), equalTo(today - 3 * day));
- }
-
- @Test
- public void testGetByTimestamp()
- {
- Repetition rep = repetitions.getByTimestamp(today);
- assertThat(rep, is(not(nullValue())));
- assertThat(rep.getTimestamp(), equalTo(today));
-
- rep = repetitions.getByTimestamp(today - 2 * day);
- assertThat(rep, is(nullValue()));
- }
-
- @Test
- public void testGetOldest()
- {
- Repetition rep = repetitions.getOldest();
- assertThat(rep, is(not(nullValue())));
- assertThat(rep.getTimestamp(), equalTo(today - 120 * day));
- }
-
- @Test
- public void testGetOldest_withEmptyHabit()
- {
- Habit empty = fixtures.createEmptyHabit();
- Repetition rep = empty.getRepetitions().getOldest();
- assertThat(rep, is(nullValue()));
- }
-
- @Test
- public void testRemove()
- {
- RepetitionRecord record = getByTimestamp(today);
- assertThat(record, is(not(nullValue())));
-
- Repetition rep = record.toRepetition();
- repetitions.remove(rep);
-
- record = getByTimestamp(today);
- assertThat(record, is(nullValue()));
- }
-
- @Nullable
- private RepetitionRecord getByTimestamp(long timestamp)
- {
- return selectByTimestamp(timestamp).executeSingle();
- }
-
- @NonNull
- private From selectByTimestamp(long timestamp)
- {
- return new Select()
- .from(RepetitionRecord.class)
- .where("habit = ?", habit.getId())
- .and("timestamp = ?", timestamp);
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteScoreListTest.java b/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteScoreListTest.java
deleted file mode 100644
index a11b7908b..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/models/sqlite/SQLiteScoreListTest.java
+++ /dev/null
@@ -1,156 +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.models.sqlite;
-
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import com.activeandroid.query.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.records.*;
-import org.isoron.uhabits.utils.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import java.util.*;
-
-import static org.hamcrest.MatcherAssert.*;
-import static org.hamcrest.Matchers.*;
-
-@SuppressWarnings("JavaDoc")
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class SQLiteScoreListTest extends BaseAndroidTest
-{
- private Habit habit;
-
- private ScoreList scores;
-
- private long today;
-
- private long day;
-
- @Override
- public void setUp()
- {
- super.setUp();
-
- habit = fixtures.createLongHabit();
- scores = habit.getScores();
-
- today = DateUtils.getStartOfToday();
- day = DateUtils.millisecondsInOneDay;
- }
-
- @Test
- public void testAdd()
- {
- new Delete().from(ScoreRecord.class).execute();
-
- List list = new LinkedList<>();
- list.add(new Score(today, 0));
- list.add(new Score(today - day, 0));
- list.add(new Score(today - 2 * day, 0));
-
- scores.add(list);
-
- List records = getAllRecords();
- assertThat(records.size(), equalTo(3));
- assertThat(records.get(0).timestamp, equalTo(today));
- }
-
- @Test
- public void testGetAll()
- {
- List list = scores.toList();
- assertThat(list.size(), equalTo(121));
- assertThat(list.get(0).getTimestamp(), equalTo(today));
- assertThat(list.get(10).getTimestamp(), equalTo(today - 10 * day));
- }
-
- @Test
- public void testGetByInterval()
- {
- long from = today - 10 * day;
- long to = today - 3 * day;
-
- List list = scores.getByInterval(from, to);
- assertThat(list.size(), equalTo(8));
-
- assertThat(list.get(0).getTimestamp(), equalTo(today - 3 * day));
- assertThat(list.get(3).getTimestamp(), equalTo(today - 6 * day));
- assertThat(list.get(7).getTimestamp(), equalTo(today - 10 * day));
- }
-
- @Test
- public void testGetByInterval_concurrent() throws Exception
- {
- Runnable block1 = () -> scores.invalidateNewerThan(0);
- Runnable block2 =
- () -> assertThat(scores.getByInterval(today, today).size(),
- equalTo(1));
- runConcurrently(block1, block2);
- }
-
- @Test
- public void testGetByInterval_withLongInterval()
- {
- long from = today - 200 * day;
- long to = today;
-
- List list = scores.getByInterval(from, to);
- assertThat(list.size(), equalTo(201));
- }
-
- @Test
- public void testGetTodayValue_concurrent() throws Exception
- {
- Runnable block1 = () -> scores.invalidateNewerThan(0);
- Runnable block2 =
- () -> assertThat(scores.getTodayValue(), equalTo(18407827));
-
- runConcurrently(block1, block2);
- }
-
- @Test
- public void testInvalidateNewerThan()
- {
- scores.getTodayValue(); // force recompute
- List records = getAllRecords();
- assertThat(records.size(), equalTo(121));
-
- scores.invalidateNewerThan(today - 10 * day);
-
- records = getAllRecords();
- assertThat(records.size(), equalTo(110));
- assertThat(records.get(0).timestamp, equalTo(today - 11 * day));
- }
-
- private List getAllRecords()
- {
- return new Select()
- .from(ScoreRecord.class)
- .where("habit = ?", habit.getId())
- .orderBy("timestamp desc")
- .execute();
- }
-}
diff --git a/app/src/androidTest/java/org/isoron/uhabits/receivers/PebbleReceiverTest.java b/app/src/androidTest/java/org/isoron/uhabits/receivers/PebbleReceiverTest.java
deleted file mode 100644
index 631f2d396..000000000
--- a/app/src/androidTest/java/org/isoron/uhabits/receivers/PebbleReceiverTest.java
+++ /dev/null
@@ -1,173 +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.pebble;
-
-import android.content.*;
-import android.support.annotation.*;
-import android.support.test.runner.*;
-import android.test.suitebuilder.annotation.*;
-
-import com.getpebble.android.kit.*;
-import com.getpebble.android.kit.util.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.receivers.*;
-import org.json.*;
-import org.junit.*;
-import org.junit.runner.*;
-
-import static com.getpebble.android.kit.Constants.*;
-import static org.hamcrest.MatcherAssert.*;
-import static org.hamcrest.core.IsEqual.*;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class PebbleReceiverTest extends BaseAndroidTest
-{
-
- private Habit habit1;
-
- private Habit habit2;
-
- @Override
- public void setUp()
- {
- super.setUp();
-
- fixtures.purgeHabits(habitList);
-
- habit1 = fixtures.createEmptyHabit();
- habit1.setName("Exercise");
-
- habit2 = fixtures.createEmptyHabit();
- habit2.setName("Meditate");
- }
-
- @Test
- public void testCount() throws Exception
- {
- onPebbleReceived((dict) -> {
- assertThat(dict.getString(0), equalTo("COUNT"));
- assertThat(dict.getInteger(1), equalTo(2L));
- });
-
- PebbleDictionary dict = buildCountRequest();
- sendFromPebbleToAndroid(dict);
- awaitLatch();
- }
-
- @Test
- public void testFetch() throws Exception
- {
- onPebbleReceived((dict) -> {
- assertThat(dict.getString(0), equalTo("HABIT"));
- assertThat(dict.getInteger(1), equalTo(habit2.getId()));
- assertThat(dict.getString(2), equalTo(habit2.getName()));
- assertThat(dict.getInteger(3), equalTo(0L));
- });
-
- PebbleDictionary dict = buildFetchRequest(1);
- sendFromPebbleToAndroid(dict);
- awaitLatch();
- }
-
-// @Test
-// public void testToggle() throws Exception
-// {
-// int v = habit1.getCheckmarks().getTodayValue();
-// assertThat(v, equalTo(Checkmark.UNCHECKED));
-//
-// onPebbleReceived((dict) -> {
-// assertThat(dict.getString(0), equalTo("OK"));
-// int value = habit1.getCheckmarks().getTodayValue();
-// assertThat(value, equalTo(200)); //Checkmark.CHECKED_EXPLICITLY));
-// });
-//
-// PebbleDictionary dict = buildToggleRequest(habit1.getId());
-// sendFromPebbleToAndroid(dict);
-// awaitLatch();
-// }
-
- @NonNull
- protected PebbleDictionary buildCountRequest()
- {
- PebbleDictionary dict = new PebbleDictionary();
- dict.addString(0, "COUNT");
- return dict;
- }
-
- @NonNull
- protected PebbleDictionary buildFetchRequest(int position)
- {
- PebbleDictionary dict = new PebbleDictionary();
- dict.addString(0, "FETCH");
- dict.addInt32(1, position);
- return dict;
- }
-
- protected void onPebbleReceived(PebbleProcessor processor)
- {
- BroadcastReceiver pebbleReceiver = new BroadcastReceiver()
- {
- @Override
- public void onReceive(Context context, Intent intent)
- {
- try
- {
- String jsonData = intent.getStringExtra(MSG_DATA);
- PebbleDictionary dict = PebbleDictionary.fromJson(jsonData);
- processor.process(dict);
- latch.countDown();
- targetContext.unregisterReceiver(this);
- }
- catch (JSONException e)
- {
- throw new RuntimeException(e);
- }
- }
- };
-
- IntentFilter filter = new IntentFilter(Constants.INTENT_APP_SEND);
- targetContext.registerReceiver(pebbleReceiver, filter);
- }
-
- protected void sendFromPebbleToAndroid(PebbleDictionary dict)
- {
- Intent intent = new Intent(Constants.INTENT_APP_RECEIVE);
- intent.putExtra(Constants.APP_UUID, PebbleReceiver.WATCHAPP_UUID);
- intent.putExtra(Constants.TRANSACTION_ID, 0);
- intent.putExtra(Constants.MSG_DATA, dict.toJsonString());
- targetContext.sendBroadcast(intent);
- }
-
- private PebbleDictionary buildToggleRequest(long habitId)
- {
- PebbleDictionary dict = new PebbleDictionary();
- dict.addString(0, "TOGGLE");
- dict.addInt32(1, (int) habitId);
- return dict;
- }
-
- interface PebbleProcessor
- {
- void process(PebbleDictionary dict);
- }
-}
diff --git a/app/src/main/assets/migrations/11.sql b/app/src/main/assets/migrations/11.sql
deleted file mode 100644
index 25b30ef51..000000000
--- a/app/src/main/assets/migrations/11.sql
+++ /dev/null
@@ -1 +0,0 @@
-alter table habits add column reminder_days integer not null default 127;
\ No newline at end of file
diff --git a/app/src/main/assets/migrations/13.sql b/app/src/main/assets/migrations/13.sql
deleted file mode 100644
index 1d7eeafcf..000000000
--- a/app/src/main/assets/migrations/13.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-create index idx_score_habit_timestamp on score(habit, timestamp);
-create index idx_checkmark_habit_timestamp on checkmarks(habit, timestamp);
-create index idx_repetitions_habit_timestamp on repetitions(habit, timestamp);
-create index idx_streak_habit_end on streak(habit, end);
\ No newline at end of file
diff --git a/app/src/main/assets/migrations/5.sql b/app/src/main/assets/migrations/5.sql
deleted file mode 100644
index bde8462b1..000000000
--- a/app/src/main/assets/migrations/5.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-alter table habits add column reminder_hour integer;
-alter table habits add column reminder_min integer;
\ No newline at end of file
diff --git a/app/src/main/assets/migrations/6.sql b/app/src/main/assets/migrations/6.sql
deleted file mode 100644
index 7f1e33c94..000000000
--- a/app/src/main/assets/migrations/6.sql
+++ /dev/null
@@ -1 +0,0 @@
-alter table habits add column highlight integer not null default 0;
\ No newline at end of file
diff --git a/app/src/main/assets/migrations/7.sql b/app/src/main/assets/migrations/7.sql
deleted file mode 100644
index b666e9bf6..000000000
--- a/app/src/main/assets/migrations/7.sql
+++ /dev/null
@@ -1 +0,0 @@
-alter table habits add column archived integer not null default 0;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/HabitsApplication.java b/app/src/main/java/org/isoron/uhabits/HabitsApplication.java
deleted file mode 100644
index 8e2e1e8ad..000000000
--- a/app/src/main/java/org/isoron/uhabits/HabitsApplication.java
+++ /dev/null
@@ -1,133 +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;
-
-import android.app.*;
-import android.content.*;
-
-import com.activeandroid.*;
-
-import org.isoron.uhabits.models.sqlite.*;
-import org.isoron.uhabits.notifications.*;
-import org.isoron.uhabits.preferences.*;
-import org.isoron.uhabits.tasks.*;
-import org.isoron.uhabits.utils.*;
-import org.isoron.uhabits.widgets.*;
-
-import java.io.*;
-
-/**
- * The Android application for Loop Habit Tracker.
- */
-public class HabitsApplication extends Application
-{
- private Context context;
-
- private static AppComponent component;
-
- private WidgetUpdater widgetUpdater;
-
- private ReminderScheduler reminderScheduler;
-
- private NotificationTray notificationTray;
-
- public AppComponent getComponent()
- {
- return component;
- }
-
- public static void setComponent(AppComponent component)
- {
- HabitsApplication.component = component;
- }
-
- public static boolean isTestMode()
- {
- try
- {
- Class.forName ("org.isoron.uhabits.BaseAndroidTest");
- return true;
- }
- catch (final ClassNotFoundException e)
- {
- return false;
- }
- }
-
- @Override
- public void onCreate()
- {
- super.onCreate();
- context = this;
-
- component = DaggerAppComponent
- .builder()
- .appModule(new AppModule(context))
- .build();
-
- if (isTestMode())
- {
- File db = DatabaseUtils.getDatabaseFile(context);
- if (db.exists()) db.delete();
- }
-
- try
- {
- DatabaseUtils.initializeActiveAndroid(context);
- }
- catch (InvalidDatabaseVersionException e)
- {
- File db = DatabaseUtils.getDatabaseFile(context);
- db.renameTo(new File(db.getAbsolutePath() + ".invalid"));
- DatabaseUtils.initializeActiveAndroid(context);
- }
-
- widgetUpdater = component.getWidgetUpdater();
- widgetUpdater.startListening();
-
- reminderScheduler = component.getReminderScheduler();
- reminderScheduler.startListening();
-
- notificationTray = component.getNotificationTray();
- notificationTray.startListening();
-
- Preferences prefs = component.getPreferences();
- prefs.initialize();
- prefs.updateLastAppVersion();
-
- TaskRunner taskRunner = component.getTaskRunner();
- taskRunner.execute(() -> {
- reminderScheduler.scheduleAll();
- widgetUpdater.updateWidgets();
- });
- }
-
- @Override
- public void onTerminate()
- {
- context = null;
- ActiveAndroid.dispose();
-
- reminderScheduler.stopListening();
- widgetUpdater.stopListening();
- notificationTray.stopListening();
- super.onTerminate();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/ActivityComponent.java b/app/src/main/java/org/isoron/uhabits/activities/ActivityComponent.java
deleted file mode 100644
index e80a9f540..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/ActivityComponent.java
+++ /dev/null
@@ -1,35 +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.activities;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.common.dialogs.*;
-
-import dagger.*;
-
-@ActivityScope
-@Component(modules = { ActivityModule.class },
- dependencies = { AppComponent.class })
-public interface ActivityComponent
-{
- ColorPickerDialogFactory getColorPickerDialogFactory();
-
- ThemeSwitcher getThemeSwitcher();
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/about/package-info.java b/app/src/main/java/org/isoron/uhabits/activities/about/package-info.java
deleted file mode 100644
index e519806ab..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/about/package-info.java
+++ /dev/null
@@ -1,23 +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 .
- */
-
-/**
- * Provides activity that shows information about the app.
- */
-package org.isoron.uhabits.activities.about;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/activities/common/dialogs/FilePickerDialog.java b/app/src/main/java/org/isoron/uhabits/activities/common/dialogs/FilePickerDialog.java
deleted file mode 100644
index a2cca7bbc..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/common/dialogs/FilePickerDialog.java
+++ /dev/null
@@ -1,191 +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.activities.common.dialogs;
-
-import android.content.*;
-import android.support.annotation.*;
-import android.support.v7.app.*;
-import android.view.*;
-import android.view.WindowManager.*;
-import android.widget.*;
-
-import com.google.auto.factory.*;
-
-import org.isoron.uhabits.activities.*;
-
-import java.io.*;
-import java.util.*;
-
-/**
- * Dialog that allows the user to pick a file.
- */
-@AutoFactory(allowSubclasses = true)
-public class FilePickerDialog implements AdapterView.OnItemClickListener
-{
- private static final String PARENT_DIR = "..";
-
- private final Context context;
-
- private ListView list;
-
- private AppCompatDialog dialog;
-
- private File currentPath;
-
- private OnFileSelectedListener listener;
-
- public FilePickerDialog(@Provided @ActivityContext Context context,
- File initialDirectory)
- {
- this.context = context;
-
- list = new ListView(context);
- list.setOnItemClickListener(this);
-
- dialog = new AppCompatDialog(context);
- dialog.setContentView(list);
- dialog
- .getWindow()
- .setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-
- navigateTo(initialDirectory);
- }
-
- public AppCompatDialog getDialog()
- {
- return dialog;
- }
-
- @Override
- public void onItemClick(AdapterView> parent,
- View view,
- int which,
- long id)
- {
- String filename = (String) list.getItemAtPosition(which);
- File file;
-
- if (filename.equals(PARENT_DIR)) file = currentPath.getParentFile();
- else file = new File(currentPath, filename);
-
- if (file.isDirectory())
- {
- navigateTo(file);
- }
- else
- {
- if (listener != null) listener.onFileSelected(file);
- dialog.dismiss();
- }
- }
-
- public void setListener(OnFileSelectedListener listener)
- {
- this.listener = listener;
- }
-
- public void show()
- {
- dialog.show();
- }
-
- @NonNull
- private String[] getFileList(File path, File[] dirs, File[] files)
- {
- int count = 0;
- int length = dirs.length + files.length;
- String[] fileList;
-
- if (path.getParentFile() == null || !path.getParentFile().canRead())
- {
- fileList = new String[length];
- }
- else
- {
- fileList = new String[length + 1];
- fileList[count++] = PARENT_DIR;
- }
-
- Arrays.sort(dirs);
- Arrays.sort(files);
-
- for (File dir : dirs)
- fileList[count++] = dir.getName();
-
- for (File file : files)
- fileList[count++] = file.getName();
-
- return fileList;
- }
-
- private void navigateTo(File path)
- {
- if (!path.exists()) return;
-
- File[] dirs = path.listFiles(new ReadableDirFilter());
- File[] files = path.listFiles(new RegularReadableFileFilter());
- if (dirs == null || files == null) return;
-
- this.currentPath = path;
- dialog.setTitle(currentPath.getPath());
- list.setAdapter(new FilePickerAdapter(getFileList(path, dirs, files)));
- }
-
- public interface OnFileSelectedListener
- {
- void onFileSelected(File file);
- }
-
- private static class ReadableDirFilter implements FileFilter
- {
- @Override
- public boolean accept(File file)
- {
- return (file.isDirectory() && file.canRead());
- }
- }
-
- private class FilePickerAdapter extends ArrayAdapter
- {
- public FilePickerAdapter(@NonNull String[] fileList)
- {
- super(FilePickerDialog.this.context,
- android.R.layout.simple_list_item_1, fileList);
- }
-
- @Override
- public View getView(int pos, View view, ViewGroup parent)
- {
- view = super.getView(pos, view, parent);
- TextView tv = (TextView) view;
- tv.setSingleLine(true);
- return view;
- }
- }
-
- private class RegularReadableFileFilter implements FileFilter
- {
- @Override
- public boolean accept(File file)
- {
- return !file.isDirectory() && file.canRead();
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialog.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialog.java
deleted file mode 100644
index d83914442..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialog.java
+++ /dev/null
@@ -1,277 +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.activities.habits.edit;
-
-import android.os.*;
-import android.support.annotation.*;
-import android.support.v7.app.*;
-import android.text.format.*;
-import android.view.*;
-
-import com.android.datetimepicker.time.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.activities.common.dialogs.*;
-import org.isoron.uhabits.commands.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.preferences.*;
-
-import java.util.*;
-
-import butterknife.*;
-
-import static org.isoron.uhabits.activities.ThemeSwitcher.*;
-
-public abstract class BaseDialog extends AppCompatDialogFragment
-{
- @Nullable
- protected Habit originalHabit;
-
- @Nullable
- protected Habit modifiedHabit;
-
- @Nullable
- protected BaseDialogHelper helper;
-
- protected Preferences prefs;
-
- protected CommandRunner commandRunner;
-
- protected HabitList habitList;
-
- protected AppComponent appComponent;
-
- protected ModelFactory modelFactory;
-
- private ColorPickerDialogFactory colorPickerDialogFactory;
-
- @Override
- public int getTheme()
- {
- AppComponent component =
- ((HabitsApplication) getContext().getApplicationContext()).getComponent();
-
- if(component.getPreferences().getTheme() == THEME_LIGHT)
- return R.style.DialogWithTitle;
- else
- return R.style.DarkDialogWithTitle;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState)
- {
- super.onActivityCreated(savedInstanceState);
-
- BaseActivity activity = (BaseActivity) getActivity();
- colorPickerDialogFactory =
- activity.getComponent().getColorPickerDialogFactory();
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- ViewGroup container,
- Bundle savedInstanceState)
- {
- View view = inflater.inflate(R.layout.edit_habit, container, false);
-
- HabitsApplication app =
- (HabitsApplication) getContext().getApplicationContext();
-
- appComponent = app.getComponent();
- prefs = appComponent.getPreferences();
- habitList = appComponent.getHabitList();
- commandRunner = appComponent.getCommandRunner();
- modelFactory = appComponent.getModelFactory();
-
- ButterKnife.bind(this, view);
-
- helper = new BaseDialogHelper(this, view);
- getDialog().setTitle(getTitle());
- initializeHabits();
- restoreSavedInstance(savedInstanceState);
- helper.populateForm(modifiedHabit);
- return view;
- }
-
- @OnItemSelected(R.id.sFrequency)
- public void onFrequencySelected(int position)
- {
- if (position < 0 || position > 4) throw new IllegalArgumentException();
- int freqNums[] = { 1, 1, 2, 5, 3 };
- int freqDens[] = { 1, 7, 7, 7, 7 };
- modifiedHabit.setFrequency(
- new Frequency(freqNums[position], freqDens[position]));
- helper.populateFrequencyFields(modifiedHabit);
- }
-
- @Override
- @SuppressWarnings("ConstantConditions")
- public void onSaveInstanceState(Bundle outState)
- {
- super.onSaveInstanceState(outState);
- outState.putInt("color", modifiedHabit.getColor());
- if (modifiedHabit.hasReminder())
- {
- Reminder reminder = modifiedHabit.getReminder();
- outState.putInt("reminderMin", reminder.getMinute());
- outState.putInt("reminderHour", reminder.getHour());
- outState.putInt("reminderDays", reminder.getDays().toInteger());
- }
- }
-
- protected abstract int getTitle();
-
- protected abstract void initializeHabits();
-
- protected void restoreSavedInstance(@Nullable Bundle bundle)
- {
- if (bundle == null) return;
- modifiedHabit.setColor(
- bundle.getInt("color", modifiedHabit.getColor()));
-
- modifiedHabit.setReminder(null);
-
- int hour = (bundle.getInt("reminderHour", -1));
- int minute = (bundle.getInt("reminderMin", -1));
- int days = (bundle.getInt("reminderDays", -1));
-
- if (hour >= 0 && minute >= 0)
- {
- Reminder reminder =
- new Reminder(hour, minute, new WeekdayList(days));
- modifiedHabit.setReminder(reminder);
- }
- }
-
- protected abstract void saveHabit();
-
- @OnClick(R.id.buttonDiscard)
- void onButtonDiscardClick()
- {
- dismiss();
- }
-
- @OnClick(R.id.tvReminderTime)
- @SuppressWarnings("ConstantConditions")
- void onDateSpinnerClick()
- {
- int defaultHour = 8;
- int defaultMin = 0;
-
- if (modifiedHabit.hasReminder())
- {
- Reminder reminder = modifiedHabit.getReminder();
- defaultHour = reminder.getHour();
- defaultMin = reminder.getMinute();
- }
-
- showTimePicker(defaultHour, defaultMin);
- }
-
- @OnClick(R.id.buttonSave)
- void onSaveButtonClick()
- {
- helper.parseFormIntoHabit(modifiedHabit);
- if (!helper.validate(modifiedHabit)) return;
- saveHabit();
- dismiss();
- }
-
- @OnClick(R.id.tvReminderDays)
- @SuppressWarnings("ConstantConditions")
- void onWeekdayClick()
- {
- if (!modifiedHabit.hasReminder()) return;
- Reminder reminder = modifiedHabit.getReminder();
-
- WeekdayPickerDialog dialog = new WeekdayPickerDialog();
- dialog.setListener(new OnWeekdaysPickedListener());
- dialog.setSelectedDays(reminder.getDays().toArray());
- dialog.show(getFragmentManager(), "weekdayPicker");
- }
-
- @OnClick(R.id.buttonPickColor)
- void showColorPicker()
- {
- int color = modifiedHabit.getColor();
- ColorPickerDialog picker = colorPickerDialogFactory.create(color);
-
- picker.setListener(c -> {
- prefs.setDefaultHabitColor(c);
- modifiedHabit.setColor(c);
- helper.populateColor(c);
- });
-
- picker.show(getFragmentManager(), "picker");
- }
-
- private void showTimePicker(int defaultHour, int defaultMin)
- {
- boolean is24HourMode = DateFormat.is24HourFormat(getContext());
- TimePickerDialog timePicker =
- TimePickerDialog.newInstance(new OnTimeSetListener(), defaultHour,
- defaultMin, is24HourMode);
- timePicker.show(getFragmentManager(), "timePicker");
- }
-
- private class OnTimeSetListener
- implements TimePickerDialog.OnTimeSetListener
- {
- @Override
- public void onTimeCleared(RadialPickerLayout view)
- {
- modifiedHabit.clearReminder();
- helper.populateReminderFields(modifiedHabit);
- }
-
- @Override
- public void onTimeSet(RadialPickerLayout view, int hour, int minute)
- {
- Reminder reminder =
- new Reminder(hour, minute, WeekdayList.EVERY_DAY);
- modifiedHabit.setReminder(reminder);
- helper.populateReminderFields(modifiedHabit);
- }
- }
-
- private class OnWeekdaysPickedListener
- implements WeekdayPickerDialog.OnWeekdaysPickedListener
- {
- @Override
- public void onWeekdaysPicked(boolean[] selectedDays)
- {
- if (isSelectionEmpty(selectedDays)) Arrays.fill(selectedDays, true);
-
- Reminder oldReminder = modifiedHabit.getReminder();
- modifiedHabit.setReminder(
- new Reminder(oldReminder.getHour(), oldReminder.getMinute(),
- new WeekdayList(selectedDays)));
- helper.populateReminderFields(modifiedHabit);
- }
-
- private boolean isSelectionEmpty(boolean[] selectedDays)
- {
- for (boolean d : selectedDays) if (d) return false;
- return true;
- }
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialogHelper.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialogHelper.java
deleted file mode 100644
index 225b509ff..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/BaseDialogHelper.java
+++ /dev/null
@@ -1,195 +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.activities.habits.edit;
-
-import android.annotation.*;
-import android.support.v4.app.*;
-import android.view.*;
-import android.widget.*;
-
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-
-import butterknife.*;
-
-public class BaseDialogHelper
-{
- private DialogFragment frag;
-
- @BindView(R.id.tvName)
- TextView tvName;
-
- @BindView(R.id.tvDescription)
- TextView tvDescription;
-
- @BindView(R.id.tvFreqNum)
- TextView tvFreqNum;
-
- @BindView(R.id.tvFreqDen)
- TextView tvFreqDen;
-
- @BindView(R.id.tvReminderTime)
- TextView tvReminderTime;
-
- @BindView(R.id.tvReminderDays)
- TextView tvReminderDays;
-
- @BindView(R.id.sFrequency)
- Spinner sFrequency;
-
- @BindView(R.id.llCustomFrequency)
- ViewGroup llCustomFrequency;
-
- @BindView(R.id.llReminderDays)
- ViewGroup llReminderDays;
-
- public BaseDialogHelper(DialogFragment frag, View view)
- {
- this.frag = frag;
- ButterKnife.bind(this, view);
- }
-
- protected void populateForm(final Habit habit)
- {
- if (habit.getName() != null) tvName.setText(habit.getName());
- if (habit.getDescription() != null)
- tvDescription.setText(habit.getDescription());
-
- populateColor(habit.getColor());
- populateFrequencyFields(habit);
- populateReminderFields(habit);
- }
-
- void parseFormIntoHabit(Habit habit)
- {
- habit.setName(tvName.getText().toString().trim());
- habit.setDescription(tvDescription.getText().toString().trim());
- String freqNum = tvFreqNum.getText().toString();
- String freqDen = tvFreqDen.getText().toString();
- if (!freqNum.isEmpty() && !freqDen.isEmpty())
- {
- int numerator = Integer.parseInt(freqNum);
- int denominator = Integer.parseInt(freqDen);
- habit.setFrequency(new Frequency(numerator, denominator));
- }
- }
-
- void populateColor(int paletteColor)
- {
- tvName.setTextColor(
- ColorUtils.getColor(frag.getContext(), paletteColor));
- }
-
- @SuppressLint("SetTextI18n")
- void populateFrequencyFields(Habit habit)
- {
- int quickSelectPosition = -1;
-
- Frequency freq = habit.getFrequency();
-
- if (freq.equals(Frequency.DAILY))
- quickSelectPosition = 0;
-
- else if (freq.equals(Frequency.WEEKLY))
- quickSelectPosition = 1;
-
- else if (freq.equals(Frequency.TWO_TIMES_PER_WEEK))
- quickSelectPosition = 2;
-
- else if (freq.equals(Frequency.FIVE_TIMES_PER_WEEK))
- quickSelectPosition = 3;
-
- if (quickSelectPosition >= 0)
- showSimplifiedFrequency(quickSelectPosition);
-
- else showCustomFrequency();
-
- tvFreqNum.setText(Integer.toString(freq.getNumerator()));
- tvFreqDen.setText(Integer.toString(freq.getDenominator()));
- }
-
- @SuppressWarnings("ConstantConditions")
- void populateReminderFields(Habit habit)
- {
- if (!habit.hasReminder())
- {
- tvReminderTime.setText(R.string.reminder_off);
- llReminderDays.setVisibility(View.GONE);
- return;
- }
-
- Reminder reminder = habit.getReminder();
-
- String time =
- DateUtils.formatTime(frag.getContext(), reminder.getHour(),
- reminder.getMinute());
- tvReminderTime.setText(time);
- llReminderDays.setVisibility(View.VISIBLE);
-
- boolean weekdays[] = reminder.getDays().toArray();
- tvReminderDays.setText(
- DateUtils.formatWeekdayList(frag.getContext(), weekdays));
- }
-
- private void showCustomFrequency()
- {
- sFrequency.setVisibility(View.GONE);
- llCustomFrequency.setVisibility(View.VISIBLE);
- }
-
- @SuppressLint("SetTextI18n")
- private void showSimplifiedFrequency(int quickSelectPosition)
- {
- sFrequency.setVisibility(View.VISIBLE);
- sFrequency.setSelection(quickSelectPosition);
- llCustomFrequency.setVisibility(View.GONE);
- }
-
- boolean validate(Habit habit)
- {
- Boolean valid = true;
-
- if (habit.getName().length() == 0)
- {
- tvName.setError(
- frag.getString(R.string.validation_name_should_not_be_blank));
- valid = false;
- }
-
- Frequency freq = habit.getFrequency();
-
- if (freq.getNumerator() <= 0)
- {
- tvFreqNum.setError(
- frag.getString(R.string.validation_number_should_be_positive));
- valid = false;
- }
-
- if (freq.getNumerator() > freq.getDenominator())
- {
- tvFreqNum.setError(
- frag.getString(R.string.validation_at_most_one_rep_per_day));
- valid = false;
- }
-
- return valid;
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/CreateHabitDialog.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/CreateHabitDialog.java
deleted file mode 100644
index 5f34e2e40..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/CreateHabitDialog.java
+++ /dev/null
@@ -1,54 +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.activities.habits.edit;
-
-import com.google.auto.factory.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.commands.*;
-import org.isoron.uhabits.models.*;
-
-@AutoFactory(allowSubclasses = true)
-public class CreateHabitDialog extends BaseDialog
-{
- @Override
- protected int getTitle()
- {
- return R.string.create_habit;
- }
-
- @Override
- protected void initializeHabits()
- {
- modifiedHabit = modelFactory.buildHabit();
- modifiedHabit.setFrequency(Frequency.DAILY);
- modifiedHabit.setColor(
- prefs.getDefaultHabitColor(modifiedHabit.getColor()));
- }
-
- @Override
- protected void saveHabit()
- {
- Command command = appComponent
- .getCreateHabitCommandFactory()
- .create(habitList, modifiedHabit);
- commandRunner.execute(command, null);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitDialog.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitDialog.java
deleted file mode 100644
index e9c1aca78..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitDialog.java
+++ /dev/null
@@ -1,52 +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.activities.habits.edit;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.commands.*;
-
-public class EditHabitDialog extends BaseDialog
-{
- @Override
- protected int getTitle()
- {
- return R.string.edit_habit;
- }
-
- @Override
- protected void initializeHabits()
- {
- Long habitId = (Long) getArguments().get("habitId");
- if (habitId == null)
- throw new IllegalArgumentException("habitId must be specified");
-
- originalHabit = habitList.getById(habitId);
- modifiedHabit = modelFactory.buildHabit();
- modifiedHabit.copyFrom(originalHabit);
- }
-
- @Override
- protected void saveHabit()
- {
- Command command = appComponent.getEditHabitCommandFactory().
- create(habitList, originalHabit, modifiedHabit);
- commandRunner.execute(command, originalHabit.getId());
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.java
deleted file mode 100644
index deb1b3649..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.java
+++ /dev/null
@@ -1,114 +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.activities.habits.list;
-
-import android.os.*;
-
-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.utils.*;
-
-/**
- * Activity that allows the user to see and modify the list of habits.
- */
-public class ListHabitsActivity extends BaseActivity
-{
- private HabitCardListAdapter adapter;
-
- private ListHabitsRootView rootView;
-
- private ListHabitsScreen screen;
-
- private ListHabitsComponent component;
-
- private boolean pureBlack;
-
- private Preferences prefs;
-
- private MidnightTimer midnightTimer;
-
- public ListHabitsComponent getListHabitsComponent()
- {
- return component;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- HabitsApplication app = (HabitsApplication) getApplicationContext();
-
- component = DaggerListHabitsComponent
- .builder()
- .appComponent(app.getComponent())
- .activityModule(new ActivityModule(this))
- .build();
-
- ListHabitsMenu menu = component.getMenu();
- ListHabitsSelectionMenu selectionMenu = component.getSelectionMenu();
- ListHabitsController controller = component.getController();
-
- adapter = component.getAdapter();
- rootView = component.getRootView();
- screen = component.getScreen();
-
- prefs = app.getComponent().getPreferences();
- pureBlack = prefs.isPureBlackEnabled();
-
- screen.setMenu(menu);
- screen.setController(controller);
- screen.setSelectionMenu(selectionMenu);
- rootView.setController(controller, selectionMenu);
-
- midnightTimer = component.getMidnightTimer();
-
- setScreen(screen);
- controller.onStartup();
- }
-
- @Override
- protected void onPause()
- {
- midnightTimer.onPause();
- screen.onDettached();
- adapter.cancelRefresh();
- super.onPause();
- }
-
- @Override
- protected void onResume()
- {
- adapter.refresh();
- screen.onAttached();
- rootView.postInvalidate();
- midnightTimer.onResume();
-
- if (prefs.getTheme() == ThemeSwitcher.THEME_DARK &&
- prefs.isPureBlackEnabled() != pureBlack)
- {
- restartWithFade();
- }
-
- super.onResume();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java
deleted file mode 100644
index 554c22a3b..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java
+++ /dev/null
@@ -1,50 +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.activities.habits.list;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.activities.habits.list.controllers.*;
-import org.isoron.uhabits.activities.habits.list.model.*;
-import org.isoron.uhabits.utils.*;
-
-import dagger.*;
-
-@ActivityScope
-@Component(modules = { ActivityModule.class },
- dependencies = { AppComponent.class })
-public interface ListHabitsComponent
-{
- CheckmarkButtonControllerFactory getCheckmarkButtonControllerFactory();
-
- HabitCardListAdapter getAdapter();
-
- ListHabitsController getController();
-
- ListHabitsMenu getMenu();
-
- ListHabitsRootView getRootView();
-
- ListHabitsScreen getScreen();
-
- ListHabitsSelectionMenu getSelectionMenu();
-
- MidnightTimer getMidnightTimer();
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java
deleted file mode 100644
index a52c4b4d6..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java
+++ /dev/null
@@ -1,224 +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.activities.habits.list;
-
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.activities.habits.list.controllers.*;
-import org.isoron.uhabits.activities.habits.list.model.*;
-import org.isoron.uhabits.commands.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.preferences.*;
-import org.isoron.uhabits.tasks.*;
-import org.isoron.uhabits.utils.*;
-import org.isoron.uhabits.widgets.*;
-
-import java.io.*;
-import java.util.*;
-
-import javax.inject.*;
-
-@ActivityScope
-public class ListHabitsController
- implements HabitCardListController.HabitListener
-{
-
- @NonNull
- private final ListHabitsScreen screen;
-
- @NonNull
- private final BaseSystem system;
-
- @NonNull
- private final HabitList habitList;
-
- @NonNull
- private final HabitCardListAdapter adapter;
-
- @NonNull
- private final Preferences prefs;
-
- @NonNull
- private final CommandRunner commandRunner;
-
- @NonNull
- private final TaskRunner taskRunner;
-
- private ReminderScheduler reminderScheduler;
-
- private WidgetUpdater widgetUpdater;
-
- private ImportDataTaskFactory importTaskFactory;
-
- private ExportCSVTaskFactory exportCSVFactory;
-
- private ExportDBTaskFactory exportDBFactory;
-
- @Inject
- public ListHabitsController(@NonNull BaseSystem system,
- @NonNull CommandRunner commandRunner,
- @NonNull HabitList habitList,
- @NonNull HabitCardListAdapter adapter,
- @NonNull ListHabitsScreen screen,
- @NonNull Preferences prefs,
- @NonNull ReminderScheduler reminderScheduler,
- @NonNull TaskRunner taskRunner,
- @NonNull WidgetUpdater widgetUpdater,
- @NonNull
- ImportDataTaskFactory importTaskFactory,
- @NonNull ExportCSVTaskFactory exportCSVFactory,
- @NonNull ExportDBTaskFactory exportDBFactory)
- {
- this.adapter = adapter;
- this.commandRunner = commandRunner;
- this.habitList = habitList;
- this.prefs = prefs;
- this.screen = screen;
- this.system = system;
- this.taskRunner = taskRunner;
- this.reminderScheduler = reminderScheduler;
- this.widgetUpdater = widgetUpdater;
- this.importTaskFactory = importTaskFactory;
- this.exportCSVFactory = exportCSVFactory;
- this.exportDBFactory = exportDBFactory;
- }
-
- public void onExportCSV()
- {
- List selected = new LinkedList<>();
- for (Habit h : habitList) selected.add(h);
-
- taskRunner.execute(exportCSVFactory.create(selected, filename -> {
- if (filename != null) screen.showSendFileScreen(filename);
- else screen.showMessage(R.string.could_not_export);
- }));
- }
-
- public void onExportDB()
- {
- taskRunner.execute(exportDBFactory.create(filename -> {
- if (filename != null) screen.showSendFileScreen(filename);
- else screen.showMessage(R.string.could_not_export);
- }));
- }
-
- @Override
- public void onHabitClick(@NonNull Habit h)
- {
- screen.showHabitScreen(h);
- }
-
- @Override
- public void onHabitReorder(@NonNull Habit from, @NonNull Habit to)
- {
- taskRunner.execute(() -> habitList.reorder(from, to));
- }
-
- public void onImportData(@NonNull File file,
- @NonNull OnFinishedListener finishedListener)
- {
- taskRunner.execute(importTaskFactory.create(file, result -> {
- switch (result)
- {
- case ImportDataTask.SUCCESS:
- adapter.refresh();
- screen.showMessage(R.string.habits_imported);
- break;
-
- case ImportDataTask.NOT_RECOGNIZED:
- screen.showMessage(R.string.file_not_recognized);
- break;
-
- default:
- screen.showMessage(R.string.could_not_import);
- break;
- }
-
- finishedListener.onFinish();
- }));
- }
-
-
- @Override
- public void onInvalidToggle()
- {
- screen.showMessage(R.string.long_press_to_toggle);
- }
-
- public void onRepairDB()
- {
- taskRunner.execute(() -> {
- habitList.repair();
- screen.showMessage(R.string.database_repaired);
- });
- }
-
- public void onSendBugReport()
- {
- try
- {
- system.dumpBugReportToFile();
- }
- catch (IOException e)
- {
- // ignored
- }
-
- try
- {
- String log = system.getBugReport();
- int to = R.string.bugReportTo;
- int subject = R.string.bugReportSubject;
- screen.showSendEmailScreen(to, subject, log);
- }
- catch (IOException e)
- {
- e.printStackTrace();
- screen.showMessage(R.string.bug_report_failed);
- }
- }
-
- public void onStartup()
- {
- prefs.incrementLaunchCount();
- if (prefs.isFirstRun()) onFirstRun();
- }
-
- @Override
- public void onToggle(@NonNull Habit habit, long timestamp)
- {
- commandRunner.execute(new ToggleRepetitionCommand(habit, timestamp),
- habit.getId());
- }
-
- private void onFirstRun()
- {
- prefs.setFirstRun(false);
- prefs.updateLastHint(-1, DateUtils.getStartOfToday());
- screen.showIntroScreen();
- }
-
- public interface OnFinishedListener
- {
- void onFinish();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsMenu.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsMenu.java
deleted file mode 100644
index aa3826c4c..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsMenu.java
+++ /dev/null
@@ -1,164 +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.activities.habits.list;
-
-import android.support.annotation.*;
-import android.view.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.activities.habits.list.model.*;
-import org.isoron.uhabits.preferences.*;
-
-import javax.inject.*;
-
-@ActivityScope
-public class ListHabitsMenu extends BaseMenu
-{
- @NonNull
- private final ListHabitsScreen screen;
-
- private final HabitCardListAdapter adapter;
-
- private boolean showArchived;
-
- private boolean showCompleted;
-
- private final Preferences preferences;
-
- private ThemeSwitcher themeSwitcher;
-
- @Inject
- public ListHabitsMenu(@NonNull BaseActivity activity,
- @NonNull ListHabitsScreen screen,
- @NonNull HabitCardListAdapter adapter,
- @NonNull Preferences preferences,
- @NonNull ThemeSwitcher themeSwitcher)
- {
- super(activity);
- this.screen = screen;
- this.adapter = adapter;
- this.preferences = preferences;
- this.themeSwitcher = themeSwitcher;
-
- showCompleted = preferences.getShowCompleted();
- showArchived = preferences.getShowArchived();
- updateAdapterFilter();
- }
-
- @Override
- public void onCreate(@NonNull Menu menu)
- {
- MenuItem nightModeItem = menu.findItem(R.id.actionToggleNightMode);
- nightModeItem.setChecked(themeSwitcher.isNightMode());
-
- MenuItem hideArchivedItem = menu.findItem(R.id.actionHideArchived);
- hideArchivedItem.setChecked(!showArchived);
-
- MenuItem hideCompletedItem = menu.findItem(R.id.actionHideCompleted);
- hideCompletedItem.setChecked(!showCompleted);
- }
-
- @Override
- public boolean onItemSelected(@NonNull MenuItem item)
- {
- switch (item.getItemId())
- {
- case R.id.actionToggleNightMode:
- screen.toggleNightMode();
- return true;
-
- case R.id.actionAdd:
- screen.showCreateHabitScreen();
- return true;
-
- case R.id.actionFAQ:
- screen.showFAQScreen();
- return true;
-
- case R.id.actionAbout:
- screen.showAboutScreen();
- return true;
-
- case R.id.actionSettings:
- screen.showSettingsScreen();
- return true;
-
- case R.id.actionHideArchived:
- toggleShowArchived();
- invalidate();
- return true;
-
- case R.id.actionHideCompleted:
- toggleShowCompleted();
- invalidate();
- return true;
-
- case R.id.actionSortColor:
- adapter.setOrder(HabitList.Order.BY_COLOR);
- return true;
-
- case R.id.actionSortManual:
- adapter.setOrder(HabitList.Order.BY_POSITION);
- return true;
-
- case R.id.actionSortName:
- adapter.setOrder(HabitList.Order.BY_NAME);
- return true;
-
- case R.id.actionSortScore:
- adapter.setOrder(HabitList.Order.BY_SCORE);
- return true;
-
- default:
- return false;
- }
- }
-
- @Override
- protected int getMenuResourceId()
- {
- return R.menu.list_habits;
- }
-
- private void toggleShowArchived()
- {
- showArchived = !showArchived;
- preferences.setShowArchived(showArchived);
- updateAdapterFilter();
- }
-
- private void toggleShowCompleted()
- {
- showCompleted = !showCompleted;
- preferences.setShowCompleted(showCompleted);
- updateAdapterFilter();
- }
-
- private void updateAdapterFilter()
- {
- adapter.setFilter(new HabitMatcherBuilder()
- .setArchivedAllowed(showArchived)
- .setCompletedAllowed(showCompleted)
- .build());
- adapter.refresh();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.java
deleted file mode 100644
index 7a716c9cd..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.java
+++ /dev/null
@@ -1,196 +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.activities.habits.list;
-
-import android.content.*;
-import android.content.res.*;
-import android.support.annotation.*;
-import android.support.v7.widget.Toolbar;
-import android.view.*;
-import android.widget.*;
-
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.activities.common.views.*;
-import org.isoron.uhabits.activities.habits.list.controllers.*;
-import org.isoron.uhabits.activities.habits.list.model.*;
-import org.isoron.uhabits.activities.habits.list.views.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.tasks.*;
-import org.isoron.uhabits.utils.*;
-
-import javax.inject.*;
-
-import butterknife.*;
-
-@ActivityScope
-public class ListHabitsRootView extends BaseRootView
- implements ModelObservable.Listener, TaskRunner.Listener
-{
- public static final int MAX_CHECKMARK_COUNT = 60;
-
- @BindView(R.id.listView)
- HabitCardListView listView;
-
- @BindView(R.id.llEmpty)
- ViewGroup llEmpty;
-
- @BindView(R.id.tvStarEmpty)
- TextView tvStarEmpty;
-
- @BindView(R.id.toolbar)
- Toolbar toolbar;
-
- @BindView(R.id.progressBar)
- ProgressBar progressBar;
-
- @BindView(R.id.hintView)
- HintView hintView;
-
- @BindView(R.id.header)
- HeaderView header;
-
- @NonNull
- private final HabitCardListAdapter listAdapter;
-
- private final TaskRunner runner;
-
- @Inject
- public ListHabitsRootView(@ActivityContext Context context,
- @NonNull HintListFactory hintListFactory,
- @NonNull HabitCardListAdapter listAdapter,
- @NonNull TaskRunner runner)
- {
- super(context);
- addView(inflate(getContext(), R.layout.list_habits, null));
- ButterKnife.bind(this);
-
- this.listAdapter = listAdapter;
- listView.setAdapter(listAdapter);
- listAdapter.setListView(listView);
-
- this.runner = runner;
- progressBar.setIndeterminate(true);
- tvStarEmpty.setTypeface(InterfaceUtils.getFontAwesome(getContext()));
-
- String hints[] =
- getContext().getResources().getStringArray(R.array.hints);
- HintList hintList = hintListFactory.create(hints);
- hintView.setHints(hintList);
-
- initToolbar();
- }
-
- @NonNull
- @Override
- public Toolbar getToolbar()
- {
- return toolbar;
- }
-
- @Override
- public void onModelChange()
- {
- updateEmptyView();
- }
-
- @Override
- public void onTaskFinished(Task task)
- {
- updateProgressBar();
- }
-
- @Override
- public void onTaskStarted(Task task)
- {
- updateProgressBar();
- }
-
- public void setController(@NonNull ListHabitsController controller,
- @NonNull ListHabitsSelectionMenu menu)
- {
- HabitCardListController listController =
- new HabitCardListController(listAdapter);
-
- listController.setHabitListener(controller);
- listController.setSelectionListener(menu);
- listView.setController(listController);
- menu.setListController(listController);
- header.setScrollController(new ScrollableChart.ScrollController() {
- @Override
- public void onDataOffsetChanged(int newDataOffset)
- {
- listView.setDataOffset(newDataOffset);
- }
- });
- }
-
- @Override
- protected void onAttachedToWindow()
- {
- super.onAttachedToWindow();
- runner.addListener(this);
- updateProgressBar();
- listAdapter.getObservable().addListener(this);
- }
-
- @Override
- protected void onDetachedFromWindow()
- {
- listAdapter.getObservable().removeListener(this);
- runner.removeListener(this);
- super.onDetachedFromWindow();
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh)
- {
- int count = getCheckmarkCount();
- header.setButtonCount(count);
- header.setMaxDataOffset(Math.max(MAX_CHECKMARK_COUNT - count, 0));
- listView.setCheckmarkCount(count);
- super.onSizeChanged(w, h, oldw, oldh);
- }
-
- private int getCheckmarkCount()
- {
- Resources res = getResources();
- float labelWidth = Math.max(getMeasuredWidth() / 3, res.getDimension(R.dimen.habitNameWidth));
- float buttonWidth = res.getDimension(R.dimen.checkmarkWidth);
- return Math.min(MAX_CHECKMARK_COUNT, Math.max(0,
- (int) ((getMeasuredWidth() - labelWidth) / buttonWidth)));
- }
-
- private void updateEmptyView()
- {
- llEmpty.setVisibility(
- listAdapter.getItemCount() > 0 ? View.GONE : View.VISIBLE);
- }
-
- private void updateProgressBar()
- {
- postDelayed(() -> {
- int activeTaskCount = runner.getActiveTaskCount();
- int newVisibility = activeTaskCount > 0 ? VISIBLE : GONE;
- if (progressBar.getVisibility() != newVisibility)
- progressBar.setVisibility(newVisibility);
- }, 500);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java
deleted file mode 100644
index 045505a90..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java
+++ /dev/null
@@ -1,303 +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.activities.habits.list;
-
-import android.app.*;
-import android.content.*;
-import android.net.*;
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.activities.common.dialogs.*;
-import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialog.*;
-import org.isoron.uhabits.activities.habits.edit.*;
-import org.isoron.uhabits.commands.*;
-import org.isoron.uhabits.intents.*;
-import org.isoron.uhabits.io.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-
-import java.io.*;
-
-import javax.inject.*;
-
-import static android.os.Build.VERSION.*;
-import static android.os.Build.VERSION_CODES.*;
-
-@ActivityScope
-public class ListHabitsScreen extends BaseScreen
- implements CommandRunner.Listener
-{
- public static final int RESULT_IMPORT_DATA = 1;
-
- public static final int RESULT_EXPORT_CSV = 2;
-
- public static final int RESULT_EXPORT_DB = 3;
-
- public static final int RESULT_BUG_REPORT = 4;
-
- public static final int RESULT_REPAIR_DB = 5;
-
- public static final int REQUEST_OPEN_DOCUMENT = 6;
-
- public static final int REQUEST_SETTINGS = 7;
-
- @Nullable
- private ListHabitsController controller;
-
- @NonNull
- private final IntentFactory intentFactory;
-
- @NonNull
- private final DirFinder dirFinder;
-
- @NonNull
- private final CommandRunner commandRunner;
-
- @NonNull
- private final ConfirmDeleteDialogFactory confirmDeleteDialogFactory;
-
- @NonNull
- private final CreateHabitDialogFactory createHabitDialogFactory;
-
- @NonNull
- private final FilePickerDialogFactory filePickerDialogFactory;
-
- @NonNull
- private final ColorPickerDialogFactory colorPickerFactory;
-
- @NonNull
- private final EditHabitDialogFactory editHabitDialogFactory;
-
- @NonNull
- private final ThemeSwitcher themeSwitcher;
-
- @Inject
- public ListHabitsScreen(@NonNull BaseActivity activity,
- @NonNull CommandRunner commandRunner,
- @NonNull DirFinder dirFinder,
- @NonNull ListHabitsRootView rootView,
- @NonNull IntentFactory intentFactory,
- @NonNull ThemeSwitcher themeSwitcher,
- @NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory,
- @NonNull CreateHabitDialogFactory createHabitDialogFactory,
- @NonNull FilePickerDialogFactory filePickerDialogFactory,
- @NonNull ColorPickerDialogFactory colorPickerFactory,
- @NonNull EditHabitDialogFactory editHabitDialogFactory)
- {
- super(activity);
- setRootView(rootView);
- this.editHabitDialogFactory = editHabitDialogFactory;
- this.colorPickerFactory = colorPickerFactory;
- this.commandRunner = commandRunner;
- this.confirmDeleteDialogFactory = confirmDeleteDialogFactory;
- this.createHabitDialogFactory = createHabitDialogFactory;
- this.dirFinder = dirFinder;
- this.filePickerDialogFactory = filePickerDialogFactory;
- this.intentFactory = intentFactory;
- this.themeSwitcher = themeSwitcher;
- }
-
- public void onAttached()
- {
- commandRunner.addListener(this);
- }
-
- @Override
- public void onCommandExecuted(@NonNull Command command,
- @Nullable Long refreshKey)
- {
- showMessage(command.getExecuteStringId());
- }
-
- public void onDettached()
- {
- commandRunner.removeListener(this);
- }
-
- @Override
- public void onResult(int requestCode, int resultCode, Intent data)
- {
- if (requestCode == REQUEST_OPEN_DOCUMENT)
- onOpenDocumentResult(resultCode, data);
-
- if (requestCode == REQUEST_SETTINGS)
- onSettingsResult(resultCode);
- }
-
- private void onSettingsResult(int resultCode)
- {
- if (controller == null) return;
-
- switch (resultCode)
- {
- case RESULT_IMPORT_DATA:
- showImportScreen();
- break;
-
- case RESULT_EXPORT_CSV:
- controller.onExportCSV();
- break;
-
- case RESULT_EXPORT_DB:
- controller.onExportDB();
- break;
-
- case RESULT_BUG_REPORT:
- controller.onSendBugReport();
- break;
-
- case RESULT_REPAIR_DB:
- controller.onRepairDB();
- break;
- }
- }
-
- private void onOpenDocumentResult(int resultCode, Intent data)
- {
- if (controller == null) return;
- if (resultCode != Activity.RESULT_OK) return;
-
- try
- {
- Uri uri = data.getData();
- ContentResolver cr = activity.getContentResolver();
- InputStream is = cr.openInputStream(uri);
-
- File cacheDir = activity.getExternalCacheDir();
- File tempFile = File.createTempFile("import", "", cacheDir);
-
- FileUtils.copy(is, tempFile);
- controller.onImportData(tempFile, () -> tempFile.delete());
- }
- catch (IOException e)
- {
- showMessage(R.string.could_not_import);
- e.printStackTrace();
- }
- }
-
- public void setController(@Nullable ListHabitsController controller)
- {
- this.controller = controller;
- }
-
- public void showAboutScreen()
- {
- Intent intent = intentFactory.startAboutActivity(activity);
- activity.startActivity(intent);
- }
-
- /**
- * Displays a {@link ColorPickerDialog} to the user.
- *
- * The selected color on the dialog is the color of the given habit.
- *
- * @param habit the habit
- * @param callback
- */
- public void showColorPicker(@NonNull Habit habit,
- @NonNull OnColorSelectedListener callback)
- {
- ColorPickerDialog picker = colorPickerFactory.create(habit.getColor());
- picker.setListener(callback);
- activity.showDialog(picker, "picker");
- }
-
- public void showCreateHabitScreen()
- {
- activity.showDialog(createHabitDialogFactory.create(), "editHabit");
- }
-
- public void showDeleteConfirmationScreen(ConfirmDeleteDialog.Callback callback)
- {
- activity.showDialog(confirmDeleteDialogFactory.create(callback));
- }
-
- public void showEditHabitScreen(Habit habit)
- {
- EditHabitDialog dialog = editHabitDialogFactory.create(habit);
- activity.showDialog(dialog, "editHabit");
- }
-
- public void showFAQScreen()
- {
- Intent intent = intentFactory.viewFAQ(activity);
- activity.startActivity(intent);
- }
-
- public void showHabitScreen(@NonNull Habit habit)
- {
- Intent intent = intentFactory.startShowHabitActivity(activity, habit);
- activity.startActivity(intent);
- }
-
- public void showImportScreen()
- {
- if (SDK_INT < KITKAT)
- {
- showImportScreenPreKitKat();
- return;
- }
-
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("*/*");
-
- activity.startActivityForResult(intent, REQUEST_OPEN_DOCUMENT);
- }
-
- public void showImportScreenPreKitKat()
- {
- File dir = dirFinder.findStorageDir(null);
-
- if (dir == null)
- {
- showMessage(R.string.could_not_import);
- return;
- }
-
- FilePickerDialog picker = filePickerDialogFactory.create(dir);
-
- if (controller != null)
- picker.setListener(file -> controller.onImportData(file, () -> {}));
-
- activity.showDialog(picker.getDialog());
- }
-
- public void showIntroScreen()
- {
- Intent intent = intentFactory.startIntroActivity(activity);
- activity.startActivity(intent);
- }
-
- public void showSettingsScreen()
- {
- Intent intent = intentFactory.startSettingsActivity(activity);
- activity.startActivityForResult(intent, REQUEST_SETTINGS);
- }
-
- public void toggleNightMode()
- {
- themeSwitcher.toggleNightMode();
- activity.restartWithFade();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsSelectionMenu.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsSelectionMenu.java
deleted file mode 100644
index 9543fe352..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsSelectionMenu.java
+++ /dev/null
@@ -1,206 +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.activities.habits.list;
-
-import android.support.annotation.*;
-import android.view.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.commands.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.activities.habits.list.controllers.*;
-import org.isoron.uhabits.activities.habits.list.model.*;
-
-import java.util.*;
-
-import javax.inject.*;
-
-@ActivityScope
-public class ListHabitsSelectionMenu extends BaseSelectionMenu
- implements HabitCardListController.SelectionListener
-{
- @NonNull
- private final ListHabitsScreen screen;
-
- @NonNull
- CommandRunner commandRunner;
-
- @NonNull
- private final HabitCardListAdapter listAdapter;
-
- @Nullable
- private HabitCardListController listController;
-
- @NonNull
- private final HabitList habitList;
-
- @Inject
- public ListHabitsSelectionMenu(@NonNull HabitList habitList,
- @NonNull ListHabitsScreen screen,
- @NonNull HabitCardListAdapter listAdapter,
- @NonNull CommandRunner commandRunner)
- {
- this.habitList = habitList;
- this.screen = screen;
- this.listAdapter = listAdapter;
- this.commandRunner = commandRunner;
- }
-
- @Override
- public void onFinish()
- {
- if (listController != null) listController.onSelectionFinished();
- super.onFinish();
- }
-
- @Override
- public boolean onItemClicked(@NonNull MenuItem item)
- {
- List selected = listAdapter.getSelected();
- if (selected.isEmpty()) return false;
-
- Habit firstHabit = selected.get(0);
-
- switch (item.getItemId())
- {
- case R.id.action_edit_habit:
- showEditScreen(firstHabit);
- finish();
- return true;
-
- case R.id.action_archive_habit:
- performArchive(selected);
- finish();
- return true;
-
- case R.id.action_unarchive_habit:
- performUnarchive(selected);
- finish();
- return true;
-
- case R.id.action_delete:
- performDelete(selected);
- return true;
-
- case R.id.action_color:
- showColorPicker(selected, firstHabit);
- return true;
-
- default:
- return false;
- }
- }
-
- @Override
- public boolean onPrepare(@NonNull Menu menu)
- {
- List selected = listAdapter.getSelected();
-
- boolean showEdit = (selected.size() == 1);
- boolean showArchive = true;
- boolean showUnarchive = true;
- for (Habit h : selected)
- {
- if (h.isArchived()) showArchive = false;
- else showUnarchive = false;
- }
-
- MenuItem itemEdit = menu.findItem(R.id.action_edit_habit);
- MenuItem itemColor = menu.findItem(R.id.action_color);
- MenuItem itemArchive = menu.findItem(R.id.action_archive_habit);
- MenuItem itemUnarchive = menu.findItem(R.id.action_unarchive_habit);
-
- itemColor.setVisible(true);
- itemEdit.setVisible(showEdit);
- itemArchive.setVisible(showArchive);
- itemUnarchive.setVisible(showUnarchive);
-
- setTitle(Integer.toString(selected.size()));
-
- return true;
- }
-
- @Override
- public void onSelectionChange()
- {
- invalidate();
- }
-
- @Override
- public void onSelectionFinish()
- {
- finish();
- }
-
- @Override
- public void onSelectionStart()
- {
- screen.startSelection();
- }
-
- public void setListController(HabitCardListController listController)
- {
- this.listController = listController;
- }
-
- @Override
- protected int getResourceId()
- {
- return R.menu.list_habits_selection;
- }
-
- private void performArchive(@NonNull List selected)
- {
- commandRunner.execute(new ArchiveHabitsCommand(habitList, selected),
- null);
- }
-
- private void performDelete(@NonNull List selected)
- {
- screen.showDeleteConfirmationScreen(() -> {
- listAdapter.performRemove(selected);
- commandRunner.execute(new DeleteHabitsCommand(habitList, selected),
- null);
- finish();
- });
- }
-
- private void performUnarchive(@NonNull List selected)
- {
- commandRunner.execute(new UnarchiveHabitsCommand(habitList, selected),
- null);
- }
-
- private void showColorPicker(@NonNull List selected,
- @NonNull Habit firstHabit)
- {
- screen.showColorPicker(firstHabit, color -> {
- commandRunner.execute(
- new ChangeHabitColorCommand(habitList, selected, color), null);
- finish();
- });
- }
-
- private void showEditScreen(@NonNull Habit firstHabit)
- {
- screen.showEditHabitScreen(firstHabit);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/CheckmarkButtonController.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/CheckmarkButtonController.java
deleted file mode 100644
index 382e12cda..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/CheckmarkButtonController.java
+++ /dev/null
@@ -1,99 +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.activities.habits.list.controllers;
-
-import android.support.annotation.*;
-
-import com.google.auto.factory.*;
-
-import org.isoron.uhabits.activities.habits.list.views.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.preferences.*;
-
-@AutoFactory
-public class CheckmarkButtonController
-{
- @Nullable
- private CheckmarkButtonView view;
-
- @Nullable
- private Listener listener;
-
- @NonNull
- private final Preferences prefs;
-
- @NonNull
- private Habit habit;
-
- private long timestamp;
-
- public CheckmarkButtonController(@Provided @NonNull Preferences prefs,
- @NonNull Habit habit,
- long timestamp)
- {
- this.habit = habit;
- this.timestamp = timestamp;
- this.prefs = prefs;
- }
-
- public void onClick()
- {
- if (prefs.isShortToggleEnabled()) performToggle();
- else performInvalidToggle();
- }
-
- public boolean onLongClick()
- {
- performToggle();
- return true;
- }
-
- public void performInvalidToggle()
- {
- if (listener != null) listener.onInvalidToggle();
- }
-
- public void performToggle()
- {
- if (view != null) view.toggle();
- if (listener != null) listener.onToggle(habit, timestamp);
- }
-
- public void setListener(@Nullable Listener listener)
- {
- this.listener = listener;
- }
-
- public void setView(@Nullable CheckmarkButtonView view)
- {
- this.view = view;
- }
-
- public interface Listener
- {
- /**
- * Called when the user's attempt to perform a toggle is rejected.
- */
- void onInvalidToggle();
-
-
- void onToggle(@NonNull Habit habit, long timestamp);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/HabitCardController.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/HabitCardController.java
deleted file mode 100644
index 01e2b4643..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/HabitCardController.java
+++ /dev/null
@@ -1,61 +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.activities.habits.list.controllers;
-
-import android.support.annotation.*;
-
-import org.isoron.uhabits.models.Habit;
-import org.isoron.uhabits.activities.habits.list.views.HabitCardView;
-
-public class HabitCardController implements HabitCardView.Controller
-{
- @Nullable
- private HabitCardView view;
-
- @Nullable
- private Listener listener;
-
- @Override
- public void onInvalidToggle()
- {
- if (listener != null) listener.onInvalidToggle();
- }
-
- @Override
- public void onToggle(@NonNull Habit habit, long timestamp)
- {
- if (view != null) view.triggerRipple(timestamp);
- if (listener != null) listener.onToggle(habit, timestamp);
- }
-
- public void setListener(@Nullable Listener listener)
- {
- this.listener = listener;
- }
-
- public void setView(@Nullable HabitCardView view)
- {
- this.view = view;
- }
-
- public interface Listener extends CheckmarkButtonController.Listener
- {
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/HabitCardListController.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/HabitCardListController.java
deleted file mode 100644
index d710c3572..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/HabitCardListController.java
+++ /dev/null
@@ -1,300 +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.activities.habits.list.controllers;
-
-import android.support.annotation.*;
-
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.activities.habits.list.model.*;
-import org.isoron.uhabits.activities.habits.list.views.*;
-
-/**
- * Controller responsible for receiving and processing the events generated by a
- * HabitListView. These include selecting and reordering items, toggling
- * checkmarks and clicking habits.
- */
-public class HabitCardListController implements HabitCardListView.Controller
-{
- private final Mode NORMAL_MODE = new NormalMode();
-
- private final Mode SELECTION_MODE = new SelectionMode();
-
- @NonNull
- private final HabitCardListAdapter adapter;
-
- @Nullable
- private HabitListener habitListener;
-
- @Nullable
- private SelectionListener selectionListener;
-
- @NonNull
- private Mode activeMode;
-
- public HabitCardListController(@NonNull HabitCardListAdapter adapter)
- {
- this.adapter = adapter;
- this.activeMode = new NormalMode();
- }
-
- /**
- * Called when the user drags a habit and drops it somewhere. Note that the
- * dragging operation is already complete.
- *
- * @param from the original position of the habit
- * @param to the position where the habit was released
- */
- @Override
- public void drop(int from, int to)
- {
- if (from == to) return;
- cancelSelection();
-
- Habit habitFrom = adapter.getItem(from);
- Habit habitTo = adapter.getItem(to);
- adapter.performReorder(from, to);
-
- if (habitListener != null)
- habitListener.onHabitReorder(habitFrom, habitTo);
- }
-
- /**
- * Called when the user attempts to perform a toggle, but attempt is
- * rejected.
- */
- @Override
- public void onInvalidToggle()
- {
- if (habitListener != null) habitListener.onInvalidToggle();
- }
-
- /**
- * Called when the user clicks at some item.
- *
- * @param position the position of the clicked item
- */
- @Override
- public void onItemClick(int position)
- {
- activeMode.onItemClick(position);
- }
-
- /**
- * Called when the user long clicks at some item.
- *
- * @param position the position of the clicked item
- */
- @Override
- public void onItemLongClick(int position)
- {
- activeMode.onItemLongClick(position);
- }
-
- /**
- * Called when the selection operation is cancelled externally, by something
- * other than this controller. This happens, for example, when the user
- * presses the back button.
- */
- public void onSelectionFinished()
- {
- cancelSelection();
- }
-
- /**
- * Called when the user wants to toggle a checkmark.
- *
- * @param habit the habit of the checkmark
- * @param timestamp the timestamps of the checkmark
- */
- @Override
- public void onToggle(@NonNull Habit habit, long timestamp)
- {
- if (habitListener != null) habitListener.onToggle(habit, timestamp);
- }
-
- public void setHabitListener(@Nullable HabitListener habitListener)
- {
- this.habitListener = habitListener;
- }
-
- public void setSelectionListener(@Nullable SelectionListener listener)
- {
- this.selectionListener = listener;
- }
-
- /**
- * Called when the user starts dragging an item.
- *
- * @param position the position of the habit dragged
- */
- @Override
- public void startDrag(int position)
- {
- activeMode.startDrag(position);
- }
-
- /**
- * Selects or deselects the item at a given position
- *
- * @param position the position of the item to be selected/deselected
- */
- protected void toggleSelection(int position)
- {
- adapter.toggleSelection(position);
- activeMode = adapter.isSelectionEmpty() ? NORMAL_MODE : SELECTION_MODE;
- }
-
- /**
- * Marks all items as not selected and finishes the selection operation.
- */
- private void cancelSelection()
- {
- adapter.clearSelection();
- activeMode = new NormalMode();
-
- if (selectionListener != null) selectionListener.onSelectionFinish();
- }
-
- public interface HabitListener extends CheckmarkButtonController.Listener
- {
- /**
- * Called when the user clicks a habit.
- *
- * @param habit the habit clicked
- */
- void onHabitClick(@NonNull Habit habit);
-
- /**
- * Called when the user wants to change the position of a habit on the
- * list.
- *
- * @param from habit to be moved
- * @param to habit that currently occupies the desired position
- */
- void onHabitReorder(@NonNull Habit from, @NonNull Habit to);
- }
-
- /**
- * A Mode describes the behaviour of the list upon clicking, long clicking
- * and dragging an item. This depends on whether some items are already
- * selected or not.
- */
- private interface Mode
- {
- void onItemClick(int position);
-
- boolean onItemLongClick(int position);
-
- void startDrag(int position);
- }
-
- public interface SelectionListener
- {
- /**
- * Called when the user changes the list of selected item. This is only
- * called if there were previously selected items. If the selection was
- * previously empty, then onHabitSelectionStart is called instead.
- */
- void onSelectionChange();
-
- /**
- * Called when the user deselects all items or cancels the selection.
- */
- void onSelectionFinish();
-
- /**
- * Called after the user selects the first item.
- */
- void onSelectionStart();
- }
-
- /**
- * Mode activated when there are no items selected. Clicks trigger habit
- * click. Long clicks start selection.
- */
- class NormalMode implements Mode
- {
- @Override
- public void onItemClick(int position)
- {
- Habit habit = adapter.getItem(position);
- if (habitListener != null) habitListener.onHabitClick(habit);
- }
-
- @Override
- public boolean onItemLongClick(int position)
- {
- startSelection(position);
- return true;
- }
-
- @Override
- public void startDrag(int position)
- {
- startSelection(position);
- }
-
- protected void startSelection(int position)
- {
- toggleSelection(position);
- activeMode = SELECTION_MODE;
- if (selectionListener != null) selectionListener.onSelectionStart();
- }
- }
-
- /**
- * Mode activated when some items are already selected.
- *
- * Clicks toggle item selection. Long clicks select more items.
- */
- class SelectionMode implements Mode
- {
- @Override
- public void onItemClick(int position)
- {
- toggleSelection(position);
- notifyListener();
- }
-
- @Override
- public boolean onItemLongClick(int position)
- {
- toggleSelection(position);
- notifyListener();
- return true;
- }
-
- @Override
- public void startDrag(int position)
- {
- toggleSelection(position);
- notifyListener();
- }
-
- protected void notifyListener()
- {
- if (selectionListener == null) return;
-
- if (activeMode == SELECTION_MODE)
- selectionListener.onSelectionChange();
- else selectionListener.onSelectionFinish();
- }
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/package-info.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/package-info.java
deleted file mode 100644
index c5b148812..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/package-info.java
+++ /dev/null
@@ -1,23 +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 .
- */
-
-/**
- * Provides controllers that are specific for {@link org.isoron.uhabits.activities.habits.list.ListHabitsActivity}.
- */
-package org.isoron.uhabits.activities.habits.list.controllers;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/model/package-info.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/model/package-info.java
deleted file mode 100644
index 755ffcaa1..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/model/package-info.java
+++ /dev/null
@@ -1,23 +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 .
- */
-
-/**
- * Provides models that are specific for {@link org.isoron.uhabits.activities.habits.list.ListHabitsActivity}.
- */
-package org.isoron.uhabits.activities.habits.list.model;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/package-info.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/package-info.java
deleted file mode 100644
index 1a39e29de..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/package-info.java
+++ /dev/null
@@ -1,23 +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 .
- */
-
-/**
- * Provides acitivity for listing habits and related classes.
- */
-package org.isoron.uhabits.activities.habits.list;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.java
deleted file mode 100644
index 818ccb615..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.java
+++ /dev/null
@@ -1,144 +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.activities.habits.list.views;
-
-import android.content.*;
-import android.content.res.*;
-import android.graphics.*;
-import android.support.annotation.*;
-import android.text.*;
-import android.util.*;
-import android.view.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.habits.list.controllers.*;
-import org.isoron.uhabits.utils.*;
-
-import static android.view.View.MeasureSpec.*;
-import static org.isoron.uhabits.models.Checkmark.*;
-import static org.isoron.uhabits.utils.AttributeSetUtils.*;
-
-public class CheckmarkButtonView extends View
-{
- private int color;
-
- private int value;
-
- private StyledResources styledRes;
-
- private TextPaint paint;
-
- private int lowContrastColor;
-
- private RectF rect;
-
- public CheckmarkButtonView(Context context)
- {
- super(context);
- init();
- }
-
- public CheckmarkButtonView(@Nullable Context ctx, @Nullable AttributeSet attrs)
- {
- super(ctx, attrs);
- init();
-
- if(ctx == null) throw new IllegalStateException();
- if(attrs == null) throw new IllegalStateException();
-
- int paletteColor = getIntAttribute(ctx, attrs, "color", 0);
- setColor(ColorUtils.getAndroidTestColor(paletteColor));
-
- int value = getIntAttribute(ctx, attrs, "value", 0);
- setValue(value);
- }
-
- public void setColor(int color)
- {
- this.color = color;
- postInvalidate();
- }
-
- public void setController(final CheckmarkButtonController controller)
- {
- setOnClickListener(v -> controller.onClick());
- setOnLongClickListener(v -> controller.onLongClick());
- }
-
- public void setValue(int value)
- {
- this.value = value;
- postInvalidate();
- }
-
- public void toggle()
- {
- value = (value == CHECKED_EXPLICITLY ? UNCHECKED : CHECKED_EXPLICITLY);
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- postInvalidate();
- }
-
- @Override
- protected void onDraw(Canvas canvas)
- {
- super.onDraw(canvas);
- Resources resources = getResources();
-
- paint.setColor(value == CHECKED_EXPLICITLY ? color : lowContrastColor);
- int id = (value == UNCHECKED ? R.string.fa_times : R.string.fa_check);
- String label = resources.getString(id);
- float em = paint.measureText("m");
-
- rect.set(0, 0, getWidth(), getHeight());
- rect.offset(0, 0.4f * em);
- canvas.drawText(label, rect.centerX(), rect.centerY(), paint);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- {
- Resources res = getResources();
- int height = res.getDimensionPixelSize(R.dimen.checkmarkHeight);
- int width = res.getDimensionPixelSize(R.dimen.checkmarkWidth);
-
- widthMeasureSpec = makeMeasureSpec(width, EXACTLY);
- heightMeasureSpec = makeMeasureSpec(height, EXACTLY);
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- private void init()
- {
- setFocusable(false);
-
- Resources res = getResources();
- styledRes = new StyledResources(getContext());
-
- paint = new TextPaint();
- paint.setTypeface(InterfaceUtils.getFontAwesome(getContext()));
- paint.setAntiAlias(true);
- paint.setTextAlign(Paint.Align.CENTER);
- paint.setTextSize(res.getDimension(R.dimen.regularTextSize));
-
- rect = new RectF();
- color = ColorUtils.getAndroidTestColor(0);
- lowContrastColor = styledRes.getColor(R.attr.lowContrastTextColor);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.java
deleted file mode 100644
index b569f9208..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.java
+++ /dev/null
@@ -1,222 +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.activities.habits.list.views;
-
-import android.content.*;
-import android.support.annotation.*;
-import android.util.*;
-import android.widget.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.habits.list.*;
-import org.isoron.uhabits.activities.habits.list.controllers.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.preferences.*;
-import org.isoron.uhabits.utils.*;
-
-import static android.view.View.MeasureSpec.*;
-
-public class CheckmarkPanelView extends LinearLayout implements Preferences.Listener
-{
- private static final int CHECKMARK_LEFT_TO_RIGHT = 0;
-
- private static final int CHECKMARK_RIGHT_TO_LEFT = 1;
-
- @Nullable
- private Preferences prefs;
-
- private int checkmarkValues[];
-
- private int nButtons;
-
- private int color;
-
- private Controller controller;
-
- @NonNull
- private Habit habit;
-
- private int dataOffset;
-
- public CheckmarkPanelView(Context context)
- {
- super(context);
- init();
- }
-
- public CheckmarkPanelView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- init();
- }
-
- public CheckmarkButtonView indexToButton(int i)
- {
- int position = i;
-
- if (getCheckmarkOrder() == CHECKMARK_RIGHT_TO_LEFT)
- position = nButtons - i - 1;
-
- return (CheckmarkButtonView) getChildAt(position);
- }
-
- public void setButtonCount(int newButtonCount)
- {
- if(nButtons != newButtonCount)
- {
- nButtons = newButtonCount;
- addCheckmarkButtons();
- }
-
- setupCheckmarkButtons();
- }
-
- public void setCheckmarkValues(int[] checkmarkValues)
- {
- this.checkmarkValues = checkmarkValues;
- setupCheckmarkButtons();
- }
-
- public void setColor(int color)
- {
- this.color = color;
- setupCheckmarkButtons();
- }
-
- public void setController(Controller controller)
- {
- this.controller = controller;
- setupCheckmarkButtons();
- }
-
- public void setDataOffset(int dataOffset)
- {
- this.dataOffset = dataOffset;
- setupCheckmarkButtons();
- }
-
- public void setHabit(@NonNull Habit habit)
- {
- this.habit = habit;
- setupCheckmarkButtons();
- }
-
- @Override
- protected void onMeasure(int widthSpec, int heightSpec)
- {
- float buttonWidth = getResources().getDimension(R.dimen.checkmarkWidth);
- float buttonHeight =
- getResources().getDimension(R.dimen.checkmarkHeight);
-
- float width = buttonWidth * nButtons;
-
- widthSpec = makeMeasureSpec((int) width, EXACTLY);
- heightSpec = makeMeasureSpec((int) buttonHeight, EXACTLY);
-
- super.onMeasure(widthSpec, heightSpec);
- }
-
- private void addCheckmarkButtons()
- {
- removeAllViews();
-
- for (int i = 0; i < nButtons; i++)
- addView(new CheckmarkButtonView(getContext()));
- }
-
- private int getCheckmarkOrder()
- {
- if (prefs == null) return CHECKMARK_LEFT_TO_RIGHT;
- return prefs.shouldReverseCheckmarks() ? CHECKMARK_RIGHT_TO_LEFT :
- CHECKMARK_LEFT_TO_RIGHT;
- }
-
- private void init()
- {
- Context appContext = getContext().getApplicationContext();
- if(appContext instanceof HabitsApplication)
- {
- HabitsApplication app = (HabitsApplication) appContext;
- prefs = app.getComponent().getPreferences();
- }
-
- setWillNotDraw(false);
- }
-
- private void setupButtonControllers(long timestamp,
- CheckmarkButtonView buttonView)
- {
- if (controller == null) return;
- if (!(getContext() instanceof ListHabitsActivity)) return;
-
- ListHabitsActivity activity = (ListHabitsActivity) getContext();
- CheckmarkButtonControllerFactory buttonControllerFactory = activity
- .getListHabitsComponent()
- .getCheckmarkButtonControllerFactory();
-
- CheckmarkButtonController buttonController =
- buttonControllerFactory.create(habit, timestamp);
- buttonController.setListener(controller);
- buttonController.setView(buttonView);
- buttonView.setController(buttonController);
- }
-
- private void setupCheckmarkButtons()
- {
- long timestamp = DateUtils.getStartOfToday();
- long day = DateUtils.millisecondsInOneDay;
- timestamp -= day * dataOffset;
-
- for (int i = 0; i < nButtons; i++)
- {
- CheckmarkButtonView buttonView = indexToButton(i);
- if(i + dataOffset >= checkmarkValues.length) break;
- buttonView.setValue(checkmarkValues[i + dataOffset]);
- buttonView.setColor(color);
- setupButtonControllers(timestamp, buttonView);
- timestamp -= day;
- }
- }
-
- @Override
- protected void onAttachedToWindow()
- {
- super.onAttachedToWindow();
- if(prefs != null) prefs.addListener(this);
- }
-
- @Override
- protected void onDetachedFromWindow()
- {
- if(prefs != null) prefs.removeListener(this);
- super.onDetachedFromWindow();
- }
-
- @Override
- public void onCheckmarkOrderChanged()
- {
- setupCheckmarkButtons();
- }
-
- public interface Controller extends CheckmarkButtonController.Listener
- {
-
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.java
deleted file mode 100644
index cd6f24dbe..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.java
+++ /dev/null
@@ -1,272 +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.activities.habits.list.views;
-
-import android.content.*;
-import android.os.*;
-import android.support.annotation.*;
-import android.support.v7.widget.*;
-import android.support.v7.widget.helper.*;
-import android.util.*;
-import android.view.*;
-
-import org.isoron.uhabits.activities.common.views.*;
-import org.isoron.uhabits.activities.habits.list.controllers.*;
-import org.isoron.uhabits.activities.habits.list.model.*;
-import org.isoron.uhabits.models.*;
-
-import java.util.*;
-
-public class HabitCardListView extends RecyclerView
-{
- @Nullable
- private HabitCardListAdapter adapter;
-
- @Nullable
- private Controller controller;
-
- private final ItemTouchHelper touchHelper;
-
- private int checkmarkCount;
-
- private int dataOffset;
-
- private LinkedList attachedHolders;
-
- public HabitCardListView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- setLongClickable(true);
- setHasFixedSize(true);
- setLayoutManager(new LinearLayoutManager(getContext()));
-
- TouchHelperCallback callback = new TouchHelperCallback();
- touchHelper = new ItemTouchHelper(callback);
- touchHelper.attachToRecyclerView(this);
-
- attachedHolders = new LinkedList<>();
- }
-
- public void attachCardView(HabitCardViewHolder holder)
- {
- attachedHolders.add(holder);
- }
-
- /**
- * Builds a new HabitCardView to be eventually added to this list,
- * containing the given data.
- *
- * @param holder the ViewHolder containing the HabitCardView that should
- * be built
- * @param habit the habit for this card
- * @param score the current score for the habit
- * @param checkmarks the list of checkmark values to be included in the
- * card
- * @param selected true if the card is selected, false otherwise
- * @return the HabitCardView generated
- */
- public View bindCardView(@NonNull HabitCardViewHolder holder,
- @NonNull Habit habit,
- int score,
- int[] checkmarks,
- boolean selected)
- {
- HabitCardView cardView = (HabitCardView) holder.itemView;
- cardView.setHabit(habit);
- cardView.setSelected(selected);
- cardView.setCheckmarkValues(checkmarks);
- cardView.setCheckmarkCount(checkmarkCount);
- cardView.setDataOffset(dataOffset);
- cardView.setScore(score);
- if (controller != null) setupCardViewController(holder);
- return cardView;
- }
-
- public View createCardView()
- {
- return new HabitCardView(getContext());
- }
-
- public void detachCardView(HabitCardViewHolder holder)
- {
- attachedHolders.remove(holder);
- }
-
- @Override
- public void setAdapter(RecyclerView.Adapter adapter)
- {
- this.adapter = (HabitCardListAdapter) adapter;
- super.setAdapter(adapter);
- }
-
- public void setCheckmarkCount(int checkmarkCount)
- {
- this.checkmarkCount = checkmarkCount;
- }
-
- public void setController(@Nullable Controller controller)
- {
- this.controller = controller;
- }
-
- public void setDataOffset(int dataOffset)
- {
- this.dataOffset = dataOffset;
- for (HabitCardViewHolder holder : attachedHolders)
- {
- HabitCardView cardView = (HabitCardView) holder.itemView;
- cardView.setDataOffset(dataOffset);
- }
- }
-
- @Override
- protected void onAttachedToWindow()
- {
- super.onAttachedToWindow();
- if (adapter != null) adapter.onAttached();
- }
-
- @Override
- protected void onDetachedFromWindow()
- {
- if (adapter != null) adapter.onDetached();
- super.onDetachedFromWindow();
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state)
- {
- if(!(state instanceof BundleSavedState))
- {
- super.onRestoreInstanceState(state);
- return;
- }
-
- BundleSavedState bss = (BundleSavedState) state;
- dataOffset = bss.bundle.getInt("dataOffset");
- super.onRestoreInstanceState(bss.getSuperState());
- }
-
- @Override
- protected Parcelable onSaveInstanceState()
- {
- Parcelable superState = super.onSaveInstanceState();
- Bundle bundle = new Bundle();
- bundle.putInt("dataOffset", dataOffset);
- return new BundleSavedState(superState, bundle);
- }
-
- protected void setupCardViewController(@NonNull HabitCardViewHolder holder)
- {
- HabitCardView cardView = (HabitCardView) holder.itemView;
- HabitCardController cardController = new HabitCardController();
- cardController.setListener(controller);
- cardView.setController(cardController);
- cardController.setView(cardView);
-
- GestureDetector detector = new GestureDetector(getContext(),
- new CardViewGestureDetector(holder));
-
- cardView.setOnTouchListener((v, ev) -> {
- detector.onTouchEvent(ev);
- return true;
- });
- }
-
- public interface Controller
- extends CheckmarkButtonController.Listener, HabitCardController.Listener
- {
- void drop(int from, int to);
-
- void onItemClick(int pos);
-
- void onItemLongClick(int pos);
-
- void startDrag(int position);
- }
-
- private class CardViewGestureDetector
- extends GestureDetector.SimpleOnGestureListener
- {
- @NonNull
- private final HabitCardViewHolder holder;
-
- public CardViewGestureDetector(@NonNull HabitCardViewHolder holder)
- {
- this.holder = holder;
- }
-
- @Override
- public void onLongPress(MotionEvent e)
- {
- int position = holder.getAdapterPosition();
- if (controller != null) controller.onItemLongClick(position);
- if (adapter.isSortable()) touchHelper.startDrag(holder);
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e)
- {
- int position = holder.getAdapterPosition();
- if (controller != null) controller.onItemClick(position);
- return true;
- }
- }
-
- class TouchHelperCallback extends ItemTouchHelper.Callback
- {
- @Override
- public int getMovementFlags(RecyclerView recyclerView,
- ViewHolder viewHolder)
- {
- int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
- int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
- return makeMovementFlags(dragFlags, swipeFlags);
- }
-
- @Override
- public boolean isItemViewSwipeEnabled()
- {
- return false;
- }
-
- @Override
- public boolean isLongPressDragEnabled()
- {
- return false;
- }
-
- @Override
- public boolean onMove(RecyclerView recyclerView,
- ViewHolder from,
- ViewHolder to)
- {
- if (controller == null) return false;
- controller.drop(from.getAdapterPosition(), to.getAdapterPosition());
- return true;
- }
-
- @Override
- public void onSwiped(ViewHolder viewHolder, int direction)
- {
- // NOP
- }
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java
deleted file mode 100644
index dd0e744fe..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java
+++ /dev/null
@@ -1,262 +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.activities.habits.list.views;
-
-import android.annotation.*;
-import android.content.*;
-import android.graphics.drawable.*;
-import android.os.*;
-import android.support.annotation.*;
-import android.util.*;
-import android.widget.*;
-
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.activities.common.views.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-
-import java.util.*;
-
-import butterknife.*;
-
-import static android.os.Build.VERSION.*;
-import static android.os.Build.VERSION_CODES.*;
-
-public class HabitCardView extends FrameLayout
- implements ModelObservable.Listener
-{
-
- private static final String EDIT_MODE_HABITS[] = {
- "Wake up early",
- "Wash dishes",
- "Exercise",
- "Meditate",
- "Play guitar",
- "Wash clothes",
- "Get a haircut"
- };
-
- @BindView(R.id.checkmarkPanel)
- CheckmarkPanelView checkmarkPanel;
-
- @BindView(R.id.innerFrame)
- LinearLayout innerFrame;
-
- @BindView(R.id.label)
- TextView label;
-
- @BindView(R.id.scoreRing)
- RingView scoreRing;
-
- private final Context context = getContext();
-
- private StyledResources res;
-
- @Nullable
- private Habit habit;
-
- private int dataOffset;
-
- public HabitCardView(Context context)
- {
- super(context);
- init();
- }
-
- public HabitCardView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- init();
- }
-
- @Override
- public void onModelChange()
- {
- new Handler(Looper.getMainLooper()).post(() -> refresh());
- }
-
- public void setCheckmarkCount(int checkmarkCount)
- {
- checkmarkPanel.setButtonCount(checkmarkCount);
- }
-
- public void setCheckmarkValues(int checkmarks[])
- {
- checkmarkPanel.setCheckmarkValues(checkmarks);
- postInvalidate();
- }
-
- public void setController(Controller controller)
- {
- checkmarkPanel.setController(null);
- if (controller == null) return;
- checkmarkPanel.setController(controller);
- }
-
- public void setDataOffset(int dataOffset)
- {
- this.dataOffset = dataOffset;
- checkmarkPanel.setDataOffset(dataOffset);
- }
-
- public void setHabit(@NonNull Habit habit)
- {
- if (this.habit != null) detachFromHabit();
-
- this.habit = habit;
- checkmarkPanel.setHabit(habit);
- refresh();
-
- attachToHabit();
- postInvalidate();
- }
-
- public void setScore(int score)
- {
- float percentage = (float) score / Score.MAX_VALUE;
- scoreRing.setPercentage(percentage);
- scoreRing.setPrecision(1.0f / 16);
- postInvalidate();
- }
-
- @Override
- public void setSelected(boolean isSelected)
- {
- super.setSelected(isSelected);
- updateBackground(isSelected);
- }
-
- public synchronized void triggerRipple(long timestamp)
- {
- long today = DateUtils.getStartOfToday();
- long day = DateUtils.millisecondsInOneDay;
- int offset = (int) ((today - timestamp) / day) - dataOffset;
- CheckmarkButtonView button = checkmarkPanel.indexToButton(offset);
- if (button == null) return;
-
- float y = button.getHeight() / 2.0f;
- float x = checkmarkPanel.getX() + button.getX() + button.getWidth() / 2;
- triggerRipple(x, y);
- }
-
- @Override
- protected void onDetachedFromWindow()
- {
- if (habit != null) detachFromHabit();
- super.onDetachedFromWindow();
- }
-
- private void attachToHabit()
- {
- if (habit != null) habit.getObservable().addListener(this);
- }
-
- private void detachFromHabit()
- {
- if (habit != null) habit.getObservable().removeListener(this);
- }
-
- private int getActiveColor(Habit habit)
- {
- int mediumContrastColor = res.getColor(R.attr.mediumContrastTextColor);
- int activeColor = ColorUtils.getColor(context, habit.getColor());
- if (habit.isArchived()) activeColor = mediumContrastColor;
-
- return activeColor;
- }
-
- private void init()
- {
- setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT));
-
- res = new StyledResources(getContext());
-
- inflate(context, R.layout.list_habits_card, this);
- ButterKnife.bind(this);
-
- innerFrame.setOnTouchListener((v, event) -> {
- if (SDK_INT >= LOLLIPOP)
- v.getBackground().setHotspot(event.getX(), event.getY());
- return false;
- });
-
- if (isInEditMode()) initEditMode();
- }
-
- @SuppressLint("SetTextI18n")
- private void initEditMode()
- {
- Random rand = new Random();
- int color = ColorUtils.getAndroidTestColor(rand.nextInt(10));
- int[] values = new int[5];
- for (int i = 0; i < 5; i++) values[i] = rand.nextInt(3);
-
- label.setText(EDIT_MODE_HABITS[rand.nextInt(EDIT_MODE_HABITS.length)]);
- label.setTextColor(color);
- scoreRing.setColor(color);
- scoreRing.setPercentage(rand.nextFloat());
- checkmarkPanel.setColor(color);
- checkmarkPanel.setCheckmarkValues(values);
- checkmarkPanel.setButtonCount(5);
- }
-
- private void refresh()
- {
- int color = getActiveColor(habit);
- label.setText(habit.getName());
- label.setTextColor(color);
- scoreRing.setColor(color);
- checkmarkPanel.setColor(color);
- postInvalidate();
- }
-
- private void triggerRipple(final float x, final float y)
- {
- final Drawable background = innerFrame.getBackground();
- if (SDK_INT >= LOLLIPOP) background.setHotspot(x, y);
- background.setState(new int[]{
- android.R.attr.state_pressed, android.R.attr.state_enabled
- });
- new Handler().postDelayed(() -> background.setState(new int[]{}), 25);
- }
-
- private void updateBackground(boolean isSelected)
- {
- if (SDK_INT >= LOLLIPOP)
- {
- if (isSelected)
- innerFrame.setBackgroundResource(R.drawable.selected_box);
- else innerFrame.setBackgroundResource(R.drawable.ripple);
- }
- else
- {
- Drawable background;
-
- if (isSelected)
- background = res.getDrawable(R.attr.selectedBackground);
- else background = res.getDrawable(R.attr.cardBackground);
-
- innerFrame.setBackgroundDrawable(background);
- }
- }
-
- public interface Controller extends CheckmarkPanelView.Controller {}
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HeaderView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HeaderView.java
deleted file mode 100644
index 4eb1f4317..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HeaderView.java
+++ /dev/null
@@ -1,187 +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.activities.habits.list.views;
-
-import android.content.*;
-import android.content.res.*;
-import android.graphics.*;
-import android.support.annotation.*;
-import android.text.*;
-import android.util.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.common.views.*;
-import org.isoron.uhabits.activities.habits.list.*;
-import org.isoron.uhabits.preferences.*;
-import org.isoron.uhabits.utils.*;
-
-import java.util.*;
-
-public class HeaderView extends ScrollableChart
- implements Preferences.Listener, MidnightTimer.MidnightListener
-{
-
- private int buttonCount;
-
- @Nullable
- private Preferences prefs;
-
- @Nullable
- private MidnightTimer midnightTimer;
-
- private final TextPaint paint;
-
- private RectF rect;
-
- public HeaderView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
-
- if (isInEditMode())
- {
- setButtonCount(5);
- }
-
- Context appContext = context.getApplicationContext();
- if (appContext instanceof HabitsApplication)
- {
- HabitsApplication app = (HabitsApplication) appContext;
- prefs = app.getComponent().getPreferences();
- }
-
- if (context instanceof ListHabitsActivity)
- {
- ListHabitsActivity activity = (ListHabitsActivity) context;
- midnightTimer = activity.getListHabitsComponent().getMidnightTimer();
- }
-
- Resources res = context.getResources();
- setScrollerBucketSize((int) res.getDimension(R.dimen.checkmarkWidth));
-
- StyledResources sr = new StyledResources(context);
- paint = new TextPaint();
- paint.setColor(Color.BLACK);
- paint.setAntiAlias(true);
- paint.setTextSize(getResources().getDimension(R.dimen.tinyTextSize));
- paint.setTextAlign(Paint.Align.CENTER);
- paint.setTypeface(Typeface.DEFAULT_BOLD);
- paint.setColor(sr.getColor(R.attr.mediumContrastTextColor));
-
- rect = new RectF();
- }
-
- @Override
- public void atMidnight()
- {
- post(() -> invalidate());
- }
-
- @Override
- public void onCheckmarkOrderChanged()
- {
- updateDirection();
- postInvalidate();
- }
-
- public void setButtonCount(int buttonCount)
- {
- this.buttonCount = buttonCount;
- postInvalidate();
- }
-
- @Override
- protected void onAttachedToWindow()
- {
- updateDirection();
- super.onAttachedToWindow();
- if (prefs != null) prefs.addListener(this);
- if (midnightTimer != null) midnightTimer.addListener(this);
- }
-
- private void updateDirection()
- {
- int direction = -1;
- if (shouldReverseCheckmarks()) direction *= -1;
- if (InterfaceUtils.isLayoutRtl(this)) direction *= -1;
- setDirection(direction);
- }
-
- @Override
- protected void onDetachedFromWindow()
- {
- if (midnightTimer != null) midnightTimer.removeListener(this);
- if (prefs != null) prefs.removeListener(this);
- super.onDetachedFromWindow();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- {
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = (int) getContext()
- .getResources()
- .getDimension(R.dimen.checkmarkHeight);
- setMeasuredDimension(width, height);
- }
-
- @Override
- protected void onDraw(Canvas canvas)
- {
- super.onDraw(canvas);
-
- GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
- Resources res = getContext().getResources();
- float width = res.getDimension(R.dimen.checkmarkWidth);
- float height = res.getDimension(R.dimen.checkmarkHeight);
- boolean reverse = shouldReverseCheckmarks();
- boolean isRtl = InterfaceUtils.isLayoutRtl(this);
-
- day.add(GregorianCalendar.DAY_OF_MONTH, -getDataOffset());
- float em = paint.measureText("m");
-
- for (int i = 0; i < buttonCount; i++)
- {
- rect.set(0, 0, width, height);
- rect.offset(canvas.getWidth(), 0);
-
- if(reverse) rect.offset(- (i + 1) * width, 0);
- else rect.offset((i - buttonCount) * width, 0);
-
- if (isRtl) rect.set(canvas.getWidth() - rect.right, rect.top,
- canvas.getWidth() - rect.left, rect.bottom);
-
- String text = DateUtils.formatHeaderDate(day).toUpperCase();
- String[] lines = text.split("\n");
-
- int y1 = (int)(rect.centerY() - 0.25 * em);
- int y2 = (int)(rect.centerY() + 1.25 * em);
-
- canvas.drawText(lines[0], rect.centerX(), y1, paint);
- canvas.drawText(lines[1], rect.centerX(), y2, paint);
- day.add(GregorianCalendar.DAY_OF_MONTH, -1);
- }
- }
-
- private boolean shouldReverseCheckmarks()
- {
- if (prefs == null) return false;
- return prefs.shouldReverseCheckmarks();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HintView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HintView.java
deleted file mode 100644
index f083b6fd2..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HintView.java
+++ /dev/null
@@ -1,134 +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.activities.habits.list.views;
-
-import android.animation.AnimatorListenerAdapter;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.activities.habits.list.model.HintList;
-
-import java.util.Random;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-
-public class HintView extends FrameLayout
-{
- @BindView(R.id.hintContent)
- TextView hintContent;
-
- @Nullable
- private HintList hintList;
-
- public HintView(Context context)
- {
- super(context);
- init();
- }
-
- public HintView(Context context, AttributeSet attrs)
- {
- super(context, attrs);
- init();
- }
-
- @Override
- public void onAttachedToWindow()
- {
- super.onAttachedToWindow();
- showNext();
- }
-
- /**
- * Sets the list of hints to be shown
- *
- * @param hintList the list of hints to be shown
- */
- public void setHints(@Nullable HintList hintList)
- {
- this.hintList = hintList;
- }
-
- private void dismiss()
- {
- animate().alpha(0f).setDuration(500).setListener(new DismissAnimator());
- }
-
- private void init()
- {
- addView(inflate(getContext(), R.layout.list_habits_hint, null));
- ButterKnife.bind(this);
-
- setVisibility(GONE);
- setClickable(true);
- setOnClickListener(v -> dismiss());
-
- if (isInEditMode()) initEditMode();
- }
-
- @SuppressLint("SetTextI18n")
- private void initEditMode()
- {
- String hints[] = {
- "Cats are the most popular pet in the United States: There " +
- "are 88 million pet cats and 74 million dogs.",
- "A cat has been mayor of Talkeetna, Alaska, for 15 years. " +
- "His name is Stubbs.",
- "Cats can’t taste sweetness."
- };
-
- int k = new Random().nextInt(hints.length);
- hintContent.setText(hints[k]);
- setVisibility(VISIBLE);
- setAlpha(1.0f);
- }
-
- protected void showNext()
- {
- if (hintList == null) return;
- if (!hintList.shouldShow()) return;
-
- String hint = hintList.pop();
- if (hint == null) return;
-
- hintContent.setText(hint);
- requestLayout();
-
- setAlpha(0.0f);
- setVisibility(View.VISIBLE);
- animate().alpha(1f).setDuration(500);
- }
-
- private class DismissAnimator extends AnimatorListenerAdapter
- {
- @Override
- public void onAnimationEnd(android.animation.Animator animation)
- {
- setVisibility(View.GONE);
- }
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.java b/app/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.java
deleted file mode 100644
index 7d9a90eef..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.java
+++ /dev/null
@@ -1,74 +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.activities.habits.show;
-
-import android.content.*;
-import android.net.*;
-import android.os.*;
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.models.*;
-
-/**
- * Activity that allows the user to see more information about a single habit.
- *
- * Shows all the metadata for the habit, in addition to several charts.
- */
-public class ShowHabitActivity extends BaseActivity
-{
- private HabitList habits;
-
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- HabitsApplication app = (HabitsApplication) getApplicationContext();
- habits = app.getComponent().getHabitList();
- Habit habit = getHabitFromIntent();
-
- ShowHabitComponent component = DaggerShowHabitComponent
- .builder()
- .appComponent(app.getComponent())
- .showHabitModule(new ShowHabitModule(this, habit))
- .build();
-
- ShowHabitRootView rootView = component.getRootView();
- ShowHabitScreen screen = component.getScreen();
-
- setScreen(screen);
- screen.setMenu(component.getMenu());
- screen.setController(component.getController());
- rootView.setController(component.getController());
-
- screen.reattachDialogs();
- }
-
- @NonNull
- private Habit getHabitFromIntent()
- {
- Uri data = getIntent().getData();
- Habit habit = habits.getById(ContentUris.parseId(data));
- if (habit == null) throw new RuntimeException("habit not found");
- return habit;
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/show/package-info.java b/app/src/main/java/org/isoron/uhabits/activities/habits/show/package-info.java
deleted file mode 100644
index ca132a6c7..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/habits/show/package-info.java
+++ /dev/null
@@ -1,24 +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 .
- */
-
-/**
- * Provides activity that displays detailed habit information and related
- * classes.
- */
-package org.isoron.uhabits.activities.habits.show;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/activities/intro/package-info.java b/app/src/main/java/org/isoron/uhabits/activities/intro/package-info.java
deleted file mode 100644
index 4023d1b94..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/intro/package-info.java
+++ /dev/null
@@ -1,23 +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 .
- */
-
-/**
- * Provides activity that introduces app to the user and related classes.
- */
-package org.isoron.uhabits.activities.intro;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java b/app/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java
deleted file mode 100644
index 330e05b34..000000000
--- a/app/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.java
+++ /dev/null
@@ -1,127 +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.activities.settings;
-
-import android.app.backup.*;
-import android.content.*;
-import android.os.*;
-import android.support.v7.preference.*;
-
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.activities.habits.list.*;
-import org.isoron.uhabits.utils.*;
-
-public class SettingsFragment extends PreferenceFragmentCompat
- implements SharedPreferences.OnSharedPreferenceChangeListener
-{
- private static int RINGTONE_REQUEST_CODE = 1;
-
- private SharedPreferences prefs;
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data)
- {
- if (requestCode == RINGTONE_REQUEST_CODE)
- {
- RingtoneUtils.parseRingtoneData(getContext(), data);
- updateRingtoneDescription();
- return;
- }
-
- super.onActivityResult(requestCode, resultCode, data);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.preferences);
-
- setResultOnPreferenceClick("importData", ListHabitsScreen.RESULT_IMPORT_DATA);
- setResultOnPreferenceClick("exportCSV", ListHabitsScreen.RESULT_EXPORT_CSV);
- setResultOnPreferenceClick("exportDB", ListHabitsScreen.RESULT_EXPORT_DB);
- setResultOnPreferenceClick("repairDB", ListHabitsScreen.RESULT_REPAIR_DB);
- setResultOnPreferenceClick("bugReport", ListHabitsScreen.RESULT_BUG_REPORT);
-
- updateRingtoneDescription();
- }
-
- @Override
- public void onCreatePreferences(Bundle bundle, String s)
- {
- // NOP
- }
-
- @Override
- public void onPause()
- {
- prefs.unregisterOnSharedPreferenceChangeListener(this);
- super.onPause();
- }
-
- @Override
- public boolean onPreferenceTreeClick(Preference preference)
- {
- String key = preference.getKey();
- if (key == null) return false;
-
- if (key.equals("reminderSound"))
- {
- RingtoneUtils.startRingtonePickerActivity(this,
- RINGTONE_REQUEST_CODE);
- return true;
- }
-
- return super.onPreferenceTreeClick(preference);
- }
-
- @Override
- public void onResume()
- {
- super.onResume();
- prefs = getPreferenceManager().getSharedPreferences();
- prefs.registerOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key)
- {
- BackupManager.dataChanged("org.isoron.uhabits");
- }
-
- private void setResultOnPreferenceClick(String key, final int result)
- {
- Preference pref = findPreference(key);
- pref.setOnPreferenceClickListener(preference -> {
- getActivity().setResult(result);
- getActivity().finish();
- return true;
- });
- }
-
- private void updateRingtoneDescription()
- {
- String ringtoneName = RingtoneUtils.getRingtoneName(getContext());
- if (ringtoneName == null) return;
- Preference ringtonePreference = findPreference("reminderSound");
- ringtonePreference.setSummary(ringtoneName);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/automation/EditSettingActivity.java b/app/src/main/java/org/isoron/uhabits/automation/EditSettingActivity.java
deleted file mode 100644
index d92e73480..000000000
--- a/app/src/main/java/org/isoron/uhabits/automation/EditSettingActivity.java
+++ /dev/null
@@ -1,50 +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.automation;
-
-import android.os.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.models.*;
-
-public class EditSettingActivity extends BaseActivity
-{
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- HabitsApplication app = (HabitsApplication) getApplicationContext();
-
- HabitList habits = app.getComponent().getHabitList();
- habits = habits.getFiltered(new HabitMatcherBuilder()
- .setArchivedAllowed(false)
- .setCompletedAllowed(true)
- .build());
-
- EditSettingController controller = new EditSettingController(this);
- EditSettingRootView rootView =
- new EditSettingRootView(this, habits, controller);
-
- BaseScreen screen = new BaseScreen(this);
- screen.setRootView(rootView);
- setScreen(screen);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/automation/EditSettingController.java b/app/src/main/java/org/isoron/uhabits/automation/EditSettingController.java
deleted file mode 100644
index 478170496..000000000
--- a/app/src/main/java/org/isoron/uhabits/automation/EditSettingController.java
+++ /dev/null
@@ -1,78 +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.automation;
-
-import android.app.*;
-import android.content.*;
-import android.os.*;
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-
-import static org.isoron.uhabits.automation.FireSettingReceiver.*;
-
-public class EditSettingController
-{
- @NonNull
- private final Activity activity;
-
- public EditSettingController(@NonNull Activity activity)
- {
- this.activity = activity;
- }
-
- public void onSave(Habit habit, int action)
- {
- if (habit.getId() == null) return;
-
- String actionName = getActionName(action);
- String blurb = String.format("%s: %s", actionName, habit.getName());
-
- Bundle bundle = new Bundle();
- bundle.putInt("action", action);
- bundle.putLong("habit", habit.getId());
-
- Intent intent = new Intent();
- intent.putExtra(EXTRA_STRING_BLURB, blurb);
- intent.putExtra(EXTRA_BUNDLE, bundle);
-
- activity.setResult(Activity.RESULT_OK, intent);
- activity.finish();
- }
-
- private String getActionName(int action)
- {
- switch (action)
- {
- case ACTION_CHECK:
- return activity.getString(R.string.check);
-
- case ACTION_UNCHECK:
- return activity.getString(R.string.uncheck);
-
- case ACTION_TOGGLE:
- return activity.getString(R.string.toggle);
-
- default:
- return "???";
- }
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/automation/EditSettingRootView.java b/app/src/main/java/org/isoron/uhabits/automation/EditSettingRootView.java
deleted file mode 100644
index 10fad0a0d..000000000
--- a/app/src/main/java/org/isoron/uhabits/automation/EditSettingRootView.java
+++ /dev/null
@@ -1,105 +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.automation;
-
-import android.content.*;
-import android.support.annotation.*;
-import android.support.v7.widget.*;
-import android.support.v7.widget.Toolbar;
-import android.widget.*;
-
-import org.isoron.uhabits.R;
-import org.isoron.uhabits.activities.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-
-import java.util.*;
-
-import butterknife.*;
-
-import static android.R.layout.*;
-
-public class EditSettingRootView extends BaseRootView
-{
- @BindView(R.id.toolbar)
- Toolbar toolbar;
-
- @BindView(R.id.habitSpinner)
- AppCompatSpinner habitSpinner;
-
- @BindView(R.id.actionSpinner)
- AppCompatSpinner actionSpinner;
-
- @NonNull
- private final HabitList habitList;
-
- @NonNull
- private final EditSettingController controller;
-
- public EditSettingRootView(@NonNull Context context,
- @NonNull HabitList habitList,
- @NonNull EditSettingController controller)
- {
- super(context);
- this.habitList = habitList;
- this.controller = controller;
-
- addView(inflate(getContext(), R.layout.automation, null));
- ButterKnife.bind(this);
- populateHabitSpinner();
- }
-
- @NonNull
- @Override
- public Toolbar getToolbar()
- {
- return toolbar;
- }
-
- @Override
- public int getToolbarColor()
- {
- StyledResources res = new StyledResources(getContext());
- if (!res.getBoolean(R.attr.useHabitColorAsPrimary))
- return super.getToolbarColor();
-
- return res.getColor(R.attr.aboutScreenColor);
- }
-
- @OnClick(R.id.buttonSave)
- public void onClickSave()
- {
- int action = actionSpinner.getSelectedItemPosition();
- int habitPosition = habitSpinner.getSelectedItemPosition();
- Habit habit = habitList.getByPosition(habitPosition);
- controller.onSave(habit, action);
- }
-
- private void populateHabitSpinner()
- {
- List names = new LinkedList<>();
- for (Habit h : habitList) names.add(h.getName());
-
- ArrayAdapter adapter =
- new ArrayAdapter<>(getContext(), simple_spinner_item, names);
- adapter.setDropDownViewResource(simple_spinner_dropdown_item);
- habitSpinner.setAdapter(adapter);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.java b/app/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.java
deleted file mode 100644
index 7ff6af588..000000000
--- a/app/src/main/java/org/isoron/uhabits/automation/FireSettingReceiver.java
+++ /dev/null
@@ -1,114 +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.automation;
-
-import android.content.*;
-import android.os.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.receivers.*;
-import org.isoron.uhabits.utils.*;
-
-import dagger.*;
-
-public class FireSettingReceiver extends BroadcastReceiver
-{
- public static final int ACTION_CHECK = 0;
-
- public static final int ACTION_UNCHECK = 1;
-
- public static final int ACTION_TOGGLE = 2;
-
- public static final String EXTRA_BUNDLE =
- "com.twofortyfouram.locale.intent.extra.BUNDLE";
-
- public static final String EXTRA_STRING_BLURB =
- "com.twofortyfouram.locale.intent.extra.BLURB";
-
- private HabitList allHabits;
-
- @Override
- public void onReceive(Context context, Intent intent)
- {
- HabitsApplication app =
- (HabitsApplication) context.getApplicationContext();
-
- ReceiverComponent component =
- DaggerFireSettingReceiver_ReceiverComponent
- .builder()
- .appComponent(app.getComponent())
- .build();
-
- allHabits = app.getComponent().getHabitList();
-
- Arguments args = parseIntent(intent);
- if (args == null) return;
-
- long timestamp = DateUtils.getStartOfToday();
- WidgetController controller = component.getWidgetController();
-
- switch (args.action)
- {
- case ACTION_CHECK:
- controller.onAddRepetition(args.habit, timestamp);
- break;
-
- case ACTION_UNCHECK:
- controller.onRemoveRepetition(args.habit, timestamp);
- break;
-
- case ACTION_TOGGLE:
- controller.onToggleRepetition(args.habit, timestamp);
- break;
- }
- }
-
- private Arguments parseIntent(Intent intent)
- {
- Arguments args = new Arguments();
-
- Bundle bundle = intent.getBundleExtra(EXTRA_BUNDLE);
- if (bundle == null) return null;
-
- args.action = bundle.getInt("action");
- if (args.action < 0 || args.action > 2) return null;
-
- Habit habit = allHabits.getById(bundle.getLong("habit"));
- if (habit == null) return null;
- args.habit = habit;
-
- return args;
- }
-
- @ReceiverScope
- @Component(dependencies = AppComponent.class)
- interface ReceiverComponent
- {
- WidgetController getWidgetController();
- }
-
- private class Arguments
- {
- int action;
-
- Habit habit;
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/commands/ArchiveHabitsCommand.java b/app/src/main/java/org/isoron/uhabits/commands/ArchiveHabitsCommand.java
deleted file mode 100644
index 51993e7c7..000000000
--- a/app/src/main/java/org/isoron/uhabits/commands/ArchiveHabitsCommand.java
+++ /dev/null
@@ -1,67 +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.commands;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-
-import java.util.*;
-
-/**
- * Command to archive a list of habits.
- */
-public class ArchiveHabitsCommand extends Command
-{
- private List selectedHabits;
-
- private final HabitList habitList;
-
- public ArchiveHabitsCommand(HabitList habitList, List selectedHabits)
- {
- this.habitList = habitList;
- this.selectedHabits = selectedHabits;
- }
-
- @Override
- public void execute()
- {
- for (Habit h : selectedHabits) h.setArchived(true);
- habitList.update(selectedHabits);
- }
-
- @Override
- public Integer getExecuteStringId()
- {
- return R.string.toast_habit_archived;
- }
-
- @Override
- public Integer getUndoStringId()
- {
- return R.string.toast_habit_unarchived;
- }
-
- @Override
- public void undo()
- {
- for (Habit h : selectedHabits) h.setArchived(false);
- habitList.update(selectedHabits);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/commands/ChangeHabitColorCommand.java b/app/src/main/java/org/isoron/uhabits/commands/ChangeHabitColorCommand.java
deleted file mode 100644
index 503acc40f..000000000
--- a/app/src/main/java/org/isoron/uhabits/commands/ChangeHabitColorCommand.java
+++ /dev/null
@@ -1,78 +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.commands;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-
-import java.util.*;
-
-/**
- * Command to change the color of a list of habits.
- */
-public class ChangeHabitColorCommand extends Command
-{
- HabitList habitList;
-
- List selected;
-
- List originalColors;
-
- Integer newColor;
-
- public ChangeHabitColorCommand(HabitList habitList,
- List selected,
- Integer newColor)
- {
- this.habitList = habitList;
- this.selected = selected;
- this.newColor = newColor;
- this.originalColors = new ArrayList<>(selected.size());
-
- for (Habit h : selected) originalColors.add(h.getColor());
- }
-
- @Override
- public void execute()
- {
- for (Habit h : selected) h.setColor(newColor);
- habitList.update(selected);
- }
-
- @Override
- public Integer getExecuteStringId()
- {
- return R.string.toast_habit_changed;
- }
-
- @Override
- public Integer getUndoStringId()
- {
- return R.string.toast_habit_changed;
- }
-
- @Override
- public void undo()
- {
- int k = 0;
- for (Habit h : selected) h.setColor(originalColors.get(k++));
- habitList.update(selected);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/commands/DeleteHabitsCommand.java b/app/src/main/java/org/isoron/uhabits/commands/DeleteHabitsCommand.java
deleted file mode 100644
index ca184d8bf..000000000
--- a/app/src/main/java/org/isoron/uhabits/commands/DeleteHabitsCommand.java
+++ /dev/null
@@ -1,71 +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.commands;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-
-import java.util.*;
-
-/**
- * Command to delete a list of habits.
- */
-public class DeleteHabitsCommand extends Command
-{
- HabitList habitList;
-
- private List habits;
-
- public DeleteHabitsCommand(HabitList habitList, List habits)
- {
- this.habits = habits;
- this.habitList = habitList;
- }
-
- @Override
- public void execute()
- {
- for (Habit h : habits)
- habitList.remove(h);
- }
-
- @Override
- public Integer getExecuteStringId()
- {
- return R.string.toast_habit_deleted;
- }
-
- public List getHabits()
- {
- return new LinkedList<>(habits);
- }
-
- @Override
- public Integer getUndoStringId()
- {
- return R.string.toast_habit_restored;
- }
-
- @Override
- public void undo()
- {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/commands/ToggleRepetitionCommand.java b/app/src/main/java/org/isoron/uhabits/commands/ToggleRepetitionCommand.java
deleted file mode 100644
index 5cc2fa8ba..000000000
--- a/app/src/main/java/org/isoron/uhabits/commands/ToggleRepetitionCommand.java
+++ /dev/null
@@ -1,54 +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.commands;
-
-import org.isoron.uhabits.models.*;
-
-/**
- * Command to toggle a repetition.
- */
-public class ToggleRepetitionCommand extends Command
-{
- private Long offset;
- private Habit habit;
-
- public ToggleRepetitionCommand(Habit habit, long offset)
- {
- this.offset = offset;
- this.habit = habit;
- }
-
- @Override
- public void execute()
- {
- habit.getRepetitions().toggleTimestamp(offset);
- }
-
- @Override
- public void undo()
- {
- execute();
- }
-
- public Habit getHabit()
- {
- return habit;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/commands/UnarchiveHabitsCommand.java b/app/src/main/java/org/isoron/uhabits/commands/UnarchiveHabitsCommand.java
deleted file mode 100644
index 6e45cda7b..000000000
--- a/app/src/main/java/org/isoron/uhabits/commands/UnarchiveHabitsCommand.java
+++ /dev/null
@@ -1,67 +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.commands;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-
-import java.util.*;
-
-/**
- * Command to unarchive a list of habits.
- */
-public class UnarchiveHabitsCommand extends Command
-{
- HabitList habitList;
-
- private List habits;
-
- public UnarchiveHabitsCommand(HabitList habitList, List selected)
- {
- this.habits = selected;
- this.habitList = habitList;
- }
-
- @Override
- public void execute()
- {
- for(Habit h : habits) h.setArchived(false);
- habitList.update(habits);
- }
-
- @Override
- public void undo()
- {
- for(Habit h : habits) h.setArchived(true);
- habitList.update(habits);
- }
-
- @Override
- public Integer getExecuteStringId()
- {
- return R.string.toast_habit_unarchived;
- }
-
- @Override
- public Integer getUndoStringId()
- {
- return R.string.toast_habit_archived;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/intents/IntentFactory.java b/app/src/main/java/org/isoron/uhabits/intents/IntentFactory.java
deleted file mode 100644
index 47172d2fa..000000000
--- a/app/src/main/java/org/isoron/uhabits/intents/IntentFactory.java
+++ /dev/null
@@ -1,111 +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.intents;
-
-import android.content.*;
-import android.net.*;
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.activities.about.*;
-import org.isoron.uhabits.activities.habits.show.*;
-import org.isoron.uhabits.activities.intro.*;
-import org.isoron.uhabits.activities.settings.*;
-import org.isoron.uhabits.models.*;
-
-import javax.inject.*;
-
-public class IntentFactory
-{
- @Inject
- public IntentFactory()
- {
- }
-
- public Intent helpTranslate(Context context)
- {
- String url = context.getString(R.string.translateURL);
- return buildViewIntent(url);
- }
-
- public Intent rateApp(Context context)
- {
- String url = context.getString(R.string.playStoreURL);
- return buildViewIntent(url);
- }
-
- public Intent sendFeedback(Context context)
- {
- String url = context.getString(R.string.feedbackURL);
- return buildSendToIntent(url);
- }
-
- public Intent startAboutActivity(Context context)
- {
- return new Intent(context, AboutActivity.class);
- }
-
- public Intent startIntroActivity(Context context)
- {
- return new Intent(context, IntroActivity.class);
- }
-
- public Intent startSettingsActivity(Context context)
- {
- return new Intent(context, SettingsActivity.class);
- }
-
- public Intent startShowHabitActivity(Context context, Habit habit)
- {
- Intent intent = new Intent(context, ShowHabitActivity.class);
- intent.setData(habit.getUri());
- return intent;
- }
-
- public Intent viewFAQ(Context context)
- {
- String url = context.getString(R.string.helpURL);
- return buildViewIntent(url);
- }
-
- public Intent viewSourceCode(Context context)
- {
- String url = context.getString(R.string.sourceCodeURL);
- return buildViewIntent(url);
- }
-
- @NonNull
- private Intent buildSendToIntent(String url)
- {
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_SENDTO);
- intent.setData(Uri.parse(url));
- return intent;
- }
-
- @NonNull
- private Intent buildViewIntent(String url)
- {
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- return intent;
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/intents/IntentParser.java b/app/src/main/java/org/isoron/uhabits/intents/IntentParser.java
deleted file mode 100644
index a6dc23e3f..000000000
--- a/app/src/main/java/org/isoron/uhabits/intents/IntentParser.java
+++ /dev/null
@@ -1,84 +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.intents;
-
-import android.content.*;
-import android.net.*;
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.*;
-
-import javax.inject.*;
-
-import static android.content.ContentUris.*;
-
-@AppScope
-public class IntentParser
-{
- private HabitList habits;
-
- @Inject
- public IntentParser(@NonNull HabitList habits)
- {
- this.habits = habits;
- }
-
- public CheckmarkIntentData parseCheckmarkIntent(@NonNull Intent intent)
- {
- Uri uri = intent.getData();
- if (uri == null) throw new IllegalArgumentException("uri is null");
-
- CheckmarkIntentData data = new CheckmarkIntentData();
- data.habit = parseHabit(uri);
- data.timestamp = parseTimestamp(intent);
- return data;
- }
-
- @NonNull
- protected Habit parseHabit(@NonNull Uri uri)
- {
- Habit habit = habits.getById(parseId(uri));
- if (habit == null)
- throw new IllegalArgumentException("habit not found");
- return habit;
- }
-
- @NonNull
- protected Long parseTimestamp(@NonNull Intent intent)
- {
- long today = DateUtils.getStartOfToday();
- Long timestamp = intent.getLongExtra("timestamp", today);
- timestamp = DateUtils.getStartOfDay(timestamp);
-
- if (timestamp < 0 || timestamp > today)
- throw new IllegalArgumentException("timestamp is not valid");
-
- return timestamp;
- }
-
- public class CheckmarkIntentData
- {
- public Habit habit;
-
- public Long timestamp;
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/intents/IntentScheduler.java b/app/src/main/java/org/isoron/uhabits/intents/IntentScheduler.java
deleted file mode 100644
index 47dd4eebf..000000000
--- a/app/src/main/java/org/isoron/uhabits/intents/IntentScheduler.java
+++ /dev/null
@@ -1,61 +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.intents;
-
-import android.app.*;
-import android.content.*;
-import android.os.*;
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-
-import javax.inject.*;
-
-import static android.app.AlarmManager.*;
-import static android.content.Context.*;
-
-@AppScope
-public class IntentScheduler
-{
- private final AlarmManager manager;
-
- @Inject
- public IntentScheduler(@AppContext Context context)
- {
- manager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
- }
-
- public void schedule(@NonNull Long timestamp, PendingIntent intent)
- {
- if (Build.VERSION.SDK_INT >= 23)
- {
- manager.setExactAndAllowWhileIdle(RTC_WAKEUP, timestamp, intent);
- return;
- }
-
- if (Build.VERSION.SDK_INT >= 19)
- {
- manager.setExact(RTC_WAKEUP, timestamp, intent);
- return;
- }
-
- manager.set(RTC_WAKEUP, timestamp, intent);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.java b/app/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.java
deleted file mode 100644
index 415f9237a..000000000
--- a/app/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.java
+++ /dev/null
@@ -1,117 +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.intents;
-
-import android.app.*;
-import android.content.*;
-import android.net.*;
-import android.support.annotation.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.receivers.*;
-
-import javax.inject.*;
-
-import static android.app.PendingIntent.*;
-
-@AppScope
-public class PendingIntentFactory
-{
- private final Context context;
-
- private IntentFactory intentFactory;
-
- @Inject
- public PendingIntentFactory(@AppContext Context context,
- @NonNull IntentFactory intentFactory)
- {
- this.context = context;
- this.intentFactory = intentFactory;
- }
-
- public PendingIntent addCheckmark(@NonNull Habit habit,
- @Nullable Long timestamp)
- {
- Intent checkIntent = new Intent(context, WidgetReceiver.class);
- checkIntent.setData(habit.getUri());
- checkIntent.setAction(WidgetReceiver.ACTION_ADD_REPETITION);
- if (timestamp != null) checkIntent.putExtra("timestamp", timestamp);
- return PendingIntent.getBroadcast(context, 1, checkIntent,
- FLAG_UPDATE_CURRENT);
- }
-
- public PendingIntent dismissNotification(@NonNull Habit habit)
- {
- Intent deleteIntent = new Intent(context, ReminderReceiver.class);
- deleteIntent.setAction(WidgetReceiver.ACTION_DISMISS_REMINDER);
- deleteIntent.setData(habit.getUri());
- return PendingIntent.getBroadcast(context, 0, deleteIntent,
- FLAG_UPDATE_CURRENT);
- }
-
- public PendingIntent showHabit(Habit habit)
- {
- Intent intent = intentFactory.startShowHabitActivity(context, habit);
-
- return android.support.v4.app.TaskStackBuilder
- .create(context)
- .addNextIntentWithParentStack(intent)
- .getPendingIntent(0, FLAG_UPDATE_CURRENT);
- }
-
- public PendingIntent showReminder(@NonNull Habit habit,
- @Nullable Long reminderTime,
- long timestamp)
- {
- Uri uri = habit.getUri();
-
- Intent intent = new Intent(context, ReminderReceiver.class);
- intent.setAction(ReminderReceiver.ACTION_SHOW_REMINDER);
- intent.setData(uri);
- intent.putExtra("timestamp", timestamp);
- intent.putExtra("reminderTime", reminderTime);
- int reqCode = ((int) (habit.getId() % Integer.MAX_VALUE)) + 1;
- return PendingIntent.getBroadcast(context, reqCode, intent,
- FLAG_UPDATE_CURRENT);
- }
-
- public PendingIntent snoozeNotification(@NonNull Habit habit)
- {
- Uri data = habit.getUri();
- Intent snoozeIntent = new Intent(context, ReminderReceiver.class);
- snoozeIntent.setData(data);
- snoozeIntent.setAction(ReminderReceiver.ACTION_SNOOZE_REMINDER);
- return PendingIntent.getBroadcast(context, 0, snoozeIntent,
- FLAG_UPDATE_CURRENT);
- }
-
- public PendingIntent toggleCheckmark(@NonNull Habit habit,
- @Nullable Long timestamp)
- {
- Uri data = habit.getUri();
- Intent checkIntent = new Intent(context, WidgetReceiver.class);
- checkIntent.setData(data);
- checkIntent.setAction(WidgetReceiver.ACTION_TOGGLE_REPETITION);
- if (timestamp != null) checkIntent.putExtra("timestamp", timestamp);
- return PendingIntent.getBroadcast(context, 2, checkIntent,
- FLAG_UPDATE_CURRENT);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/io/DirFinder.java b/app/src/main/java/org/isoron/uhabits/io/DirFinder.java
deleted file mode 100644
index 392f7716c..000000000
--- a/app/src/main/java/org/isoron/uhabits/io/DirFinder.java
+++ /dev/null
@@ -1,106 +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.io;
-
-import android.content.*;
-import android.os.*;
-import android.support.annotation.*;
-import android.util.*;
-
-import org.isoron.uhabits.*;
-
-import java.io.*;
-
-import javax.inject.*;
-
-import static android.support.v4.content.ContextCompat.*;
-
-/**
- * A DirFinder locates suitable directories for storing user files.
- */
-public class DirFinder
-{
- private static final String TAG = "DirFinder";
-
- private final Context context;
-
- @Inject
- public DirFinder(@AppContext Context context)
- {
- this.context = context;
- }
-
- @Nullable
- public File findSDCardDir(@Nullable String subpath)
- {
- File parents[] = new File[]{
- Environment.getExternalStorageDirectory()
- };
-
- return findDir(parents, subpath);
- }
-
- @Nullable
- public File findStorageDir(@Nullable String relativePath)
- {
- File potentialParents[] = getExternalFilesDirs(context, null);
-
- if (potentialParents == null)
- {
- Log.e(TAG, "getFilesDir: getExternalFilesDirs returned null");
- return null;
- }
-
- return findDir(potentialParents, relativePath);
- }
-
- @Nullable
- private File findDir(@NonNull File potentialParents[],
- @Nullable String relativePath)
- {
- if (relativePath == null) relativePath = "";
-
- File chosenDir = null;
- for (File dir : potentialParents)
- {
- if (dir == null || !dir.canWrite()) continue;
- chosenDir = dir;
- break;
- }
-
- if (chosenDir == null)
- {
- Log.e(TAG,
- "getDir: all potential parents are null or non-writable");
- return null;
- }
-
- File dir = new File(
- String.format("%s/%s/", chosenDir.getAbsolutePath(), relativePath));
- if (!dir.exists() && !dir.mkdirs())
- {
- Log.e(TAG,
- "getDir: chosen dir does not exist and cannot be created");
- return null;
- }
-
- return dir;
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/io/LoopDBImporter.java b/app/src/main/java/org/isoron/uhabits/io/LoopDBImporter.java
deleted file mode 100644
index bfcf5886f..000000000
--- a/app/src/main/java/org/isoron/uhabits/io/LoopDBImporter.java
+++ /dev/null
@@ -1,96 +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.io;
-
-import android.content.*;
-import android.database.*;
-import android.database.sqlite.*;
-import android.support.annotation.*;
-import android.util.*;
-
-import com.activeandroid.*;
-
-import org.isoron.uhabits.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.utils.DatabaseUtils;
-import org.isoron.uhabits.utils.*;
-
-import java.io.*;
-
-import javax.inject.*;
-
-/**
- * Class that imports data from database files exported by Loop Habit Tracker.
- */
-public class LoopDBImporter extends AbstractImporter
-{
- @NonNull
- private Context context;
-
- @Inject
- public LoopDBImporter(@NonNull @AppContext Context context,
- @NonNull HabitList habits)
- {
- super(habits);
- this.context = context;
- }
-
- @Override
- public boolean canHandle(@NonNull File file) throws IOException
- {
- if (!isSQLite3File(file)) return false;
-
- SQLiteDatabase db = SQLiteDatabase.openDatabase(file.getPath(), null,
- SQLiteDatabase.OPEN_READONLY);
-
- boolean canHandle = true;
-
- Cursor c = db.rawQuery(
- "select count(*) from SQLITE_MASTER where name=? or name=?",
- new String[]{ "Checkmarks", "Repetitions" });
-
- if (!c.moveToFirst() || c.getInt(0) != 2)
- {
- Log.w("LoopDBImporter", "Cannot handle file: tables not found");
- canHandle = false;
- }
-
- if (db.getVersion() > BuildConfig.databaseVersion)
- {
- Log.w("LoopDBImporter", String.format(
- "Cannot handle file: incompatible version: %d > %d",
- db.getVersion(), BuildConfig.databaseVersion));
- canHandle = false;
- }
-
- c.close();
- db.close();
- return canHandle;
- }
-
- @Override
- public void importHabitsFromFile(@NonNull File file) throws IOException
- {
- ActiveAndroid.dispose();
- File originalDB = DatabaseUtils.getDatabaseFile(context);
- FileUtils.copy(file, originalDB);
- DatabaseUtils.initializeActiveAndroid(context);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/io/package-info.java b/app/src/main/java/org/isoron/uhabits/io/package-info.java
deleted file mode 100644
index 5cbd932fb..000000000
--- a/app/src/main/java/org/isoron/uhabits/io/package-info.java
+++ /dev/null
@@ -1,23 +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 .
- */
-
-/**
- * Provides classes that deal with importing from and exporting to files.
- */
-package org.isoron.uhabits.io;
\ No newline at end of file
diff --git a/app/src/main/java/org/isoron/uhabits/models/CheckmarkList.java b/app/src/main/java/org/isoron/uhabits/models/CheckmarkList.java
deleted file mode 100644
index 0556038fd..000000000
--- a/app/src/main/java/org/isoron/uhabits/models/CheckmarkList.java
+++ /dev/null
@@ -1,291 +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.models;
-
-import android.support.annotation.*;
-
-import org.isoron.uhabits.utils.*;
-
-import java.io.*;
-import java.text.*;
-import java.util.*;
-
-/**
- * The collection of {@link Checkmark}s belonging to a habit.
- */
-public abstract class CheckmarkList
-{
- protected Habit habit;
-
- public ModelObservable observable = new ModelObservable();
-
- public CheckmarkList(Habit habit)
- {
- this.habit = habit;
- }
-
- /**
- * Adds all the given checkmarks to the list.
- *
- * This should never be called by the application, since the checkmarks are
- * computed automatically from the list of repetitions.
- *
- * @param checkmarks the checkmarks to be added.
- */
- public abstract void add(List checkmarks);
-
- /**
- * Returns the values for all the checkmarks, since the oldest repetition of
- * the habit until today.
- *
- * If there are no repetitions at all, returns an empty array. The values
- * are returned in an array containing one integer value for each day since
- * the first repetition of the habit until today. The first entry
- * corresponds to today, the second entry corresponds to yesterday, and so
- * on.
- *
- * @return values for the checkmarks in the interval
- */
- @NonNull
- public final int[] getAllValues()
- {
- Repetition oldestRep = habit.getRepetitions().getOldest();
- if (oldestRep == null) return new int[0];
-
- Long fromTimestamp = oldestRep.getTimestamp();
- Long toTimestamp = DateUtils.getStartOfToday();
-
- return getValues(fromTimestamp, toTimestamp);
- }
-
- /**
- * Returns the list of checkmarks that fall within the given interval.
- *
- * There is exactly one checkmark per day in the interval. The endpoints of
- * the interval are included. The list is ordered by timestamp (decreasing).
- * That is, the first checkmark corresponds to the newest timestamp, and the
- * last checkmark corresponds to the oldest timestamp.
- *
- * @param fromTimestamp timestamp of the beginning of the interval.
- * @param toTimestamp timestamp of the end of the interval.
- * @return the list of checkmarks within the interval.
- */
- @NonNull
- public abstract List getByInterval(long fromTimestamp,
- long toTimestamp);
-
- /**
- * Returns the checkmark for today.
- *
- * @return checkmark for today
- */
- @Nullable
- public final Checkmark getToday()
- {
- computeAll();
- return getNewestComputed();
- }
-
- /**
- * Returns the value of today's checkmark.
- *
- * @return value of today's checkmark
- */
- public int getTodayValue()
- {
- Checkmark today = getToday();
- if (today != null) return today.getValue();
- else return Checkmark.UNCHECKED;
- }
-
- /**
- * Returns the values of the checkmarks that fall inside a certain interval
- * of time.
- *
- * The values are returned in an array containing one integer value for each
- * day of the interval. The first entry corresponds to the most recent day
- * in the interval. Each subsequent entry corresponds to one day older than
- * the previous entry. The boundaries of the time interval are included.
- *
- * @param from timestamp for the oldest checkmark
- * @param to timestamp for the newest checkmark
- * @return values for the checkmarks inside the given interval
- */
- public final int[] getValues(long from, long to)
- {
- if(from > to) return new int[0];
-
- List checkmarks = getByInterval(from, to);
- int values[] = new int[checkmarks.size()];
-
- int i = 0;
- for (Checkmark c : checkmarks)
- values[i++] = c.getValue();
-
- return values;
- }
-
- /**
- * Marks as invalid every checkmark that has timestamp either equal or newer
- * than a given timestamp. These checkmarks will be recomputed at the next
- * time they are queried.
- *
- * @param timestamp the timestamp
- */
- public abstract void invalidateNewerThan(long timestamp);
-
- /**
- * Writes the entire list of checkmarks to the given writer, in CSV format.
- *
- * @param out the writer where the CSV will be output
- * @throws IOException in case write operations fail
- */
- public final void writeCSV(Writer out) throws IOException
- {
- computeAll();
-
- int values[] = getAllValues();
- long timestamp = DateUtils.getStartOfToday();
- SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat();
-
- for (int value : values)
- {
- String date = dateFormat.format(new Date(timestamp));
- out.write(String.format("%s,%d\n", date, value));
- timestamp -= DateUtils.millisecondsInOneDay;
- }
- }
-
- /**
- * Computes and stores one checkmark for each day that falls inside the
- * specified interval of time. Days that already have a corresponding
- * checkmark are skipped.
- *
- * This method assumes the list of computed checkmarks has no holes. That
- * is, if there is a checkmark computed at time t1 and another at time t2,
- * then every checkmark between t1 and t2 is also computed.
- *
- * @param from timestamp for the beginning of the interval
- * @param to timestamp for the end of the interval
- */
- protected final synchronized void compute(long from, long to)
- {
- final long day = DateUtils.millisecondsInOneDay;
-
- Checkmark newest = getNewestComputed();
- Checkmark oldest = getOldestComputed();
-
- if (newest == null || oldest == null)
- {
- forceRecompute(from, to);
- }
- else
- {
- forceRecompute(from, oldest.getTimestamp() - day);
- forceRecompute(newest.getTimestamp() + day, to);
- }
- }
-
- /**
- * Returns oldest checkmark that has already been computed.
- *
- * @return oldest checkmark already computed
- */
- @Nullable
- protected abstract Checkmark getOldestComputed();
-
- /**
- * Computes and stores one checkmark for each day that falls inside the
- * specified interval of time.
- *
- * This method does not check if the checkmarks have already been
- * computed or not. If they have, then duplicate checkmarks will
- * be stored, which is a bad thing.
- *
- * @param from timestamp for the beginning of the interval
- * @param to timestamp for the end of the interval
- */
- private synchronized void forceRecompute(long from, long to)
- {
- if (from > to) return;
-
- final long day = DateUtils.millisecondsInOneDay;
- Frequency freq = habit.getFrequency();
-
- long fromExtended = from - (long) (freq.getDenominator()) * day;
- List reps =
- habit.getRepetitions().getByInterval(fromExtended, to);
-
- final int nDays = (int) ((to - from) / day) + 1;
- int nDaysExtended = (int) ((to - fromExtended) / day) + 1;
- final int checks[] = new int[nDaysExtended];
-
- for (Repetition rep : reps)
- {
- int offset = (int) ((rep.getTimestamp() - fromExtended) / day);
- checks[nDaysExtended - offset - 1] = Checkmark.CHECKED_EXPLICITLY;
- }
-
- for (int i = 0; i < nDays; i++)
- {
- int counter = 0;
-
- for (int j = 0; j < freq.getDenominator(); j++)
- if (checks[i + j] == 2) counter++;
-
- if (counter >= freq.getNumerator())
- if (checks[i] != Checkmark.CHECKED_EXPLICITLY)
- checks[i] = Checkmark.CHECKED_IMPLICITLY;
- }
-
- List checkmarks = new LinkedList<>();
-
- for (int i = 0; i < nDays; i++)
- {
- int value = checks[i];
- long timestamp = to - i * day;
- checkmarks.add(new Checkmark(timestamp, value));
- }
-
- add(checkmarks);
- }
-
- /**
- * Computes and stores one checkmark for each day, since the first
- * repetition of the habit until today. Days that already have a
- * corresponding checkmark are skipped.
- */
- protected final void computeAll()
- {
- Repetition oldest = habit.getRepetitions().getOldest();
- if (oldest == null) return;
-
- Long today = DateUtils.getStartOfToday();
- compute(oldest.getTimestamp(), today);
- }
-
- /**
- * Returns newest checkmark that has already been computed.
- *
- * @return newest checkmark already computed
- */
- @Nullable
- protected abstract Checkmark getNewestComputed();
-}
diff --git a/app/src/main/java/org/isoron/uhabits/models/Habit.java b/app/src/main/java/org/isoron/uhabits/models/Habit.java
deleted file mode 100644
index 5ba711407..000000000
--- a/app/src/main/java/org/isoron/uhabits/models/Habit.java
+++ /dev/null
@@ -1,277 +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.models;
-
-import android.net.*;
-import android.support.annotation.*;
-
-import org.apache.commons.lang3.builder.*;
-
-import java.util.*;
-
-import javax.inject.*;
-
-/**
- * The thing that the user wants to track.
- */
-public class Habit
-{
- public static final String HABIT_URI_FORMAT =
- "content://org.isoron.uhabits/habit/%d";
-
- @Nullable
- private Long id;
-
- @NonNull
- private String name;
-
- @NonNull
- private String description;
-
- @NonNull
- private Frequency frequency;
-
- @NonNull
- private Integer color;
-
- @NonNull
- private boolean archived;
-
- @NonNull
- private StreakList streaks;
-
- @NonNull
- private ScoreList scores;
-
- @NonNull
- private RepetitionList repetitions;
-
- @NonNull
- private CheckmarkList checkmarks;
-
- @Nullable
- private Reminder reminder;
-
- private ModelObservable observable = new ModelObservable();
-
- /**
- * Constructs a habit with default attributes.
- *
- * The habit is not archived, not highlighted, has no reminders and is
- * placed in the last position of the list of habits.
- */
- @Inject
- Habit(@NonNull ModelFactory factory)
- {
- this.color = 5;
- this.archived = false;
- this.frequency = new Frequency(3, 7);
-
- checkmarks = factory.buildCheckmarkList(this);
- streaks = factory.buildStreakList(this);
- scores = factory.buildScoreList(this);
- repetitions = factory.buildRepetitionList(this);
- }
-
- /**
- * Clears the reminder for a habit.
- */
- public void clearReminder()
- {
- reminder = null;
- observable.notifyListeners();
- }
-
- /**
- * Copies all the attributes of the specified habit into this habit
- *
- * @param model the model whose attributes should be copied from
- */
- public void copyFrom(@NonNull Habit model)
- {
- this.name = model.getName();
- this.description = model.getDescription();
- this.color = model.getColor();
- this.archived = model.isArchived();
- this.frequency = model.frequency;
- this.reminder = model.reminder;
- observable.notifyListeners();
- }
-
- /**
- * List of checkmarks belonging to this habit.
- */
- @NonNull
- public CheckmarkList getCheckmarks()
- {
- return checkmarks;
- }
-
- /**
- * Color of the habit.
- *
- * This number is not an android.graphics.Color, but an index to the
- * activity color palette, which changes according to the theme. To convert
- * this color into an android.graphics.Color, use ColorHelper.getColor(context,
- * habit.color).
- */
- @NonNull
- public Integer getColor()
- {
- return color;
- }
-
- public void setColor(@NonNull Integer color)
- {
- this.color = color;
- }
-
- @NonNull
- public String getDescription()
- {
- return description;
- }
-
- public void setDescription(@NonNull String description)
- {
- this.description = description;
- }
-
- @NonNull
- public Frequency getFrequency()
- {
- return frequency;
- }
-
- public void setFrequency(@NonNull Frequency frequency)
- {
- this.frequency = frequency;
- }
-
- @Nullable
- public Long getId()
- {
- return id;
- }
-
- public void setId(@Nullable Long id)
- {
- this.id = id;
- }
-
- @NonNull
- public String getName()
- {
- return name;
- }
-
- public void setName(@NonNull String name)
- {
- this.name = name;
- }
-
- public ModelObservable getObservable()
- {
- return observable;
- }
-
- /**
- * Returns the reminder for this habit.
- *
- * Before calling this method, you should call {@link #hasReminder()} to
- * verify that a reminder does exist, otherwise an exception will be
- * thrown.
- *
- * @return the reminder for this habit
- * @throws IllegalStateException if habit has no reminder
- */
- @NonNull
- public Reminder getReminder()
- {
- if (reminder == null) throw new IllegalStateException();
- return reminder;
- }
-
- public void setReminder(@Nullable Reminder reminder)
- {
- this.reminder = reminder;
- }
-
- @NonNull
- public RepetitionList getRepetitions()
- {
- return repetitions;
- }
-
- @NonNull
- public ScoreList getScores()
- {
- return scores;
- }
-
- @NonNull
- public StreakList getStreaks()
- {
- return streaks;
- }
-
- /**
- * Returns the public URI that identifies this habit
- *
- * @return the uri
- */
- public Uri getUri()
- {
- String s = String.format(Locale.US, HABIT_URI_FORMAT, getId());
- return Uri.parse(s);
- }
-
- /**
- * Returns whether the habit has a reminder.
- *
- * @return true if habit has reminder, false otherwise
- */
- public boolean hasReminder()
- {
- return reminder != null;
- }
-
- public boolean isArchived()
- {
- return archived;
- }
-
- public void setArchived(boolean archived)
- {
- this.archived = archived;
- }
-
- @Override
- public String toString()
- {
- return new ToStringBuilder(this)
- .append("id", id)
- .append("name", name)
- .append("description", description)
- .append("color", color)
- .append("archived", archived)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/models/Repetition.java b/app/src/main/java/org/isoron/uhabits/models/Repetition.java
deleted file mode 100644
index 72e378205..000000000
--- a/app/src/main/java/org/isoron/uhabits/models/Repetition.java
+++ /dev/null
@@ -1,58 +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.models;
-
-import org.apache.commons.lang3.builder.*;
-
-/**
- * Represents a record that the user has performed a certain habit at a certain
- * date.
- */
-public final class Repetition
-{
-
- private final long timestamp;
-
- /**
- * Creates a new repetition with given parameters.
- *
- * The timestamp corresponds to the days this repetition occurred. Time of
- * day must be midnight (UTC).
- *
- * @param timestamp the time this repetition occurred.
- */
- public Repetition(long timestamp)
- {
- this.timestamp = timestamp;
- }
-
- public long getTimestamp()
- {
- return timestamp;
- }
-
- @Override
- public String toString()
- {
- return new ToStringBuilder(this)
- .append("timestamp", timestamp)
- .toString();
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/models/memory/MemoryHabitList.java b/app/src/main/java/org/isoron/uhabits/models/memory/MemoryHabitList.java
deleted file mode 100644
index 601852122..000000000
--- a/app/src/main/java/org/isoron/uhabits/models/memory/MemoryHabitList.java
+++ /dev/null
@@ -1,181 +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.models.memory;
-
-import android.support.annotation.*;
-
-import org.isoron.uhabits.models.*;
-
-import java.util.*;
-
-import static org.isoron.uhabits.models.HabitList.Order.*;
-
-/**
- * In-memory implementation of {@link HabitList}.
- */
-public class MemoryHabitList extends HabitList
-{
- @NonNull
- private LinkedList list;
-
- private Comparator comparator = null;
-
- @NonNull
- private Order order;
-
- public MemoryHabitList()
- {
- super();
- list = new LinkedList<>();
- order = Order.BY_POSITION;
- }
-
- protected MemoryHabitList(@NonNull HabitMatcher matcher)
- {
- super(matcher);
- list = new LinkedList<>();
- order = Order.BY_POSITION;
- }
-
- @Override
- public void add(@NonNull Habit habit) throws IllegalArgumentException
- {
- if (list.contains(habit))
- throw new IllegalArgumentException("habit already added");
-
- Long id = habit.getId();
- if (id != null && getById(id) != null)
- throw new RuntimeException("duplicate id");
-
- if (id == null) habit.setId((long) list.size());
- list.addLast(habit);
- resort();
- }
-
- @Override
- public Habit getById(long id)
- {
- for (Habit h : list)
- {
- if (h.getId() == null) continue;
- if (h.getId() == id) return h;
- }
- return null;
- }
-
- @NonNull
- @Override
- public Habit getByPosition(int position)
- {
- return list.get(position);
- }
-
- @NonNull
- @Override
- public HabitList getFiltered(HabitMatcher matcher)
- {
- MemoryHabitList habits = new MemoryHabitList(matcher);
- habits.comparator = comparator;
- for (Habit h : this) if (matcher.matches(h)) habits.add(h);
- return habits;
- }
-
- @Override
- public Order getOrder()
- {
- return order;
- }
-
- @Override
- public int indexOf(@NonNull Habit h)
- {
- return list.indexOf(h);
- }
-
- @Override
- public Iterator iterator()
- {
- return Collections.unmodifiableCollection(list).iterator();
- }
-
- @Override
- public void remove(@NonNull Habit habit)
- {
- list.remove(habit);
- }
-
- @Override
- public void reorder(Habit from, Habit to)
- {
- int toPos = indexOf(to);
- list.remove(from);
- list.add(toPos, from);
- }
-
- @Override
- public void setOrder(@NonNull Order order)
- {
- this.order = order;
- this.comparator = getComparatorByOrder(order);
- resort();
- }
-
- @Override
- public int size()
- {
- return list.size();
- }
-
- @Override
- public void update(List habits)
- {
- // NOP
- }
-
- private Comparator getComparatorByOrder(Order order)
- {
- Comparator nameComparator =
- (h1, h2) -> h1.getName().compareTo(h2.getName());
-
- Comparator colorComparator = (h1, h2) -> {
- Integer c1 = h1.getColor();
- Integer c2 = h2.getColor();
- if (c1.equals(c2)) return nameComparator.compare(h1, h2);
- else return c1.compareTo(c2);
- };
-
- Comparator scoreComparator = (h1, h2) -> {
- int s1 = h1.getScores().getTodayValue();
- int s2 = h2.getScores().getTodayValue();
- return Integer.compare(s2, s1);
- };
-
- if (order == BY_POSITION) return null;
- if (order == BY_NAME) return nameComparator;
- if (order == BY_COLOR) return colorComparator;
- if (order == BY_SCORE) return scoreComparator;
- throw new IllegalStateException();
- }
-
- private void resort()
- {
- if (comparator != null) Collections.sort(list, comparator);
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteCheckmarkList.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteCheckmarkList.java
deleted file mode 100644
index d41a8684a..000000000
--- a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteCheckmarkList.java
+++ /dev/null
@@ -1,224 +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.models.sqlite;
-
-import android.database.sqlite.*;
-import android.support.annotation.*;
-import android.support.annotation.Nullable;
-
-import com.activeandroid.*;
-
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.records.*;
-import org.isoron.uhabits.utils.*;
-import org.jetbrains.annotations.*;
-
-import java.util.*;
-
-/**
- * Implementation of a {@link CheckmarkList} that is backed by SQLite.
- */
-public class SQLiteCheckmarkList extends CheckmarkList
-{
-
- private static final String ADD_QUERY =
- "insert into Checkmarks(habit, timestamp, value) values (?,?,?)";
-
- private static final String INVALIDATE_QUERY =
- "delete from Checkmarks where habit = ? and timestamp >= ?";
-
- @Nullable
- private HabitRecord habitRecord;
-
- @NonNull
- private final SQLiteUtils sqlite;
-
- @Nullable
- private CachedData cache;
-
- public SQLiteCheckmarkList(Habit habit)
- {
- super(habit);
- sqlite = new SQLiteUtils<>(CheckmarkRecord.class);
- }
-
- @Override
- public void add(List checkmarks)
- {
- check(habit.getId());
- SQLiteDatabase db = Cache.openDatabase();
- SQLiteStatement statement = db.compileStatement(ADD_QUERY);
- db.beginTransaction();
- try
- {
- for (Checkmark c : checkmarks)
- {
- statement.bindLong(1, habit.getId());
- statement.bindLong(2, c.getTimestamp());
- statement.bindLong(3, c.getValue());
- statement.execute();
- }
-
- db.setTransactionSuccessful();
- }
- finally
- {
- db.endTransaction();
- }
- }
-
- @NonNull
- @Override
- public List getByInterval(long fromTimestamp, long toTimestamp)
- {
- check(habit.getId());
- compute(fromTimestamp, toTimestamp);
-
- String query = "select habit, timestamp, value from checkmarks " +
- "where habit = ? and timestamp >= ? and timestamp <= ? " +
- "order by timestamp desc";
-
- String params[] = {
- Long.toString(habit.getId()),
- Long.toString(fromTimestamp),
- Long.toString(toTimestamp)
- };
-
- List records = sqlite.query(query, params);
- for (CheckmarkRecord record : records) record.habit = habitRecord;
-
- records = fixRecords(records, habitRecord, fromTimestamp, toTimestamp);
- return toCheckmarks(records);
- }
-
- @Override
- public int getTodayValue()
- {
- if (cache == null || cache.expired())
- cache = new CachedData(super.getTodayValue());
-
- return cache.todayValue;
- }
-
- @Override
- public void invalidateNewerThan(long timestamp)
- {
- cache = null;
- SQLiteDatabase db = Cache.openDatabase();
- SQLiteStatement statement = db.compileStatement(INVALIDATE_QUERY);
- statement.bindLong(1, habit.getId());
- statement.bindLong(2, timestamp);
- statement.execute();
- observable.notifyListeners();
- }
-
- @Override
- @Nullable
- protected Checkmark getNewestComputed()
- {
- check(habit.getId());
- String query = "select habit, timestamp, value from checkmarks " +
- "where habit = ? " + "order by timestamp desc " +
- "limit 1";
-
- String params[] = { Long.toString(habit.getId()) };
- return getSingleCheckmarkFromQuery(query, params);
- }
-
- @Override
- @Nullable
- protected Checkmark getOldestComputed()
- {
- check(habit.getId());
- String query = "select habit, timestamp, value from checkmarks " +
- "where habit = ? " + "order by timestamp asc " +
- "limit 1";
-
- String params[] = { Long.toString(habit.getId()) };
- return getSingleCheckmarkFromQuery(query, params);
- }
-
- @Contract("null -> fail")
- private void check(Long id)
- {
- if (id == null) throw new RuntimeException("habit is not saved");
- if (habitRecord != null) return;
-
- habitRecord = HabitRecord.get(id);
- if (habitRecord == null) throw new RuntimeException("habit not found");
- }
-
- @Nullable
- private Checkmark getSingleCheckmarkFromQuery(String query, String params[])
- {
- CheckmarkRecord record = sqlite.querySingle(query, params);
- if (record == null) return null;
- record.habit = habitRecord;
- return record.toCheckmark();
- }
-
- @NonNull
- private List toCheckmarks(@NonNull List records)
- {
- List checkmarks = new LinkedList<>();
- for (CheckmarkRecord r : records) checkmarks.add(r.toCheckmark());
- return checkmarks;
- }
-
- public static List fixRecords(List original,
- HabitRecord habit,
- long fromTimestamp,
- long toTimestamp)
- {
- long day = DateUtils.millisecondsInOneDay;
- ArrayList records = new ArrayList<>();
-
- for (long t = toTimestamp; t >= fromTimestamp; t -= day)
- records.add(new CheckmarkRecord(habit, t, Checkmark.UNCHECKED));
-
- for (CheckmarkRecord record : original)
- {
- if ((toTimestamp - record.timestamp) % day != 0) continue;
- int offset = (int) ((toTimestamp - record.timestamp) / day);
- if (offset < 0 || offset >= records.size()) continue;
- records.set(offset, record);
- }
-
- return records;
- }
-
- private static class CachedData
- {
- int todayValue;
-
- private long today;
-
- CachedData(int todayValue)
- {
- this.todayValue = todayValue;
- this.today = DateUtils.getStartOfToday();
- }
-
- boolean expired()
- {
- return today != DateUtils.getStartOfToday();
- }
- }
-}
diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteHabitList.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteHabitList.java
deleted file mode 100644
index 397299827..000000000
--- a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteHabitList.java
+++ /dev/null
@@ -1,337 +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.models.sqlite;
-
-import android.support.annotation.*;
-
-import com.activeandroid.query.*;
-import com.activeandroid.util.*;
-
-import org.apache.commons.lang3.*;
-import org.isoron.uhabits.models.*;
-import org.isoron.uhabits.models.sqlite.records.*;
-
-import java.util.*;
-
-/**
- * Implementation of a {@link HabitList} that is backed by SQLite.
- */
-public class SQLiteHabitList extends HabitList
-{
- private static HashMap cache;
-
- private static SQLiteHabitList instance;
-
- @NonNull
- private final SQLiteUtils sqlite;
-
- @NonNull
- private final ModelFactory modelFactory;
-
- @NonNull
- private Order order;
-
- public SQLiteHabitList(@NonNull ModelFactory modelFactory)
- {
- super();
- this.modelFactory = modelFactory;
-
- if (cache == null) cache = new HashMap<>();
- sqlite = new SQLiteUtils<>(HabitRecord.class);
- order = Order.BY_POSITION;
- }
-
- protected SQLiteHabitList(@NonNull ModelFactory modelFactory,
- @NonNull HabitMatcher filter,
- @NonNull Order order)
- {
- super(filter);
- this.modelFactory = modelFactory;
-
- if (cache == null) cache = new HashMap<>();
- sqlite = new SQLiteUtils<>(HabitRecord.class);
- this.order = order;
- }
-
- public static SQLiteHabitList getInstance(
- @NonNull ModelFactory modelFactory)
- {
- if (instance == null) instance = new SQLiteHabitList(modelFactory);
- return instance;
- }
-
- @Override
- public void add(@NonNull Habit habit)
- {
- if (cache.containsValue(habit))
- throw new IllegalArgumentException("habit already added");
-
- HabitRecord record = new HabitRecord();
- record.copyFrom(habit);
- record.position = size();
-
- Long id = habit.getId();
- if (id == null) id = record.save();
- else record.save(id);
-
- if (id < 0)
- throw new IllegalArgumentException("habit could not be saved");
-
- habit.setId(id);
- cache.put(id, habit);
- }
-
- @Override
- @Nullable
- public Habit getById(long id)
- {
- if (!cache.containsKey(id))
- {
- HabitRecord record = HabitRecord.get(id);
- if (record == null) return null;
-
- Habit habit = modelFactory.buildHabit();
- record.copyTo(habit);
- cache.put(id, habit);
- }
-
- return cache.get(id);
- }
-
- @Override
- @NonNull
- public Habit getByPosition(int position)
- {
- return toList().get(position);
- }
-
- @NonNull
- @Override
- public HabitList getFiltered(HabitMatcher filter)
- {
- return new SQLiteHabitList(modelFactory, filter, order);
- }
-
- @Override
- @NonNull
- public Order getOrder()
- {
- return order;
- }
-
- @Override
- public void setOrder(@NonNull Order order)
- {
- this.order = order;
- }
-
- @Override
- public int indexOf(@NonNull Habit h)
- {
- return toList().indexOf(h);
- }
-
- @Override
- public Iterator iterator()
- {
- return Collections.unmodifiableCollection(toList()).iterator();
- }
-
- public void rebuildOrder()
- {
- List habits = toList();
-
- int i = 0;
- for (Habit h : habits)
- {
- HabitRecord record = HabitRecord.get(h.getId());
- if (record == null)
- throw new RuntimeException("habit not in database");
-
- record.position = i++;
- record.save();
- }
-
- update(habits);
- }
-
- @Override
- public void remove(@NonNull Habit habit)
- {
- if (!cache.containsKey(habit.getId()))
- throw new RuntimeException("habit not in cache");
-
- cache.remove(habit.getId());
- HabitRecord record = HabitRecord.get(habit.getId());
- if (record == null) throw new RuntimeException("habit not in database");
- record.cascadeDelete();
- rebuildOrder();
- }
-
- @Override
- public void removeAll()
- {
- sqlite.query("delete from checkmarks", null);
- sqlite.query("delete from score", null);
- sqlite.query("delete from streak", null);
- sqlite.query("delete from repetitions", null);
- sqlite.query("delete from habits", null);
- }
-
- @Override
- public synchronized void reorder(Habit from, Habit to)
- {
- if (from == to) return;
-
- HabitRecord fromRecord = HabitRecord.get(from.getId());
- HabitRecord toRecord = HabitRecord.get(to.getId());
-
- if (fromRecord == null)
- throw new RuntimeException("habit not in database");
- if (toRecord == null)
- throw new RuntimeException("habit not in database");
-
- Integer fromPos = fromRecord.position;
- Integer toPos = toRecord.position;
-
- Log.d("SQLiteHabitList",
- String.format("reorder: %d %d", fromPos, toPos));
-
- if (toPos < fromPos)
- {
- new Update(HabitRecord.class)
- .set("position = position + 1")
- .where("position >= ? and position < ?", toPos, fromPos)
- .execute();
- }
- else
- {
- new Update(HabitRecord.class)
- .set("position = position - 1")
- .where("position > ? and position <= ?", fromPos, toPos)
- .execute();
- }
-
- fromRecord.position = toPos;
- fromRecord.save();
- update(from);
- getObservable().notifyListeners();
- }
-
- @Override
- public void repair()
- {
- super.repair();
- rebuildOrder();
- }
-
- @Override
- public int size()
- {
- return toList().size();
- }
-
- @Override
- public void update(List habits)
- {
- for (Habit h : habits)
- {
- HabitRecord record = HabitRecord.get(h.getId());
- if (record == null)
- throw new RuntimeException("habit not in database");
- record.copyFrom(h);
- record.save();
- }
- }
-
- protected synchronized List toList()
- {
- String query = buildSelectQuery();
- List recordList = sqlite.query(query, null);
-
- List habits = new LinkedList<>();
- for (HabitRecord record : recordList)
- {
- Habit habit = getById(record.getId());
- if (habit == null) continue;
- if (!filter.matches(habit)) continue;
- habits.add(habit);
- }
-
- if(order == Order.BY_SCORE)
- {
- Collections.sort(habits, (lhs, rhs) -> {
- int s1 = lhs.getScores().getTodayValue();
- int s2 = rhs.getScores().getTodayValue();
- return Integer.compare(s2, s1);
- });
- }
-
- return habits;
- }
-
- private void appendOrderBy(StringBuilder query)
- {
- switch (order)
- {
- case BY_POSITION:
- query.append("order by position ");
- break;
-
- case BY_NAME:
- case BY_SCORE:
- query.append("order by name ");
- break;
-
- case BY_COLOR:
- query.append("order by color, name ");
- break;
-
- default:
- throw new IllegalStateException();
- }
- }
-
- private void appendSelect(StringBuilder query)
- {
- query.append(HabitRecord.SELECT);
- }
-
- private void appendWhere(StringBuilder query)
- {
- ArrayList