diff --git a/app/src/main/java/eu/faircode/email/ApplicationEx.java b/app/src/main/java/eu/faircode/email/ApplicationEx.java
index 27a50a98d0..8740a19958 100644
--- a/app/src/main/java/eu/faircode/email/ApplicationEx.java
+++ b/app/src/main/java/eu/faircode/email/ApplicationEx.java
@@ -281,6 +281,9 @@ public class ApplicationEx extends Application
case "schedule":
case "schedule_start":
case "schedule_end":
+ case "schedule_start_weekend":
+ case "schedule_end_weekend":
+ case "weekend":
case "schedule_day0":
case "schedule_day1":
case "schedule_day2":
diff --git a/app/src/main/java/eu/faircode/email/CalendarHelper.java b/app/src/main/java/eu/faircode/email/CalendarHelper.java
index 51bbbde5d9..ca8368ff66 100644
--- a/app/src/main/java/eu/faircode/email/CalendarHelper.java
+++ b/app/src/main/java/eu/faircode/email/CalendarHelper.java
@@ -23,11 +23,16 @@ import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
+import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract;
import android.text.TextUtils;
+import androidx.preference.PreferenceManager;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
@@ -43,6 +48,28 @@ import biweekly.property.RecurrenceRule;
import biweekly.util.ICalDate;
public class CalendarHelper {
+ static boolean isWeekend(Context context, Calendar calendar) {
+ return isWeekend(context, calendar.get(Calendar.DAY_OF_WEEK));
+ }
+
+ static boolean isWeekend(Context context, int aday) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ String weekend = prefs.getString("weekend", Calendar.SATURDAY + "," + Calendar.SUNDAY);
+ for (String day : weekend.split(","))
+ if (aday == Integer.parseInt(day))
+ return true;
+ return false;
+ }
+
+ static String formatHour(Context context, 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 Helper.getTimeInstance(context, SimpleDateFormat.SHORT).format(cal.getTime());
+ }
+
static void insert(Context context, ICalendar icalendar, VEvent event,
String selectedAccount, String selectedName, EntityMessage message) {
diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java b/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java
index 9c7ec46861..c37af668c0 100644
--- a/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java
+++ b/app/src/main/java/eu/faircode/email/FragmentOptionsSynchronize.java
@@ -22,8 +22,10 @@ package eu.faircode.email;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.text.format.DateFormat;
@@ -44,6 +46,7 @@ import android.widget.TimePicker;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SwitchCompat;
import androidx.constraintlayout.widget.Group;
import androidx.fragment.app.DialogFragment;
@@ -56,8 +59,8 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.text.DateFormatSymbols;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
@@ -75,6 +78,9 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
private TextView tvSchedulePro;
private TextView tvScheduleStart;
private TextView tvScheduleEnd;
+ private TextView tvScheduleStartWeekend;
+ private TextView tvScheduleEndWeekend;
+ private ImageButton ibWeekend;
private CheckBox[] cbDay;
private TextView tvScheduleIgnore;
private ImageButton ibSchedules;
@@ -114,8 +120,12 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
private AdapterAccountExempted adapter;
+ private int textColorTertiary;
+ private int colorAccent;
+
private final static String[] RESET_OPTIONS = new String[]{
- "enabled", "poll_interval", "auto_optimize", "schedule", "schedule_start", "schedule_end",
+ "enabled", "poll_interval", "auto_optimize",
+ "schedule", "schedule_start", "schedule_end", "schedule_start_weekend", "schedule_end_weekend", "weekend",
"sync_quick_imap", "sync_quick_pop",
"sync_nodate", "sync_unseen", "sync_flagged", "delete_unseen", "sync_kept",
"gmail_thread_id", "outlook_thread_id", "subject_threading",
@@ -125,6 +135,15 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
"tune_keep_alive"
};
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Context context = getContext();
+ this.textColorTertiary = Helper.resolveColor(context, android.R.attr.textColorTertiary);
+ this.colorAccent = Helper.resolveColor(context, R.attr.colorAccent);
+ }
+
@Override
@Nullable
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@@ -147,6 +166,9 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
tvSchedulePro = view.findViewById(R.id.tvSchedulePro);
tvScheduleStart = view.findViewById(R.id.tvScheduleStart);
tvScheduleEnd = view.findViewById(R.id.tvScheduleEnd);
+ tvScheduleStartWeekend = view.findViewById(R.id.tvScheduleStartWeekend);
+ tvScheduleEndWeekend = view.findViewById(R.id.tvScheduleEndWeekend);
+ ibWeekend = view.findViewById(R.id.ibWeekend);
cbDay = new CheckBox[]{
view.findViewById(R.id.cbDay0),
view.findViewById(R.id.cbDay1),
@@ -268,27 +290,24 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
Helper.linkPro(tvSchedulePro);
- tvScheduleStart.setOnClickListener(new View.OnClickListener() {
+ View.OnClickListener onSchedule = 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(getParentFragmentManager(), "timePicker");
- }
- });
+ int id = v.getId();
- tvScheduleEnd.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
Bundle args = new Bundle();
- args.putBoolean("start", false);
+ args.putBoolean("start", id == R.id.tvScheduleStart || id == R.id.tvScheduleStartWeekend);
+ args.putBoolean("weekend", id == R.id.tvScheduleStartWeekend || id == R.id.tvScheduleEndWeekend);
DialogFragment timePicker = new TimePickerFragment();
timePicker.setArguments(args);
timePicker.show(getParentFragmentManager(), "timePicker");
}
- });
+ };
+
+ tvScheduleStart.setOnClickListener(onSchedule);
+ tvScheduleEnd.setOnClickListener(onSchedule);
+ tvScheduleStartWeekend.setOnClickListener(onSchedule);
+ tvScheduleEndWeekend.setOnClickListener(onSchedule);
String[] daynames = new DateFormatSymbols().getWeekdays();
for (int i = 0; i < 7; i++) {
@@ -302,6 +321,14 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
});
}
+ ibWeekend.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FragmentDialogWeekend fragment = new FragmentDialogWeekend();
+ fragment.show(getParentFragmentManager(), "weekend");
+ }
+ });
+
tvScheduleIgnore.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -571,13 +598,14 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
if (view == null || getContext() == null)
return;
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
- boolean pro = ActivityBilling.isPro(getContext());
+ final Context context = getContext();
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ boolean pro = ActivityBilling.isPro(context);
swEnabled.setChecked(prefs.getBoolean("enabled", true));
swOptimize.setChecked(prefs.getBoolean("auto_optimize", false));
- int pollInterval = ServiceSynchronize.getPollInterval(getContext());
+ int pollInterval = ServiceSynchronize.getPollInterval(context);
int[] pollIntervalValues = getResources().getIntArray(R.array.pollIntervalValues);
for (int pos = 0; pos < pollIntervalValues.length; pos++)
if (pollIntervalValues[pos] == pollInterval) {
@@ -591,10 +619,22 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
swSchedule.setChecked(prefs.getBoolean("schedule", false) && pro);
swSchedule.setEnabled(pro);
- tvScheduleStart.setText(formatHour(getContext(), prefs.getInt("schedule_start", 0)));
- tvScheduleEnd.setText(formatHour(getContext(), prefs.getInt("schedule_end", 0)));
- for (int i = 0; i < 7; i++)
+
+ int schedule_start = prefs.getInt("schedule_start", 0);
+ int schedule_end = prefs.getInt("schedule_end", 0);
+ int schedule_start_weekend = prefs.getInt("schedule_start_weekend", schedule_start);
+ int schedule_end_weekend = prefs.getInt("schedule_end_weekend", schedule_end);
+ tvScheduleStart.setText(CalendarHelper.formatHour(context, schedule_start));
+ tvScheduleEnd.setText(CalendarHelper.formatHour(context, schedule_end));
+ tvScheduleStartWeekend.setText(CalendarHelper.formatHour(context, schedule_start_weekend));
+ tvScheduleEndWeekend.setText(CalendarHelper.formatHour(context, schedule_end_weekend));
+
+ for (int i = 0; i < 7; i++) {
+ boolean weekend = CalendarHelper.isWeekend(context, i + 1);
+ cbDay[i].setTypeface(weekend ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
+ cbDay[i].setTextColor(weekend ? colorAccent : textColorTertiary);
cbDay[i].setChecked(prefs.getBoolean("schedule_day" + i, true));
+ }
swQuickSyncImap.setChecked(prefs.getBoolean("sync_quick_imap", false));
swQuickSyncPop.setChecked(prefs.getBoolean("sync_quick_pop", true));
@@ -628,24 +668,13 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
rvBlocklist.setAlpha(swCheckBlocklist.isChecked() ? 1.0f : Helper.LOW_LIGHT);
}
- private String formatHour(Context context, 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 Helper.getTimeInstance(context, SimpleDateFormat.SHORT).format(cal.getTime());
- }
-
public static class TimePickerFragment extends FragmentDialogBase 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);
+ final Context context = getContext();
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ int minutes = prefs.getInt(getKey(), 0);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, minutes / 60);
@@ -653,21 +682,58 @@ public class FragmentOptionsSynchronize extends FragmentBase implements SharedPr
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
- return new TimePickerDialog(getContext(), this,
+ return new TimePickerDialog(context, this,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
- DateFormat.is24HourFormat(getContext()));
+ DateFormat.is24HourFormat(context));
}
public void onTimeSet(TimePicker view, int hour, int minute) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(getKey(), hour * 60 + minute).putBoolean("schedule", true).apply();
+ }
+
+ private String getKey() {
Bundle args = getArguments();
boolean start = args.getBoolean("start");
+ boolean weekend = args.getBoolean("weekend");
+ return "schedule" + (start ? "_start" : "_end") + (weekend ? "_weekend" : "");
+ }
+ }
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt("schedule_" + (start ? "start" : "end"), hour * 60 + minute);
- editor.putBoolean("schedule", true);
- editor.apply();
+ public static class FragmentDialogWeekend extends FragmentDialogBase {
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ boolean[] days = new boolean[7];
+
+ final Context context = getContext();
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+
+ String[] daynames = Arrays.copyOfRange(new DateFormatSymbols().getWeekdays(), 1, 8);
+
+ String weekend = prefs.getString("weekend", Calendar.SATURDAY + "," + Calendar.SUNDAY);
+ for (String day : weekend.split(","))
+ days[Integer.parseInt(day) - 1] = true;
+
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.title_advanced_schedule_weekend)
+ .setMultiChoiceItems(daynames, days, new DialogInterface.OnMultiChoiceClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < days.length; i++)
+ if (days[i]) {
+ if (sb.length() > 0)
+ sb.append(",");
+ sb.append(i + 1);
+ }
+ prefs.edit().putString("weekend", sb.toString()).apply();
+ }
+ })
+ .setNegativeButton(R.string.title_setup_done, null)
+ .create();
}
}
diff --git a/app/src/main/java/eu/faircode/email/Log.java b/app/src/main/java/eu/faircode/email/Log.java
index a80bad1459..011c3e2ec9 100644
--- a/app/src/main/java/eu/faircode/email/Log.java
+++ b/app/src/main/java/eu/faircode/email/Log.java
@@ -2396,15 +2396,21 @@ public class Log {
if (schedule) {
int minuteStart = prefs.getInt("schedule_start", 0);
int minuteEnd = prefs.getInt("schedule_end", 0);
+ int minuteStartWeekend = prefs.getInt("schedule_start_weekend", 0);
+ int minuteEndWeekend = prefs.getInt("schedule_end_weekend", 0);
- size += write(os, "schedule " +
- (minuteStart / 60) + ":" + (minuteStart % 60) + "..." +
- (minuteEnd / 60) + ":" + (minuteEnd % 60) + "\r\n");
+ size += write(os, String.format("schedule %s...%s weekend %s...%s\r\n",
+ CalendarHelper.formatHour(context, minuteStart),
+ CalendarHelper.formatHour(context, minuteEnd),
+ CalendarHelper.formatHour(context, minuteStartWeekend),
+ CalendarHelper.formatHour(context, minuteEndWeekend)));
String[] daynames = new DateFormatSymbols().getWeekdays();
for (int i = 0; i < 7; i++) {
boolean day = prefs.getBoolean("schedule_day" + i, true);
- size += write(os, "schedule " + daynames[i + 1] + "=" + day + "\r\n");
+ boolean weekend = CalendarHelper.isWeekend(context, i + 1);
+ size += write(os, String.format("schedule %s=%b %s\r\n",
+ daynames[i + 1], day, weekend ? "weekend" : ""));
}
size += write(os, "\r\n");
diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
index 5d922a9f04..171f273c7d 100644
--- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
+++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
@@ -3293,10 +3293,14 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
if (!ActivityBilling.isPro(context))
return null;
- int minuteStart = prefs.getInt("schedule_start", 0);
- int minuteEnd = prefs.getInt("schedule_end", 0);
-
Calendar calStart = Calendar.getInstance();
+ boolean weekend = CalendarHelper.isWeekend(context, calStart);
+ int defStart = (weekend ? prefs.getInt("schedule_start", 0) : 0);
+ int defEnd = (weekend ? prefs.getInt("schedule_end", 0) : 0);
+
+ int minuteStart = prefs.getInt("schedule_start" + (weekend ? "_weekend" : ""), defStart);
+ int minuteEnd = prefs.getInt("schedule_end" + (weekend ? "_weekend" : ""), defEnd);
+
calStart.set(Calendar.HOUR_OF_DAY, minuteStart / 60);
calStart.set(Calendar.MINUTE, minuteStart % 60);
calStart.set(Calendar.SECOND, 0);
@@ -3320,7 +3324,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
boolean son = prefs.getBoolean("schedule_day" + sdow, true);
boolean eon = prefs.getBoolean("schedule_day" + edow, true);
- if (BuildConfig.DEBUG)
+ if (BuildConfig.DEBUG && false)
Log.i("@@@ eval dow=" + sdow + "/" + edow +
" on=" + son + "/" + eon +
" start=" + new Date(calStart.getTimeInMillis()) +
@@ -3342,6 +3346,12 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
calEnd.set(Calendar.MINUTE, 0);
}
+ if (BuildConfig.DEBUG)
+ Log.i("@@@ eval dow=" + sdow + "/" + edow +
+ " on=" + son + "/" + eon +
+ " start=" + new Date(calStart.getTimeInMillis()) +
+ " end=" + new Date(calEnd.getTimeInMillis()));
+
break;
}
diff --git a/app/src/main/res/layout/fragment_options_synchronize.xml b/app/src/main/res/layout/fragment_options_synchronize.xml
index d25708b2f1..46fa7e5893 100644
--- a/app/src/main/res/layout/fragment_options_synchronize.xml
+++ b/app/src/main/res/layout/fragment_options_synchronize.xml
@@ -247,6 +247,17 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swSchedule" />
+
+
+ app:layout_constraintTop_toBottomOf="@id/tvScheduleWorkDays" />
+
+
+
+
+
+
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@id/tvScheduleStartWeekend" />
@@ -306,6 +374,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Monday"
+ android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbDay0" />
@@ -314,6 +383,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tuesday"
+ android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbDay1" />
@@ -322,6 +392,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wednesday"
+ android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbDay2" />
@@ -330,6 +401,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Thursday"
+ android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbDay3" />
@@ -338,6 +410,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Friday"
+ android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbDay4" />
@@ -346,6 +419,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Saturday"
+ android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbDay5" />
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b4ef3e8a0c..813d5701fe 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -402,6 +402,8 @@
Automatically optimize
Always receive messages for these accounts
Schedule
+ Workdays
+ Weekend
Advanced
Quick sync
Messages without date