mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Move ExportCSVTask to uhabits-core
This commit is contained in:
@@ -33,8 +33,8 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
targetCompatibility 1.8
|
||||
sourceCompatibility 1.8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
testOptions {
|
||||
@@ -52,7 +52,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation project(":uhabits-core")
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:25.3.1'
|
||||
@@ -61,7 +60,6 @@ dependencies {
|
||||
implementation 'com.android.support:support-v4:25.3.1'
|
||||
implementation 'com.getpebble:pebblekit:3.0.0'
|
||||
implementation 'com.github.paolorotolo:appintro:3.4.0'
|
||||
implementation 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||
implementation 'com.google.dagger:dagger:2.11-rc2'
|
||||
implementation 'com.jakewharton:butterknife:8.6.1-SNAPSHOT'
|
||||
implementation 'com.michaelpardo:activeandroid:3.1.0-SNAPSHOT'
|
||||
@@ -75,18 +73,21 @@ dependencies {
|
||||
testImplementation 'org.hamcrest:hamcrest-library:1.4-atlassian-1'
|
||||
testImplementation 'org.mockito:mockito-core:2.8.9'
|
||||
testImplementation 'org.json:json:20160810'
|
||||
|
||||
testImplementation 'org.robolectric:robolectric:3.4-rc2'
|
||||
|
||||
androidTestImplementation 'com.android.support:support-annotations:25.3.1'
|
||||
androidTestImplementation 'com.android.support.test:rules:0.5'
|
||||
androidTestImplementation 'com.android.support.test:runner:0.5'
|
||||
androidTestImplementation 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||
androidTestImplementation "com.google.dexmaker:dexmaker:1.2"
|
||||
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
|
||||
androidTestImplementation 'org.mockito:mockito-core:1.10.19'
|
||||
androidTestImplementation 'com.google.guava:guava:20.0'
|
||||
|
||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||
compileOnly 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||
|
||||
androidTestCompileOnly 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||
|
||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.11-rc2'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.1-SNAPSHOT'
|
||||
@@ -99,12 +100,10 @@ dependencies {
|
||||
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.11-rc2'
|
||||
androidTestAnnotationProcessor 'com.google.auto.factory:auto-factory:1.0-beta3'
|
||||
androidTestAnnotationProcessor 'com.jakewharton:butterknife-compiler:8.6.1-SNAPSHOT'
|
||||
|
||||
implementation ('com.opencsv:opencsv:3.9') {
|
||||
implementation('com.opencsv:opencsv:3.9') {
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
}
|
||||
|
||||
implementation ('io.socket:socket.io-client:+') {
|
||||
implementation('io.socket:socket.io-client:+') {
|
||||
exclude group: 'org.json', module: 'json'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.support.test.*;
|
||||
import android.util.*;
|
||||
|
||||
import org.isoron.androidbase.*;
|
||||
import org.isoron.androidbase.activities.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
@@ -68,6 +69,8 @@ public class BaseAndroidTest
|
||||
|
||||
protected ModelFactory modelFactory;
|
||||
|
||||
protected BaseSystem baseSystem;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
@@ -90,6 +93,8 @@ public class BaseAndroidTest
|
||||
.appModule(new AppModule(targetContext.getApplicationContext()))
|
||||
.build();
|
||||
|
||||
baseSystem = new BaseSystem(targetContext);
|
||||
|
||||
HabitsApplication.setComponent(component);
|
||||
prefs = component.getPreferences();
|
||||
habitList = component.getHabitList();
|
||||
|
||||
@@ -24,6 +24,8 @@ import android.support.annotation.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.androidbase.activities.*;
|
||||
import org.isoron.androidbase.utils.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
|
||||
@@ -170,7 +172,7 @@ public class BaseViewTest extends BaseAndroidTest
|
||||
{
|
||||
File dir = FileUtils.getSDCardDir("test-screenshots");
|
||||
if (dir == null)
|
||||
dir = FileUtils.getFilesDir(targetContext, "test-screenshots");
|
||||
dir = baseSystem.getFilesDir("test-screenshots");
|
||||
if (dir == null) throw new RuntimeException(
|
||||
"Could not find suitable dir for screenshots");
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ import android.support.test.*;
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
|
||||
import org.isoron.androidbase.utils.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.support.test.*;
|
||||
import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
|
||||
import org.isoron.androidbase.utils.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
@@ -54,9 +54,11 @@ public class ExportCSVTaskTest extends BaseAndroidTest
|
||||
|
||||
List<Habit> selected = new LinkedList<>();
|
||||
for (Habit h : habitList) selected.add(h);
|
||||
File outputDir = baseSystem.getFilesDir("CSV");
|
||||
assertNotNull(outputDir);
|
||||
|
||||
taskRunner.execute(
|
||||
new ExportCSVTask(targetContext,habitList, selected, archiveFilename -> {
|
||||
new ExportCSVTask(habitList, selected, outputDir, archiveFilename -> {
|
||||
assertThat(archiveFilename, is(not(nullValue())));
|
||||
File f = new File(archiveFilename);
|
||||
assertTrue(f.exists());
|
||||
|
||||
@@ -23,20 +23,19 @@ import android.support.test.runner.*;
|
||||
import android.test.suitebuilder.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.tasks.android.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class ExportDBTaskTest extends BaseAndroidTest
|
||||
{
|
||||
@Override
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
@@ -46,13 +45,13 @@ public class ExportDBTaskTest extends BaseAndroidTest
|
||||
@Test
|
||||
public void testExportCSV() throws Throwable
|
||||
{
|
||||
ExportDBTask task = new ExportDBTask(targetContext, filename -> {
|
||||
assertThat(filename, is(not(nullValue())));
|
||||
|
||||
File f = new File(filename);
|
||||
assertTrue(f.exists());
|
||||
assertTrue(f.canRead());
|
||||
});
|
||||
ExportDBTask task =
|
||||
new ExportDBTask(targetContext, baseSystem, filename -> {
|
||||
assertNotNull(filename);
|
||||
File f = new File(filename);
|
||||
assertTrue(f.exists());
|
||||
assertTrue(f.canRead());
|
||||
});
|
||||
|
||||
taskRunner.execute(task);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,12 @@ public abstract class BaseMenu
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public BaseActivity getActivity()
|
||||
{
|
||||
return activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare that the menu has changed, and should be recreated.
|
||||
*/
|
||||
|
||||
@@ -22,8 +22,11 @@ package org.isoron.androidbase.activities;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.support.v4.content.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
|
||||
import org.isoron.androidbase.utils.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
@@ -52,6 +55,19 @@ public class BaseSystem
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public File getFilesDir(@Nullable String relativePath)
|
||||
{
|
||||
File externalFilesDirs[] = ContextCompat.getExternalFilesDirs(context, null);
|
||||
if (externalFilesDirs == null)
|
||||
{
|
||||
Log.e("BaseSystem", "getFilesDir: getExternalFilesDirs returned null");
|
||||
return null;
|
||||
}
|
||||
|
||||
return FileUtils.getDir(externalFilesDirs, relativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures a bug report and saves it to a file in the SD card.
|
||||
* <p>
|
||||
@@ -70,7 +86,7 @@ public class BaseSystem
|
||||
|
||||
if (context == null) throw new RuntimeException(
|
||||
"application context should not be null");
|
||||
File dir = FileUtils.getFilesDir(context, "Logs");
|
||||
File dir = getFilesDir("Logs");
|
||||
if (dir == null) throw new IOException("log dir should not be null");
|
||||
|
||||
File logFile =
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
@@ -17,12 +17,10 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.utils;
|
||||
package org.isoron.androidbase.utils;
|
||||
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.support.v4.content.*;
|
||||
import android.util.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -52,8 +50,8 @@ public abstract class FileUtils
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static File getDir(@NonNull File potentialParentDirs[],
|
||||
@Nullable String relativePath)
|
||||
public static File getDir(@NonNull File potentialParentDirs[],
|
||||
@Nullable String relativePath)
|
||||
{
|
||||
if (relativePath == null) relativePath = "";
|
||||
|
||||
@@ -67,7 +65,7 @@ public abstract class FileUtils
|
||||
|
||||
if (chosenDir == null)
|
||||
{
|
||||
Log.e("DatabaseHelper",
|
||||
Log.e("FileUtils",
|
||||
"getDir: all potential parents are null or non-writable");
|
||||
return null;
|
||||
}
|
||||
@@ -76,7 +74,7 @@ public abstract class FileUtils
|
||||
String.format("%s/%s/", chosenDir.getAbsolutePath(), relativePath));
|
||||
if (!dir.exists() && !dir.mkdirs())
|
||||
{
|
||||
Log.e("DatabaseHelper",
|
||||
Log.e("FileUtils",
|
||||
"getDir: chosen dir does not exist and cannot be created");
|
||||
return null;
|
||||
}
|
||||
@@ -84,22 +82,6 @@ public abstract class FileUtils
|
||||
return dir;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getFilesDir(@NonNull Context context, @Nullable String relativePath)
|
||||
{
|
||||
File externalFilesDirs[] =
|
||||
ContextCompat.getExternalFilesDirs(context, null);
|
||||
|
||||
if (externalFilesDirs == null)
|
||||
{
|
||||
Log.e("DatabaseHelper",
|
||||
"getFilesDir: getExternalFilesDirs returned null");
|
||||
return null;
|
||||
}
|
||||
|
||||
return getDir(externalFilesDirs, relativePath);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getSDCardDir(@Nullable String relativePath)
|
||||
{
|
||||
@@ -32,6 +32,7 @@ import org.isoron.uhabits.notifications.*;
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.sync.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
import org.isoron.uhabits.tasks.android.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.isoron.uhabits.commands.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.preferences.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
import org.isoron.uhabits.tasks.android.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.isoron.uhabits.widgets.*;
|
||||
|
||||
@@ -105,11 +106,13 @@ public class ListHabitsController
|
||||
{
|
||||
List<Habit> selected = new LinkedList<>();
|
||||
for (Habit h : habitList) selected.add(h);
|
||||
File outputDir = system.getFilesDir("CSV");
|
||||
|
||||
taskRunner.execute(exportCSVFactory.create(selected, filename -> {
|
||||
if (filename != null) screen.showSendFileScreen(filename);
|
||||
else screen.showMessage(R.string.could_not_export);
|
||||
}));
|
||||
taskRunner.execute(
|
||||
exportCSVFactory.create(selected, outputDir, filename -> {
|
||||
if (filename != null) screen.showSendFileScreen(filename);
|
||||
else screen.showMessage(R.string.could_not_export);
|
||||
}));
|
||||
}
|
||||
|
||||
public void onExportDB()
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
import org.isoron.androidbase.activities.*;
|
||||
import org.isoron.androidbase.utils.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.activities.*;
|
||||
import org.isoron.uhabits.activities.common.dialogs.*;
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.inject.*;
|
||||
@@ -34,6 +35,9 @@ import javax.inject.*;
|
||||
@ActivityScope
|
||||
public class ShowHabitsMenu extends BaseMenu
|
||||
{
|
||||
@NonNull
|
||||
private final BaseSystem system;
|
||||
|
||||
@NonNull
|
||||
private final ShowHabitScreen screen;
|
||||
|
||||
@@ -48,12 +52,14 @@ public class ShowHabitsMenu extends BaseMenu
|
||||
|
||||
@Inject
|
||||
public ShowHabitsMenu(@NonNull BaseActivity activity,
|
||||
@NonNull BaseSystem system,
|
||||
@NonNull ShowHabitScreen screen,
|
||||
@NonNull Habit habit,
|
||||
@NonNull ExportCSVTaskFactory exportCSVFactory,
|
||||
@NonNull TaskRunner taskRunner)
|
||||
{
|
||||
super(activity);
|
||||
this.system = system;
|
||||
this.screen = screen;
|
||||
this.habit = habit;
|
||||
this.taskRunner = taskRunner;
|
||||
@@ -64,7 +70,9 @@ public class ShowHabitsMenu extends BaseMenu
|
||||
{
|
||||
List<Habit> selected = new LinkedList<>();
|
||||
selected.add(habit);
|
||||
ExportCSVTask task = exportCSVFactory.create(selected, filename -> {
|
||||
File outputDir = system.getFilesDir("CSV");
|
||||
ExportCSVTask task = exportCSVFactory.create(selected,
|
||||
outputDir, filename -> {
|
||||
if (filename != null) screen.showSendFileScreen(filename);
|
||||
else screen.showMessage(R.string.could_not_export);
|
||||
});
|
||||
|
||||
@@ -68,41 +68,41 @@ public class CommandParser
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Command parse(@NonNull JSONObject json) throws JSONException
|
||||
public Command parse(@NonNull String json) throws JSONException
|
||||
{
|
||||
String event = json.getString("event");
|
||||
String event = new JSONObject(json).getString("event");
|
||||
Gson gson = new GsonBuilder().create();
|
||||
|
||||
if (event.equals("Archive")) return gson
|
||||
.fromJson(json.toString(), ArchiveHabitsCommand.Record.class)
|
||||
.fromJson(json, ArchiveHabitsCommand.Record.class)
|
||||
.toCommand(habitList);
|
||||
|
||||
if (event.equals("ChangeColor")) return gson
|
||||
.fromJson(json.toString(), ChangeHabitColorCommand.Record.class)
|
||||
.fromJson(json, ChangeHabitColorCommand.Record.class)
|
||||
.toCommand(habitList);
|
||||
|
||||
if (event.equals("CreateHabit")) return gson
|
||||
.fromJson(json.toString(), CreateHabitCommand.Record.class)
|
||||
.fromJson(json, CreateHabitCommand.Record.class)
|
||||
.toCommand(modelFactory, habitList);
|
||||
|
||||
if (event.equals("CreateRep")) return gson
|
||||
.fromJson(json.toString(), CreateRepetitionCommand.Record.class)
|
||||
.fromJson(json, CreateRepetitionCommand.Record.class)
|
||||
.toCommand(habitList);
|
||||
|
||||
if (event.equals("DeleteHabit")) return gson
|
||||
.fromJson(json.toString(), DeleteHabitsCommand.Record.class)
|
||||
.fromJson(json, DeleteHabitsCommand.Record.class)
|
||||
.toCommand(habitList);
|
||||
|
||||
if (event.equals("EditHabit")) return gson
|
||||
.fromJson(json.toString(), EditHabitCommand.Record.class)
|
||||
.fromJson(json, EditHabitCommand.Record.class)
|
||||
.toCommand(modelFactory, habitList);
|
||||
|
||||
if (event.equals("Toggle")) return gson
|
||||
.fromJson(json.toString(), ToggleRepetitionCommand.Record.class)
|
||||
.fromJson(json, ToggleRepetitionCommand.Record.class)
|
||||
.toCommand(habitList);
|
||||
|
||||
if (event.equals("Unarchive")) return gson
|
||||
.fromJson(json.toString(), UnarchiveHabitsCommand.Record.class)
|
||||
.fromJson(json, UnarchiveHabitsCommand.Record.class)
|
||||
.toCommand(habitList);
|
||||
|
||||
throw new IllegalStateException("Unknown command");
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.io;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
* Class that exports the application data to CSV files.
|
||||
*/
|
||||
public class HabitsCSVExporter
|
||||
{
|
||||
private List<Habit> selectedHabits;
|
||||
|
||||
private List<String> generateDirs;
|
||||
|
||||
private List<String> generateFilenames;
|
||||
|
||||
private String exportDirName;
|
||||
/**
|
||||
* Delimiter used in a CSV file.
|
||||
*/
|
||||
private final String DELIMITER = ",";
|
||||
|
||||
@NonNull
|
||||
private final HabitList allHabits;
|
||||
|
||||
public HabitsCSVExporter(@NonNull HabitList allHabits,
|
||||
@NonNull List<Habit> selectedHabits,
|
||||
@NonNull File dir)
|
||||
{
|
||||
this.allHabits = allHabits;
|
||||
this.selectedHabits = selectedHabits;
|
||||
this.exportDirName = dir.getAbsolutePath() + "/";
|
||||
|
||||
generateDirs = new LinkedList<>();
|
||||
generateFilenames = new LinkedList<>();
|
||||
}
|
||||
|
||||
public String writeArchive() throws IOException
|
||||
{
|
||||
String zipFilename;
|
||||
|
||||
writeHabits();
|
||||
zipFilename = writeZipFile();
|
||||
cleanup();
|
||||
|
||||
return zipFilename;
|
||||
}
|
||||
|
||||
private void addFileToZip(ZipOutputStream zos, String filename)
|
||||
throws IOException
|
||||
{
|
||||
FileInputStream fis =
|
||||
new FileInputStream(new File(exportDirName + filename));
|
||||
ZipEntry ze = new ZipEntry(filename);
|
||||
zos.putNextEntry(ze);
|
||||
|
||||
int length;
|
||||
byte bytes[] = new byte[1024];
|
||||
while ((length = fis.read(bytes)) >= 0) zos.write(bytes, 0, length);
|
||||
|
||||
zos.closeEntry();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
private void cleanup()
|
||||
{
|
||||
for (String filename : generateFilenames)
|
||||
new File(exportDirName + filename).delete();
|
||||
|
||||
for (String filename : generateDirs)
|
||||
new File(exportDirName + filename).delete();
|
||||
|
||||
new File(exportDirName).delete();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String sanitizeFilename(String name)
|
||||
{
|
||||
String s = name.replaceAll("[^ a-zA-Z0-9\\._-]+", "");
|
||||
return s.substring(0, Math.min(s.length(), 100));
|
||||
}
|
||||
|
||||
private void writeHabits() throws IOException
|
||||
{
|
||||
String filename = "Habits.csv";
|
||||
new File(exportDirName).mkdirs();
|
||||
FileWriter out = new FileWriter(exportDirName + filename);
|
||||
generateFilenames.add(filename);
|
||||
allHabits.writeCSV(out);
|
||||
out.close();
|
||||
|
||||
for (Habit h : selectedHabits)
|
||||
{
|
||||
String sane = sanitizeFilename(h.getName());
|
||||
String habitDirName =
|
||||
String.format("%03d %s", allHabits.indexOf(h) + 1, sane);
|
||||
habitDirName = habitDirName.trim() + "/";
|
||||
|
||||
new File(exportDirName + habitDirName).mkdirs();
|
||||
generateDirs.add(habitDirName);
|
||||
|
||||
writeScores(habitDirName, h.getScores());
|
||||
writeCheckmarks(habitDirName, h.getCheckmarks());
|
||||
}
|
||||
|
||||
writeMultipleHabits();
|
||||
}
|
||||
|
||||
private void writeScores(String habitDirName, ScoreList scores)
|
||||
throws IOException
|
||||
{
|
||||
String path = habitDirName + "Scores.csv";
|
||||
FileWriter out = new FileWriter(exportDirName + path);
|
||||
generateFilenames.add(path);
|
||||
scores.writeCSV(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void writeCheckmarks(String habitDirName, CheckmarkList checkmarks)
|
||||
throws IOException
|
||||
{
|
||||
String filename = habitDirName + "Checkmarks.csv";
|
||||
FileWriter out = new FileWriter(exportDirName + filename);
|
||||
generateFilenames.add(filename);
|
||||
checkmarks.writeCSV(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a scores file and a checkmarks file containing scores and checkmarks of every habit.
|
||||
* The first column corresponds to the date. Subsequent columns correspond to a habit.
|
||||
* Habits are taken from the list of selected habits.
|
||||
* Dates are determined from the oldest repetition date to the newest repetition date found in
|
||||
* the list of habits.
|
||||
*
|
||||
* @throws IOException if there was problem writing the files
|
||||
*/
|
||||
private void writeMultipleHabits() throws IOException
|
||||
{
|
||||
String scoresFileName = "Scores.csv";
|
||||
String checksFileName = "Checkmarks.csv";
|
||||
generateFilenames.add(scoresFileName);
|
||||
generateFilenames.add(checksFileName);
|
||||
FileWriter scoresWriter = new FileWriter(exportDirName + scoresFileName);
|
||||
FileWriter checksWriter = new FileWriter(exportDirName + checksFileName);
|
||||
|
||||
writeMultipleHabitsHeader(scoresWriter);
|
||||
writeMultipleHabitsHeader(checksWriter);
|
||||
|
||||
long[] timeframe = getTimeframe();
|
||||
long oldest = timeframe[0];
|
||||
long newest = DateUtils.getStartOfToday();
|
||||
|
||||
List<int[]> checkmarks = new ArrayList<>();
|
||||
List<double[]> scores = new ArrayList<>();
|
||||
for (Habit h : selectedHabits)
|
||||
{
|
||||
checkmarks.add(h.getCheckmarks().getValues(oldest, newest));
|
||||
scores.add(h.getScores().getValues(oldest, newest));
|
||||
}
|
||||
|
||||
int days = DateUtils.getDaysBetween(oldest, newest);
|
||||
SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat();
|
||||
for (int i = 0; i <= days; i++)
|
||||
{
|
||||
Date day = new Date(newest - i * DateUtils.millisecondsInOneDay);
|
||||
|
||||
String date = dateFormat.format(day);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(date).append(DELIMITER);
|
||||
checksWriter.write(sb.toString());
|
||||
scoresWriter.write(sb.toString());
|
||||
|
||||
for(int j = 0; j < selectedHabits.size(); j++)
|
||||
{
|
||||
checksWriter.write(String.valueOf(checkmarks.get(j)[i]));
|
||||
checksWriter.write(DELIMITER);
|
||||
String score =
|
||||
String.format("%.4f", ((float) scores.get(j)[i]));
|
||||
scoresWriter.write(score);
|
||||
scoresWriter.write(DELIMITER);
|
||||
}
|
||||
checksWriter.write("\n");
|
||||
scoresWriter.write("\n");
|
||||
}
|
||||
scoresWriter.close();
|
||||
checksWriter.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the first row, containing header information, using the given writer.
|
||||
* This consists of the date title and the names of the selected habits.
|
||||
*
|
||||
* @param out the writer to use
|
||||
* @throws IOException if there was a problem writing
|
||||
*/
|
||||
private void writeMultipleHabitsHeader(Writer out) throws IOException
|
||||
{
|
||||
out.write("Date" + DELIMITER);
|
||||
for (Habit h : selectedHabits) {
|
||||
out.write(h.getName());
|
||||
out.write(DELIMITER);
|
||||
}
|
||||
out.write("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the overall timeframe of the selected habits.
|
||||
* The timeframe is an array containing the oldest timestamp among the habits and the
|
||||
* newest timestamp among the habits.
|
||||
* Both timestamps are in milliseconds.
|
||||
*
|
||||
* @return the timeframe containing the oldest timestamp and the newest timestamp
|
||||
*/
|
||||
private long[] getTimeframe()
|
||||
{
|
||||
long oldest = Long.MAX_VALUE;
|
||||
long newest = -1;
|
||||
for (Habit h : selectedHabits)
|
||||
{
|
||||
if(h.getRepetitions().getOldest() == null || h.getRepetitions().getNewest() == null)
|
||||
continue;
|
||||
long currOld = h.getRepetitions().getOldest().getTimestamp();
|
||||
long currNew = h.getRepetitions().getNewest().getTimestamp();
|
||||
oldest = currOld > oldest ? oldest : currOld;
|
||||
newest = currNew < newest ? newest : currNew;
|
||||
}
|
||||
return new long[]{oldest, newest};
|
||||
}
|
||||
|
||||
private String writeZipFile() throws IOException
|
||||
{
|
||||
SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat();
|
||||
String date = dateFormat.format(DateUtils.getStartOfToday());
|
||||
String zipFilename =
|
||||
String.format("%s/Loop Habits CSV %s.zip", exportDirName, date);
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(zipFilename);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos);
|
||||
|
||||
for (String filename : generateFilenames)
|
||||
addFileToZip(zos, filename);
|
||||
|
||||
zos.close();
|
||||
fos.close();
|
||||
|
||||
return zipFilename;
|
||||
}
|
||||
}
|
||||
@@ -28,10 +28,10 @@ import android.util.*;
|
||||
import com.activeandroid.*;
|
||||
|
||||
import org.isoron.androidbase.*;
|
||||
import org.isoron.androidbase.utils.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.DatabaseUtils;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ public class SyncManager implements CommandRunner.Listener
|
||||
|
||||
private void executeCommand(JSONObject root) throws JSONException
|
||||
{
|
||||
Command received = commandParser.parse(root);
|
||||
Command received = commandParser.parse(root.toString());
|
||||
received.setRemote(true);
|
||||
|
||||
for (Event e : pendingConfirmation)
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.tasks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.*;
|
||||
|
||||
import com.google.auto.factory.*;
|
||||
|
||||
import org.isoron.androidbase.AppContext;
|
||||
import org.isoron.uhabits.io.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
@AutoFactory(allowSubclasses = true)
|
||||
public class ExportCSVTask implements Task
|
||||
{
|
||||
private String archiveFilename;
|
||||
|
||||
@NonNull
|
||||
private final Context context;
|
||||
|
||||
@NonNull
|
||||
private final List<Habit> selectedHabits;
|
||||
|
||||
@NonNull
|
||||
private final ExportCSVTask.Listener listener;
|
||||
|
||||
@NonNull
|
||||
private final HabitList habitList;
|
||||
|
||||
public ExportCSVTask(@Provided @AppContext @NonNull Context context,
|
||||
@Provided @NonNull HabitList habitList,
|
||||
@NonNull List<Habit> selectedHabits,
|
||||
@NonNull Listener listener)
|
||||
{
|
||||
this.context = context;
|
||||
this.listener = listener;
|
||||
this.habitList = habitList;
|
||||
this.selectedHabits = selectedHabits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doInBackground()
|
||||
{
|
||||
try
|
||||
{
|
||||
File dir = FileUtils.getFilesDir(context, "CSV");
|
||||
if (dir == null) return;
|
||||
|
||||
HabitsCSVExporter exporter;
|
||||
exporter = new HabitsCSVExporter(habitList, selectedHabits, dir);
|
||||
archiveFilename = exporter.writeArchive();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute()
|
||||
{
|
||||
listener.onExportCSVFinished(archiveFilename);
|
||||
}
|
||||
|
||||
public interface Listener
|
||||
{
|
||||
void onExportCSVFinished(@Nullable String archiveFilename);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
@@ -17,11 +17,12 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.tasks;
|
||||
package org.isoron.uhabits.tasks.android;
|
||||
|
||||
import android.os.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
@@ -17,15 +17,16 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.tasks;
|
||||
package org.isoron.uhabits.tasks.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.*;
|
||||
import android.support.annotation.*;
|
||||
|
||||
import com.google.auto.factory.AutoFactory;
|
||||
import com.google.auto.factory.Provided;
|
||||
import com.google.auto.factory.*;
|
||||
|
||||
import org.isoron.androidbase.AppContext;
|
||||
import org.isoron.androidbase.*;
|
||||
import org.isoron.androidbase.activities.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -38,11 +39,16 @@ public class ExportDBTask implements Task
|
||||
@NonNull
|
||||
private Context context;
|
||||
|
||||
private BaseSystem system;
|
||||
|
||||
@NonNull
|
||||
private final Listener listener;
|
||||
|
||||
public ExportDBTask(@Provided @AppContext @NonNull Context context, @NonNull Listener listener)
|
||||
public ExportDBTask(@Provided @AppContext @NonNull Context context,
|
||||
@Provided @NonNull BaseSystem system,
|
||||
@NonNull Listener listener)
|
||||
{
|
||||
this.system = system;
|
||||
this.listener = listener;
|
||||
this.context = context;
|
||||
}
|
||||
@@ -54,7 +60,7 @@ public class ExportDBTask implements Task
|
||||
|
||||
try
|
||||
{
|
||||
File dir = FileUtils.getFilesDir(context, "Backups");
|
||||
File dir = system.getFilesDir("Backups");
|
||||
if (dir == null) return;
|
||||
|
||||
filename = DatabaseUtils.saveDatabaseCopy(context, dir);
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
@@ -17,13 +17,14 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.tasks;
|
||||
package org.isoron.uhabits.tasks.android;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
import com.google.auto.factory.*;
|
||||
|
||||
import org.isoron.uhabits.io.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
@@ -21,4 +21,4 @@
|
||||
* Provides async tasks for useful operations such as {@link
|
||||
* org.isoron.uhabits.tasks.ExportCSVTask}.
|
||||
*/
|
||||
package org.isoron.uhabits.tasks;
|
||||
package org.isoron.uhabits.tasks.android;
|
||||
@@ -24,6 +24,7 @@ import android.support.annotation.*;
|
||||
|
||||
import com.activeandroid.*;
|
||||
|
||||
import org.isoron.androidbase.utils.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.sqlite.*;
|
||||
import org.isoron.uhabits.models.sqlite.records.*;
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.isoron.uhabits.activities.habits.show;
|
||||
|
||||
import android.view.*;
|
||||
|
||||
import org.isoron.androidbase.activities.*;
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.models.*;
|
||||
import org.isoron.uhabits.tasks.*;
|
||||
@@ -43,19 +44,20 @@ public class ShowHabitsMenuTest extends BaseUnitTest
|
||||
|
||||
private TaskRunner taskRunner;
|
||||
|
||||
private ExportCSVTask task;
|
||||
private BaseSystem system;
|
||||
|
||||
@Override
|
||||
public void setUp()
|
||||
{
|
||||
super.setUp();
|
||||
activity = mock(ShowHabitActivity.class);
|
||||
system = mock(BaseSystem.class);
|
||||
screen = mock(ShowHabitScreen.class);
|
||||
habit = mock(Habit.class);
|
||||
exportCSVFactory = mock(ExportCSVTaskFactory.class);
|
||||
taskRunner = mock(TaskRunner.class);
|
||||
menu = new ShowHabitsMenu(activity, screen, habit, exportCSVFactory,
|
||||
taskRunner);
|
||||
menu = new ShowHabitsMenu(activity, system, screen, habit,
|
||||
exportCSVFactory, taskRunner);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user