diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index 3fcec24ef..52e34c2eb 100644 --- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java +++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java @@ -45,7 +45,7 @@ public class GBDaoGenerator { public static void main(String[] args) throws Exception { - final Schema schema = new Schema(70, MAIN_PACKAGE + ".entities"); + final Schema schema = new Schema(71, MAIN_PACKAGE + ".entities"); Entity userAttributes = addUserAttributes(schema); Entity user = addUserInfo(schema, userAttributes); @@ -835,6 +835,7 @@ public class GBDaoGenerator { alarm.addIndex(indexUnique); alarm.addBooleanProperty("enabled").notNull(); alarm.addBooleanProperty("smartWakeup").notNull(); + alarm.addIntProperty("smartWakeupInterval"); alarm.addBooleanProperty("snooze").notNull(); alarm.addIntProperty("repetition").notNull().codeBeforeGetter( "public boolean isRepetitive() { return getRepetition() != ALARM_ONCE; } " + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java index ebc389a09..0dd5938c4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java @@ -1,5 +1,5 @@ /* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Daniel - Dakhno, Daniele Gobbetti, Dmitry Markin, Lem Dulfo, Taavi Eomäe + Dakhno, Daniele Gobbetti, Dmitry Markin, Lem Dulfo, Taavi Eomäe, Martin.JM This file is part of Gadgetbridge. @@ -26,6 +26,8 @@ import android.widget.CheckedTextView; import android.widget.EditText; import android.widget.TimePicker; +import java.text.NumberFormat; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; @@ -50,6 +52,7 @@ public class AlarmDetails extends AbstractGBActivity { private CheckedTextView cbSunday; private EditText title; private EditText description; + private EditText smartWakeupInterval; private GBDevice device; @Override @@ -65,6 +68,7 @@ public class AlarmDetails extends AbstractGBActivity { timePicker = findViewById(R.id.alarm_time_picker); cbSmartWakeup = findViewById(R.id.alarm_cb_smart_wakeup); + smartWakeupInterval = findViewById(R.id.alarm_cb_smart_wakeup_interval); cbSnooze = findViewById(R.id.alarm_cb_snooze); cbMonday = findViewById(R.id.alarm_cb_monday); cbTuesday = findViewById(R.id.alarm_cb_tuesday); @@ -78,6 +82,7 @@ public class AlarmDetails extends AbstractGBActivity { cbSmartWakeup.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { ((CheckedTextView) v).toggle(); + smartWakeupInterval.setEnabled(((CheckedTextView) v).isChecked()); } }); cbSnooze.setOnClickListener(new View.OnClickListener() { @@ -127,9 +132,26 @@ public class AlarmDetails extends AbstractGBActivity { boolean smartAlarmForced = forcedSmartWakeup(alarm.getPosition()); cbSmartWakeup.setChecked(alarm.getSmartWakeup() || smartAlarmForced); - int smartAlarmVisibility = supportsSmartWakeup(alarm.getPosition()) ? View.VISIBLE : View.GONE; + boolean smartAlarmVisible = supportsSmartWakeup(alarm.getPosition()); + int smartAlarmVisibility = smartAlarmVisible ? View.VISIBLE : View.GONE; cbSmartWakeup.setVisibility(smartAlarmVisibility); - cbSmartWakeup.setEnabled(!smartAlarmForced); + if (smartAlarmForced) { + cbSmartWakeup.setEnabled(false); + // Force the text to be visible for the "interval" part + // Enabled or not can still be seen in the checkmark + // TODO: I'd like feedback on this + if (GBApplication.isDarkThemeEnabled()) + cbSmartWakeup.setTextColor(getResources().getColor(R.color.primarytext_dark)); + else + cbSmartWakeup.setTextColor(getResources().getColor(R.color.primarytext_light)); + } + if (smartAlarmVisible) + cbSmartWakeup.setText(R.string.alarm_smart_wakeup_interval); + + smartWakeupInterval.setVisibility(supportsSmartWakeupInterval(alarm.getPosition()) ? smartAlarmVisibility : View.GONE); + smartWakeupInterval.setEnabled(alarm.getSmartWakeup() || smartAlarmForced); + if (alarm.getSmartWakeupInterval() != null) + smartWakeupInterval.setText(NumberFormat.getInstance().format(alarm.getSmartWakeupInterval())); cbSnooze.setChecked(alarm.getSnooze()); int snoozeVisibility = supportsSnoozing() ? View.VISIBLE : View.GONE; @@ -163,6 +185,14 @@ public class AlarmDetails extends AbstractGBActivity { return false; } + private boolean supportsSmartWakeupInterval(int position) { + if (device != null) { + DeviceCoordinator coordinator = device.getDeviceCoordinator(); + return coordinator.supportsSmartWakeupInterval(device, position); + } + return false; + } + /** * The alarm at this position *must* be a smart alarm */ @@ -224,6 +254,8 @@ public class AlarmDetails extends AbstractGBActivity { alarm.setEnabled(true); } alarm.setSmartWakeup(supportsSmartWakeup(alarm.getPosition()) && cbSmartWakeup.isChecked()); + String interval = smartWakeupInterval.getText().toString(); + alarm.setSmartWakeupInterval(interval.equals("") ? null : Integer.parseInt(interval)); alarm.setSnooze(supportsSnoozing() && cbSnooze.isChecked()); int repetitionMask = AlarmUtils.createRepetitionMask(cbMonday.isChecked(), cbTuesday.isChecked(), cbWednesday.isChecked(), cbThursday.isChecked(), cbFriday.isChecked(), cbSaturday.isChecked(), cbSunday.isChecked()); alarm.setRepetition(repetitionMask); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java index 68e0042df..b0954b7a1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java @@ -147,7 +147,7 @@ public class ConfigureAlarms extends AbstractGBActivity { } private Alarm createDefaultAlarm(@NonNull Device device, @NonNull User user, int position) { - return new Alarm(device.getId(), user.getId(), position, false, false, false, 0, 6, 30, false, null, null); + return new Alarm(device.getId(), user.getId(), position, false, false, null, false, 0, 6, 30, false, null, null); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_71.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_71.java new file mode 100644 index 000000000..384242b8b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/schema/GadgetbridgeUpdate_71.java @@ -0,0 +1,38 @@ +/* Copyright (C) 2024 Martin.JM + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.database.schema; + +import android.database.sqlite.SQLiteDatabase; + +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; +import nodomain.freeyourgadget.gadgetbridge.entities.AlarmDao; + +public class GadgetbridgeUpdate_71 implements DBUpdateScript { + @Override + public void upgradeSchema(final SQLiteDatabase db) { + if (!DBHelper.existsColumn(AlarmDao.TABLENAME, AlarmDao.Properties.SmartWakeupInterval.columnName, db)) { + final String statement = "ALTER TABLE " + AlarmDao.TABLENAME + " ADD COLUMN \"" + + AlarmDao.Properties.SmartWakeupInterval.columnName + "\" INTEGER"; + db.execSQL(statement); + } + } + + @Override + public void downgradeSchema(final SQLiteDatabase db) { + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java index 8dce27d1b..a732d2229 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java @@ -323,6 +323,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator { return false; } + @Override + public boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition) { + return false; + } + @Override public boolean forcedSmartWakeup(GBDevice device, int alarmPosition) { return false; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java index b0bf68f60..552badc7d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java @@ -337,6 +337,12 @@ public interface DeviceCoordinator { */ boolean supportsSmartWakeup(GBDevice device, int alarmPosition); + /** + * Returns true if the smart alarm at the specified position supports setting an interval for this device/coordinator + * @param alarmPosition Position of the alarm + */ + boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition); + /** * Returns true if the alarm at the specified position *must* be a smart alarm for this device/coordinator * @param alarmPosition Position of the alarm diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java index 1ea56d7fc..b5dbc099d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java @@ -116,6 +116,11 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i return huaweiCoordinator.supportsSmartAlarm(device, position); } + @Override + public boolean supportsSmartWakeupInterval(GBDevice device, int alarmPosition) { + return supportsSmartWakeup(device, alarmPosition); + } + @Override public boolean forcedSmartWakeup(GBDevice device, int alarmPosition) { return huaweiCoordinator.forcedSmartWakeup(device, alarmPosition); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java index 5af2a2a3e..59c3a599d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/Alarm.java @@ -44,6 +44,8 @@ public interface Alarm extends Serializable { boolean getSmartWakeup(); + Integer getSmartWakeupInterval(); + boolean getSnooze(); int getRepetition(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index 8579a011e..3016a589f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -733,7 +733,7 @@ public class HuaweiSupportProvider { title = context.getString(R.string.alarm_smart_wakeup); description = context.getString(R.string.huawei_alarm_smart_description); } - return new Alarm(device.getId(), user.getId(), position, false, smartWakeup, false, 0, 6, 30, true, title, description); + return new Alarm(device.getId(), user.getId(), position, false, smartWakeup, null, false, 0, 6, 30, true, title, description); } private void getAlarms() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetEventAlarmList.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetEventAlarmList.java index 33aa9d004..5deefa4d1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetEventAlarmList.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetEventAlarmList.java @@ -66,6 +66,7 @@ public class GetEventAlarmList extends Request { eventAlarm.index + positionOffset, eventAlarm.status, false, + null, false, eventAlarm.repeat, eventAlarm.startHour, @@ -86,6 +87,7 @@ public class GetEventAlarmList extends Request { i + positionOffset, false, false, + null, false, 0, 0, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetSmartAlarmList.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetSmartAlarmList.java index f30f23fd2..ba742a9d8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetSmartAlarmList.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetSmartAlarmList.java @@ -61,6 +61,7 @@ public class GetSmartAlarmList extends Request { 0, smartAlarm.status, true, + null, false, smartAlarm.repeat, smartAlarm.startHour, @@ -79,6 +80,7 @@ public class GetSmartAlarmList extends Request { 0, false, true, + null, false, 0, 0, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java index ad267c629..14dc93911 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/AlarmUtils.java @@ -51,7 +51,8 @@ public class AlarmUtils { * @return */ public static nodomain.freeyourgadget.gadgetbridge.model.Alarm createSingleShot(int index, boolean smartWakeup, boolean snooze, Calendar calendar) { - return new Alarm(-1, -1, index, true, smartWakeup, snooze, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false, GBApplication.getContext().getString(R.string.quick_alarm), GBApplication.getContext().getString(R.string.quick_alarm_description)); + // TODO: add interval setting? + return new Alarm(-1, -1, index, true, smartWakeup, null, snooze, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false, GBApplication.getContext().getString(R.string.quick_alarm), GBApplication.getContext().getString(R.string.quick_alarm_description)); } /** @@ -130,7 +131,7 @@ public class AlarmUtils { int hour = Integer.parseInt(tokens[4]); int minute = Integer.parseInt(tokens[5]); - return new Alarm(device.getId(), user.getId(), index, enabled, smartWakeup, false, repetition, hour, minute, false, null, null); + return new Alarm(device.getId(), user.getId(), index, enabled, smartWakeup, null, false, repetition, hour, minute, false, null, null); } private static Comparator createComparator() { diff --git a/app/src/main/res/layout/activity_alarm_details.xml b/app/src/main/res/layout/activity_alarm_details.xml index 5cdd2dfc9..9ede1cd13 100644 --- a/app/src/main/res/layout/activity_alarm_details.xml +++ b/app/src/main/res/layout/activity_alarm_details.xml @@ -23,16 +23,6 @@ android:paddingRight="@dimen/activity_horizontal_margin" android:paddingBottom="@dimen/activity_vertical_margin"> - - + + + + Fri Sat Smart wakeup + Smart wakeup, interval (minutes): + Default: 5 Snooze There was an error setting the alarms, please try again. Alarms sent to device.