Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android_app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {

defaultConfig {
applicationId "com.asp.android_app"
minSdk 24
minSdk 26
targetSdk 35
versionCode 1
versionName "1.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.asp.android_app.api;

import com.asp.android_app.model.User;
import com.asp.android_app.model.request.LoginRequest;
import com.asp.android_app.model.request.ProfileImageRequest;
import com.asp.android_app.model.request.RegisterRequest;
import com.asp.android_app.model.response.AuthResponse;
import com.asp.android_app.model.response.UserInfo;
import com.asp.android_app.model.response.UserSearchResult;
Expand All @@ -25,7 +25,7 @@
public interface UserApi {

@POST("users")
Call<AuthResponse> register(@Body User user);
Call<AuthResponse> register(@Body RegisterRequest request);

@POST("tokens")
Call<AuthResponse> login(@Body LoginRequest loginRequest);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Updated MailEntity.java
package com.asp.android_app.caching.entities;

import androidx.room.Entity;
Expand All @@ -8,7 +9,7 @@
* Room cache model for a Mail.
* - Denormalized for speed (flags directly on the row).
* - We keep a few denormalized sender fields so lists render without joins.
* - Recipients & attachment names are stored as JSON strings (simple & fast).
* - Recipients & attachment data are stored as JSON strings (simple & fast).
* <p>
* NOTE: We sort by sentAtEpoch (fallback to createdAtEpoch) to match backend's order.
*/
Expand Down Expand Up @@ -56,7 +57,7 @@ public class MailEntity {

// JSON blobs to keep schema simple
public String recipientsJson; // List<UserLite> as JSON
public String attachmentNamesJson; // List<String> names only
public String attachmentsJson; // CHANGED: Full File objects as JSON instead of just names

// Bookkeeping for cache eviction (simple LRU)
public long lastAccessEpoch; // updated whenever we read/open
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Updated JsonConverters.java
package com.asp.android_app.caching.utils;

import androidx.annotation.Nullable;
import androidx.room.TypeConverter;

import com.asp.android_app.caching.entities.UserLite;
import com.asp.android_app.model.response.File;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

Expand All @@ -13,14 +15,16 @@

/**
* Room TypeConverters for small JSON blobs.
* - List<String> for attachment names
* - List<String> for simple string lists
* - List<UserLite> for recipients
* - List<File> for complete attachment information
* Keeping JSON simple avoids extra tables until we actually need them.
*/
public class JsonConverters {
private static final Gson gson = new Gson();
private static final Type LIST_STRING = new TypeToken<List<String>>() {}.getType();
private static final Type LIST_USERLITE = new TypeToken<List<UserLite>>() {}.getType();
private static final Type LIST_FILE = new TypeToken<List<File>>() {}.getType(); // ADDED

@TypeConverter
public static String listStringToJson(@Nullable List<String> list) {
Expand All @@ -43,4 +47,16 @@ public static List<UserLite> jsonToListUserLite(@Nullable String json) {
if (json == null || json.isEmpty()) return Collections.emptyList();
return gson.fromJson(json, LIST_USERLITE);
}
}

// ADDED: Converters for File objects
@TypeConverter
public static String listFileToJson(@Nullable List<File> list) {
return gson.toJson(list == null ? Collections.<File>emptyList() : list, LIST_FILE);
}

@TypeConverter
public static List<File> jsonToListFile(@Nullable String json) {
if (json == null || json.isEmpty()) return Collections.emptyList();
return gson.fromJson(json, LIST_FILE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.asp.android_app.caching.entities.UserLite;
import com.asp.android_app.model.Label;
import com.asp.android_app.model.Mail;
import com.asp.android_app.model.response.Attachment;
import com.asp.android_app.model.response.File;
import com.asp.android_app.model.response.UserInfo;
import com.google.gson.Gson;

Expand All @@ -26,7 +26,8 @@ private MailMappers() {}
public static MailEntity toEntity(Mail m) {
MailEntity e = new MailEntity();
e.id = m.getId();
e.ownerId = m.getSender() != null ? m.getSender().getId() : 0; // server stores owner separately; we keep sender id for "sent" check using fromId==ownerId
e.ownerId = m.getSender() != null ? m.getSender().getId() : 0;

// sender
UserInfo from = m.getSender();
e.fromId = (from != null ? from.getId() : 0);
Expand All @@ -37,20 +38,18 @@ public static MailEntity toEntity(Mail m) {
e.subject = m.getSubject();
e.body = m.getBody();

e.sentAtRaw = m.getSentAt(); // can be null/empty
e.createdAtRaw = m.getSentAt() == null ? "" : m.getSentAt(); // if you also expose createdAt in model, swap here
// you have createdAt in Mail; let's parse both
e.createdAtRaw = m.getClass().getDeclaredFields() != null ? (m.getClass() != null ? m.getClass().getName() : "") : e.createdAtRaw; // noop to avoid warnings
// actually parse safely:
e.sentAtRaw = m.getSentAt();
e.sentAtEpoch = parseIsoToEpoch(m.getSentAt());
// createdAt exists in Mail class:

// Handle createdAt properly
try {
java.lang.reflect.Method getCreatedAt = m.getClass().getMethod("getCreatedAt");
Object raw = getCreatedAt.invoke(m);
e.createdAtRaw = raw != null ? raw.toString() : "";
e.createdAtEpoch = parseIsoToEpoch(e.createdAtRaw);
} catch (Exception ignore) {
e.createdAtEpoch = 0L;
e.createdAtRaw = e.sentAtRaw; // fallback
e.createdAtEpoch = e.sentAtEpoch;
}

e.isDraft = m.isDraft();
Expand All @@ -68,20 +67,67 @@ public static MailEntity toEntity(Mail m) {
}
e.recipientsJson = gson.toJson(recips);

// attachment names only
List<String> names = new ArrayList<>();
if (m.getAttachments() != null) {
for (Attachment a : m.getAttachments()) {
names.add(a.getName());
}
}
e.attachmentNamesJson = gson.toJson(names);
// FIXED: Store complete File objects instead of just names
e.attachmentsJson = gson.toJson(m.getAttachments() != null ? m.getAttachments() : new ArrayList<>());

// default LRU timestamp now
e.lastAccessEpoch = System.currentTimeMillis();
return e;
}

/**
* Convert MailEntity back to Mail object with complete attachment information
*/
public static Mail fromEntity(MailEntity e) {
Mail m = new Mail();
m.setId(e.id);

// Reconstruct sender
UserInfo sender = new UserInfo(e.fromEmail, e.fromName);
try {
java.lang.reflect.Field fId = sender.getClass().getDeclaredField("id");
fId.setAccessible(true);
fId.set(sender, e.fromId);
java.lang.reflect.Field fImg = sender.getClass().getDeclaredField("image");
fImg.setAccessible(true);
fImg.set(sender, e.fromImageUrl);
} catch (Exception ignore) {}

m.setSubject(e.subject);
m.setBody(e.body);

// Set dates
try {
java.lang.reflect.Field fSentAt = m.getClass().getDeclaredField("sentAt");
fSentAt.setAccessible(true);
fSentAt.set(m, e.sentAtRaw);
java.lang.reflect.Field fCreatedAt = m.getClass().getDeclaredField("createdAt");
fCreatedAt.setAccessible(true);
fCreatedAt.set(m, e.createdAtRaw);
java.lang.reflect.Field fFrom = m.getClass().getDeclaredField("from");
fFrom.setAccessible(true);
fFrom.set(m, sender);
} catch (Exception ignore) {}

// flags
m.setIsRead(e.isRead);
m.setStarred(e.isStarred);
m.setTrashed(e.isTrashed);
m.setSpam(e.isSpam);
m.setIsDraft(e.isDraft);

// FIXED: Reconstruct complete attachments from JSON
try {
java.lang.reflect.Type fileListType = new com.google.gson.reflect.TypeToken<List<File>>(){}.getType();
List<File> attachments = gson.fromJson(e.attachmentsJson, fileListType);
m.setAttachments(attachments != null ? attachments : new ArrayList<>());
} catch (Exception ignore) {
m.setAttachments(new ArrayList<>());
}

return m;
}

public static List<Integer> labelIds(List<Label> labels) {
if (labels == null) return new ArrayList<>();
return labels.stream().map(Label::getId).collect(Collectors.toList());
Expand All @@ -95,4 +141,4 @@ private static long parseIsoToEpoch(String iso) {
return 0L;
}
}
}
}
14 changes: 11 additions & 3 deletions android_app/app/src/main/java/com/asp/android_app/model/Mail.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.asp.android_app.model;

import com.asp.android_app.model.response.Attachment;
import com.asp.android_app.model.response.File;
import com.asp.android_app.model.response.UserInfo;

import java.util.List;
Expand All @@ -26,7 +26,7 @@ public class Mail {
private boolean isStarred;
private boolean isTrashed;
private boolean isSpam;
private List<Attachment> files;
private List<File> files;
private List<Label> labels;

/**
Expand Down Expand Up @@ -57,6 +57,10 @@ public List<UserInfo> getSentTo() {
return sentTo;
}

public void setSentTo(List<UserInfo> sentTo) {
this.sentTo = sentTo;
}

/**
* @return the subject of the mail
*/
Expand Down Expand Up @@ -162,10 +166,14 @@ public void setIsDraft(boolean isDraft) {
/**
* @return list of files attached to mail
*/
public List<Attachment> getAttachments() {
public List<File> getAttachments() {
return files;
}

public void setAttachments(List<File> files) {
this.files = files;
}

/**
* @return list of labels objects the mail is marked with
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ public String getMail() {
return mail;
}

public String getDateOfBirth() {
return this.dateOfBirth;
}

public String getImage() {
return this.image;
}

/**
* @param mail the email address to set
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.asp.android_app.model.request;

import com.asp.android_app.model.User;
import com.google.gson.annotations.SerializedName;

public class RegisterRequest {

@SerializedName("fullName")
private String fullName;

@SerializedName("mail")
private String mail;

@SerializedName("password")
private String password;

@SerializedName("dateOfBirth")
private String dateOfBirth;

@SerializedName("image")
private String image;

public RegisterRequest(String fullName, String mail, String password, String dateOfBirth, String image) {
this.fullName = fullName;
this.mail = mail;
this.password = password;
this.dateOfBirth = dateOfBirth;
this.image = image;
}

public RegisterRequest(User user) {
this.fullName = user.getFullName();
this.mail = user.getMail();
this.password = user.getPassword();
this.dateOfBirth = user.getDateOfBirth();
this.image = user.getImage();
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.asp.android_app.model.request;

import com.asp.android_app.model.response.Attachment;
import com.asp.android_app.model.response.File;

import java.util.List;

Expand All @@ -12,9 +12,9 @@ public class SendMailRequest {
private String body;
private List<String> sentTo;
private boolean saveAsDraft;
private List<Attachment> files;
private List<File> files;

public SendMailRequest(String subject, String body, List<String> sentTo, boolean saveAsDraft, List<Attachment> files) {
public SendMailRequest(String subject, String body, List<String> sentTo, boolean saveAsDraft, List<File> files) {
this.subject = subject;
this.body = body;
this.sentTo = sentTo;
Expand Down
Loading