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.

-Get it on Google Play -Git if on F-Droid + Get it on Google Play + Git if on F-Droid

## 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 @@ 8dip 4dip - 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 @@ 64dp 22sp - Color %1$d - Color %1$d selected + Color %1$d + Color %1$d selected Hours circular slider @@ -74,11 +94,56 @@ Year list Select month and day Select year - %1$s selected - %1$s deleted + %1$s selected + %1$s deleted -- : sans-serif sans-serif sans-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 where = new ArrayList<>(); - if (filter.isReminderRequired()) where.add("reminder_hour is not null"); - if (!filter.isArchivedAllowed()) where.add("archived = 0"); - - if (where.isEmpty()) return; - query.append("where "); - query.append(StringUtils.join(where, " and ")); - query.append(" "); - } - - private String buildSelectQuery() - { - StringBuilder query = new StringBuilder(); - appendSelect(query); - appendWhere(query); - appendOrderBy(query); - return query.toString(); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteRepetitionList.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteRepetitionList.java deleted file mode 100644 index 758ac993a..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteRepetitionList.java +++ /dev/null @@ -1,198 +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.*; -import android.database.sqlite.*; -import android.support.annotation.*; -import android.support.annotation.Nullable; - -import com.activeandroid.*; -import com.activeandroid.query.*; - -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.models.sqlite.records.*; -import org.jetbrains.annotations.*; - -import java.util.*; - -/** - * Implementation of a {@link RepetitionList} that is backed by SQLite. - */ -public class SQLiteRepetitionList extends RepetitionList -{ - private final SQLiteUtils sqlite; - - @Nullable - private HabitRecord habitRecord; - - private SQLiteStatement addStatement; - - public SQLiteRepetitionList(@NonNull Habit habit) - { - super(habit); - sqlite = new SQLiteUtils<>(RepetitionRecord.class); - - SQLiteDatabase db = Cache.openDatabase(); - String addQuery = "insert into repetitions(habit, timestamp) values (?,?)"; - addStatement = db.compileStatement(addQuery); - } - - /** - * Adds a repetition to the global SQLite database. - *

