Create android-base module

This commit is contained in:
2017-06-05 13:33:39 -04:00
parent 382b52e5b2
commit fc4b610d59
125 changed files with 1230 additions and 1075 deletions

View File

@@ -53,6 +53,8 @@ android {
dependencies {
implementation project(":uhabits-core")
implementation project(":android-base")
implementation 'com.android.support:appcompat-v7:25.3.1'
implementation 'com.android.support:design:25.3.1'
implementation 'com.android.support:preference-v14:25.3.1'

View File

@@ -1,5 +0,0 @@
#!/bin/bash
P=/sdcard/Android/data/org.isoron.uhabits/cache/Failed/
adb pull $P Failed/
adb shell rm -r $P

View File

@@ -29,12 +29,12 @@ import dagger.*;
@AppScope
@Component(modules = {
AppModule.class,
AppContextModule.class,
HabitsModule.class,
SingleThreadModule.class,
SQLModelFactory.class
})
public interface AndroidTestComponent extends HabitsComponent
public interface AndroidTestComponent extends HabitsApplicationComponent
{
}

View File

@@ -31,11 +31,11 @@ import android.util.*;
import junit.framework.*;
import org.isoron.androidbase.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.utils.*;
import org.junit.*;
import java.io.*;
@@ -71,8 +71,6 @@ public class BaseAndroidTest extends TestCase
protected ModelFactory modelFactory;
protected BaseSystem baseSystem;
@Override
@Before
public void setUp()
@@ -89,11 +87,9 @@ public class BaseAndroidTest extends TestCase
component = DaggerAndroidTestComponent
.builder()
.appModule(new AppModule(targetContext.getApplicationContext()))
.appContextModule(new AppContextModule(targetContext.getApplicationContext()))
.build();
baseSystem = new BaseSystem(targetContext);
HabitsApplication.setComponent(component);
prefs = component.getPreferences();
habitList = component.getHabitList();
@@ -168,7 +164,7 @@ public class BaseAndroidTest extends TestCase
protected void startTracing()
{
File dir = baseSystem.getFilesDir("Profile");
File dir = new AndroidDirFinder(targetContext).getFilesDir("Profile");
assertNotNull(dir);
String tracePath = dir.getAbsolutePath() + "/performance.trace";
Log.d("PerformanceTest", String.format("Saving trace file to %s", tracePath));

View File

@@ -40,7 +40,7 @@ public class BaseUserInterfaceTest
public static UiDevice device;
private HabitsComponent component;
private HabitsApplicationComponent component;
private HabitList habitList;

View File

@@ -24,8 +24,8 @@ import android.support.annotation.*;
import android.view.*;
import android.widget.*;
import org.isoron.androidbase.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.widgets.*;
import java.io.*;
@@ -170,7 +170,7 @@ public class BaseViewTest extends BaseAndroidTest
{
File dir = FileUtils.getSDCardDir("test-screenshots");
if (dir == null)
dir = baseSystem.getFilesDir("test-screenshots");
dir = new AndroidDirFinder(targetContext).getFilesDir("test-screenshots");
if (dir == null) throw new RuntimeException(
"Could not find suitable dir for screenshots");

View File

@@ -54,8 +54,7 @@ public class HabitLoggerTest extends BaseAndroidTest
protected void assertLogcatContains(String expectedMsg) throws IOException
{
BaseSystem system = new BaseSystem(targetContext);
String logcat = system.getLogcat();
String logcat = new AndroidBugReporter(targetContext).getLogcat();
assertThat(logcat, containsString(expectedMsg));
}

View File

@@ -41,8 +41,7 @@ public class HabitsApplicationTest extends BaseAndroidTest
String msg = "LOGCAT TEST";
new RuntimeException(msg).printStackTrace();
BaseSystem system = new BaseSystem(targetContext);
String log = system.getLogcat();
String log = new AndroidBugReporter(targetContext).getLogcat();
assertThat(log, containsString(msg));
}
}

View File

@@ -48,7 +48,7 @@ public class BarChartTest extends BaseViewTest
long day = DateUtils.millisecondsInOneDay;
CheckmarkList checkmarks = habit.getCheckmarks();
view.setCheckmarks(checkmarks.getByInterval(today - 20 * day, today));
view.setColor(ColorUtils.getColor(targetContext, habit.getColor()));
view.setColor(PaletteUtils.getColor(targetContext, habit.getColor()));
view.setTarget(200.0);
measureView(view, dpToPixels(300), dpToPixels(200));
}

View File

@@ -47,7 +47,7 @@ public class FrequencyChartTest extends BaseViewTest
view = new FrequencyChart(targetContext);
view.setFrequency(habit.getRepetitions().getWeekdayFrequency());
view.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
view.setColor(PaletteUtils.getAndroidTestColor(habit.getColor()));
measureView(view, dpToPixels(300), dpToPixels(100));
}

View File

@@ -47,7 +47,7 @@ public class HistoryChartTest extends BaseViewTest
chart = new HistoryChart(targetContext);
chart.setCheckmarks(habit.getCheckmarks().getAllValues());
chart.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
chart.setColor(PaletteUtils.getAndroidTestColor(habit.getColor()));
measureView(chart, dpToPixels(400), dpToPixels(200));
}

View File

@@ -47,7 +47,7 @@ public class RingViewTest extends BaseViewTest
view = new RingView(targetContext);
view.setPercentage(0.6f);
view.setText("60%");
view.setColor(ColorUtils.getAndroidTestColor(0));
view.setColor(PaletteUtils.getAndroidTestColor(0));
view.setBackgroundColor(Color.WHITE);
view.setThickness(dpToPixels(3));
}
@@ -63,7 +63,7 @@ public class RingViewTest extends BaseViewTest
public void testRender_withDifferentParams() throws IOException
{
view.setPercentage(0.25f);
view.setColor(ColorUtils.getAndroidTestColor(5));
view.setColor(PaletteUtils.getAndroidTestColor(5));
measureView(view, dpToPixels(200), dpToPixels(200));
assertRenders(view, BASE_PATH + "renderDifferentParams.png");

View File

@@ -50,7 +50,7 @@ public class ScoreChartTest extends BaseViewTest
view = new ScoreChart(targetContext);
view.setScores(habit.getScores().toList());
view.setColor(ColorUtils.getColor(targetContext, habit.getColor()));
view.setColor(PaletteUtils.getColor(targetContext, habit.getColor()));
view.setBucketSize(7);
measureView(view, dpToPixels(300), dpToPixels(200));
}

View File

@@ -46,7 +46,7 @@ public class StreakChartTest extends BaseViewTest
Habit habit = fixtures.createLongHabit();
view = new StreakChart(targetContext);
view.setColor(ColorUtils.getAndroidTestColor(habit.getColor()));
view.setColor(PaletteUtils.getAndroidTestColor(habit.getColor()));
view.setStreaks(habit.getStreaks().getBest(5));
measureView(view, dpToPixels(300), dpToPixels(100));
}

View File

@@ -45,7 +45,7 @@ public class CheckmarkButtonViewTest extends BaseViewTest
super.setUp();
view = new CheckmarkButtonView(targetContext);
view.setValue(Checkmark.UNCHECKED);
view.setColor(ColorUtils.getAndroidTestColor(5));
view.setColor(PaletteUtils.getAndroidTestColor(5));
measureView(view, dpToPixels(48), dpToPixels(48));
}

View File

@@ -25,7 +25,7 @@ import android.test.suitebuilder.annotation.*;
import org.isoron.uhabits.core.models.Checkmark;
import org.isoron.uhabits.core.models.Habit;
import org.isoron.uhabits.BaseViewTest;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,7 +60,7 @@ public class CheckmarkPanelViewTest extends BaseViewTest
view.setHabit(habit);
view.setValues(checkmarks);
view.setButtonCount(4);
view.setColor(ColorUtils.getAndroidTestColor(7));
view.setColor(PaletteUtils.getAndroidTestColor(7));
measureView(view, dpToPixels(200), dpToPixels(200));
}

View File

@@ -51,7 +51,7 @@ public class NumberButtonViewTest extends BaseViewTest
view = new NumberButtonView(targetContext);
view.setUnit("steps");
view.setThreshold(100.0);
view.setColor(ColorUtils.getAndroidTestColor(8));
view.setColor(PaletteUtils.getAndroidTestColor(8));
measureView(view, dpToPixels(48), dpToPixels(48));

View File

