Refactor MainActivity and Preferences

pull/145/head
Alinson S. Xavier 9 years ago
parent 83ef8564e1
commit 6445bf62bc

@ -23,6 +23,7 @@ import android.os.Build;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import org.isoron.uhabits.BaseTest;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.HabitsApplication;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -34,7 +35,7 @@ import static org.hamcrest.Matchers.containsString;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class HabitsApplicationTest public class HabitsApplicationTest extends BaseTest
{ {
@Test @Test
public void test_getLogcat() throws IOException public void test_getLogcat() throws IOException
@ -45,7 +46,10 @@ public class HabitsApplicationTest
String msg = "LOGCAT TEST"; String msg = "LOGCAT TEST";
new RuntimeException(msg).printStackTrace(); new RuntimeException(msg).printStackTrace();
String log = HabitsApplication.getLogcat(); HabitsApplication app = HabitsApplication.getInstance();
assert(app != null);
String log = app.getLogcat();
assertThat(log, containsString(msg)); assertThat(log, containsString(msg));
} }
} }

@ -21,7 +21,6 @@ package org.isoron.uhabits.unit.tasks;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ProgressBar;
import org.isoron.uhabits.BaseTest; import org.isoron.uhabits.BaseTest;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
@ -55,9 +54,8 @@ public class ExportCSVTaskTest extends BaseTest
{ {
HabitFixtures.createShortHabit(); HabitFixtures.createShortHabit();
List<Habit> habits = Habit.getAll(true); List<Habit> 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() task.setListener(new ExportCSVTask.Listener()
{ {
@Override @Override

@ -19,11 +19,8 @@
package org.isoron.uhabits.unit.tasks; package org.isoron.uhabits.unit.tasks;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ProgressBar;
import org.isoron.uhabits.BaseTest; import org.isoron.uhabits.BaseTest;
import org.isoron.uhabits.tasks.ExportDBTask; import org.isoron.uhabits.tasks.ExportDBTask;
@ -52,10 +49,7 @@ public class ExportDBTaskTest extends BaseTest
@Test @Test
public void testExportCSV() throws Throwable public void testExportCSV() throws Throwable
{ {
Context context = InstrumentationRegistry.getContext(); ExportDBTask task = new ExportDBTask(null);
ProgressBar bar = new ProgressBar(context);
ExportDBTask task = new ExportDBTask(bar);
task.setListener(new ExportDBTask.Listener() task.setListener(new ExportDBTask.Listener()
{ {
@Override @Override

@ -22,11 +22,10 @@ package org.isoron.uhabits.unit.tasks;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ProgressBar;
import org.isoron.uhabits.BaseTest; import org.isoron.uhabits.BaseTest;
import org.isoron.uhabits.utils.FileUtils;
import org.isoron.uhabits.tasks.ImportDataTask; import org.isoron.uhabits.tasks.ImportDataTask;
import org.isoron.uhabits.utils.FileUtils;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -67,7 +66,7 @@ public class ImportDataTaskTest extends BaseTest
task.setListener(new ImportDataTask.Listener() task.setListener(new ImportDataTask.Listener()
{ {
@Override @Override
public void onImportFinished(int result) public void onImportDataFinished(int result)
{ {
assertThat(result, equalTo(expectedResult)); assertThat(result, equalTo(expectedResult));
} }
@ -80,11 +79,9 @@ public class ImportDataTaskTest extends BaseTest
@NonNull @NonNull
private ImportDataTask createTask(String assetFilename) throws IOException private ImportDataTask createTask(String assetFilename) throws IOException
{ {
ProgressBar bar = new ProgressBar(targetContext);
File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename)); File file = new File(String.format("%s/%s", baseDir.getPath(), assetFilename));
copyAssetToFile(assetFilename, file); copyAssetToFile(assetFilename, file);
return new ImportDataTask(file, null);
return new ImportDataTask(file, bar);
} }
@Test @Test

@ -42,6 +42,7 @@ import org.isoron.uhabits.models.Checkmark;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.ui.show.ShowHabitActivity; import org.isoron.uhabits.ui.show.ShowHabitActivity;
import org.isoron.uhabits.widgets.WidgetManager;
import java.util.Date; import java.util.Date;
@ -123,10 +124,10 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
public static void sendRefreshBroadcast(Context context) public static void sendRefreshBroadcast(Context context)
{ {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context); LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context);
Intent refreshIntent = new Intent(MainActivity.ACTION_REFRESH); Intent refreshIntent = new Intent(HabitsApplication.ACTION_REFRESH);
manager.sendBroadcast(refreshIntent); manager.sendBroadcast(refreshIntent);
MainActivity.updateWidgets(context); WidgetManager.updateWidgets(context);
} }
private void dismissAllHabits() private void dismissAllHabits()

@ -21,6 +21,8 @@ package org.isoron.uhabits;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -28,9 +30,12 @@ import android.view.WindowManager;
import com.activeandroid.ActiveAndroid; 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.DatabaseUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.FileUtils; 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.BufferedReader;
import java.io.File; import java.io.File;
@ -39,8 +44,17 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.LinkedList; 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 @Nullable
private static Context context; private static Context context;
@ -64,11 +78,18 @@ public class HabitsApplication extends Application
return context; return context;
} }
@Nullable
public static HabitsApplication getInstance()
{
return application;
}
@Override @Override
public void onCreate() public void onCreate()
{ {
super.onCreate(); super.onCreate();
HabitsApplication.context = this; HabitsApplication.context = this;
HabitsApplication.application = this;
if (isTestMode()) if (isTestMode())
{ {
@ -87,7 +108,7 @@ public class HabitsApplication extends Application
super.onTerminate(); super.onTerminate();
} }
public static String getLogcat() throws IOException public String getLogcat() throws IOException
{ {
int maxNLines = 250; int maxNLines = 250;
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@ -116,7 +137,7 @@ public class HabitsApplication extends Application
return builder.toString(); return builder.toString();
} }
public static String getDeviceInfo() public String getDeviceInfo()
{ {
if(context == null) return ""; 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 Name: %s\n", BuildConfig.VERSION_NAME));
b.append(String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE)); 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)); android.os.Build.VERSION.INCREMENTAL));
b.append(String.format("OS API Level: %s\n", android.os.Build.VERSION.SDK)); 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)); b.append(String.format("Device: %s\n", android.os.Build.DEVICE));
@ -141,7 +162,7 @@ public class HabitsApplication extends Application
} }
@NonNull @NonNull
public static File dumpBugReportToFile() throws IOException public File dumpBugReportToFile() throws IOException
{ {
String date = DateUtils.getBackupDateFormat().format(DateUtils.getLocalTime()); 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)); File logFile = new File(String.format("%s/Log %s.txt", dir.getPath(), date));
FileWriter output = new FileWriter(logFile); FileWriter output = new FileWriter(logFile);
output.write(generateBugReport()); output.write(getBugReport());
output.close(); output.close();
return logFile; return logFile;
} }
@NonNull @NonNull
public static String generateBugReport() throws IOException public String getBugReport() throws IOException
{ {
String logcat = getLogcat(); String logcat = getLogcat();
String deviceInfo = getDeviceInfo(); String deviceInfo = getDeviceInfo();
return deviceInfo + "\n" + logcat; 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();
}
} }

@ -19,86 +19,62 @@
package org.isoron.uhabits; package org.isoron.uhabits;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.preference.PreferenceManager; import android.support.v4.app.FragmentManager;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; 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.Checkmark;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.tasks.ProgressBar;
import org.isoron.uhabits.ui.AboutActivity; import org.isoron.uhabits.ui.AboutActivity;
import org.isoron.uhabits.ui.AndroidProgressBar;
import org.isoron.uhabits.ui.BaseActivity; import org.isoron.uhabits.ui.BaseActivity;
import org.isoron.uhabits.ui.IntroActivity; 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.settings.SettingsActivity;
import org.isoron.uhabits.ui.show.ShowHabitActivity; import org.isoron.uhabits.ui.show.ShowHabitActivity;
import org.isoron.uhabits.widgets.CheckmarkWidgetProvider; import org.isoron.uhabits.utils.FileUtils;
import org.isoron.uhabits.widgets.FrequencyWidgetProvider; import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.widgets.HistoryWidgetProvider; import org.isoron.uhabits.widgets.WidgetManager;
import org.isoron.uhabits.widgets.ScoreWidgetProvider;
import org.isoron.uhabits.widgets.StreakWidgetProvider;
import java.io.IOException; import java.io.File;
public class MainActivity extends BaseActivity public class MainActivity extends BaseActivity
implements ListHabitsFragment.OnHabitClickListener implements ListHabitsFragment.OnHabitClickListener, MainController.Screen
{ {
private MainController controller;
private ListHabitsFragment listHabitsFragment; 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 @Override
protected void onCreate(Bundle savedInstanceState) protected void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.list_habits_activity); setContentView(R.layout.list_habits_activity);
setupSupportActionBar(false); setupSupportActionBar(false);
prefs = PreferenceManager.getDefaultSharedPreferences(this); FragmentManager fragmentManager = getSupportFragmentManager();
listHabitsFragment = listHabitsFragment = (ListHabitsFragment) fragmentManager.findFragmentById(R.id.fragment1);
(ListHabitsFragment) getSupportFragmentManager().findFragmentById(R.id.fragment1);
receiver = new Receiver();
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(receiver, new IntentFilter(ACTION_REFRESH));
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) 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(); ActionBar actionBar = getSupportActionBar();
if(actionBar == null) return; if(actionBar == null) return;
@ -108,50 +84,13 @@ public class MainActivity extends BaseActivity
actionBar.setBackgroundDrawable(new ColorDrawable(color)); actionBar.setBackgroundDrawable(new ColorDrawable(color));
} }
private void onStartup()
{
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
InterfaceUtils.incrementLaunchCount(this);
InterfaceUtils.updateLastAppVersion(this);
showTutorial();
new AsyncTask<Void, Void, Void>() {
@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 @Override
public boolean onCreateOptionsMenu(Menu menu) public boolean onCreateOptionsMenu(Menu menu)
{ {
menu.clear(); menu.clear();
getMenuInflater().inflate(R.menu.list_habits_menu, menu); getMenuInflater().inflate(R.menu.list_habits_menu, menu);
MenuItem nightModeItem = menu.findItem(R.id.action_night_mode); MenuItem nightModeItem = menu.findItem(R.id.action_night_mode);
nightModeItem.setChecked(InterfaceUtils.isNightMode()); nightModeItem.setChecked(InterfaceUtils.isNightMode());
return true; return true;
} }
@ -161,122 +100,100 @@ public class MainActivity extends BaseActivity
switch (item.getItemId()) switch (item.getItemId())
{ {
case R.id.action_night_mode: case R.id.action_night_mode:
{ toggleNightMode();
if(InterfaceUtils.isNightMode())
InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_LIGHT);
else
InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_DARK);
refreshTheme();
return true; return true;
}
case R.id.action_settings: case R.id.action_settings:
{ showSettingsScreen();
Intent intent = new Intent(this, SettingsActivity.class);
startActivityForResult(intent, 0);
return true; return true;
}
case R.id.action_about: case R.id.action_about:
{ showAboutScreen();
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
return true; return true;
}
case R.id.action_faq: case R.id.action_faq:
{ showFAQScreen();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(getString(R.string.helpURL)));
startActivity(intent);
return true; return true;
}
default: default:
return super.onOptionsItemSelected(item); 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 @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) protected void onActivityResult(int requestCode, int resultCode, Intent data)
{ {
switch (resultCode) switch (resultCode)
{ {
case RESULT_IMPORT_DATA: case HabitsApplication.RESULT_IMPORT_DATA:
listHabitsFragment.showImportDialog(); showImportScreen();
break; break;
case RESULT_EXPORT_CSV: case HabitsApplication.RESULT_EXPORT_CSV:
listHabitsFragment.exportAllHabits(); controller.exportCSV();
break; break;
case RESULT_EXPORT_DB: case HabitsApplication.RESULT_EXPORT_DB:
listHabitsFragment.exportDB(); controller.exportDB();
break; break;
case RESULT_BUG_REPORT: case HabitsApplication.RESULT_BUG_REPORT:
generateBugReport(); controller.sendBugReport();
break; break;
} }
} }
private void generateBugReport() private void showFAQScreen()
{ {
try Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(getString(R.string.helpURL)));
startActivity(intent);
}
private void showAboutScreen()
{ {
HabitsApplication.dumpBugReportToFile(); Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
} }
catch (IOException e)
private void showSettingsScreen()
{ {
// ignored Intent intent = new Intent(this, SettingsActivity.class);
startActivityForResult(intent, 0);
} }
try private void toggleNightMode()
{ {
String log = "---------- BUG REPORT BEGINS ----------\n"; if(InterfaceUtils.isNightMode())
log += HabitsApplication.generateBugReport(); InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_LIGHT);
log += "---------- BUG REPORT ENDS ------------\n"; else
InterfaceUtils.setCurrentTheme(InterfaceUtils.THEME_DARK);
Intent intent = new Intent(); refreshTheme();
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 refreshTheme()
{
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{ {
e.printStackTrace(); Intent intent = new Intent(MainActivity.this, MainActivity.class);
showToast(R.string.bug_report_failed);
MainActivity.this.finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
startActivity(intent);
} }
}, 500); // Let the menu disappear first
} }
@Override @Override
public void onHabitClicked(Habit habit) public void onHabitClicked(Habit habit)
{ {
Intent intent = new Intent(this, ShowHabitActivity.class); showHabitScreen(habit);
intent.setData(Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId()));
startActivity(intent);
} }
@Override @Override
@ -290,7 +207,7 @@ public class MainActivity extends BaseActivity
protected void doInBackground() protected void doInBackground()
{ {
dismissNotifications(MainActivity.this); dismissNotifications(MainActivity.this);
updateWidgets(MainActivity.this); WidgetManager.updateWidgets(MainActivity.this);
} }
}.execute(); }.execute();
} }
@ -304,48 +221,49 @@ public class MainActivity extends BaseActivity
} }
} }
public static void updateWidgets(Context context) private void showHabitScreen(Habit habit)
{ {
updateWidgets(context, CheckmarkWidgetProvider.class); Intent intent = new Intent(this, ShowHabitActivity.class);
updateWidgets(context, HistoryWidgetProvider.class); intent.setData(Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId()));
updateWidgets(context, ScoreWidgetProvider.class); startActivity(intent);
updateWidgets(context, StreakWidgetProvider.class);
updateWidgets(context, FrequencyWidgetProvider.class);
} }
private static void updateWidgets(Context context, Class providerClass) public void showIntroScreen()
{ {
ComponentName provider = new ComponentName(context, providerClass); Intent intent = new Intent(this, IntroActivity.class);
Intent intent = new Intent(context, providerClass); this.startActivity(intent);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
int ids[] = AppWidgetManager.getInstance(context).getAppWidgetIds(provider);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
context.sendBroadcast(intent);
} }
@Override public void showImportScreen()
protected void onDestroy() {
File dir = FileUtils.getFilesDir(null);
if(dir == null)
{ {
localBroadcastManager.unregisterReceiver(receiver); showMessage(R.string.could_not_import);
super.onDestroy(); return;
} }
class Receiver extends BroadcastReceiver FilePickerDialog picker = new FilePickerDialog(this, dir);
picker.setListener(new FilePickerDialog.OnFileSelectedListener()
{ {
@Override @Override
public void onReceive(Context context, Intent intent) public void onFileSelected(File file)
{ {
listHabitsFragment.onPostExecuteCommand(null); controller.importData(file);
} }
});
picker.show();
} }
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, public void refresh(Long refreshKey)
@NonNull int[] grantResults)
{ {
if (grantResults.length <= 0) return; listHabitsFragment.loader.updateAllHabits(true);
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) return; }
listHabitsFragment.showImportDialog(); @Override
public ProgressBar getProgressBar()
{
return new AndroidProgressBar(listHabitsFragment.progressBar);
} }
} }

