@ -1,3 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
find uhabits-android/build/outputs/failed/test-screenshots -name '*.expected*' -delete
|
|
||||||
rsync -av uhabits-android/build/outputs/failed/test-screenshots/ uhabits-android/src/androidTest/assets/
|
|
@ -1,3 +1,3 @@
|
|||||||
org.gradle.parallel=true
|
org.gradle.parallel=false
|
||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms1024m -Xmx4096m -XX:MaxPermSize=2048m
|
org.gradle.jvmargs=-Xms2048m -Xmx2048m -XX:MaxPermSize=2048m
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 577 B After Width: | Height: | Size: 585 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 7.9 KiB |
After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.isoron.uhabits
|
||||||
|
|
||||||
|
import dagger.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
|
import org.isoron.uhabits.activities.about.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
|
import org.isoron.uhabits.activities.habits.show.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import org.mockito.Mockito.*
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class TestModule {
|
||||||
|
@Provides fun ListHabitsBehavior() = mock(ListHabitsBehavior::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
@Component(modules = arrayOf(
|
||||||
|
ActivityContextModule::class,
|
||||||
|
AboutModule::class,
|
||||||
|
HabitsActivityModule::class,
|
||||||
|
ListHabitsModule::class,
|
||||||
|
ShowHabitModule::class,
|
||||||
|
HabitModule::class,
|
||||||
|
TestModule::class
|
||||||
|
), dependencies = arrayOf(HabitsApplicationComponent::class))
|
||||||
|
interface HabitsActivityTestComponent {
|
||||||
|
fun getCheckmarkPanelViewFactory(): CheckmarkPanelViewFactory
|
||||||
|
fun getHabitCardViewFactory(): HabitCardViewFactory
|
||||||
|
fun getCheckmarkButtonViewFactory(): CheckmarkButtonViewFactory
|
||||||
|
fun getNumberButtonViewFactory(): NumberButtonViewFactory
|
||||||
|
fun getNumberPanelViewFactory(): NumberPanelViewFactory
|
||||||
|
}
|
@ -1,87 +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.activities.habits.list.views;
|
|
||||||
|
|
||||||
import android.support.test.runner.*;
|
|
||||||
import android.test.suitebuilder.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.isoron.uhabits.utils.*;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.junit.runner.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@MediumTest
|
|
||||||
public class CheckmarkButtonViewTest extends BaseViewTest
|
|
||||||
{
|
|
||||||
public static final String PATH = "habits/list/CheckmarkButtonView/";
|
|
||||||
|
|
||||||
private CheckmarkButtonView view;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Before
|
|
||||||
public void setUp()
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
view = new CheckmarkButtonView(targetContext);
|
|
||||||
view.setValue(Checkmark.UNCHECKED);
|
|
||||||
view.setColor(PaletteUtils.getAndroidTestColor(5));
|
|
||||||
measureView(view, dpToPixels(48), dpToPixels(48));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_explicitCheck() throws Exception
|
|
||||||
{
|
|
||||||
view.setValue(Checkmark.CHECKED_EXPLICITLY);
|
|
||||||
assertRendersCheckedExplicitly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_implicitCheck() throws Exception
|
|
||||||
{
|
|
||||||
view.setValue(Checkmark.CHECKED_IMPLICITLY);
|
|
||||||
assertRendersCheckedImplicitly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_unchecked() throws Exception
|
|
||||||
{
|
|
||||||
view.setValue(Checkmark.UNCHECKED);
|
|
||||||
assertRendersUnchecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void assertRendersCheckedExplicitly() throws IOException
|
|
||||||
{
|
|
||||||
assertRenders(view, PATH + "render_explicit_check.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void assertRendersCheckedImplicitly() throws IOException
|
|
||||||
{
|
|
||||||
assertRenders(view, PATH + "render_implicit_check.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void assertRendersUnchecked() throws IOException
|
|
||||||
{
|
|
||||||
assertRenders(view, PATH + "render_unchecked.png");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.support.test.filters.*
|
||||||
|
import android.support.test.runner.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
import org.junit.*
|
||||||
|
import org.junit.runner.*
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@MediumTest
|
||||||
|
class CheckmarkButtonViewTest : BaseViewTest() {
|
||||||
|
|
||||||
|
private val PATH = "habits/list/CheckmarkButtonView"
|
||||||
|
lateinit var view: CheckmarkButtonView
|
||||||
|
|
||||||
|
var toggled = false
|
||||||
|
|
||||||
|
@Before
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
view = component.getCheckmarkButtonViewFactory().create().apply {
|
||||||
|
value = Checkmark.UNCHECKED
|
||||||
|
color = PaletteUtils.getAndroidTestColor(5)
|
||||||
|
onToggle = { toggled = true }
|
||||||
|
}
|
||||||
|
measureView(view, dpToPixels(48), dpToPixels(48))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_explicitCheck() {
|
||||||
|
view.value = Checkmark.CHECKED_EXPLICITLY
|
||||||
|
assertRendersCheckedExplicitly()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_implicitCheck() {
|
||||||
|
view.value = Checkmark.CHECKED_IMPLICITLY
|
||||||
|
assertRendersCheckedImplicitly()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_unchecked() {
|
||||||
|
view.value = Checkmark.UNCHECKED
|
||||||
|
assertRendersUnchecked()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testClick_withShortToggleDisabled() {
|
||||||
|
prefs.isShortToggleEnabled = false
|
||||||
|
view.performClick()
|
||||||
|
assertFalse(toggled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testClick_withShortToggleEnabled() {
|
||||||
|
prefs.isShortToggleEnabled = true
|
||||||
|
view.performClick()
|
||||||
|
assertTrue(toggled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLongClick() {
|
||||||
|
view.performLongClick()
|
||||||
|
assertTrue(toggled)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertRendersCheckedExplicitly() {
|
||||||
|
assertRenders(view, "$PATH/render_explicit_check.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertRendersCheckedImplicitly() {
|
||||||
|
assertRenders(view, "$PATH/render_implicit_check.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertRendersUnchecked() {
|
||||||
|
assertRenders(view, "$PATH/render_unchecked.png")
|
||||||
|
}
|
||||||
|
}
|
@ -1,96 +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.activities.habits.list.views;
|
|
||||||
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
import android.test.suitebuilder.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.core.models.Checkmark;
|
|
||||||
import org.isoron.uhabits.core.models.Habit;
|
|
||||||
import org.isoron.uhabits.BaseViewTest;
|
|
||||||
import org.isoron.uhabits.utils.*;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@MediumTest
|
|
||||||
public class CheckmarkPanelViewTest extends BaseViewTest
|
|
||||||
{
|
|
||||||
public static final String PATH = "habits/list/CheckmarkPanelView/";
|
|
||||||
|
|
||||||
private CountDownLatch latch;
|
|
||||||
private CheckmarkPanelView view;
|
|
||||||
private int checkmarks[];
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Before
|
|
||||||
public void setUp()
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
prefs.setShouldReverseCheckmarks(false);
|
|
||||||
|
|
||||||
Habit habit = fixtures.createEmptyHabit();
|
|
||||||
|
|
||||||
latch = new CountDownLatch(1);
|
|
||||||
checkmarks = new int[]{
|
|
||||||
Checkmark.CHECKED_EXPLICITLY, Checkmark.UNCHECKED,
|
|
||||||
Checkmark.CHECKED_IMPLICITLY, Checkmark.CHECKED_EXPLICITLY};
|
|
||||||
|
|
||||||
view = new CheckmarkPanelView(targetContext);
|
|
||||||
view.setValues(checkmarks);
|
|
||||||
view.setButtonCount(4);
|
|
||||||
view.setColor(PaletteUtils.getAndroidTestColor(7));
|
|
||||||
|
|
||||||
measureView(view, dpToPixels(200), dpToPixels(200));
|
|
||||||
}
|
|
||||||
|
|
||||||
// protected void waitForLatch() throws InterruptedException
|
|
||||||
// {
|
|
||||||
// assertTrue("Latch timeout", latch.await(1, TimeUnit.SECONDS));
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender() throws Exception
|
|
||||||
{
|
|
||||||
assertRenders(view, PATH + "render.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Test
|
|
||||||
// public void testToggleCheckmark_withLeftToRight() throws Exception
|
|
||||||
// {
|
|
||||||
// setToggleListener();
|
|
||||||
// view.getButton(1).performToggle();
|
|
||||||
// waitForLatch();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Test
|
|
||||||
// public void testToggleCheckmark_withReverseCheckmarks() throws Exception
|
|
||||||
// {
|
|
||||||
// prefs.setShouldReverseCheckmarks(true);
|
|
||||||
// view.setCheckmarkValues(checkmarks); // refresh after preference change
|
|
||||||
//
|
|
||||||
// setToggleListener();
|
|
||||||
// view.getButton(2).performToggle();
|
|
||||||
// waitForLatch();
|
|
||||||
// }
|
|
||||||
}
|
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.support.test.filters.*
|
||||||
|
import android.support.test.runner.*
|
||||||
|
import org.hamcrest.CoreMatchers.*
|
||||||
|
import org.hamcrest.MatcherAssert.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.models.Checkmark.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
import org.junit.*
|
||||||
|
import org.junit.runner.*
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@MediumTest
|
||||||
|
class CheckmarkPanelViewTest : BaseViewTest() {
|
||||||
|
|
||||||
|
private val PATH = "habits/list/CheckmarkPanelView"
|
||||||
|
private lateinit var view: CheckmarkPanelView
|
||||||
|
|
||||||
|
@Before
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
prefs.isCheckmarkSequenceReversed = false
|
||||||
|
|
||||||
|
val checkmarks = intArrayOf(CHECKED_EXPLICITLY,
|
||||||
|
CHECKED_EXPLICITLY,
|
||||||
|
CHECKED_IMPLICITLY,
|
||||||
|
UNCHECKED,
|
||||||
|
UNCHECKED,
|
||||||
|
UNCHECKED,
|
||||||
|
CHECKED_EXPLICITLY)
|
||||||
|
|
||||||
|
view = component.getCheckmarkPanelViewFactory().create().apply {
|
||||||
|
values = checkmarks
|
||||||
|
buttonCount = 4
|
||||||
|
color = PaletteUtils.getAndroidTestColor(7)
|
||||||
|
}
|
||||||
|
view.onAttachedToWindow()
|
||||||
|
measureView(view, dpToPixels(200), dpToPixels(200))
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public override fun tearDown() {
|
||||||
|
// view.onDetachedFromWindow()
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender() {
|
||||||
|
assertRenders(view, "$PATH/render.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_withDifferentColor() {
|
||||||
|
view.color = PaletteUtils.getAndroidTestColor(1)
|
||||||
|
assertRenders(view, "$PATH/render_different_color.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_Reversed() {
|
||||||
|
prefs.isCheckmarkSequenceReversed = true
|
||||||
|
assertRenders(view, "$PATH/render_reversed.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_withOffset() {
|
||||||
|
view.dataOffset = 3
|
||||||
|
assertRenders(view, "$PATH/render_offset.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToggle() {
|
||||||
|
var timestamps = mutableListOf<Long>()
|
||||||
|
view.onToggle = { timestamps.add(it) }
|
||||||
|
view.buttons[0].performLongClick()
|
||||||
|
view.buttons[2].performLongClick()
|
||||||
|
view.buttons[3].performLongClick()
|
||||||
|
assertThat(timestamps, equalTo(listOf(day(0), day(2), day(3))))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testToggle_withOffset() {
|
||||||
|
var timestamps = LongArray(0)
|
||||||
|
view.dataOffset = 3
|
||||||
|
view.onToggle = { timestamps += it }
|
||||||
|
view.buttons[0].performLongClick()
|
||||||
|
view.buttons[2].performLongClick()
|
||||||
|
view.buttons[3].performLongClick()
|
||||||
|
assertThat(timestamps, equalTo(longArrayOf(day(3), day(5), day(6))))
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +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.activities.habits.list.views;
|
|
||||||
|
|
||||||
import android.support.test.runner.*;
|
|
||||||
import android.test.suitebuilder.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.isoron.uhabits.core.utils.*;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.junit.runner.*;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@MediumTest
|
|
||||||
public class HabitCardViewTest extends BaseViewTest
|
|
||||||
{
|
|
||||||
private HabitCardView view;
|
|
||||||
|
|
||||||
public static final String PATH = "habits/list/HabitCardView/";
|
|
||||||
|
|
||||||
private Habit habit;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp()
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
setTheme(R.style.AppBaseTheme);
|
|
||||||
|
|
||||||
habit = fixtures.createLongHabit();
|
|
||||||
CheckmarkList checkmarks = habit.getCheckmarks();
|
|
||||||
|
|
||||||
long today = DateUtils.getStartOfToday();
|
|
||||||
long day = DateUtils.millisecondsInOneDay;
|
|
||||||
int[] values = checkmarks.getValues(today - 5 * day, today);
|
|
||||||
|
|
||||||
view = new HabitCardView(targetContext);
|
|
||||||
view.setHabit(habit);
|
|
||||||
view.setValues(values);
|
|
||||||
view.setSelected(false);
|
|
||||||
view.setScore(habit.getScores().getTodayValue());
|
|
||||||
view.setButtonCount(6);
|
|
||||||
measureView(view, dpToPixels(400), dpToPixels(50));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender() throws Exception
|
|
||||||
{
|
|
||||||
assertRenders(view, PATH + "render.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_selected() throws Exception
|
|
||||||
{
|
|
||||||
view.setSelected(true);
|
|
||||||
measureView(view, dpToPixels(400), dpToPixels(50));
|
|
||||||
assertRenders(view, PATH + "render_selected.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testChangeModel() throws Exception
|
|
||||||
{
|
|
||||||
habit.setName("Wake up early");
|
|
||||||
habit.setColor(2);
|
|
||||||
habit.getObservable().notifyListeners();
|
|
||||||
Thread.sleep(500);
|
|
||||||
assertRenders(view, PATH + "render_changed.png");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.support.test.filters.*
|
||||||
|
import android.support.test.runner.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.junit.*
|
||||||
|
import org.junit.runner.*
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@MediumTest
|
||||||
|
class HabitCardViewTest : BaseViewTest() {
|
||||||
|
|
||||||
|
val PATH = "habits/list/HabitCardView"
|
||||||
|
lateinit private var view: HabitCardView
|
||||||
|
lateinit private var habit1: Habit
|
||||||
|
lateinit private var habit2: Habit
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
setTheme(R.style.AppBaseTheme)
|
||||||
|
|
||||||
|
habit1 = fixtures.createLongHabit()
|
||||||
|
habit2 = fixtures.createLongNumericalHabit()
|
||||||
|
view = component.getHabitCardViewFactory().create().apply {
|
||||||
|
habit = habit1
|
||||||
|
values = habit1.checkmarks.allValues
|
||||||
|
score = habit1.scores.todayValue
|
||||||
|
isSelected = false
|
||||||
|
buttonCount = 5
|
||||||
|
}
|
||||||
|
latch.countDown()
|
||||||
|
|
||||||
|
latch.await()
|
||||||
|
measureView(view, dpToPixels(400), dpToPixels(50))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender() {
|
||||||
|
assertRenders(view, "$PATH/render.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_selected() {
|
||||||
|
view.isSelected = true
|
||||||
|
measureView(view, dpToPixels(400), dpToPixels(50))
|
||||||
|
assertRenders(view, "$PATH/render_selected.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_numerical() {
|
||||||
|
view.apply {
|
||||||
|
habit = habit2
|
||||||
|
values = habit2.checkmarks.allValues
|
||||||
|
}
|
||||||
|
assertRenders(view, "$PATH/render_numerical.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testChangeModel() {
|
||||||
|
habit1.name = "Wake up early"
|
||||||
|
habit1.color = 2
|
||||||
|
habit1.observable.notifyListeners()
|
||||||
|
Thread.sleep(500)
|
||||||
|
assertRenders(view, "$PATH/render_changed.png")
|
||||||
|
}
|
||||||
|
}
|
@ -1,95 +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.activities.habits.list.views;
|
|
||||||
|
|
||||||
import android.support.test.filters.*;
|
|
||||||
import android.support.test.runner.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.utils.*;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.junit.runner.*;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
|
||||||
import static org.hamcrest.MatcherAssert.*;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
@MediumTest
|
|
||||||
public class NumberButtonViewTest extends BaseViewTest
|
|
||||||
{
|
|
||||||
public static final String PATH = "habits/list/NumberButtonView/";
|
|
||||||
|
|
||||||
private NumberButtonView view;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Before
|
|
||||||
public void setUp()
|
|
||||||
{
|
|
||||||
super.setUp();
|
|
||||||
|
|
||||||
view = new NumberButtonView(targetContext);
|
|
||||||
view.setUnit("steps");
|
|
||||||
view.setThreshold(100.0);
|
|
||||||
view.setColor(PaletteUtils.getAndroidTestColor(8));
|
|
||||||
|
|
||||||
measureView(view, dpToPixels(48), dpToPixels(48));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFormatValue()
|
|
||||||
{
|
|
||||||
assertThat(NumberButtonView.formatValue(0.1235), equalTo("0.12"));
|
|
||||||
assertThat(NumberButtonView.formatValue(0.1000), equalTo("0.1"));
|
|
||||||
assertThat(NumberButtonView.formatValue(5.0), equalTo("5"));
|
|
||||||
assertThat(NumberButtonView.formatValue(5.25), equalTo("5.25"));
|
|
||||||
assertThat(NumberButtonView.formatValue(12.3456), equalTo("12.3"));
|
|
||||||
assertThat(NumberButtonView.formatValue(123.123), equalTo("123"));
|
|
||||||
assertThat(NumberButtonView.formatValue(321.2), equalTo("321"));
|
|
||||||
assertThat(NumberButtonView.formatValue(4321.2), equalTo("4.3k"));
|
|
||||||
assertThat(NumberButtonView.formatValue(54321.2), equalTo("54.3k"));
|
|
||||||
assertThat(NumberButtonView.formatValue(654321.2), equalTo("654k"));
|
|
||||||
assertThat(NumberButtonView.formatValue(7654321.2), equalTo("7.7M"));
|
|
||||||
assertThat(NumberButtonView.formatValue(87654321.2), equalTo("87.7M"));
|
|
||||||
assertThat(NumberButtonView.formatValue(987654321.2), equalTo("988M"));
|
|
||||||
assertThat(NumberButtonView.formatValue(1987654321.2), equalTo("2.0G"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_aboveThreshold() throws Exception
|
|
||||||
{
|
|
||||||
view.setValue(500);
|
|
||||||
assertRenders(view, PATH + "render_above.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_belowThreshold() throws Exception
|
|
||||||
{
|
|
||||||
view.setValue(99);
|
|
||||||
assertRenders(view, PATH + "render_below.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRender_zero() throws Exception
|
|
||||||
{
|
|
||||||
view.setValue(0);
|
|
||||||
assertRenders(view, PATH + "render_zero.png");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.support.test.filters.*
|
||||||
|
import android.support.test.runner.*
|
||||||
|
import org.hamcrest.CoreMatchers.*
|
||||||
|
import org.hamcrest.MatcherAssert.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
import org.junit.*
|
||||||
|
import org.junit.runner.*
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@MediumTest
|
||||||
|
class NumberButtonViewTest : BaseViewTest() {
|
||||||
|
|
||||||
|
private val PATH = "habits/list/NumberButtonView"
|
||||||
|
private lateinit var view: NumberButtonView
|
||||||
|
var edited = false
|
||||||
|
|
||||||
|
@Before
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
view = component.getNumberButtonViewFactory().create().apply {
|
||||||
|
units = "steps"
|
||||||
|
threshold = 100.0
|
||||||
|
color = PaletteUtils.getAndroidTestColor(8)
|
||||||
|
onEdit = { edited = true }
|
||||||
|
}
|
||||||
|
measureView(view, dpToPixels(48), dpToPixels(48))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFormatValue() {
|
||||||
|
assertThat(0.1235.toShortString(), equalTo("0.12"))
|
||||||
|
assertThat(0.1000.toShortString(), equalTo("0.1"))
|
||||||
|
assertThat(5.0.toShortString(), equalTo("5"))
|
||||||
|
assertThat(5.25.toShortString(), equalTo("5.25"))
|
||||||
|
assertThat(12.3456.toShortString(), equalTo("12.3"))
|
||||||
|
assertThat(123.123.toShortString(), equalTo("123"))
|
||||||
|
assertThat(321.2.toShortString(), equalTo("321"))
|
||||||
|
assertThat(4321.2.toShortString(), equalTo("4.3k"))
|
||||||
|
assertThat(54321.2.toShortString(), equalTo("54.3k"))
|
||||||
|
assertThat(654321.2.toShortString(), equalTo("654k"))
|
||||||
|
assertThat(7654321.2.toShortString(), equalTo("7.7M"))
|
||||||
|
assertThat(87654321.2.toShortString(), equalTo("87.7M"))
|
||||||
|
assertThat(987654321.2.toShortString(), equalTo("988M"))
|
||||||
|
assertThat(1987654321.2.toShortString(), equalTo("2.0G"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_aboveThreshold() {
|
||||||
|
view.value = 500.0
|
||||||
|
assertRenders(view, "$PATH/render_above.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_belowThreshold() {
|
||||||
|
view.value = 99.0
|
||||||
|
assertRenders(view, "$PATH/render_below.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_zero() {
|
||||||
|
view.value = 0.0
|
||||||
|
assertRenders(view, "$PATH/render_zero.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testClick_shortToggleDisabled() {
|
||||||
|
prefs.isShortToggleEnabled = false
|
||||||
|
view.performClick()
|
||||||
|
assertFalse(edited)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testClick_shortToggleEnabled() {
|
||||||
|
prefs.isShortToggleEnabled = true
|
||||||
|
view.performClick()
|
||||||
|
assertTrue(edited)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLongClick() {
|
||||||
|
view.performLongClick()
|
||||||
|
assertTrue(edited)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.support.test.filters.*
|
||||||
|
import android.support.test.runner.*
|
||||||
|
import org.hamcrest.CoreMatchers.*
|
||||||
|
import org.hamcrest.MatcherAssert.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
import org.junit.*
|
||||||
|
import org.junit.runner.*
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@MediumTest
|
||||||
|
class NumberPanelViewTest : BaseViewTest() {
|
||||||
|
|
||||||
|
private val PATH = "habits/list/NumberPanelView"
|
||||||
|
private lateinit var view: NumberPanelView
|
||||||
|
|
||||||
|
@Before
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
prefs.isCheckmarkSequenceReversed = false
|
||||||
|
|
||||||
|
val checkmarks = doubleArrayOf(1400.0, 5300.0, 0.0,
|
||||||
|
14600.0, 2500.0, 45000.0)
|
||||||
|
|
||||||
|
view = component.getNumberPanelViewFactory().create().apply {
|
||||||
|
values = checkmarks
|
||||||
|
buttonCount = 4
|
||||||
|
color = PaletteUtils.getAndroidTestColor(7)
|
||||||
|
units = "steps"
|
||||||
|
threshold = 5000.0
|
||||||
|
}
|
||||||
|
view.onAttachedToWindow()
|
||||||
|
measureView(view, dpToPixels(200), dpToPixels(200))
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public override fun tearDown() {
|
||||||
|
view.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender() {
|
||||||
|
assertRenders(view, "$PATH/render.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_withDifferentColor() {
|
||||||
|
view.color = PaletteUtils.getAndroidTestColor(1)
|
||||||
|
assertRenders(view, "$PATH/render_different_color.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_Reversed() {
|
||||||
|
prefs.isCheckmarkSequenceReversed = true
|
||||||
|
assertRenders(view, "$PATH/render_reversed.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRender_withOffset() {
|
||||||
|
view.dataOffset = 3
|
||||||
|
assertRenders(view, "$PATH/render_offset.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEdit() {
|
||||||
|
var timestamps = LongArray(0)
|
||||||
|
view.onEdit = { timestamps += it }
|
||||||
|
view.buttons[0].performLongClick()
|
||||||
|
view.buttons[2].performLongClick()
|
||||||
|
view.buttons[3].performLongClick()
|
||||||
|
assertThat(timestamps, equalTo(longArrayOf(day(0), day(2), day(3))))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEdit_withOffset() {
|
||||||
|
var timestamps = LongArray(0)
|
||||||
|
view.dataOffset = 3
|
||||||
|
view.onEdit = { timestamps += it }
|
||||||
|
view.buttons[0].performLongClick()
|
||||||
|
view.buttons[2].performLongClick()
|
||||||
|
view.buttons[3].performLongClick()
|
||||||
|
assertThat(timestamps, equalTo(longArrayOf(day(3), day(5), day(6))))
|
||||||
|
}
|
||||||
|
}
|
@ -1,63 +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.activities;
|
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.core.preferences.*;
|
|
||||||
import org.isoron.uhabits.core.ui.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
public class AndroidThemeSwitcher extends ThemeSwitcher
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private final BaseActivity activity;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public AndroidThemeSwitcher(@NonNull BaseActivity activity,
|
|
||||||
@NonNull Preferences preferences)
|
|
||||||
{
|
|
||||||
super(preferences);
|
|
||||||
this.activity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyDarkTheme()
|
|
||||||
{
|
|
||||||
activity.setTheme(R.style.AppBaseThemeDark);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyLightTheme()
|
|
||||||
{
|
|
||||||
activity.setTheme(R.style.AppBaseTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyPureBlackTheme()
|
|
||||||
{
|
|
||||||
activity.setTheme(R.style.AppBaseThemeDark_PureBlack);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +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.activities;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.net.*;
|
|
||||||
import android.os.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
|
|
||||||
public abstract class HabitsActivity extends BaseActivity
|
|
||||||
{
|
|
||||||
private HabitsActivityComponent component;
|
|
||||||
|
|
||||||
private HabitsApplicationComponent appComponent;
|
|
||||||
|
|
||||||
public HabitsActivityComponent getActivityComponent()
|
|
||||||
{
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HabitsApplicationComponent getAppComponent()
|
|
||||||
{
|
|
||||||
return appComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
appComponent =
|
|
||||||
((HabitsApplication) getApplicationContext()).getComponent();
|
|
||||||
|
|
||||||
Habit habit = getHabitFromIntent(appComponent.getHabitList());
|
|
||||||
|
|
||||||
component = DaggerHabitsActivityComponent
|
|
||||||
.builder()
|
|
||||||
.activityModule(new ActivityModule(this))
|
|
||||||
.habitModule(new HabitModule(habit))
|
|
||||||
.habitsApplicationComponent(appComponent)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
component.getThemeSwitcher().apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Habit getHabitFromIntent(@NonNull HabitList habitList)
|
|
||||||
{
|
|
||||||
Uri data = getIntent().getData();
|
|
||||||
if(data == null) return null;
|
|
||||||
|
|
||||||
Habit habit = habitList.getById(ContentUris.parseId(data));
|
|
||||||
if (habit == null) throw new RuntimeException("habit not found");
|
|
||||||
|
|
||||||
return habit;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.os.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.models.*
|
||||||
|
|
||||||
|
abstract class HabitsActivity : BaseActivity() {
|
||||||
|
lateinit var component: HabitsActivityComponent
|
||||||
|
lateinit var appComponent: HabitsApplicationComponent
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
appComponent = (applicationContext as HabitsApplication).component
|
||||||
|
|
||||||
|
val habit = getHabitFromIntent(appComponent.habitList)
|
||||||
|
?: appComponent.modelFactory.buildHabit()
|
||||||
|
|
||||||
|
component = DaggerHabitsActivityComponent
|
||||||
|
.builder()
|
||||||
|
.activityContextModule(ActivityContextModule(this))
|
||||||
|
.baseActivityModule(BaseActivityModule(this))
|
||||||
|
.habitModule(HabitModule(habit))
|
||||||
|
.habitsApplicationComponent(appComponent)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
component.themeSwitcher.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHabitFromIntent(habitList: HabitList): Habit? {
|
||||||
|
val data = intent.data ?: return null
|
||||||
|
val habit = habitList.getById(ContentUris.parseId(data))
|
||||||
|
?: throw RuntimeException("habit not found")
|
||||||
|
return habit
|
||||||
|
}
|
||||||
|
}
|
@ -1,68 +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.activities;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.activities.about.*;
|
|
||||||
import org.isoron.uhabits.activities.common.dialogs.*;
|
|
||||||
import org.isoron.uhabits.activities.habits.list.*;
|
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
|
||||||
import org.isoron.uhabits.activities.habits.show.*;
|
|
||||||
import org.isoron.uhabits.core.ui.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
|
|
||||||
import dagger.*;
|
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
@Component(modules = {
|
|
||||||
ActivityModule.class,
|
|
||||||
AboutModule.class,
|
|
||||||
HabitsActivityModule.class,
|
|
||||||
ListHabitsModule.class,
|
|
||||||
ShowHabitModule.class,
|
|
||||||
HabitModule.class
|
|
||||||
}, dependencies = { HabitsApplicationComponent.class })
|
|
||||||
public interface HabitsActivityComponent
|
|
||||||
{
|
|
||||||
AboutRootView getAboutRootView();
|
|
||||||
|
|
||||||
AboutScreen getAboutScreen();
|
|
||||||
|
|
||||||
ColorPickerDialogFactory getColorPickerDialogFactory();
|
|
||||||
|
|
||||||
HabitCardListAdapter getHabitCardListAdapter();
|
|
||||||
|
|
||||||
ListHabitsBehavior getListHabitsBehavior();
|
|
||||||
|
|
||||||
ListHabitsController getListHabitsController();
|
|
||||||
|
|
||||||
ListHabitsMenu getListHabitsMenu();
|
|
||||||
|
|
||||||
ListHabitsRootView getListHabitsRootView();
|
|
||||||
|
|
||||||
ListHabitsScreen getListHabitsScreen();
|
|
||||||
|
|
||||||
ListHabitsSelectionMenu getListHabitsSelectionMenu();
|
|
||||||
|
|
||||||
ShowHabitScreen getShowHabitScreen();
|
|
||||||
|
|
||||||
ThemeSwitcher getThemeSwitcher();
|
|
||||||
}
|
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities
|
||||||
|
|
||||||
|
import dagger.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.about.*
|
||||||
|
import org.isoron.uhabits.activities.common.dialogs.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
|
import org.isoron.uhabits.activities.habits.show.*
|
||||||
|
import org.isoron.uhabits.core.ui.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
@Component(modules = arrayOf(
|
||||||
|
ActivityContextModule::class,
|
||||||
|
BaseActivityModule::class,
|
||||||
|
AboutModule::class,
|
||||||
|
HabitsActivityModule::class,
|
||||||
|
ListHabitsModule::class,
|
||||||
|
ShowHabitModule::class,
|
||||||
|
HabitModule::class
|
||||||
|
), dependencies = arrayOf(HabitsApplicationComponent::class))
|
||||||
|
interface HabitsActivityComponent {
|
||||||
|
val aboutRootView: AboutRootView
|
||||||
|
val aboutScreen: AboutScreen
|
||||||
|
val colorPickerDialogFactory: ColorPickerDialogFactory
|
||||||
|
val habitCardListAdapter: HabitCardListAdapter
|
||||||
|
val listHabitsBehavior: ListHabitsBehavior
|
||||||
|
val listHabitsMenu: ListHabitsMenu
|
||||||
|
val listHabitsRootView: ListHabitsRootView
|
||||||
|
val listHabitsScreen: ListHabitsScreen
|
||||||
|
val listHabitsSelectionMenu: ListHabitsSelectionMenu
|
||||||
|
val showHabitScreen: ShowHabitScreen
|
||||||
|
val themeSwitcher: ThemeSwitcher
|
||||||
|
}
|
@ -1,47 +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.activities;
|
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.show.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
public class HabitsDirFinder
|
|
||||||
implements ShowHabitMenuBehavior.System, ListHabitsBehavior.DirFinder
|
|
||||||
{
|
|
||||||
private AndroidDirFinder androidDirFinder;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public HabitsDirFinder(@NonNull AndroidDirFinder androidDirFinder)
|
|
||||||
{
|
|
||||||
this.androidDirFinder = androidDirFinder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getCSVOutputDir()
|
|
||||||
{
|
|
||||||
return androidDirFinder.getFilesDir("CSV");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides activity that shows information about the app.
|
|
||||||
*/
|
|
||||||
package org.isoron.uhabits.activities.about;
|
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.common.dialogs
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.support.v7.app.*
|
||||||
|
import android.text.*
|
||||||
|
import android.view.*
|
||||||
|
import android.view.inputmethod.*
|
||||||
|
import android.widget.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.androidbase.utils.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
|
class NumberPickerFactory
|
||||||
|
@Inject constructor(
|
||||||
|
@ActivityContext private val context: Context
|
||||||
|
) {
|
||||||
|
fun create(value: Double,
|
||||||
|
unit: String,
|
||||||
|
callback: ListHabitsBehavior.NumberPickerCallback): AlertDialog {
|
||||||
|
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val view = inflater.inflate(R.layout.number_picker_dialog, null)
|
||||||
|
|
||||||
|
val picker = view.findViewById(R.id.picker) as NumberPicker
|
||||||
|
val picker2 = view.findViewById(R.id.picker2) as NumberPicker
|
||||||
|
val tvUnit = view.findViewById(R.id.tvUnit) as TextView
|
||||||
|
|
||||||
|
val intValue = Math.round(value * 100).toInt()
|
||||||
|
|
||||||
|
picker.minValue = 0
|
||||||
|
picker.maxValue = Integer.MAX_VALUE / 100
|
||||||
|
picker.value = intValue / 100
|
||||||
|
picker.wrapSelectorWheel = false
|
||||||
|
|
||||||
|
picker2.minValue = 0
|
||||||
|
picker2.maxValue = 19
|
||||||
|
picker2.setFormatter { v -> String.format("%02d", 5 * v) }
|
||||||
|
picker2.value = intValue % 100 / 5
|
||||||
|
refreshInitialValue(picker2)
|
||||||
|
|
||||||
|
tvUnit.text = unit
|
||||||
|
|
||||||
|
val dialog = AlertDialog.Builder(context)
|
||||||
|
.setView(view)
|
||||||
|
.setTitle(R.string.change_value)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
picker.clearFocus()
|
||||||
|
val v = picker.value + 0.05 * picker2.value
|
||||||
|
callback.onNumberPicked(v)
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
|
||||||
|
InterfaceUtils.setupEditorAction(picker) { _, actionId, _ ->
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_DONE)
|
||||||
|
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshInitialValue(picker: NumberPicker) {
|
||||||
|
// Workaround for Android bug:
|
||||||
|
// https://code.google.com/p/android/issues/detail?id=35482
|
||||||
|
val f = NumberPicker::class.java.getDeclaredField("mInputText")
|
||||||
|
f.isAccessible = true
|
||||||
|
val inputText = f.get(picker) as EditText
|
||||||
|
inputText.filters = arrayOfNulls<InputFilter>(0)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.common.views
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.widget.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.core.tasks.*
|
||||||
|
|
||||||
|
class TaskProgressBar(
|
||||||
|
context: Context,
|
||||||
|
private val runner: TaskRunner
|
||||||
|
) : ProgressBar(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
android.R.attr.progressBarStyleHorizontal
|
||||||
|
), TaskRunner.Listener {
|
||||||
|
|
||||||
|
init {
|
||||||
|
visibility = BaseRootView.GONE
|
||||||
|
isIndeterminate = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTaskStarted(task: Task?) = update()
|
||||||
|
override fun onTaskFinished(task: Task?) = update()
|
||||||
|
|
||||||
|
override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
runner.addListener(this)
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
runner.removeListener(this)
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
val callback = {
|
||||||
|
val activeTaskCount = runner.activeTaskCount
|
||||||
|
val newVisibility = when (activeTaskCount) {
|
||||||
|
0 -> GONE
|
||||||
|
else -> VISIBLE
|
||||||
|
}
|
||||||
|
if (visibility != newVisibility) visibility = newVisibility
|
||||||
|
}
|
||||||
|
postDelayed(callback, 500)
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides views that are used across the app, such as RingView.
|
|
||||||
*/
|
|
||||||
package org.isoron.uhabits.activities.common.views;
|
|
@ -1,23 +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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides dialogs for editing habits and related classes.
|
|
||||||
*/
|
|
||||||
package org.isoron.uhabits.activities.habits.edit;
|
|
@ -1,102 +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.activities.habits.list;
|
|
||||||
|
|
||||||
import android.os.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.activities.*;
|
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
|
||||||
import org.isoron.uhabits.core.preferences.*;
|
|
||||||
import org.isoron.uhabits.core.ui.*;
|
|
||||||
import org.isoron.uhabits.core.utils.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activity that allows the user to see and modify the list of habits.
|
|
||||||
*/
|
|
||||||
public class ListHabitsActivity extends HabitsActivity
|
|
||||||
{
|
|
||||||
private HabitCardListAdapter adapter;
|
|
||||||
|
|
||||||
private ListHabitsRootView rootView;
|
|
||||||
|
|
||||||
private ListHabitsScreen screen;
|
|
||||||
|
|
||||||
private boolean pureBlack;
|
|
||||||
|
|
||||||
private Preferences prefs;
|
|
||||||
|
|
||||||
private MidnightTimer midnightTimer;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
midnightTimer = getAppComponent().getMidnightTimer();
|
|
||||||
HabitsActivityComponent component = getActivityComponent();
|
|
||||||
|
|
||||||
ListHabitsMenu menu = component.getListHabitsMenu();
|
|
||||||
ListHabitsSelectionMenu selectionMenu = component.getListHabitsSelectionMenu();
|
|
||||||
ListHabitsController controller = component.getListHabitsController();
|
|
||||||
|
|
||||||
adapter = component.getHabitCardListAdapter();
|
|
||||||
rootView = component.getListHabitsRootView();
|
|
||||||
screen = component.getListHabitsScreen();
|
|
||||||
|
|
||||||
prefs = getAppComponent().getPreferences();
|
|
||||||
pureBlack = prefs.isPureBlackEnabled();
|
|
||||||
|
|
||||||
screen.setMenu(menu);
|
|
||||||
screen.setController(controller);
|
|
||||||
screen.setSelectionMenu(selectionMenu);
|
|
||||||
rootView.setController(controller, selectionMenu);
|
|
||||||
|
|
||||||
// if(prefs.isSyncEnabled())
|
|
||||||
// startService(new Intent(this, SyncService.class));
|
|
||||||
|
|
||||||
setScreen(screen);
|
|
||||||
controller.onStartup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause()
|
|
||||||
{
|
|
||||||
midnightTimer.onPause();
|
|
||||||
screen.onDettached();
|
|
||||||
adapter.cancelRefresh();
|
|
||||||
super.onPause();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume()
|
|
||||||
{
|
|
||||||
adapter.refresh();
|
|
||||||
screen.onAttached();
|
|
||||||
rootView.postInvalidate();
|
|
||||||
midnightTimer.onResume();
|
|
||||||
|
|
||||||
if (prefs.getTheme() == ThemeSwitcher.THEME_DARK &&
|
|
||||||
prefs.isPureBlackEnabled() != pureBlack)
|
|
||||||
{
|
|
||||||
restartWithFade(ListHabitsActivity.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onResume();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list
|
||||||
|
|
||||||
|
import android.os.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
|
import org.isoron.uhabits.core.preferences.*
|
||||||
|
import org.isoron.uhabits.core.ui.ThemeSwitcher.*
|
||||||
|
import org.isoron.uhabits.core.utils.*
|
||||||
|
|
||||||
|
class ListHabitsActivity : HabitsActivity() {
|
||||||
|
|
||||||
|
var pureBlack: Boolean = false
|
||||||
|
lateinit var adapter: HabitCardListAdapter
|
||||||
|
lateinit var rootView: ListHabitsRootView
|
||||||
|
lateinit var screen: ListHabitsScreen
|
||||||
|
lateinit var prefs: Preferences
|
||||||
|
lateinit var midnightTimer: MidnightTimer
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
prefs = appComponent.preferences
|
||||||
|
pureBlack = prefs.isPureBlackEnabled
|
||||||
|
midnightTimer = appComponent.midnightTimer
|
||||||
|
rootView = component.listHabitsRootView
|
||||||
|
screen = component.listHabitsScreen
|
||||||
|
adapter = component.habitCardListAdapter
|
||||||
|
|
||||||
|
setScreen(screen)
|
||||||
|
component.listHabitsBehavior.onStartup()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
midnightTimer.onPause()
|
||||||
|
screen.onDettached()
|
||||||
|
adapter.cancelRefresh()
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
adapter.refresh()
|
||||||
|
screen.onAttached()
|
||||||
|
rootView.postInvalidate()
|
||||||
|
midnightTimer.onResume()
|
||||||
|
|
||||||
|
if (prefs.theme == THEME_DARK && prefs.isPureBlackEnabled != pureBlack) {
|
||||||
|
restartWithFade(ListHabitsActivity::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onResume()
|
||||||
|
}
|
||||||
|
}
|
@ -1,164 +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.activities.habits.list;
|
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.isoron.uhabits.core.tasks.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
import org.isoron.uhabits.tasks.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
public class ListHabitsController
|
|
||||||
implements HabitCardListController.HabitListener
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private final ListHabitsBehavior behavior;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final ListHabitsScreen screen;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final HabitCardListAdapter adapter;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final TaskRunner taskRunner;
|
|
||||||
|
|
||||||
private ImportDataTaskFactory importTaskFactory;
|
|
||||||
|
|
||||||
private ExportDBTaskFactory exportDBFactory;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ListHabitsController(@NonNull ListHabitsBehavior behavior,
|
|
||||||
@NonNull HabitCardListAdapter adapter,
|
|
||||||
@NonNull ListHabitsScreen screen,
|
|
||||||
@NonNull TaskRunner taskRunner,
|
|
||||||
@NonNull ImportDataTaskFactory importTaskFactory,
|
|
||||||
@NonNull ExportDBTaskFactory exportDBFactory)
|
|
||||||
{
|
|
||||||
this.behavior = behavior;
|
|
||||||
this.adapter = adapter;
|
|
||||||
this.screen = screen;
|
|
||||||
this.taskRunner = taskRunner;
|
|
||||||
this.importTaskFactory = importTaskFactory;
|
|
||||||
this.exportDBFactory = exportDBFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onEdit(@NonNull Habit habit, long timestamp)
|
|
||||||
{
|
|
||||||
behavior.onEdit(habit, timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onExportCSV()
|
|
||||||
{
|
|
||||||
behavior.onExportCSV();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onExportDB()
|
|
||||||
{
|
|
||||||
taskRunner.execute(exportDBFactory.create(filename ->
|
|
||||||
{
|
|
||||||
if (filename != null) screen.showSendFileScreen(filename);
|
|
||||||
else screen.showMessage(R.string.could_not_export);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHabitClick(@NonNull Habit h)
|
|
||||||
{
|
|
||||||
behavior.onClickHabit(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHabitReorder(@NonNull Habit from, @NonNull Habit to)
|
|
||||||
{
|
|
||||||
behavior.onReorderHabit(from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onImportData(@NonNull File file,
|
|
||||||
@NonNull OnFinishedListener finishedListener)
|
|
||||||
{
|
|
||||||
taskRunner.execute(importTaskFactory.create(file, result ->
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case ImportDataTask.SUCCESS:
|
|
||||||
adapter.refresh();
|
|
||||||
screen.showMessage(R.string.habits_imported);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ImportDataTask.NOT_RECOGNIZED:
|
|
||||||
screen.showMessage(R.string.file_not_recognized);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
screen.showMessage(R.string.could_not_import);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
finishedListener.onFinish();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onInvalidEdit()
|
|
||||||
{
|
|
||||||
screen.showMessage(R.string.long_press_to_edit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInvalidToggle()
|
|
||||||
{
|
|
||||||
screen.showMessage(R.string.long_press_to_toggle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onRepairDB()
|
|
||||||
{
|
|
||||||
behavior.onRepairDB();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onSendBugReport()
|
|
||||||
{
|
|
||||||
behavior.onSendBugReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStartup()
|
|
||||||
{
|
|
||||||
behavior.onStartup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onToggle(@NonNull Habit habit, long timestamp)
|
|
||||||
{
|
|
||||||
behavior.onToggle(habit, timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnFinishedListener
|
|
||||||
{
|
|
||||||
void onFinish();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +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.activities.habits.list;
|
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.view.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.core.preferences.*;
|
|
||||||
import org.isoron.uhabits.core.ui.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
public class ListHabitsMenu extends BaseMenu
|
|
||||||
{
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final ListHabitsMenuBehavior behavior;
|
|
||||||
|
|
||||||
private final Preferences preferences;
|
|
||||||
|
|
||||||
private ThemeSwitcher themeSwitcher;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ListHabitsMenu(@NonNull BaseActivity activity,
|
|
||||||
@NonNull Preferences preferences,
|
|
||||||
@NonNull ThemeSwitcher themeSwitcher,
|
|
||||||
@NonNull ListHabitsMenuBehavior behavior)
|
|
||||||
{
|
|
||||||
super(activity);
|
|
||||||
this.preferences = preferences;
|
|
||||||
this.themeSwitcher = themeSwitcher;
|
|
||||||
this.behavior = behavior;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@NonNull Menu menu)
|
|
||||||
{
|
|
||||||
MenuItem nightModeItem = menu.findItem(R.id.actionToggleNightMode);
|
|
||||||
MenuItem hideArchivedItem = menu.findItem(R.id.actionHideArchived);
|
|
||||||
MenuItem hideCompletedItem = menu.findItem(R.id.actionHideCompleted);
|
|
||||||
nightModeItem.setChecked(themeSwitcher.isNightMode());
|
|
||||||
hideArchivedItem.setChecked(!preferences.getShowArchived());
|
|
||||||
hideCompletedItem.setChecked(!preferences.getShowCompleted());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onItemSelected(@NonNull MenuItem item)
|
|
||||||
{
|
|
||||||
switch (item.getItemId())
|
|
||||||
{
|
|
||||||
case R.id.actionToggleNightMode:
|
|
||||||
behavior.onToggleNightMode();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionAdd:
|
|
||||||
behavior.onCreateHabit();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionFAQ:
|
|
||||||
behavior.onViewFAQ();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionAbout:
|
|
||||||
behavior.onViewAbout();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionSettings:
|
|
||||||
behavior.onViewSettings();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionHideArchived:
|
|
||||||
behavior.onToggleShowArchived();
|
|
||||||
invalidate();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionHideCompleted:
|
|
||||||
behavior.onToggleShowCompleted();
|
|
||||||
invalidate();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionSortColor:
|
|
||||||
behavior.onSortByColor();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionSortManual:
|
|
||||||
behavior.onSortByManually();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionSortName:
|
|
||||||
behavior.onSortByName();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.actionSortScore:
|
|
||||||
behavior.onSortByScore();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getMenuResourceId()
|
|
||||||
{
|
|
||||||
return R.menu.list_habits;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list
|
||||||
|
|
||||||
|
import android.view.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.preferences.*
|
||||||
|
import org.isoron.uhabits.core.ui.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
class ListHabitsMenu @Inject constructor(
|
||||||
|
activity: BaseActivity,
|
||||||
|
private val preferences: Preferences,
|
||||||
|
private val themeSwitcher: ThemeSwitcher,
|
||||||
|
private val behavior: ListHabitsMenuBehavior
|
||||||
|
) : BaseMenu(activity) {
|
||||||
|
|
||||||
|
override fun onCreate(menu: Menu) {
|
||||||
|
val nightModeItem = menu.findItem(R.id.actionToggleNightMode)
|
||||||
|
val hideArchivedItem = menu.findItem(R.id.actionHideArchived)
|
||||||
|
val hideCompletedItem = menu.findItem(R.id.actionHideCompleted)
|
||||||
|
nightModeItem.isChecked = themeSwitcher.isNightMode
|
||||||
|
hideArchivedItem.isChecked = !preferences.showArchived
|
||||||
|
hideCompletedItem.isChecked = !preferences.showCompleted
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.actionToggleNightMode -> {
|
||||||
|
behavior.onToggleNightMode()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionAdd -> {
|
||||||
|
behavior.onCreateHabit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionFAQ -> {
|
||||||
|
behavior.onViewFAQ()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionAbout -> {
|
||||||
|
behavior.onViewAbout()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionSettings -> {
|
||||||
|
behavior.onViewSettings()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionHideArchived -> {
|
||||||
|
behavior.onToggleShowArchived()
|
||||||
|
invalidate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionHideCompleted -> {
|
||||||
|
behavior.onToggleShowCompleted()
|
||||||
|
invalidate()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionSortColor -> {
|
||||||
|
behavior.onSortByColor()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionSortManual -> {
|
||||||
|
behavior.onSortByManually()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionSortName -> {
|
||||||
|
behavior.onSortByName()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.actionSortScore -> {
|
||||||
|
behavior.onSortByScore()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMenuResourceId() = R.menu.list_habits
|
||||||
|
}
|
@ -1,69 +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.activities.habits.list;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.*;
|
|
||||||
import org.isoron.uhabits.activities.*;
|
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
import dagger.*;
|
|
||||||
|
|
||||||
class BugReporterProxy extends AndroidBugReporter
|
|
||||||
implements ListHabitsBehavior.BugReporter
|
|
||||||
{
|
|
||||||
@Inject
|
|
||||||
public BugReporterProxy(@AppContext @NonNull Context context)
|
|
||||||
{
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public abstract class ListHabitsModule
|
|
||||||
{
|
|
||||||
@Binds
|
|
||||||
abstract ListHabitsMenuBehavior.Adapter getAdapter(HabitCardListAdapter adapter);
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract ListHabitsBehavior.BugReporter getBugReporter(BugReporterProxy proxy);
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract ListHabitsMenuBehavior.Screen getMenuScreen(ListHabitsScreen screen);
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract ListHabitsBehavior.Screen getScreen(ListHabitsScreen screen);
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract ListHabitsSelectionMenuBehavior.Adapter getSelMenuAdapter(
|
|
||||||
HabitCardListAdapter adapter);
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract ListHabitsSelectionMenuBehavior.Screen getSelMenuScreen(
|
|
||||||
ListHabitsScreen screen);
|
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract ListHabitsBehavior.DirFinder getSystem(HabitsDirFinder system);
|
|
||||||
}
|
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import dagger.*
|
||||||
|
import org.isoron.androidbase.*
|
||||||
|
import org.isoron.uhabits.activities.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
|
class BugReporterProxy
|
||||||
|
@Inject constructor(
|
||||||
|
@AppContext context: Context
|
||||||
|
) : AndroidBugReporter(context), ListHabitsBehavior.BugReporter
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class ListHabitsModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun getAdapter(adapter: HabitCardListAdapter): ListHabitsMenuBehavior.Adapter
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun getBugReporter(proxy: BugReporterProxy): ListHabitsBehavior.BugReporter
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun getMenuScreen(screen: ListHabitsScreen): ListHabitsMenuBehavior.Screen
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun getScreen(screen: ListHabitsScreen): ListHabitsBehavior.Screen
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun getSelMenuAdapter(adapter: HabitCardListAdapter): ListHabitsSelectionMenuBehavior.Adapter
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun getSelMenuScreen(screen: ListHabitsScreen): ListHabitsSelectionMenuBehavior.Screen
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun getSystem(system: HabitsDirFinder): ListHabitsBehavior.DirFinder
|
||||||
|
}
|
@ -1,198 +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.activities.habits.list;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.view.*;
|
|
||||||
import android.widget.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.androidbase.utils.*;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.activities.common.views.*;
|
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.isoron.uhabits.core.tasks.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
import butterknife.*;
|
|
||||||
|
|
||||||
import static org.isoron.androidbase.utils.InterfaceUtils.*;
|
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
public class ListHabitsRootView extends BaseRootView
|
|
||||||
implements ModelObservable.Listener, TaskRunner.Listener
|
|
||||||
{
|
|
||||||
public static final int MAX_CHECKMARK_COUNT = 60;
|
|
||||||
|
|
||||||
@BindView(R.id.listView)
|
|
||||||
HabitCardListView listView;
|
|
||||||
|
|
||||||
@BindView(R.id.llEmpty)
|
|
||||||
ViewGroup llEmpty;
|
|
||||||
|
|
||||||
@BindView(R.id.tvStarEmpty)
|
|
||||||
TextView tvStarEmpty;
|
|
||||||
|
|
||||||
@BindView(R.id.toolbar)
|
|
||||||
Toolbar toolbar;
|
|
||||||
|
|
||||||
@BindView(R.id.progressBar)
|
|
||||||
ProgressBar progressBar;
|
|
||||||
|
|
||||||
@BindView(R.id.hintView)
|
|
||||||
HintView hintView;
|
|
||||||
|
|
||||||
@BindView(R.id.header)
|
|
||||||
HeaderView header;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final HabitCardListAdapter listAdapter;
|
|
||||||
|
|
||||||
private final TaskRunner runner;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ListHabitsRootView(@ActivityContext Context context,
|
|
||||||
@NonNull HintListFactory hintListFactory,
|
|
||||||
@NonNull HabitCardListAdapter listAdapter,
|
|
||||||
@NonNull TaskRunner runner)
|
|
||||||
{
|
|
||||||
super(context);
|
|
||||||
addView(inflate(getContext(), R.layout.list_habits, null));
|
|
||||||
ButterKnife.bind(this);
|
|
||||||
|
|
||||||
this.listAdapter = listAdapter;
|
|
||||||
listView.setAdapter(listAdapter);
|
|
||||||
listAdapter.setListView(listView);
|
|
||||||
|
|
||||||
this.runner = runner;
|
|
||||||
progressBar.setIndeterminate(true);
|
|
||||||
tvStarEmpty.setTypeface(InterfaceUtils.getFontAwesome(getContext()));
|
|
||||||
|
|
||||||
String hints[] =
|
|
||||||
getContext().getResources().getStringArray(R.array.hints);
|
|
||||||
HintList hintList = hintListFactory.create(hints);
|
|
||||||
hintView.setHints(hintList);
|
|
||||||
|
|
||||||
initToolbar();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Toolbar getToolbar()
|
|
||||||
{
|
|
||||||
return toolbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onModelChange()
|
|
||||||
{
|
|
||||||
updateEmptyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTaskFinished(Task task)
|
|
||||||
{
|
|
||||||
updateProgressBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTaskStarted(Task task)
|
|
||||||
{
|
|
||||||
updateProgressBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setController(@NonNull ListHabitsController controller,
|
|
||||||
@NonNull ListHabitsSelectionMenu menu)
|
|
||||||
{
|
|
||||||
HabitCardListController listController =
|
|
||||||
new HabitCardListController(listAdapter);
|
|
||||||
|
|
||||||
listController.setHabitListener(controller);
|
|
||||||
listController.setSelectionListener(menu);
|
|
||||||
listView.setController(listController);
|
|
||||||
menu.setListController(listController);
|
|
||||||
header.setScrollController(new ScrollableChart.ScrollController()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onDataOffsetChanged(int newDataOffset)
|
|
||||||
{
|
|
||||||
listView.setDataOffset(newDataOffset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onAttachedToWindow()
|
|
||||||
{
|
|
||||||
super.onAttachedToWindow();
|
|
||||||
runner.addListener(this);
|
|
||||||
updateProgressBar();
|
|
||||||
listAdapter.getObservable().addListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDetachedFromWindow()
|
|
||||||
{
|
|
||||||
listAdapter.getObservable().removeListener(this);
|
|
||||||
runner.removeListener(this);
|
|
||||||
super.onDetachedFromWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
|
||||||
{
|
|
||||||
int count = getCheckmarkCount();
|
|
||||||
header.setButtonCount(count);
|
|
||||||
header.setMaxDataOffset(Math.max(MAX_CHECKMARK_COUNT - count, 0));
|
|
||||||
listView.setCheckmarkCount(count);
|
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getCheckmarkCount()
|
|
||||||
{
|
|
||||||
float nameWidth = getDimension(getContext(), R.dimen.habitNameWidth);
|
|
||||||
float labelWidth = Math.max(getMeasuredWidth() / 3, nameWidth);
|
|
||||||
float buttonWidth = getDimension(getContext(), R.dimen.checkmarkWidth);
|
|
||||||
return Math.min(MAX_CHECKMARK_COUNT, Math.max(0,
|
|
||||||
(int) ((getMeasuredWidth() - labelWidth) / buttonWidth)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateEmptyView()
|
|
||||||
{
|
|
||||||
llEmpty.setVisibility(
|
|
||||||
listAdapter.getItemCount() > 0 ? View.GONE : View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateProgressBar()
|
|
||||||
{
|
|
||||||
postDelayed(() ->
|
|
||||||
{
|
|
||||||
int activeTaskCount = runner.getActiveTaskCount();
|
|
||||||
int newVisibility = activeTaskCount > 0 ? VISIBLE : GONE;
|
|
||||||
if (progressBar.getVisibility() != newVisibility)
|
|
||||||
progressBar.setVisibility(newVisibility);
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.os.Build.VERSION.*
|
||||||
|
import android.os.Build.VERSION_CODES.*
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
|
import android.view.ViewGroup.LayoutParams.*
|
||||||
|
import android.widget.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.common.views.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.isoron.uhabits.core.preferences.*
|
||||||
|
import org.isoron.uhabits.core.tasks.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import org.isoron.uhabits.core.utils.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
import java.lang.Math.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
|
const val MAX_CHECKMARK_COUNT = 60
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
class ListHabitsRootView @Inject constructor(
|
||||||
|
@ActivityContext context: Context,
|
||||||
|
hintListFactory: HintListFactory,
|
||||||
|
preferences: Preferences,
|
||||||
|
midnightTimer: MidnightTimer,
|
||||||
|
runner: TaskRunner,
|
||||||
|
private val listAdapter: HabitCardListAdapter,
|
||||||
|
habitCardListViewFactory: HabitCardListViewFactory
|
||||||
|
) : BaseRootView(context), ModelObservable.Listener {
|
||||||
|
|
||||||
|
val listView: HabitCardListView = habitCardListViewFactory.create()
|
||||||
|
val llEmpty = EmptyListView(context)
|
||||||
|
val tbar = buildToolbar()
|
||||||
|
val progressBar = TaskProgressBar(context, runner)
|
||||||
|
val hintView: HintView
|
||||||
|
val header = HeaderView(context, preferences, midnightTimer)
|
||||||
|
|
||||||
|
init {
|
||||||
|
val hints = resources.getStringArray(R.array.hints)
|
||||||
|
val hintList = hintListFactory.create(hints)
|
||||||
|
hintView = HintView(context, hintList)
|
||||||
|
|
||||||
|
addView(RelativeLayout(context).apply {
|
||||||
|
background = sres.getDrawable(R.attr.windowBackgroundColor)
|
||||||
|
addAtTop(tbar)
|
||||||
|
addBelow(header, tbar)
|
||||||
|
addBelow(listView, header, height = MATCH_PARENT)
|
||||||
|
addBelow(llEmpty, header, height = MATCH_PARENT)
|
||||||
|
addBelow(progressBar, header) {
|
||||||
|
it.topMargin = dp(-6.0f).toInt()
|
||||||
|
}
|
||||||
|
addAtBottom(hintView)
|
||||||
|
if (SDK_INT < LOLLIPOP) {
|
||||||
|
addBelow(ShadowView(context), tbar)
|
||||||
|
addBelow(ShadowView(context), header)
|
||||||
|
}
|
||||||
|
}, MATCH_PARENT, MATCH_PARENT)
|
||||||
|
|
||||||
|
listAdapter.setListView(listView)
|
||||||
|
initToolbar()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getToolbar(): Toolbar {
|
||||||
|
return tbar
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onModelChange() {
|
||||||
|
updateEmptyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupControllers() {
|
||||||
|
header.setScrollController(object : ScrollableChart.ScrollController {
|
||||||
|
override fun onDataOffsetChanged(newDataOffset: Int) {
|
||||||
|
listView.dataOffset = newDataOffset
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
setupControllers()
|
||||||
|
listAdapter.observable.addListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
listAdapter.observable.removeListener(this)
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||||
|
val count = getCheckmarkCount()
|
||||||
|
header.buttonCount = count
|
||||||
|
header.setMaxDataOffset(max(MAX_CHECKMARK_COUNT - count, 0))
|
||||||
|
listView.checkmarkCount = count
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCheckmarkCount(): Int {
|
||||||
|
val nameWidth = dim(R.dimen.habitNameWidth)
|
||||||
|
val buttonWidth = dim(R.dimen.checkmarkWidth)
|
||||||
|
val labelWidth = max((measuredWidth / 3).toFloat(), nameWidth)
|
||||||
|
val buttonCount = ((measuredWidth - labelWidth) / buttonWidth).toInt()
|
||||||
|
return min(MAX_CHECKMARK_COUNT, max(0, buttonCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateEmptyView() {
|
||||||
|
llEmpty.visibility = when (listAdapter.itemCount) {
|
||||||
|
0 -> VISIBLE
|
||||||
|
else -> GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,441 +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.activities.habits.list;
|
|
||||||
|
|
||||||
import android.app.*;
|
|
||||||
import android.content.*;
|
|
||||||
import android.net.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.text.*;
|
|
||||||
import android.view.*;
|
|
||||||
import android.widget.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.androidbase.utils.*;
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.activities.common.dialogs.*;
|
|
||||||
import org.isoron.uhabits.activities.habits.edit.*;
|
|
||||||
import org.isoron.uhabits.core.commands.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
import org.isoron.uhabits.core.preferences.*;
|
|
||||||
import org.isoron.uhabits.core.ui.*;
|
|
||||||
import org.isoron.uhabits.core.ui.callbacks.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
import org.isoron.uhabits.intents.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.lang.reflect.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
import static android.content.DialogInterface.BUTTON_POSITIVE;
|
|
||||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
public class ListHabitsScreen extends BaseScreen
|
|
||||||
implements CommandRunner.Listener, ListHabitsBehavior.Screen,
|
|
||||||
ListHabitsMenuBehavior.Screen,
|
|
||||||
ListHabitsSelectionMenuBehavior.Screen
|
|
||||||
{
|
|
||||||
public static final int REQUEST_OPEN_DOCUMENT = 6;
|
|
||||||
|
|
||||||
public static final int REQUEST_SETTINGS = 7;
|
|
||||||
|
|
||||||
public static final int RESULT_BUG_REPORT = 4;
|
|
||||||
|
|
||||||
public static final int RESULT_EXPORT_CSV = 2;
|
|
||||||
|
|
||||||
public static final int RESULT_EXPORT_DB = 3;
|
|
||||||
|
|
||||||
public static final int RESULT_IMPORT_DATA = 1;
|
|
||||||
|
|
||||||
public static final int RESULT_REPAIR_DB = 5;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private ListHabitsController controller;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final IntentFactory intentFactory;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final CommandRunner commandRunner;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final ConfirmDeleteDialogFactory confirmDeleteDialogFactory;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final ColorPickerDialogFactory colorPickerFactory;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final EditHabitDialogFactory editHabitDialogFactory;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final ThemeSwitcher themeSwitcher;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Preferences prefs;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ListHabitsScreen(@NonNull BaseActivity activity,
|
|
||||||
@NonNull CommandRunner commandRunner,
|
|
||||||
@NonNull ListHabitsRootView rootView,
|
|
||||||
@NonNull IntentFactory intentFactory,
|
|
||||||
@NonNull ThemeSwitcher themeSwitcher,
|
|
||||||
@NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory,
|
|
||||||
@NonNull ColorPickerDialogFactory colorPickerFactory,
|
|
||||||
@NonNull EditHabitDialogFactory editHabitDialogFactory,
|
|
||||||
@NonNull Preferences prefs)
|
|
||||||
{
|
|
||||||
super(activity);
|
|
||||||
setRootView(rootView);
|
|
||||||
this.prefs = prefs;
|
|
||||||
this.colorPickerFactory = colorPickerFactory;
|
|
||||||
this.commandRunner = commandRunner;
|
|
||||||
this.confirmDeleteDialogFactory = confirmDeleteDialogFactory;
|
|
||||||
this.editHabitDialogFactory = editHabitDialogFactory;
|
|
||||||
this.intentFactory = intentFactory;
|
|
||||||
this.themeSwitcher = themeSwitcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
@StringRes
|
|
||||||
private Integer getExecuteString(@NonNull Command command)
|
|
||||||
{
|
|
||||||
if(command instanceof ArchiveHabitsCommand)
|
|
||||||
return R.string.toast_habit_archived;
|
|
||||||
|
|
||||||
if(command instanceof ChangeHabitColorCommand)
|
|
||||||
return R.string.toast_habit_changed;
|
|
||||||
|
|
||||||
if(command instanceof CreateHabitCommand)
|
|
||||||
return R.string.toast_habit_created;
|
|
||||||
|
|
||||||
if(command instanceof DeleteHabitsCommand)
|
|
||||||
return R.string.toast_habit_deleted;
|
|
||||||
|
|
||||||
if(command instanceof EditHabitCommand)
|
|
||||||
return R.string.toast_habit_changed;
|
|
||||||
|
|
||||||
if(command instanceof UnarchiveHabitsCommand)
|
|
||||||
return R.string.toast_habit_unarchived;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onAttached()
|
|
||||||
{
|
|
||||||
commandRunner.addListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCommandExecuted(@NonNull Command command,
|
|
||||||
@Nullable Long refreshKey)
|
|
||||||
{
|
|
||||||
if (command.isRemote()) return;
|
|
||||||
showMessage(getExecuteString(command));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDettached()
|
|
||||||
{
|
|
||||||
commandRunner.removeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResult(int requestCode, int resultCode, Intent data)
|
|
||||||
{
|
|
||||||
if (requestCode == REQUEST_OPEN_DOCUMENT)
|
|
||||||
onOpenDocumentResult(resultCode, data);
|
|
||||||
|
|
||||||
if (requestCode == REQUEST_SETTINGS) onSettingsResult(resultCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setController(@Nullable ListHabitsController controller)
|
|
||||||
{
|
|
||||||
this.controller = controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyTheme()
|
|
||||||
{
|
|
||||||
themeSwitcher.apply();
|
|
||||||
activity.restartWithFade(ListHabitsActivity.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showAboutScreen()
|
|
||||||
{
|
|
||||||
Intent intent = intentFactory.startAboutActivity(activity);
|
|
||||||
activity.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showColorPicker(int defaultColor,
|
|
||||||
@NonNull OnColorPickedCallback callback) {
|
|
||||||
ColorPickerDialog picker = colorPickerFactory.create(defaultColor);
|
|
||||||
picker.setListener(callback);
|
|
||||||
activity.showDialog(picker, "picker");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showCreateBooleanHabitScreen()
|
|
||||||
{
|
|
||||||
EditHabitDialog dialog;
|
|
||||||
dialog = editHabitDialogFactory.createBoolean();
|
|
||||||
activity.showDialog(dialog, "editHabit");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showCreateHabitScreen()
|
|
||||||
{
|
|
||||||
if (!prefs.isNumericalHabitsFeatureEnabled())
|
|
||||||
{
|
|
||||||
showCreateBooleanHabitScreen();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dialog dialog = new AlertDialog.Builder(activity)
|
|
||||||
.setTitle("Type of habit")
|
|
||||||
.setItems(R.array.habitTypes, (d, which) ->
|
|
||||||
{
|
|
||||||
if (which == 0) showCreateBooleanHabitScreen();
|
|
||||||
else showCreateNumericalHabitScreen();
|
|
||||||
})
|
|
||||||
.create();
|
|
||||||
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showDeleteConfirmationScreen(
|
|
||||||
@NonNull OnConfirmedCallback callback)
|
|
||||||
{
|
|
||||||
activity.showDialog(confirmDeleteDialogFactory.create(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showEditHabitsScreen(List<Habit> habits)
|
|
||||||
{
|
|
||||||
EditHabitDialog dialog;
|
|
||||||
dialog = editHabitDialogFactory.edit(habits.get(0));
|
|
||||||
activity.showDialog(dialog, "editNumericalHabit");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showFAQScreen()
|
|
||||||
{
|
|
||||||
Intent intent = intentFactory.viewFAQ(activity);
|
|
||||||
activity.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showHabitScreen(@NonNull Habit habit)
|
|
||||||
{
|
|
||||||
Intent intent = intentFactory.startShowHabitActivity(activity, habit);
|
|
||||||
activity.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showImportScreen()
|
|
||||||
{
|
|
||||||
Intent intent = intentFactory.openDocument();
|
|
||||||
activity.startActivityForResult(intent, REQUEST_OPEN_DOCUMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showIntroScreen()
|
|
||||||
{
|
|
||||||
Intent intent = intentFactory.startIntroActivity(activity);
|
|
||||||
activity.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showMessage(@NonNull ListHabitsBehavior.Message m)
|
|
||||||
{
|
|
||||||
switch (m)
|
|
||||||
{
|
|
||||||
case COULD_NOT_EXPORT:
|
|
||||||
showMessage(R.string.could_not_export);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IMPORT_SUCCESSFUL:
|
|
||||||
showMessage(R.string.habits_imported);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IMPORT_FAILED:
|
|
||||||
showMessage(R.string.could_not_import);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DATABASE_REPAIRED:
|
|
||||||
showMessage(R.string.database_repaired);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case COULD_NOT_GENERATE_BUG_REPORT:
|
|
||||||
showMessage(R.string.bug_report_failed);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FILE_NOT_RECOGNIZED:
|
|
||||||
showMessage(R.string.file_not_recognized);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showNumberPicker(double value,
|
|
||||||
@NonNull String unit,
|
|
||||||
@NonNull
|
|
||||||
ListHabitsBehavior.NumberPickerCallback callback)
|
|
||||||
{
|
|
||||||
LayoutInflater inflater = activity.getLayoutInflater();
|
|
||||||
View view = inflater.inflate(R.layout.number_picker_dialog, null);
|
|
||||||
|
|
||||||
final NumberPicker picker;
|
|
||||||
final NumberPicker picker2;
|
|
||||||
final TextView tvUnit;
|
|
||||||
|
|
||||||
picker = (NumberPicker) view.findViewById(R.id.picker);
|
|
||||||
picker2 = (NumberPicker) view.findViewById(R.id.picker2);
|
|
||||||
tvUnit = (TextView) view.findViewById(R.id.tvUnit);
|
|
||||||
|
|
||||||
int intValue = (int) Math.round(value * 100);
|
|
||||||
|
|
||||||
picker.setMinValue(0);
|
|
||||||
picker.setMaxValue(Integer.MAX_VALUE / 100);
|
|
||||||
picker.setValue(intValue / 100);
|
|
||||||
picker.setWrapSelectorWheel(false);
|
|
||||||
|
|
||||||
picker2.setMinValue(0);
|
|
||||||
picker2.setMaxValue(19);
|
|
||||||
picker2.setFormatter(v -> String.format("%02d", 5 * v));
|
|
||||||
picker2.setValue((intValue % 100) / 5);
|
|
||||||
refreshInitialValue(picker2);
|
|
||||||
|
|
||||||
tvUnit.setText(unit);
|
|
||||||
|
|
||||||
AlertDialog dialog = new AlertDialog.Builder(activity)
|
|
||||||
.setView(view)
|
|
||||||
.setTitle(R.string.change_value)
|
|
||||||
.setPositiveButton(android.R.string.ok, (d, which) ->
|
|
||||||
{
|
|
||||||
picker.clearFocus();
|
|
||||||
double v = picker.getValue() + 0.05 * picker2.getValue();
|
|
||||||
callback.onNumberPicked(v);
|
|
||||||
})
|
|
||||||
.create();
|
|
||||||
|
|
||||||
InterfaceUtils.setupEditorAction(picker, (v, actionId, event) ->
|
|
||||||
{
|
|
||||||
if (actionId == IME_ACTION_DONE)
|
|
||||||
dialog.getButton(BUTTON_POSITIVE).performClick();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showSendBugReportToDeveloperScreen(String log)
|
|
||||||
{
|
|
||||||
int to = R.string.bugReportTo;
|
|
||||||
int subject = R.string.bugReportSubject;
|
|
||||||
showSendEmailScreen(to, subject, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showSettingsScreen()
|
|
||||||
{
|
|
||||||
Intent intent = intentFactory.startSettingsActivity(activity);
|
|
||||||
activity.startActivityForResult(intent, REQUEST_SETTINGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOpenDocumentResult(int resultCode, Intent data)
|
|
||||||
{
|
|
||||||
if (controller == null) return;
|
|
||||||
if (resultCode != Activity.RESULT_OK) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Uri uri = data.getData();
|
|
||||||
ContentResolver cr = activity.getContentResolver();
|
|
||||||
InputStream is = cr.openInputStream(uri);
|
|
||||||
|
|
||||||
File cacheDir = activity.getExternalCacheDir();
|
|
||||||
File tempFile = File.createTempFile("import", "", cacheDir);
|
|
||||||
|
|
||||||
FileUtils.copy(is, tempFile);
|
|
||||||
controller.onImportData(tempFile, () -> tempFile.delete());
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
showMessage(R.string.could_not_import);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onSettingsResult(int resultCode)
|
|
||||||
{
|
|
||||||
if (controller == null) return;
|
|
||||||
|
|
||||||
switch (resultCode)
|
|
||||||
{
|
|
||||||
case RESULT_IMPORT_DATA:
|
|
||||||
showImportScreen();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RESULT_EXPORT_CSV:
|
|
||||||
controller.onExportCSV();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RESULT_EXPORT_DB:
|
|
||||||
controller.onExportDB();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RESULT_BUG_REPORT:
|
|
||||||
controller.onSendBugReport();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RESULT_REPAIR_DB:
|
|
||||||
controller.onRepairDB();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshInitialValue(NumberPicker picker2)
|
|
||||||
{
|
|
||||||
// Workaround for a bug on Android:
|
|
||||||
// https://code.google.com/p/android/issues/detail?id=35482
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Field f = NumberPicker.class.getDeclaredField("mInputText");
|
|
||||||
f.setAccessible(true);
|
|
||||||
EditText inputText = (EditText) f.get(picker2);
|
|
||||||
inputText.setFilters(new InputFilter[0]);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showCreateNumericalHabitScreen()
|
|
||||||
{
|
|
||||||
EditHabitDialog dialog;
|
|
||||||
dialog = editHabitDialogFactory.createNumerical();
|
|
||||||
activity.showDialog(dialog, "editHabit");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list
|
||||||
|
|
||||||
|
import android.app.*
|
||||||
|
import android.content.*
|
||||||
|
import android.support.annotation.*
|
||||||
|
import dagger.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.androidbase.utils.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.common.dialogs.*
|
||||||
|
import org.isoron.uhabits.activities.habits.edit.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
|
import org.isoron.uhabits.core.commands.*
|
||||||
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.isoron.uhabits.core.preferences.*
|
||||||
|
import org.isoron.uhabits.core.tasks.*
|
||||||
|
import org.isoron.uhabits.core.ui.*
|
||||||
|
import org.isoron.uhabits.core.ui.callbacks.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior.Message.*
|
||||||
|
import org.isoron.uhabits.intents.*
|
||||||
|
import org.isoron.uhabits.tasks.*
|
||||||
|
import java.io.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
|
const val RESULT_IMPORT_DATA = 1
|
||||||
|
const val RESULT_EXPORT_CSV = 2
|
||||||
|
const val RESULT_EXPORT_DB = 3
|
||||||
|
const val RESULT_BUG_REPORT = 4
|
||||||
|
const val RESULT_REPAIR_DB = 5
|
||||||
|
const val REQUEST_OPEN_DOCUMENT = 6
|
||||||
|
const val REQUEST_SETTINGS = 7
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
class ListHabitsScreen
|
||||||
|
@Inject constructor(
|
||||||
|
activity: BaseActivity,
|
||||||
|
rootView: ListHabitsRootView,
|
||||||
|
private val commandRunner: CommandRunner,
|
||||||
|
private val intentFactory: IntentFactory,
|
||||||
|
private val themeSwitcher: ThemeSwitcher,
|
||||||
|
private val preferences: Preferences,
|
||||||
|
private val adapter: HabitCardListAdapter,
|
||||||
|
private val taskRunner: TaskRunner,
|
||||||
|
private val exportDBFactory: ExportDBTaskFactory,
|
||||||
|
private val importTaskFactory: ImportDataTaskFactory,
|
||||||
|
private val confirmDeleteDialogFactory: ConfirmDeleteDialogFactory,
|
||||||
|
private val colorPickerFactory: ColorPickerDialogFactory,
|
||||||
|
private val editHabitDialogFactory: EditHabitDialogFactory,
|
||||||
|
private val numberPickerFactory: NumberPickerFactory,
|
||||||
|
private val behavior: Lazy<ListHabitsBehavior>,
|
||||||
|
private val menu: Lazy<ListHabitsMenu>,
|
||||||
|
private val selectionMenu: Lazy<ListHabitsSelectionMenu>
|
||||||
|
) : BaseScreen(activity),
|
||||||
|
CommandRunner.Listener,
|
||||||
|
ListHabitsBehavior.Screen,
|
||||||
|
ListHabitsMenuBehavior.Screen,
|
||||||
|
ListHabitsSelectionMenuBehavior.Screen {
|
||||||
|
|
||||||
|
init {
|
||||||
|
setRootView(rootView)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAttached() {
|
||||||
|
setMenu(menu.get())
|
||||||
|
setSelectionMenu(selectionMenu.get())
|
||||||
|
commandRunner.addListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDettached() {
|
||||||
|
commandRunner.removeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCommandExecuted(command: Command, refreshKey: Long?) {
|
||||||
|
if (command.isRemote) return
|
||||||
|
showMessage(getExecuteString(command))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
when (requestCode) {
|
||||||
|
REQUEST_OPEN_DOCUMENT -> onOpenDocumentResult(resultCode, data)
|
||||||
|
REQUEST_SETTINGS -> onSettingsResult(resultCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onOpenDocumentResult(resultCode: Int, data: Intent?) {
|
||||||
|
if (data == null) return
|
||||||
|
if (resultCode != Activity.RESULT_OK) return
|
||||||
|
try {
|
||||||
|
val inStream = activity.contentResolver.openInputStream(data.data)
|
||||||
|
val cacheDir = activity.externalCacheDir
|
||||||
|
val tempFile = File.createTempFile("import", "", cacheDir)
|
||||||
|
FileUtils.copy(inStream, tempFile)
|
||||||
|
onImportData(tempFile) { tempFile.delete() }
|
||||||
|
} catch (e: IOException) {
|
||||||
|
showMessage(R.string.could_not_import)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSettingsResult(resultCode: Int) {
|
||||||
|
when (resultCode) {
|
||||||
|
RESULT_IMPORT_DATA -> showImportScreen()
|
||||||
|
RESULT_EXPORT_CSV -> behavior.get().onExportCSV()
|
||||||
|
RESULT_EXPORT_DB -> onExportDB()
|
||||||
|
RESULT_BUG_REPORT -> behavior.get().onSendBugReport()
|
||||||
|
RESULT_REPAIR_DB -> behavior.get().onRepairDB()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyTheme() {
|
||||||
|
themeSwitcher.apply()
|
||||||
|
activity.restartWithFade(ListHabitsActivity::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showAboutScreen() {
|
||||||
|
val intent = intentFactory.startAboutActivity(activity)
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showCreateBooleanHabitScreen() {
|
||||||
|
val dialog = editHabitDialogFactory.createBoolean()
|
||||||
|
activity.showDialog(dialog, "editHabit")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showCreateHabitScreen() {
|
||||||
|
if (!preferences.isNumericalHabitsFeatureEnabled) {
|
||||||
|
showCreateBooleanHabitScreen()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val dialog = AlertDialog.Builder(activity)
|
||||||
|
.setTitle("Type of habit")
|
||||||
|
.setItems(R.array.habitTypes) { _, which ->
|
||||||
|
if (which == 0) showCreateBooleanHabitScreen()
|
||||||
|
else showCreateNumericalHabitScreen()
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showDeleteConfirmationScreen(callback: OnConfirmedCallback) {
|
||||||
|
activity.showDialog(confirmDeleteDialogFactory.create(callback))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showEditHabitsScreen(habits: List<Habit>) {
|
||||||
|
val dialog = editHabitDialogFactory.edit(habits[0])
|
||||||
|
activity.showDialog(dialog, "editNumericalHabit")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showFAQScreen() {
|
||||||
|
val intent = intentFactory.viewFAQ(activity)
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showHabitScreen(habit: Habit) {
|
||||||
|
val intent = intentFactory.startShowHabitActivity(activity, habit)
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showImportScreen() {
|
||||||
|
val intent = intentFactory.openDocument()
|
||||||
|
activity.startActivityForResult(intent, REQUEST_OPEN_DOCUMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showIntroScreen() {
|
||||||
|
val intent = intentFactory.startIntroActivity(activity)
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showMessage(m: ListHabitsBehavior.Message) {
|
||||||
|
showMessage(when (m) {
|
||||||
|
COULD_NOT_EXPORT -> R.string.could_not_export
|
||||||
|
IMPORT_SUCCESSFUL -> R.string.habits_imported
|
||||||
|
IMPORT_FAILED -> R.string.could_not_import
|
||||||
|
DATABASE_REPAIRED -> R.string.database_repaired
|
||||||
|
COULD_NOT_GENERATE_BUG_REPORT -> R.string.bug_report_failed
|
||||||
|
FILE_NOT_RECOGNIZED -> R.string.file_not_recognized
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showSendBugReportToDeveloperScreen(log: String) {
|
||||||
|
val to = R.string.bugReportTo
|
||||||
|
val subject = R.string.bugReportSubject
|
||||||
|
showSendEmailScreen(to, subject, log)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showSettingsScreen() {
|
||||||
|
val intent = intentFactory.startSettingsActivity(activity)
|
||||||
|
activity.startActivityForResult(intent, REQUEST_SETTINGS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showColorPicker(defaultColor: Int,
|
||||||
|
callback: OnColorPickedCallback) {
|
||||||
|
val picker = colorPickerFactory.create(defaultColor)
|
||||||
|
picker.setListener(callback)
|
||||||
|
activity.showDialog(picker, "picker")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showNumberPicker(value: Double,
|
||||||
|
unit: String,
|
||||||
|
callback: ListHabitsBehavior.NumberPickerCallback) {
|
||||||
|
numberPickerFactory.create(value, unit, callback).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
private fun getExecuteString(command: Command): Int? {
|
||||||
|
when (command) {
|
||||||
|
is ArchiveHabitsCommand -> return R.string.toast_habit_archived
|
||||||
|
is ChangeHabitColorCommand -> return R.string.toast_habit_changed
|
||||||
|
is CreateHabitCommand -> return R.string.toast_habit_created
|
||||||
|
is DeleteHabitsCommand -> return R.string.toast_habit_deleted
|
||||||
|
is EditHabitCommand -> return R.string.toast_habit_changed
|
||||||
|
is UnarchiveHabitsCommand -> return R.string.toast_habit_unarchived
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showCreateNumericalHabitScreen() {
|
||||||
|
val dialog = editHabitDialogFactory.createNumerical()
|
||||||
|
activity.showDialog(dialog, "editHabit")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onImportData(file: File, onFinished: () -> Unit) {
|
||||||
|
taskRunner.execute(importTaskFactory.create(file) { result ->
|
||||||
|
if (result == ImportDataTask.SUCCESS) {
|
||||||
|
adapter.refresh()
|
||||||
|
showMessage(R.string.habits_imported)
|
||||||
|
} else if (result == ImportDataTask.NOT_RECOGNIZED) {
|
||||||
|
showMessage(R.string.file_not_recognized)
|
||||||
|
} else {
|
||||||
|
showMessage(R.string.could_not_import)
|
||||||
|
}
|
||||||
|
onFinished()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onExportDB() {
|
||||||
|
taskRunner.execute(exportDBFactory.create { filename ->
|
||||||
|
if (filename != null) showSendFileScreen(filename)
|
||||||
|
else showMessage(R.string.could_not_export)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,145 +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.activities.habits.list;
|
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.view.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
|
||||||
import org.isoron.uhabits.core.commands.*;
|
|
||||||
import org.isoron.uhabits.core.ui.screens.habits.list.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
public class ListHabitsSelectionMenu extends BaseSelectionMenu
|
|
||||||
implements HabitCardListController.SelectionListener
|
|
||||||
{
|
|
||||||
@NonNull
|
|
||||||
private final ListHabitsScreen screen;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
CommandRunner commandRunner;
|
|
||||||
|
|
||||||
private ListHabitsSelectionMenuBehavior behavior;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final HabitCardListAdapter listAdapter;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private HabitCardListController listController;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ListHabitsSelectionMenu(@NonNull ListHabitsScreen screen,
|
|
||||||
@NonNull HabitCardListAdapter listAdapter,
|
|
||||||
@NonNull CommandRunner commandRunner,
|
|
||||||
@NonNull ListHabitsSelectionMenuBehavior behavior)
|
|
||||||
{
|
|
||||||
this.screen = screen;
|
|
||||||
this.listAdapter = listAdapter;
|
|
||||||
this.commandRunner = commandRunner;
|
|
||||||
this.behavior = behavior;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFinish()
|
|
||||||
{
|
|
||||||
if (listController != null) listController.onSelectionFinished();
|
|
||||||
super.onFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onItemClicked(@NonNull MenuItem item)
|
|
||||||
{
|
|
||||||
switch (item.getItemId())
|
|
||||||
{
|
|
||||||
case R.id.action_edit_habit:
|
|
||||||
behavior.onEditHabits();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.action_archive_habit:
|
|
||||||
behavior.onArchiveHabits();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.action_unarchive_habit:
|
|
||||||
behavior.onUnarchiveHabits();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.action_delete:
|
|
||||||
behavior.onDeleteHabits();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case R.id.action_color:
|
|
||||||
behavior.onChangeColor();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPrepare(@NonNull Menu menu)
|
|
||||||
{
|
|
||||||
MenuItem itemEdit = menu.findItem(R.id.action_edit_habit);
|
|
||||||
MenuItem itemColor = menu.findItem(R.id.action_color);
|
|
||||||
MenuItem itemArchive = menu.findItem(R.id.action_archive_habit);
|
|
||||||
MenuItem itemUnarchive = menu.findItem(R.id.action_unarchive_habit);
|
|
||||||
|
|
||||||
itemColor.setVisible(true);
|
|
||||||
itemEdit.setVisible(behavior.canEdit());
|
|
||||||
itemArchive.setVisible(behavior.canArchive());
|
|
||||||
itemUnarchive.setVisible(behavior.canUnarchive());
|
|
||||||
setTitle(Integer.toString(listAdapter.getSelected().size()));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSelectionChange()
|
|
||||||
{
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSelectionFinish()
|
|
||||||
{
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSelectionStart()
|
|
||||||
{
|
|
||||||
screen.startSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setListController(HabitCardListController listController)
|
|
||||||
{
|
|
||||||
this.listController = listController;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getResourceId()
|
|
||||||
{
|
|
||||||
return R.menu.list_habits_selection;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list
|
||||||
|
|
||||||
|
import android.view.*
|
||||||
|
import dagger.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.views.*
|
||||||
|
import org.isoron.uhabits.core.commands.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
|
@ActivityScope
|
||||||
|
class ListHabitsSelectionMenu @Inject constructor(
|
||||||
|
private val screen: ListHabitsScreen,
|
||||||
|
private val listAdapter: HabitCardListAdapter,
|
||||||
|
var commandRunner: CommandRunner,
|
||||||
|
private val behavior: ListHabitsSelectionMenuBehavior,
|
||||||
|
private val listController: Lazy<HabitCardListController>
|
||||||
|
) : BaseSelectionMenu() {
|
||||||
|
|
||||||
|
override fun onFinish() {
|
||||||
|
listController.get().onSelectionFinished()
|
||||||
|
super.onFinish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemClicked(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_edit_habit -> {
|
||||||
|
behavior.onEditHabits()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_archive_habit -> {
|
||||||
|
behavior.onArchiveHabits()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_unarchive_habit -> {
|
||||||
|
behavior.onUnarchiveHabits()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_delete -> {
|
||||||
|
behavior.onDeleteHabits()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_color -> {
|
||||||
|
behavior.onChangeColor()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepare(menu: Menu): Boolean {
|
||||||
|
val itemEdit = menu.findItem(R.id.action_edit_habit)
|
||||||
|
val itemColor = menu.findItem(R.id.action_color)
|
||||||
|
val itemArchive = menu.findItem(R.id.action_archive_habit)
|
||||||
|
val itemUnarchive = menu.findItem(R.id.action_unarchive_habit)
|
||||||
|
|
||||||
|
itemColor.isVisible = true
|
||||||
|
itemEdit.isVisible = behavior.canEdit()
|
||||||
|
itemArchive.isVisible = behavior.canArchive()
|
||||||
|
itemUnarchive.isVisible = behavior.canUnarchive()
|
||||||
|
setTitle(Integer.toString(listAdapter.selected.size))
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSelectionStart() = screen.startSelection()
|
||||||
|
fun onSelectionChange() = invalidate()
|
||||||
|
fun onSelectionFinish() = finish()
|
||||||
|
override fun getResourceId() = R.menu.list_habits_selection
|
||||||
|
}
|
@ -1,23 +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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides acitivity for listing habits and related classes.
|
|
||||||
*/
|
|
||||||
package org.isoron.uhabits.activities.habits.list;
|
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.view.*
|
||||||
|
import android.view.View.MeasureSpec.*
|
||||||
|
import android.widget.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.preferences.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
|
||||||
|
abstract class ButtonPanelView<T : View>(
|
||||||
|
context: Context,
|
||||||
|
val preferences: Preferences
|
||||||
|
) : LinearLayout(context),
|
||||||
|
Preferences.Listener {
|
||||||
|
|
||||||
|
var buttonCount = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
inflateButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataOffset = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
setupButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
var buttons = mutableListOf<T>()
|
||||||
|
|
||||||
|
override fun onCheckmarkSequenceChanged() {
|
||||||
|
inflateButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
protected fun inflateButtons() {
|
||||||
|
val reverse = preferences.isCheckmarkSequenceReversed
|
||||||
|
|
||||||
|
buttons.clear()
|
||||||
|
repeat(buttonCount) { buttons.add(createButton()) }
|
||||||
|
|
||||||
|
removeAllViews()
|
||||||
|
if (reverse) buttons.reversed().forEach { addView(it) }
|
||||||
|
else buttons.forEach { addView(it) }
|
||||||
|
setupButtons()
|
||||||
|
requestLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
preferences.addListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onDetachedFromWindow() {
|
||||||
|
preferences.removeListener(this)
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
|
||||||
|
val buttonWidth = dim(R.dimen.checkmarkWidth)
|
||||||
|
val buttonHeight = dim(R.dimen.checkmarkHeight)
|
||||||
|
val width = (buttonWidth * buttonCount)
|
||||||
|
super.onMeasure(width.toMeasureSpec(EXACTLY),
|
||||||
|
buttonHeight.toMeasureSpec(EXACTLY))
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun setupButtons()
|
||||||
|
protected abstract fun createButton(): T
|
||||||
|
}
|
@ -1,194 +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.activities.habits.list.views;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.content.res.*;
|
|
||||||
import android.graphics.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.text.*;
|
|
||||||
import android.util.*;
|
|
||||||
import android.view.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.utils.*;
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.activities.*;
|
|
||||||
import org.isoron.uhabits.core.preferences.*;
|
|
||||||
import org.isoron.uhabits.utils.*;
|
|
||||||
|
|
||||||
import static android.view.View.MeasureSpec.EXACTLY;
|
|
||||||
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
|
||||||
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
|
|
||||||
import static org.isoron.androidbase.utils.InterfaceUtils.getFontAwesome;
|
|
||||||
import static org.isoron.uhabits.core.models.Checkmark.CHECKED_EXPLICITLY;
|
|
||||||
import static org.isoron.uhabits.core.models.Checkmark.UNCHECKED;
|
|
||||||
import static org.isoron.uhabits.utils.AttributeSetUtils.getIntAttribute;
|
|
||||||
|
|
||||||
public class CheckmarkButtonView extends View
|
|
||||||
{
|
|
||||||
private int color;
|
|
||||||
|
|
||||||
private int value;
|
|
||||||
|
|
||||||
private StyledResources styledRes;
|
|
||||||
|
|
||||||
private TextPaint paint;
|
|
||||||
|
|
||||||
private int lowContrastColor;
|
|
||||||
|
|
||||||
private RectF rect;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Preferences prefs;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private OnToggleListener onToggleListener;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private OnInvalidToggleListener onInvalidToggleListener;
|
|
||||||
|
|
||||||
public CheckmarkButtonView(@Nullable Context context)
|
|
||||||
{
|
|
||||||
super(context);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CheckmarkButtonView(@Nullable Context ctx, @Nullable AttributeSet attrs)
|
|
||||||
{
|
|
||||||
super(ctx, attrs);
|
|
||||||
init();
|
|
||||||
|
|
||||||
if(ctx == null) throw new IllegalStateException();
|
|
||||||
if(attrs == null) throw new IllegalStateException();
|
|
||||||
|
|
||||||
int paletteColor = getIntAttribute(ctx, attrs, "color", 0);
|
|
||||||
setColor(PaletteUtils.getAndroidTestColor(paletteColor));
|
|
||||||
int value = getIntAttribute(ctx, attrs, "value", 0);
|
|
||||||
setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColor(int color)
|
|
||||||
{
|
|
||||||
this.color = color;
|
|
||||||
postInvalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(int value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
postInvalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void performToggle()
|
|
||||||
{
|
|
||||||
onToggleListener.onToggle();
|
|
||||||
value = (value == CHECKED_EXPLICITLY ? UNCHECKED : CHECKED_EXPLICITLY);
|
|
||||||
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
|
||||||
postInvalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas)
|
|
||||||
{
|
|
||||||
super.onDraw(canvas);
|
|
||||||
Resources resources = getResources();
|
|
||||||
|
|
||||||
paint.setColor(value == CHECKED_EXPLICITLY ? color : lowContrastColor);
|
|
||||||
int id = (value == UNCHECKED ? R.string.fa_times : R.string.fa_check);
|
|
||||||
String label = resources.getString(id);
|
|
||||||
float em = paint.measureText("m");
|
|
||||||
|
|
||||||
rect.set(0, 0, getWidth(), getHeight());
|
|
||||||
rect.offset(0, 0.4f * em);
|
|
||||||
canvas.drawText(label, rect.centerX(), rect.centerY(), paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
|
||||||
{
|
|
||||||
Resources res = getResources();
|
|
||||||
int height = res.getDimensionPixelSize(R.dimen.checkmarkHeight);
|
|
||||||
int width = res.getDimensionPixelSize(R.dimen.checkmarkWidth);
|
|
||||||
|
|
||||||
widthMeasureSpec = makeMeasureSpec(width, EXACTLY);
|
|
||||||
heightMeasureSpec = makeMeasureSpec(height, EXACTLY);
|
|
||||||
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setFocusable(false);
|
|
||||||
|
|
||||||
styledRes = new StyledResources(getContext());
|
|
||||||
|
|
||||||
paint = new TextPaint();
|
|
||||||
paint.setTypeface(getFontAwesome(getContext()));
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
paint.setTextAlign(Paint.Align.CENTER);
|
|
||||||
paint.setTextSize(getDimension(getContext(), R.dimen.smallTextSize));
|
|
||||||
|
|
||||||
rect = new RectF();
|
|
||||||
color = Color.BLACK;
|
|
||||||
lowContrastColor = styledRes.getColor(R.attr.lowContrastTextColor);
|
|
||||||
|
|
||||||
onToggleListener = () -> {};
|
|
||||||
onInvalidToggleListener = () -> {};
|
|
||||||
|
|
||||||
if (getContext() instanceof HabitsActivity)
|
|
||||||
{
|
|
||||||
HabitsApplicationComponent component =
|
|
||||||
((HabitsActivity) getContext()).getAppComponent();
|
|
||||||
prefs = component.getPreferences();
|
|
||||||
}
|
|
||||||
|
|
||||||
setOnClickListener((v) -> {
|
|
||||||
if (prefs == null) return;
|
|
||||||
if (prefs.isShortToggleEnabled()) performToggle();
|
|
||||||
else onInvalidToggleListener.onInvalidToggle();
|
|
||||||
});
|
|
||||||
|
|
||||||
setOnLongClickListener(v -> {
|
|
||||||
performToggle();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnInvalidToggleListener(
|
|
||||||
@NonNull OnInvalidToggleListener onInvalidToggleListener)
|
|
||||||
{
|
|
||||||
this.onInvalidToggleListener = onInvalidToggleListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnToggleListener(@NonNull OnToggleListener onToggleListener)
|
|
||||||
{
|
|
||||||
this.onToggleListener = onToggleListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnInvalidToggleListener
|
|
||||||
{
|
|
||||||
void onInvalidToggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnToggleListener
|
|
||||||
{
|
|
||||||
void onToggle();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.graphics.*
|
||||||
|
import android.text.*
|
||||||
|
import android.view.*
|
||||||
|
import android.view.View.MeasureSpec.*
|
||||||
|
import com.google.auto.factory.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.core.models.Checkmark.*
|
||||||
|
import org.isoron.uhabits.core.preferences.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
|
||||||
|
@AutoFactory
|
||||||
|
class CheckmarkButtonView(
|
||||||
|
@Provided @ActivityContext context: Context,
|
||||||
|
@Provided val preferences: Preferences
|
||||||
|
) : View(context),
|
||||||
|
View.OnClickListener,
|
||||||
|
View.OnLongClickListener {
|
||||||
|
|
||||||
|
var color: Int = Color.BLACK
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
var value: Int = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
var onToggle: () -> Unit = {}
|
||||||
|
private var drawer = Drawer()
|
||||||
|
|
||||||
|
init {
|
||||||
|
isFocusable = false
|
||||||
|
setOnClickListener(this)
|
||||||
|
setOnLongClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun performToggle() {
|
||||||
|
onToggle()
|
||||||
|
value = when (value) {
|
||||||
|
CHECKED_EXPLICITLY -> UNCHECKED
|
||||||
|
else -> CHECKED_EXPLICITLY
|
||||||
|
}
|
||||||
|
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
if (preferences.isShortToggleEnabled) performToggle()
|
||||||
|
else showMessage(R.string.long_press_to_toggle)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLongClick(v: View): Boolean {
|
||||||
|
performToggle()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
drawer.draw(canvas)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
val height = resources.getDimensionPixelSize(R.dimen.checkmarkHeight)
|
||||||
|
val width = resources.getDimensionPixelSize(R.dimen.checkmarkWidth)
|
||||||
|
super.onMeasure(width.toMeasureSpec(EXACTLY),
|
||||||
|
height.toMeasureSpec(EXACTLY))
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class Drawer {
|
||||||
|
private val rect = RectF()
|
||||||
|
private val lowContrastColor = sres.getColor(R.attr.lowContrastTextColor)
|
||||||
|
|
||||||
|
private val paint = TextPaint().apply {
|
||||||
|
typeface = getFontAwesome()
|
||||||
|
isAntiAlias = true
|
||||||
|
textAlign = Paint.Align.CENTER
|
||||||
|
textSize = dim(R.dimen.smallTextSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun draw(canvas: Canvas) {
|
||||||
|
paint.color = when (value) {
|
||||||
|
CHECKED_EXPLICITLY -> color
|
||||||
|
else -> lowContrastColor
|
||||||
|
}
|
||||||
|
val id = when (value) {
|
||||||
|
UNCHECKED -> R.string.fa_times
|
||||||
|
else -> R.string.fa_check
|
||||||
|
}
|
||||||
|
val label = resources.getString(id)
|
||||||
|
val em = paint.measureText("m")
|
||||||
|
|
||||||
|
rect.set(0f, 0f, width.toFloat(), height.toFloat())
|
||||||
|
rect.offset(0f, 0.4f * em)
|
||||||
|
canvas.drawText(label, rect.centerX(), rect.centerY(), paint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,243 +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.activities.habits.list.views;
|
|
||||||
|
|
||||||
import android.content.*;
|
|
||||||
import android.support.annotation.*;
|
|
||||||
import android.util.*;
|
|
||||||
import android.widget.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.*;
|
|
||||||
import org.isoron.uhabits.core.preferences.*;
|
|
||||||
import org.isoron.uhabits.core.utils.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static android.view.View.MeasureSpec.EXACTLY;
|
|
||||||
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
|
||||||
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
|
|
||||||
import static org.isoron.uhabits.utils.AttributeSetUtils.getIntAttribute;
|
|
||||||
import static org.isoron.uhabits.utils.PaletteUtils.getAndroidTestColor;
|
|
||||||
|
|
||||||
public class CheckmarkPanelView extends LinearLayout
|
|
||||||
implements Preferences.Listener
|
|
||||||
{
|
|
||||||
private static final int LEFT_TO_RIGHT = 0;
|
|
||||||
|
|
||||||
private static final int RIGHT_TO_LEFT = 1;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Preferences prefs;
|
|
||||||
|
|
||||||
private int values[];
|
|
||||||
|
|
||||||
private int nButtons;
|
|
||||||
|
|
||||||
private int color;
|
|
||||||
|
|
||||||
private int dataOffset;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private OnInvalidToggleListener onInvalidToggleListener;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private OnToggleListener onToggleLister;
|
|
||||||
|
|
||||||
public CheckmarkPanelView(Context context)
|
|
||||||
{
|
|
||||||
super(context);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CheckmarkPanelView(Context ctx, AttributeSet attrs)
|
|
||||||
{
|
|
||||||
super(ctx, attrs);
|
|
||||||
init();
|
|
||||||
|
|
||||||
if (ctx != null && attrs != null)
|
|
||||||
{
|
|
||||||
int paletteColor = getIntAttribute(ctx, attrs, "color", 0);
|
|
||||||
setColor(getAndroidTestColor(paletteColor));
|
|
||||||
setButtonCount(getIntAttribute(ctx, attrs, "button_count", 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInEditMode()) initEditMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CheckmarkButtonView indexToButton(int i)
|
|
||||||
{
|
|
||||||
int position = i;
|
|
||||||
|
|
||||||
if (getCheckmarkOrder() == RIGHT_TO_LEFT) position = nButtons - i - 1;
|
|
||||||
|
|
||||||
return (CheckmarkButtonView) getChildAt(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCheckmarkOrderChanged()
|
|
||||||
{
|
|
||||||
setupButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setButtonCount(int newButtonCount)
|
|
||||||
{
|
|
||||||
if (nButtons != newButtonCount)
|
|
||||||
{
|
|
||||||
nButtons = newButtonCount;
|
|
||||||
addButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
setupButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColor(int color)
|
|
||||||
{
|
|
||||||
this.color = color;
|
|
||||||
setupButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDataOffset(int dataOffset)
|
|
||||||
{
|
|
||||||
this.dataOffset = dataOffset;
|
|
||||||
setupButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnInvalidToggleListener(
|
|
||||||
@NonNull OnInvalidToggleListener onInvalidToggleListener)
|
|
||||||
{
|
|
||||||
this.onInvalidToggleListener = onInvalidToggleListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnToggleLister(@NonNull OnToggleListener onToggleLister)
|
|
||||||
{
|
|
||||||
this.onToggleLister = onToggleLister;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValues(int[] values)
|
|
||||||
{
|
|
||||||
this.values = values;
|
|
||||||
setupButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onAttachedToWindow()
|
|
||||||
{
|
|
||||||
super.onAttachedToWindow();
|
|
||||||
if (prefs != null) prefs.addListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDetachedFromWindow()
|
|
||||||
{
|
|
||||||
if (prefs != null) prefs.removeListener(this);
|
|
||||||
super.onDetachedFromWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthSpec, int heightSpec)
|
|
||||||
{
|
|
||||||
float buttonWidth = getDimension(getContext(), R.dimen.checkmarkWidth);
|
|
||||||
float buttonHeight =
|
|
||||||
getDimension(getContext(), R.dimen.checkmarkHeight);
|
|
||||||
|
|
||||||
float width = buttonWidth * nButtons;
|
|
||||||
|
|
||||||
widthSpec = makeMeasureSpec((int) width, EXACTLY);
|
|
||||||
heightSpec = makeMeasureSpec((int) buttonHeight, EXACTLY);
|
|
||||||
|
|
||||||
super.onMeasure(widthSpec, heightSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addButtons()
|
|
||||||
{
|
|
||||||
removeAllViews();
|
|
||||||
|
|
||||||
for (int i = 0; i < nButtons; i++)
|
|
||||||
addView(new CheckmarkButtonView(getContext()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getCheckmarkOrder()
|
|
||||||
{
|
|
||||||
if (prefs == null) return LEFT_TO_RIGHT;
|
|
||||||
return prefs.shouldReverseCheckmarks() ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
Context appContext = getContext().getApplicationContext();
|
|
||||||
if (appContext instanceof HabitsApplication)
|
|
||||||
{
|
|
||||||
HabitsApplication app = (HabitsApplication) appContext;
|
|
||||||
prefs = app.getComponent().getPreferences();
|
|
||||||
}
|
|
||||||
|
|
||||||
onInvalidToggleListener = () -> {};
|
|
||||||
onToggleLister = (t) -> {};
|
|
||||||
|
|
||||||
setWillNotDraw(false);
|
|
||||||
values = new int[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initEditMode()
|
|
||||||
{
|
|
||||||
int values[] = new int[nButtons];
|
|
||||||
|
|
||||||
for (int i = 0; i < nButtons; i++)
|
|
||||||
values[i] = Math.min(2, new Random().nextInt(4));
|
|
||||||
|
|
||||||
setValues(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupButtonControllers(long timestamp,
|
|
||||||
CheckmarkButtonView buttonView)
|
|
||||||
{
|
|
||||||
buttonView.setOnInvalidToggleListener(
|
|
||||||
() -> onInvalidToggleListener.onInvalidToggle());
|
|
||||||
buttonView.setOnToggleListener(
|
|
||||||
() -> onToggleLister.onToggle(timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupButtons()
|
|
||||||
{
|
|
||||||
long timestamp = DateUtils.getStartOfToday();
|
|
||||||
long day = DateUtils.millisecondsInOneDay;
|
|
||||||
timestamp -= day * dataOffset;
|
|
||||||
|
|
||||||
for (int i = 0; i < nButtons; i++)
|
|
||||||
{
|
|
||||||
CheckmarkButtonView buttonView = indexToButton(i);
|
|
||||||
if (i + dataOffset >= values.length) break;
|
|
||||||
buttonView.setValue(values[i + dataOffset]);
|
|
||||||
buttonView.setColor(color);
|
|
||||||
setupButtonControllers(timestamp, buttonView);
|
|
||||||
timestamp -= day;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnInvalidToggleListener
|
|
||||||
{
|
|
||||||
void onInvalidToggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnToggleListener
|
|
||||||
{
|
|
||||||
void onToggle(long timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import com.google.auto.factory.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.core.models.Checkmark.*
|
||||||
|
import org.isoron.uhabits.core.preferences.*
|
||||||
|
import org.isoron.uhabits.core.utils.*
|
||||||
|
|
||||||
|
@AutoFactory
|
||||||
|
class CheckmarkPanelView(
|
||||||
|
@Provided @ActivityContext context: Context,
|
||||||
|
@Provided preferences: Preferences,
|
||||||
|
@Provided private val buttonFactory: CheckmarkButtonViewFactory
|
||||||
|
) : ButtonPanelView<CheckmarkButtonView>(context, preferences) {
|
||||||
|
|
||||||
|
var values = IntArray(0)
|
||||||
|
set(values) {
|
||||||
|
field = values
|
||||||
|
setupButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
var color = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
setupButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
var onToggle: (Long) -> Unit = {}
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
setupButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createButton(): CheckmarkButtonView = buttonFactory.create()
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun setupButtons() {
|
||||||
|
val today = DateUtils.getStartOfToday()
|
||||||
|
val day = DateUtils.millisecondsInOneDay
|
||||||
|
|
||||||
|
buttons.forEachIndexed { index, button ->
|
||||||
|
val timestamp = today - (index + dataOffset) * day
|
||||||
|
button.value = when {
|
||||||
|
index + dataOffset < values.size -> values[index + dataOffset]
|
||||||
|
else -> UNCHECKED
|
||||||
|
}
|
||||||
|
button.color = color
|
||||||
|
button.onToggle = { onToggle(timestamp) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.view.*
|
||||||
|
import android.view.Gravity.*
|
||||||
|
import android.view.ViewGroup.LayoutParams.*
|
||||||
|
import android.widget.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.*
|
||||||
|
import org.isoron.uhabits.utils.*
|
||||||
|
|
||||||
|
class EmptyListView(context: Context) : LinearLayout(context) {
|
||||||
|
init {
|
||||||
|
orientation = VERTICAL
|
||||||
|
gravity = Gravity.CENTER
|
||||||
|
visibility = BaseRootView.GONE
|
||||||
|
|
||||||
|
addView(TextView(context).apply {
|
||||||
|
text = str(R.string.fa_star_half_o)
|
||||||
|
typeface = getFontAwesome()
|
||||||
|
textSize = sp(40.0f)
|
||||||
|
gravity = CENTER
|
||||||
|
setTextColor(sres.getColor(R.attr.mediumContrastTextColor))
|
||||||
|
}, MATCH_PARENT, WRAP_CONTENT)
|
||||||
|
|
||||||
|
addView(TextView(context).apply {
|
||||||
|
text = str(R.string.no_habits_found)
|
||||||
|
gravity = CENTER
|
||||||
|
setPadding(0, dp(20.0f).toInt(), 0, 0)
|
||||||
|
setTextColor(sres.getColor(R.attr.mediumContrastTextColor))
|
||||||
|
}, MATCH_PARENT, WRAP_CONTENT)
|
||||||
|
}
|
||||||
|
}
|
@ -1,334 +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.activities.habits.list.views;
|
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.isoron.androidbase.activities.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
|
||||||
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller responsible for receiving and processing the events generated by a
|
|
||||||
* HabitListView. These include selecting and reordering items, toggling
|
|
||||||
* checkmarks and clicking habits.
|
|
||||||
*/
|
|
||||||
@ActivityScope
|
|
||||||
public class HabitCardListController implements HabitCardListView.Controller,
|
|
||||||
ModelObservable.Listener
|
|
||||||
{
|
|
||||||
private final Mode NORMAL_MODE = new NormalMode();
|
|
||||||
|
|
||||||
private final Mode SELECTION_MODE = new SelectionMode();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final HabitCardListAdapter adapter;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private HabitListener habitListener;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private SelectionListener selectionListener;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Mode activeMode;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public HabitCardListController(@NonNull HabitCardListAdapter adapter)
|
|
||||||
{
|
|
||||||
this.adapter = adapter;
|
|
||||||
this.activeMode = new NormalMode();
|
|
||||||
adapter.getObservable().addListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user drags a habit and drops it somewhere. Note that the
|
|
||||||
* dragging operation is already complete.
|
|
||||||
*
|
|
||||||
* @param from the original position of the habit
|
|
||||||
* @param to the position where the habit was released
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void drop(int from, int to)
|
|
||||||
{
|
|
||||||
if (from == to) return;
|
|
||||||
cancelSelection();
|
|
||||||
|
|
||||||
Habit habitFrom = adapter.getItem(from);
|
|
||||||
Habit habitTo = adapter.getItem(to);
|
|
||||||
adapter.performReorder(from, to);
|
|
||||||
|
|
||||||
if (habitListener != null)
|
|
||||||
habitListener.onHabitReorder(habitFrom, habitTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEdit(@NonNull Habit habit, long timestamp)
|
|
||||||
{
|
|
||||||
if (habitListener != null) habitListener.onEdit(habit, timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInvalidEdit()
|
|
||||||
{
|
|
||||||
if (habitListener != null) habitListener.onInvalidEdit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user attempts to perform a toggle, but attempt is
|
|
||||||
* rejected.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onInvalidToggle()
|
|
||||||
{
|
|
||||||
if (habitListener != null) habitListener.onInvalidToggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user clicks at some item.
|
|
||||||
*
|
|
||||||
* @param position the position of the clicked item
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onItemClick(int position)
|
|
||||||
{
|
|
||||||
activeMode.onItemClick(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user long clicks at some item.
|
|
||||||
*
|
|
||||||
* @param position the position of the clicked item
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onItemLongClick(int position)
|
|
||||||
{
|
|
||||||
activeMode.onItemLongClick(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onModelChange()
|
|
||||||
{
|
|
||||||
if(adapter.isSelectionEmpty())
|
|
||||||
{
|
|
||||||
activeMode = new NormalMode();
|
|
||||||
if (selectionListener != null) selectionListener.onSelectionFinish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the selection operation is cancelled externally, by something
|
|
||||||
* other than this controller. This happens, for example, when the user
|
|
||||||
* presses the back button.
|
|
||||||
*/
|
|
||||||
public void onSelectionFinished()
|
|
||||||
{
|
|
||||||
cancelSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user wants to toggle a checkmark.
|
|
||||||
*
|
|
||||||
* @param habit the habit of the checkmark
|
|
||||||
* @param timestamp the timestamps of the checkmark
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onToggle(@NonNull Habit habit, long timestamp)
|
|
||||||
{
|
|
||||||
if (habitListener != null) habitListener.onToggle(habit, timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHabitListener(@Nullable HabitListener habitListener)
|
|
||||||
{
|
|
||||||
this.habitListener = habitListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSelectionListener(@Nullable SelectionListener listener)
|
|
||||||
{
|
|
||||||
this.selectionListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user starts dragging an item.
|
|
||||||
*
|
|
||||||
* @param position the position of the habit dragged
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void startDrag(int position)
|
|
||||||
{
|
|
||||||
activeMode.startDrag(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selects or deselects the item at a given position
|
|
||||||
*
|
|
||||||
* @param position the position of the item to be selected/deselected
|
|
||||||
*/
|
|
||||||
protected void toggleSelection(int position)
|
|
||||||
{
|
|
||||||
adapter.toggleSelection(position);
|
|
||||||
activeMode = adapter.isSelectionEmpty() ? NORMAL_MODE : SELECTION_MODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks all items as not selected and finishes the selection operation.
|
|
||||||
*/
|
|
||||||
private void cancelSelection()
|
|
||||||
{
|
|
||||||
adapter.clearSelection();
|
|
||||||
activeMode = new NormalMode();
|
|
||||||
if (selectionListener != null) selectionListener.onSelectionFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface HabitListener
|
|
||||||
{
|
|
||||||
void onEdit(Habit habit, long timestamp);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user clicks a habit.
|
|
||||||
*
|
|
||||||
* @param habit the habit clicked
|
|
||||||
*/
|
|
||||||
void onHabitClick(@NonNull Habit habit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user wants to change the position of a habit on the
|
|
||||||
* list.
|
|
||||||
*
|
|
||||||
* @param from habit to be moved
|
|
||||||
* @param to habit that currently occupies the desired position
|
|
||||||
*/
|
|
||||||
void onHabitReorder(@NonNull Habit from, @NonNull Habit to);
|
|
||||||
|
|
||||||
void onInvalidEdit();
|
|
||||||
|
|
||||||
void onInvalidToggle();
|
|
||||||
|
|
||||||
void onToggle(Habit habit, long timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Mode describes the behaviour of the list upon clicking, long clicking
|
|
||||||
* and dragging an item. This depends on whether some items are already
|
|
||||||
* selected or not.
|
|
||||||
*/
|
|
||||||
private interface Mode
|
|
||||||
{
|
|
||||||
void onItemClick(int position);
|
|
||||||
|
|
||||||
boolean onItemLongClick(int position);
|
|
||||||
|
|
||||||
void startDrag(int position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface SelectionListener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Called when the user changes the list of selected item. This is only
|
|
||||||
* called if there were previously selected items. If the selection was
|
|
||||||
* previously empty, then onHabitSelectionStart is called instead.
|
|
||||||
*/
|
|
||||||
void onSelectionChange();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user deselects all items or cancels the selection.
|
|
||||||
*/
|
|
||||||
void onSelectionFinish();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after the user selects the first item.
|
|
||||||
*/
|
|
||||||
void onSelectionStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mode activated when there are no items selected. Clicks trigger habit
|
|
||||||
* click. Long clicks start selection.
|
|
||||||
*/
|
|
||||||
class NormalMode implements Mode
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onItemClick(int position)
|
|
||||||
{
|
|
||||||
Habit habit = adapter.getItem(position);
|
|
||||||
if (habitListener != null) habitListener.onHabitClick(habit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onItemLongClick(int position)
|
|
||||||
{
|
|
||||||
startSelection(position);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startDrag(int position)
|
|
||||||
{
|
|
||||||
startSelection(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void startSelection(int position)
|
|
||||||
{
|
|
||||||
toggleSelection(position);
|
|
||||||
activeMode = SELECTION_MODE;
|
|
||||||
if (selectionListener != null) selectionListener.onSelectionStart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mode activated when some items are already selected.
|
|
||||||
* <p>
|
|
||||||
* Clicks toggle item selection. Long clicks select more items.
|
|
||||||
*/
|
|
||||||
class SelectionMode implements Mode
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onItemClick(int position)
|
|
||||||
{
|
|
||||||
toggleSelection(position);
|
|
||||||
notifyListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onItemLongClick(int position)
|
|
||||||
{
|
|
||||||
toggleSelection(position);
|
|
||||||
notifyListener();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startDrag(int position)
|
|
||||||
{
|
|
||||||
toggleSelection(position);
|
|
||||||
notifyListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void notifyListener()
|
|
||||||
{
|
|
||||||
if (selectionListener == null) return;
|
|
||||||
|
|
||||||
if (activeMode == SELECTION_MODE)
|
|
||||||
selectionListener.onSelectionChange();
|
|
||||||
else selectionListener.onSelectionFinish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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.activities.habits.list.views
|
||||||
|
|
||||||
|
import dagger.*
|
||||||
|
import org.isoron.androidbase.activities.*
|
||||||
|
import org.isoron.uhabits.activities.habits.list.*
|
||||||
|
import org.isoron.uhabits.core.models.*
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.*
|
||||||
|
import javax.inject.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller responsible for receiving and processing the events generated by a
|
||||||
|
* HabitListView. These include selecting and reordering items, toggling
|
||||||
|
* checkmarks and clicking habits.
|
||||||
|
*/
|
||||||
|
@ActivityScope
|
||||||
|
class HabitCardListController @Inject constructor(
|
||||||
|
private val adapter: HabitCardListAdapter,
|
||||||
|
private val behavior: ListHabitsBehavior,
|
||||||
|
private val selectionMenu: Lazy<ListHabitsSelectionMenu>
|
||||||
|
) : HabitCardListView.Controller, ModelObservable.Listener {
|
||||||
|
|
||||||
|
private val NORMAL_MODE = NormalMode()
|
||||||
|
private val SELECTION_MODE = SelectionMode()
|
||||||
|
private var activeMode: Mode
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.activeMode = NORMAL_MODE
|
||||||
|
adapter.observable.addListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drop(from: Int, to: Int) {
|
||||||
|
if (from == to) return
|
||||||
|
cancelSelection()
|
||||||
|
|
||||||
|
val habitFrom = adapter.getItem(from)
|
||||||
|
val habitTo = adapter.getItem(to)
|
||||||
|
if(habitFrom == null || habitTo == null) return
|
||||||
|
|
||||||
|
adapter.performReorder(from, to)
|
||||||
|
behavior.onReorderHabit(habitFrom, habitTo)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemClick(position: Int) {
|
||||||
|
activeMode.onItemClick(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemLongClick(position: Int) {
|
||||||
|
activeMode.onItemLongClick(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onModelChange() {
|
||||||
|
if (adapter.isSelectionEmpty) {
|
||||||
|
activeMode = NormalMode()
|
||||||
|
selectionMenu.get().onSelectionFinish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSelectionFinished() {
|
||||||
|
cancelSelection()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startDrag(position: Int) {
|
||||||
|
activeMode.startDrag(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun toggleSelection(position: Int) {
|
||||||
|
adapter.toggleSelection(position)
|
||||||
|
activeMode = if (adapter.isSelectionEmpty) NORMAL_MODE else SELECTION_MODE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cancelSelection() {
|
||||||
|
adapter.clearSelection()
|
||||||
|
activeMode = NormalMode()
|
||||||
|
selectionMenu.get().onSelectionFinish()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HabitListener {
|
||||||
|
fun onHabitClick(habit: Habit)
|
||||||
|
fun onHabitReorder(from: Habit, to: Habit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Mode describes the behavior of the list upon clicking, long clicking
|
||||||
|
* and dragging an item. This depends on whether some items are already
|
||||||
|
* selected or not.
|
||||||
|
*/
|
||||||
|
private interface Mode {
|
||||||
|
fun onItemClick(position: Int)
|
||||||
|
fun onItemLongClick(position: Int): Boolean
|
||||||
|
fun startDrag(position: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode activated when there are no items selected. Clicks trigger habit
|
||||||
|
* click. Long clicks start selection.
|
||||||
|
*/
|
||||||
|
internal inner class NormalMode : Mode {
|
||||||
|
override fun onItemClick(position: Int) {
|
||||||
|
val habit = adapter.getItem(position)
|
||||||
|
if (habit == null) return
|
||||||
|
behavior.onClickHabit(habit)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemLongClick(position: Int): Boolean {
|
||||||
|
startSelection(position)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startDrag(position: Int) {
|
||||||
|
startSelection(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun startSelection(position: Int) {
|
||||||
|
toggleSelection(position)
|
||||||
|
activeMode = SELECTION_MODE
|
||||||
|
selectionMenu.get().onSelectionStart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode activated when some items are already selected. Clicks toggle
|
||||||
|
* item selection. Long clicks select more items.
|
||||||
|
*/
|
||||||
|
internal inner class SelectionMode : Mode {
|
||||||
|
override fun onItemClick(position: Int) {
|
||||||
|
toggleSelection(position)
|
||||||
|
notifyListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemLongClick(position: Int): Boolean {
|
||||||
|
toggleSelection(position)
|
||||||
|
notifyListener()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startDrag(position: Int) {
|
||||||
|
toggleSelection(position)
|
||||||
|
notifyListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun notifyListener() {
|
||||||
|
if (activeMode === SELECTION_MODE)
|
||||||
|
selectionMenu.get().onSelectionChange()
|
||||||
|
else
|
||||||
|
selectionMenu.get().onSelectionFinish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|