mirror of https://github.com/M66B/FairEmail.git
Added answer stats
This commit is contained in:
parent
0563c8808b
commit
044f62bd6a
File diff suppressed because it is too large
Load Diff
|
@ -47,6 +47,8 @@ import androidx.recyclerview.widget.DiffUtil;
|
|||
import androidx.recyclerview.widget.ListUpdateCallback;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -57,6 +59,9 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
private LifecycleOwner owner;
|
||||
private LayoutInflater inflater;
|
||||
|
||||
private DateFormat DF;
|
||||
private NumberFormat NF = NumberFormat.getNumberInstance();
|
||||
|
||||
private String search = null;
|
||||
private List<EntityAnswer> all = new ArrayList<>();
|
||||
private List<EntityAnswer> selected = new ArrayList<>();
|
||||
|
@ -70,6 +75,8 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
private ImageView ivStandard;
|
||||
private ImageView ivFavorite;
|
||||
private ImageView ivReceipt;
|
||||
private TextView tvLastApplied;
|
||||
private TextView tvApplied;
|
||||
|
||||
private TwoStateOwner powner = new TwoStateOwner(owner, "RulePopup");
|
||||
|
||||
|
@ -82,6 +89,8 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
ivStandard = itemView.findViewById(R.id.ivStandard);
|
||||
ivFavorite = itemView.findViewById(R.id.ivFavorite);
|
||||
ivReceipt = itemView.findViewById(R.id.ivReceipt);
|
||||
tvLastApplied = itemView.findViewById(R.id.tvLastApplied);
|
||||
tvApplied = itemView.findViewById(R.id.tvApplied);
|
||||
}
|
||||
|
||||
private void wire() {
|
||||
|
@ -102,6 +111,8 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
ivStandard.setVisibility(answer.standard ? View.VISIBLE : View.GONE);
|
||||
ivFavorite.setVisibility(answer.favorite ? View.VISIBLE : View.GONE);
|
||||
ivReceipt.setVisibility(answer.receipt ? View.VISIBLE : View.GONE);
|
||||
tvLastApplied.setText(answer.last_applied == null ? null : DF.format(answer.last_applied));
|
||||
tvApplied.setText(NF.format(answer.applied));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,7 +150,8 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
.setCheckable(true).setChecked(answer.favorite);
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_answer_hide, 3, R.string.title_answer_hide)
|
||||
.setCheckable(true).setChecked(answer.hide);
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_copy, 4, R.string.title_copy);
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_reset, 4, R.string.title_reset);
|
||||
popupMenu.getMenu().add(Menu.NONE, R.string.title_copy, 5, R.string.title_copy);
|
||||
|
||||
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
|
@ -154,6 +166,9 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
} else if (itemId == R.string.title_answer_hide) {
|
||||
onActionHide(!item.isChecked());
|
||||
return true;
|
||||
} else if (itemId == R.string.title_reset) {
|
||||
onActionReset();
|
||||
return true;
|
||||
} else if (itemId == R.string.title_copy) {
|
||||
onActionCopy();
|
||||
return true;
|
||||
|
@ -215,6 +230,28 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
}.execute(context, owner, args, "answer:hide");
|
||||
}
|
||||
|
||||
private void onActionReset() {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", answer.id);
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long id = args.getLong("id");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
db.answer().resetAnswer(id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(parentFragment.getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(context, owner, args, "rule:execute");
|
||||
}
|
||||
|
||||
private void onActionCopy() {
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
|
||||
lbm.sendBroadcast(
|
||||
|
@ -237,6 +274,8 @@ public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder
|
|||
this.owner = parentFragment.getViewLifecycleOwner();
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
|
||||
this.DF = Helper.getDateTimeInstance(this.context);
|
||||
|
||||
setHasStableIds(true);
|
||||
|
||||
owner.getLifecycle().addObserver(new LifecycleObserver() {
|
||||
|
|
|
@ -65,7 +65,7 @@ import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_PASSWORD;
|
|||
// https://developer.android.com/topic/libraries/architecture/room.html
|
||||
|
||||
@Database(
|
||||
version = 196,
|
||||
version = 197,
|
||||
entities = {
|
||||
EntityIdentity.class,
|
||||
EntityAccount.class,
|
||||
|
@ -2013,6 +2013,13 @@ public abstract class DB extends RoomDatabase {
|
|||
Log.i("DB migration from version " + startVersion + " to " + endVersion);
|
||||
db.execSQL("ALTER TABLE `identity` ADD COLUMN `internal` TEXT");
|
||||
}
|
||||
}).addMigrations(new Migration(196, 197) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
Log.i("DB migration from version " + startVersion + " to " + endVersion);
|
||||
db.execSQL("ALTER TABLE `answer` ADD COLUMN `applied` INTEGER NOT NULL DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE `answer` ADD COLUMN `last_applied` INTEGER");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,16 @@ public interface DaoAnswer {
|
|||
@Query("UPDATE answer SET receipt = 0 WHERE NOT (receipt IS 0)")
|
||||
void resetReceipt();
|
||||
|
||||
@Query("UPDATE answer" +
|
||||
" SET applied = applied + 1, last_applied = :time" +
|
||||
" WHERE id = :id")
|
||||
int applyAnswer(long id, long time);
|
||||
|
||||
@Query("UPDATE answer" +
|
||||
" SET applied = 0, last_applied = NULL" +
|
||||
" WHERE id = :id AND NOT (applied IS 0)")
|
||||
int resetAnswer(long id);
|
||||
|
||||
@Query("DELETE FROM answer WHERE id = :id")
|
||||
void deleteAnswer(long id);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,9 @@ public class EntityAnswer implements Serializable {
|
|||
public Boolean hide;
|
||||
@NonNull
|
||||
public String text;
|
||||
@NonNull
|
||||
public Integer applied = 0;
|
||||
public Long last_applied;
|
||||
|
||||
String getText(Address[] address) {
|
||||
return replacePlaceholders(text, address);
|
||||
|
@ -128,6 +131,8 @@ public class EntityAnswer implements Serializable {
|
|||
json.put("favorite", favorite);
|
||||
json.put("hide", hide);
|
||||
json.put("text", text);
|
||||
json.put("applied", applied);
|
||||
json.put("last_applied", last_applied);
|
||||
return json;
|
||||
}
|
||||
|
||||
|
@ -141,6 +146,9 @@ public class EntityAnswer implements Serializable {
|
|||
answer.favorite = json.optBoolean("favorite");
|
||||
answer.hide = json.optBoolean("hide");
|
||||
answer.text = json.getString("text");
|
||||
answer.applied = json.optInt("applied", 0);
|
||||
if (json.has("last_applied") && !json.isNull("last_applied"))
|
||||
answer.last_applied = json.getLong("last_applied");
|
||||
return answer;
|
||||
}
|
||||
|
||||
|
@ -154,8 +162,9 @@ public class EntityAnswer implements Serializable {
|
|||
this.receipt.equals(other.receipt) &&
|
||||
this.favorite.equals(other.favorite) &&
|
||||
this.hide.equals(other.hide) &&
|
||||
this.text.equals(other.text)
|
||||
);
|
||||
this.text.equals(other.text) &&
|
||||
this.applied.equals(other.applied) &&
|
||||
Objects.equals(this.last_applied, other.last_applied));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -183,6 +183,11 @@ public class FragmentAnswer extends FragmentBase {
|
|||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, EntityAnswer answer) {
|
||||
if (copy > 0 && answer != null) {
|
||||
answer.applied = 0;
|
||||
answer.last_applied = null;
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
Bundle a = getArguments();
|
||||
if (a == null)
|
||||
|
|
|
@ -1796,8 +1796,28 @@ public class FragmentCompose extends FragmentBase {
|
|||
}
|
||||
|
||||
long id = intent.getLongExtra("id", -1);
|
||||
for (EntityAnswer answer : answers)
|
||||
if (answer.id.equals(id)) {
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", id);
|
||||
|
||||
new SimpleTask<EntityAnswer>() {
|
||||
@Override
|
||||
protected EntityAnswer onExecute(Context context, Bundle args) throws Throwable {
|
||||
long id = args.getLong("id");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
EntityAnswer answer = db.answer().getAnswer(id);
|
||||
if (answer != null)
|
||||
db.answer().applyAnswer(answer.id, new Date().getTime());
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, EntityAnswer answer) {
|
||||
if (answer == null)
|
||||
return;
|
||||
|
||||
if (etSubject.getText().length() == 0)
|
||||
etSubject.setText(answer.name);
|
||||
|
||||
|
@ -1841,13 +1861,15 @@ public class FragmentCompose extends FragmentBase {
|
|||
if (pos >= 0)
|
||||
etBody.setSelection(pos);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.e("Answer=" + id + " count=" + answers.size() + " not found");
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(FragmentCompose.this, args, "compose:answer");
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3820,6 +3842,7 @@ public class FragmentCompose extends FragmentBase {
|
|||
? db.answer().getStandardAnswer()
|
||||
: db.answer().getAnswer(answer));
|
||||
if (a != null) {
|
||||
db.answer().applyAnswer(a.id, new Date().getTime());
|
||||
data.draft.subject = a.name;
|
||||
Document d = JsoupEx.parse(a.getText(null));
|
||||
document.body().append(d.body().html());
|
||||
|
@ -3978,6 +4001,7 @@ public class FragmentCompose extends FragmentBase {
|
|||
if (receipt == null)
|
||||
texts = Helper.getStrings(context, ref.language, R.string.title_receipt_text);
|
||||
else {
|
||||
db.answer().applyAnswer(receipt.id, new Date().getTime());
|
||||
texts = new String[0];
|
||||
Document d = JsoupEx.parse(receipt.getText(null));
|
||||
document.body().append(d.body().html());
|
||||
|
@ -4023,6 +4047,7 @@ public class FragmentCompose extends FragmentBase {
|
|||
a = db.answer().getAnswer(answer);
|
||||
|
||||
if (a != null) {
|
||||
db.answer().applyAnswer(a.id, new Date().getTime());
|
||||
Document d = JsoupEx.parse(a.getText(data.draft.to));
|
||||
document.body().append(d.body().html());
|
||||
}
|
||||
|
|
|
@ -41,12 +41,31 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvName" />
|
||||
|
||||
<eu.faircode.email.FixedTextView
|
||||
android:id="@+id/tvLastApplied"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:text="Jan 1, 12:34"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toStartOf="@id/tvApplied"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvGroup" />
|
||||
|
||||
<eu.faircode.email.FixedTextView
|
||||
android:id="@+id/tvApplied"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="123"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvGroup" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivReceipt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/ivStandard"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/twotone_playlist_add_check_24" />
|
||||
|
@ -56,7 +75,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/ivFavorite"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/twotone_quickreply_24" />
|
||||
|
@ -66,10 +84,9 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/twotone_star_24" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</eu.faircode.email.ViewCardOptional>
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
|
Loading…
Reference in New Issue