mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-24 01:25:50 +01:00
Mi Band 3: Add support for Reminders
This commit is contained in:
parent
1e715b4914
commit
710b6f6699
@ -43,7 +43,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
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 user = addUserInfo(schema, userAttributes);
|
||||
@ -86,6 +86,7 @@ public class GBDaoGenerator {
|
||||
addHybridHRActivitySample(schema, user, device);
|
||||
addCalendarSyncState(schema, device);
|
||||
addAlarms(schema, user, device);
|
||||
addReminders(schema, user, device);
|
||||
|
||||
Entity notificationFilter = addNotificationFilters(schema);
|
||||
|
||||
@ -541,6 +542,25 @@ public class GBDaoGenerator {
|
||||
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) {
|
||||
Entity notificatonFilterEntry = addEntity(schema, "NotificationFilterEntry");
|
||||
notificatonFilterEntry.addIdProperty().autoincrement();
|
||||
|
@ -485,6 +485,10 @@
|
||||
android:name=".activities.ConfigureAlarms"
|
||||
android:label="@string/title_activity_set_alarm"
|
||||
android:parentActivityName=".activities.ControlCenterv2" />
|
||||
<activity
|
||||
android:name=".activities.ConfigureReminders"
|
||||
android:label="@string/title_activity_set_reminders"
|
||||
android:parentActivityName=".activities.ControlCenterv2" />
|
||||
<activity
|
||||
android:name=".activities.devicesettings.DeviceSettingsActivity"
|
||||
android:label="@string/title_activity_device_specific_settings"
|
||||
@ -494,6 +498,12 @@
|
||||
android:label="@string/title_activity_alarm_details"
|
||||
android:parentActivityName=".activities.ConfigureAlarms"
|
||||
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
|
||||
android:name=".activities.VibrationActivity"
|
||||
android:label="@string/title_activity_vibration"
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ public class DeviceSettingsPreferenceConst {
|
||||
public static final String PREF_NOTIFICATION_ENABLE = "notification_enable";
|
||||
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_REMINDERS_CALENDAR = "reserve_reminders_calendar";
|
||||
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_USE_CUSTOM_DEVICEICON = "use_custom_deviceicon";
|
||||
|
@ -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(MakibesHR3Constants.PREF_FIND_PHONE_DURATION, 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);
|
||||
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.BatteryInfoActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureReminders;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateDialog;
|
||||
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
|
||||
holder.showActivityGraphs.setVisibility(coordinator.supportsActivityTracking() ? View.VISIBLE : View.GONE);
|
||||
holder.showActivityGraphs.setOnClickListener(new View.OnClickListener()
|
||||
@ -743,6 +759,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
||||
ImageView takeScreenshotView;
|
||||
ImageView manageAppsView;
|
||||
ImageView setAlarmsView;
|
||||
ImageView setRemindersView;
|
||||
ImageView showActivityGraphs;
|
||||
ImageView showActivityTracks;
|
||||
ImageView calibrateDevice;
|
||||
@ -797,6 +814,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
||||
takeScreenshotView = view.findViewById(R.id.device_action_take_screenshot);
|
||||
manageAppsView = view.findViewById(R.id.device_action_manage_apps);
|
||||
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);
|
||||
showActivityTracks = view.findViewById(R.id.device_action_show_activity_tracks);
|
||||
deviceInfoView = view.findViewById(R.id.device_info_image);
|
||||
|
@ -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.DeviceAttributesDao;
|
||||
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.TagDao;
|
||||
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() {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
DaoSession session = dbHandler.getDaoSession();
|
||||
|
@ -222,6 +222,16 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumReminderMessageLength() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReminderSlotCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRgbLedColor() {
|
||||
return false;
|
||||
|
@ -321,6 +321,16 @@ public interface DeviceCoordinator {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -30,6 +30,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
/**
|
||||
@ -46,6 +47,8 @@ public interface EventHandler {
|
||||
|
||||
void onSetAlarms(ArrayList<? extends Alarm> alarms);
|
||||
|
||||
void onSetReminders(ArrayList<? extends Reminder> reminders);
|
||||
|
||||
void onSetCallState(CallSpec callSpec);
|
||||
|
||||
void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec);
|
||||
|
@ -84,6 +84,15 @@ public class MiBand3Coordinator extends HuamiCoordinator {
|
||||
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) {
|
||||
Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress));
|
||||
@ -111,6 +120,7 @@ public class MiBand3Coordinator extends HuamiCoordinator {
|
||||
R.xml.devicesettings_liftwrist_display,
|
||||
R.xml.devicesettings_swipeunlock,
|
||||
R.xml.devicesettings_sync_calendar,
|
||||
R.xml.devicesettings_reserve_reminders_calendar,
|
||||
R.xml.devicesettings_expose_hr_thirdparty,
|
||||
R.xml.devicesettings_bt_connected_advertisement,
|
||||
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.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.RtlUtils;
|
||||
@ -225,6 +226,13 @@ public class GBDeviceService implements DeviceService {
|
||||
invokeService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||
Intent intent = createIntent().setAction(ACTION_SET_REMINDERS)
|
||||
.putExtra(EXTRA_REMINDERS, reminders);
|
||||
invokeService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetMusicInfo(MusicSpec musicSpec) {
|
||||
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_ALARMS = PREFIX + ".action.set_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_REALTIME_SAMPLES = PREFIX + ".action.realtime_samples";
|
||||
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_CONFIG = "config";
|
||||
String EXTRA_ALARMS = "alarms";
|
||||
String EXTRA_REMINDERS = "reminders";
|
||||
String EXTRA_CONNECT_FIRST_TIME = "connect_first_time";
|
||||
String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps";
|
||||
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();
|
||||
}
|
@ -73,6 +73,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.receivers.AutoConnectIntervalReceiver;
|
||||
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_HEARTRATE_MEASUREMENT_INTERVAL;
|
||||
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_STARTAPP;
|
||||
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_TYPE;
|
||||
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_URI;
|
||||
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);
|
||||
mDeviceSupport.onSetAlarms(alarms);
|
||||
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: {
|
||||
boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false);
|
||||
mDeviceSupport.onEnableRealtimeSteps(enable);
|
||||
|
@ -37,6 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
/**
|
||||
@ -309,6 +310,14 @@ public class ServiceDeviceSupport implements DeviceSupport {
|
||||
delegate.onSetAlarms(alarms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||
if (checkBusy("set reminders")) {
|
||||
return;
|
||||
}
|
||||
delegate.onSetReminders(reminders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnableRealtimeSteps(boolean enable) {
|
||||
if (checkBusy("enable realtime steps: " + enable)) {
|
||||
|
@ -36,6 +36,7 @@ import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.Logging;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.CheckInitializedAction;
|
||||
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
|
||||
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
|
||||
|
||||
|
@ -107,6 +107,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
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_LANGUAGE;
|
||||
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_SYNC_CALENDAR;
|
||||
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
|
||||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
if (notificationSpec.type == NotificationType.GENERIC_ALARM_CLOCK) {
|
||||
@ -1903,19 +2016,21 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
return this;
|
||||
}
|
||||
|
||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||
int availableSlots = prefs.getInt(PREF_RESERVER_REMINDERS_CALENDAR, 9);
|
||||
|
||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
||||
List<CalendarEvents.CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList(getContext());
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
||||
int iteration = 0;
|
||||
int iterationMax = 8;
|
||||
|
||||
for (CalendarEvents.CalendarEvent calendarEvent : calendarEvents) {
|
||||
if (calendarEvent.isAllDay()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iteration > iterationMax) { // limit ?
|
||||
if (iteration >= availableSlots) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1948,7 +2063,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
// Continue by deleting the events
|
||||
for(;iteration < iterationMax; iteration++){
|
||||
for(;iteration < availableSlots; iteration++){
|
||||
int length = 1 + 1 + 4 + 6 + 6 + 1 + 0 + 1;
|
||||
ByteBuffer buf = ByteBuffer.allocate(length);
|
||||
|
||||
@ -3014,6 +3129,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
setDisconnectNotification(builder);
|
||||
setExposeHRThridParty(builder);
|
||||
setHeartrateMeasurementInterval(builder, getHeartRateMeasurementInterval());
|
||||
sendReminders(builder);
|
||||
requestAlarms(builder);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.serial;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
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.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
||||
|
||||
@ -262,4 +264,10 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport
|
||||
byte[] bytes = gbDeviceProtocol.encodeLedColor(color);
|
||||
sendToDevice(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
||||
byte[] bytes = gbDeviceProtocol.encodeReminders(reminders);
|
||||
sendToDevice(bytes);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.serial;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
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.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
|
||||
public abstract class GBDeviceProtocol {
|
||||
@ -141,6 +143,10 @@ public abstract class GBDeviceProtocol {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] encodeReminders(ArrayList<? extends Reminder> reminders) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] encodeFmFrequency(float frequency) {
|
||||
return null;
|
||||
}
|
||||
|
9
app/src/main/res/drawable/ic_device_set_reminders.xml
Normal file
9
app/src/main/res/drawable/ic_device_set_reminders.xml
Normal file
@ -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>
|
9
app/src/main/res/drawable/ic_save.xml
Normal file
9
app/src/main/res/drawable/ic_save.xml
Normal file
@ -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>
|
27
app/src/main/res/layout/activity_configure_reminders.xml
Normal file
27
app/src/main/res/layout/activity_configure_reminders.xml
Normal file
@ -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>
|
175
app/src/main/res/layout/activity_reminder_details.xml
Normal file
175
app/src/main/res/layout/activity_reminder_details.xml
Normal file
@ -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" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_action_show_activity_graphs"
|
||||
android:id="@+id/device_action_set_reminders"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_below="@id/device_image"
|
||||
@ -378,6 +378,22 @@
|
||||
android:layout_toEndOf="@id/device_action_set_alarms"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
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:focusable="true"
|
||||
android:padding="3dp"
|
||||
|
51
app/src/main/res/layout/item_reminder.xml
Normal file
51
app/src/main/res/layout/item_reminder.xml
Normal file
@ -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="title_activity_charts">Atividade e sono</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_reminders">Configurar lembretes</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_mon_short">Seg</string>
|
||||
<string name="alarm_tue_short">Ter</string>
|
||||
|
@ -1490,6 +1490,14 @@
|
||||
<item>1800</item>
|
||||
</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">
|
||||
<item>@string/filter_mode_none</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="title_activity_charts">Activity and Sleep</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_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_reminder_details">Reminder details</string>
|
||||
<string name="alarm_sun_short">Sun</string>
|
||||
<string name="alarm_mon_short">Mon</string>
|
||||
<string name="alarm_tue_short">Tue</string>
|
||||
@ -577,6 +598,7 @@
|
||||
<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="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_device_time_offset_hours">Device time offset in hours (for detecting sleep of shift workers)</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>
|
Loading…
Reference in New Issue
Block a user