- * Given a repetition, this creates and saves the corresponding - * RepetitionRecord to the database. - * - * @param rep the repetition to be added - */ - @Override - public void add(Repetition rep) - { - check(habit.getId()); - addStatement.bindLong(1, habit.getId()); - addStatement.bindLong(2, rep.getTimestamp()); - addStatement.execute(); - observable.notifyListeners(); - } - - @Override - public List getByInterval(long timeFrom, long timeTo) - { - check(habit.getId()); - String query = "select habit, timestamp " + - "from Repetitions " + - "where habit = ? and timestamp >= ? and timestamp <= ? " + - "order by timestamp"; - - String params[] = { - Long.toString(habit.getId()), - Long.toString(timeFrom), - Long.toString(timeTo) - }; - - List records = sqlite.query(query, params); - return toRepetitions(records); - } - - @Override - @Nullable - public Repetition getByTimestamp(long timestamp) - { - check(habit.getId()); - String query = "select habit, timestamp " + - "from Repetitions " + - "where habit = ? and timestamp = ? " + - "limit 1"; - - String params[] = - { Long.toString(habit.getId()), Long.toString(timestamp) }; - - RepetitionRecord record = sqlite.querySingle(query, params); - if (record == null) return null; - record.habit = habitRecord; - return record.toRepetition(); - } - - @Override - public Repetition getOldest() - { - check(habit.getId()); - String query = "select habit, timestamp " + - "from Repetitions " + - "where habit = ? " + - "order by timestamp asc " + - "limit 1"; - - String params[] = { Long.toString(habit.getId()) }; - - RepetitionRecord record = sqlite.querySingle(query, params); - if (record == null) return null; - record.habit = habitRecord; - return record.toRepetition(); - } - - @Override - public Repetition getNewest() - { - check(habit.getId()); - String query = "select habit, timestamp " + - "from Repetitions " + - "where habit = ? " + - "order by timestamp desc " + - "limit 1"; - - String params[] = { Long.toString(habit.getId()) }; - - RepetitionRecord record = sqlite.querySingle(query, params); - if (record == null) return null; - record.habit = habitRecord; - return record.toRepetition(); - } - - @Override - public void remove(@NonNull Repetition repetition) - { - new Delete() - .from(RepetitionRecord.class) - .where("habit = ?", habit.getId()) - .and("timestamp = ?", repetition.getTimestamp()) - .execute(); - - observable.notifyListeners(); - } - - @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"); - } - - @NonNull - private List toRepetitions( - @NonNull List records) - { - check(habit.getId()); - - List reps = new LinkedList<>(); - for (RepetitionRecord record : records) - { - record.habit = habitRecord; - reps.add(record.toRepetition()); - } - - return reps; - } - - @NonNull - @Override - public long getTotalCount() - { - SQLiteDatabase db = Cache.openDatabase(); - - return DatabaseUtils.queryNumEntries(db, "Repetitions", - "habit=?", new String[] { Long.toString(habit.getId()) }); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteScoreList.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteScoreList.java deleted file mode 100644 index bfd1af1da..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteScoreList.java +++ /dev/null @@ -1,236 +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 ScoreList that is backed by SQLite. - */ -public class SQLiteScoreList extends ScoreList -{ - public static final String ADD_QUERY = - "insert into Score(habit, timestamp, score) values (?,?,?)"; - - public static final String INVALIDATE_QUERY = - "delete from Score where habit = ? and timestamp >= ?"; - - @Nullable - private HabitRecord habitRecord; - - @NonNull - private final SQLiteUtils sqlite; - - @Nullable - private CachedData cache = null; - - /** - * Constructs a new ScoreList associated with the given habit. - * - * @param habit the habit this list should be associated with - */ - public SQLiteScoreList(@NonNull Habit habit) - { - super(habit); - sqlite = new SQLiteUtils<>(ScoreRecord.class); - } - - @Override - public void add(List scores) - { - check(habit.getId()); - SQLiteDatabase db = Cache.openDatabase(); - SQLiteStatement statement = db.compileStatement(ADD_QUERY); - db.beginTransaction(); - try - { - for (Score s : scores) - { - statement.bindLong(1, habit.getId()); - statement.bindLong(2, s.getTimestamp()); - statement.bindLong(3, s.getValue()); - statement.execute(); - } - - db.setTransactionSuccessful(); - } - finally - { - db.endTransaction(); - } - } - - @NonNull - @Override - public synchronized List getByInterval(long fromTimestamp, - long toTimestamp) - { - check(habit.getId()); - compute(fromTimestamp, toTimestamp); - - String query = "select habit, timestamp, score from Score " + - "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 (ScoreRecord record : records) record.habit = habitRecord; - return toScores(records); - } - - @Override - @Nullable - public Score getComputedByTimestamp(long timestamp) - { - check(habit.getId()); - - String query = "select habit, timestamp, score from Score " + - "where habit = ? and timestamp = ? " + - "order by timestamp desc"; - - String params[] = - { Long.toString(habit.getId()), Long.toString(timestamp) }; - - return getScoreFromQuery(query, params); - } - - @Override - public synchronized int getTodayValue() - { - if (cache == null || cache.expired()) - cache = new CachedData(super.getTodayValue()); - - return cache.todayValue; - } - - @Override - public synchronized 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(); - getObservable().notifyListeners(); - } - - @Override - @NonNull - public List toList() - { - check(habit.getId()); - computeAll(); - - String query = "select habit, timestamp, score from Score " + - "where habit = ? order by timestamp desc"; - - String params[] = { Long.toString(habit.getId()) }; - - List records = sqlite.query(query, params); - for (ScoreRecord record : records) record.habit = habitRecord; - - return toScores(records); - } - - @Nullable - @Override - protected Score getNewestComputed() - { - check(habit.getId()); - String query = "select habit, timestamp, score from Score " + - "where habit = ? order by timestamp desc limit 1"; - - String params[] = { Long.toString(habit.getId()) }; - return getScoreFromQuery(query, params); - } - - @Nullable - @Override - protected Score getOldestComputed() - { - check(habit.getId()); - String query = "select habit, timestamp, score from Score " + - "where habit = ? order by timestamp asc limit 1"; - - String params[] = { Long.toString(habit.getId()) }; - return getScoreFromQuery(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 Score getScoreFromQuery(String query, String[] params) - { - ScoreRecord record = sqlite.querySingle(query, params); - if (record == null) return null; - record.habit = habitRecord; - return record.toScore(); - } - - @NonNull - private List toScores(@NonNull List records) - { - List scores = new LinkedList<>(); - for (ScoreRecord r : records) scores.add(r.toScore()); - return scores; - } - - 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/SQLiteStreakList.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteStreakList.java deleted file mode 100644 index a14811b45..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteStreakList.java +++ /dev/null @@ -1,150 +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 StreakList that is backed by SQLite. - */ -public class SQLiteStreakList extends StreakList -{ - - private static final String INVALIDATE_QUERY = - "delete from Streak where habit = ? and end >= ?"; - - private HabitRecord habitRecord; - - @NonNull - private final SQLiteUtils sqlite; - - public SQLiteStreakList(Habit habit) - { - super(habit); - sqlite = new SQLiteUtils<>(StreakRecord.class); - } - - @Override - public List getAll() - { - check(habit.getId()); - rebuild(); - - String query = StreakRecord.SELECT + "where habit = ? " + - "order by end desc"; - - String params[] = { Long.toString(habit.getId())}; - - List records = sqlite.query(query, params); - return recordsToStreaks(records); - } - - @Override - public Streak getNewestComputed() - { - StreakRecord newestRecord = getNewestRecord(); - if (newestRecord == null) return null; - return newestRecord.toStreak(); - } - - @Override - public void invalidateNewerThan(long timestamp) - { - SQLiteDatabase db = Cache.openDatabase(); - SQLiteStatement statement = db.compileStatement(INVALIDATE_QUERY); - statement.bindLong(1, habit.getId()); - statement.bindLong(2, timestamp - DateUtils.millisecondsInOneDay); - statement.execute(); - observable.notifyListeners(); - } - - @Override - protected void add(@NonNull List streaks) - { - check(habit.getId()); - - DatabaseUtils.executeAsTransaction(() -> { - for (Streak streak : streaks) - { - StreakRecord record = new StreakRecord(); - record.copyFrom(streak); - record.habit = habitRecord; - record.save(); - } - }); - } - - @Override - protected void removeNewestComputed() - { - StreakRecord newestStreak = getNewestRecord(); - if (newestStreak != null) newestStreak.delete(); - } - - @Nullable - private StreakRecord getNewestRecord() - { - check(habit.getId()); - String query = StreakRecord.SELECT + "where habit = ? " + - "order by end desc " + - "limit 1 "; - String params[] = { habit.getId().toString() }; - StreakRecord record = sqlite.querySingle(query, params); - if (record != null) record.habit = habitRecord; - return record; - - } - - @NonNull - private List recordsToStreaks(List records) - { - LinkedList streaks = new LinkedList<>(); - - for (StreakRecord record : records) - { - record.habit = habitRecord; - streaks.add(record.toStreak()); - } - - return streaks; - } - - @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"); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteUtils.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteUtils.java deleted file mode 100644 index 616b0d12f..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/SQLiteUtils.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.models.sqlite; - -import android.database.*; -import android.database.sqlite.*; -import android.support.annotation.*; - -import com.activeandroid.*; - -import org.isoron.uhabits.models.sqlite.records.*; - -import java.util.*; - -public class SQLiteUtils -{ - private Class klass; - - public SQLiteUtils(Class klass) - { - this.klass = klass; - } - - @NonNull - public List query(String query, String params[]) - { - SQLiteDatabase db = Cache.openDatabase(); - try (Cursor c = db.rawQuery(query, params)) - { - return cursorToMultipleRecords(c); - } - } - - @Nullable - public T querySingle(String query, String params[]) - { - SQLiteDatabase db = Cache.openDatabase(); - try(Cursor c = db.rawQuery(query, params)) - { - if (!c.moveToNext()) return null; - return cursorToSingleRecord(c); - } - } - - @NonNull - private List cursorToMultipleRecords(Cursor c) - { - List records = new LinkedList<>(); - while (c.moveToNext()) records.add(cursorToSingleRecord(c)); - return records; - } - - @NonNull - private T cursorToSingleRecord(Cursor c) - { - try - { - T record = (T) klass.newInstance(); - record.copyFrom(c); - return record; - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } -} diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/HabitRecord.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/records/HabitRecord.java deleted file mode 100644 index b4120a386..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/HabitRecord.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.models.sqlite.records; - -import android.annotation.*; -import android.database.*; -import android.support.annotation.*; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.activeandroid.*; -import com.activeandroid.annotation.*; -import com.activeandroid.query.*; -import com.activeandroid.util.*; - -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.utils.DatabaseUtils; - -import java.lang.reflect.*; - -/** - * The SQLite database record corresponding to a {@link Habit}. - */ -@Table(name = "Habits") -public class HabitRecord extends Model implements SQLiteRecord -{ - public static String SELECT = - "select id, color, description, freq_den, freq_num, " + - "name, position, reminder_hour, reminder_min, " + - "highlight, archived, reminder_days from habits "; - - @Column(name = "name") - public String name; - - @Column(name = "description") - public String description; - - @Column(name = "freq_num") - public Integer freqNum; - - @Column(name = "freq_den") - public Integer freqDen; - - @Column(name = "color") - public Integer color; - - @Column(name = "position") - public Integer position; - - @Nullable - @Column(name = "reminder_hour") - public Integer reminderHour; - - @Nullable - @Column(name = "reminder_min") - public Integer reminderMin; - - @NonNull - @Column(name = "reminder_days") - public Integer reminderDays; - - @Column(name = "highlight") - public Integer highlight; - - @Column(name = "archived") - public Integer archived; - - public HabitRecord() - { - } - - @Nullable - public static HabitRecord get(long id) - { - return HabitRecord.load(HabitRecord.class, id); - } - - /** - * Changes the id of a habit on the database. - * - * @param oldId the original id - * @param newId the new id - */ - @SuppressLint("DefaultLocale") - public static void updateId(long oldId, long newId) - { - SQLiteUtils.execSql( - String.format("update Habits set Id = %d where Id = %d", newId, - oldId)); - } - - /** - * Deletes the habit and all data associated to it, including checkmarks, - * repetitions and scores. - */ - public void cascadeDelete() - { - Long id = getId(); - - DatabaseUtils.executeAsTransaction(() -> { - new Delete() - .from(CheckmarkRecord.class) - .where("habit = ?", id) - .execute(); - - new Delete() - .from(RepetitionRecord.class) - .where("habit = ?", id) - .execute(); - - new Delete() - .from(ScoreRecord.class) - .where("habit = ?", id) - .execute(); - - new Delete() - .from(StreakRecord.class) - .where("habit = ?", id) - .execute(); - - delete(); - }); - } - - public void copyFrom(Habit model) - { - this.name = model.getName(); - this.description = model.getDescription(); - this.highlight = 0; - this.color = model.getColor(); - this.archived = model.isArchived() ? 1 : 0; - Frequency freq = model.getFrequency(); - this.freqNum = freq.getNumerator(); - this.freqDen = freq.getDenominator(); - this.reminderDays = 0; - this.reminderMin = null; - this.reminderHour = null; - - if (model.hasReminder()) - { - Reminder reminder = model.getReminder(); - this.reminderHour = reminder.getHour(); - this.reminderMin = reminder.getMinute(); - this.reminderDays = reminder.getDays().toInteger(); - } - } - - @Override - public void copyFrom(Cursor c) - { - setId(c.getLong(0)); - color = c.getInt(1); - description = c.getString(2); - freqDen = c.getInt(3); - freqNum = c.getInt(4); - name = c.getString(5); - position = c.getInt(6); - reminderHour = c.getInt(7); - reminderMin = c.getInt(8); - highlight = c.getInt(9); - archived = c.getInt(10); - reminderDays = c.getInt(11); - } - - public void copyTo(Habit habit) - { - habit.setName(this.name); - habit.setDescription(this.description); - habit.setFrequency(new Frequency(this.freqNum, this.freqDen)); - habit.setColor(this.color); - habit.setArchived(this.archived != 0); - habit.setId(this.getId()); - - if (reminderHour != null && reminderMin != null) - { - habit.setReminder(new Reminder(reminderHour, reminderMin, - new WeekdayList(reminderDays))); - } - } - - /** - * Saves the habit on the database, and assigns the specified id to it. - * - * @param id the id that the habit should receive - */ - public void save(long id) - { - save(); - updateId(getId(), id); - } - - private void setId(Long id) - { - try - { - Field f = (Model.class).getDeclaredField("mId"); - f.setAccessible(true); - f.set(this, id); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } -} diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/ScoreRecord.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/records/ScoreRecord.java deleted file mode 100644 index daac00d3f..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/ScoreRecord.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.models.sqlite.records; - -import android.database.*; - -import com.activeandroid.*; -import com.activeandroid.annotation.*; - -import org.isoron.uhabits.models.*; - -/** - * The SQLite database record corresponding to a Score. - */ -@Table(name = "Score") -public class ScoreRecord extends Model implements SQLiteRecord -{ - @Column(name = "habit") - public HabitRecord habit; - - /** - * Timestamp of the day to which this score applies. Time of day should be - * midnight (UTC). - */ - @Column(name = "timestamp") - public Long timestamp; - - /** - * Value of the score. - */ - @Column(name = "score") - public Integer score; - - @Override - public void copyFrom(Cursor c) - { - timestamp = c.getLong(1); - score = c.getInt(2); - } - - /** - * Constructs and returns a {@link Score} based on this record's data. - * - * @return a {@link Score} with this record's data - */ - public Score toScore() - { - return new Score(timestamp, score); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/StreakRecord.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/records/StreakRecord.java deleted file mode 100644 index 1638089db..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/StreakRecord.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.models.sqlite.records; - -import android.database.*; - -import com.activeandroid.*; -import com.activeandroid.annotation.*; - -import org.isoron.uhabits.models.*; - -import java.lang.reflect.*; - -/** - * The SQLite database record corresponding to a Streak. - */ -@Table(name = "Streak") -public class StreakRecord extends Model implements SQLiteRecord -{ - public static final String SELECT = "select id, start, end, length from Streak "; - - @Column(name = "habit") - public HabitRecord habit; - - @Column(name = "start") - public Long start; - - @Column(name = "end") - public Long end; - - @Column(name = "length") - public Long length; - - public static StreakRecord get(Long id) - { - return StreakRecord.load(StreakRecord.class, id); - } - - public void copyFrom(Streak streak) - { - start = streak.getStart(); - end = streak.getEnd(); - length = streak.getLength(); - } - - @Override - public void copyFrom(Cursor c) - { - setId(c.getLong(0)); - start = c.getLong(1); - end = c.getLong(2); - length = c.getLong(3); - } - - private void setId(long id) - { - try - { - Field f = (Model.class).getDeclaredField("mId"); - f.setAccessible(true); - f.set(this, id); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } - - public Streak toStreak() - { - return new Streak(start, end); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/package-info.java b/app/src/main/java/org/isoron/uhabits/models/sqlite/records/package-info.java deleted file mode 100644 index 379d6a6e0..000000000 --- a/app/src/main/java/org/isoron/uhabits/models/sqlite/records/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 represent rows in the SQLite database. - */ -package org.isoron.uhabits.models.sqlite.records; \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/package-info.java b/app/src/main/java/org/isoron/uhabits/package-info.java deleted file mode 100644 index b080842fc..000000000 --- a/app/src/main/java/org/isoron/uhabits/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 for the Loop Habit Tracker app. - */ -package org.isoron.uhabits; \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/preferences/Preferences.java b/app/src/main/java/org/isoron/uhabits/preferences/Preferences.java deleted file mode 100644 index e8626aa5f..000000000 --- a/app/src/main/java/org/isoron/uhabits/preferences/Preferences.java +++ /dev/null @@ -1,260 +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.preferences; - -import android.content.*; -import android.preference.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.activities.*; -import org.isoron.uhabits.models.*; - -import java.util.*; - -import javax.inject.*; - -@AppScope -public class Preferences - implements SharedPreferences.OnSharedPreferenceChangeListener -{ - private final Context context; - - private SharedPreferences prefs; - - private Boolean shouldReverseCheckmarks = null; - - private LinkedList listeners; - - @Inject - public Preferences(@AppContext Context context) - { - this.context = context; - listeners = new LinkedList<>(); - - prefs = PreferenceManager.getDefaultSharedPreferences(context); - prefs.registerOnSharedPreferenceChangeListener(this); - } - - public void addListener(Listener listener) - { - listeners.add(listener); - } - - public Integer getDefaultHabitColor(int fallbackColor) - { - return prefs.getInt("pref_default_habit_palette_color", fallbackColor); - } - - public HabitList.Order getDefaultOrder() - { - String name = prefs.getString("pref_default_order", "BY_POSITION"); - - try - { - return HabitList.Order.valueOf(name); - } - catch (IllegalArgumentException e) - { - setDefaultOrder(HabitList.Order.BY_POSITION); - return HabitList.Order.BY_POSITION; - } - } - - public int getDefaultScoreSpinnerPosition() - { - int defaultScoreInterval = prefs.getInt("pref_score_view_interval", 1); - if (defaultScoreInterval > 5 || defaultScoreInterval < 0) - defaultScoreInterval = 1; - return defaultScoreInterval; - } - - public void setDefaultOrder(HabitList.Order order) - { - prefs.edit().putString("pref_default_order", order.name()).apply(); - } - - public void setDefaultScoreSpinnerPosition(int position) - { - prefs.edit().putInt("pref_score_view_interval", position).apply(); - } - - /** - * Returns the number of the last hint shown to the user. - * - * @return number of last hint shown - */ - public int getLastHintNumber() - { - return prefs.getInt("last_hint_number", -1); - } - - /** - * Returns the time when the last hint was shown to the user. - * - * @return timestamp of the day the last hint was shown - */ - public long getLastHintTimestamp() - { - return prefs.getLong("last_hint_timestamp", -1); - } - - public boolean getShowArchived() - { - return prefs.getBoolean("pref_show_archived", false); - } - - public void setShowArchived(boolean showArchived) - { - prefs.edit().putBoolean("pref_show_archived", showArchived).apply(); - } - - public boolean getShowCompleted() - { - return prefs.getBoolean("pref_show_completed", true); - } - - public void setShowCompleted(boolean showCompleted) - { - prefs.edit().putBoolean("pref_show_completed", showCompleted).apply(); - } - - public long getSnoozeInterval() - { - return Long.parseLong(prefs.getString("pref_snooze_interval", "15")); - } - - public int getTheme() - { - return prefs.getInt("pref_theme", ThemeSwitcher.THEME_LIGHT); - } - - public void setTheme(int theme) - { - prefs.edit().putInt("pref_theme", theme).apply(); - } - - public void incrementLaunchCount() - { - int count = prefs.getInt("launch_count", 0); - prefs.edit().putInt("launch_count", count + 1).apply(); - } - - public void initialize() - { - PreferenceManager.setDefaultValues(context, R.xml.preferences, false); - } - - public boolean isFirstRun() - { - return prefs.getBoolean("pref_first_run", true); - } - - public void setFirstRun(boolean isFirstRun) - { - prefs.edit().putBoolean("pref_first_run", isFirstRun).apply(); - } - - public boolean isPureBlackEnabled() - { - return prefs.getBoolean("pref_pure_black", false); - } - - public boolean isShortToggleEnabled() - { - return prefs.getBoolean("pref_short_toggle", false); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) - { - if (key.equals("pref_checkmark_reverse_order")) - { - shouldReverseCheckmarks = null; - for(Listener l : listeners) l.onCheckmarkOrderChanged(); - } - - if(key.equals("pref_sticky_notifications")) - { - for(Listener l : listeners) l.onNotificationsChanged(); - } - } - - public void removeListener(Listener listener) - { - listeners.remove(listener); - } - - public void setDefaultHabitColor(int color) - { - prefs.edit().putInt("pref_default_habit_palette_color", color).apply(); - } - - public void setShouldReverseCheckmarks(boolean reverse) - { - shouldReverseCheckmarks = null; - prefs - .edit() - .putBoolean("pref_checkmark_reverse_order", reverse) - .apply(); - - for(Listener l : listeners) l.onCheckmarkOrderChanged(); - } - - public boolean shouldReverseCheckmarks() - { - if (shouldReverseCheckmarks == null) shouldReverseCheckmarks = - prefs.getBoolean("pref_checkmark_reverse_order", false); - - return shouldReverseCheckmarks; - } - - public boolean shouldMakeNotificationsSticky() - { - return prefs.getBoolean("pref_sticky_notifications", false); - } - - public void updateLastAppVersion() - { - prefs.edit().putInt("last_version", BuildConfig.VERSION_CODE).apply(); - } - - /** - * Sets the last hint shown to the user, and the time that it was shown. - * - * @param number number of the last hint shown - * @param timestamp timestamp for the day the last hint was shown - */ - public void updateLastHint(int number, long timestamp) - { - prefs - .edit() - .putInt("last_hint_number", number) - .putLong("last_hint_timestamp", timestamp) - .apply(); - } - - public interface Listener - { - default void onCheckmarkOrderChanged() {} - - default void onNotificationsChanged() {} - } -} diff --git a/app/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java b/app/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java deleted file mode 100644 index 55243f015..000000000 --- a/app/src/main/java/org/isoron/uhabits/receivers/PebbleReceiver.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.receivers; - -import android.content.*; -import android.support.annotation.*; -import android.util.*; - -import com.getpebble.android.kit.*; -import com.getpebble.android.kit.PebbleKit.*; -import com.getpebble.android.kit.util.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.commands.*; -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.tasks.*; -import org.isoron.uhabits.utils.*; - -import java.util.*; - -public class PebbleReceiver extends PebbleDataReceiver -{ - public static final UUID WATCHAPP_UUID = - UUID.fromString("82629d99-8ea6-4631-a022-9ca77a12a058"); - - @NonNull - private Context context; - - private HabitList allHabits; - - private CommandRunner commandRunner; - - private TaskRunner taskRunner; - - private HabitList filteredHabits; - - public PebbleReceiver() - { - super(WATCHAPP_UUID); - } - - @Override - public void receiveData(@Nullable Context context, - int transactionId, - @Nullable PebbleDictionary data) - { - if (context == null) throw new RuntimeException("context is null"); - if (data == null) throw new RuntimeException("data is null"); - - this.context = context; - - HabitsApplication app = - (HabitsApplication) context.getApplicationContext(); - - commandRunner = app.getComponent().getCommandRunner(); - taskRunner = app.getComponent().getTaskRunner(); - allHabits = app.getComponent().getHabitList(); - - HabitMatcher build = new HabitMatcherBuilder() - .setArchivedAllowed(false) - .setCompletedAllowed(false) - .build(); - - filteredHabits = allHabits.getFiltered(build); - - PebbleKit.sendAckToPebble(context, transactionId); - Log.d("PebbleReceiver", "<-- " + data.getString(0)); - - taskRunner.execute(() -> { - switch (data.getString(0)) - { - case "COUNT": - sendCount(); - break; - - case "FETCH": - processFetch(data); - break; - - case "TOGGLE": - processToggle(data); - break; - } - }); - } - - private void processFetch(@NonNull PebbleDictionary dict) - { - Long position = dict.getInteger(1); - if (position == null) return; - if (position < 0 || position >= filteredHabits.size()) return; - - Habit habit = filteredHabits.getByPosition(position.intValue()); - if (habit == null) return; - - sendHabit(habit); - } - - private void processToggle(@NonNull PebbleDictionary dict) - { - Long habitId = dict.getInteger(1); - if (habitId == null) return; - - Habit habit = allHabits.getById(habitId); - if (habit == null) return; - - long today = DateUtils.getStartOfToday(); - commandRunner.execute(new ToggleRepetitionCommand(habit, today), - habitId); - - sendOK(); - } - - private void sendCount() - { - PebbleDictionary dict = new PebbleDictionary(); - dict.addString(0, "COUNT"); - dict.addInt32(1, filteredHabits.size()); - sendDict(dict); - - Log.d("PebbleReceiver", - String.format("--> COUNT %d", filteredHabits.size())); - } - - private void sendDict(@NonNull PebbleDictionary dict) - { - PebbleKit.sendDataToPebble(context, - PebbleReceiver.WATCHAPP_UUID, dict); - } - - private void sendHabit(@NonNull Habit habit) - { - if (habit.getId() == null) return; - - PebbleDictionary response = new PebbleDictionary(); - response.addString(0, "HABIT"); - response.addInt32(1, habit.getId().intValue()); - response.addString(2, habit.getName()); - response.addInt32(3, habit.getCheckmarks().getTodayValue()); - sendDict(response); - } - - private void sendOK() - { - PebbleDictionary dict = new PebbleDictionary(); - dict.addString(0, "OK"); - sendDict(dict); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/tasks/package-info.java b/app/src/main/java/org/isoron/uhabits/tasks/package-info.java deleted file mode 100644 index cc837895e..000000000 --- a/app/src/main/java/org/isoron/uhabits/tasks/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 async tasks for useful operations such as {@link - * org.isoron.uhabits.tasks.ExportCSVTask}. - */ -package org.isoron.uhabits.tasks; \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/utils/RingtoneUtils.java b/app/src/main/java/org/isoron/uhabits/utils/RingtoneUtils.java deleted file mode 100644 index c6a3b4a30..000000000 --- a/app/src/main/java/org/isoron/uhabits/utils/RingtoneUtils.java +++ /dev/null @@ -1,118 +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.utils; - -import android.content.*; -import android.media.*; -import android.net.*; -import android.preference.*; -import android.provider.*; -import android.support.annotation.*; -import android.support.v4.app.*; - -import org.isoron.uhabits.*; - -import static android.media.RingtoneManager.*; - -public abstract class RingtoneUtils -{ - @Nullable - public static String getRingtoneName(Context context) - { - try - { - Uri ringtoneUri = getRingtoneUri(context); - String ringtoneName = - context.getResources().getString(R.string.none); - - if (ringtoneUri != null) - { - Ringtone ringtone = getRingtone(context, ringtoneUri); - if (ringtone != null) - { - ringtoneName = ringtone.getTitle(context); - ringtone.stop(); - } - } - - return ringtoneName; - } - catch (RuntimeException e) - { - e.printStackTrace(); - return null; - } - } - - @Nullable - public static Uri getRingtoneUri(Context context) - { - Uri ringtoneUri = null; - Uri defaultRingtoneUri = Settings.System.DEFAULT_NOTIFICATION_URI; - - SharedPreferences prefs = - PreferenceManager.getDefaultSharedPreferences(context); - String prefRingtoneUri = - prefs.getString("pref_ringtone_uri", defaultRingtoneUri.toString()); - if (prefRingtoneUri.length() > 0) - ringtoneUri = Uri.parse(prefRingtoneUri); - - return ringtoneUri; - } - - public static void parseRingtoneData(Context context, @Nullable Intent data) - { - if (data == null) return; - - Uri ringtoneUri = data.getParcelableExtra(EXTRA_RINGTONE_PICKED_URI); - - if (ringtoneUri != null) - { - SharedPreferences prefs = - PreferenceManager.getDefaultSharedPreferences(context); - prefs - .edit() - .putString("pref_ringtone_uri", ringtoneUri.toString()) - .apply(); - } - else - { - String off = context.getResources().getString(R.string.none); - SharedPreferences prefs = - PreferenceManager.getDefaultSharedPreferences(context); - prefs.edit().putString("pref_ringtone_uri", "").apply(); - } - } - - public static void startRingtonePickerActivity(Fragment fragment, - int requestCode) - { - Uri existingRingtoneUri = getRingtoneUri(fragment.getContext()); - Uri defaultRingtoneUri = Settings.System.DEFAULT_NOTIFICATION_URI; - - Intent intent = new Intent(ACTION_RINGTONE_PICKER); - intent.putExtra(EXTRA_RINGTONE_TYPE, TYPE_NOTIFICATION); - intent.putExtra(EXTRA_RINGTONE_SHOW_DEFAULT, true); - intent.putExtra(EXTRA_RINGTONE_SHOW_SILENT, true); - intent.putExtra(EXTRA_RINGTONE_DEFAULT_URI, defaultRingtoneUri); - intent.putExtra(EXTRA_RINGTONE_EXISTING_URI, existingRingtoneUri); - fragment.startActivityForResult(intent, requestCode); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/utils/WidgetUtils.java b/app/src/main/java/org/isoron/uhabits/utils/WidgetUtils.java deleted file mode 100644 index 45b992205..000000000 --- a/app/src/main/java/org/isoron/uhabits/utils/WidgetUtils.java +++ /dev/null @@ -1,72 +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.utils; - -import android.appwidget.*; -import android.content.*; -import android.os.*; -import android.support.annotation.*; -import android.widget.*; - -import org.isoron.uhabits.widgets.*; - -import static android.appwidget.AppWidgetManager.*; -import static android.os.Build.VERSION.*; -import static android.os.Build.VERSION_CODES.*; -import static org.isoron.uhabits.utils.InterfaceUtils.*; - -public abstract class WidgetUtils -{ - @NonNull - public static WidgetDimensions getDimensionsFromOptions( - @NonNull Context ctx, @NonNull Bundle options) - { - if (SDK_INT < JELLY_BEAN) - throw new AssertionError("method requires jelly-bean"); - - int maxWidth = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH)); - int maxHeight = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT)); - int minWidth = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH)); - int minHeight = - (int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT)); - - return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight); - } - - public static void updateAppWidget(@NonNull AppWidgetManager manager, - @NonNull BaseWidget widget) - { - if (SDK_INT < JELLY_BEAN) - { - RemoteViews portrait = widget.getPortraitRemoteViews(); - manager.updateAppWidget(widget.getId(), portrait); - } - else - { - RemoteViews landscape = widget.getLandscapeRemoteViews(); - RemoteViews portrait = widget.getPortraitRemoteViews(); - RemoteViews views = new RemoteViews(landscape, portrait); - manager.updateAppWidget(widget.getId(), views); - } - } -} diff --git a/app/src/main/java/org/isoron/uhabits/utils/package-info.java b/app/src/main/java/org/isoron/uhabits/utils/package-info.java deleted file mode 100644 index 51db3c7a3..000000000 --- a/app/src/main/java/org/isoron/uhabits/utils/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 various utilities classes, such as {@link org.isoron.uhabits.utils.ColorUtils}. - */ -package org.isoron.uhabits.utils; \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.java b/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.java deleted file mode 100644 index 3266d16a2..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.java +++ /dev/null @@ -1,83 +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.widgets; - -import android.app.*; -import android.content.*; -import android.support.annotation.*; -import android.view.*; - -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.utils.*; -import org.isoron.uhabits.widgets.views.*; - -public class CheckmarkWidget extends BaseWidget -{ - @NonNull - private final Habit habit; - - public CheckmarkWidget(@NonNull Context context, - int widgetId, - @NonNull Habit habit) - { - super(context, widgetId); - this.habit = habit; - } - - @Override - public PendingIntent getOnClickPendingIntent(Context context) - { - return pendingIntentFactory.toggleCheckmark(habit, null); - } - - @Override - public void refreshData(View v) - { - CheckmarkWidgetView view = (CheckmarkWidgetView) v; - int color = ColorUtils.getColor(getContext(), habit.getColor()); - int score = habit.getScores().getTodayValue(); - float percentage = (float) score / Score.MAX_VALUE; - int checkmark = habit.getCheckmarks().getTodayValue(); - - view.setPercentage(percentage); - view.setActiveColor(color); - view.setName(habit.getName()); - view.setCheckmarkValue(checkmark); - view.refresh(); - } - - @Override - protected View buildView() - { - return new CheckmarkWidgetView(getContext()); - } - - @Override - protected int getDefaultHeight() - { - return 125; - } - - @Override - protected int getDefaultWidth() - { - return 125; - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.java deleted file mode 100644 index cd3fe8e62..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.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.widgets; - -import android.content.*; -import android.support.annotation.*; - -import org.isoron.uhabits.models.*; - -public class CheckmarkWidgetProvider extends BaseWidgetProvider -{ - @NonNull - @Override - protected CheckmarkWidget getWidgetFromId(@NonNull Context context, int id) - { - Habit habit = getHabitFromWidgetId(id); - return new CheckmarkWidget(context, id, habit); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.java b/app/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.java deleted file mode 100644 index ff76fdac4..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.java +++ /dev/null @@ -1,83 +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.widgets; - -import android.app.*; -import android.content.*; -import android.support.annotation.*; -import android.view.*; - -import org.isoron.uhabits.activities.common.views.*; -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.utils.*; -import org.isoron.uhabits.widgets.views.*; - -public class FrequencyWidget extends BaseWidget -{ - @NonNull - private final Habit habit; - - public FrequencyWidget(@NonNull Context context, - int widgetId, - @NonNull Habit habit) - { - super(context, widgetId); - this.habit = habit; - } - - @Override - public PendingIntent getOnClickPendingIntent(Context context) - { - return pendingIntentFactory.showHabit(habit); - } - - @Override - public void refreshData(View v) - { - GraphWidgetView widgetView = (GraphWidgetView) v; - FrequencyChart chart = (FrequencyChart) widgetView.getDataView(); - - widgetView.setTitle(habit.getName()); - - int color = ColorUtils.getColor(getContext(), habit.getColor()); - - chart.setColor(color); - chart.setFrequency(habit.getRepetitions().getWeekdayFrequency()); - } - - @Override - protected View buildView() - { - FrequencyChart chart = new FrequencyChart(getContext()); - return new GraphWidgetView(getContext(), chart); - } - - @Override - protected int getDefaultHeight() - { - return 200; - } - - @Override - protected int getDefaultWidth() - { - return 200; - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java b/app/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java deleted file mode 100644 index e648db7e6..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.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.widgets; - -import android.app.*; -import android.content.*; -import android.os.*; -import android.view.*; -import android.widget.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.preferences.*; - -import java.util.*; - -import static android.appwidget.AppWidgetManager.*; - -public class HabitPickerDialog extends Activity - implements AdapterView.OnItemClickListener -{ - private HabitList habitList; - - private WidgetPreferences preferences; - - private Integer widgetId; - - private ArrayList habitIds; - - @Override - public void onItemClick(AdapterView parent, - View view, - int position, - long id) - { - Long habitId = habitIds.get(position); - preferences.addWidget(widgetId, habitId); - - HabitsApplication app = (HabitsApplication) getApplicationContext(); - app.getComponent().getWidgetUpdater().updateWidgets(); - - Intent resultValue = new Intent(); - resultValue.putExtra(EXTRA_APPWIDGET_ID, widgetId); - setResult(RESULT_OK, resultValue); - finish(); - } - - @Override - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - setContentView(R.layout.widget_configure_activity); - - HabitsApplication app = (HabitsApplication) getApplicationContext(); - AppComponent component = app.getComponent(); - habitList = component.getHabitList(); - preferences = component.getWidgetPreferences(); - - Intent intent = getIntent(); - Bundle extras = intent.getExtras(); - - if (extras != null) - widgetId = extras.getInt(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID); - - ListView listView = (ListView) findViewById(R.id.listView); - - habitIds = new ArrayList<>(); - ArrayList habitNames = new ArrayList<>(); - - for (Habit h : habitList) - { - habitIds.add(h.getId()); - habitNames.add(h.getName()); - } - - ArrayAdapter adapter = - new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, - habitNames); - listView.setAdapter(adapter); - listView.setOnItemClickListener(this); - } - -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.java b/app/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.java deleted file mode 100644 index 0553e35ff..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.java +++ /dev/null @@ -1,83 +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.widgets; - -import android.app.*; -import android.content.*; -import android.support.annotation.*; -import android.view.*; - -import org.isoron.uhabits.activities.common.views.*; -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.utils.*; -import org.isoron.uhabits.widgets.views.*; - -public class HistoryWidget extends BaseWidget -{ - @NonNull - private Habit habit; - - public HistoryWidget(@NonNull Context context, int id, @NonNull Habit habit) - { - super(context, id); - this.habit = habit; - } - - @Override - public PendingIntent getOnClickPendingIntent(Context context) - { - return pendingIntentFactory.showHabit(habit); - } - - @Override - public void refreshData(View view) - { - GraphWidgetView widgetView = (GraphWidgetView) view; - HistoryChart chart = (HistoryChart) widgetView.getDataView(); - - int color = ColorUtils.getColor(getContext(), habit.getColor()); - int[] values = habit.getCheckmarks().getAllValues(); - - chart.setColor(color); - chart.setCheckmarks(values); - } - - @Override - protected View buildView() - { - HistoryChart dataView = new HistoryChart(getContext()); - GraphWidgetView widgetView = - new GraphWidgetView(getContext(), dataView); - widgetView.setTitle(habit.getName()); - return widgetView; - } - - @Override - protected int getDefaultHeight() - { - return 250; - } - - @Override - protected int getDefaultWidth() - { - return 250; - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.java b/app/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.java deleted file mode 100644 index 7ff8cf1fe..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.java +++ /dev/null @@ -1,103 +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.widgets; - -import android.app.*; -import android.content.*; -import android.support.annotation.*; -import android.view.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.activities.common.views.*; -import org.isoron.uhabits.activities.habits.show.views.*; -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.preferences.*; -import org.isoron.uhabits.utils.*; -import org.isoron.uhabits.widgets.views.*; - -import java.util.*; - -public class ScoreWidget extends BaseWidget -{ - @NonNull - private Habit habit; - - private final Preferences prefs; - - public ScoreWidget(@NonNull Context context, int id, @NonNull Habit habit) - { - super(context, id); - this.habit = habit; - - HabitsApplication app = - (HabitsApplication) context.getApplicationContext(); - prefs = app.getComponent().getPreferences(); - } - - @Override - public PendingIntent getOnClickPendingIntent(Context context) - { - return pendingIntentFactory.showHabit(habit); - } - - @Override - public void refreshData(View view) - { - int defaultScoreInterval = prefs.getDefaultScoreSpinnerPosition(); - int size = ScoreCard.BUCKET_SIZES[defaultScoreInterval]; - - GraphWidgetView widgetView = (GraphWidgetView) view; - ScoreChart chart = (ScoreChart) widgetView.getDataView(); - - List scores; - ScoreList scoreList = habit.getScores(); - - if (size == 1) scores = scoreList.toList(); - else scores = scoreList.groupBy(ScoreCard.getTruncateField(size)); - - int color = ColorUtils.getColor(getContext(), habit.getColor()); - - chart.setIsTransparencyEnabled(true); - chart.setBucketSize(size); - chart.setColor(color); - chart.setScores(scores); - } - - @Override - protected View buildView() - { - ScoreChart dataView = new ScoreChart(getContext()); - GraphWidgetView view = new GraphWidgetView(getContext(), dataView); - view.setTitle(habit.getName()); - return view; - } - - @Override - protected int getDefaultHeight() - { - return 300; - } - - @Override - protected int getDefaultWidth() - { - return 300; - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/StreakWidget.java b/app/src/main/java/org/isoron/uhabits/widgets/StreakWidget.java deleted file mode 100644 index ecf3fe957..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/StreakWidget.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.widgets; - -import android.app.*; -import android.content.*; -import android.support.annotation.*; -import android.view.*; -import android.view.ViewGroup.*; - -import org.isoron.uhabits.activities.common.views.*; -import org.isoron.uhabits.models.*; -import org.isoron.uhabits.utils.*; -import org.isoron.uhabits.widgets.views.*; - -import java.util.*; - -import static android.view.ViewGroup.LayoutParams.*; - -public class StreakWidget extends BaseWidget -{ - @NonNull - private Habit habit; - - public StreakWidget(@NonNull Context context, int id, @NonNull Habit habit) - { - super(context, id); - this.habit = habit; - } - - @Override - public PendingIntent getOnClickPendingIntent(Context context) - { - return pendingIntentFactory.showHabit(habit); - } - - @Override - public void refreshData(View view) - { - GraphWidgetView widgetView = (GraphWidgetView) view; - StreakChart chart = (StreakChart) widgetView.getDataView(); - - int color = ColorUtils.getColor(getContext(), habit.getColor()); - - int count = chart.getMaxStreakCount(); - List streaks = habit.getStreaks().getBest(count); - - chart.setColor(color); - chart.setStreaks(streaks); - } - - @Override - protected View buildView() - { - StreakChart dataView = new StreakChart(getContext()); - GraphWidgetView view = new GraphWidgetView(getContext(), dataView); - LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - view.setTitle(habit.getName()); - view.setLayoutParams(params); - return view; - } - - @Override - protected int getDefaultHeight() - { - return 200; - } - - @Override - protected int getDefaultWidth() - { - return 200; - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.java deleted file mode 100644 index 211246eb3..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.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.widgets; - -import android.content.*; -import android.support.annotation.*; - -import org.isoron.uhabits.models.*; - -public class StreakWidgetProvider extends BaseWidgetProvider -{ - @NonNull - @Override - protected BaseWidget getWidgetFromId(@NonNull Context context, int id) - { - Habit habit = getHabitFromWidgetId(id); - return new StreakWidget(context, id, habit); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/WidgetDimensions.java b/app/src/main/java/org/isoron/uhabits/widgets/WidgetDimensions.java deleted file mode 100644 index 5c88a2114..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/WidgetDimensions.java +++ /dev/null @@ -1,62 +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.widgets; - -public class WidgetDimensions -{ - private final int portraitWidth; - - private final int portraitHeight; - - private final int landscapeWidth; - - private final int landscapeHeight; - - public WidgetDimensions(int portraitWidth, - int portraitHeight, - int landscapeWidth, - int landscapeHeight) - { - this.portraitWidth = portraitWidth; - this.portraitHeight = portraitHeight; - this.landscapeWidth = landscapeWidth; - this.landscapeHeight = landscapeHeight; - } - - public int getLandscapeHeight() - { - return landscapeHeight; - } - - public int getLandscapeWidth() - { - return landscapeWidth; - } - - public int getPortraitHeight() - { - return portraitHeight; - } - - public int getPortraitWidth() - { - return portraitWidth; - } -} \ No newline at end of file diff --git a/app/src/main/java/org/isoron/uhabits/widgets/WidgetUpdater.java b/app/src/main/java/org/isoron/uhabits/widgets/WidgetUpdater.java deleted file mode 100644 index 81928f917..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/WidgetUpdater.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.widgets; - -import android.appwidget.*; -import android.content.*; -import android.support.annotation.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.commands.*; - -import javax.inject.*; - -/** - * A WidgetUpdater listens to the commands being executed by the application and - * updates the home-screen widgets accordingly. - *

- * There should be only one instance of this class, created when the application - * starts. To access it, call HabitApplication.getWidgetUpdater(). - */ -public class WidgetUpdater implements CommandRunner.Listener -{ - @NonNull - private final CommandRunner commandRunner; - - @NonNull - private final Context context; - - @Inject - public WidgetUpdater(@NonNull @AppContext Context context, - @NonNull CommandRunner commandRunner) - { - this.context = context; - this.commandRunner = commandRunner; - } - - @Override - public void onCommandExecuted(@NonNull Command command, - @Nullable Long refreshKey) - { - updateWidgets(); - } - - /** - * Instructs the updater to start listening to commands. If any relevant - * commands are executed after this method is called, the corresponding - * widgets will get updated. - */ - public void startListening() - { - commandRunner.addListener(this); - } - - /** - * Instructs the updater to stop listening to commands. Every command - * executed after this method is called will be ignored by the updater. - */ - public void stopListening() - { - commandRunner.removeListener(this); - } - - public void updateWidgets() - { - updateWidgets(CheckmarkWidgetProvider.class); - updateWidgets(HistoryWidgetProvider.class); - updateWidgets(ScoreWidgetProvider.class); - updateWidgets(StreakWidgetProvider.class); - updateWidgets(FrequencyWidgetProvider.class); - } - - public void updateWidgets(Class providerClass) - { - ComponentName provider = new ComponentName(context, providerClass); - Intent intent = new Intent(context, providerClass); - intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - int ids[] = - AppWidgetManager.getInstance(context).getAppWidgetIds(provider); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids); - context.sendBroadcast(intent); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/widgets/package-info.java b/app/src/main/java/org/isoron/uhabits/widgets/package-info.java deleted file mode 100644 index 5616e64ad..000000000 --- a/app/src/main/java/org/isoron/uhabits/widgets/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 home-screen Android widgets and related classes. - */ -package org.isoron.uhabits.widgets; \ No newline at end of file diff --git a/app/src/main/res/layout/edit_habit.xml b/app/src/main/res/layout/edit_habit.xml deleted file mode 100644 index 007fe9500..000000000 --- a/app/src/main/res/layout/edit_habit.xml +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -