The previous AccessibilityDelegateCompat approach had two fatal flaws:
1. The delegate was only set when isTouchExplorationEnabled() returned
true AT BIND TIME — a timing bug that caused TalkBack to see no
actions if the view was bound before TalkBack fully initialised.
2. Even when set, the delegate/custom-action-ID approach did not
reliably produce an "Actions" submenu in the TalkBack local context
menu on Android 14+.
Replace the entire mechanism with ViewCompat.addAccessibilityAction(),
the modern API (androidx.core 1.5.0+) that TalkBack always surfaces
under "Actions". Actions are registered unconditionally at bind time;
stale actions from recycled views are removed via
ViewCompat.removeAccessibilityAction() before re-registration.
Delete the now-unused LinkAccessibilityDelegate class.
Agent-Logs-Url: https://github.com/ArcaneChat/android/sessions/95854760-c8e5-43d8-b7b4-55879a7c5dea
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
The previous code used View.AccessibilityDelegate (raw framework) and
AccessibilityNodeInfoCompat.wrap() which is deprecated and does not
reliably propagate addAction() to the real AccessibilityNodeInfo that
TalkBack reads.
Switch to AccessibilityDelegateCompat (AndroidX) set via
ViewCompat.setAccessibilityDelegate(). Its onInitializeAccessibilityNodeInfo
callback receives a properly-backed AccessibilityNodeInfoCompat so
info.addAction() reliably surfaces custom actions in the TalkBack
context menu (L-gesture) on all Android versions including API 36.
Also clear the delegate in the CALL/empty-text branch to prevent a
stale delegate remaining on a recycled view.
Agent-Logs-Url: https://github.com/ArcaneChat/android/sessions/87aa7735-a87e-473d-b80c-67e697cd4fa7
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
- Explain why accessibility delegate is not set during batch selection
- Explain why map is cleared and rebuilt on each accessibility update
- Improves code maintainability and readability
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
- Reuse LinkAccessibilityDelegate instance instead of creating new one each time
- Add detailed comment explaining the magic number for action IDs
- Improves performance by avoiding unnecessary object allocations
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
- Added accessibility_link_action string resource
- Updated LinkAccessibilityDelegate to accept Context and use resource
- Updated ConversationItem to pass context to delegate
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
- Created LinkAccessibilityDelegate to expose links as custom actions
- Updated ConversationItem to use delegate when TalkBack is enabled
- Each link becomes a separate accessible action with clear label
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
Avatar-images with a resolution larger than 512x512 will be resized by Chatmail Core, while media-quality is set to balanced, which is currently the highest quality-setting.
Co-authored-by: Hocuri <hocuri@gmx.de>
that way, the end is always visible,
which contains important information more often than the middle.
this is common knowledge since the 90's or so
however, as quite some previously stable ux patterns, lost on the way.
(cmp. Scott Jensen, https://www.youtube.com/watch?v=1fZTOjd_bOQ )
clarify, that the "Add Second Device" settings are within Delta Chat,
not within system or app settings.
we got reports of ppl searching within system settings,
esp. on iOS, some apps have additional settings there,
so it is not so far fetched.
but also for other OS, the hint to start Delta Chat is useful
and not only noise.
even if that is done for non-chatmail only,
it raises false expectations for other profiles,
and here it is easy to avoid - if that is really an important information for the user,
they can add it to the label.
also, this synchronizes UI which what is done on desktop/iOS
Counterpart of https://github.com/chatmail/core/pull/6851
* Make sending of statistics into a setting
* feat: Count securejoin sources and UI paths
* feat: Rename self_reporting to send_statistics
* Adapt core's API change
* WIP, untested: Adapt to a rename on the core side
* Adapt to generated jsonrpc
* New strings and a new dialog
* Adapt to the API change
* Rewording: `...and support research`
* "More Info" button rather than link
* Small fixes
* Open the correct survey (though it doesn't work yet)
* Changelog
* Update help
* Fix compile error
* Fix compilation
* Revert submodule change
* Don't show a device message yet
* Move "Send Statistics" setting
* Fix compilation error
* Remove unused constant
---------
Co-authored-by: adb <adb@merlinux.eu>
it was renamed first on iOS from 'Chats and Media' to 'Chats'
to not confuse with 'All Apps and Media' -
however, that point is also valid for android,
but even if not, it is good for inner consistency and simpler documentation.
moreover, the settings are in reality also about contacts and more,
so just a broad chats is fine.
but also for outer consistency,
this seems better - also in quite some other apps,
it is just called 'chats'
this removes the addendum 'on all your devices'
from the 'really delete?' questions.
- after polls, and looking at what other apps are doing,
it is just the default expectation, that a message is deleted from all devices,
also, we do not have an option (nor do not want to have)
- so, at that point - fresh user, one device -
there is no need to clutter with other convepts and relativation.
also, most user will never have more devices.
- ppl anyway do not read -
but if they do, it is good to have things as much on point as possible :)
- the question fits better to the "delete for everyone" option
- simplify code and strings,
as device message deletion is no longer special
(there, we never said "on all your devices")
the addendum 'from your devices' was added as
one year ago, for technical limitations, deletion was really on one device.
when we removed that limitation, we added to addendum,
so ppl used to old apps have a chance to get the change.
meanwhile, the new default is clear and settled and the addendum
does more harm and raise questions than doing good.
instead, one should be asked whether to add a transport.
- it is very probably the more wanted action -
when one wants a new profile, it is better to learn first,
that one has to go over "switch profil"
- less can go wrong -
if ppl play around,
adding a transport is less harmful than a new profile
where they do not know how to switch, send from different ones etc.
by the bare title, this is not clear to everyone.
technically, i also tried <PreferenceCategory summary>,
but that does not wrap text.
moved down 'app picker' for better layout and to match
order of other UI.
- 'backgound' term is used in many other contextes
- 'messages' may also be confused with what the user usually thinks of being a 'message',
similar for 'send'
* deprecate 'what is webxdc?' string"
it is used when an in-app is on the screen (on desktop),
however, instead of helping, immediately raises another question,
as the user just did not know about webxdc at all at that point
(we are not using the term in the apps at all).
better just use the string 'Help' and open
offline help at #webxdc - the entry is also just improved :)
* add 'help' to app-menu
* just 'help' may be confused with 'help about that app', be little more specific
* update CHANGELOG
Before this PR, when a QR code couldn't be loaded because of https://github.com/chatmail/core/pull/7399, Delta Chat crashed.
Now, the button does nothing.
It's not perfect, but easy to do, and only about an edge case where the user tried out the experimental broadcast channels in the past, and now tries to add a new member to a broadcast channel created with an old version of DC.
The hollistic alternative would be to switch to RPC for getSecurejoinQrSvg, so that the UI can get a proper error message.
---------
Co-authored-by: adb <adb@merlinux.eu>
# GitHub Copilot Instructions for ArcaneChat Android
## Project Overview
ArcaneChat is a Delta Chat Android client built on top of the official Delta Chat client with several improvements. It is a messenger app that uses email infrastructure for secure communication.
**Technology Stack:**
- **Language:** Java (Java 8 compatibility)
- **Build System:** Gradle with Android Gradle Plugin 8.11.1
body:'[<img src="store/get-it-on-gplay.png" alt="Get it on Google Play" height="48">](https://play.google.com/store/apps/details?id=com.github.arcanechat) [<img src="store/get-it-on-fdroid.png" alt="Get it on F-Droid" height="48">](https://f-droid.org/packages/chat.delta.lite) [<img src="store/get-it-on-github.png" alt="Get it on GitHub" height="48">](https://github.com/ArcaneChat/android/releases/latest/download/ArcaneChat-gplay.apk)'
@@ -23,17 +23,14 @@ ArcaneChat is a Delta Chat client and was created with a focus on usability, goo
<li>Multiple color themes/skins</li>
<li>It is possible to disable profiles to completely disconnect them saving data/bandwidth</li>
<li>You can easily see the connection status of all your profiles in the profile switcher</li>
<li>A videochat instance is set by default</li>
<li>Extra option to share location for 12 hours</li>
<li>Clicking on a message with a POI location, will open the POI on the map</li>
<li>Last-seen status of contacts is shown in your contact list, like in WhatsApp, Telegram, etc.</li>
<li>Videos are played in loop, useful for short GIF videos</li>
<li>Verified icon is shown in the chat list for the "Device Messages" chat</li>
<li>Verified icon is shown in the chat list for the "Device Messages" and "Saved Messages" chat to avoid fishing attempts by scammer pretending to be the official chats</li>
<li>Voice messages have more aggressive compression in "worse quality" mode to save data plan</li>
<li>Automatic download of messages limited to 640KB by default</li>
<li>Profile's display name is always shown in the app's title bar instead of the name of the app</li>
<li>Your avatar is visible to other users in Mailing Lists</li>
<li>Can be selected as app to open .xdc files</li>
<li>For mini-apps developers: there are some extra features in the WebXDC API, check https://github.com/ArcaneChat/android/#webxdc</li>
<li>Better settings organization with additional "Privacy" section</li>
ArcaneChat — децентрализованный и защищённый мессенджер, удобный для друзей и семьи.
• Анонимность. Мгновенный вход без номера телефона, e-mail или других личных данных.
• Гибкость. Поддерживает несколько профилей чатов и легко настраивается на нескольких устройствах.
• Расширяемость. В чатах можно использовать мини-приложения: списки покупок, календари или игры.
• Надёжность. Работает даже при плохом соединении и в сложных сетевых условиях.
• Безопасность. Проверенное сквозное шифрование, защищённое от сетевых и серверных атак.
• Самостоятельность. Может работать с вашим собственным e-mail-адресом или сервером.
ArcaneChat — клиент Delta Chat, разработанный с акцентом на удобство, качественный UX и экономию трафика. Также приложение часто экспериментирует с новыми функциями, которые со временем могут быть добавлены в официальный клиент Delta Chat.
<b>Основные отличия от официального клиента Delta Chat:</b>
<ul>
<li>Поддержка некоторых стилей markdown в текстовых сообщениях (жирный, курсив, зачёркнутый и т.д.)</li>
/* `Automatic` means that provider database setting should be taken. If there is no provider database setting for certificate checks, check certificates strictly. */
/** `Automatic` means that provider database setting should be taken. If there is no provider database setting for certificate checks, check certificates strictly. */
automatic,
/* Ensure that TLS certificate is valid for the server hostname. */
/** Ensure that TLS certificate is valid for the server hostname. */
strict,
/* Accept certificates that are expired, self-signed or otherwise not valid for the server hostname. */
/** Accept certificates that are expired, self-signed or otherwise not valid for the server hostname. */
/** An action cannot be performed because the user is not in the group. Reported eg. after a call to setChatName(), setChatProfileImage(), addContactToChat(), removeContactFromChat(), and messages sending functions. */
/** Messages or chats changed. One or more messages or chats changed for various reasons in the database: - Messages sent, received or removed - Chats created, deleted or archived - A draft has been set */
publicstaticclassMsgsChangedextendsEventType{
/** Set if only a single chat is affected by the changes, otherwise 0. */
publicIntegerchatId;
/** Set if only a single message is affected by the changes, otherwise 0. */
/** ID of the chat where the message is assigned. */
publicIntegerchatId;
/** ID of the message. */
publicIntegermsgId;
}
/** Downloading a bunch of messages just finished. This is an event to allow the UI to only show one notification per message bunch, instead of cluttering the user with many notifications. */
/** Messages were seen or noticed. chat id is always set. */
publicstaticclassMsgsNoticedextendsEventType{
publicIntegerchatId;
}
/** A single message is sent successfully. State changed from DC_STATE_OUT_PENDING to DC_STATE_OUT_DELIVERED, see `Message.state`. */
publicstaticclassMsgDeliveredextendsEventType{
/** ID of the chat which the message belongs to. */
publicIntegerchatId;
/** ID of the message that was successfully sent. */
publicIntegermsgId;
}
/** A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to DC_STATE_OUT_FAILED, see `Message.state`. */
publicstaticclassMsgFailedextendsEventType{
/** ID of the chat which the message belongs to. */
publicIntegerchatId;
/** ID of the message that could not be sent. */
publicIntegermsgId;
}
/** A single message is read by the receiver. State changed from DC_STATE_OUT_DELIVERED to DC_STATE_OUT_MDN_RCVD, see `Message.state`. */
publicstaticclassMsgReadextendsEventType{
/** ID of the chat which the message belongs to. */
/** Location of one or more contact has changed. */
publicstaticclassLocationChangedextendsEventType{
/** contact_id of the contact for which the location has changed. If the locations of several contacts have been changed, this parameter is set to `None`. */
/** The type of the joined chat. This can take the same values as `BasicChat.chatType` ([`crate::api::types::chat::BasicChat::chat_type`]). */
publicChatTypechatType;
/** ID of the contact that wants to join. */
publicIntegercontactId;
/** Progress, always 1000. */
publicIntegerprogress;
}
/** Progress information of a secure-join handshake from the view of the joiner (Bob, the person who scans the QR code). The events are typically sent while secureJoin(), which may take some time, is executed. */
/** Progress as: 400=vg-/vc-request-with-auth sent, typically shown as "alice@addr verified, introducing myself." (Bob has verified alice and waits until Alice does the same for him) 1000=vg-member-added/vc-contact-confirm received */
publicIntegerprogress;
}
/** The connectivity to the server changed. This means that you should refresh the connectivity view and possibly the connectivtiy HTML; see getConnectivity() and getConnectivityHtml() for details. */
/** A multi-device synced config value changed. Maybe the app needs to refresh smth. For uniformity this is emitted on the source device too. The value isn't here, otherwise it would be logged which might not be good for privacy. */
/** Inform that a single chat list item changed and needs to be rerendered. If `chat_id` is set to None, then all currently visible chats need to be rerendered, and all not-visible items need to be cleared from cache if the UI has a cache. */
/** Note that this is different from [`ChatListItem::is_self_in_group`](`crate::api::types::chat_list::ChatListItemFetchResult::ChatListItem::is_self_in_group`). This property should only be accessed when [`FullChat::chat_type`] is [`Chattype::Group`]. */
/** Check if a message has a POI location bound to it. These locations are also returned by `get_locations` method. The UI may decide to display a special icon beside such messages. */
publicBooleanhasLocation;
publicIntegerid;
/** if is_info is set, this refers to the contact profile that should be opened when the info message is tapped. */
/** Check if a message has a POI location bound to it. These locations are also returned by `get_locations` method. The UI may decide to display a special icon beside such messages. */
publicBooleanhasLocation;
publicIntegerid;
/** if is_info is set, this refers to the contact profile that should be opened when the info message is tapped. */
/** Fingerprint of the contact key as scanned from the QR code. */
publicStringfingerprint;
/** Invite number. */
publicStringinvitenumber;
}
/** Ask the user whether to join the group. */
publicstaticclassAskVerifyGroupextendsQr{
/** Authentication code. */
publicStringauthcode;
/** ID of the contact. */
publicIntegercontact_id;
/** Fingerprint of the contact key as scanned from the QR code. */
publicStringfingerprint;
/** Group ID. */
publicStringgrpid;
/** Group name. */
publicStringgrpname;
/** Invite number. */
publicStringinvitenumber;
}
/** Ask the user whether to join the broadcast channel. */
publicstaticclassAskJoinBroadcastextendsQr{
/** Authentication code. */
publicStringauthcode;
/** ID of the contact who owns the broadcast channel and created the QR code. */
publicIntegercontact_id;
/** Fingerprint of the broadcast channel owner's key as scanned from the QR code. */
publicStringfingerprint;
/** A string of random characters, uniquely identifying this broadcast channel across all databases/clients. Called `grpid` for historic reasons: The id of multi-user chats is always called `grpid` in the database because groups were once the only multi-user chats. */
publicStringgrpid;
/** Invite number. */
publicStringinvitenumber;
/** The user-visible name of this broadcast channel */
publicStringname;
}
/**
*Contactfingerprintisverified.
*<p>
*Asktheuseriftheywanttostartchatting.
*/
publicstaticclassFprOkextendsQr{
/** Contact ID. */
publicIntegercontact_id;
}
/** Scanned fingerprint does not match the last seen fingerprint. */
/** A voice message that was directly recorded by the user. For all other audio messages, the type `Viewtype.Audio` should be used. */
Voice,
/** Video messages. */
Video,
/** Message containing any file, eg. a PDF. */
File,
/** Message is a call. */
Call,
/** Message is an webxdc instance. */
Webxdc,
/** Message containing shared contacts represented as a vCard (virtual contact file) with email addresses and possibly other fields. Use `parse_vcard()` to retrieve them. */
/** True if full internet access should be granted to the app. */
publicBooleaninternetAccess;
/**
*Thenameoftheapp.
*<p>
*Defaultstothefilenameifnotsetinthemanifest.
*/
publicStringname;
/** Address to be used for `window.webxdc.selfAddr` in JS land. */
publicStringselfAddr;
/** Milliseconds to wait before calling `sendUpdate()` again since the last call. Should be exposed to `window.sendUpdateInterval` in JS land. */
publicIntegersendUpdateInterval;
/** Maximum number of bytes accepted for a serialized update object. Should be exposed to `window.sendUpdateMaxSize` in JS land. */
publicIntegersendUpdateMaxSize;
/** URL where the source code of the Webxdc and other information can be found; defaults to an empty string. Implementations may offer an menu or a button to open this URL. */
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.