@ -0,0 +1,179 @@
/*
* 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;
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);
}
}
}

@ -0,0 +1,81 @@
/*
* 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;
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);
}
}

@ -20,12 +20,10 @@
package org.isoron.uhabits.tasks; package org.isoron.uhabits.tasks;
import android.support.annotation.Nullable; 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.io.HabitsCSVExporter;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.utils.FileUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -58,12 +56,7 @@ public class ExportCSVTask extends BaseTask
protected void onPreExecute() protected void onPreExecute()
{ {
super.onPreExecute(); super.onPreExecute();
if(progressBar != null) progressBar.show();
if(progressBar != null)
{
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.VISIBLE);
}
} }
@Override @Override
@ -72,9 +65,7 @@ public class ExportCSVTask extends BaseTask
if(listener != null) if(listener != null)
listener.onExportCSVFinished(archiveFilename); listener.onExportCSVFinished(archiveFilename);
if(progressBar != null) if(progressBar != null) progressBar.hide();
progressBar.setVisibility(View.GONE);
super.onPostExecute(null); super.onPostExecute(null);
} }

@ -20,8 +20,6 @@
package org.isoron.uhabits.tasks; package org.isoron.uhabits.tasks;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.view.View;
import android.widget.ProgressBar;
import org.isoron.uhabits.utils.DatabaseUtils; import org.isoron.uhabits.utils.DatabaseUtils;
import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.utils.FileUtils;
@ -54,23 +52,14 @@ public class ExportDBTask extends BaseTask
protected void onPreExecute() protected void onPreExecute()
{ {
super.onPreExecute(); super.onPreExecute();
if(progressBar != null) progressBar.show();
if(progressBar != null)
{
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.VISIBLE);
}
} }
@Override @Override
protected void onPostExecute(Void aVoid) protected void onPostExecute(Void aVoid)
{ {
if(listener != null) if(listener != null) listener.onExportDBFinished(filename);
listener.onExportDBFinished(filename); if(progressBar != null) progressBar.hide();
if(progressBar != null)
progressBar.setVisibility(View.GONE);
super.onPostExecute(null); super.onPostExecute(null);
} }

@ -21,8 +21,6 @@ package org.isoron.uhabits.tasks;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.view.View;
import android.widget.ProgressBar;
import org.isoron.uhabits.io.GenericImporter; import org.isoron.uhabits.io.GenericImporter;
@ -36,7 +34,7 @@ public class ImportDataTask extends BaseTask
public interface Listener public interface Listener
{ {
void onImportFinished(int result); void onImportDataFinished(int result);
} }
@Nullable @Nullable
@ -66,21 +64,14 @@ public class ImportDataTask extends BaseTask
{ {
super.onPreExecute(); super.onPreExecute();
if(progressBar != null) if(progressBar != null) progressBar.show();
{
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.VISIBLE);
}
} }
@Override @Override
protected void onPostExecute(Void aVoid) protected void onPostExecute(Void aVoid)
{ {
if(progressBar != null) if(progressBar != null) progressBar.hide();
progressBar.setVisibility(View.GONE); if(listener != null) listener.onImportDataFinished(result);
if(listener != null) listener.onImportFinished(result);
super.onPostExecute(null); super.onPostExecute(null);
} }

@ -0,0 +1,26 @@
/*
* 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.tasks;
public interface ProgressBar
{
void show();
void hide();
}

@ -0,0 +1,47 @@
/*
* 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.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);
}
}

@ -72,28 +72,28 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
{ {
if (undoList.isEmpty()) if (undoList.isEmpty())
{ {
showToast(R.string.toast_nothing_to_undo); showMessage(R.string.toast_nothing_to_undo);
return; return;
} }
Command last = undoList.pop(); Command last = undoList.pop();
redoList.push(last); redoList.push(last);
last.undo(); last.undo();
showToast(last.getUndoStringId()); showMessage(last.getUndoStringId());
} }
protected void redo() protected void redo()
{ {
if (redoList.isEmpty()) if (redoList.isEmpty())
{ {
showToast(R.string.toast_nothing_to_redo); showMessage(R.string.toast_nothing_to_redo);
return; return;
} }
Command last = redoList.pop(); Command last = redoList.pop();
executeCommand(last, false, null); executeCommand(last, false, null);
} }
public void showToast(Integer stringId) public void showMessage(Integer stringId)
{ {
if (stringId == null) return; if (stringId == null) return;
if (toast == null) toast = Toast.makeText(this, stringId, Toast.LENGTH_SHORT); 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(); }.execute();
showToast(command.getExecuteStringId()); showMessage(command.getExecuteStringId());
} }
protected void setupSupportActionBar(boolean homeButtonEnabled) protected void setupSupportActionBar(boolean homeButtonEnabled)
@ -156,7 +156,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
try try
{ {
ex.printStackTrace(); ex.printStackTrace();
HabitsApplication.dumpBugReportToFile(); ((HabitsApplication) getApplication()).dumpBugReportToFile();
} }
catch(Exception e) catch(Exception e)
{ {

@ -0,0 +1,37 @@
/*
* 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.ui.list;
public class ListHabitsController
{
public interface Screen
{
}
private Screen screen;
public void setScreen(Screen screen)
{
this.screen = screen;
}
}

@ -20,16 +20,9 @@
package org.isoron.uhabits.ui.list; package org.isoron.uhabits.ui.list;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.view.ActionMode; import android.support.v7.view.ActionMode;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.HapticFeedbackConstants; import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -40,7 +33,6 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener; import android.view.View.OnLongClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
@ -48,80 +40,96 @@ import android.widget.TextView;
import com.mobeta.android.dslv.DragSortController; import com.mobeta.android.dslv.DragSortController;
import com.mobeta.android.dslv.DragSortListView; 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.R;
import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.commands.Command;
import org.isoron.uhabits.commands.ToggleRepetitionCommand; 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.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.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;
import org.isoron.uhabits.utils.InterfaceUtils.OnSavedListener; import org.isoron.uhabits.utils.InterfaceUtils.OnSavedListener;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.utils.ReminderUtils;
import org.isoron.uhabits.tasks.ExportCSVTask;
import org.isoron.uhabits.tasks.ExportDBTask;
import org.isoron.uhabits.tasks.ImportDataTask;
import java.io.File;
import java.util.Date; import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class ListHabitsFragment extends Fragment public class ListHabitsFragment extends Fragment
implements OnSavedListener, OnItemClickListener, OnLongClickListener, DropListener, implements OnSavedListener, OnItemClickListener, OnLongClickListener,
OnClickListener, ListHabitsLoader.Listener, AdapterView.OnItemLongClickListener, OnClickListener, ListHabitsLoader.Listener, AdapterView.OnItemLongClickListener,
HabitSelectionCallback.Listener, ImportDataTask.Listener, ExportCSVTask.Listener, HabitSelectionCallback.Listener, ListHabitsController.Screen
ExportDBTask.Listener
{ {
long lastLongClick = 0; long lastLongClick = 0;
private boolean isShortToggleEnabled;
private boolean showArchived; private boolean showArchived;
private ActionMode actionMode; private ActionMode actionMode;
private ListHabitsAdapter adapter; private ListHabitsAdapter adapter;
private ListHabitsLoader loader; public ListHabitsLoader loader;
private HintManager hintManager; private HintManager hintManager;
private ListHabitsHelper helper; private ListHabitsHelper helper;
private List<Integer> selectedPositions; private List<Integer> selectedPositions;
private OnHabitClickListener habitClickListener; private OnHabitClickListener habitClickListener;
private BaseActivity activity; private BaseActivity activity;
private SharedPreferences prefs;
private DragSortListView listView; private DragSortListView listView;
private LinearLayout llButtonsHeader; private LinearLayout llButtonsHeader;
private ProgressBar progressBar; public ProgressBar progressBar;
private View llEmpty; private View llEmpty;
private ListHabitsController controller;
private Preferences prefs;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) Bundle savedInstanceState)
{ {
View view = inflater.inflate(R.layout.list_habits_fragment, container, false); View view = inflater.inflate(R.layout.list_habits_fragment, container, false);
View llHint = view.findViewById(R.id.llHint); 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); llButtonsHeader = (LinearLayout) view.findViewById(R.id.llButtonsHeader);
llEmpty = view.findViewById(R.id.llEmpty); llEmpty = view.findViewById(R.id.llEmpty);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar); progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
selectedPositions = new LinkedList<>(); selectedPositions = new LinkedList<>();
loader = new ListHabitsLoader(); loader = new ListHabitsLoader();
helper = new ListHabitsHelper(activity, loader); helper = new ListHabitsHelper(activity, loader);
hintManager = new HintManager(activity, llHint); hintManager = new HintManager(activity, llHint);
loader.setListener(this); loader.setListener(this);
loader.setCheckmarkCount(helper.getButtonCount()); loader.setCheckmarkCount(helper.getButtonCount());
llHint.setOnClickListener(this); llHint.setOnClickListener(this);
TextView tvStarEmpty = (TextView) view.findViewById(R.id.tvStarEmpty);
tvStarEmpty.setTypeface(InterfaceUtils.getFontAwesome(activity)); 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 = new ListHabitsAdapter(getActivity(), loader);
adapter.setSelectedPositions(selectedPositions); adapter.setSelectedPositions(selectedPositions);
adapter.setOnCheckmarkClickListener(this); adapter.setOnCheckmarkClickListener(this);
@ -130,26 +138,15 @@ public class ListHabitsFragment extends Fragment
DragSortListView.DragListener dragListener = new HabitsDragListener(); DragSortListView.DragListener dragListener = new HabitsDragListener();
DragSortController dragSortController = new HabitsDragSortController(); DragSortController dragSortController = new HabitsDragSortController();
listView = (DragSortListView) view.findViewById(R.id.listView);
listView.setAdapter(adapter); listView.setAdapter(adapter);
listView.setOnItemClickListener(this); listView.setOnItemClickListener(this);
listView.setOnItemLongClickListener(this); listView.setOnItemLongClickListener(this);
listView.setDropListener(this); listView.setDropListener(new HabitsDropListener());
listView.setDragListener(dragListener); listView.setDragListener(dragListener);
listView.setFloatViewManager(dragSortController); listView.setFloatViewManager(dragSortController);
listView.setDragEnabled(true); listView.setDragEnabled(true);
listView.setLongClickable(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 @Override
@ -158,9 +155,7 @@ public class ListHabitsFragment extends Fragment
{ {
super.onAttach(activity); super.onAttach(activity);
this.activity = (BaseActivity) activity; this.activity = (BaseActivity) activity;
habitClickListener = (OnHabitClickListener) activity; habitClickListener = (OnHabitClickListener) activity;
prefs = PreferenceManager.getDefaultSharedPreferences(activity);
} }
@Override @Override
@ -175,9 +170,7 @@ public class ListHabitsFragment extends Fragment
helper.updateEmptyMessage(llEmpty); helper.updateEmptyMessage(llEmpty);
helper.updateHeader(llButtonsHeader); helper.updateHeader(llButtonsHeader);
hintManager.showHintIfAppropriate(); hintManager.showHintIfAppropriate();
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
isShortToggleEnabled = prefs.getBoolean("pref_short_toggle", false);
} }
@Override @Override
@ -192,49 +185,41 @@ public class ListHabitsFragment extends Fragment
{ {
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.list_habits_options, menu); inflater.inflate(R.menu.list_habits_options, menu);
MenuItem showArchivedItem = menu.findItem(R.id.action_show_archived); MenuItem showArchivedItem = menu.findItem(R.id.action_show_archived);
showArchivedItem.setChecked(showArchived); 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 @Override
public boolean onOptionsItemSelected(MenuItem item) public boolean onOptionsItemSelected(MenuItem item)
{ {
switch (item.getItemId()) switch (item.getItemId())
{ {
case R.id.action_add: case R.id.action_add:
{ showCreateHabitScreen();
EditHabitDialogFragment frag = EditHabitDialogFragment.createHabitFragment();
frag.setOnSavedListener(this);
frag.show(getFragmentManager(), "editHabit");
return true; return true;
}
case R.id.action_show_archived: case R.id.action_show_archived:
toggleShowArchived();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void toggleShowArchived()
{ {
showArchived = !showArchived; showArchived = !showArchived;
loader.setIncludeArchived(showArchived); loader.setIncludeArchived(showArchived);
loader.updateAllHabits(true); loader.updateAllHabits(true);
activity.invalidateOptionsMenu(); activity.invalidateOptionsMenu();
return true;
} }
default: private void showCreateHabitScreen()
return super.onOptionsItemSelected(item); {
} EditHabitDialogFragment frag = EditHabitDialogFragment.createHabitFragment();
frag.setOnSavedListener(this);
frag.show(getFragmentManager(), "editHabit");
} }
@Override @Override
@ -248,47 +233,46 @@ public class ListHabitsFragment extends Fragment
habitClickListener.onHabitClicked(habit); habitClickListener.onHabitClicked(habit);
} }
else else
{
toggleItemSelected(position);
adapter.notifyDataSetChanged();
}
}
private void toggleItemSelected(int position)
{ {
int k = selectedPositions.indexOf(position); int k = selectedPositions.indexOf(position);
if(k < 0) if(k < 0) selectedPositions.add(position);
selectedPositions.add(position); else selectedPositions.remove(k);
else
selectedPositions.remove(k);
if(selectedPositions.isEmpty()) actionMode.finish(); if(selectedPositions.isEmpty()) actionMode.finish();
else actionMode.invalidate(); else actionMode.invalidate();
adapter.notifyDataSetChanged();
}
} }
@Override @Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
{ {
selectItem(position); selectHabit(position);
return true; return true;
} }
private void selectItem(int position) private void selectHabit(int position)
{ {
if(!selectedPositions.contains(position)) if(!selectedPositions.contains(position)) selectedPositions.add(position);
selectedPositions.add(position);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
if(actionMode == null) startSupportActionMode();
actionMode.invalidate();
}
if(actionMode == null) private void startSupportActionMode()
{ {
HabitSelectionCallback callback = new HabitSelectionCallback(activity, loader); HabitSelectionCallback callback = new HabitSelectionCallback(activity, loader);
callback.setSelectedPositions(selectedPositions); callback.setSelectedPositions(selectedPositions);
callback.setOnSavedListener(this); callback.setOnSavedListener(this);
callback.setListener(this); callback.setListener(this);
actionMode = activity.startSupportActionMode(callback); actionMode = activity.startSupportActionMode(callback);
} }
if(actionMode != null) actionMode.invalidate();
}
@Override @Override
public void onSaved(Command command, Object savedObject) public void onSaved(Command command, Object savedObject)
{ {
@ -320,12 +304,11 @@ public class ListHabitsFragment extends Fragment
private void onCheckmarkLongClick(View v) private void onCheckmarkLongClick(View v)
{ {
if (isShortToggleEnabled) return; if (prefs.isShortToggleEnabled()) return;
toggleCheckmark(v);
toggleCheck(v);
} }
private void toggleCheck(View v) private void toggleCheckmark(View v)
{ {
Long id = helper.getHabitIdFromCheckmarkView(v); Long id = helper.getHabitIdFromCheckmarkView(v);
Habit habit = loader.habits.get(id); Habit habit = loader.habits.get(id);
@ -347,25 +330,14 @@ public class ListHabitsFragment extends Fragment
activity.executeCommand(c, refreshKey); 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 @Override
public void onClick(View v) public void onClick(View v)
{ {
switch (v.getId()) switch (v.getId())
{ {
case R.id.tvCheck: case R.id.tvCheck:
if (isShortToggleEnabled) toggleCheck(v); if (prefs.isShortToggleEnabled()) toggleCheckmark(v);
else activity.showToast(R.string.long_press_to_toggle); else activity.showMessage(R.string.long_press_to_toggle);
break; break;
case R.id.llHint: 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 @Override
public void drag(int from, int to) public void drop(int from, int to)
{
}
@Override
public void startDrag(int position)
{
selectItem(position);
}
}
public void showImportDialog()
{
File dir = FileUtils.getFilesDir(null);
if(dir == null)
{
activity.showToast(R.string.could_not_import);
return;
}
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: if(from == to) return;
loader.updateAllHabits(true); if(actionMode != null) actionMode.finish();
activity.showToast(R.string.habits_imported);
break;
case ImportDataTask.NOT_RECOGNIZED:
activity.showToast(R.string.file_not_recognized);
break;
default: loader.reorder(from, to);
activity.showToast(R.string.could_not_import); adapter.notifyDataSetChanged();
break; loader.updateAllHabits(false);
} }
} }
public void exportAllHabits() private class HabitsDragListener implements DragSortListView.DragListener
{ {
ExportCSVTask task = new ExportCSVTask(Habit.getAll(true), progressBar);
task.setListener(this);
task.execute();
}
@Override @Override
public void onExportCSVFinished(@Nullable String archiveFilename) public void drag(int from, int to)
{
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
{
activity.showToast(R.string.could_not_export);
}
}
public void exportDB()
{ {
ExportDBTask task = new ExportDBTask(progressBar);
task.setListener(this);
task.execute();
} }
@Override @Override
public void onExportDBFinished(@Nullable String filename) public void startDrag(int position)
{
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
{ {
activity.showToast(R.string.could_not_export); selectHabit(position);
} }
} }
} }

@ -27,7 +27,7 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceFragmentCompat; 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.R;
import org.isoron.uhabits.utils.ReminderUtils; import org.isoron.uhabits.utils.ReminderUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
@ -43,10 +43,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.preferences);
setResultOnPreferenceClick("importData", MainActivity.RESULT_IMPORT_DATA); setResultOnPreferenceClick("importData", HabitsApplication.RESULT_IMPORT_DATA);
setResultOnPreferenceClick("exportCSV", MainActivity.RESULT_EXPORT_CSV); setResultOnPreferenceClick("exportCSV", HabitsApplication.RESULT_EXPORT_CSV);
setResultOnPreferenceClick("exportDB", MainActivity.RESULT_EXPORT_DB); setResultOnPreferenceClick("exportDB", HabitsApplication.RESULT_EXPORT_DB);
setResultOnPreferenceClick("bugReport", MainActivity.RESULT_BUG_REPORT); setResultOnPreferenceClick("bugReport", HabitsApplication.RESULT_BUG_REPORT);
updateRingtoneDescription(); updateRingtoneDescription();

@ -33,10 +33,7 @@ import android.preference.PreferenceManager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.TypedValue; 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.HabitsApplication;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.commands.Command;
@ -71,32 +68,6 @@ public abstract class InterfaceUtils
return fontAwesome; 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, public static String getAttribute(Context context, AttributeSet attrs, String name,
String defaultValue) String defaultValue)
{ {

@ -30,7 +30,6 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ListView; import android.widget.ListView;
import org.isoron.uhabits.MainActivity;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
@ -81,7 +80,7 @@ public class HabitPickerDialog extends Activity implements AdapterView.OnItemCli
getApplicationContext()); getApplicationContext());
prefs.edit().putLong(BaseWidgetProvider.getHabitIdKey(widgetId), habitId).commit(); prefs.edit().putLong(BaseWidgetProvider.getHabitIdKey(widgetId), habitId).commit();
MainActivity.updateWidgets(this); WidgetManager.updateWidgets(this);
Intent resultValue = new Intent(); Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);

@ -0,0 +1,47 @@
/*
* 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.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);
}
}
Loading…
Cancel
Save