mirror of
https://github.com/M66B/FairEmail.git
synced 2024-12-27 02:07:12 +00:00
Added simple scheduling
This commit is contained in:
parent
084265a1ce
commit
041f2ca3d4
5 changed files with 254 additions and 33 deletions
|
@ -19,6 +19,8 @@ package eu.faircode.email;
|
|||
Copyright 2018-2019 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -31,6 +33,7 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -42,13 +45,17 @@ import android.widget.Button;
|
|||
import android.widget.CompoundButton;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.constraintlayout.widget.Group;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
|
@ -56,7 +63,8 @@ import static android.app.Activity.RESULT_OK;
|
|||
|
||||
public class FragmentOptions extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private SwitchCompat swEnabled;
|
||||
private SwitchCompat swUpdates;
|
||||
private TextView tvScheduleStart;
|
||||
private TextView tvScheduleEnd;
|
||||
|
||||
private TextView tvConnectionType;
|
||||
private SwitchCompat swMetered;
|
||||
|
@ -90,6 +98,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
private SwitchCompat swLight;
|
||||
private Button btnSound;
|
||||
|
||||
private SwitchCompat swUpdates;
|
||||
private SwitchCompat swDebug;
|
||||
|
||||
private Group grpNotification;
|
||||
|
@ -101,13 +110,13 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
};
|
||||
|
||||
private final static String[] ADVANCED_OPTIONS = new String[]{
|
||||
"enabled", "updates",
|
||||
"enabled", "schedule_start", "schedule_end",
|
||||
"metered", "download",
|
||||
"unified", "date", "threading", "avatars", "identicons", "name_email", "preview", "addresses", "autoimages", "actionbar",
|
||||
"pull", "swipenav", "autoexpand", "autoclose", "autonext", "collapse", "autoread", "automove",
|
||||
"autoresize", "sender", "autosend",
|
||||
"notify_preview", "light", "sound",
|
||||
"debug",
|
||||
"updates", "debug",
|
||||
"first", "why", "last_update_check", "app_support", "message_swipe", "message_select", "folder_actions", "folder_sync",
|
||||
"edit_ref_confirmed", "show_html_confirmed", "show_images_confirmed"
|
||||
};
|
||||
|
@ -122,7 +131,8 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
|
||||
// Get controls
|
||||
swEnabled = view.findViewById(R.id.swEnabled);
|
||||
swUpdates = view.findViewById(R.id.swUpdates);
|
||||
tvScheduleStart = view.findViewById(R.id.tvScheduleStart);
|
||||
tvScheduleEnd = view.findViewById(R.id.tvScheduleEnd);
|
||||
|
||||
tvConnectionType = view.findViewById(R.id.tvConnectionType);
|
||||
swMetered = view.findViewById(R.id.swMetered);
|
||||
|
@ -156,6 +166,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
swLight = view.findViewById(R.id.swLight);
|
||||
btnSound = view.findViewById(R.id.btnSound);
|
||||
|
||||
swUpdates = view.findViewById(R.id.swUpdates);
|
||||
swDebug = view.findViewById(R.id.swDebug);
|
||||
|
||||
grpNotification = view.findViewById(R.id.grpNotification);
|
||||
|
@ -174,6 +185,28 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
}
|
||||
});
|
||||
|
||||
tvScheduleStart.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("start", true);
|
||||
DialogFragment timePicker = new TimePickerFragment();
|
||||
timePicker.setArguments(args);
|
||||
timePicker.show(getFragmentManager(), "timePicker");
|
||||
}
|
||||
});
|
||||
|
||||
tvScheduleEnd.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("start", false);
|
||||
DialogFragment timePicker = new TimePickerFragment();
|
||||
timePicker.setArguments(args);
|
||||
timePicker.show(getFragmentManager(), "timePicker");
|
||||
}
|
||||
});
|
||||
|
||||
swUpdates.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
|
@ -480,8 +513,9 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
swEnabled.setChecked(prefs.getBoolean("enabled", true));
|
||||
swUpdates.setChecked(prefs.getBoolean("updates", true));
|
||||
swUpdates.setVisibility(Helper.isPlayStoreInstall(getContext()) ? View.GONE : View.VISIBLE);
|
||||
|
||||
tvScheduleStart.setText(formatHour(prefs.getInt("schedule_start", 0)));
|
||||
tvScheduleEnd.setText(formatHour(prefs.getInt("schedule_end", 0)));
|
||||
|
||||
swMetered.setChecked(prefs.getBoolean("metered", true));
|
||||
|
||||
|
@ -524,11 +558,55 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
|
||||
swNotifyPreview.setChecked(prefs.getBoolean("notify_preview", true));
|
||||
swLight.setChecked(prefs.getBoolean("light", false));
|
||||
swUpdates.setChecked(prefs.getBoolean("updates", true));
|
||||
swUpdates.setVisibility(Helper.isPlayStoreInstall(getContext()) ? View.GONE : View.VISIBLE);
|
||||
swDebug.setChecked(prefs.getBoolean("debug", false));
|
||||
|
||||
grpNotification.setVisibility(BuildConfig.DEBUG || Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private String formatHour(int minutes) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, minutes / 60);
|
||||
cal.set(Calendar.MINUTE, minutes % 60);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
return SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(cal.getTime());
|
||||
}
|
||||
|
||||
public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle args = getArguments();
|
||||
boolean start = args.getBoolean("start");
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
int minutes = prefs.getInt("schedule_" + (start ? "start" : "end"), 0);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, minutes / 60);
|
||||
cal.set(Calendar.MINUTE, minutes % 60);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
return new TimePickerDialog(getActivity(), this,
|
||||
cal.get(Calendar.HOUR_OF_DAY),
|
||||
cal.get(Calendar.MINUTE),
|
||||
DateFormat.is24HourFormat(getActivity()));
|
||||
}
|
||||
|
||||
public void onTimeSet(TimePicker view, int hour, int minute) {
|
||||
Bundle args = getArguments();
|
||||
boolean start = args.getBoolean("start");
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
prefs.edit().putInt("schedule_" + (start ? "start" : "end"), hour * 60 + minute).apply();
|
||||
|
||||
ServiceSynchronize.schedule(getContext());
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
|
@ -587,5 +665,9 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O
|
|||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
if ("enabled".equals(key))
|
||||
swEnabled.setChecked(prefs.getBoolean(key, true));
|
||||
else if ("schedule_start".equals(key))
|
||||
tvScheduleStart.setText(formatHour(prefs.getInt(key, 0)));
|
||||
else if ("schedule_end".equals(key))
|
||||
tvScheduleEnd.setText(formatHour(prefs.getInt(key, 0)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,19 +42,22 @@ public class JobDaily extends JobService {
|
|||
private static final long CACHE_IMAGE_DURATION = 3 * 24 * 3600 * 1000L; // milliseconds
|
||||
private static final long KEEP_LOG_DURATION = 24 * 3600 * 1000L; // milliseconds
|
||||
|
||||
public static void schedule(Context context) {
|
||||
Log.i("Scheduling daily job");
|
||||
public static void schedule(Context context, boolean enabled) {
|
||||
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
|
||||
JobInfo.Builder job = new JobInfo.Builder(Helper.JOB_DAILY, new ComponentName(context, JobDaily.class))
|
||||
.setPeriodic(CLEANUP_INTERVAL)
|
||||
.setRequiresDeviceIdle(true);
|
||||
|
||||
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
scheduler.cancel(Helper.JOB_DAILY);
|
||||
if (scheduler.schedule(job.build()) == JobScheduler.RESULT_SUCCESS)
|
||||
Log.i("Scheduled daily job");
|
||||
else
|
||||
Log.e("Scheduling daily job failed");
|
||||
if (enabled)
|
||||
if (scheduler.schedule(job.build()) == JobScheduler.RESULT_SUCCESS)
|
||||
Log.i("Scheduled daily job");
|
||||
else
|
||||
Log.e("Scheduling daily job failed");
|
||||
else {
|
||||
Log.i("Cancelled daily job");
|
||||
scheduler.cancel(Helper.JOB_DAILY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -163,6 +163,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
static final int PI_TRASH = 6;
|
||||
static final int PI_IGNORED = 7;
|
||||
static final int PI_SNOOZED = 8;
|
||||
static final int PI_SCHEDULE = 9;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
|
@ -304,6 +305,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String action = (intent == null ? null : intent.getAction());
|
||||
Log.i("Service command intent=" + intent + " action=" + action);
|
||||
Log.logExtras(intent);
|
||||
|
||||
startForeground(NOTIFICATION_SYNCHRONIZE, getNotificationService(null).build());
|
||||
|
||||
|
@ -335,6 +337,10 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
serviceManager.service_init();
|
||||
break;
|
||||
|
||||
case "schedule":
|
||||
serviceManager.service_schedule();
|
||||
break;
|
||||
|
||||
case "reload":
|
||||
serviceManager.service_reload(intent.getStringExtra("reason"));
|
||||
break;
|
||||
|
@ -3015,6 +3021,18 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
|
||||
private void service_init() {
|
||||
EntityLog.log(ServiceSynchronize.this, "Service init");
|
||||
|
||||
next_schedule();
|
||||
|
||||
boolean enabled = isEnabled();
|
||||
JobDaily.schedule(ServiceSynchronize.this, enabled);
|
||||
if (!enabled)
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
private void service_schedule() {
|
||||
next_schedule();
|
||||
service_reload("schedule");
|
||||
}
|
||||
|
||||
private void service_reload(String reason) {
|
||||
|
@ -3033,6 +3051,8 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
if (started)
|
||||
queue_reload(false, "service destroy");
|
||||
}
|
||||
|
||||
JobDaily.schedule(ServiceSynchronize.this, false);
|
||||
}
|
||||
|
||||
private void start() {
|
||||
|
@ -3209,11 +3229,63 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
state = null;
|
||||
}
|
||||
|
||||
private void next_schedule() {
|
||||
Intent schedule = new Intent(ServiceSynchronize.this, ServiceSynchronize.class);
|
||||
schedule.setAction("schedule");
|
||||
PendingIntent piSchedule = PendingIntent.getService(
|
||||
ServiceSynchronize.this, PI_SCHEDULE, schedule, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
am.cancel(piSchedule);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSynchronize.this);
|
||||
int minuteStart = prefs.getInt("schedule_start", 0);
|
||||
int minuteEnd = prefs.getInt("schedule_end", 0);
|
||||
|
||||
if (minuteEnd <= minuteStart)
|
||||
minuteEnd += 24 * 60;
|
||||
|
||||
Calendar calStart = Calendar.getInstance();
|
||||
calStart.set(Calendar.HOUR_OF_DAY, minuteStart / 60);
|
||||
calStart.set(Calendar.MINUTE, minuteStart % 60);
|
||||
calStart.set(Calendar.SECOND, 0);
|
||||
calStart.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
Calendar calEnd = Calendar.getInstance();
|
||||
calEnd.set(Calendar.HOUR_OF_DAY, minuteEnd / 60);
|
||||
calEnd.set(Calendar.MINUTE, minuteEnd % 60);
|
||||
calEnd.set(Calendar.SECOND, 0);
|
||||
calEnd.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
long now = new Date().getTime();
|
||||
if (now > calEnd.getTimeInMillis()) {
|
||||
calStart.set(Calendar.DAY_OF_MONTH, calStart.get(Calendar.DAY_OF_MONTH) + 1);
|
||||
calEnd.set(Calendar.DAY_OF_MONTH, calEnd.get(Calendar.DAY_OF_MONTH) + 1);
|
||||
}
|
||||
|
||||
long start = calStart.getTimeInMillis();
|
||||
long end = calEnd.getTimeInMillis();
|
||||
long next = (now < start ? start : end);
|
||||
|
||||
EntityLog.log(ServiceSynchronize.this, "Schedule now=" + new Date(now));
|
||||
EntityLog.log(ServiceSynchronize.this, "Schedule start=" + new Date(start));
|
||||
EntityLog.log(ServiceSynchronize.this, "Schedule end=" + new Date(end));
|
||||
EntityLog.log(ServiceSynchronize.this, "Schedule next=" + new Date(next));
|
||||
|
||||
boolean enabled = (now >= start && now < end);
|
||||
prefs.edit().putBoolean("enabled", enabled).apply();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, next, piSchedule);
|
||||
else
|
||||
am.set(AlarmManager.RTC_WAKEUP, next, piSchedule);
|
||||
}
|
||||
|
||||
private void queue_reload(final boolean start, final String reason) {
|
||||
final boolean doStop = started;
|
||||
final boolean doStart = (start && isEnabled() && suitableNetwork());
|
||||
|
||||
EntityLog.log(ServiceSynchronize.this, "Queue reload " +
|
||||
EntityLog.log(ServiceSynchronize.this, "Queue reload" +
|
||||
" doStop=" + doStop + " doStart=" + doStart + " queued=" + queued + " " + reason);
|
||||
|
||||
started = doStart;
|
||||
|
@ -3276,13 +3348,15 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (prefs.getBoolean("enabled", true)) {
|
||||
ContextCompat.startForegroundService(context,
|
||||
new Intent(context, ServiceSynchronize.class)
|
||||
.setAction("init"));
|
||||
JobDaily.schedule(context);
|
||||
}
|
||||
ContextCompat.startForegroundService(context,
|
||||
new Intent(context, ServiceSynchronize.class)
|
||||
.setAction("init"));
|
||||
}
|
||||
|
||||
public static void schedule(Context context) {
|
||||
ContextCompat.startForegroundService(context,
|
||||
new Intent(context, ServiceSynchronize.class)
|
||||
.setAction("schedule"));
|
||||
}
|
||||
|
||||
public static void reload(Context context, String reason) {
|
||||
|
|
|
@ -57,17 +57,65 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/swEnabled" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/swUpdates"
|
||||
android:layout_width="match_parent"
|
||||
<TextView
|
||||
android:id="@+id/tvSchedule"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="@string/title_advanced_updates"
|
||||
android:text="@string/title_advanced_schedule"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tvScheduleStart"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvEnabledHint"
|
||||
app:switchPadding="12dp" />
|
||||
app:layout_constraintTop_toTopOf="@+id/tvScheduleStart" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvScheduleStart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:padding="12dp"
|
||||
android:text="00:00"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tvScheduleSeparator"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvEnabledHint" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvScheduleSeparator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:text="—"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tvScheduleStart"
|
||||
app:layout_constraintEnd_toStartOf="@+id/tvScheduleEnd"
|
||||
app:layout_constraintTop_toTopOf="@+id/tvScheduleStart" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvScheduleEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:text="00:00"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvEnabledHint" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvScheduleHint"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="60dp"
|
||||
android:text="@string/title_advanced_schedule_hint"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvScheduleEnd" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSectionConnection"
|
||||
|
@ -78,7 +126,7 @@
|
|||
android:text="@string/title_advanced_section_connection"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/swUpdates" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvScheduleHint" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorConnection"
|
||||
|
@ -680,6 +728,18 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/swLight" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/swUpdates"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="@string/title_advanced_updates"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnSound"
|
||||
app:switchPadding="12dp" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/swDebug"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -690,7 +750,7 @@
|
|||
android:layout_marginBottom="12dp"
|
||||
android:text="@string/title_advanced_debug"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnSound"
|
||||
app:layout_constraintTop_toBottomOf="@id/swUpdates"
|
||||
app:switchPadding="12dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
|
|
|
@ -141,7 +141,8 @@
|
|||
<string name="title_advanced_section_misc">Miscellaneous</string>
|
||||
|
||||
<string name="title_advanced_enabled">Synchronize</string>
|
||||
<string name="title_advanced_updates">Check for updates</string>
|
||||
<string name="title_advanced_schedule">Schedule</string>
|
||||
<string name="title_advanced_schedule_hint">Tap on a time to set a time</string>
|
||||
|
||||
<string name="title_advanced_metered">Use metered connections</string>
|
||||
<string name="title_advanced_download">Automatically download messages and attachments on a metered connection up to</string>
|
||||
|
@ -174,6 +175,7 @@
|
|||
<string name="title_advanced_notify_preview">Show message preview in notifications</string>
|
||||
<string name="title_advanced_light">Use notification light</string>
|
||||
<string name="title_advanced_sound">Select notification sound</string>
|
||||
<string name="title_advanced_updates">Check for updates</string>
|
||||
<string name="title_advanced_debug">Debug mode</string>
|
||||
|
||||
<string name="title_advanced_enabled_hint">Globally disable or enable receiving and sending of messages</string>
|
||||
|
|
Loading…
Reference in a new issue