diff --git a/app/src/androidTest/java/org/isoron/uhabits/unit/HabitsApplicationTest.java b/app/src/androidTest/java/org/isoron/uhabits/unit/HabitsApplicationTest.java index 1c4f78ad8..72e721d37 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/unit/HabitsApplicationTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/unit/HabitsApplicationTest.java @@ -23,6 +23,7 @@ import android.os.Build; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; +import org.isoron.uhabits.BaseTest; import org.isoron.uhabits.HabitsApplication; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,7 +35,7 @@ import static org.hamcrest.Matchers.containsString; @RunWith(AndroidJUnit4.class) @SmallTest -public class HabitsApplicationTest +public class HabitsApplicationTest extends BaseTest { @Test public void test_getLogcat() throws IOException @@ -45,7 +46,10 @@ public class HabitsApplicationTest String msg = "LOGCAT TEST"; new RuntimeException(msg).printStackTrace(); - String log = HabitsApplication.getLogcat(); + HabitsApplication app = HabitsApplication.getInstance(); + assert(app != null); + + String log = app.getLogcat(); assertThat(log, containsString(msg)); } } diff --git a/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportCSVTaskTest.java b/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportCSVTaskTest.java index f827dddf4..384d94b94 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportCSVTaskTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportCSVTaskTest.java @@ -21,7 +21,6 @@ package org.isoron.uhabits.unit.tasks; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; -import android.widget.ProgressBar; import org.isoron.uhabits.BaseTest; import org.isoron.uhabits.models.Habit; @@ -55,9 +54,8 @@ public class ExportCSVTaskTest extends BaseTest { HabitFixtures.createShortHabit(); List habits = Habit.getAll(true); - ProgressBar bar = new ProgressBar(targetContext); - ExportCSVTask task = new ExportCSVTask(habits, bar); + ExportCSVTask task = new ExportCSVTask(habits, null); task.setListener(new ExportCSVTask.Listener() { @Override diff --git a/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportDBTaskTest.java b/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportDBTaskTest.java index 26269e353..5dca0ec33 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportDBTaskTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ExportDBTaskTest.java @@ -19,11 +19,8 @@ package org.isoron.uhabits.unit.tasks; -import android.content.Context; -import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; -import android.widget.ProgressBar; import org.isoron.uhabits.BaseTest; import org.isoron.uhabits.tasks.ExportDBTask; @@ -52,10 +49,7 @@ public class ExportDBTaskTest extends BaseTest @Test public void testExportCSV() throws Throwable { - Context context = InstrumentationRegistry.getContext(); - - ProgressBar bar = new ProgressBar(context); - ExportDBTask task = new ExportDBTask(bar); + ExportDBTask task = new ExportDBTask(null); task.setListener(new ExportDBTask.Listener() { @Override diff --git a/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ImportDataTaskTest.java b/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ImportDataTaskTest.java index 833675896..8e67cc883 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ImportDataTaskTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/unit/tasks/ImportDataTaskTest.java @@ -22,11 +22,10 @@ package org.isoron.uhabits.unit.tasks; import android.support.annotation.NonNull; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; -import android.widget.ProgressBar; import org.isoron.uhabits.BaseTest; -import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.tasks.ImportDataTask; +import org.isoron.uhabits.utils.FileUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,7 +66,7 @@ public class ImportDataTaskTest extends BaseTest task.setListener(new ImportDataTask.Listener() { @Override - public void onImportFinished(int result) + public void onImportDataFinished(int result) { assertThat(result, equalTo(expectedResult)); } @@ -80,11 +79,9 @@ public class ImportDataTaskTest extends BaseTest @NonNull private ImportDataTask createTask(String assetFilename) throws IOException { - ProgressBar bar = new ProgressBar(targetContext); File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename)); copyAssetToFile(assetFilename, file); - - return new ImportDataTask(file, bar); + return new ImportDataTask(file, null); } @Test diff --git a/app/src/main/java/org/isoron/uhabits/HabitBroadcastReceiver.java b/app/src/main/java/org/isoron/uhabits/HabitBroadcastReceiver.java index c4adf9394..a6fa0a01e 100644 --- a/app/src/main/java/org/isoron/uhabits/HabitBroadcastReceiver.java +++ b/app/src/main/java/org/isoron/uhabits/HabitBroadcastReceiver.java @@ -42,6 +42,7 @@ import org.isoron.uhabits.models.Checkmark; import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.ui.show.ShowHabitActivity; +import org.isoron.uhabits.widgets.WidgetManager; import java.util.Date; @@ -123,10 +124,10 @@ public class HabitBroadcastReceiver extends BroadcastReceiver public static void sendRefreshBroadcast(Context context) { LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context); - Intent refreshIntent = new Intent(MainActivity.ACTION_REFRESH); + Intent refreshIntent = new Intent(HabitsApplication.ACTION_REFRESH); manager.sendBroadcast(refreshIntent); - MainActivity.updateWidgets(context); + WidgetManager.updateWidgets(context); } private void dismissAllHabits() diff --git a/app/src/main/java/org/isoron/uhabits/HabitsApplication.java b/app/src/main/java/org/isoron/uhabits/HabitsApplication.java index 076b30e7d..ab69642b4 100644 --- a/app/src/main/java/org/isoron/uhabits/HabitsApplication.java +++ b/app/src/main/java/org/isoron/uhabits/HabitsApplication.java @@ -21,6 +21,8 @@ package org.isoron.uhabits; import android.app.Application; import android.content.Context; +import android.content.Intent; +import android.net.Uri; import android.os.Environment; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -28,9 +30,12 @@ import android.view.WindowManager; import com.activeandroid.ActiveAndroid; -import org.isoron.uhabits.utils.DateUtils; +import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.utils.DatabaseUtils; +import org.isoron.uhabits.utils.DateUtils; import org.isoron.uhabits.utils.FileUtils; +import org.isoron.uhabits.utils.ReminderUtils; +import org.isoron.uhabits.widgets.WidgetManager; import java.io.BufferedReader; import java.io.File; @@ -39,8 +44,17 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.LinkedList; -public class HabitsApplication extends Application +public class HabitsApplication extends Application implements MainController.System { + public static final String ACTION_REFRESH = "org.isoron.uhabits.ACTION_REFRESH"; + public static final int RESULT_IMPORT_DATA = 1; + public static final int RESULT_EXPORT_CSV = 2; + public static final int RESULT_EXPORT_DB = 3; + public static final int RESULT_BUG_REPORT = 4; + + @Nullable + private static HabitsApplication application; + @Nullable private static Context context; @@ -64,11 +78,18 @@ public class HabitsApplication extends Application return context; } + @Nullable + public static HabitsApplication getInstance() + { + return application; + } + @Override public void onCreate() { super.onCreate(); HabitsApplication.context = this; + HabitsApplication.application = this; if (isTestMode()) { @@ -87,7 +108,7 @@ public class HabitsApplication extends Application super.onTerminate(); } - public static String getLogcat() throws IOException + public String getLogcat() throws IOException { int maxNLines = 250; StringBuilder builder = new StringBuilder(); @@ -116,7 +137,7 @@ public class HabitsApplication extends Application return builder.toString(); } - public static String getDeviceInfo() + public String getDeviceInfo() { if(context == null) return ""; @@ -125,7 +146,7 @@ public class HabitsApplication extends Application b.append(String.format("App Version Name: %s\n", BuildConfig.VERSION_NAME)); b.append(String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE)); - b.append(String.format("OS Version: %s (%s)\n", System.getProperty("os.version"), + b.append(String.format("OS Version: %s (%s)\n", java.lang.System.getProperty("os.version"), android.os.Build.VERSION.INCREMENTAL)); b.append(String.format("OS API Level: %s\n", android.os.Build.VERSION.SDK)); b.append(String.format("Device: %s\n", android.os.Build.DEVICE)); @@ -141,7 +162,7 @@ public class HabitsApplication extends Application } @NonNull - public static File dumpBugReportToFile() throws IOException + public File dumpBugReportToFile() throws IOException { String date = DateUtils.getBackupDateFormat().format(DateUtils.getLocalTime()); @@ -151,17 +172,63 @@ public class HabitsApplication extends Application File logFile = new File(String.format("%s/Log %s.txt", dir.getPath(), date)); FileWriter output = new FileWriter(logFile); - output.write(generateBugReport()); + output.write(getBugReport()); output.close(); return logFile; } @NonNull - public static String generateBugReport() throws IOException + public String getBugReport() throws IOException { String logcat = getLogcat(); String deviceInfo = getDeviceInfo(); return deviceInfo + "\n" + logcat; } + + public void sendFile(@NonNull String archiveFilename) + { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_SEND); + intent.setType("application/zip"); + intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(archiveFilename))); + startActivity(intent); + } + + public void sendEmail(String to, String subject, String content) + { + 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); + startActivity(intent); + } + + public void scheduleReminders() + { + new BaseTask() + { + + @Override + protected void doInBackground() + { + ReminderUtils.createReminderAlarms(getContext()); + } + }.execute(); + } + + public void updateWidgets() + { + new BaseTask() + { + + @Override + protected void doInBackground() + { + WidgetManager.updateWidgets(getContext()); + } + }.execute(); + } } diff --git a/app/src/main/java/org/isoron/uhabits/MainActivity.java b/app/src/main/java/org/isoron/uhabits/MainActivity.java index 6703eb40c..dbf4b4f2b 100644 --- a/app/src/main/java/org/isoron/uhabits/MainActivity.java +++ b/app/src/main/java/org/isoron/uhabits/MainActivity.java @@ -19,86 +19,62 @@ package org.isoron.uhabits; -import android.appwidget.AppWidgetManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; import android.graphics.drawable.ColorDrawable; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.preference.PreferenceManager; -import android.support.annotation.NonNull; -import android.support.v4.content.LocalBroadcastManager; +import android.support.v4.app.FragmentManager; import android.support.v7.app.ActionBar; import android.view.Menu; import android.view.MenuItem; -import org.isoron.uhabits.ui.list.ListHabitsFragment; -import org.isoron.uhabits.utils.DateUtils; -import org.isoron.uhabits.utils.ReminderUtils; -import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.models.Checkmark; import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.tasks.BaseTask; +import org.isoron.uhabits.tasks.ProgressBar; import org.isoron.uhabits.ui.AboutActivity; +import org.isoron.uhabits.ui.AndroidProgressBar; import org.isoron.uhabits.ui.BaseActivity; import org.isoron.uhabits.ui.IntroActivity; +import org.isoron.uhabits.ui.list.ListHabitsFragment; +import org.isoron.uhabits.ui.settings.FilePickerDialog; import org.isoron.uhabits.ui.settings.SettingsActivity; import org.isoron.uhabits.ui.show.ShowHabitActivity; -import org.isoron.uhabits.widgets.CheckmarkWidgetProvider; -import org.isoron.uhabits.widgets.FrequencyWidgetProvider; -import org.isoron.uhabits.widgets.HistoryWidgetProvider; -import org.isoron.uhabits.widgets.ScoreWidgetProvider; -import org.isoron.uhabits.widgets.StreakWidgetProvider; +import org.isoron.uhabits.utils.FileUtils; +import org.isoron.uhabits.utils.InterfaceUtils; +import org.isoron.uhabits.widgets.WidgetManager; -import java.io.IOException; +import java.io.File; public class MainActivity extends BaseActivity - implements ListHabitsFragment.OnHabitClickListener + implements ListHabitsFragment.OnHabitClickListener, MainController.Screen { + private MainController controller; private ListHabitsFragment listHabitsFragment; - private SharedPreferences prefs; - private BroadcastReceiver receiver; - private LocalBroadcastManager localBroadcastManager; - - public static final String ACTION_REFRESH = "org.isoron.uhabits.ACTION_REFRESH"; - - public static final int RESULT_IMPORT_DATA = 1; - public static final int RESULT_EXPORT_CSV = 2; - public static final int RESULT_EXPORT_DB = 3; - public static final int RESULT_BUG_REPORT = 4; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.list_habits_activity); - setupSupportActionBar(false); - prefs = PreferenceManager.getDefaultSharedPreferences(this); - listHabitsFragment = - (ListHabitsFragment) getSupportFragmentManager().findFragmentById(R.id.fragment1); - - receiver = new Receiver(); - localBroadcastManager = LocalBroadcastManager.getInstance(this); - localBroadcastManager.registerReceiver(receiver, new IntentFilter(ACTION_REFRESH)); + FragmentManager fragmentManager = getSupportFragmentManager(); + listHabitsFragment = (ListHabitsFragment) fragmentManager.findFragmentById(R.id.fragment1); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - onPreLollipopStartup(); + onPreLollipopCreate(); - onStartup(); + controller = new MainController(); + controller.setScreen(this); + controller.setSystem((HabitsApplication) getApplication()); + controller.onStartup(); } - private void onPreLollipopStartup() + private void onPreLollipopCreate() { ActionBar actionBar = getSupportActionBar(); if(actionBar == null) return; @@ -108,50 +84,13 @@ public class MainActivity extends BaseActivity actionBar.setBackgroundDrawable(new ColorDrawable(color)); } - private void onStartup() - { - PreferenceManager.setDefaultValues(this, R.xml.preferences, false); - InterfaceUtils.incrementLaunchCount(this); - InterfaceUtils.updateLastAppVersion(this); - showTutorial(); - - new AsyncTask() { - @Override - protected Void doInBackground(Void... params) - { - ReminderUtils.createReminderAlarms(MainActivity.this); - updateWidgets(MainActivity.this); - return null; - } - }.execute(); - - } - - private void showTutorial() - { - Boolean firstRun = prefs.getBoolean("pref_first_run", true); - - if (firstRun) - { - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean("pref_first_run", false); - editor.putLong("last_hint_timestamp", DateUtils.getStartOfToday()).apply(); - editor.apply(); - - Intent intent = new Intent(this, IntroActivity.class); - this.startActivity(intent); - } - } - @Override public boolean onCreateOptionsMenu(Menu menu) { menu.clear(); getMenuInflater().inflate(R.menu.list_habits_menu, menu); - MenuItem nightModeItem = menu.findItem(R.id.action_night_mode); nightModeItem.setChecked(InterfaceUtils.isNightMode()); - return true; } @@ -161,122 +100,100 @@ public class MainActivity extends BaseActivity switch (item.getItemId()) { case R.id.action_night_mode: - { - if(InterfaceUtils.isNightMode()) - InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_LIGHT); - else - InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_DARK); - - refreshTheme(); + toggleNightMode(); return true; - } case R.id.action_settings: - { - Intent intent = new Intent(this, SettingsActivity.class); - startActivityForResult(intent, 0); + showSettingsScreen(); return true; - } case R.id.action_about: - { - Intent intent = new Intent(this, AboutActivity.class); - startActivity(intent); + showAboutScreen(); return true; - } case R.id.action_faq: - { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(getString(R.string.helpURL))); - startActivity(intent); + showFAQScreen(); return true; - } default: return super.onOptionsItemSelected(item); } } - private void refreshTheme() - { - new Handler().postDelayed(new Runnable() - { - @Override - public void run() - { - Intent intent = new Intent(MainActivity.this, MainActivity.class); - - MainActivity.this.finish(); - overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); - startActivity(intent); - - } - }, 500); // Let the menu disappear first - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (resultCode) { - case RESULT_IMPORT_DATA: - listHabitsFragment.showImportDialog(); + case HabitsApplication.RESULT_IMPORT_DATA: + showImportScreen(); break; - case RESULT_EXPORT_CSV: - listHabitsFragment.exportAllHabits(); + case HabitsApplication.RESULT_EXPORT_CSV: + controller.exportCSV(); break; - case RESULT_EXPORT_DB: - listHabitsFragment.exportDB(); + case HabitsApplication.RESULT_EXPORT_DB: + controller.exportDB(); break; - case RESULT_BUG_REPORT: - generateBugReport(); + case HabitsApplication.RESULT_BUG_REPORT: + controller.sendBugReport(); break; } } - private void generateBugReport() + private void showFAQScreen() { - try - { - HabitsApplication.dumpBugReportToFile(); - } - catch (IOException e) - { - // ignored - } + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.setData(Uri.parse(getString(R.string.helpURL))); + startActivity(intent); + } - try - { - String log = "---------- BUG REPORT BEGINS ----------\n"; - log += HabitsApplication.generateBugReport(); - log += "---------- BUG REPORT ENDS ------------\n"; - - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.setType("message/rfc822"); - intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "dev@loophabits.org" }); - intent.putExtra(Intent.EXTRA_SUBJECT, "Bug Report - Loop Habit Tracker"); - intent.putExtra(Intent.EXTRA_TEXT, log); - startActivity(intent); - } - catch (IOException e) + private void showAboutScreen() + { + Intent intent = new Intent(this, AboutActivity.class); + startActivity(intent); + } + + private void showSettingsScreen() + { + Intent intent = new Intent(this, SettingsActivity.class); + startActivityForResult(intent, 0); + } + + private void toggleNightMode() + { + if(InterfaceUtils.isNightMode()) + InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_LIGHT); + else + InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_DARK); + + refreshTheme(); + } + + private void refreshTheme() + { + new Handler().postDelayed(new Runnable() { - e.printStackTrace(); - showToast(R.string.bug_report_failed); - } + @Override + public void run() + { + Intent intent = new Intent(MainActivity.this, MainActivity.class); + + MainActivity.this.finish(); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); + startActivity(intent); + + } + }, 500); // Let the menu disappear first } @Override public void onHabitClicked(Habit habit) { - Intent intent = new Intent(this, ShowHabitActivity.class); - intent.setData(Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId())); - startActivity(intent); + showHabitScreen(habit); } @Override @@ -290,7 +207,7 @@ public class MainActivity extends BaseActivity protected void doInBackground() { dismissNotifications(MainActivity.this); - updateWidgets(MainActivity.this); + WidgetManager.updateWidgets(MainActivity.this); } }.execute(); } @@ -304,48 +221,49 @@ public class MainActivity extends BaseActivity } } - public static void updateWidgets(Context context) - { - updateWidgets(context, CheckmarkWidgetProvider.class); - updateWidgets(context, HistoryWidgetProvider.class); - updateWidgets(context, ScoreWidgetProvider.class); - updateWidgets(context, StreakWidgetProvider.class); - updateWidgets(context, FrequencyWidgetProvider.class); - } - - private static void updateWidgets(Context context, Class providerClass) + private void showHabitScreen(Habit habit) { - ComponentName provider = new ComponentName(context, providerClass); - Intent intent = new Intent(context, providerClass); - intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - int ids[] = AppWidgetManager.getInstance(context).getAppWidgetIds(provider); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids); - context.sendBroadcast(intent); + Intent intent = new Intent(this, ShowHabitActivity.class); + intent.setData(Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId())); + startActivity(intent); } - @Override - protected void onDestroy() + public void showIntroScreen() { - localBroadcastManager.unregisterReceiver(receiver); - super.onDestroy(); + Intent intent = new Intent(this, IntroActivity.class); + this.startActivity(intent); } - class Receiver extends BroadcastReceiver + public void showImportScreen() { - @Override - public void onReceive(Context context, Intent intent) + File dir = FileUtils.getFilesDir(null); + if(dir == null) { - listHabitsFragment.onPostExecuteCommand(null); + showMessage(R.string.could_not_import); + return; } + + FilePickerDialog picker = new FilePickerDialog(this, dir); + picker.setListener(new FilePickerDialog.OnFileSelectedListener() + { + @Override + public void onFileSelected(File file) + { + controller.importData(file); + } + }); + picker.show(); } @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) + public void refresh(Long refreshKey) { - if (grantResults.length <= 0) return; - if (grantResults[0] != PackageManager.PERMISSION_GRANTED) return; + listHabitsFragment.loader.updateAllHabits(true); + } - listHabitsFragment.showImportDialog(); + @Override + public ProgressBar getProgressBar() + { + return new AndroidProgressBar(listHabitsFragment.progressBar); } } diff --git a/app/src/main/java/org/isoron/uhabits/MainController.java b/app/src/main/java/org/isoron/uhabits/MainController.java new file mode 100644 index 000000000..d857d012f --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/MainController.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits; + +import org.isoron.uhabits.models.Habit; +import org.isoron.uhabits.tasks.ExportCSVTask; +import org.isoron.uhabits.tasks.ExportDBTask; +import org.isoron.uhabits.tasks.ImportDataTask; +import org.isoron.uhabits.tasks.ProgressBar; +import org.isoron.uhabits.utils.DateUtils; + +import java.io.File; +import java.io.IOException; + +public class MainController implements ImportDataTask.Listener, ExportCSVTask.Listener, + ExportDBTask.Listener +{ + public interface Screen + { + void showIntroScreen(); + + void showMessage(Integer stringId); + + void refresh(Long refreshKey); + + ProgressBar getProgressBar(); + } + + public interface System + { + void sendFile(String filename); + + void sendEmail(String to, String subject, String content); + + void scheduleReminders(); + + void updateWidgets(); + + File dumpBugReportToFile() throws IOException; + + String getBugReport() throws IOException; + } + + System sys; + Screen screen; + Preferences prefs; + + public MainController() + { + prefs = Preferences.getInstance(); + } + + public void setScreen(Screen screen) + { + this.screen = screen; + } + + public void setSystem(System sys) + { + this.sys = sys; + } + + public void onStartup() + { + prefs.initialize(); + prefs.incrementLaunchCount(); + prefs.updateLastAppVersion(); + if(prefs.isFirstRun()) onFirstRun(); + + sys.updateWidgets(); + sys.scheduleReminders(); + } + + private void onFirstRun() + { + prefs.setFirstRun(false); + prefs.setLastHintTimestamp(DateUtils.getStartOfToday()); + screen.showIntroScreen(); + } + + public void importData(File file) + { + ImportDataTask task = new ImportDataTask(file, screen.getProgressBar()); + task.setListener(this); + task.execute(); + } + + @Override + public void onImportDataFinished(int result) + { + switch (result) + { + case ImportDataTask.SUCCESS: + screen.refresh(null); + screen.showMessage(R.string.habits_imported); + break; + + case ImportDataTask.NOT_RECOGNIZED: + screen.showMessage(R.string.file_not_recognized); + break; + + default: + screen.showMessage(R.string.could_not_import); + break; + } + } + + public void exportCSV() + { + ExportCSVTask task = new ExportCSVTask(Habit.getAll(true), screen.getProgressBar()); + task.setListener(this); + task.execute(); + } + + @Override + public void onExportCSVFinished(String filename) + { + if(filename != null) sys.sendFile(filename); + else screen.showMessage(R.string.could_not_export); + } + + public void exportDB() + { + ExportDBTask task = new ExportDBTask(screen.getProgressBar()); + task.setListener(this); + task.execute(); + } + + @Override + public void onExportDBFinished(String filename) + { + if(filename != null) sys.sendFile(filename); + else screen.showMessage(R.string.could_not_export); + } + + public void sendBugReport() + { + try + { + sys.dumpBugReportToFile(); + } + catch (IOException e) + { + // ignored + } + + try + { + String log = "---------- BUG REPORT BEGINS ----------\n"; + log += sys.getBugReport(); + log += "---------- BUG REPORT ENDS ------------\n"; + String to = "dev@loophabits.org"; + String subject = "Bug Report - Loop Habit Tracker"; + sys.sendEmail(log, to, subject); + } + catch (IOException e) + { + e.printStackTrace(); + screen.showMessage(R.string.bug_report_failed); + } + } +} diff --git a/app/src/main/java/org/isoron/uhabits/Preferences.java b/app/src/main/java/org/isoron/uhabits/Preferences.java new file mode 100644 index 000000000..f7b8f4f26 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/Preferences.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +public class Preferences +{ + private static Preferences singleton; + + private Context context; + private SharedPreferences prefs; + + private Preferences() + { + this.context = HabitsApplication.getContext(); + prefs = PreferenceManager.getDefaultSharedPreferences(context); + } + + public static Preferences getInstance() + { + if(singleton == null) singleton = new Preferences(); + return singleton; + } + + public void initialize() + { + PreferenceManager.setDefaultValues(context, R.xml.preferences, false); + } + + + public void incrementLaunchCount() + { + int count = prefs.getInt("launch_count", 0); + prefs.edit().putInt("launch_count", count + 1).apply(); + } + + public void updateLastAppVersion() + { + prefs.edit().putInt("last_version", BuildConfig.VERSION_CODE).apply(); + } + + public boolean isFirstRun() + { + return prefs.getBoolean("pref_first_run", true); + } + + public void setFirstRun(boolean isFirstRun) + { + prefs.edit().putBoolean("pref_first_run", isFirstRun).apply(); + } + + public void setLastHintTimestamp(long timestamp) + { + prefs.edit().putLong("last_hint_timestamp", timestamp).apply(); + } + + public boolean isShortToggleEnabled() + { + return prefs.getBoolean("pref_short_toggle", false); + } +} diff --git a/app/src/main/java/org/isoron/uhabits/tasks/ExportCSVTask.java b/app/src/main/java/org/isoron/uhabits/tasks/ExportCSVTask.java index ccea2b14b..1eb23a12a 100644 --- a/app/src/main/java/org/isoron/uhabits/tasks/ExportCSVTask.java +++ b/app/src/main/java/org/isoron/uhabits/tasks/ExportCSVTask.java @@ -20,12 +20,10 @@ package org.isoron.uhabits.tasks; import android.support.annotation.Nullable; -import android.view.View; -import android.widget.ProgressBar; -import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.io.HabitsCSVExporter; import org.isoron.uhabits.models.Habit; +import org.isoron.uhabits.utils.FileUtils; import java.io.File; import java.io.IOException; @@ -58,12 +56,7 @@ public class ExportCSVTask extends BaseTask protected void onPreExecute() { super.onPreExecute(); - - if(progressBar != null) - { - progressBar.setIndeterminate(true); - progressBar.setVisibility(View.VISIBLE); - } + if(progressBar != null) progressBar.show(); } @Override @@ -72,9 +65,7 @@ public class ExportCSVTask extends BaseTask if(listener != null) listener.onExportCSVFinished(archiveFilename); - if(progressBar != null) - progressBar.setVisibility(View.GONE); - + if(progressBar != null) progressBar.hide(); super.onPostExecute(null); } diff --git a/app/src/main/java/org/isoron/uhabits/tasks/ExportDBTask.java b/app/src/main/java/org/isoron/uhabits/tasks/ExportDBTask.java index 60b3cba19..541d3519f 100644 --- a/app/src/main/java/org/isoron/uhabits/tasks/ExportDBTask.java +++ b/app/src/main/java/org/isoron/uhabits/tasks/ExportDBTask.java @@ -20,8 +20,6 @@ package org.isoron.uhabits.tasks; import android.support.annotation.Nullable; -import android.view.View; -import android.widget.ProgressBar; import org.isoron.uhabits.utils.DatabaseUtils; import org.isoron.uhabits.utils.FileUtils; @@ -54,23 +52,14 @@ public class ExportDBTask extends BaseTask protected void onPreExecute() { super.onPreExecute(); - - if(progressBar != null) - { - progressBar.setIndeterminate(true); - progressBar.setVisibility(View.VISIBLE); - } + if(progressBar != null) progressBar.show(); } @Override protected void onPostExecute(Void aVoid) { - if(listener != null) - listener.onExportDBFinished(filename); - - if(progressBar != null) - progressBar.setVisibility(View.GONE); - + if(listener != null) listener.onExportDBFinished(filename); + if(progressBar != null) progressBar.hide(); super.onPostExecute(null); } diff --git a/app/src/main/java/org/isoron/uhabits/tasks/ImportDataTask.java b/app/src/main/java/org/isoron/uhabits/tasks/ImportDataTask.java index 477f1f51b..cdc6c538a 100644 --- a/app/src/main/java/org/isoron/uhabits/tasks/ImportDataTask.java +++ b/app/src/main/java/org/isoron/uhabits/tasks/ImportDataTask.java @@ -21,8 +21,6 @@ package org.isoron.uhabits.tasks; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.view.View; -import android.widget.ProgressBar; import org.isoron.uhabits.io.GenericImporter; @@ -36,7 +34,7 @@ public class ImportDataTask extends BaseTask public interface Listener { - void onImportFinished(int result); + void onImportDataFinished(int result); } @Nullable @@ -66,21 +64,14 @@ public class ImportDataTask extends BaseTask { super.onPreExecute(); - if(progressBar != null) - { - progressBar.setIndeterminate(true); - progressBar.setVisibility(View.VISIBLE); - } + if(progressBar != null) progressBar.show(); } @Override protected void onPostExecute(Void aVoid) { - if(progressBar != null) - progressBar.setVisibility(View.GONE); - - if(listener != null) listener.onImportFinished(result); - + if(progressBar != null) progressBar.hide(); + if(listener != null) listener.onImportDataFinished(result); super.onPostExecute(null); } diff --git a/app/src/main/java/org/isoron/uhabits/tasks/ProgressBar.java b/app/src/main/java/org/isoron/uhabits/tasks/ProgressBar.java new file mode 100644 index 000000000..17c3ebbf1 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/tasks/ProgressBar.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.tasks; + +public interface ProgressBar +{ + void show(); + void hide(); +} diff --git a/app/src/main/java/org/isoron/uhabits/ui/AndroidProgressBar.java b/app/src/main/java/org/isoron/uhabits/ui/AndroidProgressBar.java new file mode 100644 index 000000000..c366bf88c --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/ui/AndroidProgressBar.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.ui; + +import android.view.View; + +import org.isoron.uhabits.tasks.ProgressBar; + +public class AndroidProgressBar implements ProgressBar +{ + private final android.widget.ProgressBar progressBar; + + public AndroidProgressBar(android.widget.ProgressBar progressBar) + { + this.progressBar = progressBar; + } + + @Override + public void show() + { + progressBar.setIndeterminate(true); + progressBar.setVisibility(View.VISIBLE); + } + + @Override + public void hide() + { + progressBar.setVisibility(View.GONE); + } +} diff --git a/app/src/main/java/org/isoron/uhabits/ui/BaseActivity.java b/app/src/main/java/org/isoron/uhabits/ui/BaseActivity.java index f41b6eb87..d8d6f26e9 100644 --- a/app/src/main/java/org/isoron/uhabits/ui/BaseActivity.java +++ b/app/src/main/java/org/isoron/uhabits/ui/BaseActivity.java @@ -72,28 +72,28 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U { if (undoList.isEmpty()) { - showToast(R.string.toast_nothing_to_undo); + showMessage(R.string.toast_nothing_to_undo); return; } Command last = undoList.pop(); redoList.push(last); last.undo(); - showToast(last.getUndoStringId()); + showMessage(last.getUndoStringId()); } protected void redo() { if (redoList.isEmpty()) { - showToast(R.string.toast_nothing_to_redo); + showMessage(R.string.toast_nothing_to_redo); return; } Command last = redoList.pop(); executeCommand(last, false, null); } - public void showToast(Integer stringId) + public void showMessage(Integer stringId) { if (stringId == null) return; if (toast == null) toast = Toast.makeText(this, stringId, Toast.LENGTH_SHORT); @@ -126,7 +126,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U }.execute(); - showToast(command.getExecuteStringId()); + showMessage(command.getExecuteStringId()); } protected void setupSupportActionBar(boolean homeButtonEnabled) @@ -156,7 +156,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U try { ex.printStackTrace(); - HabitsApplication.dumpBugReportToFile(); + ((HabitsApplication) getApplication()).dumpBugReportToFile(); } catch(Exception e) { diff --git a/app/src/main/java/org/isoron/uhabits/ui/list/ListHabitsController.java b/app/src/main/java/org/isoron/uhabits/ui/list/ListHabitsController.java new file mode 100644 index 000000000..dd56c4622 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/ui/list/ListHabitsController.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.ui.list; + +public class ListHabitsController +{ + public interface Screen + { + + } + + private Screen screen; + + + public void setScreen(Screen screen) + { + this.screen = screen; + } + +} diff --git a/app/src/main/java/org/isoron/uhabits/ui/list/ListHabitsFragment.java b/app/src/main/java/org/isoron/uhabits/ui/list/ListHabitsFragment.java index 4b9bf23d1..111246108 100644 --- a/app/src/main/java/org/isoron/uhabits/ui/list/ListHabitsFragment.java +++ b/app/src/main/java/org/isoron/uhabits/ui/list/ListHabitsFragment.java @@ -20,16 +20,9 @@ package org.isoron.uhabits.ui.list; import android.app.Activity; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.view.ActionMode; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.Menu; @@ -40,7 +33,6 @@ import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import android.widget.LinearLayout; import android.widget.ProgressBar; @@ -48,80 +40,96 @@ import android.widget.TextView; import com.mobeta.android.dslv.DragSortController; import com.mobeta.android.dslv.DragSortListView; -import com.mobeta.android.dslv.DragSortListView.DropListener; -import org.isoron.uhabits.ui.BaseActivity; +import org.isoron.uhabits.Preferences; import org.isoron.uhabits.R; import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.commands.ToggleRepetitionCommand; +import org.isoron.uhabits.models.Habit; +import org.isoron.uhabits.ui.BaseActivity; +import org.isoron.uhabits.ui.HintManager; import org.isoron.uhabits.ui.edit.EditHabitDialogFragment; -import org.isoron.uhabits.ui.settings.FilePickerDialog; -import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.utils.DateUtils; -import org.isoron.uhabits.ui.HintManager; -import org.isoron.uhabits.utils.ReminderUtils; import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils.OnSavedListener; -import org.isoron.uhabits.models.Habit; -import org.isoron.uhabits.tasks.ExportCSVTask; -import org.isoron.uhabits.tasks.ExportDBTask; -import org.isoron.uhabits.tasks.ImportDataTask; +import org.isoron.uhabits.utils.ReminderUtils; -import java.io.File; import java.util.Date; import java.util.LinkedList; import java.util.List; public class ListHabitsFragment extends Fragment - implements OnSavedListener, OnItemClickListener, OnLongClickListener, DropListener, + implements OnSavedListener, OnItemClickListener, OnLongClickListener, OnClickListener, ListHabitsLoader.Listener, AdapterView.OnItemLongClickListener, - HabitSelectionCallback.Listener, ImportDataTask.Listener, ExportCSVTask.Listener, - ExportDBTask.Listener + HabitSelectionCallback.Listener, ListHabitsController.Screen { long lastLongClick = 0; - private boolean isShortToggleEnabled; private boolean showArchived; private ActionMode actionMode; private ListHabitsAdapter adapter; - private ListHabitsLoader loader; + public ListHabitsLoader loader; private HintManager hintManager; private ListHabitsHelper helper; private List selectedPositions; private OnHabitClickListener habitClickListener; private BaseActivity activity; - private SharedPreferences prefs; private DragSortListView listView; private LinearLayout llButtonsHeader; - private ProgressBar progressBar; + public ProgressBar progressBar; private View llEmpty; + private ListHabitsController controller; + private Preferences prefs; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.list_habits_fragment, container, false); + View llHint = view.findViewById(R.id.llHint); - TextView tvStarEmpty = (TextView) view.findViewById(R.id.tvStarEmpty); - listView = (DragSortListView) view.findViewById(R.id.listView); llButtonsHeader = (LinearLayout) view.findViewById(R.id.llButtonsHeader); llEmpty = view.findViewById(R.id.llEmpty); - progressBar = (ProgressBar) view.findViewById(R.id.progressBar); progressBar.setVisibility(View.GONE); selectedPositions = new LinkedList<>(); loader = new ListHabitsLoader(); helper = new ListHabitsHelper(activity, loader); + hintManager = new HintManager(activity, llHint); loader.setListener(this); loader.setCheckmarkCount(helper.getButtonCount()); llHint.setOnClickListener(this); + + TextView tvStarEmpty = (TextView) view.findViewById(R.id.tvStarEmpty); tvStarEmpty.setTypeface(InterfaceUtils.getFontAwesome(activity)); + createListView(view); + + if(savedInstanceState != null) + { + EditHabitDialogFragment frag = (EditHabitDialogFragment) getFragmentManager() + .findFragmentByTag("editHabit"); + if(frag != null) frag.setOnSavedListener(this); + } + + loader.updateAllHabits(true); + + controller = new ListHabitsController(); + controller.setScreen(this); + prefs = Preferences.getInstance(); + + setHasOptionsMenu(true); + return view; + } + + private void createListView(View view) + { adapter = new ListHabitsAdapter(getActivity(), loader); adapter.setSelectedPositions(selectedPositions); adapter.setOnCheckmarkClickListener(this); @@ -130,26 +138,15 @@ public class ListHabitsFragment extends Fragment DragSortListView.DragListener dragListener = new HabitsDragListener(); DragSortController dragSortController = new HabitsDragSortController(); + listView = (DragSortListView) view.findViewById(R.id.listView); listView.setAdapter(adapter); listView.setOnItemClickListener(this); listView.setOnItemLongClickListener(this); - listView.setDropListener(this); + listView.setDropListener(new HabitsDropListener()); listView.setDragListener(dragListener); listView.setFloatViewManager(dragSortController); listView.setDragEnabled(true); listView.setLongClickable(true); - - if(savedInstanceState != null) - { - EditHabitDialogFragment frag = (EditHabitDialogFragment) getFragmentManager() - .findFragmentByTag("editHabit"); - if(frag != null) frag.setOnSavedListener(this); - } - - loader.updateAllHabits(true); - - setHasOptionsMenu(true); - return view; } @Override @@ -158,9 +155,7 @@ public class ListHabitsFragment extends Fragment { super.onAttach(activity); this.activity = (BaseActivity) activity; - habitClickListener = (OnHabitClickListener) activity; - prefs = PreferenceManager.getDefaultSharedPreferences(activity); } @Override @@ -175,9 +170,7 @@ public class ListHabitsFragment extends Fragment helper.updateEmptyMessage(llEmpty); helper.updateHeader(llButtonsHeader); hintManager.showHintIfAppropriate(); - adapter.notifyDataSetChanged(); - isShortToggleEnabled = prefs.getBoolean("pref_short_toggle", false); } @Override @@ -192,51 +185,43 @@ public class ListHabitsFragment extends Fragment { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.list_habits_options, menu); - MenuItem showArchivedItem = menu.findItem(R.id.action_show_archived); showArchivedItem.setChecked(showArchived); } - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) - { - super.onCreateContextMenu(menu, view, menuInfo); - getActivity().getMenuInflater().inflate(R.menu.list_habits_context, menu); - - AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; - final Habit habit = loader.habits.get(info.id); - - if (habit.isArchived()) menu.findItem(R.id.action_archive_habit).setVisible(false); - else menu.findItem(R.id.action_unarchive_habit).setVisible(false); - } - @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_add: - { - EditHabitDialogFragment frag = EditHabitDialogFragment.createHabitFragment(); - frag.setOnSavedListener(this); - frag.show(getFragmentManager(), "editHabit"); + showCreateHabitScreen(); return true; - } case R.id.action_show_archived: - { - showArchived = !showArchived; - loader.setIncludeArchived(showArchived); - loader.updateAllHabits(true); - activity.invalidateOptionsMenu(); + toggleShowArchived(); return true; - } default: return super.onOptionsItemSelected(item); } } + private void toggleShowArchived() + { + showArchived = !showArchived; + loader.setIncludeArchived(showArchived); + loader.updateAllHabits(true); + activity.invalidateOptionsMenu(); + } + + private void showCreateHabitScreen() + { + EditHabitDialogFragment frag = EditHabitDialogFragment.createHabitFragment(); + frag.setOnSavedListener(this); + frag.show(getFragmentManager(), "editHabit"); + } + @Override public void onItemClick(AdapterView parent, View view, int position, long id) { @@ -249,44 +234,43 @@ public class ListHabitsFragment extends Fragment } else { - int k = selectedPositions.indexOf(position); - if(k < 0) - selectedPositions.add(position); - else - selectedPositions.remove(k); - - if(selectedPositions.isEmpty()) actionMode.finish(); - else actionMode.invalidate(); - + toggleItemSelected(position); adapter.notifyDataSetChanged(); } } + private void toggleItemSelected(int position) + { + int k = selectedPositions.indexOf(position); + if(k < 0) selectedPositions.add(position); + else selectedPositions.remove(k); + + if(selectedPositions.isEmpty()) actionMode.finish(); + else actionMode.invalidate(); + } + @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - selectItem(position); + selectHabit(position); return true; } - private void selectItem(int position) + private void selectHabit(int position) { - if(!selectedPositions.contains(position)) - selectedPositions.add(position); - + if(!selectedPositions.contains(position)) selectedPositions.add(position); adapter.notifyDataSetChanged(); + if(actionMode == null) startSupportActionMode(); + actionMode.invalidate(); + } - if(actionMode == null) - { - HabitSelectionCallback callback = new HabitSelectionCallback(activity, loader); - callback.setSelectedPositions(selectedPositions); - callback.setOnSavedListener(this); - callback.setListener(this); - - actionMode = activity.startSupportActionMode(callback); - } - - if(actionMode != null) actionMode.invalidate(); + private void startSupportActionMode() + { + HabitSelectionCallback callback = new HabitSelectionCallback(activity, loader); + callback.setSelectedPositions(selectedPositions); + callback.setOnSavedListener(this); + callback.setListener(this); + actionMode = activity.startSupportActionMode(callback); } @Override @@ -320,12 +304,11 @@ public class ListHabitsFragment extends Fragment private void onCheckmarkLongClick(View v) { - if (isShortToggleEnabled) return; - - toggleCheck(v); + if (prefs.isShortToggleEnabled()) return; + toggleCheckmark(v); } - private void toggleCheck(View v) + private void toggleCheckmark(View v) { Long id = helper.getHabitIdFromCheckmarkView(v); Habit habit = loader.habits.get(id); @@ -347,25 +330,14 @@ public class ListHabitsFragment extends Fragment activity.executeCommand(c, refreshKey); } - @Override - public void drop(int from, int to) - { - if(from == to) return; - if(actionMode != null) actionMode.finish(); - - loader.reorder(from, to); - adapter.notifyDataSetChanged(); - loader.updateAllHabits(false); - } - @Override public void onClick(View v) { switch (v.getId()) { case R.id.tvCheck: - if (isShortToggleEnabled) toggleCheck(v); - else activity.showToast(R.string.long_press_to_toggle); + if (prefs.isShortToggleEnabled()) toggleCheckmark(v); + else activity.showMessage(R.string.long_press_to_toggle); break; case R.id.llHint: @@ -414,109 +386,31 @@ public class ListHabitsFragment extends Fragment } } - private class HabitsDragListener implements DragSortListView.DragListener + private class HabitsDropListener implements DragSortListView.DropListener { @Override - public void drag(int from, int to) - { - } - - @Override - public void startDrag(int position) + public void drop(int from, int to) { - selectItem(position); - } - } - - public void showImportDialog() - { - File dir = FileUtils.getFilesDir(null); - if(dir == null) - { - activity.showToast(R.string.could_not_import); - return; - } + if(from == to) return; + if(actionMode != null) actionMode.finish(); - FilePickerDialog picker = new FilePickerDialog(activity, dir); - picker.setListener(new FilePickerDialog.OnFileSelectedListener() - { - @Override - public void onFileSelected(File file) - { - ImportDataTask task = new ImportDataTask(file, progressBar); - task.setListener(ListHabitsFragment.this); - task.execute(); - } - }); - - picker.show(); - } - - @Override - public void onImportFinished(int result) - { - switch (result) - { - case ImportDataTask.SUCCESS: - loader.updateAllHabits(true); - activity.showToast(R.string.habits_imported); - break; - - case ImportDataTask.NOT_RECOGNIZED: - activity.showToast(R.string.file_not_recognized); - break; - - default: - activity.showToast(R.string.could_not_import); - break; + loader.reorder(from, to); + adapter.notifyDataSetChanged(); + loader.updateAllHabits(false); } } - public void exportAllHabits() - { - ExportCSVTask task = new ExportCSVTask(Habit.getAll(true), progressBar); - task.setListener(this); - task.execute(); - } - - @Override - public void onExportCSVFinished(@Nullable String archiveFilename) + private class HabitsDragListener implements DragSortListView.DragListener { - if(archiveFilename != null) - { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.setType("application/zip"); - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(archiveFilename))); - activity.startActivity(intent); - } - else + @Override + public void drag(int from, int to) { - activity.showToast(R.string.could_not_export); } - } - - public void exportDB() - { - ExportDBTask task = new ExportDBTask(progressBar); - task.setListener(this); - task.execute(); - } - @Override - public void onExportDBFinished(@Nullable String filename) - { - if(filename != null) - { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.setType("application/octet-stream"); - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(filename))); - activity.startActivity(intent); - } - else + @Override + public void startDrag(int position) { - activity.showToast(R.string.could_not_export); + selectHabit(position); } } } diff --git a/app/src/main/java/org/isoron/uhabits/ui/settings/SettingsFragment.java b/app/src/main/java/org/isoron/uhabits/ui/settings/SettingsFragment.java index 9789b6790..bdb925c12 100644 --- a/app/src/main/java/org/isoron/uhabits/ui/settings/SettingsFragment.java +++ b/app/src/main/java/org/isoron/uhabits/ui/settings/SettingsFragment.java @@ -27,7 +27,7 @@ import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceFragmentCompat; -import org.isoron.uhabits.MainActivity; +import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.R; import org.isoron.uhabits.utils.ReminderUtils; import org.isoron.uhabits.utils.InterfaceUtils; @@ -43,10 +43,10 @@ public class SettingsFragment extends PreferenceFragmentCompat super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); - setResultOnPreferenceClick("importData", MainActivity.RESULT_IMPORT_DATA); - setResultOnPreferenceClick("exportCSV", MainActivity.RESULT_EXPORT_CSV); - setResultOnPreferenceClick("exportDB", MainActivity.RESULT_EXPORT_DB); - setResultOnPreferenceClick("bugReport", MainActivity.RESULT_BUG_REPORT); + setResultOnPreferenceClick("importData", HabitsApplication.RESULT_IMPORT_DATA); + setResultOnPreferenceClick("exportCSV", HabitsApplication.RESULT_EXPORT_CSV); + setResultOnPreferenceClick("exportDB", HabitsApplication.RESULT_EXPORT_DB); + setResultOnPreferenceClick("bugReport", HabitsApplication.RESULT_BUG_REPORT); updateRingtoneDescription(); diff --git a/app/src/main/java/org/isoron/uhabits/utils/InterfaceUtils.java b/app/src/main/java/org/isoron/uhabits/utils/InterfaceUtils.java index 5625bd7f9..f6492725a 100644 --- a/app/src/main/java/org/isoron/uhabits/utils/InterfaceUtils.java +++ b/app/src/main/java/org/isoron/uhabits/utils/InterfaceUtils.java @@ -33,10 +33,7 @@ import android.preference.PreferenceManager; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import org.isoron.uhabits.BuildConfig; import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.R; import org.isoron.uhabits.commands.Command; @@ -71,32 +68,6 @@ public abstract class InterfaceUtils return fontAwesome; } - public static void showSoftKeyboard(View view) - { - InputMethodManager imm = (InputMethodManager) view.getContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); - } - - public static void incrementLaunchCount(Context context) - { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - int count = prefs.getInt("launch_count", 0); - prefs.edit().putInt("launch_count", count + 1).apply(); - } - - public static void updateLastAppVersion(Context context) - { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - prefs.edit().putInt("last_version", BuildConfig.VERSION_CODE).apply(); - } - - public static int getLaunchCount(Context context) - { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - return prefs.getInt("launch_count", 0); - } - public static String getAttribute(Context context, AttributeSet attrs, String name, String defaultValue) { diff --git a/app/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java b/app/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java index 9d4f187c3..6082f0a2b 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/HabitPickerDialog.java @@ -30,7 +30,6 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; -import org.isoron.uhabits.MainActivity; import org.isoron.uhabits.R; import org.isoron.uhabits.models.Habit; @@ -81,7 +80,7 @@ public class HabitPickerDialog extends Activity implements AdapterView.OnItemCli getApplicationContext()); prefs.edit().putLong(BaseWidgetProvider.getHabitIdKey(widgetId), habitId).commit(); - MainActivity.updateWidgets(this); + WidgetManager.updateWidgets(this); Intent resultValue = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); diff --git a/app/src/main/java/org/isoron/uhabits/widgets/WidgetManager.java b/app/src/main/java/org/isoron/uhabits/widgets/WidgetManager.java new file mode 100644 index 000000000..69643059c --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/widgets/WidgetManager.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.widgets; + +import android.appwidget.AppWidgetManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; + +public class WidgetManager +{ + public static void updateWidgets(Context context) + { + updateWidgets(context, CheckmarkWidgetProvider.class); + updateWidgets(context, HistoryWidgetProvider.class); + updateWidgets(context, ScoreWidgetProvider.class); + updateWidgets(context, StreakWidgetProvider.class); + updateWidgets(context, FrequencyWidgetProvider.class); + } + + private static void updateWidgets(Context context, Class providerClass) + { + ComponentName provider = new ComponentName(context, providerClass); + Intent intent = new Intent(context, providerClass); + intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); + int ids[] = AppWidgetManager.getInstance(context).getAppWidgetIds(provider); + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids); + context.sendBroadcast(intent); + } +}