mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Merge branch 'dev'
This commit is contained in:
@@ -4,13 +4,13 @@ if [ -z "$GPG_PASSWORD" ]; then
|
||||
echo Env variable GPG_PASSWORD must be defined
|
||||
exit 1
|
||||
fi
|
||||
for file in gcp-key.json keystore.jks gradle.properties env; do
|
||||
gpg \
|
||||
gpg \
|
||||
--quiet \
|
||||
--batch \
|
||||
--yes \
|
||||
--decrypt \
|
||||
--passphrase="$GPG_PASSWORD" \
|
||||
--output $file \
|
||||
$file.gpg
|
||||
done
|
||||
--output secret.tar.gz \
|
||||
secret
|
||||
tar -xzf secret.tar.gz
|
||||
rm secret.tar.gz
|
||||
|
||||
BIN
.secret/env.gpg
BIN
.secret/env.gpg
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<EFBFBD>
|
||||
Binary file not shown.
BIN
.secret/secret
Normal file
BIN
.secret/secret
Normal file
Binary file not shown.
44
README.md
44
README.md
@@ -7,7 +7,7 @@ source.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://play.google.com/store/apps/details?id=org.isoron.uhabits&utm_source=global_co&utm_medium=prtnr&utm_content=Mar2515&utm_campaign=PartBadge&pcampaignid=MKT-AC-global-none-all-co-pr-py-PartBadges-Oct1515-1"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/apps/en-play-badge-border.png" height="75px"/></a>
|
||||
<a href="http://f-droid.org/app/org.isoron.uhabits"><img alt="Git if on F-Droid" src="http://i.imgur.com/baSPE7X.png" height="75px"/></a>
|
||||
<a href="http://f-droid.org/app/org.isoron.uhabits"><img alt="Get it on F-Droid" src="http://i.imgur.com/baSPE7X.png" height="75px"/></a>
|
||||
</p>
|
||||
|
||||
## Screenshots
|
||||
@@ -21,34 +21,32 @@ source.
|
||||
|
||||
## Features
|
||||
|
||||
* **Simple, beautiful and modern interface.** Loop has a minimalistic interface
|
||||
that is easy to use and follows the material design guidelines.
|
||||
* <b>Beautiful, minimalistic and lightweight interface.</b>
|
||||
Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones.
|
||||
|
||||
* **Habit score.** In addition to showing your current streak, Loop has an
|
||||
advanced algorithm for calculating the strength of your habits. Every
|
||||
repetition makes your habit stronger, and every missed day makes it weaker. A
|
||||
few missed days after a long streak, however, will not completely destroy
|
||||
your entire progress.
|
||||
* <b>Habit score.</b>
|
||||
Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps.
|
||||
|
||||
* **Detailed graphs and statistics.** Clearly see how your habits improved over
|
||||
time with beautiful and detailed graphs. Scroll back to see the complete
|
||||
history of your habits.
|
||||
* <b>Flexible schedules.</b>
|
||||
In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day.
|
||||
|
||||
* **Flexible schedules.** Supports both daily habits and habits with more
|
||||
complex schedules, such as 3 times every week; one time every other week; or
|
||||
every other day.
|
||||
* <b>Reminders.</b>
|
||||
Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification.
|
||||
|
||||
* **Reminders.** Create an individual reminder for each habit, at a chosen hour
|
||||
of the day. Easily check, dismiss or snooze your habit directly from the
|
||||
notification, without opening the app.
|
||||
* <b>Widgets.</b>
|
||||
Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app.
|
||||
|
||||
* **Optimized for smartwatches.** Reminders can be checked, snoozed or
|
||||
dismissed directly from your Android Wear watch.
|
||||
* <b>Take control of your data.</b>
|
||||
If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker.
|
||||
|
||||
* **Completely ad-free and open source.** There are absolutely no
|
||||
advertisements, annoying notifications or intrusive permissions in this app,
|
||||
and there will never be. The complete source code is available under the
|
||||
GPLv3.
|
||||
* <b>No limitations.</b>
|
||||
Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases.
|
||||
|
||||
* <b>Completely ad-free and open source.</b>
|
||||
There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3).
|
||||
|
||||
* <b>Works offline and respects your privacy.</b>
|
||||
Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it.
|
||||
|
||||
## Installing
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
VERSION_CODE = 45
|
||||
VERSION_NAME = 1.8.2
|
||||
VERSION_CODE = 46
|
||||
VERSION_NAME = 1.8.3
|
||||
|
||||
MIN_SDK_VERSION = 21
|
||||
TARGET_SDK_VERSION = 29
|
||||
|
||||
1
android/play
Symbolic link
1
android/play
Symbolic link
@@ -0,0 +1 @@
|
||||
uhabits-android/src/main/play/
|
||||
@@ -115,4 +115,10 @@ public class BaseUserInterfaceTest
|
||||
h4.setColor(2);
|
||||
habitList.update(h4);
|
||||
}
|
||||
|
||||
protected void rotateDevice() throws Exception
|
||||
{
|
||||
device.setOrientationLeft();
|
||||
device.setOrientationNatural();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package org.isoron.uhabits.acceptance.steps;
|
||||
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.support.test.espresso.*;
|
||||
import android.support.test.espresso.contrib.*;
|
||||
@@ -30,8 +29,7 @@ import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.R;
|
||||
import org.isoron.uhabits.activities.habits.list.*;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.os.Build.VERSION_CODES.LOLLIPOP;
|
||||
import static android.os.Build.VERSION.*;
|
||||
import static android.support.test.espresso.Espresso.*;
|
||||
import static android.support.test.espresso.action.ViewActions.*;
|
||||
import static android.support.test.espresso.assertion.PositionAssertions.*;
|
||||
|
||||
@@ -58,6 +58,28 @@ public class EditHabitSteps
|
||||
typeTextWithId(R.id.tvDescription, name);
|
||||
}
|
||||
|
||||
public static void setReminder()
|
||||
{
|
||||
onView(withId(R.id.tvReminderTime)).perform(click());
|
||||
onView(withId(R.id.done_button)).perform(click());
|
||||
}
|
||||
|
||||
public static void clickReminderDays()
|
||||
{
|
||||
onView(withId(R.id.tvReminderDays)).perform(click());
|
||||
}
|
||||
|
||||
public static void unselectAllDays()
|
||||
{
|
||||
onView(withText("Saturday")).perform(click());
|
||||
onView(withText("Sunday")).perform(click());
|
||||
onView(withText("Monday")).perform(click());
|
||||
onView(withText("Tuesday")).perform(click());
|
||||
onView(withText("Wednesday")).perform(click());
|
||||
onView(withText("Thursday")).perform(click());
|
||||
onView(withText("Friday")).perform(click());
|
||||
}
|
||||
|
||||
private static void typeTextWithId(int id, String name)
|
||||
{
|
||||
onView(withId(id)).perform(clearText(), typeText(name), closeSoftKeyboard());
|
||||
|
||||
@@ -83,11 +83,12 @@ class CheckmarkPanelViewTest : BaseViewTest() {
|
||||
// assertRenders(view, "$PATH/render_reversed.png")
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testRender_withOffset() {
|
||||
view.dataOffset = 3
|
||||
assertRenders(view, "$PATH/render_offset.png")
|
||||
}
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withOffset() {
|
||||
// view.dataOffset = 3
|
||||
// assertRenders(view, "$PATH/render_offset.png")
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testToggle() {
|
||||
|
||||
@@ -77,11 +77,12 @@ class NumberPanelViewTest : BaseViewTest() {
|
||||
assertRenders(view, "$PATH/render_reversed.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRender_withOffset() {
|
||||
view.dataOffset = 3
|
||||
assertRenders(view, "$PATH/render_offset.png")
|
||||
}
|
||||
// // Flaky test
|
||||
// @Test
|
||||
// fun testRender_withOffset() {
|
||||
// view.dataOffset = 3
|
||||
// assertRenders(view, "$PATH/render_offset.png")
|
||||
// }
|
||||
|
||||
@Test
|
||||
fun testEdit() {
|
||||
|
||||
@@ -1,51 +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.integration;
|
||||
|
||||
import android.support.test.filters.*;
|
||||
import android.support.test.runner.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.activities.about.*;
|
||||
import org.isoron.uhabits.activities.habits.list.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import static java.lang.Thread.*;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class SavedStateTest extends BaseUserInterfaceTest
|
||||
{
|
||||
/**
|
||||
* Make sure that the main activity can be recreated by using
|
||||
* BundleSavedState after being destroyed. See bug:
|
||||
* https://github.com/iSoron/uhabits/issues/287
|
||||
*/
|
||||
@Test
|
||||
public void testBundleSavedState() throws Exception
|
||||
{
|
||||
startActivity(ListHabitsActivity.class);
|
||||
device.waitForIdle();
|
||||
startActivity(AboutActivity.class);
|
||||
sleep(1000);
|
||||
device.pressBack();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.regression
|
||||
|
||||
import android.support.test.filters.*
|
||||
|
||||
import org.isoron.uhabits.*
|
||||
import org.junit.*
|
||||
|
||||
import org.isoron.uhabits.acceptance.steps.CommonSteps.*
|
||||
import org.isoron.uhabits.acceptance.steps.EditHabitSteps.*
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.*
|
||||
import org.isoron.uhabits.acceptance.steps.ListHabitsSteps.MenuItem.*
|
||||
import org.isoron.uhabits.acceptance.steps.WidgetSteps.clickText
|
||||
import org.isoron.uhabits.activities.about.*
|
||||
import org.isoron.uhabits.activities.habits.list.*
|
||||
import java.lang.Thread.*
|
||||
|
||||
@LargeTest
|
||||
class SavedStateTest : BaseUserInterfaceTest() {
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun shouldNotCrashWhenRotatingWeekdayPickerDialog() {
|
||||
// https://github.com/iSoron/uhabits/issues/534
|
||||
launchApp()
|
||||
clickMenu(ADD)
|
||||
setReminder()
|
||||
clickReminderDays()
|
||||
unselectAllDays()
|
||||
rotateDevice()
|
||||
clickText("Monday")
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the main activity can be recreated by using
|
||||
* BundleSavedState after being destroyed. See bug:
|
||||
* https://github.com/iSoron/uhabits/issues/287
|
||||
*/
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testBundleSavedState() {
|
||||
launchApp()
|
||||
startActivity(AboutActivity::class.java)
|
||||
sleep(1000)
|
||||
device.pressBack()
|
||||
}
|
||||
}
|
||||
@@ -19,17 +19,19 @@
|
||||
|
||||
package org.isoron.uhabits.activities.common.dialogs;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.*;
|
||||
import android.support.v7.app.AppCompatDialogFragment;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.models.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.isoron.uhabits.R;
|
||||
import org.isoron.uhabits.core.models.WeekdayList;
|
||||
import org.isoron.uhabits.core.utils.DateUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Dialog that allows the user to pick one or more days of the week.
|
||||
@@ -38,6 +40,7 @@ public class WeekdayPickerDialog extends AppCompatDialogFragment implements
|
||||
DialogInterface.OnMultiChoiceClickListener,
|
||||
DialogInterface.OnClickListener
|
||||
{
|
||||
private static final String KEY_SELECTED_DAYS = "selectedDays";
|
||||
private boolean[] selectedDays;
|
||||
|
||||
private OnWeekdaysPickedListener listener;
|
||||
@@ -48,6 +51,21 @@ public class WeekdayPickerDialog extends AppCompatDialogFragment implements
|
||||
selectedDays[which] = isChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if(savedInstanceState != null){
|
||||
selectedDays = savedInstanceState.getBooleanArray(KEY_SELECTED_DAYS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBooleanArray(KEY_SELECTED_DAYS, selectedDays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package org.isoron.uhabits.activities.habits.edit;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
@@ -27,7 +27,7 @@ import android.support.v7.app.*;
|
||||
import android.text.format.*;
|
||||
import android.view.*;
|
||||
|
||||
import com.android.datetimepicker.time.*;
|
||||
import com.android.datetimepicker.time.TimePickerDialog;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.R;
|
||||
@@ -40,7 +40,7 @@ import org.isoron.uhabits.core.preferences.*;
|
||||
|
||||
import butterknife.*;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.*;
|
||||
|
||||
public class EditHabitDialog extends AppCompatDialogFragment
|
||||
{
|
||||
@@ -48,6 +48,8 @@ public class EditHabitDialog extends AppCompatDialogFragment
|
||||
|
||||
public static final String BUNDLE_HABIT_TYPE = "habitType";
|
||||
|
||||
private static final String WEEKDAY_PICKER_TAG = "weekdayPicker";
|
||||
|
||||
protected Habit originalHabit;
|
||||
|
||||
protected Preferences prefs;
|
||||
@@ -109,6 +111,8 @@ public class EditHabitDialog extends AppCompatDialogFragment
|
||||
setupReminderController();
|
||||
setupNameController();
|
||||
|
||||
restoreChildFragmentListeners();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -268,8 +272,16 @@ public class EditHabitDialog extends AppCompatDialogFragment
|
||||
WeekdayPickerDialog dialog = new WeekdayPickerDialog();
|
||||
dialog.setListener(reminderPanel);
|
||||
dialog.setSelectedDays(currentDays);
|
||||
dialog.show(getFragmentManager(), "weekdayPicker");
|
||||
dialog.show(getChildFragmentManager(), WEEKDAY_PICKER_TAG);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void restoreChildFragmentListeners()
|
||||
{
|
||||
final WeekdayPickerDialog dialog =
|
||||
(WeekdayPickerDialog) getChildFragmentManager()
|
||||
.findFragmentByTag(WEEKDAY_PICKER_TAG);
|
||||
if(dialog != null) dialog.setListener(reminderPanel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
Loop helps you create and maintain good habits, allowing you to achieve your long-term goals. Detailed charts and statistics show you how your habits improved over time. The app is completely ad-free, open source and it respects your privacy.
|
||||
Loop Habit Tracker helps you create and maintain long-term positive habits in your life. Detailed charts and statistics give you a clear picture of how your habits have improved over time. The app is completely ad-free, open source and it respects your privacy.
|
||||
|
||||
<b>Simple, beautiful and modern interface</b>
|
||||
Loop has a minimalistic interface that is very easy to use and follows the material design guidelines.
|
||||
<b>Beautiful, minimalistic and lightweight interface</b>
|
||||
Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones.
|
||||
|
||||
<b>Habit score</b>
|
||||
In addition to showing your current streak, Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger, and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your entire progress, unlike other don't-break-the-chain apps.
|
||||
|
||||
<b>Detailed graphs and statistics</b>
|
||||
Clearly see how your habits improved over time with detailed charts and statistics. Scroll back to see the complete history of your habits.
|
||||
Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps.
|
||||
|
||||
<b>Flexible schedules</b>
|
||||
Supports not only daily habits, but also habits with more complex schedules, such as 3 times every week; one time every other week; or every other day.
|
||||
In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day.
|
||||
|
||||
<b>Reminders</b>
|
||||
Create an individual reminder for each habit, at a chosen hour of the day. Easily check, dismiss or snooze your habit directly from the notification, without opening the app.
|
||||
Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification.
|
||||
|
||||
<b>Widgets</b>
|
||||
Track your habits directly from your home screen, with beautiful and colorful widgets.
|
||||
Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app.
|
||||
|
||||
<b>Take control of your data</b>
|
||||
If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker.
|
||||
|
||||
<b>No limitations</b>
|
||||
Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases.
|
||||
|
||||
<b>Completely ad-free and open source</b>
|
||||
There are absolutely no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The complete source code is available under an open-source license (GPLv3).
|
||||
There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3).
|
||||
|
||||
<b>Works offline and respects your privacy</b>
|
||||
Loop doesn't require an Internet connection or online account registration. Your confidential habit data never leaves your phone. Neither the developers nor any third-parties have access to it.
|
||||
Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it.
|
||||
|
||||
<b>Take your data with you</b>
|
||||
If you want to further analyze your data or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database format (SQLite).
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
1.8.2:
|
||||
* Fix issues with reminders
|
||||
* Fix crash (HUAWEI)
|
||||
1.8.3
|
||||
* Bugfixes
|
||||
1.8:
|
||||
* New bar chart showing number of repetitions performed each week, month or year
|
||||
* Performing habits on irregular weekdays will no longer break your streak
|
||||
|
||||
@@ -30,7 +30,6 @@ import static org.isoron.uhabits.core.utils.StringUtils.*;
|
||||
|
||||
public final class Timestamp
|
||||
{
|
||||
|
||||
public static final long DAY_LENGTH = 86400000;
|
||||
|
||||
public static final Timestamp ZERO = new Timestamp(0);
|
||||
@@ -39,10 +38,13 @@ public final class Timestamp
|
||||
|
||||
public Timestamp(long unixTime)
|
||||
{
|
||||
if (unixTime < 0 || unixTime % DAY_LENGTH != 0)
|
||||
if (unixTime < 0)
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid unix time: " + unixTime);
|
||||
|
||||
if (unixTime % DAY_LENGTH != 0)
|
||||
unixTime = (unixTime / DAY_LENGTH) * DAY_LENGTH;
|
||||
|
||||
this.unixTime = unixTime;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ package org.isoron.uhabits.core.models;
|
||||
import org.isoron.uhabits.core.*;
|
||||
import org.isoron.uhabits.core.utils.*;
|
||||
import org.junit.*;
|
||||
import org.mockito.internal.verification.*;
|
||||
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
@@ -64,5 +65,10 @@ public class TimestampTest extends BaseUnitTest
|
||||
assertThat(t.daysUntil(t.minus(300)), equalTo(-300));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInexact() throws Exception
|
||||
{
|
||||
Timestamp t = new Timestamp(1578054764000L);
|
||||
assertThat(t.getUnixTime(), equalTo(1578009600000L));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user