mirror of https://github.com/iSoron/uhabits.git
parent
ced78e0b1f
commit
79b134164a
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.io;
|
||||
|
||||
import androidx.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* AbstractImporter is the base class for all classes that import data from
|
||||
* files into the app.
|
||||
*/
|
||||
public abstract class AbstractImporter
|
||||
{
|
||||
protected final HabitList habitList;
|
||||
|
||||
public AbstractImporter(HabitList habitList)
|
||||
{
|
||||
this.habitList = habitList;
|
||||
}
|
||||
|
||||
public abstract boolean canHandle(@NonNull File file) throws IOException;
|
||||
|
||||
public abstract void importHabitsFromFile(@NonNull File file) throws IOException;
|
||||
|
||||
public static boolean isSQLite3File(@NonNull File file) throws IOException
|
||||
{
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
|
||||
byte[] sqliteHeader = "SQLite format 3".getBytes();
|
||||
byte[] buffer = new byte[sqliteHeader.length];
|
||||
|
||||
int count = fis.read(buffer);
|
||||
if(count < sqliteHeader.length) return false;
|
||||
|
||||
return Arrays.equals(buffer, sqliteHeader);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.isoron.uhabits.core.io
|
||||
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractImporter {
|
||||
abstract fun canHandle(file: File): Boolean
|
||||
abstract fun importHabitsFromFile(file: File)
|
||||
}
|
@ -1,293 +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.core.io;
|
||||
|
||||
import androidx.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.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(Locale.US, "%03d %s", allHabits.indexOf(h) + 1, sane);
|
||||
habitDirName = habitDirName.trim() + "/";
|
||||
|
||||
new File(exportDirName + habitDirName).mkdirs();
|
||||
generateDirs.add(habitDirName);
|
||||
|
||||
writeScores(habitDirName, h);
|
||||
writeEntries(habitDirName, h.getComputedEntries());
|
||||
}
|
||||
|
||||
writeMultipleHabits();
|
||||
}
|
||||
|
||||
private void writeScores(String habitDirName, Habit habit)
|
||||
throws IOException
|
||||
{
|
||||
String path = habitDirName + "Scores.csv";
|
||||
FileWriter out = new FileWriter(exportDirName + path);
|
||||
generateFilenames.add(path);
|
||||
SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat();
|
||||
|
||||
Timestamp today = DateUtils.getTodayWithOffset();
|
||||
Timestamp oldest = today;
|
||||
List<Entry> known = habit.getComputedEntries().getKnown();
|
||||
if(!known.isEmpty()) oldest = known.get(known.size() - 1).getTimestamp();
|
||||
|
||||
for (Score s : habit.getScores().getByInterval(oldest, today))
|
||||
{
|
||||
String timestamp = dateFormat.format(s.getTimestamp().getUnixTime());
|
||||
String score = String.format(Locale.US, "%.4f", s.getValue());
|
||||
out.write(String.format("%s,%s\n", timestamp, score));
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void writeEntries(String habitDirName, EntryList entries)
|
||||
throws IOException
|
||||
{
|
||||
String filename = habitDirName + "Checkmarks.csv";
|
||||
FileWriter out = new FileWriter(exportDirName + filename);
|
||||
generateFilenames.add(filename);
|
||||
|
||||
SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat();
|
||||
for (Entry e : entries.getKnown())
|
||||
{
|
||||
String date = dateFormat.format(e.getTimestamp().toJavaDate());
|
||||
out.write(String.format(Locale.US, "%s,%d\n", date, e.getValue()));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Timestamp[] timeframe = getTimeframe();
|
||||
Timestamp oldest = timeframe[0];
|
||||
Timestamp newest = DateUtils.getToday();
|
||||
|
||||
List<int[]> checkmarks = new ArrayList<>();
|
||||
List<ArrayList<Score>> scores = new ArrayList<>();
|
||||
for (Habit h : selectedHabits)
|
||||
{
|
||||
checkmarks.add(h.getComputedEntries().getValues(oldest, newest));
|
||||
scores.add(new ArrayList<>(h.getScores().getByInterval(oldest, newest)));
|
||||
}
|
||||
|
||||
int days = oldest.daysUntil(newest);
|
||||
SimpleDateFormat dateFormat = DateFormats.getCSVDateFormat();
|
||||
for (int i = 0; i <= days; i++)
|
||||
{
|
||||
Date day = newest.minus(i).toJavaDate();
|
||||
|
||||
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(Locale.US, "%.4f", scores.get(j).get(i).getValue());
|
||||
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 Timestamp[] getTimeframe()
|
||||
{
|
||||
Timestamp oldest = Timestamp.ZERO.plus(1000000);
|
||||
Timestamp newest = Timestamp.ZERO;
|
||||
for (Habit h : selectedHabits)
|
||||
{
|
||||
List<Entry> entries = h.getOriginalEntries().getKnown();
|
||||
if (entries.isEmpty()) continue;
|
||||
Timestamp currNew = entries.get(0).getTimestamp();
|
||||
Timestamp currOld = entries.get(entries.size() - 1).getTimestamp();
|
||||
oldest = currOld.isOlderThan(oldest) ? currOld : oldest;
|
||||
newest = currNew.isNewerThan(newest) ? currNew : newest;
|
||||
}
|
||||
return new Timestamp[]{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;
|
||||
}
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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.core.io
|
||||
|
||||
import org.isoron.uhabits.core.models.EntryList
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.Score
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.utils.DateFormats
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.FileWriter
|
||||
import java.io.IOException
|
||||
import java.io.Writer
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedList
|
||||
import java.util.Locale
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
/**
|
||||
* Class that exports the application data to CSV files.
|
||||
*/
|
||||
class HabitsCSVExporter(
|
||||
private val allHabits: HabitList,
|
||||
private val selectedHabits: List<Habit>,
|
||||
dir: File
|
||||
) {
|
||||
private val generatedDirs = LinkedList<String>()
|
||||
private val generatedFilenames = LinkedList<String>()
|
||||
private val exportDirName: String = dir.absolutePath + "/"
|
||||
private val delimiter = ","
|
||||
|
||||
fun writeArchive(): String {
|
||||
writeHabits()
|
||||
val zipFilename = writeZipFile()
|
||||
cleanup()
|
||||
return zipFilename
|
||||
}
|
||||
|
||||
private fun addFileToZip(zos: ZipOutputStream, filename: String) {
|
||||
val fis = FileInputStream(File(exportDirName + filename))
|
||||
val ze = ZipEntry(filename)
|
||||
zos.putNextEntry(ze)
|
||||
var length: Int
|
||||
val bytes = ByteArray(1024)
|
||||
while (fis.read(bytes).also { length = it } >= 0) zos.write(bytes, 0, length)
|
||||
zos.closeEntry()
|
||||
fis.close()
|
||||
}
|
||||
|
||||
private fun cleanup() {
|
||||
for (filename in generatedFilenames) File(exportDirName + filename).delete()
|
||||
for (filename in generatedDirs) File(exportDirName + filename).delete()
|
||||
File(exportDirName).delete()
|
||||
}
|
||||
|
||||
private fun sanitizeFilename(name: String): String {
|
||||
val s = name.replace("[^ a-zA-Z0-9\\._-]+".toRegex(), "")
|
||||
return s.substring(0, Math.min(s.length, 100))
|
||||
}
|
||||
|
||||
private fun writeHabits() {
|
||||
val filename = "Habits.csv"
|
||||
File(exportDirName).mkdirs()
|
||||
val out = FileWriter(exportDirName + filename)
|
||||
generatedFilenames.add(filename)
|
||||
allHabits.writeCSV(out)
|
||||
out.close()
|
||||
for (h in selectedHabits) {
|
||||
val sane = sanitizeFilename(h.name)
|
||||
var habitDirName = String.format(Locale.US, "%03d %s", allHabits.indexOf(h) + 1, sane)
|
||||
habitDirName = habitDirName.trim() + "/"
|
||||
File(exportDirName + habitDirName).mkdirs()
|
||||
generatedDirs.add(habitDirName)
|
||||
writeScores(habitDirName, h)
|
||||
writeEntries(habitDirName, h.computedEntries)
|
||||
}
|
||||
writeMultipleHabits()
|
||||
}
|
||||
|
||||
private fun writeScores(habitDirName: String, habit: Habit) {
|
||||
val path = habitDirName + "Scores.csv"
|
||||
val out = FileWriter(exportDirName + path)
|
||||
generatedFilenames.add(path)
|
||||
val dateFormat = DateFormats.getCSVDateFormat()
|
||||
val today = DateUtils.getTodayWithOffset()
|
||||
var oldest = today
|
||||
val known = habit.computedEntries.getKnown()
|
||||
if (known.isNotEmpty()) oldest = known[known.size - 1].timestamp
|
||||
for ((timestamp1, value) in habit.scores.getByInterval(oldest, today)) {
|
||||
val timestamp = dateFormat.format(timestamp1.unixTime)
|
||||
val score = String.format(Locale.US, "%.4f", value)
|
||||
out.write(String.format("%s,%s\n", timestamp, score))
|
||||
}
|
||||
out.close()
|
||||
}
|
||||
|
||||
private fun writeEntries(habitDirName: String, entries: EntryList) {
|
||||
val filename = habitDirName + "Checkmarks.csv"
|
||||
val out = FileWriter(exportDirName + filename)
|
||||
generatedFilenames.add(filename)
|
||||
val dateFormat = DateFormats.getCSVDateFormat()
|
||||
for ((timestamp, value) in entries.getKnown()) {
|
||||
val date = dateFormat.format(timestamp.toJavaDate())
|
||||
out.write(String.format(Locale.US, "%s,%d\n", date, value))
|
||||
}
|
||||
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.
|
||||
*/
|
||||
private fun writeMultipleHabits() {
|
||||
val scoresFileName = "Scores.csv"
|
||||
val checksFileName = "Checkmarks.csv"
|
||||
generatedFilenames.add(scoresFileName)
|
||||
generatedFilenames.add(checksFileName)
|
||||
|
||||
val scoresWriter = FileWriter(exportDirName + scoresFileName)
|
||||
val checksWriter = FileWriter(exportDirName + checksFileName)
|
||||
writeMultipleHabitsHeader(scoresWriter)
|
||||
writeMultipleHabitsHeader(checksWriter)
|
||||
|
||||
val timeframe = getTimeframe()
|
||||
val oldest = timeframe[0]
|
||||
val newest = DateUtils.getToday()
|
||||
val checkmarks: MutableList<IntArray> = ArrayList()
|
||||
val scores: MutableList<ArrayList<Score>> = ArrayList()
|
||||
for (habit in selectedHabits) {
|
||||
checkmarks.add(habit.computedEntries.getValues(oldest, newest))
|
||||
scores.add(ArrayList(habit.scores.getByInterval(oldest, newest)))
|
||||
}
|
||||
|
||||
val days = oldest.daysUntil(newest)
|
||||
val dateFormat = DateFormats.getCSVDateFormat()
|
||||
for (i in 0..days) {
|
||||
val day = newest.minus(i).toJavaDate()
|
||||
val date = dateFormat.format(day)
|
||||
val sb = StringBuilder()
|
||||
sb.append(date).append(delimiter)
|
||||
checksWriter.write(sb.toString())
|
||||
scoresWriter.write(sb.toString())
|
||||
for (j in selectedHabits.indices) {
|
||||
checksWriter.write(checkmarks[j][i].toString())
|
||||
checksWriter.write(delimiter)
|
||||
val score = String.format(Locale.US, "%.4f", scores[j][i].value)
|
||||
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
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
private fun writeMultipleHabitsHeader(out: Writer) {
|
||||
out.write("Date$delimiter")
|
||||
for (habit in selectedHabits) {
|
||||
out.write(habit.name)
|
||||
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 fun getTimeframe(): Array<Timestamp> {
|
||||
var oldest = Timestamp.ZERO.plus(1000000)
|
||||
var newest = Timestamp.ZERO
|
||||
for (habit in selectedHabits) {
|
||||
val entries = habit.originalEntries.getKnown()
|
||||
if (entries.isEmpty()) continue
|
||||
val currNew = entries[0].timestamp
|
||||
val currOld = entries[entries.size - 1].timestamp
|
||||
oldest = if (currOld.isOlderThan(oldest)) currOld else oldest
|
||||
newest = if (currNew.isNewerThan(newest)) currNew else newest
|
||||
}
|
||||
return arrayOf(oldest, newest)
|
||||
}
|
||||
|
||||
private fun writeZipFile(): String {
|
||||
val dateFormat = DateFormats.getCSVDateFormat()
|
||||
val date = dateFormat.format(DateUtils.getStartOfToday())
|
||||
val zipFilename = String.format("%s/Loop Habits CSV %s.zip", exportDirName, date)
|
||||
val fos = FileOutputStream(zipFilename)
|
||||
val zos = ZipOutputStream(fos)
|
||||
for (filename in generatedFilenames) addFileToZip(zos, filename)
|
||||
zos.close()
|
||||
fos.close()
|
||||
return zipFilename
|
||||
}
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.io;
|
||||
|
||||
import androidx.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.core.database.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
import static org.isoron.uhabits.core.models.Entry.*;
|
||||
|
||||
/**
|
||||
* Class that imports database files exported by Rewire.
|
||||
*/
|
||||
public class RewireDBImporter extends AbstractImporter
|
||||
{
|
||||
private ModelFactory modelFactory;
|
||||
|
||||
@NonNull
|
||||
private final DatabaseOpener opener;
|
||||
|
||||
@Inject
|
||||
public RewireDBImporter(@NonNull HabitList habits,
|
||||
@NonNull ModelFactory modelFactory,
|
||||
@NonNull DatabaseOpener opener)
|
||||
{
|
||||
super(habits);
|
||||
this.modelFactory = modelFactory;
|
||||
this.opener = opener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(@NonNull File file) throws IOException
|
||||
{
|
||||
if (!isSQLite3File(file)) return false;
|
||||
|
||||
Database db = opener.open(file);
|
||||
Cursor c = db.query("select count(*) from SQLITE_MASTER " +
|
||||
"where name='CHECKINS' or name='UNIT'");
|
||||
|
||||
boolean result = (c.moveToNext() && c.getInt(0) == 2);
|
||||
|
||||
c.close();
|
||||
db.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importHabitsFromFile(@NonNull File file) throws IOException
|
||||
{
|
||||
Database db = opener.open(file);
|
||||
db.beginTransaction();
|
||||
createHabits(db);
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
db.close();
|
||||
}
|
||||
|
||||
private void createHabits(Database db)
|
||||
{
|
||||
Cursor c = null;
|
||||
|
||||
try
|
||||
{
|
||||
c = db.query("select _id, name, description, schedule, " +
|
||||
"active_days, repeating_count, days, period " +
|
||||
"from habits");
|
||||
if (!c.moveToNext()) return;
|
||||
|
||||
do
|
||||
{
|
||||
int id = c.getInt(0);
|
||||
String name = c.getString(1);
|
||||
String description = c.getString(2);
|
||||
int schedule = c.getInt(3);
|
||||
String activeDays = c.getString(4);
|
||||
int repeatingCount = c.getInt(5);
|
||||
int days = c.getInt(6);
|
||||
int periodIndex = c.getInt(7);
|
||||
|
||||
Habit habit = modelFactory.buildHabit();
|
||||
habit.setName(name);
|
||||
habit.setDescription(description == null ? "" : description);
|
||||
|
||||
int periods[] = { 7, 31, 365 };
|
||||
int numerator, denominator;
|
||||
|
||||
switch (schedule)
|
||||
{
|
||||
case 0:
|
||||
numerator = activeDays.split(",").length;
|
||||
denominator = 7;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
numerator = days;
|
||||
denominator = (periods[periodIndex]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
numerator = 1;
|
||||
denominator = repeatingCount;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
habit.setFrequency(new Frequency(numerator, denominator));
|
||||
habitList.add(habit);
|
||||
|
||||
createReminder(db, habit, id);
|
||||
createCheckmarks(db, habit, id);
|
||||
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (c != null) c.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void createCheckmarks(@NonNull Database db,
|
||||
@NonNull Habit habit,
|
||||
int rewireHabitId)
|
||||
{
|
||||
Cursor c = null;
|
||||
|
||||
try
|
||||
{
|
||||
String[] params = { Integer.toString(rewireHabitId) };
|
||||
c = db.query(
|
||||
"select distinct date from checkins where habit_id=? and type=2",
|
||||
params);
|
||||
if (!c.moveToNext()) return;
|
||||
|
||||
do
|
||||
{
|
||||
String date = c.getString(0);
|
||||
int year = Integer.parseInt(date.substring(0, 4));
|
||||
int month = Integer.parseInt(date.substring(4, 6));
|
||||
int day = Integer.parseInt(date.substring(6, 8));
|
||||
|
||||
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
|
||||
cal.set(year, month - 1, day);
|
||||
|
||||
habit.getOriginalEntries().add(new Entry(new Timestamp(cal), YES_MANUAL));
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (c != null) c.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void createReminder(Database db, Habit habit, int rewireHabitId)
|
||||
{
|
||||
String[] params = { Integer.toString(rewireHabitId) };
|
||||
Cursor c = null;
|
||||
|
||||
try
|
||||
{
|
||||
c = db.query(
|
||||
"select time, active_days from reminders where habit_id=? limit 1",
|
||||
params);
|
||||
|
||||
if (!c.moveToNext()) return;
|
||||
int rewireReminder = Integer.parseInt(c.getString(0));
|
||||
if (rewireReminder <= 0 || rewireReminder >= 1440) return;
|
||||
|
||||
boolean reminderDays[] = new boolean[7];
|
||||
|
||||
String activeDays[] = c.getString(1).split(",");
|
||||
for (String d : activeDays)
|
||||
{
|
||||
int idx = (Integer.parseInt(d) + 1) % 7;
|
||||
reminderDays[idx] = true;
|
||||
}
|
||||
|
||||
int hour = rewireReminder / 60;
|
||||
int minute = rewireReminder % 60;
|
||||
WeekdayList days = new WeekdayList(reminderDays);
|
||||
|
||||
Reminder reminder = new Reminder(hour, minute, days);
|
||||
habit.setReminder(reminder);
|
||||
habitList.update(habit);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (c != null) c.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.isoron.uhabits.core.io
|
||||
|
||||
import org.isoron.uhabits.core.database.Cursor
|
||||
import org.isoron.uhabits.core.database.Database
|
||||
import org.isoron.uhabits.core.database.DatabaseOpener
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.ModelFactory
|
||||
import org.isoron.uhabits.core.models.Reminder
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.models.WeekdayList
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
import org.isoron.uhabits.core.utils.isSQLite3File
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Class that imports database files exported by Rewire.
|
||||
*/
|
||||
class RewireDBImporter
|
||||
@Inject constructor(
|
||||
private val habitList: HabitList,
|
||||
private val modelFactory: ModelFactory,
|
||||
private val opener: DatabaseOpener
|
||||
) : AbstractImporter() {
|
||||
|
||||
override fun canHandle(file: File): Boolean {
|
||||
if (!file.isSQLite3File()) return false
|
||||
val db = opener.open(file)
|
||||
val c = db.query(
|
||||
"select count(*) from SQLITE_MASTER " +
|
||||
"where name='CHECKINS' or name='UNIT'"
|
||||
)
|
||||
val result = c.moveToNext() && c.getInt(0) == 2
|
||||
c.close()
|
||||
db.close()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun importHabitsFromFile(file: File) {
|
||||
val db = opener.open(file)
|
||||
db.beginTransaction()
|
||||
createHabits(db)
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
db.close()
|
||||
}
|
||||
|
||||
private fun createHabits(db: Database) {
|
||||
var c: Cursor? = null
|
||||
try {
|
||||
c = db.query(
|
||||
"select _id, name, description, schedule, " +
|
||||
"active_days, repeating_count, days, period " +
|
||||
"from habits"
|
||||
)
|
||||
if (!c.moveToNext()) return
|
||||
do {
|
||||
val id = c.getInt(0)!!
|
||||
val name = c.getString(1)
|
||||
val description = c.getString(2)
|
||||
val schedule = c.getInt(3)!!
|
||||
val activeDays = c.getString(4)
|
||||
val repeatingCount = c.getInt(5)!!
|
||||
val days = c.getInt(6)!!
|
||||
val periodIndex = c.getInt(7)!!
|
||||
|
||||
val habit = modelFactory.buildHabit()
|
||||
habit.name = name!!
|
||||
habit.description = description ?: ""
|
||||
val periods = intArrayOf(7, 31, 365)
|
||||
var numerator: Int
|
||||
var denominator: Int
|
||||
when (schedule) {
|
||||
0 -> {
|
||||
numerator = activeDays!!.split(",").toTypedArray().size
|
||||
denominator = 7
|
||||
}
|
||||
1 -> {
|
||||
numerator = days
|
||||
denominator = periods[periodIndex]
|
||||
}
|
||||
2 -> {
|
||||
numerator = 1
|
||||
denominator = repeatingCount
|
||||
}
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
habit.frequency = Frequency(numerator, denominator)
|
||||
habitList.add(habit)
|
||||
createReminder(db, habit, id)
|
||||
createCheckmarks(db, habit, id)
|
||||
} while (c.moveToNext())
|
||||
} finally {
|
||||
c?.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCheckmarks(
|
||||
db: Database,
|
||||
habit: Habit,
|
||||
rewireHabitId: Int
|
||||
) {
|
||||
var c: Cursor? = null
|
||||
try {
|
||||
c = db.query(
|
||||
"select distinct date from checkins where habit_id=? and type=2",
|
||||
rewireHabitId.toString(),
|
||||
)
|
||||
if (!c.moveToNext()) return
|
||||
do {
|
||||
val date = c.getString(0)
|
||||
val year = date!!.substring(0, 4).toInt()
|
||||
val month = date.substring(4, 6).toInt()
|
||||
val day = date.substring(6, 8).toInt()
|
||||
val cal = DateUtils.getStartOfTodayCalendar()
|
||||
cal[year, month - 1] = day
|
||||
habit.originalEntries.add(Entry(Timestamp(cal), Entry.YES_MANUAL))
|
||||
} while (c.moveToNext())
|
||||
} finally {
|
||||
c?.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createReminder(db: Database, habit: Habit, rewireHabitId: Int) {
|
||||
var c: Cursor? = null
|
||||
try {
|
||||
c = db.query(
|
||||
"select time, active_days from reminders where habit_id=? limit 1",
|
||||
rewireHabitId.toString(),
|
||||
)
|
||||
if (!c.moveToNext()) return
|
||||
val rewireReminder = c.getInt(0)!!
|
||||
if (rewireReminder <= 0 || rewireReminder >= 1440) return
|
||||
val reminderDays = BooleanArray(7)
|
||||
val activeDays = c.getString(1)!!.split(",").toTypedArray()
|
||||
for (d in activeDays) {
|
||||
val idx = (d.toInt() + 1) % 7
|
||||
reminderDays[idx] = true
|
||||
}
|
||||
val hour = rewireReminder / 60
|
||||
val minute = rewireReminder % 60
|
||||
val days = WeekdayList(reminderDays)
|
||||
val reminder = Reminder(hour, minute, days)
|
||||
habit.reminder = reminder
|
||||
habitList.update(habit)
|
||||
} finally {
|
||||
c?.close()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.core.io;
|
||||
|
||||
import androidx.annotation.*;
|
||||
|
||||
import org.isoron.uhabits.core.database.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.inject.*;
|
||||
|
||||
import static org.isoron.uhabits.core.models.Entry.*;
|
||||
|
||||
/**
|
||||
* Class that imports data from database files exported by Tickmate.
|
||||
*/
|
||||
public class TickmateDBImporter extends AbstractImporter
|
||||
{
|
||||
private ModelFactory modelFactory;
|
||||
|
||||
@NonNull
|
||||
private final DatabaseOpener opener;
|
||||
|
||||
@Inject
|
||||
public TickmateDBImporter(@NonNull HabitList habits,
|
||||
@NonNull ModelFactory modelFactory,
|
||||
@NonNull DatabaseOpener opener)
|
||||
{
|
||||
super(habits);
|
||||
this.modelFactory = modelFactory;
|
||||
this.opener = opener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(@NonNull File file) throws IOException
|
||||
{
|
||||
if (!isSQLite3File(file)) return false;
|
||||
|
||||
Database db = opener.open(file);
|
||||
Cursor c = db.query("select count(*) from SQLITE_MASTER " +
|
||||
"where name='tracks' or name='track2groups'");
|
||||
|
||||
boolean result = (c.moveToNext() && c.getInt(0) == 2);
|
||||
|
||||
c.close();
|
||||
db.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importHabitsFromFile(@NonNull File file) throws IOException
|
||||
{
|
||||
final Database db = opener.open(file);
|
||||
db.beginTransaction();
|
||||
createHabits(db);
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
db.close();
|
||||
}
|
||||
|
||||
private void createCheckmarks(@NonNull Database db,
|
||||
@NonNull Habit habit,
|
||||
int tickmateTrackId)
|
||||
{
|
||||
Cursor c = null;
|
||||
|
||||
try
|
||||
{
|
||||
String[] params = {Integer.toString(tickmateTrackId)};
|
||||
c = db.query(
|
||||
"select distinct year, month, day from ticks where _track_id=?",
|
||||
params);
|
||||
if (!c.moveToNext()) return;
|
||||
|
||||
do
|
||||
{
|
||||
int year = c.getInt(0);
|
||||
int month = c.getInt(1);
|
||||
int day = c.getInt(2);
|
||||
|
||||
GregorianCalendar cal = DateUtils.getStartOfTodayCalendar();
|
||||
cal.set(year, month, day);
|
||||
|
||||
habit.getOriginalEntries().add(new Entry(new Timestamp(cal), YES_MANUAL));
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (c != null) c.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void createHabits(Database db)
|
||||
{
|
||||
Cursor c = null;
|
||||
|
||||
try
|
||||
{
|
||||
c = db.query("select _id, name, description from tracks",
|
||||
new String[0]);
|
||||
if (!c.moveToNext()) return;
|
||||
|
||||
do
|
||||
{
|
||||
int id = c.getInt(0);
|
||||
String name = c.getString(1);
|
||||
String description = c.getString(2);
|
||||
|
||||
Habit habit = modelFactory.buildHabit();
|
||||
habit.setName(name);
|
||||
habit.setDescription(description == null ? "" : description);
|
||||
habit.setFrequency(Frequency.DAILY);
|
||||
habitList.add(habit);
|
||||
|
||||
createCheckmarks(db, habit, id);
|
||||
|
||||
} while (c.moveToNext());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (c != null) c.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.isoron.uhabits.core.io
|
||||
|
||||
import org.isoron.uhabits.core.database.Cursor
|
||||
import org.isoron.uhabits.core.database.Database
|
||||
import org.isoron.uhabits.core.database.DatabaseOpener
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.models.Frequency
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.ModelFactory
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
import org.isoron.uhabits.core.utils.isSQLite3File
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Class that imports data from database files exported by Tickmate.
|
||||
*/
|
||||
class TickmateDBImporter @Inject constructor(
|
||||
private val habitList: HabitList,
|
||||
private val modelFactory: ModelFactory,
|
||||
private val opener: DatabaseOpener
|
||||
) : AbstractImporter() {
|
||||
|
||||
override fun canHandle(file: File): Boolean {
|
||||
if (!file.isSQLite3File()) return false
|
||||
val db = opener.open(file)
|
||||
val c = db.query(
|
||||
"select count(*) from SQLITE_MASTER " +
|
||||
"where name='tracks' or name='track2groups'"
|
||||
)
|
||||
val result = c.moveToNext() && c.getInt(0) == 2
|
||||
c.close()
|
||||
db.close()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun importHabitsFromFile(file: File) {
|
||||
val db = opener.open(file)
|
||||
db.beginTransaction()
|
||||
createHabits(db)
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
db.close()
|
||||
}
|
||||
|
||||
private fun createCheckmarks(
|
||||
db: Database,
|
||||
habit: Habit,
|
||||
tickmateTrackId: Int
|
||||
) {
|
||||
var c: Cursor? = null
|
||||
try {
|
||||
c = db.query(
|
||||
"select distinct year, month, day from ticks where _track_id=?",
|
||||
tickmateTrackId.toString(),
|
||||
)
|
||||
if (!c.moveToNext()) return
|
||||
do {
|
||||
val year = c.getInt(0)!!
|
||||
val month = c.getInt(1)!!
|
||||
val day = c.getInt(2)!!
|
||||
val cal = DateUtils.getStartOfTodayCalendar()
|
||||
cal[year, month] = day
|
||||
habit.originalEntries.add(Entry(Timestamp(cal), Entry.YES_MANUAL))
|
||||
} while (c.moveToNext())
|
||||
} finally {
|
||||
c?.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHabits(db: Database) {
|
||||
var c: Cursor? = null
|
||||
try {
|
||||
c = db.query("select _id, name, description from tracks")
|
||||
if (!c.moveToNext()) return
|
||||
do {
|
||||
val id = c.getInt(0)!!
|
||||
val name = c.getString(1)
|
||||
val description = c.getString(2)
|
||||
val habit = modelFactory.buildHabit()
|
||||
habit.name = name!!
|
||||
habit.description = description ?: ""
|
||||
habit.frequency = Frequency.DAILY
|
||||
habitList.add(habit)
|
||||
createCheckmarks(db, habit, id)
|
||||
} while (c.moveToNext())
|
||||
} finally {
|
||||
c?.close()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2020 Á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.core.utils
|
||||
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
fun File.isSQLite3File(): Boolean {
|
||||
val fis = FileInputStream(this)
|
||||
val sqliteHeader = "SQLite format 3".toByteArray()
|
||||
val buffer = ByteArray(sqliteHeader.size)
|
||||
val count = fis.read(buffer)
|
||||
return if (count < sqliteHeader.size) false else buffer.contentEquals(sqliteHeader)
|
||||
}
|
Loading…
Reference in new issue