mirror of https://github.com/M66B/FairEmail.git
parent
b2c869597f
commit
e8027bde38
@ -0,0 +1,164 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class FragmentDialogAddImage extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
int title = getArguments().getInt("title");
|
||||
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
boolean add_inline = prefs.getBoolean("add_inline", true);
|
||||
boolean resize_images = prefs.getBoolean("resize_images", true);
|
||||
int resize = prefs.getInt("resize", FragmentCompose.REDUCED_IMAGE_SIZE);
|
||||
boolean privacy_images = prefs.getBoolean("privacy_images", false);
|
||||
boolean image_dialog = prefs.getBoolean("image_dialog", true);
|
||||
|
||||
final ViewGroup dview = (ViewGroup) LayoutInflater.from(getContext()).inflate(R.layout.dialog_add_image, null);
|
||||
final ImageView ivType = dview.findViewById(R.id.ivType);
|
||||
final RadioGroup rgAction = dview.findViewById(R.id.rgAction);
|
||||
final ImageButton ibSettings = dview.findViewById(R.id.ibSettings);
|
||||
final CheckBox cbResize = dview.findViewById(R.id.cbResize);
|
||||
final ImageButton ibResize = dview.findViewById(R.id.ibResize);
|
||||
final Spinner spResize = dview.findViewById(R.id.spResize);
|
||||
final TextView tvResize = dview.findViewById(R.id.tvResize);
|
||||
final CheckBox cbPrivacy = dview.findViewById(R.id.cbPrivacy);
|
||||
final CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain);
|
||||
final TextView tvNotAgain = dview.findViewById(R.id.tvNotAgain);
|
||||
|
||||
ivType.setImageResource(title == R.string.title_attachment_photo
|
||||
? R.drawable.twotone_photo_camera_24 : R.drawable.twotone_image_24);
|
||||
rgAction.check(add_inline ? R.id.rbInline : R.id.rbAttach);
|
||||
cbResize.setChecked(resize_images);
|
||||
spResize.setEnabled(resize_images);
|
||||
cbPrivacy.setChecked(privacy_images);
|
||||
|
||||
final int[] resizeValues = getResources().getIntArray(R.array.resizeValues);
|
||||
for (int pos = 0; pos < resizeValues.length; pos++)
|
||||
if (resizeValues[pos] == resize) {
|
||||
spResize.setSelection(pos);
|
||||
tvResize.setText(getString(R.string.title_add_resize_pixels, resizeValues[pos]));
|
||||
break;
|
||||
}
|
||||
|
||||
rgAction.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(RadioGroup group, int checkedId) {
|
||||
prefs.edit().putBoolean("add_inline", checkedId == R.id.rbInline).apply();
|
||||
}
|
||||
});
|
||||
|
||||
// https://developer.android.com/reference/android/provider/MediaStore#ACTION_PICK_IMAGES_SETTINGS
|
||||
PackageManager pm = getContext().getPackageManager();
|
||||
Intent settings = new Intent(MediaStore.ACTION_PICK_IMAGES_SETTINGS);
|
||||
ibSettings.setVisibility(settings.resolveActivity(pm) == null ? View.GONE : View.VISIBLE);
|
||||
ibSettings.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
v.getContext().startActivity(settings);
|
||||
}
|
||||
});
|
||||
|
||||
cbResize.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
prefs.edit().putBoolean("resize_images", isChecked).apply();
|
||||
spResize.setEnabled(isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
ibResize.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.viewFAQ(v.getContext(), 63);
|
||||
}
|
||||
});
|
||||
|
||||
spResize.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
prefs.edit().putInt("resize", resizeValues[position]).apply();
|
||||
tvResize.setText(getString(R.string.title_add_resize_pixels, resizeValues[position]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
prefs.edit().remove("resize").apply();
|
||||
}
|
||||
});
|
||||
|
||||
cbPrivacy.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
prefs.edit().putBoolean("privacy_images", isChecked).apply();
|
||||
}
|
||||
});
|
||||
|
||||
cbNotAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
prefs.edit().putBoolean("image_dialog", !isChecked).apply();
|
||||
tvNotAgain.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
cbNotAgain.setChecked(!image_dialog);
|
||||
tvNotAgain.setVisibility(cbNotAgain.isChecked() ? View.VISIBLE : View.GONE);
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setView(dview)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(title,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
sendResult(RESULT_OK);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class FragmentDialogAskSpam extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Bundle args = getArguments();
|
||||
int count = args.getInt("count");
|
||||
|
||||
final Context context = getContext();
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
boolean block_sender = prefs.getBoolean("block_sender", true);
|
||||
String text = getResources().getQuantityString(R.plurals.title_ask_spam, count, count);
|
||||
|
||||
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_ask_spam, null);
|
||||
TextView tvMessage = dview.findViewById(R.id.tvMessage);
|
||||
CheckBox cbBlockSender = dview.findViewById(R.id.cbBlockSender);
|
||||
|
||||
tvMessage.setText(text);
|
||||
cbBlockSender.setChecked(block_sender);
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
boolean block = cbBlockSender.isChecked();
|
||||
prefs.edit().putBoolean("block_sender", block).apply();
|
||||
getArguments().putBoolean("block", block);
|
||||
sendResult(Activity.RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class FragmentDialogBoundaryError extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
String error = getArguments().getString("error");
|
||||
|
||||
final Context context = getContext();
|
||||
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_boundary_error, null);
|
||||
TextView tvError = dview.findViewById(R.id.tvError);
|
||||
|
||||
tvError.setText(error);
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(R.string.title_boundary_retry, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
sendResult(Activity.RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
sendResult(Activity.RESULT_CANCELED);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class FragmentDialogContactDelete extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setIcon(R.drawable.twotone_warning_24)
|
||||
.setTitle(getString(R.string.title_delete_contacts))
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
Long account = args.getLong("account");
|
||||
boolean junk = args.getBoolean("junk");
|
||||
|
||||
if (account < 0)
|
||||
account = null;
|
||||
int[] types = (junk
|
||||
? new int[]{EntityContact.TYPE_JUNK, EntityContact.TYPE_NO_JUNK}
|
||||
: new int[]{EntityContact.TYPE_FROM, EntityContact.TYPE_TO});
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
int count = db.contact().clearContacts(account, types);
|
||||
Log.i("Cleared contacts=" + count);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(getContext(), getActivity(), getArguments(), "contacts:delete");
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class FragmentDialogContactEdit extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
final Context context = getContext();
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.dialog_edit_contact, null);
|
||||
final Spinner spType = view.findViewById(R.id.spType);
|
||||
final EditText etEmail = view.findViewById(R.id.etEmail);
|
||||
final EditText etName = view.findViewById(R.id.etName);
|
||||
final EditText etGroup = view.findViewById(R.id.etGroup);
|
||||
|
||||
final Bundle args = getArguments();
|
||||
int type = args.getInt("type");
|
||||
|
||||
boolean junk = (type == EntityContact.TYPE_JUNK || type == EntityContact.TYPE_NO_JUNK);
|
||||
String[] values = getResources().getStringArray(R.array.contactTypes);
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, R.layout.spinner_item1, android.R.id.text1, values) {
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
if (junk)
|
||||
return (position == EntityContact.TYPE_JUNK || position == EntityContact.TYPE_NO_JUNK);
|
||||
else
|
||||
return (position == EntityContact.TYPE_TO || position == EntityContact.TYPE_FROM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
View view = super.getDropDownView(position, convertView, parent);
|
||||
TextView tv = view.findViewById(android.R.id.text1);
|
||||
tv.setEnabled(isEnabled(position));
|
||||
return view;
|
||||
}
|
||||
};
|
||||
adapter.setDropDownViewResource(R.layout.spinner_item1_dropdown);
|
||||
spType.setAdapter(adapter);
|
||||
|
||||
spType.setSelection(args.getInt("type"));
|
||||
etEmail.setText(args.getString("email"));
|
||||
etName.setText(args.getString("name"));
|
||||
etGroup.setText(args.getString("group"));
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
args.putInt("type", spType.getSelectedItemPosition());
|
||||
args.putString("email", etEmail.getText().toString().trim());
|
||||
args.putString("name", etName.getText().toString());
|
||||
args.putString("group", etGroup.getText().toString().trim());
|
||||
sendResult(RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import static android.app.Activity.RESULT_CANCELED;
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.widget.AdapterView.INVALID_POSITION;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.database.MergeCursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.cursoradapter.widget.SimpleCursorAdapter;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public class FragmentDialogContactGroup extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
final Bundle args = getArguments();
|
||||
final long working = args.getLong("working");
|
||||
int focussed = args.getInt("focussed");
|
||||
|
||||
final Context context = getContext();
|
||||
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_contact_group, null);
|
||||
final ImageButton ibInfo = dview.findViewById(R.id.ibInfo);
|
||||
final Spinner spGroup = dview.findViewById(R.id.spGroup);
|
||||
final Spinner spTarget = dview.findViewById(R.id.spTarget);
|
||||
final Spinner spType = dview.findViewById(R.id.spType);
|
||||
|
||||
ibInfo.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.view(v.getContext(), Uri.parse(Helper.URI_SUPPORT_CONTACT_GROUP), true);
|
||||
}
|
||||
});
|
||||
|
||||
new SimpleTask<Cursor>() {
|
||||
@Override
|
||||
protected Cursor onExecute(Context context, Bundle args) {
|
||||
final String[] projection = new String[]{
|
||||
ContactsContract.Groups._ID,
|
||||
ContactsContract.Groups.TITLE,
|
||||
ContactsContract.Groups.SUMMARY_COUNT,
|
||||
ContactsContract.Groups.ACCOUNT_NAME,
|
||||
ContactsContract.Groups.ACCOUNT_TYPE,
|
||||
};
|
||||
|
||||
Cursor contacts = new MatrixCursor(projection);
|
||||
if (Helper.hasPermission(context, Manifest.permission.READ_CONTACTS))
|
||||
try {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
contacts = resolver.query(
|
||||
ContactsContract.Groups.CONTENT_SUMMARY_URI,
|
||||
projection,
|
||||
// ContactsContract.Groups.GROUP_VISIBLE + " = 1" + " AND " +
|
||||
ContactsContract.Groups.DELETED + " = 0" +
|
||||
" AND " + ContactsContract.Groups.SUMMARY_COUNT + " > 0",
|
||||
null,
|
||||
ContactsContract.Groups.TITLE
|
||||
);
|
||||
} catch (SecurityException ex) {
|
||||
Log.w(ex);
|
||||
}
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
Cursor local = db.contact().getGroups(
|
||||
null,
|
||||
context.getString(R.string.app_name),
|
||||
BuildConfig.APPLICATION_ID);
|
||||
|
||||
return new MergeCursor(new Cursor[]{contacts, local});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Cursor cursor) {
|
||||
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
|
||||
context,
|
||||
R.layout.spinner_contact_group,
|
||||
cursor,
|
||||
new String[]{ContactsContract.Groups.TITLE, ContactsContract.Groups.ACCOUNT_NAME},
|
||||
new int[]{R.id.tvGroup, R.id.tvAccount},
|
||||
0);
|
||||
|
||||
final NumberFormat NF = NumberFormat.getInstance();
|
||||
|
||||
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
|
||||
@Override
|
||||
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
|
||||
if (view.getId() == R.id.tvGroup) {
|
||||
String title = cursor.getString(1);
|
||||
if (TextUtils.isEmpty(title))
|
||||
title = "-";
|
||||
int count = cursor.getInt(2);
|
||||
((TextView) view).setText(context.getString(R.string.title_name_count, title, NF.format(count)));
|
||||
return true;
|
||||
} else if (view.getId() == R.id.tvAccount) {
|
||||
String account = cursor.getString(3);
|
||||
String type = cursor.getString(4);
|
||||
((TextView) view).setText(account + (BuildConfig.DEBUG ? "/" + type : ""));
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
spGroup.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(this, new Bundle(), "compose:groups");
|
||||
|
||||
spTarget.setSelection(focussed);
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
try {
|
||||
int target = spTarget.getSelectedItemPosition();
|
||||
Cursor cursor = (Cursor) spGroup.getSelectedItem();
|
||||
if (target != INVALID_POSITION &&
|
||||
cursor != null && cursor.getCount() > 0) {
|
||||
long group = cursor.getLong(0);
|
||||
String name = cursor.getString(1);
|
||||
|
||||
Bundle args = getArguments();
|
||||
args.putLong("id", working);
|
||||
args.putInt("target", target);
|
||||
args.putLong("group", group);
|
||||
args.putString("name", name);
|
||||
args.putInt("type", spType.getSelectedItemPosition());
|
||||
|
||||
sendResult(RESULT_OK);
|
||||
} else
|
||||
sendResult(RESULT_CANCELED);
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class FragmentDialogDoze extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setIcon(R.drawable.twotone_info_24)
|
||||
.setTitle(R.string.title_setup_doze)
|
||||
.setMessage(R.string.title_setup_doze_instructions)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
try {
|
||||
startActivity(new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS));
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
public class FragmentDialogExport extends FragmentDialogBase {
|
||||
private TextInputLayout tilPassword1;
|
||||
private TextInputLayout tilPassword2;
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
outState.putString("fair:password1", tilPassword1 == null ? null : tilPassword1.getEditText().getText().toString());
|
||||
outState.putString("fair:password2", tilPassword2 == null ? null : tilPassword2.getEditText().getText().toString());
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Context context = getContext();
|
||||
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_export, null);
|
||||
tilPassword1 = dview.findViewById(R.id.tilPassword1);
|
||||
tilPassword2 = dview.findViewById(R.id.tilPassword2);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
tilPassword1.getEditText().setText(savedInstanceState.getString("fair:password1"));
|
||||
tilPassword2.getEditText().setText(savedInstanceState.getString("fair:password2"));
|
||||
}
|
||||
|
||||
Dialog dialog = new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(R.string.title_save_file, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
ViewModelExport vme = new ViewModelProvider(getActivity()).get(ViewModelExport.class);
|
||||
vme.setPassword(tilPassword1.getEditText().getText().toString());
|
||||
sendResult(RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
boolean debug = (BuildConfig.DEBUG || prefs.getBoolean("debug", false));
|
||||
|
||||
Button btnOk = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
|
||||
TextWatcher w = new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
String p1 = tilPassword1.getEditText().getText().toString();
|
||||
String p2 = tilPassword2.getEditText().getText().toString();
|
||||
btnOk.setEnabled((debug || !TextUtils.isEmpty(p1)) && p1.equals(p2));
|
||||
tilPassword2.setHint(!TextUtils.isEmpty(p2) && !p2.equals(p1)
|
||||
? R.string.title_setup_password_different
|
||||
: R.string.title_setup_password_repeat);
|
||||
}
|
||||
};
|
||||
|
||||
tilPassword1.getEditText().addTextChangedListener(w);
|
||||
tilPassword2.getEditText().addTextChangedListener(w);
|
||||
w.afterTextChanged(null);
|
||||
|
||||
tilPassword2.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
btnOk.performClick();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class FragmentDialogFirst extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
View dview = inflater.inflate(R.layout.dialog_first, null);
|
||||
ImageButton ibBatteryInfo = dview.findViewById(R.id.ibBatteryInfo);
|
||||
ImageButton ibReformatInfo = dview.findViewById(R.id.ibReformatInfo);
|
||||
|
||||
ibBatteryInfo.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.viewFAQ(v.getContext(), 39);
|
||||
}
|
||||
});
|
||||
|
||||
ibReformatInfo.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.viewFAQ(v.getContext(), 35);
|
||||
}
|
||||
});
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
prefs.edit().putBoolean("first", false).apply();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,149 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FragmentDialogFoldersApply extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_folder_all, null);
|
||||
final RadioGroup rgSynchronize = view.findViewById(R.id.rgSynchronize);
|
||||
final EditText etSyncDays = view.findViewById(R.id.etSyncDays);
|
||||
final EditText etKeepDays = view.findViewById(R.id.etKeepDays);
|
||||
final CheckBox cbKeepAll = view.findViewById(R.id.cbKeepAll);
|
||||
final CheckBox cbPollSystem = view.findViewById(R.id.cbPollSystem);
|
||||
final CheckBox cbPollUser = view.findViewById(R.id.cbPollUser);
|
||||
|
||||
cbKeepAll.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
etKeepDays.setEnabled(!isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Bundle args = getArguments();
|
||||
int optionId = rgSynchronize.getCheckedRadioButtonId();
|
||||
if (optionId == R.id.rbEnable)
|
||||
args.putBoolean("enable", true);
|
||||
else if (optionId == R.id.rbDisable)
|
||||
args.putBoolean("enable", false);
|
||||
args.putString("sync", etSyncDays.getText().toString());
|
||||
args.putString("keep", cbKeepAll.isChecked()
|
||||
? Integer.toString(Integer.MAX_VALUE)
|
||||
: etKeepDays.getText().toString());
|
||||
args.putBoolean("system", cbPollSystem.isChecked());
|
||||
args.putBoolean("user", cbPollUser.isChecked());
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) throws Throwable {
|
||||
long aid = args.getLong("account");
|
||||
Boolean enable = null;
|
||||
if (args.containsKey("enable"))
|
||||
enable = args.getBoolean("enable");
|
||||
String sync = args.getString("sync");
|
||||
String keep = args.getString("keep");
|
||||
boolean system = args.getBoolean("system");
|
||||
boolean user = args.getBoolean("user");
|
||||
|
||||
if (TextUtils.isEmpty(sync))
|
||||
sync = "7";
|
||||
if (TextUtils.isEmpty(keep))
|
||||
keep = "30";
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
EntityAccount account = db.account().getAccount(aid);
|
||||
if (account == null)
|
||||
return null;
|
||||
|
||||
if (system && account.poll_interval > 15)
|
||||
db.account().setAccountKeepAliveInterval(account.id, 15);
|
||||
|
||||
List<EntityFolder> folders = db.folder().getFolders(aid, false, true);
|
||||
if (folders == null)
|
||||
return null;
|
||||
|
||||
for (EntityFolder folder : folders) {
|
||||
if (EntityFolder.USER.equals(folder.type)) {
|
||||
if (enable != null) {
|
||||
folder.synchronize = enable;
|
||||
db.folder().setFolderSynchronize(folder.id, folder.synchronize);
|
||||
}
|
||||
|
||||
db.folder().setFolderProperties(
|
||||
folder.id,
|
||||
Integer.parseInt(sync),
|
||||
Integer.parseInt(keep));
|
||||
}
|
||||
|
||||
if (folder.synchronize && !folder.poll)
|
||||
if (EntityFolder.USER.equals(folder.type)
|
||||
? user
|
||||
: system && !EntityFolder.INBOX.equals(folder.type))
|
||||
db.folder().setFolderPoll(folder.id, true);
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
ServiceSynchronize.reload(context, aid, false, "Apply");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(FragmentDialogFoldersApply.this, args, "folders:all");
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import static android.app.Activity.RESULT_CANCELED;
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
public class FragmentDialogImport extends FragmentDialogBase {
|
||||
private TextInputLayout tilPassword1;
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
outState.putString("fair:password1", tilPassword1 == null ? null : tilPassword1.getEditText().getText().toString());
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Context context = getContext();
|
||||
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_import, null);
|
||||
tilPassword1 = dview.findViewById(R.id.tilPassword1);
|
||||
CheckBox cbAccounts = dview.findViewById(R.id.cbAccounts);
|
||||
CheckBox cbDelete = dview.findViewById(R.id.cbDelete);
|
||||
CheckBox cbRules = dview.findViewById(R.id.cbRules);
|
||||
CheckBox cbContacts = dview.findViewById(R.id.cbContacts);
|
||||
CheckBox cbAnswers = dview.findViewById(R.id.cbAnswers);
|
||||
CheckBox cbSearches = dview.findViewById(R.id.cbSearches);
|
||||
CheckBox cbSettings = dview.findViewById(R.id.cbSettings);
|
||||
|
||||
cbAccounts.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
cbRules.setEnabled(checked);
|
||||
cbContacts.setEnabled(checked);
|
||||
}
|
||||
});
|
||||
|
||||
if (savedInstanceState != null)
|
||||
tilPassword1.getEditText().setText(savedInstanceState.getString("fair:password1"));
|
||||
|
||||
Dialog dialog = new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(R.string.title_add_image_select, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String password1 = tilPassword1.getEditText().getText().toString();
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean debug = prefs.getBoolean("debug", false);
|
||||
|
||||
if (TextUtils.isEmpty(password1) && !(debug || BuildConfig.DEBUG)) {
|
||||
ToastEx.makeText(context, R.string.title_setup_password_missing, Toast.LENGTH_LONG).show();
|
||||
sendResult(RESULT_CANCELED);
|
||||
} else {
|
||||
ViewModelExport vme = new ViewModelProvider(getActivity()).get(ViewModelExport.class);
|
||||
vme.setPassword(password1);
|
||||
vme.setOptions("accounts", cbAccounts.isChecked());
|
||||
vme.setOptions("delete", cbDelete.isChecked());
|
||||
vme.setOptions("rules", cbRules.isChecked());
|
||||
vme.setOptions("contacts", cbContacts.isChecked());
|
||||
vme.setOptions("answers", cbAnswers.isChecked());
|
||||
vme.setOptions("searches", cbSearches.isChecked());
|
||||
vme.setOptions("settings", cbSettings.isChecked());
|
||||
sendResult(RESULT_OK);
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
Button btnOk = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
|
||||
tilPassword1.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
btnOk.performClick();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FragmentDialogOperationsDelete extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
final Context context = getContext();
|
||||
final View dview = LayoutInflater.from(context).inflate(R.layout.dialog_delete_operations, null);
|
||||
final CheckBox cbError = dview.findViewById(R.id.cbError);
|
||||
final CheckBox cbFetch = dview.findViewById(R.id.cbFetch);
|
||||
final CheckBox cbMove = dview.findViewById(R.id.cbMove);
|
||||
final CheckBox cbFlag = dview.findViewById(R.id.cbFlag);
|
||||
final CheckBox cbDelete = dview.findViewById(R.id.cbDelete);
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("error", cbError.isChecked());
|
||||
args.putBoolean("fetch", cbFetch.isChecked());
|
||||
args.putBoolean("move", cbMove.isChecked());
|
||||
args.putBoolean("flag", cbFlag.isChecked());
|
||||
args.putBoolean("delete", cbDelete.isChecked());
|
||||
|
||||
new SimpleTask<Integer>() {
|
||||
private Toast toast = null;
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bundle args) {
|
||||
toast = ToastEx.makeText(context, R.string.title_executing, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute(Bundle args) {
|
||||
if (toast != null)
|
||||
toast.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer onExecute(Context context, Bundle args) {
|
||||
boolean error = args.getBoolean("error");
|
||||
boolean fetch = args.getBoolean("fetch");
|
||||
boolean move = args.getBoolean("move");
|
||||
boolean flag = args.getBoolean("flag");
|
||||
boolean delete = args.getBoolean("delete");
|
||||
|
||||
int deleted = 0;
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
List<EntityOperation> ops = new ArrayList<>();
|
||||
|
||||
// ADD, SEND, EXISTS, SUBSCRIBE
|
||||
|
||||
if (error)
|
||||
addAll(ops, db.operation().getOperationsError());
|
||||
|
||||
if (fetch) {
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.FETCH));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.DOWNLOAD));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.RAW));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.BODY));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.ATTACHMENT));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.HEADERS));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.RULE));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.SYNC));
|
||||
}
|
||||
|
||||
if (move) {
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.MOVE));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.COPY));
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.SEEN));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.ANSWERED));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.FLAG));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.KEYWORD));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.LABEL));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.REPORT));
|
||||
}
|
||||
|
||||
if (delete) {
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.DELETE));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.PURGE));
|
||||
addAll(ops, db.operation().getOperations(EntityOperation.EXPUNGE));
|
||||
}
|
||||
|
||||
for (EntityOperation op : ops) {
|
||||
EntityLog.log(context, "Deleting operation=" + op.id + ":" + op.name + " error=" + op.error);
|
||||
|
||||
if (db.operation().deleteOperation(op.id) > 0) {
|
||||
op.cleanup(context, false);
|
||||
deleted++;
|
||||
}
|
||||
|
||||
if (EntityOperation.SYNC.equals(op.name))
|
||||
db.folder().setFolderSyncState(op.folder, null);
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Integer deleted) {
|
||||
if (deleted == null)
|
||||
deleted = -1;
|
||||
Context context = getContext();
|
||||
if (context == null)
|
||||
return;
|
||||
ToastEx.makeText(
|
||||
context,
|
||||
getString(R.string.title_delete_operation_deleted, deleted),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
|
||||
private void addAll(List<EntityOperation> list, List<EntityOperation> sublist) {
|
||||
if (sublist != null)
|
||||
list.addAll(sublist);
|
||||
}
|
||||
}.execute(context, getActivity(), args, "operations:delete");
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class FragmentDialogPin extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
final View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_pin_set, null);
|
||||
final EditText etPin = dview.findViewById(R.id.etPin);
|
||||
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String pin = etPin.getText().toString();
|
||||
if (TextUtils.isEmpty(pin))
|
||||
prefs.edit().remove("pin").apply();
|
||||
else {
|
||||
boolean pro = ActivityBilling.isPro(getContext());
|
||||
if (pro) {
|
||||
Helper.setAuthenticated(getContext());
|
||||
prefs.edit()
|
||||
.remove("biometrics")
|
||||
.putString("pin", pin)
|
||||
.apply();
|
||||
} else
|
||||
startActivity(new Intent(getContext(), ActivityBilling.class));
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
String pin = prefs.getString("pin", null);
|
||||
if (!TextUtils.isEmpty(pin))
|
||||
builder.setNeutralButton(R.string.title_reset, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
prefs.edit().remove("pin").apply();
|
||||
}
|
||||
});
|
||||
|
||||
final Dialog dialog = builder.create();
|
||||
|
||||
etPin.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
((AlertDialog) getDialog()).getButton(DialogInterface.BUTTON_POSITIVE).performClick();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
etPin.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (hasFocus)
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
ApplicationEx.getMainHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
|
||||
return;
|
||||
etPin.requestFocus();
|
||||
}
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class FragmentDialogQuickActions extends FragmentDialogBase {
|
||||
static final int MAX_QUICK_ACTIONS = 5;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
final Context context = getContext();
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
final View dview = LayoutInflater.from(context).inflate(R.layout.dialog_quick_actions, null);
|
||||
final TextView tvHint = dview.findViewById(R.id.tvHint);
|
||||
final CheckBox cbSeen = dview.findViewById(R.id.cbSeen);
|
||||
final CheckBox cbUnseen = dview.findViewById(R.id.cbUnseen);
|
||||
final CheckBox cbSnooze = dview.findViewById(R.id.cbSnooze);
|
||||
final CheckBox cbHide = dview.findViewById(R.id.cbHide);
|
||||
final CheckBox cbFlag = dview.findViewById(R.id.cbFlag);
|
||||
final CheckBox cbFlagColor = dview.findViewById(R.id.cbFlagColor);
|
||||
final CheckBox cbImportanceLow = dview.findViewById(R.id.cbImportanceLow);
|
||||
final CheckBox cbImportanceNormal = dview.findViewById(R.id.cbImportanceNormal);
|
||||
final CheckBox cbImportanceHigh = dview.findViewById(R.id.cbImportanceHigh);
|
||||
final CheckBox cbInbox = dview.findViewById(R.id.cbInbox);
|
||||
final CheckBox cbArchive = dview.findViewById(R.id.cbArchive);
|
||||
final CheckBox cbJunk = dview.findViewById(R.id.cbJunk);
|
||||
final CheckBox cbTrash = dview.findViewById(R.id.cbTrash);
|
||||
final CheckBox cbDelete = dview.findViewById(R.id.cbDelete);
|
||||
final CheckBox cbMove = dview.findViewById(R.id.cbMove);
|
||||
final CheckBox cbClear = dview.findViewById(R.id.cbClear);
|
||||
|
||||
tvHint.setText(getString(R.string.title_quick_actions_hint, MAX_QUICK_ACTIONS));
|
||||
cbSeen.setChecked(prefs.getBoolean("more_seen", true));
|
||||
cbUnseen.setChecked(prefs.getBoolean("more_unseen", false));
|
||||
cbSnooze.setChecked(prefs.getBoolean("more_snooze", false));
|
||||
cbHide.setChecked(prefs.getBoolean("more_hide", false));
|
||||
cbFlag.setChecked(prefs.getBoolean("more_flag", false));
|
||||
cbFlagColor.setChecked(prefs.getBoolean("more_flag_color", false));
|
||||
cbImportanceLow.setChecked(prefs.getBoolean("more_importance_low", false));
|
||||
cbImportanceNormal.setChecked(prefs.getBoolean("more_importance_normal", false));
|
||||
cbImportanceHigh.setChecked(prefs.getBoolean("more_importance_high", false));
|
||||
cbInbox.setChecked(prefs.getBoolean("more_inbox", true));
|
||||
cbArchive.setChecked(prefs.getBoolean("more_archive", true));
|
||||
cbJunk.setChecked(prefs.getBoolean("more_junk", true));
|
||||
cbTrash.setChecked(prefs.getBoolean("more_trash", true));
|
||||
cbDelete.setChecked(prefs.getBoolean("more_delete", false));
|
||||
cbMove.setChecked(prefs.getBoolean("more_move", true));
|
||||
cbClear.setChecked(prefs.getBoolean("more_clear", true));
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean("more_seen", cbSeen.isChecked());
|
||||
editor.putBoolean("more_unseen", cbUnseen.isChecked());
|
||||
editor.putBoolean("more_snooze", cbSnooze.isChecked());
|
||||
editor.putBoolean("more_hide", cbHide.isChecked());
|
||||
editor.putBoolean("more_flag", cbFlag.isChecked());
|
||||
editor.putBoolean("more_flag_color", cbFlagColor.isChecked());
|
||||
editor.putBoolean("more_importance_low", cbImportanceLow.isChecked());
|
||||
editor.putBoolean("more_importance_normal", cbImportanceNormal.isChecked());
|
||||
editor.putBoolean("more_importance_high", cbImportanceHigh.isChecked());
|
||||
editor.putBoolean("more_inbox", cbInbox.isChecked());
|
||||
editor.putBoolean("more_archive", cbArchive.isChecked());
|
||||
editor.putBoolean("more_junk", cbJunk.isChecked());
|
||||
editor.putBoolean("more_trash", cbTrash.isChecked());
|
||||
editor.putBoolean("more_delete", cbDelete.isChecked());
|
||||
editor.putBoolean("more_move", cbMove.isChecked());
|
||||
editor.putBoolean("more_clear", cbClear.isChecked());
|
||||
editor.apply();
|
||||
sendResult(Activity.RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
sendResult(Activity.RESULT_CANCELED);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class FragmentDialogRate extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setMessage(R.string.title_issue)
|
||||
.setPositiveButton(R.string.title_yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Helper.viewFAQ(getContext(), 0);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.title_no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Helper.view(getContext(), Helper.getIntentRate(getContext()));
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class FragmentDialogReporting extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_error_reporting, null);
|
||||
Button btnInfo = dview.findViewById(R.id.btnInfo);
|
||||
|
||||
btnInfo.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.viewFAQ(v.getContext(), 104);
|
||||
}
|
||||
});
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
prefs.edit().putBoolean("crash_reports", true).apply();
|
||||
Log.setCrashReporting(true);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
prefs.edit().putBoolean("crash_reports_asked", true).apply();
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class FragmentDialogReview extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_review, null);
|
||||
TextView tvHelp = dview.findViewById(R.id.tvHelp);
|
||||
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
Dialog dialog = new AlertDialog.Builder(getContext())
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
prefs.edit().putBoolean("review_asked", true).apply();
|
||||
startActivity(Helper.getIntentRate(getContext()));
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
prefs.edit().putBoolean("review_asked", true).apply();
|
||||
}
|
||||
})
|
||||
.setNeutralButton(R.string.title_later, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
prefs.edit().putLong("review_later", new Date().getTime()).apply();
|
||||
}
|
||||
})
|
||||
.create();
|
||||
|
||||
tvHelp.setPaintFlags(tvHelp.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
tvHelp.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dismiss();
|
||||
prefs.edit().putLong("review_later", new Date().getTime()).apply();
|
||||
startActivity(Helper.getIntentIssue(v.getContext(), "Review:issue"));
|
||||
}
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(@NonNull DialogInterface dialog) {
|
||||
super.onCancel(dialog);
|
||||
try {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
prefs.edit().putBoolean("review_asked", true).apply();
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FragmentDialogRuleCheck extends FragmentDialogBase {
|
||||
private final static int MAX_CHECK = 10;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
long folder = getArguments().getLong("folder");
|
||||
boolean daily = getArguments().getBoolean("daily");
|
||||
String condition = getArguments().getString("condition");
|
||||
String action = getArguments().getString("action");
|
||||
|
||||
final View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_rule_match, null);
|
||||
final TextView tvNoMessages = dview.findViewById(R.id.tvNoMessages);
|
||||
final RecyclerView rvMessage = dview.findViewById(R.id.rvMessage);
|
||||
final Button btnExecute = dview.findViewById(R.id.btnExecute);
|
||||
final ContentLoadingProgressBar pbWait = dview.findViewById(R.id.pbWait);
|
||||
|
||||
rvMessage.setHasFixedSize(false);
|
||||
LinearLayoutManager llm = new LinearLayoutManager(getContext());
|
||||
rvMessage.setLayoutManager(llm);
|
||||
|
||||
final AdapterRuleMatch adapter = new AdapterRuleMatch(getContext(), getViewLifecycleOwner());
|
||||
rvMessage.setAdapter(adapter);
|
||||
|
||||
tvNoMessages.setVisibility(View.GONE);
|
||||
rvMessage.setVisibility(View.GONE);
|
||||
btnExecute.setVisibility(View.GONE);
|
||||
|
||||
final Bundle args = new Bundle();
|
||||
args.putLong("folder", folder);
|
||||
args.putBoolean("daily", daily);
|
||||
args.putString("condition", condition);
|
||||
args.putString("action", action);
|
||||
|
||||
btnExecute.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
new SimpleTask<Integer>() {
|
||||
private Toast toast = null;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute(Bundle args) {
|
||||
toast = ToastEx.makeText(getContext(), R.string.title_executing, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bundle args) {
|
||||
if (toast != null)
|
||||
toast.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer onExecute(Context context, Bundle args) throws Throwable {
|
||||
EntityRule rule = new EntityRule();
|
||||
rule.folder = args.getLong("folder");
|
||||
rule.daily = args.getBoolean("daily");
|
||||
rule.condition = args.getString("condition");
|
||||
rule.action = args.getString("action");
|
||||
|
||||
int applied = 0;
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
List<Long> ids =
|
||||
db.message().getMessageIdsByFolder(rule.folder);
|
||||
for (long mid : ids)
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
EntityMessage message = db.message().getMessage(mid);
|
||||
if (message == null || message.ui_hide)
|
||||
continue;
|
||||
|
||||
if (rule.matches(context, message, null, null))
|
||||
if (rule.execute(context, message))
|
||||
applied++;
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
if (applied > 0)
|
||||
ServiceSynchronize.eval(context, "rules/manual");
|
||||
|
||||
return applied;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Integer applied) {
|
||||
dismiss();
|
||||
ToastEx.makeText(getContext(), getString(R.string.title_rule_applied, applied), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
if (ex instanceof IllegalArgumentException)
|
||||
ToastEx.makeText(getContext(), ex.getMessage(), Toast.LENGTH_LONG).show();
|
||||
else
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(FragmentDialogRuleCheck.this, args, "rule:execute");
|
||||
}
|
||||
});
|
||||
|
||||
new SimpleTask<List<EntityMessage>>() {
|
||||
@Override
|
||||
protected void onPreExecute(Bundle args) {
|
||||
pbWait.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bundle args) {
|
||||
pbWait.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<EntityMessage> onExecute(Context context, Bundle args) throws Throwable {
|
||||
EntityRule rule = new EntityRule();
|
||||
rule.folder = args.getLong("folder");
|
||||
rule.daily = args.getBoolean("daily");
|
||||
rule.condition = args.getString("condition");
|
||||
rule.action = args.getString("action");
|
||||
rule.validate(context);
|
||||
|
||||
List<EntityMessage> matching = new ArrayList<>();
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
List<Long> ids =
|
||||
db.message().getMessageIdsByFolder(rule.folder);
|
||||
for (long id : ids) {
|
||||
EntityMessage message = db.message().getMessage(id);
|
||||
if (message == null)
|
||||
continue;
|
||||
|
||||
if (rule.matches(context, message, null, null))
|
||||
matching.add(message);
|
||||
|
||||
if (matching.size() >= MAX_CHECK)
|
||||
break;
|
||||
}
|
||||
|
||||
return matching;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, List<EntityMessage> messages) {
|
||||
adapter.set(messages);
|
||||
|
||||
if (messages.size() > 0) {
|
||||
rvMessage.setVisibility(View.VISIBLE);
|
||||
btnExecute.setVisibility(View.VISIBLE);
|
||||
} else
|
||||
tvNoMessages.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
if (ex instanceof IllegalArgumentException) {
|
||||
tvNoMessages.setText(ex.getMessage());
|
||||
tvNoMessages.setVisibility(View.VISIBLE);
|
||||
} else
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(this, args, "rule:check");
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setIcon(R.drawable.baseline_mail_outline_24)
|
||||
.setTitle(R.string.title_rule_matched)
|
||||
.setView(dview)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class FragmentDialogSaveSearch extends FragmentDialogBase {
|
||||
private ViewButtonColor btnColor;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
final Bundle args = getArguments();
|
||||
|
||||
BoundaryCallbackMessages.SearchCriteria criteria =
|
||||
(BoundaryCallbackMessages.SearchCriteria) args.getSerializable("criteria");
|
||||
if (criteria == null)
|
||||
criteria = new BoundaryCallbackMessages.SearchCriteria();
|
||||
|
||||
final Context context = getContext();
|
||||
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_save_search, null);
|
||||
EditText etName = dview.findViewById(R.id.etName);
|
||||
EditText etOrder = dview.findViewById(R.id.etOrder);
|
||||
btnColor = dview.findViewById(R.id.btnColor);
|
||||
|
||||
btnColor.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.hideKeyboard(etName);
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("color", btnColor.getColor());
|
||||
args.putString("title", getString(R.string.title_color));
|
||||
args.putBoolean("reset", true);
|
||||
|
||||
FragmentDialogColor fragment = new FragmentDialogColor();
|
||||
fragment.setArguments(args);
|
||||
fragment.setTargetFragment(FragmentDialogSaveSearch.this, 1234);
|
||||
fragment.show(getParentFragmentManager(), "search:color");
|
||||
}
|
||||
});
|
||||
|
||||
etName.setText(criteria.name == null ? criteria.getTitle(context) : criteria.name);
|
||||
etOrder.setText(criteria.order == null ? null : Integer.toString(criteria.order));
|
||||
btnColor.setColor(criteria.color);
|
||||
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(R.string.title_save, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
String order = etOrder.getText().toString();
|
||||
args.putString("name", etName.getText().toString());
|
||||
args.putInt("order",
|
||||
!TextUtils.isEmpty(order) && TextUtils.isDigitsOnly(order)
|
||||
? Integer.parseInt(order) : -1);
|
||||
args.putInt("color", btnColor.getColor());
|
||||
sendResult(Activity.RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
sendResult(Activity.RESULT_CANCELED);
|
||||
}
|
||||
});
|
||||
|
||||
if (criteria.id != null)
|
||||
dialog.setNeutralButton(R.string.title_delete, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
sendResult(Activity.RESULT_FIRST_USER);
|
||||
}
|
||||
});
|
||||
|
||||
return dialog.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
try {
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
Bundle args = data.getBundleExtra("args");
|
||||
int color = args.getInt("color");
|
||||
btnColor.setColor(color);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,696 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
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.lifecycle.Observer;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.Address;
|
||||
|
||||
public class FragmentDialogSend extends FragmentDialogBase {
|
||||
static final int MAX_SHOW_RECIPIENTS = 5;
|
||||
static final int RECIPIENTS_WARNING = 10;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Bundle args = getArguments();
|
||||
long id = args.getLong("id");
|
||||
final boolean sent_missing = args.getBoolean("sent_missing", false);
|
||||
final String address_error = args.getString("address_error");
|
||||
final String mx_error = args.getString("mx_error");
|
||||
final boolean remind_dsn = args.getBoolean("remind_dsn", false);
|
||||
final boolean remind_size = args.getBoolean("remind_size", false);
|
||||
final boolean remind_pgp = args.getBoolean("remind_pgp", false);
|
||||
final boolean remind_smime = args.getBoolean("remind_smime", false);
|
||||
final boolean remind_to = args.getBoolean("remind_to", false);
|
||||
final boolean remind_extra = args.getBoolean("remind_extra", false);
|
||||
final boolean remind_noreply = args.getBoolean("remind_noreply", false);
|
||||
final boolean remind_external = args.getBoolean("remind_external", false);
|
||||
final boolean remind_subject = args.getBoolean("remind_subject", false);
|
||||
final boolean remind_text = args.getBoolean("remind_text", false);
|
||||
final boolean remind_attachment = args.getBoolean("remind_attachment", false);
|
||||
final String remind_extension = args.getString("remind_extension");
|
||||
final boolean remind_internet = args.getBoolean("remind_internet", false);
|
||||
final boolean styled = args.getBoolean("styled", false);
|
||||
final long size = args.getLong("size", -1);
|
||||
final long max_size = args.getLong("max_size", -1);
|
||||
|
||||
final Context context = getContext();
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final boolean send_reminders = prefs.getBoolean("send_reminders", true);
|
||||
final int send_delayed = prefs.getInt("send_delayed", 0);
|
||||
final boolean send_dialog = prefs.getBoolean("send_dialog", true);
|
||||
final boolean send_archive = prefs.getBoolean("send_archive", false);
|
||||
final MessageHelper.AddressFormat email_format = MessageHelper.getAddressFormat(getContext());
|
||||
|
||||
final int[] encryptValues = getResources().getIntArray(R.array.encryptValues);
|
||||
final int[] sendDelayedValues = getResources().getIntArray(R.array.sendDelayedValues);
|
||||
final String[] sendDelayedNames = getResources().getStringArray(R.array.sendDelayedNames);
|
||||
|
||||
final ViewGroup dview = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.dialog_send, null);
|
||||
final Button btnFixSent = dview.findViewById(R.id.btnFixSent);
|
||||
final TextView tvAddressError = dview.findViewById(R.id.tvAddressError);
|
||||
final TextView tvRemindDsn = dview.findViewById(R.id.tvRemindDsn);
|
||||
final TextView tvRemindSize = dview.findViewById(R.id.tvRemindSize);
|
||||
final TextView tvRemindPgp = dview.findViewById(R.id.tvRemindPgp);
|
||||
final TextView tvRemindSmime = dview.findViewById(R.id.tvRemindSmime);
|
||||
final TextView tvRemindTo = dview.findViewById(R.id.tvRemindTo);
|
||||
final TextView tvRemindExtra = dview.findViewById(R.id.tvRemindExtra);
|
||||
final TextView tvRemindNoReply = dview.findViewById(R.id.tvRemindNoReply);
|
||||
final TextView tvRemindExternal = dview.findViewById(R.id.tvRemindExternal);
|
||||
final TextView tvRemindSubject = dview.findViewById(R.id.tvRemindSubject);
|
||||
final TextView tvRemindText = dview.findViewById(R.id.tvRemindText);
|
||||
final TextView tvRemindAttachment = dview.findViewById(R.id.tvRemindAttachment);
|
||||
final TextView tvRemindExtension = dview.findViewById(R.id.tvRemindExtension);
|
||||
final TextView tvRemindInternet = dview.findViewById(R.id.tvRemindInternet);
|
||||
final SwitchCompat swSendReminders = dview.findViewById(R.id.swSendReminders);
|
||||
final TextView tvSendRemindersHint = dview.findViewById(R.id.tvSendRemindersHint);
|
||||
final TextView tvTo = dview.findViewById(R.id.tvTo);
|
||||
final TextView tvViaTitle = dview.findViewById(R.id.tvViaTitle);
|
||||
final TextView tvVia = dview.findViewById(R.id.tvVia);
|
||||
final CheckBox cbPlainOnly = dview.findViewById(R.id.cbPlainOnly);
|
||||
final TextView tvPlainHint = dview.findViewById(R.id.tvPlainHint);
|
||||
final CheckBox cbReceipt = dview.findViewById(R.id.cbReceipt);
|
||||
final TextView tvReceiptHint = dview.findViewById(R.id.tvReceiptHint);
|
||||
final TextView tvEncrypt = dview.findViewById(R.id.tvEncrypt);
|
||||
final Spinner spEncrypt = dview.findViewById(R.id.spEncrypt);
|
||||
final ImageButton ibEncryption = dview.findViewById(R.id.ibEncryption);
|
||||
final Spinner spPriority = dview.findViewById(R.id.spPriority);
|
||||
final Spinner spSensitivity = dview.findViewById(R.id.spSensitivity);
|
||||
final ImageButton ibSensitivity = dview.findViewById(R.id.ibSensitivity);
|
||||
final TextView tvSendAt = dview.findViewById(R.id.tvSendAt);
|
||||
final ImageButton ibSendAt = dview.findViewById(R.id.ibSendAt);
|
||||
final CheckBox cbArchive = dview.findViewById(R.id.cbArchive);
|
||||
final CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain);
|
||||
final TextView tvNotAgain = dview.findViewById(R.id.tvNotAgain);
|
||||
final Group grpSentMissing = dview.findViewById(R.id.grpSentMissing);
|
||||
final Group grpDsn = dview.findViewById(R.id.grpDsn);
|
||||
|
||||
btnFixSent.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
v.getContext().startActivity(new Intent(v.getContext(), ActivitySetup.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.putExtra("target", "accounts"));
|
||||
}
|
||||
});
|
||||
|
||||
grpSentMissing.setVisibility(sent_missing ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvAddressError.setText(address_error == null ? mx_error : address_error);
|
||||
tvAddressError.setVisibility(address_error == null && mx_error == null ? View.GONE : View.VISIBLE);
|
||||
|
||||
tvRemindDsn.setVisibility(remind_dsn ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvRemindSize.setText(getString(R.string.title_size_reminder,
|
||||
Helper.humanReadableByteCount(size),
|
||||
Helper.humanReadableByteCount(max_size)));
|
||||
tvRemindSize.setVisibility(remind_size ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvRemindPgp.setVisibility(remind_pgp ? View.VISIBLE : View.GONE);
|
||||
tvRemindSmime.setVisibility(remind_smime ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvRemindTo.setVisibility(remind_to ? View.VISIBLE : View.GONE);
|
||||
tvRemindExtra.setVisibility(send_reminders && remind_extra ? View.VISIBLE : View.GONE);
|
||||
tvRemindNoReply.setVisibility(remind_noreply ? View.VISIBLE : View.GONE);
|
||||
tvRemindExternal.setVisibility(remind_external ? View.VISIBLE : View.GONE);
|
||||
tvRemindSubject.setVisibility(send_reminders && remind_subject ? View.VISIBLE : View.GONE);
|
||||
tvRemindText.setVisibility(send_reminders && remind_text ? View.VISIBLE : View.GONE);
|
||||
tvRemindAttachment.setVisibility(send_reminders && remind_attachment ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvRemindExtension.setText(getString(R.string.title_attachment_warning, remind_extension));
|
||||
tvRemindExtension.setVisibility(send_reminders && remind_extension != null ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvRemindInternet.setVisibility(send_reminders && remind_internet ? View.VISIBLE : View.GONE);
|
||||
|
||||
tvTo.setText(null);
|
||||
tvVia.setText(null);
|
||||
tvPlainHint.setVisibility(View.GONE);
|
||||
tvReceiptHint.setVisibility(View.GONE);
|
||||
spEncrypt.setTag(0);
|
||||
spEncrypt.setSelection(0);
|
||||
spPriority.setTag(1);
|
||||
spPriority.setSelection(1);
|
||||
spSensitivity.setTag(0);
|
||||
spSensitivity.setSelection(0);
|
||||
tvSendAt.setText(null);
|
||||
cbArchive.setEnabled(false);
|
||||
cbNotAgain.setChecked(!send_dialog);
|
||||
cbNotAgain.setVisibility(send_dialog ? View.VISIBLE : View.GONE);
|
||||
tvNotAgain.setVisibility(cbNotAgain.isChecked() ? View.VISIBLE : View.GONE);
|
||||
|
||||
Helper.setViewsEnabled(dview, false);
|
||||
|
||||
boolean reminder = (remind_extra || remind_subject || remind_text ||
|
||||
remind_attachment || remind_extension != null || remind_internet);
|
||||
swSendReminders.setChecked(send_reminders);
|
||||
swSendReminders.setVisibility(send_reminders && reminder ? View.VISIBLE : View.GONE);
|
||||
tvSendRemindersHint.setVisibility(View.GONE);
|
||||
swSendReminders.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
prefs.edit().putBoolean("send_reminders", checked).apply();
|
||||
tvRemindExtra.setVisibility(checked && remind_extra ? View.VISIBLE : View.GONE);
|
||||
tvRemindSubject.setVisibility(checked && remind_subject ? View.VISIBLE : View.GONE);
|
||||
tvRemindText.setVisibility(checked && remind_text ? View.VISIBLE : View.GONE);
|
||||
tvRemindAttachment.setVisibility(checked && remind_attachment ? View.VISIBLE : View.GONE);
|
||||
tvRemindExtension.setVisibility(checked && remind_extension != null ? View.VISIBLE : View.GONE);
|
||||
tvRemindInternet.setVisibility(checked && remind_internet ? View.VISIBLE : View.GONE);
|
||||
tvSendRemindersHint.setVisibility(checked ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
cbNotAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
prefs.edit().putBoolean("send_dialog", !isChecked).apply();
|
||||
tvNotAgain.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
cbPlainOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
tvPlainHint.setVisibility(checked && styled ? View.VISIBLE : View.GONE);
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
args.putBoolean("plain_only", checked);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
boolean plain_only = args.getBoolean("plain_only");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
db.message().setMessagePlainOnly(id, plain_only ? 1 : 0);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.serial().execute(FragmentDialogSend.this, args, "compose:plain_only");
|
||||
}
|
||||
});
|
||||
|
||||
cbReceipt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
tvReceiptHint.setVisibility(checked ? View.VISIBLE : View.GONE);
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
args.putBoolean("receipt", checked);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
boolean receipt = args.getBoolean("receipt");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
db.message().setMessageReceiptRequest(id, receipt);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.serial().execute(FragmentDialogSend.this, args, "compose:receipt");
|
||||
}
|
||||
});
|
||||
|
||||
spEncrypt.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
int last = (int) spEncrypt.getTag();
|
||||
if (last != position) {
|
||||
spEncrypt.setTag(position);
|
||||
setEncrypt(encryptValues[position]);
|
||||
|
||||
if ((encryptValues[position] == EntityMessage.PGP_SIGNONLY ||
|
||||
encryptValues[position] == EntityMessage.PGP_ENCRYPTONLY ||
|
||||
encryptValues[position] == EntityMessage.PGP_SIGNENCRYPT) &&
|
||||
Helper.isOpenKeychainInstalled(context)) {
|
||||
tvEncrypt.setPaintFlags(tvEncrypt.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
tvEncrypt.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String pkg = Helper.getOpenKeychainPackage(v.getContext());
|
||||
PackageManager pm = v.getContext().getPackageManager();
|
||||
v.getContext().startActivity(pm.getLaunchIntentForPackage(pkg));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
tvEncrypt.setPaintFlags(tvEncrypt.getPaintFlags() & ~Paint.UNDERLINE_TEXT_FLAG);
|
||||
tvEncrypt.setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
spEncrypt.setTag(0);
|
||||
setEncrypt(encryptValues[0]);
|
||||
}
|
||||
|
||||
private void setEncrypt(int encrypt) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
args.putInt("encrypt", encrypt);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
int encrypt = args.getInt("encrypt");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
EntityMessage message = db.message().getMessage(id);
|
||||
if (message == null)
|
||||
return null;
|
||||
|
||||
db.message().setMessageUiEncrypt(message.id, encrypt);
|
||||
|
||||
List<EntityAttachment> attachments = db.attachment().getAttachments(message.id);
|
||||
if (attachments == null)
|
||||
return null;
|
||||
for (EntityAttachment attachment : attachments)
|
||||
if (attachment.isEncryption())
|
||||
db.attachment().deleteAttachment(attachment.id);
|
||||
|
||||
if (encrypt != EntityMessage.ENCRYPT_NONE &&
|
||||
message.identity != null) {
|
||||
int iencrypt =
|
||||
(encrypt == EntityMessage.SMIME_SIGNONLY ||
|
||||
encrypt == EntityMessage.SMIME_SIGNENCRYPT
|
||||
? 1 : 0);
|
||||
db.identity().setIdentityEncrypt(message.identity, iencrypt);
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Void data) {
|
||||
int encrypt = args.getInt("encrypt");
|
||||
|
||||
boolean none = EntityMessage.ENCRYPT_NONE.equals(encrypt);
|
||||
tvRemindPgp.setVisibility(remind_pgp && none ? View.VISIBLE : View.GONE);
|
||||
tvRemindSmime.setVisibility(remind_smime && none ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.serial().execute(FragmentDialogSend.this, args, "compose:encrypt");
|
||||
}
|
||||
});
|
||||
|
||||
ibEncryption.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.viewFAQ(v.getContext(), 12);
|
||||
}
|
||||
});
|
||||
|
||||
spPriority.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
int last = (int) spPriority.getTag();
|
||||
if (last != position) {
|
||||
spPriority.setTag(position);
|
||||
setPriority(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
spPriority.setTag(1);
|
||||
setPriority(1);
|
||||
}
|
||||
|
||||
private void setPriority(int priority) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
args.putInt("priority", priority);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
int priority = args.getInt("priority");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
db.message().setMessagePriority(id, priority);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.serial().execute(FragmentDialogSend.this, args, "compose:priority");
|
||||
}
|
||||
});
|
||||
|
||||
spSensitivity.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
int last = (int) spSensitivity.getTag();
|
||||
if (last != position) {
|
||||
spSensitivity.setTag(position);
|
||||
setSensitivity(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
spSensitivity.setTag(0);
|
||||
setSensitivity(0);
|
||||
}
|
||||
|
||||
private void setSensitivity(int sensitivity) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
args.putInt("sensitivity", sensitivity);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
int sensitivity = args.getInt("sensitivity");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
db.message().setMessageSensitivity(id, sensitivity < 1 ? null : sensitivity);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.serial().execute(FragmentDialogSend.this, args, "compose:sensitivity");
|
||||
}
|
||||
});
|
||||
|
||||
ibSensitivity.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.viewFAQ(v.getContext(), 177);
|
||||
}
|
||||
});
|
||||
|
||||
View.OnClickListener sendAt = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString("title", getString(R.string.title_send_at));
|
||||
args.putLong("id", id);
|
||||
|
||||
FragmentDialogDuration fragment = new FragmentDialogDuration();
|
||||
fragment.setArguments(args);
|
||||
fragment.setTargetFragment(FragmentDialogSend.this, 1);
|
||||
fragment.show(getParentFragmentManager(), "send:snooze");
|
||||
}
|
||||
};
|
||||
|
||||
tvSendAt.setOnClickListener(sendAt);
|
||||
ibSendAt.setOnClickListener(sendAt);
|
||||
|
||||
cbArchive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
prefs.edit().putBoolean("send_archive", isChecked).apply();
|
||||
}
|
||||
});
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
db.message().liveMessage(id).observe(getViewLifecycleOwner(), new Observer<TupleMessageEx>() {
|
||||
@Override
|
||||
public void onChanged(TupleMessageEx draft) {
|
||||
if (draft == null) {
|
||||
dismiss();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean dsn = (draft.dsn != null && !EntityMessage.DSN_NONE.equals(draft.dsn));
|
||||
int to = (draft.to == null ? 0 : draft.to.length);
|
||||
int extra = (draft.cc == null ? 0 : draft.cc.length) + (draft.bcc == null ? 0 : draft.bcc.length);
|
||||
|
||||
List<Address> t = new ArrayList<>();
|
||||
if (draft.to != null)
|
||||
if (to <= MAX_SHOW_RECIPIENTS)
|
||||
t.addAll(Arrays.asList(draft.to));
|
||||
else {
|
||||
t.addAll((Arrays.asList(Arrays.copyOf(draft.to, MAX_SHOW_RECIPIENTS))));
|
||||
extra += draft.to.length - MAX_SHOW_RECIPIENTS;
|
||||
}
|
||||
Address[] tos = t.toArray(new Address[0]);
|
||||
|
||||
if (extra == 0)
|
||||
tvTo.setText(MessageHelper.formatAddresses(tos, email_format, false));
|
||||
else
|
||||
tvTo.setText(getString(R.string.title_name_plus,
|
||||
MessageHelper.formatAddresses(tos, email_format, false), extra));
|
||||
tvTo.setTextColor(Helper.resolveColor(context,
|
||||
to + extra > RECIPIENTS_WARNING ? R.attr.colorWarning : android.R.attr.textColorPrimary));
|
||||
if (draft.identityColor != null && draft.identityColor != Color.TRANSPARENT)
|
||||
tvViaTitle.setTextColor(draft.identityColor);
|
||||
tvVia.setText(draft.identityEmail);
|
||||
|
||||
cbPlainOnly.setChecked(draft.isPlainOnly() && !dsn);
|
||||
cbReceipt.setChecked(draft.receipt_request != null && draft.receipt_request && !dsn);
|
||||
|
||||
int encrypt = (draft.ui_encrypt == null || dsn ? EntityMessage.ENCRYPT_NONE : draft.ui_encrypt);
|
||||
for (int i = 0; i < encryptValues.length; i++)
|
||||
if (encryptValues[i] == encrypt) {
|
||||
spEncrypt.setTag(i);
|
||||
spEncrypt.setSelection(i);
|
||||
break;
|
||||
}
|
||||
|
||||
int priority = (draft.priority == null ? 1 : draft.priority);
|
||||
spPriority.setTag(priority);
|
||||
spPriority.setSelection(priority);
|
||||
|
||||
int sensitivity = (draft.sensitivity == null ? 0 : draft.sensitivity);
|
||||
spSensitivity.setTag(sensitivity);
|
||||
spSensitivity.setSelection(sensitivity);
|
||||
|
||||
if (draft.ui_snoozed == null) {
|
||||
if (send_delayed == 0)
|
||||
tvSendAt.setText(getString(R.string.title_now));
|
||||
else
|
||||
for (int pos = 0; pos < sendDelayedValues.length; pos++)
|
||||
if (sendDelayedValues[pos] == send_delayed) {
|
||||
tvSendAt.setText(getString(R.string.title_after, sendDelayedNames[pos]));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DateFormat DTF = Helper.getDateTimeInstance(context, SimpleDateFormat.MEDIUM, SimpleDateFormat.SHORT);
|
||||
DateFormat D = new SimpleDateFormat("E");
|
||||
tvSendAt.setText(D.format(draft.ui_snoozed) + " " + DTF.format(draft.ui_snoozed));
|
||||
}
|
||||
|
||||
grpDsn.setVisibility(dsn ? View.GONE : View.VISIBLE);
|
||||
|
||||
Helper.setViewsEnabled(dview, true);
|
||||
}
|
||||
});
|
||||
|
||||
Bundle aargs = new Bundle();
|
||||
aargs.putLong("id", id);
|
||||
|
||||
new SimpleTask<Boolean>() {
|
||||
@Override
|
||||
protected @NonNull
|
||||
Boolean onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
EntityMessage draft = db.message().getMessage(id);
|
||||
if (draft == null) {
|
||||
args.putString("reason", "Draft gone");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(draft.inreplyto)) {
|
||||
args.putString("reason", "No in-reply-to");
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityFolder archive = db.folder().getFolderByType(draft.account, EntityFolder.ARCHIVE);
|
||||
if (archive == null) {
|
||||
args.putString("reason", "No archive");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<EntityMessage> messages = db.message().getMessagesByMsgId(draft.account, draft.inreplyto);
|
||||
if (messages == null || messages.size() == 0) {
|
||||
args.putString("reason", "In-reply-to gone");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EntityMessage message : messages) {
|
||||
EntityFolder folder = db.folder().getFolder(message.folder);
|
||||
if (folder == null)
|
||||
continue;
|
||||
if (EntityFolder.INBOX.equals(folder.type) || EntityFolder.USER.equals(folder.type))
|
||||
return true;
|
||||
}
|
||||
|
||||
args.putString("reason", "Not in inbox or unread");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Boolean data) {
|
||||
if (!data) {
|
||||
String reason = args.getString("reason");
|
||||
if (BuildConfig.DEBUG)
|
||||
cbArchive.setText(reason);
|
||||
else
|
||||
Log.i("Auto archive reason=" + reason);
|
||||
}
|
||||
if (send_archive && data)
|
||||
cbArchive.setChecked(true);
|
||||
cbArchive.setEnabled(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
// Ignored
|
||||
}
|
||||
}.serial().execute(FragmentDialogSend.this, aargs, "send:archive");
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
if (address_error == null && !remind_to && !remind_size) {
|
||||
if (send_delayed != 0)
|
||||
builder.setNeutralButton(R.string.title_send_now, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
getArguments().putBoolean("archive", cbArchive.isChecked());
|
||||
sendResult(Activity.RESULT_FIRST_USER);
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton(R.string.title_send, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
getArguments().putBoolean("archive", cbArchive.isChecked());
|
||||
sendResult(Activity.RESULT_OK);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
if (resultCode == RESULT_OK && intent != null) {
|
||||
Bundle data = intent.getBundleExtra("args");
|
||||
long id = data.getLong("id");
|
||||
long duration = data.getLong("duration");
|
||||
long time = data.getLong("time");
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
args.putLong("wakeup", duration == 0 ? -1 : time);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
long wakeup = args.getLong("wakeup");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
db.message().setMessageSnoozed(id, wakeup < 0 ? null : wakeup);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.serial().execute(this, args, "compose:snooze");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FragmentDialogSwipes extends FragmentDialogBase {
|
||||
private Spinner spLeft;
|
||||
private Spinner spRight;
|
||||
private ArrayAdapter<EntityFolder> adapter;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_swipes, null);
|
||||
spLeft = dview.findViewById(R.id.spLeft);
|
||||
spRight = dview.findViewById(R.id.spRight);
|
||||
|
||||
adapter = new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1, new ArrayList<EntityFolder>());
|
||||
adapter.setDropDownViewResource(R.layout.spinner_item1_dropdown);
|
||||
|
||||
spLeft.setAdapter(adapter);
|
||||
spRight.setAdapter(adapter);
|
||||
|
||||
List<EntityFolder> folders = FragmentAccount.getFolderActions(getContext());
|
||||
|
||||
EntityFolder trash = new EntityFolder();
|
||||
trash.id = 2L;
|
||||
trash.name = getString(R.string.title_trash);
|
||||
folders.add(1, trash);
|
||||
|
||||
EntityFolder archive = new EntityFolder();
|
||||
archive.id = 1L;
|
||||
archive.name = getString(R.string.title_archive);
|
||||
folders.add(1, archive);
|
||||
|
||||
adapter.addAll(folders);
|
||||
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
int leftPos = prefs.getInt("swipe_left_default", 2); // Trash
|
||||
int rightPos = prefs.getInt("swipe_right_default", 1); // Archive
|
||||
|
||||
spLeft.setSelection(leftPos);
|
||||
spRight.setSelection(rightPos);
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
prefs.edit()
|
||||
.putInt("swipe_left_default", spLeft.getSelectedItemPosition())
|
||||
.putInt("swipe_right_default", spRight.getSelectedItemPosition())
|
||||
.apply();
|
||||
|
||||
EntityFolder left = (EntityFolder) spLeft.getSelectedItem();
|
||||
EntityFolder right = (EntityFolder) spRight.getSelectedItem();
|
||||
|
||||
if ((left != null && EntityMessage.SWIPE_ACTION_HIDE.equals(left.id)) ||
|
||||
(right != null && EntityMessage.SWIPE_ACTION_HIDE.equals(right.id)))
|
||||
prefs.edit()
|
||||
.putBoolean("message_tools", true)
|
||||
.putBoolean("button_hide", true)
|
||||
.apply();
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("left", left == null ? 0 : left.id);
|
||||
args.putLong("right", right == null ? 0 : right.id);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long left = args.getLong("left");
|
||||
long right = args.getLong("right");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
List<EntityAccount> accounts = db.account().getAccounts();
|
||||
for (EntityAccount account : accounts)
|
||||
if (account.protocol == EntityAccount.TYPE_IMAP)
|
||||
db.account().setAccountSwipes(
|
||||
account.id,
|
||||
getAction(context, left, account.id),
|
||||
getAction(context, right, account.id));
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Void data) {
|
||||
ToastEx.makeText(getContext(), R.string.title_completed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
|
||||
private Long getAction(Context context, long selection, long account) {
|
||||
if (selection < 0)
|
||||
return selection;
|
||||
else if (selection == 0)
|
||||
return null;
|
||||
else {
|
||||
DB db = DB.getInstance(context);
|
||||
String type = (selection == 2 ? EntityFolder.TRASH : EntityFolder.ARCHIVE);
|
||||
EntityFolder archive = db.folder().getFolderByType(account, type);
|
||||
return (archive == null ? null : archive.id);
|
||||
}
|
||||
}
|
||||
}.execute(getContext(), getViewLifecycleOwner(), args, "dialog:swipe");
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,248 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FragmentDialogVirusTotal extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Bundle args = getArguments();
|
||||
String apiKey = args.getString("apiKey");
|
||||
String name = args.getString("name");
|
||||
|
||||
final Context context = getContext();
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.dialog_virus_total, null);
|
||||
final TextView tvName = view.findViewById(R.id.tvName);
|
||||
final TextView tvError = view.findViewById(R.id.tvError);
|
||||
final TextView tvUnknown = view.findViewById(R.id.tvUnknown);
|
||||
final TextView tvSummary = view.findViewById(R.id.tvSummary);
|
||||
final TextView tvLabel = view.findViewById(R.id.tvLabel);
|
||||
final TextView tvReport = view.findViewById(R.id.tvReport);
|
||||
final RecyclerView rvScan = view.findViewById(R.id.rvScan);
|
||||
final Button btnUpload = view.findViewById(R.id.btnUpload);
|
||||
final ProgressBar pbUpload = view.findViewById(R.id.pbUpload);
|
||||
final TextView tvAnalyzing = view.findViewById(R.id.tvAnalyzing);
|
||||
final TextView tvPrivacy = view.findViewById(R.id.tvPrivacy);
|
||||
final ProgressBar pbWait = view.findViewById(R.id.pbWait);
|
||||
|
||||
tvName.setText(name);
|
||||
tvName.setVisibility(TextUtils.isEmpty(name) ? View.GONE : View.VISIBLE);
|
||||
tvError.setVisibility(View.GONE);
|
||||
tvUnknown.setVisibility(View.GONE);
|
||||
tvSummary.setVisibility(View.GONE);
|
||||
tvLabel.setVisibility(View.GONE);
|
||||
tvReport.setVisibility(View.GONE);
|
||||
tvReport.getPaint().setUnderlineText(true);
|
||||
|
||||
rvScan.setHasFixedSize(false);
|
||||
LinearLayoutManager llm = new LinearLayoutManager(getContext());
|
||||
rvScan.setLayoutManager(llm);
|
||||
|
||||
final AdapterVirusTotal adapter = new AdapterVirusTotal(getContext(), getViewLifecycleOwner());
|
||||
rvScan.setAdapter(adapter);
|
||||
|
||||
rvScan.setVisibility(View.GONE);
|
||||
|
||||
btnUpload.setVisibility(View.GONE);
|
||||
pbUpload.setVisibility(View.GONE);
|
||||
tvAnalyzing.setVisibility(View.GONE);
|
||||
tvPrivacy.setVisibility(View.GONE);
|
||||
tvPrivacy.getPaint().setUnderlineText(true);
|
||||
pbWait.setVisibility(View.GONE);
|
||||
|
||||
final SimpleTask<Bundle> taskLookup = new SimpleTask<Bundle>() {
|
||||
@Override
|
||||
protected void onPreExecute(Bundle args) {
|
||||
tvError.setVisibility(View.GONE);
|
||||
pbWait.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bundle args) {
|
||||
pbWait.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bundle onExecute(Context context, Bundle args) throws Throwable {
|
||||
String apiKey = args.getString("apiKey");
|
||||
File file = (File) args.getSerializable("file");
|
||||
return VirusTotal.lookup(context, file, apiKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Bundle result) {
|
||||
List<VirusTotal.ScanResult> scans = result.getParcelableArrayList("scans");
|
||||
String label = result.getString("label");
|
||||
String analysis = args.getString("analysis");
|
||||
|
||||
int malicious = 0;
|
||||
if (scans != null)
|
||||
for (VirusTotal.ScanResult scan : scans)
|
||||
if ("malicious".equals(scan.category))
|
||||
malicious++;
|
||||
|
||||
NumberFormat NF = NumberFormat.getNumberInstance();
|
||||
|
||||
tvUnknown.setVisibility(scans == null ? View.VISIBLE : View.GONE);
|
||||
tvSummary.setText(getString(R.string.title_vt_summary, NF.format(malicious)));
|
||||
tvSummary.setTextColor(Helper.resolveColor(context,
|
||||
malicious == 0 ? android.R.attr.textColorPrimary : R.attr.colorWarning));
|
||||
tvSummary.setTypeface(malicious == 0 ? Typeface.DEFAULT : Typeface.DEFAULT_BOLD);
|
||||
tvSummary.setVisibility(scans == null ? View.GONE : View.VISIBLE);
|
||||
tvLabel.setText(label);
|
||||
tvReport.setVisibility(scans == null ? View.GONE : View.VISIBLE);
|
||||
adapter.set(scans == null ? new ArrayList<>() : scans);
|
||||
rvScan.setVisibility(scans == null ? View.GONE : View.VISIBLE);
|
||||
btnUpload.setVisibility(scans == null && !TextUtils.isEmpty(apiKey) ? View.VISIBLE : View.GONE);
|
||||
tvPrivacy.setVisibility(btnUpload.getVisibility());
|
||||
|
||||
if (analysis != null && args.getBoolean("init")) {
|
||||
args.remove("init");
|
||||
btnUpload.callOnClick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
tvError.setText(Log.formatThrowable(ex, false));
|
||||
tvError.setVisibility(View.VISIBLE);
|
||||
}
|
||||
};
|
||||
|
||||
final SimpleTask<Void> taskUpload = new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected void onPreExecute(Bundle args) {
|
||||
btnUpload.setEnabled(false);
|
||||
pbUpload.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bundle args) {
|
||||
btnUpload.setEnabled(true);
|
||||
tvAnalyzing.setVisibility(View.GONE);
|
||||
pbUpload.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) throws Throwable {
|
||||
String apiKey = args.getString("apiKey");
|
||||
File file = (File) args.getSerializable("file");
|
||||
|
||||
String analysis = args.getString("analysis");
|
||||
if (analysis == null) {
|
||||
analysis = VirusTotal.upload(context, file, apiKey);
|
||||
args.putString("analysis", analysis);
|
||||
}
|
||||
postProgress(analysis);
|
||||
VirusTotal.waitForAnalysis(context, analysis, apiKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgress(CharSequence status, Bundle data) {
|
||||
tvAnalyzing.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Void data) {
|
||||
taskLookup.execute(FragmentDialogVirusTotal.this, args, "attachment:lookup");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
};
|
||||
|
||||
final SimpleTask<String> taskUrl = new SimpleTask<String>() {
|
||||
@Override
|
||||
protected String onExecute(Context context, Bundle args) throws Throwable {
|
||||
File file = (File) args.getSerializable("file");
|
||||
return VirusTotal.getUrl(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, String uri) {
|
||||
Helper.view(context, Uri.parse(uri), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
};
|
||||
|
||||
tvReport.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
taskUrl.execute(FragmentDialogVirusTotal.this, args, "attachment:report");
|
||||
}
|
||||
});
|
||||
|
||||
btnUpload.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
taskUpload.execute(FragmentDialogVirusTotal.this, args, "attachment:upload");
|
||||
}
|
||||
});
|
||||
|
||||
tvPrivacy.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Helper.view(v.getContext(), Uri.parse(VirusTotal.URI_PRIVACY), true);
|
||||
}
|
||||
});
|
||||
|
||||
if (TextUtils.isEmpty(apiKey))
|
||||
pbWait.setVisibility(View.GONE);
|
||||
else {
|
||||
args.putBoolean("init", true);
|
||||
taskLookup.execute(this, args, "attachment:lookup");
|
||||
}
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(view)
|
||||
.setNegativeButton(R.string.title_setup_done, null)
|
||||
.create();
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
|
||||
public 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();
|
||||
}
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
package eu.faircode.email;
|
||||
|
||||
/*
|
||||
This file is part of FairEmail.
|
||||
|
||||
FairEmail is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
FairEmail 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2018-2023 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class FragmentMoveAsk extends FragmentDialogBase {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
String notagain = getArguments().getString("notagain");
|
||||
ArrayList<FragmentMessages.MessageTarget> result = getArguments().getParcelableArrayList("result");
|
||||
|
||||
final Context context = getContext();
|
||||
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_ask_move, null);
|
||||
TextView tvMessages = dview.findViewById(R.id.tvMessages);
|
||||
TextView tvSourceFolders = dview.findViewById(R.id.tvSourceFolders);
|
||||
TextView tvTargetFolders = dview.findViewById(R.id.tvTargetFolders);
|
||||
CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain);
|
||||
TextView tvJunkLearn = dview.findViewById(R.id.tvJunkLearn);
|
||||
|
||||
String question = context.getResources()
|
||||
.getQuantityString(R.plurals.title_moving_messages,
|
||||
result.size(), result.size());
|
||||
|
||||
tvMessages.setText(question);
|
||||
tvSourceFolders.setText(getNames(result, false));
|
||||
tvTargetFolders.setText(getNames(result, true));
|
||||
|
||||
List<String> sources = new ArrayList<>();
|
||||
List<String> targets = new ArrayList<>();
|
||||
Integer sourceColor = null;
|
||||
Integer targetColor = null;
|
||||
boolean junk = false;
|
||||
for (FragmentMessages.MessageTarget t : result) {
|
||||
if (!sources.contains(t.sourceFolder.type))
|
||||
sources.add(t.sourceFolder.type);
|
||||
if (!targets.contains(t.targetFolder.type))
|
||||
targets.add(t.targetFolder.type);
|
||||
if (sourceColor == null)
|
||||
sourceColor = t.sourceFolder.color;
|
||||
if (targetColor == null)
|
||||
targetColor = t.targetFolder.color;
|
||||
if (!junk &&
|
||||
(EntityFolder.JUNK.equals(t.sourceFolder.type) ||
|
||||
EntityFolder.JUNK.equals(t.targetFolder.type)))
|
||||
junk = true;
|
||||
}
|
||||
|
||||
Drawable source = null;
|
||||
if (sources.size() == 1) {
|
||||
source = ContextCompat.getDrawable(context, EntityFolder.getIcon(sources.get(0)));
|
||||
if (source != null)
|
||||
source.setBounds(0, 0, source.getIntrinsicWidth(), source.getIntrinsicHeight());
|
||||
if (sourceColor == null)
|
||||
sourceColor = EntityFolder.getDefaultColor(sources.get(0), context);
|
||||
} else {
|
||||
source = ContextCompat.getDrawable(context, R.drawable.twotone_folders_24);
|
||||
source.setBounds(0, 0, source.getIntrinsicWidth(), source.getIntrinsicHeight());
|
||||
sourceColor = null;
|
||||
}
|
||||
|
||||
Drawable target = null;
|
||||
if (targets.size() == 1) {
|
||||
target = ContextCompat.getDrawable(context, EntityFolder.getIcon(targets.get(0)));
|
||||
if (target != null)
|
||||
target.setBounds(0, 0, target.getIntrinsicWidth(), target.getIntrinsicHeight());
|
||||
if (targetColor == null)
|
||||
targetColor = EntityFolder.getDefaultColor(targets.get(0), context);
|
||||
} else
|
||||
targetColor = null;
|
||||
|
||||
tvSourceFolders.setCompoundDrawablesRelative(source, null, null, null);
|
||||
tvTargetFolders.setCompoundDrawablesRelative(target, null, null, null);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (sourceColor != null)
|
||||
tvSourceFolders.setCompoundDrawableTintList(ColorStateList.valueOf(sourceColor));
|
||||
if (targetColor != null)
|
||||
tvTargetFolders.setCompoundDrawableTintList(ColorStateList.valueOf(targetColor));
|
||||
}
|
||||
|
||||
if (notagain != null)
|
||||
cbNotAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(buttonView.getContext());
|
||||
prefs.edit().putBoolean(notagain, isChecked).apply();
|
||||
}
|
||||
});
|
||||
|
||||
tvJunkLearn.setVisibility(junk ? View.VISIBLE : View.GONE);
|
||||
|
||||
return new AlertDialog.Builder(context)
|
||||
.setView(dview)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
sendResult(Activity.RESULT_OK);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
sendResult(Activity.RESULT_CANCELED);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
static String getNames(ArrayList<FragmentMessages.MessageTarget> result, boolean dest) {
|
||||
boolean across = false;
|
||||
for (FragmentMessages.MessageTarget target : result)
|
||||
if (target.isAcross())
|
||||
across = true;
|
||||
|
||||
Map<String, Integer> nameCount = new HashMap<>();
|
||||
for (FragmentMessages.MessageTarget target : result) {
|
||||
String name = "";
|
||||
if (across)
|
||||
name += (dest ? target.targetAccount.name : target.sourceAccount.name) + "/";
|
||||
name += (dest ? target.targetFolder.display : target.sourceFolder.display);
|
||||
if (!nameCount.containsKey(name))
|
||||
nameCount.put(name, 0);
|
||||
nameCount.put(name, nameCount.get(name) + 1);
|
||||
}
|
||||
|
||||
List<String> keys = new ArrayList(nameCount.keySet());
|
||||
|
||||
Collator collator = Collator.getInstance(Locale.getDefault());
|
||||
collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc
|
||||
Collections.sort(keys, collator);
|
||||
|
||||
NumberFormat NF = NumberFormat.getNumberInstance();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
if (i > 0)
|
||||
sb.append(", ");
|
||||
sb.append(keys.get(i));
|
||||
if (!dest && keys.size() > 1) {
|
||||
int count = nameCount.get(keys.get(i));
|
||||
sb.append('(').append(NF.format(count)).append(')');
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
Loading…
Reference in new issue