@@ -22,6 +22,7 @@ package org.isoron.uhabits.tasks;
import android.support.test.runner.*;
import android.test.suitebuilder.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.tasks.*;
@@ -31,8 +32,8 @@ import org.junit.runner.*;
import java.io.*;
import java.util.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.core.IsNot.not;
@RunWith(AndroidJUnit4.class)
@@ -54,7 +55,7 @@ public class ExportCSVTaskTest extends BaseAndroidTest
List<Habit> selected = new LinkedList<>();
for (Habit h : habitList) selected.add(h);
File outputDir = baseSystem.getFilesDir("CSV");
File outputDir = new AndroidDirFinder(targetContext).getFilesDir("CSV");
assertNotNull(outputDir);
taskRunner.execute(

View File

@@ -22,6 +22,7 @@ package org.isoron.uhabits.tasks;
import android.support.test.runner.*;
import android.test.suitebuilder.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.junit.*;
import org.junit.runner.*;
@@ -43,12 +44,14 @@ public class ExportDBTaskTest extends BaseAndroidTest
public void testExportCSV() throws Throwable
{
ExportDBTask task =
new ExportDBTask(targetContext, baseSystem, filename -> {
assertNotNull(filename);
File f = new File(filename);
assertTrue(f.exists());
assertTrue(f.canRead());
});
new ExportDBTask(targetContext, new AndroidDirFinder(targetContext),
filename ->
{
assertNotNull(filename);
File f = new File(filename);
assertTrue(f.exists());
assertTrue(f.canRead());
});
taskRunner.execute(task);
}

View File

@@ -50,7 +50,7 @@ public class CheckmarkWidgetViewTest extends BaseViewTest
double score = habit.getScores().getTodayValue();
float percentage = (float) score;
view.setActiveColor(ColorUtils.getAndroidTestColor(0));
view.setActiveColor(PaletteUtils.getAndroidTestColor(0));
view.setCheckmarkValue(habit.getCheckmarks().getTodayValue());
view.setPercentage(percentage);
view.setName(habit.getName());

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase;
import java.lang.annotation.*;
import javax.inject.*;
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface AppContext
{
}

View File

@@ -1,202 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase;
import android.content.*;
import android.os.*;
import android.support.annotation.*;
import android.support.v4.content.*;
import android.util.*;
import android.view.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.ui.screens.habits.list.*;
import org.isoron.uhabits.core.ui.screens.habits.show.*;
import org.isoron.uhabits.core.utils.*;
import java.io.*;
import java.lang.Process;
import java.util.*;
import javax.inject.*;
/**
* Base class for all systems class in the application.
* <p>
* 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.
*/
@AppScope
public class BaseSystem implements CACertSSLContextProvider,
ListHabitsBehavior.System,
ShowHabitMenuBehavior.System
{
private Context context;
@Override
public Context getContext()
{
return context;
}
@Inject
public BaseSystem(@AppContext Context context)
{
this.context = context;
}
@Nullable
public File getFilesDir(@Nullable String relativePath)
{
File externalFilesDirs[] = ContextCompat.getExternalFilesDirs(context, null);
if (externalFilesDirs == null)
{
Log.e("BaseSystem", "getFilesDir: getExternalFilesDirs returned null");
return null;
}
return FileUtils.getDir(externalFilesDirs, relativePath);
}
/**
* Captures a bug report and saves it to a file in the SD card.
* <p>
* 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.
*/
@Override
@NonNull
public void dumpBugReportToFile()
{
try
{
String date = DateFormats
.getBackupDateFormat()
.format(DateUtils.getLocalTime());
if (context == null) throw new IllegalStateException();
File dir = 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();
}
}
/**
* Captures and returns a bug report.
* <p>
* 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.
*/
@Override
@NonNull
public String getBugReport() throws IOException
{
String logcat = getLogcat();
String deviceInfo = getDeviceInfo();
String log = "---------- BUG REPORT BEGINS ----------\n";
log += deviceInfo + "\n" + logcat;
log += "---------- BUG REPORT ENDS ------------\n";
return log;
}
@Override
public File getCSVOutputDir()
{
return getFilesDir("CSV");
}
public String getLogcat() throws IOException
{
int maxLineCount = 250;
StringBuilder builder = new StringBuilder();
String[] command = new String[]{ "logcat", "-d" };
Process process = Runtime.getRuntime().exec(command);
InputStreamReader in = new InputStreamReader(process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(in);
LinkedList<String> log = new LinkedList<>();
String line;
while ((line = bufferedReader.readLine()) != null)
{
log.addLast(line);
if (log.size() > maxLineCount) log.removeFirst();
}
for (String l : log)
{
builder.append(l);
builder.append('\n');
}
return builder.toString();
}
private 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());
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase;
import android.content.*;
import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.*;
import javax.net.ssl.*;
public interface CACertSSLContextProvider
{
default SSLContext getCACertSSLContext()
{
try
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getContext().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);
}
}
Context getContext();
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.common.dialogs.*;
import org.isoron.uhabits.core.ui.*;
import dagger.*;
@ActivityScope
@Component(modules = { ActivityModule.class },
dependencies = { HabitsComponent.class })
public interface ActivityComponent
{
BaseActivity getActivity();
ColorPickerDialogFactory getColorPickerDialogFactory();
ThemeSwitcher getThemeSwitcher();
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import android.content.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.core.ui.*;
import dagger.*;
@Module
public class ActivityModule
{
private BaseActivity activity;
public ActivityModule(BaseActivity activity)
{
this.activity = activity;
}
@Provides
public BaseActivity getActivity()
{
return activity;
}
@Provides
@ActivityContext
public Context getContext()
{
return activity;
}
@Provides
@ActivityScope
public static ThemeSwitcher getThemeSwitcher(AndroidThemeSwitcher t)
{
return t;
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import javax.inject.*;
/**
* Scope used by objects that live as long as the activity is alive.
*/
@Scope
public @interface ActivityScope { }

View File

@@ -1,139 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import android.content.*;
import android.os.*;
import android.support.annotation.*;
import android.support.v7.app.*;
import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.*;
import static android.R.anim.fade_in;
import static android.R.anim.fade_out;
/**
* Base class for all activities in the application.
* <p>
* This class delegates the responsibilities of an Android activity to other
* classes. For example, callbacks related to menus are forwarded to a {@link
* BaseMenu}, while callbacks related to activity results are forwarded to a
* {@link BaseScreen}.
* <p>
* A BaseActivity also installs an {@link java.lang.Thread.UncaughtExceptionHandler}
* 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
{
@Nullable
private BaseMenu baseMenu;
@Nullable
private BaseScreen screen;
private ActivityComponent component;
public ActivityComponent getComponent()
{
return component;
}
@Override
public boolean onCreateOptionsMenu(@Nullable Menu menu)
{
if (menu == null) return true;
if (baseMenu == null) return true;
baseMenu.onCreate(getMenuInflater(), menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@Nullable MenuItem item)
{
if (item == null) return false;
if (baseMenu == null) return false;
return baseMenu.onItemSelected(item);
}
public void restartWithFade(Class<?> cls)
{
new Handler().postDelayed(() ->
{
finish();
overridePendingTransition(fade_in, fade_out);
startActivity(new Intent(this, cls));
}, 500); // HACK: Let the menu disappear first
}
public void setBaseMenu(@Nullable BaseMenu baseMenu)
{
this.baseMenu = baseMenu;
}
public void setScreen(@Nullable BaseScreen screen)
{
this.screen = screen;
}
public void showDialog(AppCompatDialogFragment dialog, String tag)
{
dialog.show(getSupportFragmentManager(), tag);
}
public void showDialog(AppCompatDialog dialog)
{
dialog.show();
}
@Override
protected void onActivityResult(int request, int result, Intent data)
{
if (screen == null) super.onActivityResult(request, result, data);
else screen.onResult(request, result, data);
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(getExceptionHandler());
HabitsApplication app = (HabitsApplication) getApplicationContext();
component = DaggerActivityComponent
.builder()
.activityModule(new ActivityModule(this))
.habitsComponent(app.getComponent())
.build();
component.getThemeSwitcher().apply();
}
protected Thread.UncaughtExceptionHandler getExceptionHandler()
{
return new BaseExceptionHandler(this);
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import android.support.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.models.sqlite.*;
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 BaseSystem(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);
}
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import android.support.annotation.*;
import android.view.*;
import javax.annotation.*;
/**
* Base class for all the menus in the application.
* <p>
* This class receives from BaseActivity all callbacks related to menus, such as
* menu creation and click events. It also handles some implementation details
* of creating menus in Android, such as inflating the resources.
*/
public abstract class BaseMenu
{
@NonNull
private final BaseActivity activity;
public BaseMenu(@NonNull BaseActivity activity)
{
this.activity = activity;
}
@NonNull
public BaseActivity getActivity()
{
return activity;
}
/**
* Declare that the menu has changed, and should be recreated.
*/
public void invalidate()
{
activity.invalidateOptionsMenu();
}
/**
* Called when the menu is first displayed.
* <p>
* The given menu is already inflated and ready to receive items. The
* application should override this method and add items to the menu here.
*
* @param menu the menu that is being created.
*/
public void onCreate(@NonNull Menu menu)
{
}
/**
* Called when the menu is first displayed.
* <p>
* 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 void onCreate(@NonNull MenuInflater inflater,
@NonNull Menu menu)
{
menu.clear();
inflater.inflate(getMenuResourceId(), menu);
onCreate(menu);
}
/**
* Called whenever an item on the menu is selected.
*
* @param item the item that was selected.
* @return true if the event was consumed, or false otherwise
*/
public boolean onItemSelected(@NonNull MenuItem item)
{
return false;
}
/**
* Returns the id of the resource that should be used to inflate this menu.
*
* @return id of the menu resource.
*/
@Resource
protected abstract int getMenuResourceId();
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.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.core.ui.*;
import org.isoron.uhabits.utils.*;
import static android.os.Build.VERSION.*;
import static android.os.Build.VERSION_CODES.*;
/**
* Base class for all root views in the application.
* <p>
* A root view is an Android view that is directly attached to an activity. This
* view usually includes a toolbar and a progress bar. This abstract class hides
* some of the complexity of setting these things up, for every version of
* Android.
*/
public abstract class BaseRootView extends FrameLayout
{
@NonNull
private final Context context;
private final ThemeSwitcher themeSwitcher;
boolean shouldDisplayHomeAsUp = false;
public BaseRootView(@NonNull Context context)
{
super(context);
this.context = context;
BaseActivity activity = (BaseActivity) context;
themeSwitcher = activity.getComponent().getThemeSwitcher();
}
public boolean getDisplayHomeAsUp()
{
return shouldDisplayHomeAsUp;
}
public void setDisplayHomeAsUp(boolean b)
{
shouldDisplayHomeAsUp = b;
}
@NonNull
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);
}
protected void initToolbar()
{
if (SDK_INT >= LOLLIPOP)
{
getToolbar().setElevation(InterfaceUtils.dpToPixels(context, 2));
View view = findViewById(R.id.toolbarShadow);
if (view != null) view.setVisibility(GONE);
view = findViewById(R.id.headerShadow);
if (view != null) view.setVisibility(GONE);
}
}
}

View File

@@ -1,332 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import android.content.*;
import android.graphics.*;
import android.graphics.drawable.*;
import android.net.*;
import android.os.*;
import android.provider.*;
import android.support.annotation.*;
import android.support.design.widget.*;
import android.support.v4.app.*;
import android.support.v4.content.res.*;
import android.support.v7.app.*;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.Toolbar;
import android.view.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.notifications.*;
import org.isoron.uhabits.utils.*;
import java.io.*;
import static android.media.RingtoneManager.ACTION_RINGTONE_PICKER;
import static android.media.RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI;
import static android.media.RingtoneManager.EXTRA_RINGTONE_EXISTING_URI;
import static android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT;
import static android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT;
import static android.media.RingtoneManager.EXTRA_RINGTONE_TYPE;
import static android.media.RingtoneManager.TYPE_NOTIFICATION;
import static android.os.Build.VERSION.*;
import static android.os.Build.VERSION_CODES.*;
import static android.support.v4.content.FileProvider.*;
/**
* Base class for all screens in the application.
* <p>
* Screens are responsible for deciding what root views and what menus should be
* attached to the main window. They are also responsible for showing other
* screens and for receiving their results.
*/
public class BaseScreen
{
public static final int REQUEST_CREATE_DOCUMENT = 1;
protected BaseActivity activity;
@Nullable
private BaseRootView rootView;
@Nullable
private BaseSelectionMenu selectionMenu;
protected Snackbar snackbar;
public BaseScreen(@NonNull BaseActivity activity)
{
this.activity = activity;
}
@Deprecated
public static void setupActionBarColor(@NonNull AppCompatActivity activity,
int color)
{
Toolbar toolbar = (Toolbar) activity.findViewById(R.id.toolbar);
if (toolbar == null) return;
activity.setSupportActionBar(toolbar);
ActionBar actionBar = activity.getSupportActionBar();
if (actionBar == null) return;
actionBar.setDisplayHomeAsUpEnabled(true);
ColorDrawable drawable = new ColorDrawable(color);
actionBar.setBackgroundDrawable(drawable);
if (SDK_INT >= LOLLIPOP)
{
int darkerColor = ColorUtils.mixColors(color, Color.BLACK, 0.75f);
activity.getWindow().setStatusBarColor(darkerColor);
toolbar.setElevation(InterfaceUtils.dpToPixels(activity, 2));
View view = activity.findViewById(R.id.toolbarShadow);
if (view != null) view.setVisibility(View.GONE);
view = activity.findViewById(R.id.headerShadow);
if (view != null) view.setVisibility(View.GONE);
}
}
@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);
}
}
public static void showRingtonePicker(Fragment fragment,
int requestCode)
{
Uri existingRingtoneUri = RingtoneManager.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);
}
/**
* Notifies the screen that its contents should be updated.
*/
public void invalidate()
{
if (rootView == null) return;
rootView.invalidate();
}
public void invalidateToolbar()
{
if (rootView == null) return;
activity.runOnUiThread(() -> {
Toolbar toolbar = rootView.getToolbar();
activity.setSupportActionBar(toolbar);
ActionBar actionBar = activity.getSupportActionBar();
if (actionBar == null) return;
actionBar.setDisplayHomeAsUpEnabled(rootView.getDisplayHomeAsUp());
int color = rootView.getToolbarColor();
setActionBarColor(actionBar, color);
setStatusBarColor(color);
});
}
/**
* Called when another Activity has finished, and has returned some result.
*
* @param requestCode the request code originally supplied to {@link
* android.app.Activity#startActivityForResult(Intent,
* int, Bundle)}.
* @param resultCode the result code sent by the other activity.
* @param data an Intent containing extra data sent by the other
* activity.
* @see {@link android.app.Activity#onActivityResult(int, int, Intent)}
*/
public void onResult(int requestCode, int resultCode, Intent data)
{
}
/**
* Sets the menu to be shown by this screen.
* <p>
* This menu will be visible if when there is no active selection operation.
* If the provided menu is null, then no menu will be shown.
*
* @param menu the menu to be shown.
*/
public void setMenu(@Nullable BaseMenu menu)
{
activity.setBaseMenu(menu);
}
/**
* Sets the root view for this screen.
*
* @param rootView the root view for this screen.
*/
public void setRootView(@Nullable BaseRootView rootView)
{
this.rootView = rootView;
activity.setContentView(rootView);
if (rootView == null) return;
invalidateToolbar();
}
/**
* Sets the menu to be shown when a selection is active on the screen.
*
* @param menu the menu to be shown during a selection
*/
public void setSelectionMenu(@Nullable BaseSelectionMenu menu)
{
this.selectionMenu = menu;
}
/**
* Shows a message on the screen.
*
* @param stringId the string resource id for this message.
*/
public void showMessage(@StringRes Integer stringId)
{
if (stringId == null || rootView == null) return;
if (snackbar == null)
{
snackbar = Snackbar.make(rootView, stringId, Snackbar.LENGTH_SHORT);
int tvId = android.support.design.R.id.snackbar_text;
TextView tv = (TextView) snackbar.getView().findViewById(tvId);
tv.setTextColor(Color.WHITE);
}
else snackbar.setText(stringId);
snackbar.show();
}
public void showSendEmailScreen(@StringRes int toId,
@StringRes int subjectId,
String content)
{
String to = activity.getString(toId);
String subject = activity.getString(subjectId);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{ to });
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, content);
activity.startActivity(intent);
}
public void showSendFileScreen(@NonNull String archiveFilename)
{
File file = new File(archiveFilename);
Uri fileUri = getUriForFile(activity, "org.isoron.uhabits", file);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("application/zip");
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent);
}
/**
* Instructs the screen to start a selection.
* <p>
* If a selection menu was provided, this menu will be shown instead of the
* regular one.
*/
public void startSelection()
{
activity.startSupportActionMode(new ActionModeWrapper());
}
private void setActionBarColor(@NonNull ActionBar actionBar, int color)
{
ColorDrawable drawable = new ColorDrawable(color);
actionBar.setBackgroundDrawable(drawable);
}
private void setStatusBarColor(int baseColor)
{
if (SDK_INT < LOLLIPOP) return;
int darkerColor = ColorUtils.mixColors(baseColor, Color.BLACK, 0.75f);
activity.getWindow().setStatusBarColor(darkerColor);
}
private class ActionModeWrapper implements ActionMode.Callback
{
@Override
public boolean onActionItemClicked(@Nullable ActionMode mode,
@Nullable MenuItem item)
{
if (item == null || selectionMenu == null) return false;
return selectionMenu.onItemClicked(item);
}
@Override
public boolean onCreateActionMode(@Nullable ActionMode mode,
@Nullable Menu menu)
{
if (selectionMenu == null) return false;
if (mode == null || menu == null) return false;
selectionMenu.onCreate(activity.getMenuInflater(), mode, menu);
return true;
}
@Override
public void onDestroyActionMode(@Nullable ActionMode mode)
{
if (selectionMenu == null) return;
selectionMenu.onFinish();
}
@Override
public boolean onPrepareActionMode(@Nullable ActionMode mode,
@Nullable Menu menu)
{
if (selectionMenu == null || menu == null) return false;
return selectionMenu.onPrepare(menu);
}
}
}

