Store message preview

pull/146/head
M66B 6 years ago
parent f60418c71b
commit dee32db0b8

File diff suppressed because it is too large Load Diff

@ -66,7 +66,6 @@ import android.widget.Toast;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.snackbar.Snackbar;
import org.jsoup.Jsoup;
import org.xml.sax.XMLReader;
import java.io.File;
@ -333,38 +332,8 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
ivAttachments.setVisibility(message.attachments > 0 ? View.VISIBLE : View.GONE);
tvSubject.setText(message.subject);
tvPreview.setVisibility(View.GONE);
if (preview && message.content) {
Bundle args = new Bundle();
args.putSerializable("message", message);
new SimpleTask<String>() {
@Override
protected void onInit(Bundle args) {
tvPreview.setHasTransientState(true);
}
@Override
protected String onLoad(Context context, Bundle args) throws Throwable {
TupleMessageEx message = (TupleMessageEx) args.getSerializable("message");
String body = message.read(context);
return Jsoup.parse(body).text();
}
@Override
protected void onLoaded(Bundle args, String preview) {
tvPreview.setText(preview);
tvPreview.setVisibility(View.VISIBLE);
tvPreview.setHasTransientState(false);
}
@Override
protected void onException(Bundle args, Throwable ex) {
tvPreview.setHasTransientState(false);
Helper.unexpectedError(context, ex);
}
}.load(context, owner, args);
}
tvPreview.setText(message.preview);
tvPreview.setVisibility(preview && !TextUtils.isEmpty(message.preview) ? View.VISIBLE : View.GONE);
if (viewType == ViewType.UNIFIED)
tvFolder.setText(message.accountName);

@ -45,7 +45,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase;
// https://developer.android.com/topic/libraries/architecture/room.html
@Database(
version = 23,
version = 24,
entities = {
EntityIdentity.class,
EntityAccount.class,
@ -284,6 +284,13 @@ public abstract class DB extends RoomDatabase {
db.execSQL("ALTER TABLE `identity` ADD COLUMN `insecure` INTEGER NOT NULL DEFAULT 0");
}
})
.addMigrations(new Migration(23, 24) {
@Override
public void migrate(SupportSQLiteDatabase db) {
Log.i(Helper.TAG, "DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `message` ADD COLUMN `preview` TEXT");
}
})
.build();
}

@ -158,6 +158,11 @@ public interface DaoMessage {
" AND ui_seen")
List<EntityMessage> getMessageSeen(long folder);
@Query("SELECT id FROM message" +
" WHERE content" +
" AND preview IS NULL")
List<Long> getMessageWithoutPreview();
@Query("SELECT message.*" +
", account.name AS accountName, account.color AS accountColor" +
", folder.name AS folderName, folder.display AS folderDisplay, folder.type AS folderType" +
@ -220,8 +225,8 @@ public interface DaoMessage {
@Query("UPDATE message SET error = :error WHERE id = :id")
int setMessageError(long id, String error);
@Query("UPDATE message SET content = :content WHERE id = :id")
int setMessageContent(long id, boolean content);
@Query("UPDATE message SET content = NOT preview IS NULL, preview = :preview WHERE id = :id")
int setMessageContent(long id, String preview);
@Query("UPDATE message SET headers = :headers WHERE id = :id")
int setMessageHeaders(long id, String headers);

@ -94,6 +94,7 @@ public class EntityMessage implements Serializable {
public Integer size;
@NonNull
public Boolean content = false;
public String preview;
public Long sent; // compose = null
@NonNull
public Long received; // compose = stored
@ -198,6 +199,7 @@ public class EntityMessage implements Serializable {
(this.subject == null ? other.subject == null : this.subject.equals(other.subject)) &&
(this.size == null ? other.size == null : this.size.equals(other.size)) &&
this.content == other.content &&
(this.preview == null ? other.preview == null : this.preview.equals(other.preview)) &&
(this.sent == null ? other.sent == null : this.sent.equals(other.sent)) &&
this.received.equals(other.received) &&
this.stored.equals(other.stored) &&

@ -19,9 +19,12 @@ package eu.faircode.email;
Copyright 2018 by Marcel Bokhorst (M66B)
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -29,6 +32,10 @@ import android.widget.AdapterView;
import android.widget.CompoundButton;
import android.widget.Spinner;
import org.jsoup.Jsoup;
import java.io.IOException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
@ -113,6 +120,36 @@ public class FragmentOptions extends FragmentEx {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("preview", checked).apply();
if (checked)
new SimpleTask<Void>() {
@Override
protected Void onLoad(Context context, Bundle args) {
DB db = DB.getInstance(context);
ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
boolean metered = (cm == null || cm.isActiveNetworkMetered());
for (Long id : db.message().getMessageWithoutPreview()) {
EntityMessage message = db.message().getMessage(id);
try {
Log.i(Helper.TAG, "Building preview id=" + id);
String html = message.read(context);
String text = Jsoup.parse(html).text();
String preview = text.substring(0, Math.min(text.length(), 250));
db.message().setMessageContent(message.id, preview);
} catch (IOException ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
db.message().setMessageContent(message.id, null);
if (!metered)
EntityOperation.queue(db, message, EntityOperation.BODY);
}
}
EntityOperation.process(context);
return null;
}
}.load(FragmentOptions.this, null);
}
});

@ -61,6 +61,7 @@ import com.sun.mail.util.MailConnectException;
import org.json.JSONArray;
import org.json.JSONException;
import org.jsoup.Jsoup;
import java.io.IOException;
import java.net.SocketException;
@ -134,6 +135,7 @@ public class ServiceSynchronize extends LifecycleService {
private static final int SYNC_BATCH_SIZE = 20;
private static final int DOWNLOAD_BATCH_SIZE = 20;
private static final long RECONNECT_BACKOFF = 90 * 1000L; // milliseconds
private static final int PREVIEW_SIZE = 250;
static final int PI_CLEAR = 1;
static final int PI_SEEN = 2;
@ -1432,8 +1434,11 @@ public class ServiceSynchronize extends LifecycleService {
throw new MessageRemovedException();
MessageHelper helper = new MessageHelper((MimeMessage) imessage);
message.write(this, helper.getHtml());
db.message().setMessageContent(message.id, true);
String html = helper.getHtml();
String text = Jsoup.parse(html).text();
String preview = text.substring(0, Math.min(text.length(), PREVIEW_SIZE));
message.write(this, html);
db.message().setMessageContent(message.id, preview);
}
private void doAttachment(EntityFolder folder, EntityOperation op, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws JSONException, MessagingException, IOException {
@ -1890,8 +1895,11 @@ public class ServiceSynchronize extends LifecycleService {
if (!message.content)
if (!metered || (message.size != null && message.size < download)) {
message.write(context, helper.getHtml());
db.message().setMessageContent(message.id, true);
String html = helper.getHtml();
String text = Jsoup.parse(html).text();
String preview = text.substring(0, Math.min(text.length(), PREVIEW_SIZE));
message.write(context, html);
db.message().setMessageContent(message.id, preview);
Log.i(Helper.TAG, folder.name + " downloaded message id=" + message.id + " size=" + message.size);
}

Loading…
Cancel
Save