mirror of https://github.com/iSoron/uhabits.git
parent
7cab0a39e5
commit
a546f6de73
Binary file not shown.
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016-2019 Á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.models
|
|
||||||
|
|
||||||
import org.isoron.uhabits.utils.Database
|
|
||||||
import org.isoron.uhabits.utils.StepResult
|
|
||||||
|
|
||||||
class HabitList(var db: Database) {
|
|
||||||
var habits = mutableListOf<Habit>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
loadHabitsFromDatabase()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getActive(): List<Habit> {
|
|
||||||
return habits.filter { h -> !h.isArchived }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadHabitsFromDatabase() {
|
|
||||||
val stmt = db.prepareStatement(
|
|
||||||
"select id, name, description, freq_num, freq_den, color, " +
|
|
||||||
"archived, position, unit, target_value, type " +
|
|
||||||
"from habits")
|
|
||||||
|
|
||||||
while (stmt.step() == StepResult.ROW) {
|
|
||||||
habits.add(Habit(id = stmt.getInt(0),
|
|
||||||
name = stmt.getText(1),
|
|
||||||
description = stmt.getText(2),
|
|
||||||
frequency = Frequency(stmt.getInt(3),
|
|
||||||
stmt.getInt(4)),
|
|
||||||
color = Color(stmt.getInt(5)),
|
|
||||||
isArchived = (stmt.getInt(6) != 0),
|
|
||||||
position = stmt.getInt(7),
|
|
||||||
unit = stmt.getText(8),
|
|
||||||
target = 0,
|
|
||||||
type = HabitType.YES_NO_HABIT))
|
|
||||||
}
|
|
||||||
stmt.finalize()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2019 Á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.models
|
||||||
|
|
||||||
|
import org.isoron.uhabits.utils.Database
|
||||||
|
import org.isoron.uhabits.utils.PreparedStatement
|
||||||
|
import org.isoron.uhabits.utils.StepResult
|
||||||
|
import org.isoron.uhabits.utils.nextId
|
||||||
|
|
||||||
|
class HabitRepository(var db: Database) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val SELECT_COLUMNS = "id, name, description, freq_num, freq_den, color, archived, position, unit, target_value, type"
|
||||||
|
const val SELECT_PLACEHOLDERS = "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
|
||||||
|
const val UPDATE_COLUMNS = "id=?, name=?, description=?, freq_num=?, freq_den=?, color=?, archived=?, position=?, unit=?, target_value=?, type=?"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val findAllStatement = db.prepareStatement("select $SELECT_COLUMNS from habits order by position")
|
||||||
|
private val insertStatement = db.prepareStatement("insert into Habits($SELECT_COLUMNS) values ($SELECT_PLACEHOLDERS)")
|
||||||
|
private val updateStatement = db.prepareStatement("update Habits set $UPDATE_COLUMNS where id=?")
|
||||||
|
private val deleteStatement = db.prepareStatement("delete from Habits where id=?")
|
||||||
|
|
||||||
|
fun nextId(): Int {
|
||||||
|
return db.nextId("Habits")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findAll(): MutableMap<Int, Habit> {
|
||||||
|
val result = mutableMapOf<Int, Habit>()
|
||||||
|
while (findAllStatement.step() == StepResult.ROW) {
|
||||||
|
val habit = buildHabitFromStatement(findAllStatement)
|
||||||
|
result[habit.id] = habit
|
||||||
|
}
|
||||||
|
findAllStatement.reset()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insert(habit: Habit) {
|
||||||
|
bindHabitToStatement(habit, insertStatement)
|
||||||
|
insertStatement.step()
|
||||||
|
insertStatement.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(habit: Habit) {
|
||||||
|
bindHabitToStatement(habit, updateStatement)
|
||||||
|
updateStatement.bindInt(11, habit.id)
|
||||||
|
updateStatement.step()
|
||||||
|
updateStatement.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildHabitFromStatement(stmt: PreparedStatement): Habit {
|
||||||
|
return Habit(id = stmt.getInt(0),
|
||||||
|
name = stmt.getText(1),
|
||||||
|
description = stmt.getText(2),
|
||||||
|
frequency = Frequency(stmt.getInt(3), stmt.getInt(4)),
|
||||||
|
color = Color(stmt.getInt(5)),
|
||||||
|
isArchived = stmt.getInt(6) != 0,
|
||||||
|
position = stmt.getInt(7),
|
||||||
|
unit = stmt.getText(8),
|
||||||
|
target = stmt.getReal(9),
|
||||||
|
type = if (stmt.getInt(10) == 0) HabitType.YES_NO_HABIT else HabitType.NUMERICAL_HABIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindHabitToStatement(habit: Habit, statement: PreparedStatement) {
|
||||||
|
statement.bindInt(0, habit.id)
|
||||||
|
statement.bindText(1, habit.name)
|
||||||
|
statement.bindText(2, habit.description)
|
||||||
|
statement.bindInt(3, habit.frequency.numerator)
|
||||||
|
statement.bindInt(4, habit.frequency.denominator)
|
||||||
|
statement.bindInt(5, habit.color.paletteIndex)
|
||||||
|
statement.bindInt(6, if (habit.isArchived) 1 else 0)
|
||||||
|
statement.bindInt(7, habit.position)
|
||||||
|
statement.bindText(8, habit.unit)
|
||||||
|
statement.bindReal(9, habit.target)
|
||||||
|
statement.bindInt(10, habit.type.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun delete(habit: Habit) {
|
||||||
|
deleteStatement.bindInt(0, habit.id)
|
||||||
|
deleteStatement.step()
|
||||||
|
deleteStatement.reset()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2019 Á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.utils
|
||||||
|
|
||||||
|
import platform.Foundation.*
|
||||||
|
|
||||||
|
class IosResourceFile(val path: String) : ResourceFile {
|
||||||
|
private val fileManager = NSFileManager.defaultManager()
|
||||||
|
override fun readLines(): List<String> {
|
||||||
|
val contents = NSString.stringWithContentsOfFile(path) as NSString
|
||||||
|
return contents.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) as List<String>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IosUserFile(val path: String) : UserFile {
|
||||||
|
override fun exists(): Boolean {
|
||||||
|
return NSFileManager.defaultManager().fileExistsAtPath(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun delete() {
|
||||||
|
NSFileManager.defaultManager().removeItemAtPath(path, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IosFileOpener : FileOpener {
|
||||||
|
override fun openResourceFile(filename: String): ResourceFile {
|
||||||
|
val root = NSBundle.mainBundle.resourcePath!!
|
||||||
|
return IosResourceFile("$root/$filename")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openUserFile(filename: String): UserFile {
|
||||||
|
val manager = NSFileManager.defaultManager()
|
||||||
|
val root = manager.URLForDirectory(NSDocumentDirectory,
|
||||||
|
NSUserDomainMask,
|
||||||
|
null, false, null)!!.path
|
||||||
|
return IosUserFile("$root/$filename")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2019 Á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.models
|
||||||
|
|
||||||
|
import junit.framework.Assert.assertEquals
|
||||||
|
import org.isoron.uhabits.BaseTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class HabitRepositoryTest : BaseTest() {
|
||||||
|
lateinit var repository: HabitRepository
|
||||||
|
|
||||||
|
lateinit private var original0: Habit
|
||||||
|
lateinit private var original1: Habit
|
||||||
|
lateinit private var original2: Habit
|
||||||
|
|
||||||
|
@Before
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
|
||||||
|
original0 = Habit(id = 0,
|
||||||
|
name = "Wake up early",
|
||||||
|
description = "Did you wake up before 6am?",
|
||||||
|
frequency = Frequency(1, 1),
|
||||||
|
color = Color(3),
|
||||||
|
isArchived = false,
|
||||||
|
position = 0,
|
||||||
|
unit = "",
|
||||||
|
target = 0.0,
|
||||||
|
type = HabitType.YES_NO_HABIT)
|
||||||
|
|
||||||
|
original1 = Habit(id = 1,
|
||||||
|
name = "Exercise",
|
||||||
|
description = "Did you exercise for at least 20 minutes?",
|
||||||
|
frequency = Frequency(1, 2),
|
||||||
|
color = Color(4),
|
||||||
|
isArchived = false,
|
||||||
|
position = 1,
|
||||||
|
unit = "",
|
||||||
|
target = 0.0,
|
||||||
|
type = HabitType.YES_NO_HABIT)
|
||||||
|
|
||||||
|
original2 = Habit(id = 2,
|
||||||
|
name = "Learn Japanese",
|
||||||
|
description = "Did you study Japanese today?",
|
||||||
|
frequency = Frequency(1, 1),
|
||||||
|
color = Color(3),
|
||||||
|
isArchived = false,
|
||||||
|
position = 2,
|
||||||
|
unit = "",
|
||||||
|
target = 0.0,
|
||||||
|
type = HabitType.YES_NO_HABIT)
|
||||||
|
|
||||||
|
repository = HabitRepository(db)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFindActive() {
|
||||||
|
var habits = repository.findAll()
|
||||||
|
assertEquals(0, repository.nextId())
|
||||||
|
assertEquals(0, habits.size)
|
||||||
|
|
||||||
|
repository.insert(original0)
|
||||||
|
repository.insert(original1)
|
||||||
|
repository.insert(original2)
|
||||||
|
habits = repository.findAll()
|
||||||
|
assertEquals(3, habits.size)
|
||||||
|
assertEquals(original0, habits[0])
|
||||||
|
assertEquals(original1, habits[1])
|
||||||
|
assertEquals(original2, habits[2])
|
||||||
|
|
||||||
|
assertEquals(3, repository.nextId())
|
||||||
|
|
||||||
|
original0.description = "New description"
|
||||||
|
repository.update(original0)
|
||||||
|
habits = repository.findAll()
|
||||||
|
assertEquals(original0, habits[0])
|
||||||
|
|
||||||
|
repository.delete(original0)
|
||||||
|
habits = repository.findAll()
|
||||||
|
assertEquals(2, habits.size)
|
||||||
|
assertEquals(original1, habits[1])
|
||||||
|
assertEquals(original2, habits[2])
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "29x29",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "29x29",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "40x40",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "40x40",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "60x60",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "60x60",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "29x29",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "29x29",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "40x40",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "40x40",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "76x76",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "76x76",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"scale" : "1x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2019 Á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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class EditHabitTableViewController: NSObject, UITableViewDataSource, UITableViewDelegate {
|
||||||
|
func disclosure(title: String, subtitle: String) -> UITableViewCell {
|
||||||
|
let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
|
||||||
|
cell.textLabel?.text = title
|
||||||
|
cell.detailTextLabel?.text = subtitle
|
||||||
|
cell.accessoryType = .disclosureIndicator
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func input(title: String) -> UITableViewCell {
|
||||||
|
let cell = UITableViewCell()
|
||||||
|
let field = UITextField(frame: cell.bounds.insetBy(dx: 20, dy: 0))
|
||||||
|
field.placeholder = title
|
||||||
|
field.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth,
|
||||||
|
UIView.AutoresizingMask.flexibleHeight]
|
||||||
|
cell.contentView.addSubview(field)
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
var primary = [UITableViewCell]()
|
||||||
|
var secondary = [UITableViewCell]()
|
||||||
|
var parentController: EditHabitController
|
||||||
|
|
||||||
|
init(withParentController parentController: EditHabitController) {
|
||||||
|
self.parentController = parentController
|
||||||
|
super.init()
|
||||||
|
primary.append(input(title: "Name"))
|
||||||
|
primary.append(input(title: "Question (e.g. Did you wake up early today?)"))
|
||||||
|
secondary.append(disclosure(title: "Color", subtitle: "Blue"))
|
||||||
|
secondary.append(disclosure(title: "Repeat", subtitle: "Daily"))
|
||||||
|
secondary.append(disclosure(title: "Reminder", subtitle: "Disabled"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return section == 0 ? primary.count : secondary.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
return indexPath.section == 0 ? primary[indexPath.item] : secondary[indexPath.item]
|
||||||
|
}
|
||||||
|
|
||||||
|
// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
// let alert = UIAlertController(title: "Hello", message: "You selected something", preferredStyle: .alert)
|
||||||
|
// parentController.present(alert, animated: true)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditHabitController: UIViewController {
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
let bounds = UIScreen.main.bounds
|
||||||
|
let tableController = EditHabitTableViewController(withParentController: self)
|
||||||
|
let table = UITableView(frame: bounds, style: .grouped)
|
||||||
|
table.dataSource = tableController
|
||||||
|
table.delegate = tableController
|
||||||
|
self.view = table
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
self.title = "Edit Habit"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>Launch.storyboard</string>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes/>
|
||||||
|
</document>
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2019 Á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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class ListHabitsController: UIViewController {
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
self.title = "Habits"
|
||||||
|
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
|
||||||
|
target: self,
|
||||||
|
action: #selector(self.onCreateHabitClicked))
|
||||||
|
|
||||||
|
// let box = UIView(frame: view.bounds.insetBy(dx: 100, dy: 100))
|
||||||
|
// box.backgroundColor = .blue
|
||||||
|
//// box.translatesAutoresizingMaskIntoConstraints = true
|
||||||
|
// box.autoresizingMask = [UIView.AutoresizingMask.flexibleLeftMargin,
|
||||||
|
// UIView.AutoresizingMask.flexibleRightMargin]
|
||||||
|
// view.addSubview(box)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func onCreateHabitClicked() {
|
||||||
|
self.navigationController?.pushViewController(EditHabitController(), animated: true)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>BNDL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016-2019 Á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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
class IosResourceFile : NSObject, ResourceFile {
|
|
||||||
|
|
||||||
var path: String
|
|
||||||
|
|
||||||
var fileManager = FileManager.default
|
|
||||||
|
|
||||||
init(forPath path: String) {
|
|
||||||
self.path = path
|
|
||||||
}
|
|
||||||
|
|
||||||
func readLines() -> [String] {
|
|
||||||
do {
|
|
||||||
let contents = try String(contentsOfFile: self.path, encoding: .utf8)
|
|
||||||
return contents.components(separatedBy: CharacterSet.newlines)
|
|
||||||
} catch {
|
|
||||||
return [""]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IosUserFile : NSObject, UserFile {
|
|
||||||
|
|
||||||
var path: String
|
|
||||||
|
|
||||||
init(forPath path: String) {
|
|
||||||
self.path = path
|
|
||||||
}
|
|
||||||
|
|
||||||
func delete() {
|
|
||||||
do {
|
|
||||||
try FileManager.default.removeItem(atPath: path)
|
|
||||||
} catch {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func exists() -> Bool {
|
|
||||||
return FileManager.default.fileExists(atPath: path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IosFileOpener : NSObject, FileOpener {
|
|
||||||
func openResourceFile(filename: String) -> ResourceFile {
|
|
||||||
let path = "\(Bundle.main.resourcePath!)/\(filename)"
|
|
||||||
return IosResourceFile(forPath: path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func openUserFile(filename: String) -> UserFile {
|
|
||||||
do {
|
|
||||||
let root = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).path
|
|
||||||
return IosUserFile(forPath: "\(root)/\(filename)")
|
|
||||||
} catch {
|
|
||||||
return IosUserFile(forPath: "invalid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2019 Á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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
TextInput,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
ScrollView,
|
||||||
|
TouchableOpacity,
|
||||||
|
TouchableHighlight,
|
||||||
|
} from 'react-native';
|
||||||
|
import FontAwesome from '../../helpers/FontAwesome';
|
||||||
|
import { Colors } from '../../helpers/Colors';
|
||||||
|
import ColorCircle from '../common/ColorCircle';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
backgroundColor: Colors.appBackground,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
fontSize: 17,
|
||||||
|
paddingTop: 15,
|
||||||
|
paddingBottom: 15,
|
||||||
|
paddingRight: 15,
|
||||||
|
paddingLeft: 15,
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 17,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: 17,
|
||||||
|
},
|
||||||
|
multiline: {
|
||||||
|
},
|
||||||
|
middle: {
|
||||||
|
borderBottomColor: Colors.headerBorderColor,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
backgroundColor: Colors.appBackground,
|
||||||
|
marginTop: 30,
|
||||||
|
borderTopColor: Colors.headerBorderColor,
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderBottomColor: Colors.headerBorderColor,
|
||||||
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
fontFamily: 'FontAwesome',
|
||||||
|
color: Colors.unchecked,
|
||||||
|
marginLeft: 10,
|
||||||
|
fontSize: 12,
|
||||||
|
paddingTop: 2,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
borderWidth: 1,
|
||||||
|
padding: 25,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default class EditHabitsScene extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ScrollView style={styles.container}>
|
||||||
|
<View style={styles.section}>
|
||||||
|
<TextInput
|
||||||
|
autoFocus
|
||||||
|
style={[styles.item, styles.middle, { color: Colors[1] }]}
|
||||||
|
placeholder="Name"
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.item]}
|
||||||
|
placeholder="Question (e.g. Did you exercise today?)"
|
||||||
|
multiline
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.section}>
|
||||||
|
<TouchableHighlight onPress={() => {}}>
|
||||||
|
<View style={[styles.item, styles.middle]}>
|
||||||
|
<Text style={styles.label}>Color</Text>
|
||||||
|
<ColorCircle size={20} color={Colors[1]} />
|
||||||
|
<Text style={styles.icon}>{FontAwesome.chevronRight}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
<TouchableHighlight onPress={() => {}}>
|
||||||
|
<View style={[styles.item, styles.middle]}>
|
||||||
|
<Text style={styles.label}>Repeat</Text>
|
||||||
|
<Text style={styles.value}>Every Day</Text>
|
||||||
|
<Text style={styles.icon}>{FontAwesome.chevronRight}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
<TouchableHighlight onPress={() => {}}>
|
||||||
|
<View style={[styles.item, styles.middle]}>
|
||||||
|
<Text style={styles.label}>Reminder</Text>
|
||||||
|
<Text style={styles.value}>12:30</Text>
|
||||||
|
<Text style={styles.icon}>{FontAwesome.chevronRight}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
check: '\uf00c',
|
check: '\uf00c',
|
||||||
times: '\uf00d',
|
times: '\uf00d',
|
||||||
|
chevronRight: '\uf054',
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in new issue