From 298bb0176298c66b83e4775c7413898147ab699b Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Tue, 29 Dec 2020 22:18:53 -0600 Subject: [PATCH] Convert some core.io classes to Kotlin --- .../uhabits/core/io/GenericImporter.java | 69 --------- .../isoron/uhabits/core/io/GenericImporter.kt | 61 ++++++++ .../uhabits/core/io/HabitBullCSVImporter.java | 101 ------------ .../uhabits/core/io/HabitBullCSVImporter.kt | 71 +++++++++ .../org/isoron/uhabits/core/io/Logging.kt | 25 +++ .../uhabits/core/io/LoopDBImporter.java | 145 ------------------ .../isoron/uhabits/core/io/LoopDBImporter.kt | 103 +++++++++++++ .../isoron/uhabits/core/io/ImportTest.java | 2 +- 8 files changed, 261 insertions(+), 316 deletions(-) delete mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.java create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.kt delete mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt delete mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.kt diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.java deleted file mode 100644 index 48b7b61cb..000000000 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2017 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.io; - -import androidx.annotation.*; - -import org.isoron.uhabits.core.models.*; - -import java.io.*; -import java.util.*; - -import javax.inject.*; - -/** - * A GenericImporter decides which implementation of AbstractImporter is able to - * handle a given file and delegates to it the task of importing the data. - */ -public class GenericImporter extends AbstractImporter -{ - List importers; - - @Inject - public GenericImporter(@NonNull HabitList habits, - @NonNull LoopDBImporter loopDBImporter, - @NonNull RewireDBImporter rewireDBImporter, - @NonNull TickmateDBImporter tickmateDBImporter, - @NonNull HabitBullCSVImporter habitBullCSVImporter) - { - super(habits); - importers = new LinkedList<>(); - importers.add(loopDBImporter); - importers.add(rewireDBImporter); - importers.add(tickmateDBImporter); - importers.add(habitBullCSVImporter); - } - - @Override - public boolean canHandle(@NonNull File file) throws IOException - { - for (AbstractImporter importer : importers) - if (importer.canHandle(file)) return true; - - return false; - } - - @Override - public void importHabitsFromFile(@NonNull File file) throws IOException - { - for (AbstractImporter importer : importers) - if (importer.canHandle(file)) importer.importHabitsFromFile(file); - } -} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.kt new file mode 100644 index 000000000..ed91f05a9 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/GenericImporter.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.core.io + +import org.isoron.uhabits.core.models.* +import java.io.* +import javax.inject.* + +/** + * A GenericImporter decides which implementation of AbstractImporter is able to + * handle a given file and delegates to it the task of importing the data. + */ +class GenericImporter +@Inject constructor( + habits: HabitList, + loopDBImporter: LoopDBImporter, + rewireDBImporter: RewireDBImporter, + tickmateDBImporter: TickmateDBImporter, + habitBullCSVImporter: HabitBullCSVImporter, +) : AbstractImporter(habits) { + + var importers: List = listOf( + loopDBImporter, + rewireDBImporter, + tickmateDBImporter, + habitBullCSVImporter, + ) + + override fun canHandle(file: File): Boolean { + for (importer in importers) { + if (importer.canHandle(file)) { + return true + } + } + return false + } + + override fun importHabitsFromFile(file: File) { + for (importer in importers) { + if (importer.canHandle(file)) { + importer.importHabitsFromFile(file) + } + } + } +} \ No newline at end of file diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java deleted file mode 100644 index d5b2beac6..000000000 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2017 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.io; - -import androidx.annotation.*; - -import com.opencsv.*; - -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 HabitBull CSV files. - */ -public class HabitBullCSVImporter extends AbstractImporter -{ - private ModelFactory modelFactory; - - @Inject - public HabitBullCSVImporter(@NonNull HabitList habits, - @NonNull ModelFactory modelFactory) - { - super(habits); - this.modelFactory = modelFactory; - } - - @Override - public boolean canHandle(@NonNull File file) throws IOException - { - BufferedReader reader = new BufferedReader(new FileReader(file)); - String line = reader.readLine(); - return line.startsWith("HabitName,HabitDescription,HabitCategory"); - } - - @Override - public void importHabitsFromFile(@NonNull final File file) - throws IOException - { - CSVReader reader = new CSVReader(new FileReader(file)); - HashMap map = new HashMap<>(); - - for (String line[] : reader) - { - String name = line[0]; - if (name.equals("HabitName")) continue; - - String description = line[1]; - String dateString[] = line[3].split("-"); - int year = Integer.parseInt(dateString[0]); - int month = Integer.parseInt(dateString[1]); - int day = Integer.parseInt(dateString[2]); - - Calendar date = DateUtils.getStartOfTodayCalendar(); - date.set(year, month - 1, day); - - Timestamp timestamp = new Timestamp(date.getTimeInMillis()); - - int value = Integer.parseInt(line[4]); - if (value != 1) continue; - - Habit h = map.get(name); - - if (h == null) - { - h = modelFactory.buildHabit(); - h.setName(name); - h.setDescription(description == null ? "" : description); - h.setFrequency(Frequency.DAILY); - habitList.add(h); - map.put(name, h); - } - - h.getOriginalEntries().add(new Entry(timestamp, YES_MANUAL)); - } - } -} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt new file mode 100644 index 000000000..bd4c80162 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.core.io + +import com.opencsv.* +import org.isoron.uhabits.core.models.* +import org.isoron.uhabits.core.utils.* +import java.io.* +import java.util.* +import javax.inject.* + +/** + * Class that imports data from HabitBull CSV files. + */ +class HabitBullCSVImporter +@Inject constructor( + habits: HabitList, + private val modelFactory: ModelFactory, +) : AbstractImporter(habits) { + + override fun canHandle(file: File): Boolean { + val reader = BufferedReader(FileReader(file)) + val line = reader.readLine() + return line.startsWith("HabitName,HabitDescription,HabitCategory") + } + + override fun importHabitsFromFile(file: File) { + val reader = CSVReader(FileReader(file)) + val map = HashMap() + for (line in reader) { + val name = line[0] + if (name == "HabitName") continue + val description = line[1] + val dateString = line[3].split("-").toTypedArray() + val year = dateString[0].toInt() + val month = dateString[1].toInt() + val day = dateString[2].toInt() + val date = DateUtils.getStartOfTodayCalendar() + date[year, month - 1] = day + val timestamp = Timestamp(date.timeInMillis) + val value = line[4].toInt() + if (value != 1) continue + var h = map[name] + if (h == null) { + h = modelFactory.buildHabit() + h.name = name + h.description = description ?: "" + h.frequency = Frequency.DAILY + habitList.add(h) + map[name] = h + } + h.originalEntries.add(Entry(timestamp, Entry.YES_MANUAL)) + } + } +} \ No newline at end of file diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/Logging.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/Logging.kt index 6197de3e3..f46be1f29 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/Logging.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/Logging.kt @@ -30,4 +30,29 @@ interface Logger { fun debug(msg: String) fun error(msg: String) fun error(exception: Exception) +} + +class StandardLogging : Logging { + override fun getLogger(name: String): Logger { + return StandardLogger(name) + } +} + +class StandardLogger(val name: String): Logger { + override fun info(msg: String) { + println("[$name] $msg") + } + + override fun debug(msg: String) { + println("[$name] $msg") + } + + override fun error(msg: String) { + println("[$name] $msg") + } + + override fun error(exception: Exception) { + exception.printStackTrace() + } + } \ No newline at end of file diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java deleted file mode 100644 index c67d90cca..000000000 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2017 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.io; - -import androidx.annotation.*; - -import org.isoron.uhabits.core.*; -import org.isoron.uhabits.core.commands.*; -import org.isoron.uhabits.core.database.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.models.sqlite.records.*; - -import java.io.*; -import java.util.*; - -import javax.inject.*; - -import static org.isoron.uhabits.core.ConstantsKt.*; - -/** - * Class that imports data from database files exported by Loop Habit Tracker. - */ -public class LoopDBImporter extends AbstractImporter -{ - @NonNull - private final ModelFactory modelFactory; - - @NonNull - private final DatabaseOpener opener; - @NonNull - private final CommandRunner runner; - - @Inject - public LoopDBImporter(@AppScope @NonNull HabitList habitList, - @AppScope @NonNull ModelFactory modelFactory, - @AppScope @NonNull DatabaseOpener opener, - @AppScope @NonNull CommandRunner runner) - { - super(habitList); - this.modelFactory = modelFactory; - this.opener = opener; - this.runner = runner; - } - - @Override - public boolean canHandle(@NonNull File file) throws IOException - { - if (!isSQLite3File(file)) return false; - - Database db = opener.open(file); - boolean canHandle = true; - - Cursor c = db.query("select count(*) from SQLITE_MASTER " + - "where name='Habits' or name='Repetitions'"); - - if (!c.moveToNext() || c.getInt(0) != 2) - { -// Log.w("LoopDBImporter", "Cannot handle file: tables not found"); - canHandle = false; - } - - if (db.getVersion() > DATABASE_VERSION) - { -// Log.w("LoopDBImporter", String.format( -// "Cannot handle file: incompatible version: %d > %d", -// db.getVersion(), DATABASE_VERSION)); - canHandle = false; - } - - c.close(); - db.close(); - return canHandle; - } - - @Override - public synchronized void importHabitsFromFile(@NonNull File file) - { - Database db = opener.open(file); - MigrationHelper helper = new MigrationHelper(db); - helper.migrateTo(DATABASE_VERSION); - - Repository habitsRepository; - Repository entryRepository; - habitsRepository = new Repository<>(HabitRecord.class, db); - entryRepository = new Repository<>(EntryRecord.class, db); - - List habitRecords = habitsRepository.findAll("order by position"); - for (HabitRecord habitRecord : habitRecords) - { - List entryRecords = - entryRepository.findAll("where habit = ?", - habitRecord.id.toString()); - - Habit habit = habitList.getByUUID(habitRecord.uuid); - Command command; - if (habit == null) - { - habit = modelFactory.buildHabit(); - habitRecord.id = null; - habitRecord.copyTo(habit); - command = new CreateHabitCommand(modelFactory, habitList, habit); - command.run(); - } - else - { - Habit modified = modelFactory.buildHabit(); - habitRecord.id = habit.getId(); - habitRecord.copyTo(modified); - command = new EditHabitCommand(habitList, habit.getId(), modified); - command.run(); - } - - // Reload saved version of the habit - habit = habitList.getByUUID(habitRecord.uuid); - - for (EntryRecord r : entryRecords) - { - Timestamp t = new Timestamp(r.timestamp); - Entry existingEntry = habit.getOriginalEntries().get(t); - if (existingEntry.getValue() != r.value) - new CreateRepetitionCommand(habitList, habit, t, r.value).run(); - } - - runner.notifyListeners(command); - } - db.close(); - } -} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.kt new file mode 100644 index 000000000..8caa5d349 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/io/LoopDBImporter.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.core.io + +import org.isoron.uhabits.core.* +import org.isoron.uhabits.core.commands.* +import org.isoron.uhabits.core.database.* +import org.isoron.uhabits.core.models.* +import org.isoron.uhabits.core.models.sqlite.records.* +import java.io.* +import javax.inject.* + +/** + * Class that imports data from database files exported by Loop Habit Tracker. + */ +class LoopDBImporter +@Inject constructor( + @AppScope val habitList: HabitList, + @AppScope val modelFactory: ModelFactory, + @AppScope val opener: DatabaseOpener, + @AppScope val runner: CommandRunner, + @AppScope logging: Logging, +) : AbstractImporter(habitList) { + + private val logger = logging.getLogger("LoopDBImporter") + + override fun canHandle(file: File): Boolean { + if (!isSQLite3File(file)) return false + val db = opener.open(file)!! + var canHandle = true + val c = db.query("select count(*) from SQLITE_MASTER where name='Habits' or name='Repetitions'") + if (!c.moveToNext() || c.getInt(0) != 2) { + logger.error("Cannot handle file: tables not found") + canHandle = false + } + if (db.version > DATABASE_VERSION) { + logger.error("Cannot handle file: incompatible version: ${db.version} > $DATABASE_VERSION") + canHandle = false + } + c.close() + db.close() + return canHandle + } + + override fun importHabitsFromFile(file: File) { + val db = opener.open(file)!! + val helper = MigrationHelper(db) + helper.migrateTo(DATABASE_VERSION) + + val habitsRepository = Repository(HabitRecord::class.java, db) + val entryRepository = Repository(EntryRecord::class.java, db) + + for (habitRecord in habitsRepository.findAll("order by position")) { + var habit = habitList.getByUUID(habitRecord.uuid) + val entryRecords = entryRepository.findAll("where habit = ?", habitRecord.id.toString()) + + var command: Command + if (habit == null) { + habit = modelFactory.buildHabit() + habitRecord.id = null + habitRecord.copyTo(habit) + command = CreateHabitCommand(modelFactory, habitList, habit) + command.run() + } else { + val modified = modelFactory.buildHabit() + habitRecord.id = habit.id + habitRecord.copyTo(modified) + command = EditHabitCommand(habitList, habit.id!!, modified) + command.run() + } + + // Reload saved version of the habit + habit = habitList.getByUUID(habitRecord.uuid) + + for (r in entryRecords) { + val t = Timestamp(r.timestamp) + val (_, value) = habit!!.originalEntries.get(t) + if (value != r.value) CreateRepetitionCommand(habitList, habit, t, r.value).run() + } + + runner.notifyListeners(command) + } + + db.close() + } + +} \ No newline at end of file diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java index 58dc4b85b..f76ce25f4 100644 --- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java +++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/io/ImportTest.java @@ -134,7 +134,7 @@ public class ImportTest extends BaseUnitTest assertTrue(file.canRead()); GenericImporter importer = new GenericImporter(habitList, - new LoopDBImporter(habitList, modelFactory, databaseOpener, commandRunner), + new LoopDBImporter(habitList, modelFactory, databaseOpener, commandRunner, new StandardLogging()), new RewireDBImporter(habitList, modelFactory, databaseOpener), new TickmateDBImporter(habitList, modelFactory, databaseOpener), new HabitBullCSVImporter(habitList, modelFactory));