View File

@@ -1,129 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
import android.support.annotation.*;
import android.support.v7.view.ActionMode;
import android.view.*;
/**
* Base class for all the selection menus in the application.
* <p>
* A selection menu is a menu that appears when the screen starts a selection
* operation. It contains actions that modify the selected items, such as delete
* or archive. Since it replaces the toolbar, it also has a title.
* <p>
* This class hides many implementation details of creating such menus in
* Android. The interface is supposed to look very similar to {@link BaseMenu},
* with a few additional methods, such as finishing the selection operation.
* Internally, it uses an {@link ActionMode}.
*/
public abstract class BaseSelectionMenu
{
@Nullable
private ActionMode actionMode;
/**
* Finishes the selection operation.
*/
public void finish()
{
if (actionMode != null) actionMode.finish();
}
/**
* Declare that the menu has changed, and should be recreated.
*/
public void invalidate()
{
if (actionMode != null) actionMode.invalidate();
}
/**
* Called when the menu is first displayed.
* <p>
* 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 void onCreate(@NonNull MenuInflater inflater,
@NonNull ActionMode mode,
@NonNull Menu menu)
{
this.actionMode = mode;
inflater.inflate(getResourceId(), menu);
onCreate(menu);
}
/**
* Called when the selection operation is about to finish.
*/
public void onFinish()
{
}
/**
* Called whenever an item on the menu is selected.
*
* @param item the item that was selected.
* @return true if the event was consumed, or false otherwise
*/
public boolean onItemClicked(@NonNull MenuItem item)
{
return false;
}
/**
* Called whenever the menu is invalidated.
*
* @param menu the menu to be refreshed
* @return true if the menu has changes, false otherwise
*/
public boolean onPrepare(@NonNull Menu menu)
{
return false;
}
/**
* Sets the title of the selection menu.
*
* @param title the new title.
*/
public void setTitle(String title)
{
if (actionMode != null) actionMode.setTitle(title);
}
protected abstract int getResourceId();
/**
* Called when the menu is first created.
*
* @param menu the menu being created
*/
protected void onCreate(@NonNull Menu menu)
{
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.utils;
import android.os.*;
import android.support.annotation.*;
import android.util.*;
import java.io.*;
public abstract class FileUtils
{
public static void copy(File src, File dst) throws IOException
{
FileInputStream inStream = new FileInputStream(src);
FileOutputStream outStream = new FileOutputStream(dst);
copy(inStream, outStream);
}
public static void copy(InputStream inStream, File dst) throws IOException
{
FileOutputStream outStream = new FileOutputStream(dst);
copy(inStream, outStream);
}
public static void copy(InputStream in, OutputStream out) throws IOException
{
int numBytes;
byte[] buffer = new byte[1024];
while ((numBytes = in.read(buffer)) != -1)
out.write(buffer, 0, numBytes);
}
@Nullable
public static File getDir(@NonNull File potentialParentDirs[],
@Nullable String relativePath)
{
if (relativePath == null) relativePath = "";
File chosenDir = null;
for (File dir : potentialParentDirs)
{
if (dir == null || !dir.canWrite()) continue;
chosenDir = dir;
break;
}
if (chosenDir == null)
{
Log.e("FileUtils",
"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("FileUtils",
"getDir: chosen dir does not exist and cannot be created");
return null;
}
return dir;
}
@Nullable
public static File getSDCardDir(@Nullable String relativePath)
{
File parents[] =
new File[]{ Environment.getExternalStorageDirectory() };
return getDir(parents, relativePath);
}
}

View File

@@ -42,7 +42,7 @@ public class HabitsApplication extends Application
{
private Context context;
private static HabitsComponent component;
private static HabitsApplicationComponent component;
private WidgetUpdater widgetUpdater;
@@ -50,12 +50,12 @@ public class HabitsApplication extends Application
private NotificationTray notificationTray;
public HabitsComponent getComponent()
public HabitsApplicationComponent getComponent()
{
return component;
}
public static void setComponent(HabitsComponent component)
public static void setComponent(HabitsApplicationComponent component)
{
HabitsApplication.component = component;
}
@@ -79,9 +79,9 @@ public class HabitsApplication extends Application
super.onCreate();
context = this;
component = DaggerHabitsComponent
component = DaggerHabitsApplicationComponent
.builder()
.appModule(new AppModule(context))
.appContextModule(new AppContextModule(context))
.build();
if (isTestMode())

View File

@@ -43,15 +43,10 @@ import dagger.*;
@AppScope
@Component(modules = {
AppModule.class,
HabitsModule.class,
AndroidTaskRunner.class,
SQLModelFactory.class
AppContextModule.class, HabitsModule.class, AndroidTaskRunner.class, SQLModelFactory.class
})
public interface HabitsComponent
public interface HabitsApplicationComponent
{
BaseSystem getBaseSystem();
CommandRunner getCommandRunner();
@AppContext

View File

@@ -22,7 +22,7 @@ package org.isoron.uhabits.activities;
import android.support.annotation.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.*;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
@@ -17,26 +17,25 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase;
package org.isoron.uhabits.activities;
import android.content.*;
import org.isoron.uhabits.core.models.*;
import dagger.*;
@Module
public class AppModule
public class HabitModule
{
private final Context context;
private final Habit habit;
public AppModule(@AppContext Context context)
public HabitModule(Habit habit)
{
this.context = context;
this.habit = habit;
}
@Provides
@AppContext
Context getContext()
public Habit getHabit()
{
return context;
return habit;
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.activities;
import android.content.*;
import android.net.*;
import android.os.*;
import android.support.annotation.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*;
public abstract class HabitsActivity extends BaseActivity
{
private HabitsActivityComponent component;
private HabitsApplicationComponent appComponent;
public HabitsActivityComponent getActivityComponent()
{
return component;
}
public HabitsApplicationComponent getAppComponent()
{
return appComponent;
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
appComponent =
((HabitsApplication) getApplicationContext()).getComponent();
Habit habit = getHabitFromIntent(appComponent.getHabitList());
component = DaggerHabitsActivityComponent
.builder()
.activityModule(new ActivityModule(this))
.habitModule(new HabitModule(habit))
.habitsApplicationComponent(appComponent)
.build();
component.getThemeSwitcher().apply();
}
@Nullable
private Habit getHabitFromIntent(@NonNull HabitList habitList)
{
Uri data = getIntent().getData();
if(data == null) return null;
Habit habit = habitList.getById(ContentUris.parseId(data));
if (habit == null) throw new RuntimeException("habit not found");
return habit;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.activities;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.common.dialogs.*;
import org.isoron.uhabits.activities.habits.list.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.activities.habits.show.*;
import org.isoron.uhabits.core.ui.*;
import dagger.*;
@ActivityScope
@Component(modules = {
ActivityModule.class,
HabitsActivityModule.class,
ListHabitsModule.class,
ShowHabitModule.class,
HabitModule.class
}, dependencies = { HabitsApplicationComponent.class })
public interface HabitsActivityComponent
{
BaseActivity getActivity();
CheckmarkButtonControllerFactory getCheckmarkButtonControllerFactory();
ColorPickerDialogFactory getColorPickerDialogFactory();
HabitCardListAdapter getHabitCardListAdapter();
HabitCardListController getHabitCardListController();
ListHabitsController getListHabitsController();
ListHabitsMenu getListHabitsMenu();
ListHabitsRootView getListHabitsRootView();
ListHabitsScreen getListHabitsScreen();
ListHabitsSelectionMenu getListHabitsSelectionMenu();
NumberButtonControllerFactory getNumberButtonControllerFactory();
ShowHabitController getShowHabitController();
ShowHabitsMenu getShowHabitMenu();
ShowHabitRootView getShowHabitRootView();
ShowHabitScreen getShowHabitScreen();
ThemeSwitcher getThemeSwitcher();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
@@ -17,15 +17,17 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.androidbase.activities;
package org.isoron.uhabits.activities;
import java.lang.annotation.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.core.ui.*;
import javax.inject.*;
import dagger.*;
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityContext
@Module
public abstract class HabitsActivityModule
{
@Binds
@ActivityScope
abstract ThemeSwitcher getThemeSwitcher(AndroidThemeSwitcher t);
}

View File

@@ -16,30 +16,32 @@
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.activities.habits.show;
package org.isoron.uhabits.activities;
import android.support.annotation.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.core.ui.screens.habits.list.*;
import org.isoron.uhabits.core.ui.screens.habits.show.*;
import dagger.*;
import java.io.*;
@ActivityScope
@Component(modules = { ShowHabitModule.class },
dependencies = { HabitsComponent.class })
public interface ShowHabitComponent
import javax.inject.*;
public class HabitsDirFinder
implements ShowHabitMenuBehavior.System, ListHabitsBehavior.DirFinder
{
@NonNull
ShowHabitController getController();
private AndroidDirFinder androidDirFinder;
@NonNull
ShowHabitsMenu getMenu();
@Inject
public HabitsDirFinder(@NonNull AndroidDirFinder androidDirFinder)
{
this.androidDirFinder = androidDirFinder;
}
@NonNull
ShowHabitRootView getRootView();
@NonNull
ShowHabitScreen getScreen();
@Override
public File getCSVOutputDir()
{
return androidDirFinder.getFilesDir("CSV");
}
}

View File

@@ -21,22 +21,21 @@ package org.isoron.uhabits.activities.about;
import android.os.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.core.ui.screens.about.*;
/**
* Activity that allows the user to see information about the app itself.
* Display current version, link to Google Play and list of contributors.
*/
public class AboutActivity extends BaseActivity
public class AboutActivity extends HabitsActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
HabitsApplication app = (HabitsApplication) getApplication();
HabitsComponent cmp = app.getComponent();
HabitsApplicationComponent cmp = getAppComponent();
AboutScreen screen = new AboutScreen(this, cmp.getIntentFactory());
AboutBehavior behavior = new AboutBehavior(cmp.getPreferences(), screen);
AboutRootView rootView = new AboutRootView(this, behavior);

View File

@@ -24,10 +24,10 @@ import android.support.annotation.*;
import android.widget.*;
import org.isoron.androidbase.activities.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.BuildConfig;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.ui.screens.about.*;
import org.isoron.uhabits.utils.*;
import butterknife.*;

View File

@@ -31,7 +31,7 @@ public class ColorPickerDialog extends com.android.colorpicker.ColorPickerDialog
{
super.setOnColorSelectedListener(c ->
{
c = ColorUtils.colorToPaletteIndex(getContext(), c);
c = PaletteUtils.colorToPaletteIndex(getContext(), c);
callback.onColorPicked(c);
});
}

View File

@@ -22,7 +22,8 @@ package org.isoron.uhabits.activities.common.dialogs;
import android.content.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.utils.*;
import javax.inject.*;
@@ -42,7 +43,7 @@ public class ColorPickerDialogFactory
{
ColorPickerDialog dialog = new ColorPickerDialog();
StyledResources res = new StyledResources(context);
int color = ColorUtils.getColor(context, paletteColor);
int color = PaletteUtils.getColor(context, paletteColor);
dialog.initialize(R.string.color_picker_default_title, res.getPalette(),
color, 4, com.android.colorpicker.ColorPickerDialog.SIZE_SMALL);

View File

@@ -33,7 +33,7 @@ import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.utils.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class HistoryEditorDialog extends AppCompatDialogFragment
implements DialogInterface.OnClickListener, ModelObservable.Listener
@@ -171,7 +171,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
if (getContext() == null || habit == null || historyChart == null)
return;
int color = ColorUtils.getColor(getContext(), habit.getColor());
int color = PaletteUtils.getColor(getContext(), habit.getColor());
historyChart.setColor(color);
historyChart.setCheckmarks(checkmarks);
}

View File

@@ -24,6 +24,7 @@ import android.graphics.*;
import android.support.annotation.*;
import android.util.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.views.*;
import org.isoron.uhabits.core.models.*;
@@ -33,7 +34,7 @@ import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class BarChart extends ScrollableChart
{

View File

@@ -24,6 +24,7 @@ import android.graphics.*;
import android.support.annotation.*;
import android.util.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.utils.*;

View File

@@ -26,6 +26,7 @@ import android.support.annotation.*;
import android.util.*;
import android.view.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.utils.*;
@@ -34,7 +35,7 @@ import java.text.*;
import java.util.*;
import static org.isoron.uhabits.core.models.Checkmark.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class HistoryChart extends ScrollableChart
{

View File

@@ -26,11 +26,12 @@ import android.text.*;
import android.util.*;
import android.view.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.utils.*;
import static org.isoron.uhabits.utils.AttributeSetUtils.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class RingView extends View
{
@@ -76,7 +77,7 @@ public class RingView extends View
percentage = 0.0f;
precision = 0.01f;
color = ColorUtils.getAndroidTestColor(0);
color = PaletteUtils.getAndroidTestColor(0);
thickness = dpToPixels(getContext(), 2);
text = "";
textSize = getDimension(context, R.dimen.smallTextSize);

View File

@@ -24,6 +24,7 @@ import android.graphics.*;
import android.support.annotation.*;
import android.util.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*;
@@ -32,7 +33,7 @@ import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class ScoreChart extends ScrollableChart
{

View File

@@ -25,16 +25,16 @@ import android.util.*;
import android.view.*;
import android.view.ViewGroup.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
import static android.view.View.MeasureSpec.*;
import static org.isoron.uhabits.utils.InterfaceUtils.getDimension;
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
public class StreakChart extends View
{

View File

@@ -28,9 +28,9 @@ import android.view.*;
import com.android.datetimepicker.time.*;
import org.isoron.androidbase.activities.*;
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.activities.habits.edit.views.*;
import org.isoron.uhabits.core.commands.*;
@@ -39,8 +39,8 @@ import org.isoron.uhabits.core.preferences.*;
import butterknife.*;
import static android.view.View.*;
import static org.isoron.uhabits.core.ui.ThemeSwitcher.*;
import static android.view.View.GONE;
import static org.isoron.uhabits.core.ui.ThemeSwitcher.THEME_LIGHT;
public class EditHabitDialog extends AppCompatDialogFragment
{
@@ -56,7 +56,7 @@ public class EditHabitDialog extends AppCompatDialogFragment
protected HabitList habitList;
protected HabitsComponent component;
protected HabitsApplicationComponent component;
protected ModelFactory modelFactory;
@@ -77,7 +77,7 @@ public class EditHabitDialog extends AppCompatDialogFragment
@Override
public int getTheme()
{
HabitsComponent component =
HabitsApplicationComponent component =
((HabitsApplication) getContext().getApplicationContext()).getComponent();
if(component.getPreferences().getTheme() == THEME_LIGHT)
@@ -91,9 +91,9 @@ public class EditHabitDialog extends AppCompatDialogFragment
{
super.onActivityCreated(savedInstanceState);
BaseActivity activity = (BaseActivity) getActivity();
HabitsActivity activity = (HabitsActivity) getActivity();
colorPickerDialogFactory =
activity.getComponent().getColorPickerDialogFactory();
activity.getActivityComponent().getColorPickerDialogFactory();
}
@Override

View File

@@ -26,8 +26,8 @@ import android.util.*;
import android.view.*;
import android.widget.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.utils.*;
import static org.isoron.uhabits.utils.AttributeSetUtils.*;

View File

@@ -68,7 +68,7 @@ public class NameDescriptionPanel extends FrameLayout
public void setColor(int color)
{
this.color = color;
tvName.setTextColor(ColorUtils.getColor(getContext(), color));
tvName.setTextColor(PaletteUtils.getColor(getContext(), color));
}
@NonNull

View File

@@ -21,8 +21,7 @@ package org.isoron.uhabits.activities.habits.list;
import android.os.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.*;
@@ -31,7 +30,7 @@ import org.isoron.uhabits.core.utils.*;
/**
* Activity that allows the user to see and modify the list of habits.
*/
public class ListHabitsActivity extends BaseActivity
public class ListHabitsActivity extends HabitsActivity
{
private HabitCardListAdapter adapter;
@@ -39,47 +38,33 @@ public class ListHabitsActivity extends BaseActivity
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);
midnightTimer = getAppComponent().getMidnightTimer();
HabitsActivityComponent component = getActivityComponent();
HabitsApplication app = (HabitsApplication) getApplicationContext();
midnightTimer = app.getComponent().getMidnightTimer();
ListHabitsMenu menu = component.getListHabitsMenu();
ListHabitsSelectionMenu selectionMenu = component.getListHabitsSelectionMenu();
ListHabitsController controller = component.getListHabitsController();
component = DaggerListHabitsComponent
.builder()
.habitsComponent(app.getComponent())
.listHabitsModule(new ListHabitsModule(this))
.build();
adapter = component.getHabitCardListAdapter();
rootView = component.getListHabitsRootView();
screen = component.getListHabitsScreen();
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();
prefs = getAppComponent().getPreferences();
pureBlack = prefs.isPureBlackEnabled();
screen.setMenu(menu);
screen.setController(controller);
screen.setListController(component.getListController());
screen.setListController(component.getHabitCardListController());
screen.setSelectionMenu(selectionMenu);
rootView.setController(controller, selectionMenu);

View File

@@ -1,51 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.activities.habits.list;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import dagger.*;
@ActivityScope
@Component(modules = { ListHabitsModule.class },
dependencies = { HabitsComponent.class })
public interface ListHabitsComponent
{
HabitCardListAdapter getAdapter();
CheckmarkButtonControllerFactory getCheckmarkButtonControllerFactory();
ListHabitsController getController();
HabitCardListController getListController();
ListHabitsMenu getMenu();
NumberButtonControllerFactory getNumberButtonControllerFactory();
ListHabitsRootView getRootView();
ListHabitsScreen getScreen();
ListHabitsSelectionMenu getSelectionMenu();
}

View File

@@ -22,7 +22,7 @@ package org.isoron.uhabits.activities.habits.list;
import android.support.annotation.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.core.models.*;

View File

@@ -23,7 +23,7 @@ import android.support.annotation.*;
import android.view.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.*;
import org.isoron.uhabits.core.ui.screens.habits.list.*;

View File

@@ -19,56 +19,51 @@
package org.isoron.uhabits.activities.habits.list;
import android.content.*;
import android.support.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.core.ui.screens.habits.list.*;
import javax.inject.*;
import dagger.*;
@Module
public class ListHabitsModule extends ActivityModule
class BugReporterProxy extends AndroidBugReporter
implements ListHabitsBehavior.BugReporter
{
public ListHabitsModule(BaseActivity activity)
@Inject
public BugReporterProxy(@AppContext @NonNull Context context)
{
super(activity);
}
@Provides
ListHabitsMenuBehavior.Adapter getAdapter(HabitCardListAdapter adapter)
{
return adapter;
}
@Provides
ListHabitsMenuBehavior.Screen getMenuScreen(ListHabitsScreen screen)
{
return screen;
}
@Provides
ListHabitsBehavior.Screen getScreen(ListHabitsScreen screen)
{
return screen;
}
@Provides
ListHabitsSelectionMenuBehavior.Adapter getSelMenuAdapter(
HabitCardListAdapter adapter)
{
return adapter;
}
@Provides
ListHabitsSelectionMenuBehavior.Screen getSelMenuScreen(ListHabitsScreen screen)
{
return screen;
}
@Provides
ListHabitsBehavior.System getSystem(BaseSystem system)
{
return system;
super(context);
}
}
@Module
public abstract class ListHabitsModule
{
@Binds
abstract ListHabitsMenuBehavior.Adapter getAdapter(HabitCardListAdapter adapter);
@Binds
abstract ListHabitsBehavior.BugReporter getBugReporter(BugReporterProxy proxy);
@Binds
abstract ListHabitsMenuBehavior.Screen getMenuScreen(ListHabitsScreen screen);
@Binds
abstract ListHabitsBehavior.Screen getScreen(ListHabitsScreen screen);
@Binds
abstract ListHabitsSelectionMenuBehavior.Adapter getSelMenuAdapter(
HabitCardListAdapter adapter);
@Binds
abstract ListHabitsSelectionMenuBehavior.Screen getSelMenuScreen(
ListHabitsScreen screen);
@Binds
abstract ListHabitsBehavior.DirFinder getSystem(HabitsDirFinder system);
}

View File

@@ -26,6 +26,7 @@ import android.view.*;
import android.widget.*;
import org.isoron.androidbase.activities.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
@@ -34,13 +35,12 @@ import org.isoron.uhabits.activities.habits.list.views.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.core.ui.screens.habits.list.*;
import org.isoron.uhabits.utils.*;
import javax.inject.*;
import butterknife.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
@ActivityScope
public class ListHabitsRootView extends BaseRootView

View File

@@ -30,7 +30,7 @@ import android.widget.*;
import org.isoron.androidbase.activities.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.dialogs.*;
import org.isoron.uhabits.activities.habits.edit.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
@@ -41,7 +41,6 @@ import org.isoron.uhabits.core.ui.*;
import org.isoron.uhabits.core.ui.callbacks.*;
import org.isoron.uhabits.core.ui.screens.habits.list.*;
import org.isoron.uhabits.intents.*;
import org.isoron.uhabits.utils.*;
import java.io.*;
import java.lang.reflect.*;

View File

@@ -23,7 +23,7 @@ import android.support.annotation.*;
import android.view.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.activities.habits.list.model.*;
import org.isoron.uhabits.core.commands.*;

View File

@@ -27,6 +27,7 @@ import android.text.*;
import android.util.*;
import android.view.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.utils.*;
@@ -34,8 +35,8 @@ import org.isoron.uhabits.utils.*;
import static android.view.View.MeasureSpec.*;
import static org.isoron.uhabits.core.models.Checkmark.*;
import static org.isoron.uhabits.utils.AttributeSetUtils.*;
import static org.isoron.uhabits.utils.InterfaceUtils.getDimension;
import static org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome;
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
import static org.isoron.androidbase.utils.InterfaceUtils.getFontAwesome;
public class CheckmarkButtonView extends View
{
@@ -66,7 +67,7 @@ public class CheckmarkButtonView extends View
if(attrs == null) throw new IllegalStateException();
int paletteColor = getIntAttribute(ctx, attrs, "color", 0);
setColor(ColorUtils.getAndroidTestColor(paletteColor));
setColor(PaletteUtils.getAndroidTestColor(paletteColor));
int value = getIntAttribute(ctx, attrs, "value", 0);
setValue(value);

View File

@@ -25,7 +25,7 @@ import android.util.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
@@ -33,10 +33,11 @@ import org.isoron.uhabits.core.utils.*;
import java.util.*;
import static android.view.View.MeasureSpec.*;
import static org.isoron.uhabits.utils.AttributeSetUtils.*;
import static org.isoron.uhabits.utils.ColorUtils.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static org.isoron.uhabits.utils.AttributeSetUtils.getIntAttribute;
import static org.isoron.uhabits.utils.PaletteUtils.getAndroidTestColor;
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
public class CheckmarkPanelView extends LinearLayout
implements Preferences.Listener
@@ -207,11 +208,11 @@ public class CheckmarkPanelView extends LinearLayout
CheckmarkButtonView buttonView)
{
if (controller == null) return;
if (!(getContext() instanceof ListHabitsActivity)) return;
if (!(getContext() instanceof HabitsActivity)) return;
ListHabitsActivity activity = (ListHabitsActivity) getContext();
HabitsActivity activity = (HabitsActivity) getContext();
CheckmarkButtonControllerFactory buttonControllerFactory = activity
.getListHabitsComponent()
.getActivityComponent()
.getCheckmarkButtonControllerFactory();
CheckmarkButtonController buttonController =

View File

@@ -29,6 +29,7 @@ import android.util.*;
import android.view.*;
import android.widget.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.core.models.*;
@@ -40,7 +41,7 @@ import java.util.*;
import static android.os.Build.VERSION.*;
import static android.os.Build.VERSION_CODES.*;
import static android.view.ViewGroup.LayoutParams.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class HabitCardView extends FrameLayout
implements ModelObservable.Listener
@@ -194,7 +195,7 @@ public class HabitCardView extends FrameLayout
private int getActiveColor(Habit habit)
{
int mediumContrastColor = res.getColor(R.attr.mediumContrastTextColor);
int activeColor = ColorUtils.getColor(context, habit.getColor());
int activeColor = PaletteUtils.getColor(context, habit.getColor());
if (habit.isArchived()) activeColor = mediumContrastColor;
return activeColor;
@@ -237,7 +238,7 @@ public class HabitCardView extends FrameLayout
private void initEditMode()
{
Random rand = new Random();
int color = ColorUtils.getAndroidTestColor(rand.nextInt(10));
int color = PaletteUtils.getAndroidTestColor(rand.nextInt(10));
label.setText(EDIT_MODE_HABITS[rand.nextInt(EDIT_MODE_HABITS.length)]);
label.setTextColor(color);
scoreRing.setColor(color);

View File

@@ -25,15 +25,15 @@ import android.support.annotation.*;
import android.text.*;
import android.util.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class HeaderView extends ScrollableChart
implements Preferences.Listener, MidnightTimer.MidnightListener

View File

@@ -26,6 +26,7 @@ import android.text.*;
import android.util.*;
import android.view.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.utils.*;
@@ -33,8 +34,7 @@ import org.isoron.uhabits.utils.*;
import java.text.*;
import static org.isoron.uhabits.utils.AttributeSetUtils.*;
import static org.isoron.uhabits.utils.ColorUtils.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
public class NumberButtonView extends View
{
@@ -81,7 +81,7 @@ public class NumberButtonView extends View
int value = getIntAttribute(ctx, attrs, "value", 0);
int threshold = getIntAttribute(ctx, attrs, "threshold", 1);
String unit = getAttribute(ctx, attrs, "unit", "min");
setColor(getAndroidTestColor(color));
setColor(PaletteUtils.getAndroidTestColor(color));
setThreshold(threshold);
setValue(value);
setUnit(unit);

View File

@@ -25,7 +25,7 @@ import android.util.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.activities.habits.list.controllers.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
@@ -33,10 +33,12 @@ import org.isoron.uhabits.core.utils.*;
import java.util.*;
import static android.view.View.MeasureSpec.*;
import static org.isoron.uhabits.utils.AttributeSetUtils.*;
import static org.isoron.uhabits.utils.ColorUtils.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static org.isoron.uhabits.utils.AttributeSetUtils.getAttribute;
import static org.isoron.uhabits.utils.AttributeSetUtils.getIntAttribute;
import static org.isoron.uhabits.utils.PaletteUtils.getAndroidTestColor;
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
public class NumberPanelView extends LinearLayout
implements Preferences.Listener
@@ -222,11 +224,11 @@ public class NumberPanelView extends LinearLayout
NumberButtonView buttonView)
{
if (controller == null) return;
if (!(getContext() instanceof ListHabitsActivity)) return;
if (!(getContext() instanceof HabitsActivity)) return;
ListHabitsActivity activity = (ListHabitsActivity) getContext();
HabitsActivity activity = (HabitsActivity) getContext();
NumberButtonControllerFactory buttonControllerFactory = activity
.getListHabitsComponent()
.getActivityComponent()
.getNumberButtonControllerFactory();
NumberButtonController buttonController =

View File

@@ -19,27 +19,18 @@
package org.isoron.uhabits.activities.habits.show;
import android.content.*;
import android.net.*;
import android.os.*;
import android.support.annotation.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.activities.*;
/**
* Activity that allows the user to see more information about a single habit.
* <p>
* Shows all the metadata for the habit, in addition to several charts.
*/
public class ShowHabitActivity extends BaseActivity
public class ShowHabitActivity extends HabitsActivity
{
@Nullable
private HabitList habitList;
@Nullable
private HabitsComponent appComponent;
@Nullable
private ShowHabitScreen screen;
@@ -49,42 +40,21 @@ public class ShowHabitActivity extends BaseActivity
{
super.onCreate(savedInstanceState);
HabitsApplication app = (HabitsApplication) getApplicationContext();
appComponent = app.getComponent();
habitList = appComponent.getHabitList();
Habit habit = getHabitFromIntent();
ShowHabitComponent component = DaggerShowHabitComponent
.builder()
.habitsComponent(app.getComponent())
.showHabitModule(new ShowHabitModule(this, habit))
.build();
screen = component.getScreen();
screen.setMenu(component.getMenu());
screen.setController(component.getController());
component.getRootView().setController(component.getController());
HabitsActivityComponent component = getActivityComponent();
screen = component.getShowHabitScreen();
screen.setMenu(component.getShowHabitMenu());
screen.setController(component.getShowHabitController());
component
.getShowHabitRootView()
.setController(component.getShowHabitController());
setScreen(screen);
}
@Override
protected void onResume()
{
if(screen == null) throw new IllegalStateException();
if (screen == null) throw new IllegalStateException();
super.onResume();
screen.reattachDialogs();
}
@NonNull
private Habit getHabitFromIntent()
{
if(habitList == null) throw new IllegalStateException();
Uri data = getIntent().getData();
Habit habit = habitList.getById(ContentUris.parseId(data));
if (habit == null) throw new RuntimeException("habit not found");
return habit;
}
}

View File

@@ -19,47 +19,20 @@
package org.isoron.uhabits.activities.habits.show;
import android.support.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.activities.*;
import org.isoron.uhabits.core.ui.screens.habits.show.*;
import dagger.*;
@Module
public class ShowHabitModule extends ActivityModule
public abstract class ShowHabitModule
{
private Habit habit;
@Binds
abstract ShowHabitBehavior.Screen getScreen(ShowHabitScreen screen);
public ShowHabitModule(@NonNull BaseActivity activity, @NonNull Habit habit)
{
super(activity);
this.habit = habit;
}
@Binds
abstract ShowHabitMenuBehavior.Screen getMenuScreen(ShowHabitScreen screen);
@Provides
public Habit getHabit()
{
return habit;
}
@Provides
public ShowHabitBehavior.Screen getScreen(ShowHabitScreen screen)
{
return screen;
}
@Provides
public ShowHabitMenuBehavior.Screen getMenuScreen(ShowHabitScreen screen)
{
return screen;
}
@Provides
public ShowHabitMenuBehavior.System getSystem(BaseSystem system)
{
return system;
}
@Binds
abstract ShowHabitMenuBehavior.System getSystem(HabitsDirFinder system);
}

View File

@@ -25,6 +25,7 @@ import android.support.annotation.*;
import android.support.v7.widget.*;
import org.isoron.androidbase.activities.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.habits.show.views.*;
import org.isoron.uhabits.core.models.*;
@@ -90,7 +91,7 @@ public class ShowHabitRootView extends BaseRootView
if (!res.getBoolean(R.attr.useHabitColorAsPrimary))
return super.getToolbarColor();
return ColorUtils.getColor(getContext(), habit.getColor());
return PaletteUtils.getColor(getContext(), habit.getColor());
}
@Override

View File

@@ -22,7 +22,7 @@ package org.isoron.uhabits.activities.habits.show;
import android.support.annotation.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.dialogs.*;
import org.isoron.uhabits.activities.habits.edit.*;
import org.isoron.uhabits.core.models.*;

View File

@@ -23,7 +23,7 @@ import android.support.annotation.*;
import android.view.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.ui.screens.habits.show.*;
import javax.inject.*;

View File

@@ -83,7 +83,7 @@ public class BarCard extends HabitCard
private void initEditMode()
{
int color = ColorUtils.getAndroidTestColor(1);
int color = PaletteUtils.getAndroidTestColor(1);
title.setTextColor(color);
chart.setColor(color);
chart.populateWithRandomData();
@@ -107,7 +107,7 @@ public class BarCard extends HabitCard
@Override
public void onPreExecute()
{
int color = ColorUtils.getColor(getContext(), habit.getColor());
int color = PaletteUtils.getColor(getContext(), habit.getColor());
title.setTextColor(color);
chart.setColor(color);
chart.setTarget(habit.getTargetValue());

View File

@@ -82,7 +82,7 @@ public class FrequencyCard extends HabitCard
private void initEditMode()
{
int color = ColorUtils.getAndroidTestColor(1);
int color = PaletteUtils.getAndroidTestColor(1);
title.setTextColor(color);
chart.setColor(color);
chart.populateWithRandomData();
@@ -102,7 +102,7 @@ public class FrequencyCard extends HabitCard
public void onPreExecute()
{
int paletteColor = getHabit().getColor();
int color = ColorUtils.getColor(getContext(), paletteColor);
int color = PaletteUtils.getColor(getContext(), paletteColor);
title.setTextColor(color);
chart.setColor(color);
}

View File

@@ -96,7 +96,7 @@ public class HistoryCard extends HabitCard
private void initEditMode()
{
int color = ColorUtils.getAndroidTestColor(1);
int color = PaletteUtils.getAndroidTestColor(1);
title.setTextColor(color);
chart.setColor(color);
chart.populateWithRandomData();
@@ -123,7 +123,7 @@ public class HistoryCard extends HabitCard
@Override
public void onPreExecute()
{
int color = ColorUtils.getColor(getContext(), habit.getColor());
int color = PaletteUtils.getColor(getContext(), habit.getColor());
title.setTextColor(color);
chart.setColor(color);
if(habit.isNumerical())

View File

@@ -24,6 +24,7 @@ import android.support.annotation.*;
import android.util.*;
import android.widget.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.views.*;
@@ -105,7 +106,7 @@ public class OverviewCard extends HabitCard
private void initEditMode()
{
color = ColorUtils.getAndroidTestColor(1);
color = PaletteUtils.getAndroidTestColor(1);
cache.todayScore = 0.6f;
cache.lastMonthScore = 0.42f;
cache.lastYearScore = 0.75f;
@@ -182,7 +183,7 @@ public class OverviewCard extends HabitCard
@Override
public void onPreExecute()
{
color = ColorUtils.getColor(getContext(), getHabit().getColor());
color = PaletteUtils.getColor(getContext(), getHabit().getColor());
refreshColors();
}
}

View File

@@ -127,8 +127,8 @@ public class ScoreCard extends HabitCard
if (isInEditMode())
{
spinner.setVisibility(GONE);
title.setTextColor(ColorUtils.getAndroidTestColor(1));
chart.setColor(ColorUtils.getAndroidTestColor(1));
title.setTextColor(PaletteUtils.getAndroidTestColor(1));
chart.setColor(PaletteUtils.getAndroidTestColor(1));
chart.populateWithRandomData();
}
}
@@ -159,7 +159,7 @@ public class ScoreCard extends HabitCard
public void onPreExecute()
{
int color =
ColorUtils.getColor(getContext(), getHabit().getColor());
PaletteUtils.getColor(getContext(), getHabit().getColor());
title.setTextColor(color);
chart.setColor(color);
}

View File

@@ -84,7 +84,7 @@ public class StreakCard extends HabitCard
private void initEditMode()
{
int color = ColorUtils.getAndroidTestColor(1);
int color = PaletteUtils.getAndroidTestColor(1);
title.setTextColor(color);
streakChart.setColor(color);
streakChart.populateWithRandomData();
@@ -111,7 +111,7 @@ public class StreakCard extends HabitCard
public void onPreExecute()
{
int color =
ColorUtils.getColor(getContext(), getHabit().getColor());
PaletteUtils.getColor(getContext(), getHabit().getColor());
title.setTextColor(color);
streakChart.setColor(color);
}

View File

@@ -52,7 +52,7 @@ public class SubtitleCard extends HabitCard
protected void refreshData()
{
Habit habit = getHabit();
int color = ColorUtils.getColor(getContext(), habit.getColor());
int color = PaletteUtils.getColor(getContext(), habit.getColor());
reminderLabel.setText(getResources().getString(R.string.reminder_off));
questionLabel.setVisibility(VISIBLE);
@@ -79,7 +79,7 @@ public class SubtitleCard extends HabitCard
@SuppressLint("SetTextI18n")
private void initEditMode()
{
questionLabel.setTextColor(ColorUtils.getAndroidTestColor(1));
questionLabel.setTextColor(PaletteUtils.getAndroidTestColor(1));
questionLabel.setText("Have you meditated today?");
reminderLabel.setText("08:00");
}

View File

@@ -22,8 +22,8 @@ package org.isoron.uhabits.activities.settings;
import android.os.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.utils.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.R;
/**
* Activity that allows the user to view and modify the app settings.

View File

@@ -21,17 +21,29 @@ package org.isoron.uhabits.activities.settings;
import android.app.backup.*;
import android.content.*;
import android.net.*;
import android.os.*;
import android.provider.*;
import android.support.annotation.*;
import android.support.v7.preference.*;
import org.isoron.androidbase.activities.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.notifications.*;
import static org.isoron.uhabits.activities.habits.list.ListHabitsScreen.*;
import static android.media.RingtoneManager.ACTION_RINGTONE_PICKER;
import static android.media.RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI;
import static android.media.RingtoneManager.EXTRA_RINGTONE_EXISTING_URI;
import static android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT;
import static android.media.RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT;
import static android.media.RingtoneManager.EXTRA_RINGTONE_TYPE;
import static android.media.RingtoneManager.TYPE_NOTIFICATION;
import static org.isoron.uhabits.activities.habits.list.ListHabitsScreen.RESULT_BUG_REPORT;
import static org.isoron.uhabits.activities.habits.list.ListHabitsScreen.RESULT_EXPORT_CSV;
import static org.isoron.uhabits.activities.habits.list.ListHabitsScreen.RESULT_EXPORT_DB;
import static org.isoron.uhabits.activities.habits.list.ListHabitsScreen.RESULT_IMPORT_DATA;
import static org.isoron.uhabits.activities.habits.list.ListHabitsScreen.RESULT_REPAIR_DB;
public class SettingsFragment extends PreferenceFragmentCompat
implements SharedPreferences.OnSharedPreferenceChangeListener
@@ -100,7 +112,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
if (key.equals("reminderSound"))
{
BaseScreen.showRingtonePicker(this, RINGTONE_REQUEST_CODE);
showRingtonePicker();
return true;
}
@@ -142,6 +154,20 @@ public class SettingsFragment extends PreferenceFragmentCompat
});
}
private void showRingtonePicker()
{
Uri existingRingtoneUri = RingtoneManager.getRingtoneUri(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);
startActivityForResult(intent, RINGTONE_REQUEST_CODE);
}
private void updateRingtoneDescription()
{
String ringtoneName = RingtoneManager.getRingtoneName(getContext());

View File

@@ -26,9 +26,9 @@ import android.support.v7.widget.Toolbar;
import android.widget.*;
import org.isoron.androidbase.activities.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.utils.*;
import java.util.*;

View File

@@ -55,7 +55,7 @@ public class FireSettingReceiver extends BroadcastReceiver
ReceiverComponent component =
DaggerFireSettingReceiver_ReceiverComponent
.builder()
.habitsComponent(app.getComponent())
.habitsApplicationComponent(app.getComponent())
.build();
allHabits = app.getComponent().getHabitList();
@@ -100,7 +100,7 @@ public class FireSettingReceiver extends BroadcastReceiver
}
@ReceiverScope
@Component(dependencies = HabitsComponent.class)
@Component(dependencies = HabitsApplicationComponent.class)
interface ReceiverComponent
{
WidgetBehavior getWidgetController();

View File

@@ -29,7 +29,7 @@ import com.activeandroid.*;
import org.isoron.androidbase.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.BuildConfig;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.utils.DatabaseUtils;

View File

@@ -27,7 +27,7 @@ import android.support.v4.app.*;
import android.support.v4.app.NotificationCompat.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
@@ -36,8 +36,8 @@ import org.isoron.uhabits.intents.*;
import javax.inject.*;
import static android.graphics.BitmapFactory.*;
import static org.isoron.uhabits.notifications.RingtoneManager.*;
import static android.graphics.BitmapFactory.decodeResource;
import static org.isoron.uhabits.notifications.RingtoneManager.getRingtoneUri;
@AppScope
public class AndroidNotificationTray implements NotificationTray.SystemTray

View File

@@ -26,23 +26,20 @@ import android.preference.*;
import android.provider.*;
import android.support.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.*;
import javax.inject.*;
import static android.media.RingtoneManager.*;
import static android.media.RingtoneManager.EXTRA_RINGTONE_PICKED_URI;
import static android.media.RingtoneManager.getRingtone;
@AppScope
public class RingtoneManager
{
private Context context;
@Inject
public RingtoneManager(@AppContext @NonNull Context context)
public RingtoneManager()
{
this.context = context;
}
@Nullable
@@ -106,7 +103,6 @@ public class RingtoneManager
}
else
{
String off = context.getResources().getString(R.string.none);
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putString("pref_ringtone_uri", "").apply();

View File

@@ -24,7 +24,7 @@ import android.preference.*;
import android.support.annotation.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.preferences.*;

View File

@@ -36,7 +36,7 @@ public class ConnectivityReceiver extends BroadcastReceiver
if (context == null) return;
if (intent == null) return;
HabitsComponent component =
HabitsApplicationComponent component =
((HabitsApplication) context.getApplicationContext()).getComponent();
NetworkInfo networkInfo =

View File

@@ -73,7 +73,7 @@ public class PebbleReceiver extends PebbleDataReceiver
HabitsApplication app =
(HabitsApplication) context.getApplicationContext();
HabitsComponent component = app.getComponent();
HabitsApplicationComponent component = app.getComponent();
commandRunner = component.getCommandRunner();
taskRunner = component.getTaskRunner();
allHabits = component.getHabitList();

View File

@@ -56,7 +56,7 @@ public class ReminderReceiver extends BroadcastReceiver
ReminderComponent component = DaggerReminderReceiver_ReminderComponent
.builder()
.habitsComponent(app.getComponent())
.habitsApplicationComponent(app.getComponent())
.build();
HabitList habits = app.getComponent().getHabitList();
@@ -105,7 +105,7 @@ public class ReminderReceiver extends BroadcastReceiver
}
@ReceiverScope
@Component(dependencies = HabitsComponent.class)
@Component(dependencies = HabitsApplicationComponent.class)
interface ReminderComponent
{
ReminderController getReminderController();

View File

@@ -57,7 +57,7 @@ public class WidgetReceiver extends BroadcastReceiver
WidgetComponent component = DaggerWidgetReceiver_WidgetComponent
.builder()
.habitsComponent(app.getComponent())
.habitsApplicationComponent(app.getComponent())
.build();
IntentParser parser = app.getComponent().getIntentParser();
@@ -94,7 +94,7 @@ public class WidgetReceiver extends BroadcastReceiver
}
@ReceiverScope
@Component(dependencies = HabitsComponent.class)
@Component(dependencies = HabitsApplicationComponent.class)
interface WidgetComponent
{
WidgetBehavior getWidgetController();

View File

@@ -23,7 +23,7 @@ import android.support.annotation.*;
import android.util.*;
import org.isoron.androidbase.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.BuildConfig;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.commands.*;
import org.isoron.uhabits.core.preferences.*;
@@ -38,7 +38,17 @@ import io.socket.client.*;
import io.socket.client.Socket;
import io.socket.emitter.*;
import static io.socket.client.Socket.*;
import static io.socket.client.Socket.EVENT_CONNECT;
import static io.socket.client.Socket.EVENT_CONNECTING;
import static io.socket.client.Socket.EVENT_CONNECT_ERROR;
import static io.socket.client.Socket.EVENT_CONNECT_TIMEOUT;
import static io.socket.client.Socket.EVENT_DISCONNECT;
import static io.socket.client.Socket.EVENT_PING;
import static io.socket.client.Socket.EVENT_PONG;
import static io.socket.client.Socket.EVENT_RECONNECT;
import static io.socket.client.Socket.EVENT_RECONNECT_ATTEMPT;
import static io.socket.client.Socket.EVENT_RECONNECT_ERROR;
import static io.socket.client.Socket.EVENT_RECONNECT_FAILED;
@AppScope
public class SyncManager implements CommandRunner.Listener
@@ -83,17 +93,17 @@ public class SyncManager implements CommandRunner.Listener
private boolean isListening;
private BaseSystem system;
private SSLContextProvider sslProvider;
@Inject
public SyncManager(@NonNull BaseSystem system,
public SyncManager(@NonNull SSLContextProvider sslProvider,
@NonNull Preferences prefs,
@NonNull CommandRunner commandRunner,
@NonNull CommandParser commandParser)
{
this.system = system;
Log.i("SyncManager", this.toString());
this.sslProvider = sslProvider;
this.prefs = prefs;
this.commandRunner = commandRunner;
this.commandParser = commandParser;
@@ -110,18 +120,6 @@ public class SyncManager implements CommandRunner.Listener
connect(serverURL);
}
private JSONObject toJSONObject(String json)
{
try
{
return new JSONObject(json);
}
catch (JSONException e)
{
throw new RuntimeException(e);
}
}
@Override
public void onCommandExecuted(@NonNull Command command,
@Nullable Long refreshKey)
@@ -141,8 +139,8 @@ public class SyncManager implements CommandRunner.Listener
public void onNetworkStatusChanged(boolean isConnected)
{
if(!isListening) return;
if(isConnected) socket.connect();
if (!isListening) return;
if (isConnected) socket.connect();
else socket.disconnect();
}
@@ -159,7 +157,7 @@ public class SyncManager implements CommandRunner.Listener
public void stopListening()
{
if(!isListening) return;
if (!isListening) return;
commandRunner.removeListener(this);
socket.close();
@@ -170,7 +168,7 @@ public class SyncManager implements CommandRunner.Listener
{
try
{
IO.setDefaultSSLContext(system.getCACertSSLContext());
IO.setDefaultSSLContext(sslProvider.getCACertSSLContext());
socket = IO.socket(serverURL);
logSocketEvent(socket, EVENT_CONNECT, "Connected");
@@ -228,6 +226,18 @@ public class SyncManager implements CommandRunner.Listener
});
}
private JSONObject toJSONObject(String json)
{
try
{
return new JSONObject(json);
}
catch (JSONException e)
{
throw new RuntimeException(e);
}
}
private void updateLastSync(Long timestamp)
{
prefs.setLastSync(timestamp + 1);
@@ -292,7 +302,7 @@ public class SyncManager implements CommandRunner.Listener
public void call(Object... args)
{
readyToEmit = false;
for(Event e : pendingConfirmation) pendingEmit.add(e);
for (Event e : pendingConfirmation) pendingEmit.add(e);
pendingConfirmation.clear();
}
}

View File

@@ -38,13 +38,13 @@ public class ExportDBTask implements Task
@NonNull
private Context context;
private BaseSystem system;
private AndroidDirFinder system;
@NonNull
private final Listener listener;
public ExportDBTask(@Provided @AppContext @NonNull Context context,
@Provided @NonNull BaseSystem system,
@Provided @NonNull AndroidDirFinder system,
@NonNull Listener listener)
{
this.system = system;

View File

@@ -21,10 +21,8 @@ package org.isoron.uhabits.utils;
import android.content.*;
import android.text.format.*;
import android.text.format.DateUtils;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.utils.*;
import java.util.*;

View File

@@ -1,125 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils;
import android.content.*;
import android.graphics.*;
import android.util.*;
public abstract class ColorUtils
{
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 deep orange
Color.parseColor("#F57C00"), // 2 orange
Color.parseColor("#FF8F00"), // 3 amber
Color.parseColor("#F9A825"), // 4 yellow
Color.parseColor("#AFB42B"), // 5 lime
Color.parseColor("#7CB342"), // 6 light green
Color.parseColor("#388E3C"), // 7 green
Color.parseColor("#00897B"), // 8 teal
Color.parseColor("#00ACC1"), // 9 cyan
Color.parseColor("#039BE5"), // 10 light blue
Color.parseColor("#1976D2"), // 11 blue
Color.parseColor("#303F9F"), // 12 indigo
Color.parseColor("#5E35B1"), // 13 deep purple
Color.parseColor("#8E24AA"), // 14 purple
Color.parseColor("#D81B60"), // 15 pink
Color.parseColor("#5D4037"), // 16 brown
Color.parseColor("#303030"), // 17 dark grey
Color.parseColor("#757575"), // 18 grey
Color.parseColor("#aaaaaa") // 19 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;
final byte RED_CHANNEL = 16;
final byte GREEN_CHANNEL = 8;
final byte BLUE_CHANNEL = 0;
final float inverseAmount = 1.0f - amount;
int a = ((int) (((float) (color1 >> ALPHA_CHANNEL & 0xff) * amount) +
((float) (color2 >> ALPHA_CHANNEL & 0xff) *
inverseAmount))) & 0xff;
int r = ((int) (((float) (color1 >> RED_CHANNEL & 0xff) * amount) +
((float) (color2 >> RED_CHANNEL & 0xff) *
inverseAmount))) & 0xff;
int g = ((int) (((float) (color1 >> GREEN_CHANNEL & 0xff) * amount) +
((float) (color2 >> GREEN_CHANNEL & 0xff) *
inverseAmount))) & 0xff;
int b = ((int) (((float) (color1 & 0xff) * amount) +
((float) (color2 & 0xff) * inverseAmount))) & 0xff;
return a << ALPHA_CHANNEL | r << RED_CHANNEL | g << GREEN_CHANNEL |
b << BLUE_CHANNEL;
}
public static int setAlpha(int color, float newAlpha)
{
int intAlpha = (int) (newAlpha * 255);
return Color.argb(intAlpha, Color.red(color), Color.green(color),
Color.blue(color));
}
public static int setMinValue(int color, float newValue)
{
float hsv[] = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] = Math.max(hsv[2], newValue);
return Color.HSVToColor(hsv);
}
}

View File

@@ -1,102 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.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");
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);
}
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) ==
ViewCompat.LAYOUT_DIRECTION_RTL;
}
}

View File

@@ -0,0 +1,67 @@
package org.isoron.uhabits.utils;
import android.content.*;
import android.graphics.*;
import android.util.*;
import org.isoron.androidbase.utils.*;
public class PaletteUtils
{
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 deep orange
Color.parseColor("#F57C00"), // 2 orange
Color.parseColor("#FF8F00"), // 3 amber
Color.parseColor("#F9A825"), // 4 yellow
Color.parseColor("#AFB42B"), // 5 lime
Color.parseColor("#7CB342"), // 6 light green
Color.parseColor("#388E3C"), // 7 green
Color.parseColor("#00897B"), // 8 teal
Color.parseColor("#00ACC1"), // 9 cyan
Color.parseColor("#039BE5"), // 10 light blue
Color.parseColor("#1976D2"), // 11 blue
Color.parseColor("#303F9F"), // 12 indigo
Color.parseColor("#5E35B1"), // 13 deep purple
Color.parseColor("#8E24AA"), // 14 purple
Color.parseColor("#D81B60"), // 15 pink
Color.parseColor("#5D4037"), // 16 brown
Color.parseColor("#303030"), // 17 dark grey
Color.parseColor("#757575"), // 18 grey
Color.parseColor("#aaaaaa") // 19 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];
}
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.utils;
import android.content.*;
import android.content.res.*;
import android.graphics.drawable.*;
import android.support.annotation.*;
import org.isoron.uhabits.*;
public class StyledResources
{
private static Integer fixedTheme;
private final Context context;
public StyledResources(@NonNull Context context)
{
this.context = context;
}
public static void setFixedTheme(Integer theme)
{
fixedTheme = theme;
}
public boolean getBoolean(@AttrRes int attrId)
{
TypedArray ta = getTypedArray(attrId);
boolean bool = ta.getBoolean(0, false);
ta.recycle();
return bool;
}
public int getColor(@AttrRes int attrId)
{
TypedArray ta = getTypedArray(attrId);
int color = ta.getColor(0, 0);
ta.recycle();
return color;
}
public Drawable getDrawable(@AttrRes int attrId)
{
TypedArray ta = getTypedArray(attrId);
Drawable drawable = ta.getDrawable(0);
ta.recycle();
return drawable;
}
public float getFloat(@AttrRes int attrId)
{
TypedArray ta = getTypedArray(attrId);
float f = ta.getFloat(0, 0);
ta.recycle();
return f;
}
public int[] getPalette()
{
int resourceId = getStyleResource(R.attr.palette);
if (resourceId < 0) throw new RuntimeException("resource not found");
return context.getResources().getIntArray(resourceId);
}
int getStyleResource(@AttrRes int attrId)
{
TypedArray ta = getTypedArray(attrId);
int resourceId = ta.getResourceId(0, -1);
ta.recycle();
return resourceId;
}
private TypedArray getTypedArray(@AttrRes int attrId)
{
int[] attrs = new int[]{ attrId };
if (fixedTheme != null)
return context.getTheme().obtainStyledAttributes(fixedTheme, attrs);
return context.obtainStyledAttributes(attrs);
}
}

Some files were not shown because too many files have changed in this diff Show More