mirror of https://github.com/M66B/FairEmail.git
Added time condition to rule
This commit is contained in:
parent
c54a4bfc25
commit
3185166d32
|
@ -110,6 +110,8 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
|
|||
condition.add(context.getString(R.string.title_rule_subject));
|
||||
if (jcondition.has("header"))
|
||||
condition.add(context.getString(R.string.title_rule_header));
|
||||
if (jcondition.has("schedule"))
|
||||
condition.add(context.getString(R.string.title_rule_time));
|
||||
tvCondition.setText(TextUtils.join(" & ", condition));
|
||||
} catch (Throwable ex) {
|
||||
tvCondition.setText(ex.getMessage());
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.json.JSONObject;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
@ -143,6 +144,7 @@ public class EntityRule {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Subject
|
||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||
if (jsubject != null) {
|
||||
String value = jsubject.getString("value");
|
||||
|
@ -152,6 +154,7 @@ public class EntityRule {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Header
|
||||
JSONObject jheader = jcondition.optJSONObject("header");
|
||||
if (jheader != null && imessage != null) {
|
||||
String value = jheader.getString("value");
|
||||
|
@ -171,8 +174,30 @@ public class EntityRule {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Schedule
|
||||
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
||||
if (jschedule != null) {
|
||||
int day = jschedule.optInt("day", -1) + 1;
|
||||
int start = jschedule.optInt("start", 0);
|
||||
int end = jschedule.optInt("end", 0);
|
||||
if (end <= start)
|
||||
end += 24 * 60;
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(new Date(message.received));
|
||||
int mday = cal.get(Calendar.DAY_OF_WEEK);
|
||||
int mhour = cal.get(Calendar.HOUR_OF_DAY);
|
||||
int mminute = cal.get(Calendar.MINUTE);
|
||||
int minutes = mhour * 60 + mminute;
|
||||
|
||||
if (day > 0 && mday != day)
|
||||
return false;
|
||||
if (minutes < start || minutes > end)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Safeguard
|
||||
if (jsender == null && jrecipient == null && jsubject == null && jheader == null)
|
||||
if (jsender == null && jrecipient == null && jsubject == null && jheader == null && jschedule == null)
|
||||
return false;
|
||||
} catch (JSONException ex) {
|
||||
Log.e(ex);
|
||||
|
|
|
@ -20,6 +20,7 @@ package eu.faircode.email;
|
|||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
|
@ -30,6 +31,7 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -45,12 +47,15 @@ import android.widget.NumberPicker;
|
|||
import android.widget.ScrollView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.constraintlayout.widget.Group;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -61,7 +66,10 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -92,6 +100,10 @@ public class FragmentRule extends FragmentBase {
|
|||
private EditText etHeader;
|
||||
private CheckBox cbHeader;
|
||||
|
||||
private Spinner spScheduleDay;
|
||||
private TextView tvScheduleStart;
|
||||
private TextView tvScheduleEnd;
|
||||
|
||||
private Spinner spAction;
|
||||
private TextView tvActionRemark;
|
||||
|
||||
|
@ -123,6 +135,7 @@ public class FragmentRule extends FragmentBase {
|
|||
private Group grpAnswer;
|
||||
private Group grpAutomation;
|
||||
|
||||
private ArrayAdapter<String> adapterDay;
|
||||
private ArrayAdapter<Action> adapterAction;
|
||||
private ArrayAdapter<EntityFolder> adapterTarget;
|
||||
private ArrayAdapter<EntityIdentity> adapterIdentity;
|
||||
|
@ -139,6 +152,8 @@ public class FragmentRule extends FragmentBase {
|
|||
private static final int REQUEST_RECIPIENT = 2;
|
||||
private static final int REQUEST_COLOR = 3;
|
||||
private final static int REQUEST_DELETE = 4;
|
||||
private final static int REQUEST_SCHEDULE_START = 5;
|
||||
private final static int REQUEST_SCHEDULE_END = 6;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -182,12 +197,14 @@ public class FragmentRule extends FragmentBase {
|
|||
etHeader = view.findViewById(R.id.etHeader);
|
||||
cbHeader = view.findViewById(R.id.cbHeader);
|
||||
|
||||
spScheduleDay = view.findViewById(R.id.spScheduleDay);
|
||||
tvScheduleStart = view.findViewById(R.id.tvScheduleStart);
|
||||
tvScheduleEnd = view.findViewById(R.id.tvScheduleEnd);
|
||||
|
||||
spAction = view.findViewById(R.id.spAction);
|
||||
tvActionRemark = view.findViewById(R.id.tvActionRemark);
|
||||
|
||||
npDuration = view.findViewById(R.id.npDuration);
|
||||
npDuration.setMinValue(1);
|
||||
npDuration.setMaxValue(99);
|
||||
|
||||
btnColor = view.findViewById(R.id.btnColor);
|
||||
vwColor = view.findViewById(R.id.vwColor);
|
||||
|
@ -238,6 +255,10 @@ public class FragmentRule extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
adapterDay = new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1, new ArrayList<String>());
|
||||
adapterDay.setDropDownViewResource(R.layout.spinner_item1_dropdown);
|
||||
spScheduleDay.setAdapter(adapterDay);
|
||||
|
||||
adapterAction = new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1, new ArrayList<Action>());
|
||||
adapterAction.setDropDownViewResource(R.layout.spinner_item1_dropdown);
|
||||
spAction.setAdapter(adapterAction);
|
||||
|
@ -254,6 +275,37 @@ public class FragmentRule extends FragmentBase {
|
|||
adapterAnswer.setDropDownViewResource(R.layout.spinner_item1_dropdown);
|
||||
spAnswer.setAdapter(adapterAnswer);
|
||||
|
||||
adapterDay.add(getString(R.string.title_any));
|
||||
String[] dayNames = DateFormatSymbols.getInstance().getWeekdays();
|
||||
for (int day = Calendar.SUNDAY; day <= Calendar.SATURDAY; day++)
|
||||
adapterDay.add(dayNames[day]);
|
||||
|
||||
tvScheduleStart.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Object time = v.getTag();
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("minutes", time == null ? 0 : (int) time);
|
||||
DialogFragment timePicker = new TimePickerFragment();
|
||||
timePicker.setArguments(args);
|
||||
timePicker.setTargetFragment(FragmentRule.this, REQUEST_SCHEDULE_START);
|
||||
timePicker.show(getFragmentManager(), "timePicker");
|
||||
}
|
||||
});
|
||||
|
||||
tvScheduleEnd.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Object time = v.getTag();
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("minutes", time == null ? 0 : (int) time);
|
||||
DialogFragment timePicker = new TimePickerFragment();
|
||||
timePicker.setArguments(args);
|
||||
timePicker.setTargetFragment(FragmentRule.this, REQUEST_SCHEDULE_END);
|
||||
timePicker.show(getFragmentManager(), "timePicker");
|
||||
}
|
||||
});
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new Action(EntityRule.TYPE_SEEN, getString(R.string.title_rule_seen)));
|
||||
actions.add(new Action(EntityRule.TYPE_UNSEEN, getString(R.string.title_rule_unseen)));
|
||||
|
@ -293,6 +345,9 @@ public class FragmentRule extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
npDuration.setMinValue(1);
|
||||
npDuration.setMaxValue(99);
|
||||
|
||||
tvActionRemark.setVisibility(View.GONE);
|
||||
|
||||
onSelectColor(color);
|
||||
|
@ -443,6 +498,14 @@ public class FragmentRule extends FragmentBase {
|
|||
if (resultCode == RESULT_OK)
|
||||
onDelete();
|
||||
break;
|
||||
case REQUEST_SCHEDULE_START:
|
||||
if (resultCode == RESULT_OK)
|
||||
onScheduleStart(data);
|
||||
break;
|
||||
case REQUEST_SCHEDULE_END:
|
||||
if (resultCode == RESULT_OK)
|
||||
onScheduleEnd(data);
|
||||
break;
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
|
@ -511,6 +574,18 @@ public class FragmentRule extends FragmentBase {
|
|||
}.execute(FragmentRule.this, args, "rule:delete");
|
||||
}
|
||||
|
||||
private void onScheduleStart(Intent data) {
|
||||
int minutes = data.getIntExtra("minutes", 0);
|
||||
tvScheduleStart.setTag(minutes);
|
||||
tvScheduleStart.setText(formatHour(getContext(), minutes));
|
||||
}
|
||||
|
||||
private void onScheduleEnd(Intent data) {
|
||||
int minutes = data.getIntExtra("minutes", 0);
|
||||
tvScheduleEnd.setTag(minutes);
|
||||
tvScheduleEnd.setText(formatHour(getContext(), minutes));
|
||||
}
|
||||
|
||||
private void loadRule() {
|
||||
Bundle rargs = new Bundle();
|
||||
rargs.putLong("id", id);
|
||||
|
@ -535,6 +610,7 @@ public class FragmentRule extends FragmentBase {
|
|||
JSONObject jrecipient = jcondition.optJSONObject("recipient");
|
||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||
JSONObject jheader = jcondition.optJSONObject("header");
|
||||
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
||||
|
||||
etName.setText(rule == null ? args.getString("subject") : rule.name);
|
||||
etOrder.setText(rule == null ? null : Integer.toString(rule.order));
|
||||
|
@ -553,6 +629,15 @@ public class FragmentRule extends FragmentBase {
|
|||
etHeader.setText(jheader == null ? null : jheader.getString("value"));
|
||||
cbHeader.setChecked(jheader != null && jheader.getBoolean("regex"));
|
||||
|
||||
if (jschedule != null && jschedule.has("day"))
|
||||
spScheduleDay.setSelection(jschedule.getInt("day") + 1);
|
||||
int start = (jschedule != null && jschedule.has("start") ? jschedule.getInt("start") : 0);
|
||||
tvScheduleStart.setTag(start);
|
||||
tvScheduleStart.setText(formatHour(getContext(), start));
|
||||
int end = (jschedule != null && jschedule.has("end") ? jschedule.getInt("end") : 0);
|
||||
tvScheduleEnd.setTag(end);
|
||||
tvScheduleEnd.setText(formatHour(getContext(), end));
|
||||
|
||||
if (rule == null) {
|
||||
for (int pos = 0; pos < adapterIdentity.getCount(); pos++)
|
||||
if (adapterIdentity.getItem(pos).primary) {
|
||||
|
@ -721,8 +806,9 @@ public class FragmentRule extends FragmentBase {
|
|||
JSONObject jrecipient = jcondition.optJSONObject("recipient");
|
||||
JSONObject jsubject = jcondition.optJSONObject("subject");
|
||||
JSONObject jheader = jcondition.optJSONObject("header");
|
||||
JSONObject jschedule = jcondition.optJSONObject("schedule");
|
||||
|
||||
if (jsender == null && jrecipient == null && jsubject == null && jheader == null)
|
||||
if (jsender == null && jrecipient == null && jsubject == null && jheader == null && jschedule == null)
|
||||
throw new IllegalArgumentException(context.getString(R.string.title_rule_condition_missing));
|
||||
|
||||
if (TextUtils.isEmpty(order))
|
||||
|
@ -807,6 +893,20 @@ public class FragmentRule extends FragmentBase {
|
|||
jcondition.put("header", jheader);
|
||||
}
|
||||
|
||||
Object start = tvScheduleStart.getTag();
|
||||
Object end = tvScheduleEnd.getTag();
|
||||
if (start == null)
|
||||
start = 0;
|
||||
if (end == null)
|
||||
end = 0;
|
||||
if (!start.equals(end)) {
|
||||
JSONObject jschedule = new JSONObject();
|
||||
jschedule.put("day", spScheduleDay.getSelectedItemPosition() - 1);
|
||||
jschedule.put("start", (int) start);
|
||||
jschedule.put("end", (int) end);
|
||||
jcondition.put("schedule", jschedule);
|
||||
}
|
||||
|
||||
return jcondition;
|
||||
}
|
||||
|
||||
|
@ -871,6 +971,44 @@ public class FragmentRule extends FragmentBase {
|
|||
}
|
||||
}
|
||||
|
||||
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 FragmentDialogEx implements TimePickerDialog.OnTimeSetListener {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle args = getArguments();
|
||||
int minutes = args.getInt("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 new TimePickerDialog(getContext(), this,
|
||||
cal.get(Calendar.HOUR_OF_DAY),
|
||||
cal.get(Calendar.MINUTE),
|
||||
DateFormat.is24HourFormat(getContext()));
|
||||
}
|
||||
|
||||
public void onTimeSet(TimePicker view, int hour, int minute) {
|
||||
Fragment target = getTargetFragment();
|
||||
if (target != null) {
|
||||
Intent data = new Intent();
|
||||
data.putExtra("minutes", hour * 60 + minute);
|
||||
target.onActivityResult(getTargetRequestCode(), RESULT_OK, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FragmentDialogCheck extends FragmentDialogEx {
|
||||
@NonNull
|
||||
@Override
|
||||
|
|
|
@ -324,6 +324,79 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbHeader" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAndHeader"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/title_rule_and"
|
||||
android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/etHeader" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorSchedule"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvAndHeader" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSchedule"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/title_rule_time"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorSchedule" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spScheduleDay"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvSchedule" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvScheduleStart"
|
||||
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_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/spScheduleDay" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvScheduleSeparator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="—"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tvScheduleStart"
|
||||
app:layout_constraintStart_toEndOf="@id/tvScheduleStart"
|
||||
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_constraintStart_toEndOf="@id/tvScheduleSeparator"
|
||||
app:layout_constraintTop_toTopOf="@id/tvScheduleStart" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorAction"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -331,7 +404,7 @@
|
|||
android:layout_marginTop="24dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/etHeader" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvScheduleStart" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAction"
|
||||
|
@ -532,7 +605,8 @@
|
|||
vSeparatorSender,tvSender,cbSender,etSender,ivSender,tvAndSender,
|
||||
vSeparatorRecipient,tvRecipient,cbRecipient,etRecipient,ivRecipient,tvAndRecipient,
|
||||
vSeparatorSubject,tvSubject,cbSubject,etSubject,tvAndSubject,
|
||||
vSeparatorHeader,tvHeader,cbHeader,etHeader,
|
||||
vSeparatorHeader,tvHeader,cbHeader,etHeader,tvAndHeader,
|
||||
vSeparatorSchedule,spScheduleDay,tvScheduleStart,tvScheduleSeparator,tvScheduleEnd,
|
||||
vSeparatorAction,tvAction,spAction,tvActionRemark,
|
||||
vSeparatorParameters" />
|
||||
|
||||
|
|
|
@ -614,6 +614,7 @@
|
|||
<string name="title_rule_recipient">Recipient contains</string>
|
||||
<string name="title_rule_subject">Subject contains</string>
|
||||
<string name="title_rule_header">Header contains</string>
|
||||
<string name="title_rule_time">Time between</string>
|
||||
<string name="title_rule_regex">Regex</string>
|
||||
<string name="title_rule_and">AND</string>
|
||||
<string name="title_rule_action">Action</string>
|
||||
|
@ -755,6 +756,7 @@
|
|||
<string name="title_report">Report</string>
|
||||
<string name="title_fix">Fix</string>
|
||||
<string name="title_enable">Enable</string>
|
||||
<string name="title_any">Any</string>
|
||||
<string name="title_executing">Executing</string>
|
||||
<string name="title_completed">Completed</string>
|
||||
<string name="title_ask_what">Ask what to do</string>
|
||||
|
|
Loading…
Reference in New Issue