Compare commits

...

5 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 0bc34daf35 move ConversationListRelayingActivity.finishActivity into completion callback
Agent-Logs-Url: https://github.com/ArcaneChat/android/sessions/97d2da3a-a390-4296-9c53-970922fe75f1

Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-05-12 22:16:48 +00:00
copilot-swe-agent[bot] c47482851b guard recoding progress dialog creation
Agent-Logs-Url: https://github.com/ArcaneChat/android/sessions/b8e9e663-8e3c-4ea7-bed3-67efe44ad239

Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-05-12 17:55:43 +00:00
copilot-swe-agent[bot] e2fb3968ca delay finishing until relay completion
Agent-Logs-Url: https://github.com/ArcaneChat/android/sessions/b8e9e663-8e3c-4ea7-bed3-67efe44ad239

Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-05-12 17:53:40 +00:00
copilot-swe-agent[bot] ceffc5df1c address code review: use AtomicReference, remove redundant null check, log failed videos
Agent-Logs-Url: https://github.com/ArcaneChat/android/sessions/46f23f6d-d5a5-48b9-8b1d-4aa5cfdda115

Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-04-29 15:00:18 +00:00
copilot-swe-agent[bot] e6fd96bf35 recode videos when multiple are shared/attached, show progress dialog
Agent-Logs-Url: https://github.com/ArcaneChat/android/sessions/46f23f6d-d5a5-48b9-8b1d-4aa5cfdda115

Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-04-29 14:57:53 +00:00
4 changed files with 136 additions and 51 deletions
@@ -122,9 +122,6 @@ public abstract class BaseConversationListFragment extends Fragment implements A
Context context = getContext(); Context context = getContext();
if (context != null) { if (context != null) {
if (SendRelayedMessageUtil.containsVideoType(context, uris)) {
message += "\n\n" + getString(R.string.videos_sent_without_recoding);
}
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setMessage(message) .setMessage(message)
.setCancelable(false) .setCancelable(false)
@@ -132,11 +129,16 @@ public abstract class BaseConversationListFragment extends Fragment implements A
.setPositiveButton( .setPositiveButton(
R.string.menu_send, R.string.menu_send,
(dialog, which) -> { (dialog, which) -> {
Activity activity = getActivity();
if (activity == null) {
return;
}
SendRelayedMessageUtil.immediatelyRelay( SendRelayedMessageUtil.immediatelyRelay(
getActivity(), selectedChats.toArray(new Long[selectedChats.size()])); activity,
selectedChats.toArray(new Long[selectedChats.size()]),
() -> activity.finish());
actionMode.finish(); actionMode.finish();
actionMode = null; actionMode = null;
getActivity().finish();
}) })
.show(); .show();
} }
@@ -860,9 +860,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void askSendingFiles(ArrayList<Uri> uriList, Runnable onConfirm) { private void askSendingFiles(ArrayList<Uri> uriList, Runnable onConfirm) {
String message = String message =
String.format(getString(R.string.ask_send_files_to_chat), uriList.size(), dcChat.getName()); String.format(getString(R.string.ask_send_files_to_chat), uriList.size(), dcChat.getName());
if (SendRelayedMessageUtil.containsVideoType(context, uriList)) {
message += "\n\n" + getString(R.string.videos_sent_without_recoding);
}
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setMessage(message) .setMessage(message)
.setCancelable(false) .setCancelable(false)
@@ -626,14 +626,18 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
final DcContext dcContext = DcHelper.getContext(this); final DcContext dcContext = DcHelper.getContext(this);
int fwdAccId = getForwardedMessageAccountId(this); int fwdAccId = getForwardedMessageAccountId(this);
if (fwdAccId == dcContext.getAccountId() && dcContext.getChat(chatId).isSelfTalk()) { if (fwdAccId == dcContext.getAccountId() && dcContext.getChat(chatId).isSelfTalk()) {
SendRelayedMessageUtil.immediatelyRelay(this, chatId); SendRelayedMessageUtil.immediatelyRelay(
Toast.makeText( this,
this, chatId,
DynamicTheme.getCheckmarkEmoji(this) + " " + getString(R.string.saved), () -> {
Toast.LENGTH_SHORT) Toast.makeText(
.show(); this,
handleResetRelaying(); DynamicTheme.getCheckmarkEmoji(this) + " " + getString(R.string.saved),
finish(); Toast.LENGTH_SHORT)
.show();
handleResetRelaying();
finish();
});
} else { } else {
Intent intent = new Intent(this, ConversationActivity.class); Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ACCOUNT_ID_EXTRA, dcContext.getAccountId()); intent.putExtra(ConversationActivity.ACCOUNT_ID_EXTRA, dcContext.getAccountId());
@@ -9,6 +9,7 @@ import static org.thoughtcrime.securesms.util.ShareUtil.isSharing;
import static org.thoughtcrime.securesms.util.ShareUtil.resetRelayingMessageContent; import static org.thoughtcrime.securesms.util.ShareUtil.resetRelayingMessageContent;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
@@ -26,57 +27,75 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.thoughtcrime.securesms.ConversationListRelayingActivity; import org.thoughtcrime.securesms.ConversationListRelayingActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.providers.PersistentBlobProvider; import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
import org.thoughtcrime.securesms.video.recode.VideoRecoder;
public class SendRelayedMessageUtil { public class SendRelayedMessageUtil {
private static final String TAG = SendRelayedMessageUtil.class.getSimpleName(); private static final String TAG = SendRelayedMessageUtil.class.getSimpleName();
public static void immediatelyRelay(Activity activity, int chatId) { public static void immediatelyRelay(Activity activity, int chatId) {
immediatelyRelay(activity, new Long[] {(long) chatId}); immediatelyRelay(activity, chatId, null);
}
public static void immediatelyRelay(Activity activity, int chatId, Runnable onCompletion) {
immediatelyRelay(activity, new Long[] {(long) chatId}, onCompletion);
} }
public static void immediatelyRelay(Activity activity, final Long[] chatIds) { public static void immediatelyRelay(Activity activity, final Long[] chatIds) {
ConversationListRelayingActivity.finishActivity(); immediatelyRelay(activity, chatIds, null);
}
public static void immediatelyRelay(
Activity activity, final Long[] chatIds, Runnable onCompletion) {
if (isForwarding(activity)) { if (isForwarding(activity)) {
int forwardedMsgAccId = getForwardedMessageAccountId(activity); int forwardedMsgAccId = getForwardedMessageAccountId(activity);
int[] forwardedMessageIDs = getForwardedMessageIDs(activity); int[] forwardedMessageIDs = getForwardedMessageIDs(activity);
resetRelayingMessageContent(activity); resetRelayingMessageContent(activity);
if (forwardedMessageIDs == null || forwardedMsgAccId <= 0) return; if (forwardedMessageIDs == null || forwardedMsgAccId <= 0) {
runOnCompletion(onCompletion);
return;
}
Util.runOnAnyBackgroundThread( Util.runOnAnyBackgroundThread(
() -> { () -> {
DcContext dcContext = DcHelper.getContext(activity); try {
int accId = dcContext.getAccountId(); DcContext dcContext = DcHelper.getContext(activity);
if (forwardedMsgAccId != accId) { int accId = dcContext.getAccountId();
Rpc rpc = DcHelper.getRpc(activity); if (forwardedMsgAccId != accId) {
List<Integer> list = Util.toList(forwardedMessageIDs); Rpc rpc = DcHelper.getRpc(activity);
for (long longChatId : chatIds) { List<Integer> list = Util.toList(forwardedMessageIDs);
try { for (long longChatId : chatIds) {
rpc.forwardMessagesToAccount(forwardedMsgAccId, list, accId, (int) longChatId); try {
} catch (RpcException e) { rpc.forwardMessagesToAccount(forwardedMsgAccId, list, accId, (int) longChatId);
e.printStackTrace(); } catch (RpcException e) {
} e.printStackTrace();
}
return;
}
for (long longChatId : chatIds) {
int chatId = (int) longChatId;
if (dcContext.getChat(chatId).isSelfTalk()) {
for (int msgId : forwardedMessageIDs) {
DcMsg msg = dcContext.getMsg(msgId);
if (msg.canSave() && msg.getSavedMsgId() == 0 && msg.getChatId() != chatId) {
dcContext.saveMsgs(new int[] {msgId});
} else {
handleForwarding(activity, chatId, new int[] {msgId});
} }
} }
} else { return;
handleForwarding(activity, chatId, forwardedMessageIDs);
} }
for (long longChatId : chatIds) {
int chatId = (int) longChatId;
if (dcContext.getChat(chatId).isSelfTalk()) {
for (int msgId : forwardedMessageIDs) {
DcMsg msg = dcContext.getMsg(msgId);
if (msg.canSave() && msg.getSavedMsgId() == 0 && msg.getChatId() != chatId) {
dcContext.saveMsgs(new int[] {msgId});
} else {
handleForwarding(activity, chatId, new int[] {msgId});
}
}
} else {
handleForwarding(activity, chatId, forwardedMessageIDs);
}
}
} finally {
runOnCompletion(onCompletion);
} }
}); });
} else if (isSharing(activity)) { } else if (isSharing(activity)) {
@@ -88,14 +107,30 @@ public class SendRelayedMessageUtil {
resetRelayingMessageContent(activity); resetRelayingMessageContent(activity);
Util.runOnAnyBackgroundThread( Util.runOnAnyBackgroundThread(
() -> { () -> {
for (long chatId : chatIds) { try {
sendMultipleMsgs( for (long chatId : chatIds) {
activity, (int) chatId, sharedUris, msgType, sharedHtml, subject, sharedText); sendMultipleMsgs(
activity, (int) chatId, sharedUris, msgType, sharedHtml, subject, sharedText);
}
} finally {
runOnCompletion(onCompletion);
} }
}); });
} else {
runOnCompletion(onCompletion);
} }
} }
private static void runOnCompletion(Runnable onCompletion) {
Util.runOnMain(
() -> {
ConversationListRelayingActivity.finishActivity();
if (onCompletion != null) {
onCompletion.run();
}
});
}
private static void handleForwarding(Context context, int chatId, int[] forwardedMessageIDs) { private static void handleForwarding(Context context, int chatId, int[] forwardedMessageIDs) {
DcContext dcContext = DcHelper.getContext(context); DcContext dcContext = DcHelper.getContext(context);
dcContext.forwardMsgs(forwardedMessageIDs, chatId); dcContext.forwardMsgs(forwardedMessageIDs, chatId);
@@ -118,17 +153,64 @@ public class SendRelayedMessageUtil {
ArrayList<Uri> uris = sharedUris; ArrayList<Uri> uris = sharedUris;
String text = sharedText; String text = sharedText;
boolean hasVideos = containsVideoType(context, uris);
AtomicReference<ProgressDialog> progressDialogRef = new AtomicReference<>(null);
if (hasVideos && context instanceof Activity) {
Activity activity = (Activity) context;
Util.runOnMain(
() -> {
try {
if (!activity.isFinishing()) {
progressDialogRef.set(
ProgressDialog.show(
activity, "", context.getString(R.string.one_moment), true, false));
}
} catch (RuntimeException e) {
Log.w(TAG, "Failed to show recoding progress dialog", e);
}
});
}
if (uris.size() == 1) { if (uris.size() == 1) {
dcContext.sendMsg( DcMsg msg = createMessage(context, uris.get(0), msgType, sharedHtml, subject, text);
chatId, createMessage(context, uris.get(0), msgType, sharedHtml, subject, text)); if (msg.getType() == DcMsg.DC_MSG_VIDEO) {
if (!VideoRecoder.prepareVideo(context, chatId, msg)) {
dismissProgressDialog(progressDialogRef);
return;
}
}
dcContext.sendMsg(chatId, msg);
} else { } else {
if (text != null || sharedHtml != null) { if (text != null || sharedHtml != null) {
dcContext.sendMsg(chatId, createMessage(context, null, null, sharedHtml, subject, text)); dcContext.sendMsg(chatId, createMessage(context, null, null, sharedHtml, subject, text));
} }
for (Uri uri : uris) { for (Uri uri : uris) {
dcContext.sendMsg(chatId, createMessage(context, uri, null, null, subject, null)); DcMsg msg = createMessage(context, uri, null, null, subject, null);
if (msg.getType() == DcMsg.DC_MSG_VIDEO) {
if (!VideoRecoder.prepareVideo(context, chatId, msg)) {
Log.w(TAG, "prepareVideo failed for " + uri + ", skipping");
continue;
}
}
dcContext.sendMsg(chatId, msg);
} }
} }
dismissProgressDialog(progressDialogRef);
}
private static void dismissProgressDialog(AtomicReference<ProgressDialog> progressDialogRef) {
ProgressDialog dialog = progressDialogRef.get();
if (dialog != null) {
Util.runOnMain(
() -> {
try {
dialog.dismiss();
} catch (final IllegalArgumentException e) {
// The activity is finishing/destroyed, do nothing.
}
});
}
} }
public static boolean containsVideoType(Context context, ArrayList<Uri> uris) { public static boolean containsVideoType(Context context, ArrayList<Uri> uris) {