mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Mi Band 3: Add support for Reminders
This commit is contained in:
@@ -43,7 +43,7 @@ public class GBDaoGenerator {
|
|||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Schema schema = new Schema(36, MAIN_PACKAGE + ".entities");
|
final Schema schema = new Schema(37, MAIN_PACKAGE + ".entities");
|
||||||
|
|
||||||
Entity userAttributes = addUserAttributes(schema);
|
Entity userAttributes = addUserAttributes(schema);
|
||||||
Entity user = addUserInfo(schema, userAttributes);
|
Entity user = addUserInfo(schema, userAttributes);
|
||||||
@@ -86,6 +86,7 @@ public class GBDaoGenerator {
|
|||||||
addHybridHRActivitySample(schema, user, device);
|
addHybridHRActivitySample(schema, user, device);
|
||||||
addCalendarSyncState(schema, device);
|
addCalendarSyncState(schema, device);
|
||||||
addAlarms(schema, user, device);
|
addAlarms(schema, user, device);
|
||||||
|
addReminders(schema, user, device);
|
||||||
|
|
||||||
Entity notificationFilter = addNotificationFilters(schema);
|
Entity notificationFilter = addNotificationFilters(schema);
|
||||||
|
|
||||||
@@ -541,6 +542,25 @@ public class GBDaoGenerator {
|
|||||||
alarm.addToOne(device, deviceId);
|
alarm.addToOne(device, deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addReminders(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity reminder = addEntity(schema, "Reminder");
|
||||||
|
reminder.implementsInterface("nodomain.freeyourgadget.gadgetbridge.model.Reminder");
|
||||||
|
Property deviceId = reminder.addLongProperty("deviceId").notNull().getProperty();
|
||||||
|
Property userId = reminder.addLongProperty("userId").notNull().getProperty();
|
||||||
|
Property reminderId = reminder.addStringProperty("reminderId").notNull().primaryKey().getProperty();
|
||||||
|
Index indexUnique = new Index();
|
||||||
|
indexUnique.addProperty(deviceId);
|
||||||
|
indexUnique.addProperty(userId);
|
||||||
|
indexUnique.addProperty(reminderId);
|
||||||
|
indexUnique.makeUnique();
|
||||||
|
reminder.addIndex(indexUnique);
|
||||||
|
reminder.addStringProperty("message").notNull();
|
||||||
|
reminder.addDateProperty("date").notNull();
|
||||||
|
reminder.addIntProperty("repetition").notNull();
|
||||||
|
reminder.addToOne(user, userId);
|
||||||
|
reminder.addToOne(device, deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
private static void addNotificationFilterEntry(Schema schema, Entity notificationFilterEntity) {
|
private static void addNotificationFilterEntry(Schema schema, Entity notificationFilterEntity) {
|
||||||
Entity notificatonFilterEntry = addEntity(schema, "NotificationFilterEntry");
|
Entity notificatonFilterEntry = addEntity(schema, "NotificationFilterEntry");
|
||||||
notificatonFilterEntry.addIdProperty().autoincrement();
|
notificatonFilterEntry.addIdProperty().autoincrement();
|
||||||
|
|||||||
@@ -485,6 +485,10 @@
|
|||||||
android:name=".activities.ConfigureAlarms"
|
android:name=".activities.ConfigureAlarms"
|
||||||
android:label="@string/title_activity_set_alarm"
|
android:label="@string/title_activity_set_alarm"
|
||||||
android:parentActivityName=".activities.ControlCenterv2" />
|
android:parentActivityName=".activities.ControlCenterv2" />
|
||||||
|
<activity
|
||||||
|
android:name=".activities.ConfigureReminders"
|
||||||
|
android:label="@string/title_activity_set_reminders"
|
||||||
|
android:parentActivityName=".activities.ControlCenterv2" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.devicesettings.DeviceSettingsActivity"
|
android:name=".activities.devicesettings.DeviceSettingsActivity"
|
||||||
android:label="@string/title_activity_device_specific_settings"
|
android:label="@string/title_activity_device_specific_settings"
|
||||||
@@ -494,6 +498,12 @@
|
|||||||
android:label="@string/title_activity_alarm_details"
|
android:label="@string/title_activity_alarm_details"
|
||||||
android:parentActivityName=".activities.ConfigureAlarms"
|
android:parentActivityName=".activities.ConfigureAlarms"
|
||||||
android:screenOrientation="portrait" />
|
android:screenOrientation="portrait" />
|
||||||
|
<activity
|
||||||
|
android:name=".activities.ReminderDetails"
|
||||||
|
android:label="@string/title_activity_reminder_details"
|
||||||
|
android:parentActivityName=".activities.ConfigureReminders"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.VibrationActivity"
|
android:name=".activities.VibrationActivity"
|
||||||
android:label="@string/title_activity_vibration"
|
android:label="@string/title_activity_vibration"
|
||||||
|
|||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
/* Copyright (C) 2019 José Rebelo
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.adapter.GBReminderListAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Reminder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
|
|
||||||
|
public class ConfigureReminders extends AbstractGBActivity {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ConfigureReminders.class);
|
||||||
|
|
||||||
|
private static final int REQ_CONFIGURE_REMINDER = 1;
|
||||||
|
|
||||||
|
private GBReminderListAdapter mGBReminderListAdapter;
|
||||||
|
private GBDevice gbDevice;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_configure_reminders);
|
||||||
|
|
||||||
|
gbDevice = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||||
|
|
||||||
|
mGBReminderListAdapter = new GBReminderListAdapter(this);
|
||||||
|
|
||||||
|
final RecyclerView remindersRecyclerView = findViewById(R.id.reminder_list);
|
||||||
|
remindersRecyclerView.setHasFixedSize(true);
|
||||||
|
remindersRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
remindersRecyclerView.setAdapter(mGBReminderListAdapter);
|
||||||
|
updateRemindersFromDB();
|
||||||
|
|
||||||
|
final FloatingActionButton fab = findViewById(R.id.fab);
|
||||||
|
fab.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||||
|
|
||||||
|
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||||
|
int reservedSlots = prefs.getInt(DeviceSettingsPreferenceConst.PREF_RESERVER_REMINDERS_CALENDAR, 9);
|
||||||
|
|
||||||
|
int deviceSlots = coordinator.getReminderSlotCount() - reservedSlots;
|
||||||
|
|
||||||
|
if (mGBReminderListAdapter.getItemCount() >= deviceSlots) {
|
||||||
|
// No more free slots
|
||||||
|
new AlertDialog.Builder(v.getContext())
|
||||||
|
.setTitle(R.string.reminder_no_free_slots_title)
|
||||||
|
.setMessage(getBaseContext().getString(R.string.reminder_no_free_slots_description, String.format(Locale.getDefault(), "%d", deviceSlots)))
|
||||||
|
.setIcon(R.drawable.ic_warning)
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(final DialogInterface dialog, final int whichButton) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Reminder reminder;
|
||||||
|
try (DBHandler db = GBApplication.acquireDB()) {
|
||||||
|
final DaoSession daoSession = db.getDaoSession();
|
||||||
|
final Device device = DBHelper.getDevice(gbDevice, daoSession);
|
||||||
|
final User user = DBHelper.getUser(daoSession);
|
||||||
|
reminder = createDefaultReminder(device, user);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Error accessing database", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
configureReminder(reminder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (requestCode == REQ_CONFIGURE_REMINDER && resultCode == 1) {
|
||||||
|
updateRemindersFromDB();
|
||||||
|
sendRemindersToDevice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Reminder createDefaultReminder(@NonNull Device device, @NonNull User user) {
|
||||||
|
final Reminder reminder = new Reminder();
|
||||||
|
reminder.setRepetition(Reminder.ONCE);
|
||||||
|
reminder.setDate(Calendar.getInstance().getTime());
|
||||||
|
reminder.setMessage("");
|
||||||
|
reminder.setDeviceId(device.getId());
|
||||||
|
reminder.setUserId(user.getId());
|
||||||
|
reminder.setReminderId(UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
return reminder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the available reminders from the database and updates the view afterwards.
|
||||||
|
*/
|
||||||
|
private void updateRemindersFromDB() {
|
||||||
|
final List<Reminder> reminders = DBHelper.getReminders(gbDevice);
|
||||||
|
|
||||||
|
mGBReminderListAdapter.setReminderList(reminders);
|
||||||
|
mGBReminderListAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home:
|
||||||
|
// back button
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configureReminder(final Reminder reminder) {
|
||||||
|
final Intent startIntent = new Intent(getApplicationContext(), ReminderDetails.class);
|
||||||
|
startIntent.putExtra(GBDevice.EXTRA_DEVICE, gbDevice);
|
||||||
|
startIntent.putExtra(Reminder.EXTRA_REMINDER, reminder);
|
||||||
|
startActivityForResult(startIntent, REQ_CONFIGURE_REMINDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteReminder(final Reminder reminder) {
|
||||||
|
DBHelper.delete(reminder);
|
||||||
|
updateRemindersFromDB();
|
||||||
|
sendRemindersToDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendRemindersToDevice() {
|
||||||
|
if (gbDevice.isInitialized()) {
|
||||||
|
GBApplication.deviceService().onSetReminders(mGBReminderListAdapter.getReminderList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+222
@@ -0,0 +1,222 @@
|
|||||||
|
/* Copyright (C) 2019 José Rebelo
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.DatePickerDialog;
|
||||||
|
import android.app.TimePickerDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.InputFilter;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.DatePicker;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.TimePicker;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Reminder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
public class ReminderDetails extends AbstractGBActivity implements TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ReminderDetails.class);
|
||||||
|
|
||||||
|
private Reminder reminder;
|
||||||
|
private GBDevice device;
|
||||||
|
|
||||||
|
ArrayAdapter<String> repeatAdapter;
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||||
|
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||||
|
|
||||||
|
TextView reminderRepeat;
|
||||||
|
TextView reminderDate;
|
||||||
|
TextView reminderTime;
|
||||||
|
EditText reminderText;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_reminder_details);
|
||||||
|
|
||||||
|
reminder = (Reminder) getIntent().getSerializableExtra(Reminder.EXTRA_REMINDER);
|
||||||
|
|
||||||
|
if (reminder == null) {
|
||||||
|
GB.toast("No reminder provided to ReminderDetails Activity", Toast.LENGTH_LONG, GB.ERROR);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reminderRepeat = findViewById(R.id.reminder_repeat);
|
||||||
|
reminderDate = findViewById(R.id.reminder_date);
|
||||||
|
reminderTime = findViewById(R.id.reminder_time);
|
||||||
|
reminderText = findViewById(R.id.reminder_message);
|
||||||
|
|
||||||
|
device = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||||
|
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(device);
|
||||||
|
|
||||||
|
final String[] repeatStrings = getResources().getStringArray(R.array.reminder_repeat);
|
||||||
|
repeatAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, repeatStrings);
|
||||||
|
|
||||||
|
final View cardRepeat = findViewById(R.id.card_repeat);
|
||||||
|
cardRepeat.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
new AlertDialog.Builder(ReminderDetails.this).setAdapter(repeatAdapter, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
|
reminder.setRepetition(i);
|
||||||
|
updateUiFromReminder();
|
||||||
|
}
|
||||||
|
}).create().show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final View cardDate = findViewById(R.id.card_date);
|
||||||
|
cardDate.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
final Calendar date = new GregorianCalendar();
|
||||||
|
date.setTime(reminder.getDate());
|
||||||
|
new DatePickerDialog(
|
||||||
|
ReminderDetails.this,
|
||||||
|
ReminderDetails.this,
|
||||||
|
date.get(Calendar.YEAR),
|
||||||
|
date.get(Calendar.MONTH),
|
||||||
|
date.get(Calendar.DAY_OF_MONTH)
|
||||||
|
).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final View cardTime = findViewById(R.id.card_time);
|
||||||
|
cardTime.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
new TimePickerDialog(
|
||||||
|
ReminderDetails.this,
|
||||||
|
ReminderDetails.this,
|
||||||
|
reminder.getDate().getHours(),
|
||||||
|
reminder.getDate().getMinutes(),
|
||||||
|
DateFormat.is24HourFormat(GBApplication.getContext())
|
||||||
|
).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
reminderText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(coordinator.getMaximumReminderMessageLength())});
|
||||||
|
reminderText.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(final CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(final CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(final Editable s) {
|
||||||
|
reminder.setMessage(s.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final FloatingActionButton fab = findViewById(R.id.fab_save);
|
||||||
|
fab.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
updateReminder();
|
||||||
|
ReminderDetails.this.setResult(1);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateUiFromReminder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home:
|
||||||
|
// back button
|
||||||
|
// TODO confirm when exiting without saving
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateReminder() {
|
||||||
|
DBHelper.store(reminder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle state) {
|
||||||
|
super.onSaveInstanceState(state);
|
||||||
|
state.putSerializable("reminder", reminder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
reminder = (Reminder) savedInstanceState.getSerializable("reminder");
|
||||||
|
updateUiFromReminder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTimeSet(TimePicker timePicker, int hour, int minute) {
|
||||||
|
reminder.getDate().setHours(hour);
|
||||||
|
reminder.getDate().setMinutes(minute);
|
||||||
|
updateUiFromReminder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDateSet(DatePicker datePicker, int year, int month, int dayOfMonth) {
|
||||||
|
final Calendar date = new GregorianCalendar(year, month, dayOfMonth);
|
||||||
|
reminder.setDate(new Date(date.getTimeInMillis()));
|
||||||
|
updateUiFromReminder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateUiFromReminder() {
|
||||||
|
reminderRepeat.setText(repeatAdapter.getItem(reminder.getRepetition()));
|
||||||
|
reminderText.setText(reminder.getMessage());
|
||||||
|
|
||||||
|
if (reminder.getDate() != null) {
|
||||||
|
reminderDate.setText(dateFormat.format(reminder.getDate()));
|
||||||
|
reminderTime.setText(timeFormat.format(reminder.getDate()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -25,6 +25,7 @@ public class DeviceSettingsPreferenceConst {
|
|||||||
public static final String PREF_NOTIFICATION_ENABLE = "notification_enable";
|
public static final String PREF_NOTIFICATION_ENABLE = "notification_enable";
|
||||||
public static final String PREF_SCREEN_ORIENTATION = "screen_orientation";
|
public static final String PREF_SCREEN_ORIENTATION = "screen_orientation";
|
||||||
public static final String PREF_RESERVER_ALARMS_CALENDAR = "reserve_alarms_calendar";
|
public static final String PREF_RESERVER_ALARMS_CALENDAR = "reserve_alarms_calendar";
|
||||||
|
public static final String PREF_RESERVER_REMINDERS_CALENDAR = "reserve_reminders_calendar";
|
||||||
public static final String PREF_ALLOW_HIGH_MTU = "allow_high_mtu";
|
public static final String PREF_ALLOW_HIGH_MTU = "allow_high_mtu";
|
||||||
public static final String PREF_SYNC_CALENDAR = "sync_calendar";
|
public static final String PREF_SYNC_CALENDAR = "sync_calendar";
|
||||||
public static final String PREF_USE_CUSTOM_DEVICEICON = "use_custom_deviceicon";
|
public static final String PREF_USE_CUSTOM_DEVICEICON = "use_custom_deviceicon";
|
||||||
|
|||||||
+1
@@ -738,6 +738,7 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
|
|||||||
setInputTypeFor(MiBandConst.PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS, InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
|
setInputTypeFor(MiBandConst.PREF_MIBAND_DEVICE_TIME_OFFSET_HOURS, InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
|
||||||
setInputTypeFor(MakibesHR3Constants.PREF_FIND_PHONE_DURATION, InputType.TYPE_CLASS_NUMBER);
|
setInputTypeFor(MakibesHR3Constants.PREF_FIND_PHONE_DURATION, InputType.TYPE_CLASS_NUMBER);
|
||||||
setInputTypeFor(DeviceSettingsPreferenceConst.PREF_RESERVER_ALARMS_CALENDAR, InputType.TYPE_CLASS_NUMBER);
|
setInputTypeFor(DeviceSettingsPreferenceConst.PREF_RESERVER_ALARMS_CALENDAR, InputType.TYPE_CLASS_NUMBER);
|
||||||
|
setInputTypeFor(DeviceSettingsPreferenceConst.PREF_RESERVER_REMINDERS_CALENDAR, InputType.TYPE_CLASS_NUMBER);
|
||||||
|
|
||||||
String deviceActionsFellSleepSelection = prefs.getString(PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION, PREF_DEVICE_ACTION_SELECTION_OFF);
|
String deviceActionsFellSleepSelection = prefs.getString(PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION, PREF_DEVICE_ACTION_SELECTION_OFF);
|
||||||
final Preference deviceActionsFellSleep = findPreference(PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION);
|
final Preference deviceActionsFellSleep = findPreference(PREF_DEVICE_ACTION_FELL_SLEEP_SELECTION);
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ import nodomain.freeyourgadget.gadgetbridge.R;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.activities.ActivitySummariesActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.ActivitySummariesActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.BatteryInfoActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.BatteryInfoActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureReminders;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2;
|
import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateDialog;
|
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateDialog;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity;
|
||||||
@@ -320,6 +321,21 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//set reminders
|
||||||
|
holder.setRemindersView.setVisibility(coordinator.getReminderSlotCount() > 0 ? View.VISIBLE : View.GONE);
|
||||||
|
holder.setRemindersView.setOnClickListener(new View.OnClickListener()
|
||||||
|
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Intent startIntent;
|
||||||
|
startIntent = new Intent(context, ConfigureReminders.class);
|
||||||
|
startIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
||||||
|
context.startActivity(startIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
//show graphs
|
//show graphs
|
||||||
holder.showActivityGraphs.setVisibility(coordinator.supportsActivityTracking() ? View.VISIBLE : View.GONE);
|
holder.showActivityGraphs.setVisibility(coordinator.supportsActivityTracking() ? View.VISIBLE : View.GONE);
|
||||||
holder.showActivityGraphs.setOnClickListener(new View.OnClickListener()
|
holder.showActivityGraphs.setOnClickListener(new View.OnClickListener()
|
||||||
@@ -743,6 +759,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
ImageView takeScreenshotView;
|
ImageView takeScreenshotView;
|
||||||
ImageView manageAppsView;
|
ImageView manageAppsView;
|
||||||
ImageView setAlarmsView;
|
ImageView setAlarmsView;
|
||||||
|
ImageView setRemindersView;
|
||||||
ImageView showActivityGraphs;
|
ImageView showActivityGraphs;
|
||||||
ImageView showActivityTracks;
|
ImageView showActivityTracks;
|
||||||
ImageView calibrateDevice;
|
ImageView calibrateDevice;
|
||||||
@@ -797,6 +814,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
|||||||
takeScreenshotView = view.findViewById(R.id.device_action_take_screenshot);
|
takeScreenshotView = view.findViewById(R.id.device_action_take_screenshot);
|
||||||
manageAppsView = view.findViewById(R.id.device_action_manage_apps);
|
manageAppsView = view.findViewById(R.id.device_action_manage_apps);
|
||||||
setAlarmsView = view.findViewById(R.id.device_action_set_alarms);
|
setAlarmsView = view.findViewById(R.id.device_action_set_alarms);
|
||||||
|
setRemindersView = view.findViewById(R.id.device_action_set_reminders);
|
||||||
showActivityGraphs = view.findViewById(R.id.device_action_show_activity_graphs);
|
showActivityGraphs = view.findViewById(R.id.device_action_show_activity_graphs);
|
||||||
showActivityTracks = view.findViewById(R.id.device_action_show_activity_tracks);
|
showActivityTracks = view.findViewById(R.id.device_action_show_activity_tracks);
|
||||||
deviceInfoView = view.findViewById(R.id.device_info_image);
|
deviceInfoView = view.findViewById(R.id.device_info_image);
|
||||||
|
|||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
/* Copyright (C) 2019 José Rebelo
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||||
|
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.cardview.widget.CardView;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureReminders;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Reminder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter for displaying Reminder instances.
|
||||||
|
*/
|
||||||
|
public class GBReminderListAdapter extends RecyclerView.Adapter<GBReminderListAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private ArrayList<Reminder> reminderList;
|
||||||
|
|
||||||
|
public GBReminderListAdapter(Context context) {
|
||||||
|
this.mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReminderList(List<Reminder> reminders) {
|
||||||
|
this.reminderList = new ArrayList<>(reminders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Reminder> getReminderList() {
|
||||||
|
return reminderList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public GBReminderListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_reminder, parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
|
||||||
|
final Reminder reminder = reminderList.get(position);
|
||||||
|
|
||||||
|
holder.container.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
((ConfigureReminders) mContext).configureReminder(reminder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
holder.container.setOnLongClickListener(new View.OnLongClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onLongClick(View v) {
|
||||||
|
new AlertDialog.Builder(v.getContext())
|
||||||
|
.setTitle(R.string.reminder_delete_confirm_title)
|
||||||
|
.setMessage(R.string.reminder_delete_confirm_description)
|
||||||
|
.setIcon(R.drawable.ic_warning)
|
||||||
|
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(final DialogInterface dialog, final int whichButton) {
|
||||||
|
((ConfigureReminders) mContext).deleteReminder(reminder);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.no, null)
|
||||||
|
.show();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
holder.reminderMessage.setText(reminder.getMessage());
|
||||||
|
|
||||||
|
final Date time = reminder.getDate();
|
||||||
|
final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault());
|
||||||
|
|
||||||
|
int stringResId = 0;
|
||||||
|
|
||||||
|
switch (reminder.getRepetition()) {
|
||||||
|
case Reminder.ONCE:
|
||||||
|
stringResId = R.string.reminder_time_once;
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_DAY:
|
||||||
|
stringResId = R.string.reminder_time_every_day;
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_WEEK:
|
||||||
|
stringResId = R.string.reminder_time_every_week;
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_MONTH:
|
||||||
|
stringResId = R.string.reminder_time_every_month;
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_YEAR:
|
||||||
|
stringResId = R.string.reminder_time_every_year;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String reminderTimeText = mContext.getString(stringResId, format.format(time));
|
||||||
|
holder.reminderTime.setText(reminderTimeText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return reminderList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
final CardView container;
|
||||||
|
|
||||||
|
final TextView reminderTime;
|
||||||
|
final TextView reminderMessage;
|
||||||
|
|
||||||
|
ViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
|
||||||
|
container = view.findViewById(R.id.card_view);
|
||||||
|
|
||||||
|
reminderTime = view.findViewById(R.id.reminder_item_time);
|
||||||
|
reminderMessage = view.findViewById(R.id.reminder_item_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributes;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributes;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributesDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceAttributesDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DeviceDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Reminder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.ReminderDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Tag;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Tag;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.TagDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.TagDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||||
@@ -620,6 +622,60 @@ public class DBHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all user-configurable reminders for the given user and device. The list is sorted by
|
||||||
|
* {@link Reminder#getDate}. Calendar events that may also be modeled as reminders are not stored
|
||||||
|
* in the database and hence not returned by this method.
|
||||||
|
* @param gbDevice the device for which the alarms shall be loaded
|
||||||
|
* @return the list of reminders for the given device
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static List<Reminder> getReminders(@NonNull GBDevice gbDevice) {
|
||||||
|
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||||
|
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||||
|
|
||||||
|
int reservedSlots = prefs.getInt(DeviceSettingsPreferenceConst.PREF_RESERVER_REMINDERS_CALENDAR, 9);
|
||||||
|
|
||||||
|
final int reminderSlots = coordinator.getReminderSlotCount();
|
||||||
|
|
||||||
|
try (DBHandler db = GBApplication.acquireDB()) {
|
||||||
|
final DaoSession daoSession = db.getDaoSession();
|
||||||
|
final User user = getUser(daoSession);
|
||||||
|
final Device dbDevice = DBHelper.findDevice(gbDevice, daoSession);
|
||||||
|
if (dbDevice != null) {
|
||||||
|
final ReminderDao reminderDao = daoSession.getReminderDao();
|
||||||
|
final Long deviceId = dbDevice.getId();
|
||||||
|
final QueryBuilder<Reminder> qb = reminderDao.queryBuilder();
|
||||||
|
qb.where(
|
||||||
|
ReminderDao.Properties.UserId.eq(user.getId()),
|
||||||
|
ReminderDao.Properties.DeviceId.eq(deviceId)).orderAsc(ReminderDao.Properties.Date).limit(reminderSlots - reservedSlots);
|
||||||
|
return qb.build().list();
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Error reading reminders from db", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void store(final Reminder reminder) {
|
||||||
|
try (DBHandler db = GBApplication.acquireDB()) {
|
||||||
|
final DaoSession daoSession = db.getDaoSession();
|
||||||
|
daoSession.insertOrReplace(reminder);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Error acquiring database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void delete(final Reminder reminder) {
|
||||||
|
try (DBHandler db = GBApplication.acquireDB()) {
|
||||||
|
final DaoSession daoSession = db.getDaoSession();
|
||||||
|
daoSession.delete(reminder);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Error acquiring database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void clearSession() {
|
public static void clearSession() {
|
||||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||||
DaoSession session = dbHandler.getDaoSession();
|
DaoSession session = dbHandler.getDaoSession();
|
||||||
|
|||||||
+10
@@ -222,6 +222,16 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaximumReminderMessageLength() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReminderSlotCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsRgbLedColor() {
|
public boolean supportsRgbLedColor() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -321,6 +321,16 @@ public interface DeviceCoordinator {
|
|||||||
*/
|
*/
|
||||||
boolean supportsMusicInfo();
|
boolean supportsMusicInfo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates the maximum reminder message length.
|
||||||
|
*/
|
||||||
|
int getMaximumReminderMessageLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates the maximum number of reminder slots available in the device.
|
||||||
|
*/
|
||||||
|
int getReminderSlotCount();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the device has an led which supports custom colors
|
* Indicates whether the device has an led which supports custom colors
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,6 +47,8 @@ public interface EventHandler {
|
|||||||
|
|
||||||
void onSetAlarms(ArrayList<? extends Alarm> alarms);
|
void onSetAlarms(ArrayList<? extends Alarm> alarms);
|
||||||
|
|
||||||
|
void onSetReminders(ArrayList<? extends Reminder> reminders);
|
||||||
|
|
||||||
void onSetCallState(CallSpec callSpec);
|
void onSetCallState(CallSpec callSpec);
|
||||||
|
|
||||||
void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec);
|
void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec);
|
||||||
|
|||||||
+10
@@ -84,6 +84,15 @@ public class MiBand3Coordinator extends HuamiCoordinator {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaximumReminderMessageLength() {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getReminderSlotCount() {
|
||||||
|
return 22; // At least, Mi Fit still allows more
|
||||||
|
}
|
||||||
|
|
||||||
public static String getNightMode(String deviceAddress) {
|
public static String getNightMode(String deviceAddress) {
|
||||||
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress));
|
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress));
|
||||||
@@ -111,6 +120,7 @@ public class MiBand3Coordinator extends HuamiCoordinator {
|
|||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
R.xml.devicesettings_swipeunlock,
|
R.xml.devicesettings_swipeunlock,
|
||||||
R.xml.devicesettings_sync_calendar,
|
R.xml.devicesettings_sync_calendar,
|
||||||
|
R.xml.devicesettings_reserve_reminders_calendar,
|
||||||
R.xml.devicesettings_expose_hr_thirdparty,
|
R.xml.devicesettings_expose_hr_thirdparty,
|
||||||
R.xml.devicesettings_bt_connected_advertisement,
|
R.xml.devicesettings_bt_connected_advertisement,
|
||||||
R.xml.devicesettings_device_actions,
|
R.xml.devicesettings_device_actions,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.RtlUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.RtlUtils;
|
||||||
@@ -225,6 +226,13 @@ public class GBDeviceService implements DeviceService {
|
|||||||
invokeService(intent);
|
invokeService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||||
|
Intent intent = createIntent().setAction(ACTION_SET_REMINDERS)
|
||||||
|
.putExtra(EXTRA_REMINDERS, reminders);
|
||||||
|
invokeService(intent);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetMusicInfo(MusicSpec musicSpec) {
|
public void onSetMusicInfo(MusicSpec musicSpec) {
|
||||||
Intent intent = createIntent().setAction(ACTION_SETMUSICINFO)
|
Intent intent = createIntent().setAction(ACTION_SETMUSICINFO)
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ public interface DeviceService extends EventHandler {
|
|||||||
String ACTION_SET_CONSTANT_VIBRATION = PREFIX + ".action.set_constant_vibration";
|
String ACTION_SET_CONSTANT_VIBRATION = PREFIX + ".action.set_constant_vibration";
|
||||||
String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms";
|
String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms";
|
||||||
String ACTION_SAVE_ALARMS = PREFIX + ".action.save_alarms";
|
String ACTION_SAVE_ALARMS = PREFIX + ".action.save_alarms";
|
||||||
|
String ACTION_SET_REMINDERS = PREFIX + ".action.set_reminders";
|
||||||
String ACTION_ENABLE_REALTIME_STEPS = PREFIX + ".action.enable_realtime_steps";
|
String ACTION_ENABLE_REALTIME_STEPS = PREFIX + ".action.enable_realtime_steps";
|
||||||
String ACTION_REALTIME_SAMPLES = PREFIX + ".action.realtime_samples";
|
String ACTION_REALTIME_SAMPLES = PREFIX + ".action.realtime_samples";
|
||||||
String ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT = PREFIX + ".action.realtime_hr_measurement";
|
String ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT = PREFIX + ".action.realtime_hr_measurement";
|
||||||
@@ -107,6 +108,7 @@ public interface DeviceService extends EventHandler {
|
|||||||
String EXTRA_URI = "uri";
|
String EXTRA_URI = "uri";
|
||||||
String EXTRA_CONFIG = "config";
|
String EXTRA_CONFIG = "config";
|
||||||
String EXTRA_ALARMS = "alarms";
|
String EXTRA_ALARMS = "alarms";
|
||||||
|
String EXTRA_REMINDERS = "reminders";
|
||||||
String EXTRA_CONNECT_FIRST_TIME = "connect_first_time";
|
String EXTRA_CONNECT_FIRST_TIME = "connect_first_time";
|
||||||
String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps";
|
String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps";
|
||||||
String EXTRA_INTERVAL_SECONDS = "interval_seconds";
|
String EXTRA_INTERVAL_SECONDS = "interval_seconds";
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/* Copyright (C) 2019 José Rebelo
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface Reminder extends Serializable {
|
||||||
|
/**
|
||||||
|
* The {@link android.os.Bundle} name for transferring parceled reminders.
|
||||||
|
*/
|
||||||
|
String EXTRA_REMINDER = "reminder";
|
||||||
|
|
||||||
|
int ONCE = 0;
|
||||||
|
int EVERY_DAY = 1;
|
||||||
|
int EVERY_WEEK = 2;
|
||||||
|
int EVERY_MONTH = 3;
|
||||||
|
int EVERY_YEAR = 4;
|
||||||
|
|
||||||
|
String getReminderId();
|
||||||
|
String getMessage();
|
||||||
|
Date getDate();
|
||||||
|
int getRepetition();
|
||||||
|
}
|
||||||
+7
@@ -73,6 +73,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.receivers.AutoConnectIntervalReceiver;
|
import nodomain.freeyourgadget.gadgetbridge.service.receivers.AutoConnectIntervalReceiver;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBAutoFetchReceiver;
|
import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBAutoFetchReceiver;
|
||||||
@@ -117,6 +118,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SE
|
|||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_FM_FREQUENCY;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_FM_FREQUENCY;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_HEARTRATE_MEASUREMENT_INTERVAL;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_HEARTRATE_MEASUREMENT_INTERVAL;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_LED_COLOR;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_LED_COLOR;
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_REMINDERS;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_START;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_START;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_STARTAPP;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_STARTAPP;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_TEST_NEW_FUNCTION;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_TEST_NEW_FUNCTION;
|
||||||
@@ -170,6 +172,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOT
|
|||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TITLE;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TITLE;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TYPE;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TYPE;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_RECORDED_DATA_TYPES;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_RECORDED_DATA_TYPES;
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_REMINDERS;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_RESET_FLAGS;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_RESET_FLAGS;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_VIBRATION_INTENSITY;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_VIBRATION_INTENSITY;
|
||||||
@@ -578,6 +581,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
|||||||
ArrayList<? extends Alarm> alarms = (ArrayList<? extends Alarm>) intent.getSerializableExtra(EXTRA_ALARMS);
|
ArrayList<? extends Alarm> alarms = (ArrayList<? extends Alarm>) intent.getSerializableExtra(EXTRA_ALARMS);
|
||||||
mDeviceSupport.onSetAlarms(alarms);
|
mDeviceSupport.onSetAlarms(alarms);
|
||||||
break;
|
break;
|
||||||
|
case ACTION_SET_REMINDERS:
|
||||||
|
ArrayList<? extends Reminder> reminders = (ArrayList<? extends Reminder>) intent.getSerializableExtra(EXTRA_REMINDERS);
|
||||||
|
mDeviceSupport.onSetReminders(reminders);
|
||||||
|
break;
|
||||||
case ACTION_ENABLE_REALTIME_STEPS: {
|
case ACTION_ENABLE_REALTIME_STEPS: {
|
||||||
boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false);
|
boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false);
|
||||||
mDeviceSupport.onEnableRealtimeSteps(enable);
|
mDeviceSupport.onEnableRealtimeSteps(enable);
|
||||||
|
|||||||
+9
@@ -37,6 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,6 +310,14 @@ public class ServiceDeviceSupport implements DeviceSupport {
|
|||||||
delegate.onSetAlarms(alarms);
|
delegate.onSetAlarms(alarms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||||
|
if (checkBusy("set reminders")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delegate.onSetReminders(reminders);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnableRealtimeSteps(boolean enable) {
|
public void onEnableRealtimeSteps(boolean enable) {
|
||||||
if (checkBusy("enable realtime steps: " + enable)) {
|
if (checkBusy("enable realtime steps: " + enable)) {
|
||||||
|
|||||||
+6
@@ -36,6 +36,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.Logging;
|
import nodomain.freeyourgadget.gadgetbridge.Logging;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.CheckInitializedAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.CheckInitializedAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBleProfile;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBleProfile;
|
||||||
@@ -366,6 +367,11 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
|
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
|
||||||
|
|
||||||
|
|||||||
+119
-3
@@ -107,6 +107,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||||
@@ -150,6 +151,7 @@ import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.Dev
|
|||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DATEFORMAT;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DATEFORMAT;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_LANGUAGE;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_LANGUAGE;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_RESERVER_ALARMS_CALENDAR;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_RESERVER_ALARMS_CALENDAR;
|
||||||
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_RESERVER_REMINDERS_CALENDAR;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SOUNDS;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SOUNDS;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
|
||||||
@@ -778,6 +780,117 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||||
|
final TransactionBuilder builder;
|
||||||
|
try {
|
||||||
|
builder = performInitialized("onSetReminders");
|
||||||
|
} catch (final IOException e) {
|
||||||
|
LOG.error("Unable to send reminders to device", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendReminders(builder, reminders);
|
||||||
|
|
||||||
|
builder.queue(getQueue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendReminders(final TransactionBuilder builder) {
|
||||||
|
final List<? extends Reminder> reminders = DBHelper.getReminders(gbDevice);
|
||||||
|
sendReminders(builder, reminders);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendReminders(final TransactionBuilder builder, final List<? extends Reminder> reminders) {
|
||||||
|
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||||
|
|
||||||
|
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||||
|
int reservedSlots = prefs.getInt(PREF_RESERVER_REMINDERS_CALENDAR, 9);
|
||||||
|
LOG.info("On Set Reminders. Reminders: {}, Reserved slots: {}", reminders.size(), reservedSlots);
|
||||||
|
|
||||||
|
// Send the reminders, skipping the reserved slots for calendar events
|
||||||
|
for (int i = 0; i < reminders.size(); i++) {
|
||||||
|
LOG.debug("Sending reminder at position {}", i + reservedSlots);
|
||||||
|
|
||||||
|
sendReminderToDevice(builder, i + reservedSlots, reminders.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the remaining slots, skipping the sent reminders and reserved slots
|
||||||
|
for (int i = reminders.size() + reservedSlots; i < coordinator.getReminderSlotCount(); i++) {
|
||||||
|
LOG.debug("Deleting reminder at position {}", i);
|
||||||
|
|
||||||
|
sendReminderToDevice(builder, i, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendReminderToDevice(final TransactionBuilder builder, int position, final Reminder reminder) {
|
||||||
|
if (characteristicChunked == null) {
|
||||||
|
LOG.warn("characteristicChunked is null, not sending reminder");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||||
|
|
||||||
|
if (position + 1 > coordinator.getReminderSlotCount()) {
|
||||||
|
LOG.error("Reminder for position {} is over the limit of {} reminders", position, coordinator.getReminderSlotCount());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reminder == null) {
|
||||||
|
// Delete reminder
|
||||||
|
writeToChunked(builder, 3, new byte[]{(byte) (position & 0xFF), 0, 0, 0, 0, 0});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ByteBuffer buf = ByteBuffer.allocate(14 + reminder.getMessage().getBytes().length);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
buf.put((byte) 0x0B);
|
||||||
|
buf.put((byte) (position & 0xFF));
|
||||||
|
|
||||||
|
switch(reminder.getRepetition()) {
|
||||||
|
case Reminder.ONCE:
|
||||||
|
buf.put(new byte[]{0x09, 0x00});
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_DAY:
|
||||||
|
buf.put(new byte[]{(byte) 0xE9, 0x0F});
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_WEEK:
|
||||||
|
buf.put(new byte[]{0x09, 0x01});
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_MONTH:
|
||||||
|
buf.put(new byte[]{0x09, 0x10});
|
||||||
|
break;
|
||||||
|
case Reminder.EVERY_YEAR:
|
||||||
|
buf.put(new byte[]{0x09, 0x20});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG.warn("Unknown repetition for reminder in position {}, defaulting to once", position);
|
||||||
|
buf.put(new byte[]{0x09, 0x00});
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.put(new byte[]{0x00, 0x00}); // unknown
|
||||||
|
|
||||||
|
final Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTime(reminder.getDate());
|
||||||
|
|
||||||
|
buf.put(BLETypeConversions.shortCalendarToRawBytes(cal));
|
||||||
|
buf.put((byte) 0x00);
|
||||||
|
|
||||||
|
if (reminder.getMessage().getBytes().length > coordinator.getMaximumReminderMessageLength()) {
|
||||||
|
LOG.warn("The reminder message length {} is longer than {}, will be truncated",
|
||||||
|
reminder.getMessage().getBytes().length,
|
||||||
|
coordinator.getMaximumReminderMessageLength()
|
||||||
|
);
|
||||||
|
buf.put(Arrays.copyOf(reminder.getMessage().getBytes(), coordinator.getMaximumReminderMessageLength()));
|
||||||
|
} else {
|
||||||
|
buf.put(reminder.getMessage().getBytes());
|
||||||
|
}
|
||||||
|
buf.put((byte) 0x00);
|
||||||
|
|
||||||
|
writeToChunked(builder, 2, buf.array());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNotification(NotificationSpec notificationSpec) {
|
public void onNotification(NotificationSpec notificationSpec) {
|
||||||
if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) {
|
if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) {
|
||||||
@@ -1903,19 +2016,21 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||||
|
int availableSlots = prefs.getInt(PREF_RESERVER_REMINDERS_CALENDAR, 9);
|
||||||
|
|
||||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
CalendarEvents upcomingEvents = new CalendarEvents();
|
||||||
List<CalendarEvents.CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList(getContext());
|
List<CalendarEvents.CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList(getContext());
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
|
||||||
int iteration = 0;
|
int iteration = 0;
|
||||||
int iterationMax = 8;
|
|
||||||
|
|
||||||
for (CalendarEvents.CalendarEvent calendarEvent : calendarEvents) {
|
for (CalendarEvents.CalendarEvent calendarEvent : calendarEvents) {
|
||||||
if (calendarEvent.isAllDay()) {
|
if (calendarEvent.isAllDay()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iteration > iterationMax) { // limit ?
|
if (iteration >= availableSlots) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1948,7 +2063,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Continue by deleting the events
|
// Continue by deleting the events
|
||||||
for(;iteration < iterationMax; iteration++){
|
for(;iteration < availableSlots; iteration++){
|
||||||
int length = 1 + 1 + 4 + 6 + 6 + 1 + 0 + 1;
|
int length = 1 + 1 + 4 + 6 + 6 + 1 + 0 + 1;
|
||||||
ByteBuffer buf = ByteBuffer.allocate(length);
|
ByteBuffer buf = ByteBuffer.allocate(length);
|
||||||
|
|
||||||
@@ -3014,6 +3129,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
setDisconnectNotification(builder);
|
setDisconnectNotification(builder);
|
||||||
setExposeHRThridParty(builder);
|
setExposeHRThridParty(builder);
|
||||||
setHeartrateMeasurementInterval(builder, getHeartRateMeasurementInterval());
|
setHeartrateMeasurementInterval(builder, getHeartRateMeasurementInterval());
|
||||||
|
sendReminders(builder);
|
||||||
requestAlarms(builder);
|
requestAlarms(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
@@ -17,6 +17,7 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.service.serial;
|
package nodomain.freeyourgadget.gadgetbridge.service.serial;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||||
@@ -28,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
||||||
|
|
||||||
@@ -262,4 +264,10 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
|
|||||||
byte[] bytes = gbDeviceProtocol.encodeLedColor(color);
|
byte[] bytes = gbDeviceProtocol.encodeLedColor(color);
|
||||||
sendToDevice(bytes);
|
sendToDevice(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||||
|
byte[] bytes = gbDeviceProtocol.encodeReminders(reminders);
|
||||||
|
sendToDevice(bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -17,6 +17,7 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.service.serial;
|
package nodomain.freeyourgadget.gadgetbridge.service.serial;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||||
@@ -24,6 +25,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
|
|
||||||
public abstract class GBDeviceProtocol {
|
public abstract class GBDeviceProtocol {
|
||||||
@@ -141,6 +143,10 @@ public abstract class GBDeviceProtocol {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] encodeReminders(ArrayList<? extends Reminder> reminders) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] encodeFmFrequency(float frequency) {
|
public byte[] encodeFmFrequency(float frequency) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.ConfigureReminders">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:divider="@null"
|
||||||
|
android:id="@+id/reminder_list" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
app:srcCompat="@drawable/ic_add"
|
||||||
|
android:layout_margin="16dp" />
|
||||||
|
</RelativeLayout>
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/constraintLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.ReminderDetails">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_repeat"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
card_view:cardCornerRadius="4dp"
|
||||||
|
card_view:cardElevation="4dp"
|
||||||
|
card_view:contentPadding="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_repeat"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reminder_repeat"
|
||||||
|
android:textAppearance="?android:attr/textAppearance"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/reminder_repeat"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:text="Once"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/label_repeat" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_date"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/card_time"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/card_repeat"
|
||||||
|
card_view:cardCornerRadius="4dp"
|
||||||
|
card_view:cardElevation="4dp"
|
||||||
|
card_view:contentPadding="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reminder_date"
|
||||||
|
android:textAppearance="?android:attr/textAppearance"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/reminder_date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:text="2019-08-17"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/label_date" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_time"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/card_date"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/card_repeat"
|
||||||
|
card_view:cardCornerRadius="4dp"
|
||||||
|
card_view:cardElevation="4dp"
|
||||||
|
card_view:contentPadding="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reminder_time"
|
||||||
|
android:textAppearance="?android:attr/textAppearance"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/reminder_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:text="16:35"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/label_time" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_view4"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/card_time"
|
||||||
|
card_view:cardCornerRadius="4dp"
|
||||||
|
card_view:cardElevation="4dp"
|
||||||
|
card_view:contentPadding="4dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/reminder_message"
|
||||||
|
android:textAppearance="?android:attr/textAppearance"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/reminder_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/label_message" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab_save"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_save" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -370,7 +370,7 @@
|
|||||||
card_view:tint="@color/secondarytext" />
|
card_view:tint="@color/secondarytext" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/device_action_show_activity_graphs"
|
android:id="@+id/device_action_set_reminders"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_below="@id/device_image"
|
android:layout_below="@id/device_image"
|
||||||
@@ -378,6 +378,22 @@
|
|||||||
android:layout_toEndOf="@id/device_action_set_alarms"
|
android:layout_toEndOf="@id/device_action_set_alarms"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
android:contentDescription="@string/controlcenter_start_configure_reminders"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
card_view:srcCompat="@drawable/ic_device_set_reminders"
|
||||||
|
android:tint="@color/secondarytext" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/device_action_show_activity_graphs"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_below="@id/device_image"
|
||||||
|
android:layout_margin="3dp"
|
||||||
|
android:layout_toEndOf="@id/device_action_set_reminders"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
android:contentDescription="@string/controlcenter_start_activitymonitor"
|
android:contentDescription="@string/controlcenter_start_activitymonitor"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="3dp"
|
android:padding="3dp"
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/card_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
card_view:cardCornerRadius="4dp"
|
||||||
|
card_view:cardElevation="4dp"
|
||||||
|
card_view:contentPadding="4dp">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/reminder_item_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginStart="3dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="Every ?, at ??:??"
|
||||||
|
android:textAppearance="?android:attr/textAppearance" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/reminder_item_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginStart="3dp"
|
||||||
|
android:layout_marginTop="25dp"
|
||||||
|
android:layout_marginEnd="0dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="?"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@@ -222,8 +222,23 @@
|
|||||||
<string name="control_center_cancel_to_stop_vibration">Cancele para parar a vibração.</string>
|
<string name="control_center_cancel_to_stop_vibration">Cancele para parar a vibração.</string>
|
||||||
<string name="title_activity_charts">Atividade e sono</string>
|
<string name="title_activity_charts">Atividade e sono</string>
|
||||||
<string name="title_activity_set_alarm">Configurar alarmes</string>
|
<string name="title_activity_set_alarm">Configurar alarmes</string>
|
||||||
|
<string name="title_activity_set_reminders">Configurar Lembretes</string>
|
||||||
<string name="controlcenter_start_configure_alarms">Configurar alarmes</string>
|
<string name="controlcenter_start_configure_alarms">Configurar alarmes</string>
|
||||||
|
<string name="controlcenter_start_configure_reminders">Configurar lembretes</string>
|
||||||
<string name="title_activity_alarm_details">Detalhes do alarme</string>
|
<string name="title_activity_alarm_details">Detalhes do alarme</string>
|
||||||
|
<string name="title_activity_reminder_details">Detalhes do lembrete</string>
|
||||||
|
<string name="reminder_time_once">%1$s, uma vez</string>
|
||||||
|
<string name="reminder_time_every_day">%1$s, todos os dias</string>
|
||||||
|
<string name="reminder_time_every_week">%1$s, todas as semanas</string>
|
||||||
|
<string name="reminder_time_every_month">%1$s, todos os meses</string>
|
||||||
|
<string name="reminder_time_every_year">%1$s, todos os anos</string>
|
||||||
|
<string name="reminder_once">Uma vez</string>
|
||||||
|
<string name="reminder_every_day">Todos os dias</string>
|
||||||
|
<string name="reminder_every_week">Todas as semanas</string>
|
||||||
|
<string name="reminder_every_month">Todos os meses</string>
|
||||||
|
<string name="reminder_every_year">Todos os anos</string>
|
||||||
|
<string name="reminder_delete_confirm_title">Apagar lembrete</string>
|
||||||
|
<string name="reminder_delete_confirm_description">De certeza que pretende apagar o lembrete?</string>
|
||||||
<string name="alarm_sun_short">Dom</string>
|
<string name="alarm_sun_short">Dom</string>
|
||||||
<string name="alarm_mon_short">Seg</string>
|
<string name="alarm_mon_short">Seg</string>
|
||||||
<string name="alarm_tue_short">Ter</string>
|
<string name="alarm_tue_short">Ter</string>
|
||||||
|
|||||||
@@ -1490,6 +1490,14 @@
|
|||||||
<item>1800</item>
|
<item>1800</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="reminder_repeat">
|
||||||
|
<item>@string/reminder_once</item>
|
||||||
|
<item>@string/reminder_every_day</item>
|
||||||
|
<item>@string/reminder_every_week</item>
|
||||||
|
<item>@string/reminder_every_month</item>
|
||||||
|
<item>@string/reminder_every_year</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="notification_filter_modes_entries">
|
<string-array name="notification_filter_modes_entries">
|
||||||
<item>@string/filter_mode_none</item>
|
<item>@string/filter_mode_none</item>
|
||||||
<item>@string/filter_mode_whitelist</item>
|
<item>@string/filter_mode_whitelist</item>
|
||||||
|
|||||||
@@ -451,8 +451,29 @@
|
|||||||
<string name="control_center_cancel_to_stop_vibration">Cancel to stop vibration.</string>
|
<string name="control_center_cancel_to_stop_vibration">Cancel to stop vibration.</string>
|
||||||
<string name="title_activity_charts">Activity and Sleep</string>
|
<string name="title_activity_charts">Activity and Sleep</string>
|
||||||
<string name="title_activity_set_alarm">Configure alarms</string>
|
<string name="title_activity_set_alarm">Configure alarms</string>
|
||||||
|
<string name="title_activity_set_reminders">Configure reminders</string>
|
||||||
<string name="controlcenter_start_configure_alarms">Configure alarms</string>
|
<string name="controlcenter_start_configure_alarms">Configure alarms</string>
|
||||||
|
<string name="controlcenter_start_configure_reminders">Configure reminders</string>
|
||||||
|
<string name="reminder_repeat">Repeat</string>
|
||||||
|
<string name="reminder_date">Date</string>
|
||||||
|
<string name="reminder_time">Time</string>
|
||||||
|
<string name="reminder_message">Message</string>
|
||||||
|
<string name="reminder_time_once">%1$s, once</string>
|
||||||
|
<string name="reminder_time_every_day">%1$s, every day</string>
|
||||||
|
<string name="reminder_time_every_week">%1$s, every week</string>
|
||||||
|
<string name="reminder_time_every_month">%1$s, every month</string>
|
||||||
|
<string name="reminder_time_every_year">%1$s, every year</string>
|
||||||
|
<string name="reminder_once">Once</string>
|
||||||
|
<string name="reminder_every_day">Every day</string>
|
||||||
|
<string name="reminder_every_week">Every week</string>
|
||||||
|
<string name="reminder_every_month">Every month</string>
|
||||||
|
<string name="reminder_every_year">Every year</string>
|
||||||
|
<string name="reminder_delete_confirm_title">Delete reminder</string>
|
||||||
|
<string name="reminder_delete_confirm_description">Are you sure you want to delete the reminder?</string>
|
||||||
|
<string name="reminder_no_free_slots_title">No free slots</string>
|
||||||
|
<string name="reminder_no_free_slots_description">The device has no free slots for reminders (total slots: %1$s)</string>
|
||||||
<string name="title_activity_alarm_details">Alarm details</string>
|
<string name="title_activity_alarm_details">Alarm details</string>
|
||||||
|
<string name="title_activity_reminder_details">Reminder details</string>
|
||||||
<string name="alarm_sun_short">Sun</string>
|
<string name="alarm_sun_short">Sun</string>
|
||||||
<string name="alarm_mon_short">Mon</string>
|
<string name="alarm_mon_short">Mon</string>
|
||||||
<string name="alarm_tue_short">Tue</string>
|
<string name="alarm_tue_short">Tue</string>
|
||||||
@@ -577,6 +598,7 @@
|
|||||||
<string name="miband_fwinstaller_incompatible_version">Incompatible firmware</string>
|
<string name="miband_fwinstaller_incompatible_version">Incompatible firmware</string>
|
||||||
<string name="fwinstaller_firmware_not_compatible_to_device">This firmware is not compatible with the device</string>
|
<string name="fwinstaller_firmware_not_compatible_to_device">This firmware is not compatible with the device</string>
|
||||||
<string name="miband_prefs_reserve_alarm_calendar">Alarms to reserve for upcoming events</string>
|
<string name="miband_prefs_reserve_alarm_calendar">Alarms to reserve for upcoming events</string>
|
||||||
|
<string name="miband_prefs_reserve_reminder_calendar">Reminders to reserve for upcoming events</string>
|
||||||
<string name="miband_prefs_hr_sleep_detection">Use heart rate sensor to improve sleep detection</string>
|
<string name="miband_prefs_hr_sleep_detection">Use heart rate sensor to improve sleep detection</string>
|
||||||
<string name="miband_prefs_device_time_offset_hours">Device time offset in hours (for detecting sleep of shift workers)</string>
|
<string name="miband_prefs_device_time_offset_hours">Device time offset in hours (for detecting sleep of shift workers)</string>
|
||||||
<string name="prefs_find_phone">Find phone</string>
|
<string name="prefs_find_phone">Find phone</string>
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<EditTextPreference
|
||||||
|
android:icon="@drawable/ic_access_alarms"
|
||||||
|
android:defaultValue="9"
|
||||||
|
android:digits="0123"
|
||||||
|
android:inputType="number"
|
||||||
|
android:key="reserve_reminders_calendar"
|
||||||
|
android:maxLength="1"
|
||||||
|
android:title="@string/miband_prefs_reserve_reminder_calendar" />
|
||||||
|
|
||||||
|
</androidx.preference.PreferenceScreen>
|
||||||
Reference in New Issue
Block a user