Merge branch 'master' into f/badge-subscriptions

# Conflicts:
#	simplex-chat.cabal
#	src/Simplex/Chat/Store/Postgres/Migrations.hs
#	src/Simplex/Chat/Store/SQLite/Migrations.hs
This commit is contained in:
spacedandy-agents-simplex committed 2026-10-26 07:20:22 +00:00
commit 2d2d3abeda
179 files changed
+8524 -1338

No files matched your search

@@ -96,6 +96,7 @@ class Bot(Client):
update_profile: bool = True,
auto_accept: bool = True,
business_address: bool = False,
chat_layout: T.ChatLayout | None = None,
allow_files: bool = False,
log_contacts: bool = True,
log_network: bool = False,
@@ -115,6 +116,7 @@ class Bot(Client):
self._update_address = update_address
self._auto_accept = auto_accept
self._business_address = business_address
self._chat_layout = chat_layout
self._allow_files = allow_files
# ------------------------------------------------------------------ #
@@ -153,6 +155,8 @@ class Bot(Client):
desired: T.AddressSettings = {"businessAddress": self._business_address}
if self._auto_accept:
desired["autoAccept"] = {"acceptIncognito": False}
if self._chat_layout is not None:
desired["chatLayout"] = self._chat_layout
if self._welcome is not None:
desired["autoReply"] = (
{"type": "text", "text": self._welcome}
@@ -23,6 +23,7 @@ class AddRelayResult(TypedDict):
class AddressSettings(TypedDict):
businessAddress: bool
autoAccept: NotRequired["AutoAccept"]
chatLayout: NotRequired["ChatLayout"]
autoReply: NotRequired["MsgContent"]
class AgentCryptoError_DECRYPT_AES(TypedDict):
@@ -1311,6 +1312,8 @@ class ChatItemDeletion(TypedDict):
deletedChatItem: "AChatItem"
toChatItem: NotRequired["AChatItem"]
ChatLayout = Literal["classic", "terminal"]
class ChatListQuery_filters(TypedDict):
type: Literal["filters"]
favorite: bool
@@ -1602,6 +1605,7 @@ class Contact(TypedDict):
chatTags: list[int] # int64
chatItemTTL: NotRequired[int] # int64
uiThemes: NotRequired["UIThemeEntityOverrides"]
chatLayout: NotRequired["ChatLayout"]
chatDeleted: bool
customData: NotRequired[dict[str, object]]
@@ -1643,6 +1647,7 @@ class ContactShortLinkData(TypedDict):
profile: "Profile"
message: NotRequired["MsgContent"]
business: bool
chatLayout: NotRequired["ChatLayout"]
localBadge: NotRequired["LocalBadge"]
ContactStatus = Literal["active", "deleted", "deletedByUser", "rejected"]
@@ -2175,6 +2180,7 @@ class GroupProfile(TypedDict):
publicGroup: NotRequired["PublicGroupProfile"]
groupPreferences: NotRequired["GroupPreferences"]
memberAdmission: NotRequired["GroupMemberAdmission"]
chatLayout: NotRequired["ChatLayout"]
class GroupRelay(TypedDict):
groupRelayId: int # int64
@@ -3780,6 +3786,7 @@ class UIThemeEntityOverride(TypedDict):
class UIThemeEntityOverrides(TypedDict):
light: NotRequired["UIThemeEntityOverride"]
dark: NotRequired["UIThemeEntityOverride"]
chatLayout: NotRequired["ChatLayout"]
class UpdatedMessage(TypedDict):
msgContent: "MsgContent"
@@ -729,6 +729,7 @@ class _StubApi:
def __init__(self) -> None:
self.profiles: list[dict] = []
self.address_settings: list[dict] = []
self.user: dict = {"userId": 1, "profile": {"displayName": "x", "fullName": ""}}
self.address: dict | None = None
@@ -758,8 +759,8 @@ class _StubApi:
async def api_get_user_address(self, _user_id):
return self.address
async def api_set_address_settings(self, _user_id, _settings):
pass
async def api_set_address_settings(self, _user_id, settings):
self.address_settings.append(settings)
async def send_chat_cmd(self, _cmd):
return {"type": "cmdOk"}
@@ -942,6 +943,55 @@ def test_sync_profile_keeps_the_bot_address_in_the_profile(monkeypatch):
assert api.profiles[0]["contactLink"] == "https://l"
def test_bot_address_settings_include_the_chat_layout(monkeypatch):
import simplex_chat.client as client_mod
api = _StubApi()
api.address = {
"connLinkContact": {"connFullLink": "https://l"},
"addressSettings": {"businessAddress": False, "autoAccept": {"acceptIncognito": False}},
}
monkeypatch.setattr(client_mod, "ChatApi", _init_returning(api))
bot = Bot(
profile=BotProfile(display_name="x"),
db=SqliteDb(file_prefix="/tmp/test"),
update_profile=False,
chat_layout="terminal",
)
async def go():
async with bot:
pass
asyncio.run(go())
assert api.address_settings == [
{"businessAddress": False, "autoAccept": {"acceptIncognito": False}, "chatLayout": "terminal"}
]
def test_bot_address_settings_remove_the_chat_layout_not_in_bot_settings(monkeypatch):
import simplex_chat.client as client_mod
api = _StubApi()
api.address = {
"connLinkContact": {"connFullLink": "https://l"},
"addressSettings": {"businessAddress": False, "chatLayout": "terminal"},
}
monkeypatch.setattr(client_mod, "ChatApi", _init_returning(api))
bot = Bot(
profile=BotProfile(display_name="x"),
db=SqliteDb(file_prefix="/tmp/test"),
update_profile=False,
)
async def go():
async with bot:
pass
asyncio.run(go())
assert api.address_settings == [{"businessAddress": False, "autoAccept": {"acceptIncognito": False}}]
def test_profile_can_be_replaced(monkeypatch):
c, _ = _client_with_stub_api(monkeypatch)
c.profile = Profile(display_name="other", full_name="Other")