diff --git a/app/src/main/java/eu/faircode/email/EntityRule.java b/app/src/main/java/eu/faircode/email/EntityRule.java
index 34859f0757..c97e88c3e6 100644
--- a/app/src/main/java/eu/faircode/email/EntityRule.java
+++ b/app/src/main/java/eu/faircode/email/EntityRule.java
@@ -251,6 +251,15 @@ public class EntityRule {
return false;
}
+ // Date
+ JSONObject jdate = jcondition.optJSONObject("date");
+ if (jdate != null) {
+ long after = jdate.optLong("after", 0);
+ long before = jdate.optLong("before", 0);
+ if ((after != 0 && message.received < after) || (before != 0 && message.received > before))
+ return false;
+ }
+
// Schedule
JSONObject jschedule = jcondition.optJSONObject("schedule");
if (jschedule != null) {
@@ -274,6 +283,7 @@ public class EntityRule {
jsubject == null &&
!jcondition.optBoolean("attachments") &&
jheader == null &&
+ jdate == null &&
jschedule == null)
return false;
} catch (JSONException ex) {
diff --git a/app/src/main/java/eu/faircode/email/FragmentDialogDuration.java b/app/src/main/java/eu/faircode/email/FragmentDialogDuration.java
index 7eb22d3406..8f1e8a911e 100644
--- a/app/src/main/java/eu/faircode/email/FragmentDialogDuration.java
+++ b/app/src/main/java/eu/faircode/email/FragmentDialogDuration.java
@@ -44,7 +44,7 @@ import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;
public class FragmentDialogDuration extends FragmentDialogBase {
- private Calendar cal = Calendar.getInstance();
+ private final Calendar cal = Calendar.getInstance();
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
@@ -55,7 +55,10 @@ public class FragmentDialogDuration extends FragmentDialogBase {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
- String title = getArguments().getString("title");
+ Bundle args = getArguments();
+ String title = args.getString("title");
+ boolean day = args.getBoolean("day");
+ long time = args.getLong("time", 0);
final View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_duration, null);
final TextView tvDuration = dview.findViewById(R.id.tvDuration);
@@ -65,9 +68,16 @@ public class FragmentDialogDuration extends FragmentDialogBase {
final TimePicker timePicker = dview.findViewById(R.id.timePicker);
final DatePicker datePicker = dview.findViewById(R.id.datePicker);
- if (savedInstanceState == null)
- cal.setTimeInMillis((new Date().getTime() / (3600 * 1000L) + 1) * (3600 * 1000L));
- else
+ if (savedInstanceState == null) {
+ if (time == 0) {
+ cal.setTimeInMillis(new Date().getTime());
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ cal.set(Calendar.HOUR_OF_DAY, day ? 0 : cal.get(Calendar.HOUR_OF_DAY) + 1);
+ } else
+ cal.setTimeInMillis(time);
+ } else
cal.setTimeInMillis(savedInstanceState.getLong("fair:time"));
Log.i("Set init=" + new Date(cal.getTimeInMillis()));
@@ -107,6 +117,7 @@ public class FragmentDialogDuration extends FragmentDialogBase {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Bundle args = getArguments();
+ args.putBoolean("reset", true);
args.putLong("duration", 0);
args.putLong("time", new Date().getTime());
diff --git a/app/src/main/java/eu/faircode/email/FragmentRule.java b/app/src/main/java/eu/faircode/email/FragmentRule.java
index 5383999cc3..fad17e14da 100644
--- a/app/src/main/java/eu/faircode/email/FragmentRule.java
+++ b/app/src/main/java/eu/faircode/email/FragmentRule.java
@@ -30,7 +30,6 @@ import android.os.Bundle;
import android.provider.ContactsContract;
import android.speech.tts.TextToSpeech;
import android.text.TextUtils;
-import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -66,6 +65,7 @@ import com.google.android.material.snackbar.Snackbar;
import org.json.JSONException;
import org.json.JSONObject;
+import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -104,6 +104,11 @@ public class FragmentRule extends FragmentBase {
private EditText etHeader;
private CheckBox cbHeader;
+ private TextView tvDateAfter;
+ private TextView tvDateBefore;
+ private Button btnDateAfter;
+ private Button btnDateBefore;
+
private Spinner spScheduleDayStart;
private Spinner spScheduleDayEnd;
private TextView tvScheduleHourStart;
@@ -165,6 +170,8 @@ public class FragmentRule extends FragmentBase {
private int protocol = -1;
private long folder = -1;
+ private DateFormat DF;
+
private final static int MAX_CHECK = 10;
private static final int REQUEST_SENDER = 1;
@@ -176,6 +183,8 @@ public class FragmentRule extends FragmentBase {
private static final int REQUEST_TO = 7;
private final static int REQUEST_TTS_CHECK = 8;
private final static int REQUEST_TTS_DATA = 9;
+ private final static int REQUEST_DATE_AFTER = 10;
+ private final static int REQUEST_DATE_BEFORE = 11;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -190,6 +199,8 @@ public class FragmentRule extends FragmentBase {
account = args.getLong("account", -1);
protocol = args.getInt("protocol", EntityAccount.TYPE_IMAP);
folder = args.getLong("folder", -1);
+
+ DF = Helper.getDateTimeInstance(getContext(), DateFormat.SHORT, DateFormat.SHORT);
}
@Override
@@ -228,6 +239,11 @@ public class FragmentRule extends FragmentBase {
etHeader = view.findViewById(R.id.etHeader);
cbHeader = view.findViewById(R.id.cbHeader);
+ tvDateAfter = view.findViewById(R.id.tvDateAfter);
+ tvDateBefore = view.findViewById(R.id.tvDateBefore);
+ btnDateAfter = view.findViewById(R.id.btnDateAfter);
+ btnDateBefore = view.findViewById(R.id.btnDateBefore);
+
spScheduleDayStart = view.findViewById(R.id.spScheduleDayStart);
spScheduleDayEnd = view.findViewById(R.id.spScheduleDayEnd);
tvScheduleHourStart = view.findViewById(R.id.tvScheduleHourStart);
@@ -309,6 +325,45 @@ public class FragmentRule extends FragmentBase {
}
});
+ tvDateAfter.setText("-");
+ tvDateBefore.setText("-");
+
+ btnDateAfter.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Bundle args = new Bundle();
+ args.putString("title", getString(R.string.title_rule_date_after));
+ args.putBoolean("day", true);
+
+ Object time = tvDateAfter.getTag();
+ if (time != null)
+ args.putLong("time", (long) time);
+
+ FragmentDialogDuration fragment = new FragmentDialogDuration();
+ fragment.setArguments(args);
+ fragment.setTargetFragment(FragmentRule.this, REQUEST_DATE_AFTER);
+ fragment.show(getParentFragmentManager(), "date:after");
+ }
+ });
+
+ btnDateBefore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Bundle args = new Bundle();
+ args.putString("title", getString(R.string.title_rule_date_before));
+ args.putBoolean("day", true);
+
+ Object time = tvDateBefore.getTag();
+ if (time != null)
+ args.putLong("time", (long) time);
+
+ FragmentDialogDuration fragment = new FragmentDialogDuration();
+ fragment.setArguments(args);
+ fragment.setTargetFragment(FragmentRule.this, REQUEST_DATE_BEFORE);
+ fragment.show(getParentFragmentManager(), "date:before");
+ }
+ });
+
adapterDay = new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1, new ArrayList());
adapterDay.setDropDownViewResource(R.layout.spinner_item1_dropdown);
spScheduleDayStart.setAdapter(adapterDay);
@@ -678,6 +733,14 @@ public class FragmentRule extends FragmentBase {
break;
case REQUEST_TTS_DATA:
break;
+ case REQUEST_DATE_AFTER:
+ if (resultCode == RESULT_OK && data != null)
+ onDateAfter(data.getBundleExtra("args"));
+ break;
+ case REQUEST_DATE_BEFORE:
+ if (resultCode == RESULT_OK && data != null)
+ onDateBefore(data.getBundleExtra("args"));
+ break;
}
} catch (Throwable ex) {
Log.e(ex);
@@ -748,6 +811,24 @@ public class FragmentRule extends FragmentBase {
cbScheduleEnd.setChecked(true);
}
+ private void onDateAfter(Bundle args) {
+ boolean reset = args.getBoolean("reset");
+ long time = args.getLong("time");
+ if (reset)
+ time = 0;
+ tvDateAfter.setTag(time);
+ tvDateAfter.setText(time == 0 ? "-" : DF.format(time));
+ }
+
+ private void onDateBefore(Bundle args) {
+ boolean reset = args.getBoolean("reset");
+ long time = args.getLong("time");
+ if (reset)
+ time = 0;
+ tvDateBefore.setTag(time);
+ tvDateBefore.setText(time == 0 ? "-" : DF.format(time));
+ }
+
private void loadRule(final Bundle savedInstanceState) {
Bundle rargs = new Bundle();
rargs.putLong("id", copy < 0 ? id : copy);
@@ -788,6 +869,7 @@ public class FragmentRule extends FragmentBase {
JSONObject jrecipient = jcondition.optJSONObject("recipient");
JSONObject jsubject = jcondition.optJSONObject("subject");
JSONObject jheader = jcondition.optJSONObject("header");
+ JSONObject jdate = jcondition.optJSONObject("date");
JSONObject jschedule = jcondition.optJSONObject("schedule");
etName.setText(rule == null ? args.getString("subject") : rule.name);
@@ -815,6 +897,15 @@ public class FragmentRule extends FragmentBase {
etHeader.setText(jheader == null ? null : jheader.getString("value"));
cbHeader.setChecked(jheader != null && jheader.getBoolean("regex"));
+ long after = (jdate != null && jdate.has("after") ? jdate.getLong("after") : 0);
+ long before = (jdate != null && jdate.has("before") ? jdate.getLong("before") : 0);
+
+ tvDateAfter.setTag(after);
+ tvDateAfter.setText(after == 0 ? "-" : DF.format(after));
+
+ tvDateBefore.setTag(before);
+ tvDateBefore.setText(before == 0 ? "-" : DF.format(before));
+
int start = (jschedule != null && jschedule.has("start") ? jschedule.getInt("start") : 0);
int end = (jschedule != null && jschedule.has("end") ? jschedule.getInt("end") : 0);
@@ -1126,6 +1217,21 @@ public class FragmentRule extends FragmentBase {
jcondition.put("header", jheader);
}
+ Object hafter = tvDateAfter.getTag();
+ Object hbefore = tvDateBefore.getTag();
+
+ long after = (hafter == null ? 0 : (long) hafter);
+ long before = (hbefore == null ? 0 : (long) hbefore);
+
+ if (after != before) {
+ JSONObject jdate = new JSONObject();
+ if (after != 0)
+ jdate.put("after", after);
+ if (before != 0)
+ jdate.put("before", before);
+ jcondition.put("date", jdate);
+ }
+
int dstart = spScheduleDayStart.getSelectedItemPosition();
int dend = spScheduleDayEnd.getSelectedItemPosition();
Object hstart = tvScheduleHourStart.getTag();
@@ -1264,7 +1370,7 @@ public class FragmentRule extends FragmentBase {
return new TimePickerDialog(getContext(), this,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
- DateFormat.is24HourFormat(getContext()));
+ android.text.format.DateFormat.is24HourFormat(getContext()));
}
public void onTimeSet(TimePicker view, int hour, int minute) {
diff --git a/app/src/main/res/layout/fragment_rule.xml b/app/src/main/res/layout/fragment_rule.xml
index 297310f8a8..2d91af94bb 100644
--- a/app/src/main/res/layout/fragment_rule.xml
+++ b/app/src/main/res/layout/fragment_rule.xml
@@ -408,13 +408,95 @@
app:layout_constraintTop_toBottomOf="@+id/etHeader" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Swipe down to close conversation
Swipe up to move conversation
Automatically expand messages
- Automatically expand the first message when the conversation is read
+ Automatically expand the first message when the conversation has been read
Automatically expand all read messages
Expand only one message at a time
Collapse messages in a conversation with multiple messages on \'back\'
@@ -1239,6 +1239,9 @@
Has attachments
Mime type
Header contains
+ Date range
+ Date after
+ Date before
Time between
Regex
AND