mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-04 10:47:32 +00:00
core, ui: terminal chat layout for LLM and service bot chats (#7811)
* plan: UI improvements to improve LLM usage via SimpleX * core, ui: types for chat layout * core, ui: settings for alternative terminal-like chat layout for managing LLMs or other service bots * plan: message priority * fixes * query plan * update plans * remove silent messages plan * rename migrations * implement layout * amend * fix * fix * fix * improve * time on the right, sender name in blue * no avatar in direct chats * better previews * update, fixes * update * time gap * changes * ui: terminal layout line heights, gaps and time placement * ui: simplify terminal meta layout, correct its docs and tests * ui: right-to-left emoji edge in terminal rows, time placement tests * android, desktop: raise Kotlin compiler memory to 4 GB * ui: terminal captions as follow-up text, classic event separators * ui: terminal media edge and overlay time, plan decisions * ui: simplify terminal row separation, correct doc line references * ui: keep the media time inside terminal rows, restore caption conditions * ui: terminal heading capitals at large font scales, idle live message time * ui: rename the classic voice-with-text flag, correct the meta copy docs * ui: smaller terminal layout diff, sender gap and meta names * ui: terminal row as tall as the media time * docs: remove the chat layout section from the bots readme * docs: shorten the terminal layout section of the chat view * core: address settings API as on master, /auto_accept reads the stored layout * ui: smaller terminal headings * ui: classic sender rows and avatar rule as on master * ui: classic reply quote text colour as on master * ios: keep the chat layout setting with other UI settings * ui: go-to button at the end of terminal rows, no gutter in direct chats * ui: forwarded arrow on the header line of terminal rows, above the time * ui: forwarded arrow centred above the time line of terminal rows --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
1 parent
4f81c6f632
commit
7810fc4752
103 files changed
+5098
-901
No files matched your search
@@ -39,12 +39,15 @@ export interface BotAddressSettings {
|
||||
* @default false
|
||||
*/
|
||||
businessAddress?: boolean
|
||||
|
||||
chatLayout?: T.ChatLayout
|
||||
}
|
||||
|
||||
export const defaultBotAddressSettings: BotAddressSettings = {
|
||||
autoAccept: true,
|
||||
welcomeMessage: undefined,
|
||||
businessAddress: false
|
||||
businessAddress: false,
|
||||
chatLayout: undefined
|
||||
}
|
||||
|
||||
export type EventSubscriberFunc<K extends CEvt.Tag> = (event: ChatEvent & {type: K}, chat: ChatApi) => void | Promise<void>
|
||||
@@ -413,12 +416,13 @@ export class ChatApi {
|
||||
* Set bot address settings.
|
||||
* Network usage: interactive.
|
||||
*/
|
||||
async apiSetAddressSettings(userId: number, {autoAccept, welcomeMessage, businessAddress}: BotAddressSettings): Promise<void> {
|
||||
async apiSetAddressSettings(userId: number, {autoAccept, welcomeMessage, businessAddress, chatLayout}: BotAddressSettings): Promise<void> {
|
||||
const autoReply = welcomeMessage || defaultBotAddressSettings.welcomeMessage
|
||||
const settings: T.AddressSettings = {
|
||||
autoAccept: (autoAccept === undefined ? defaultBotAddressSettings.autoAccept : autoAccept) ? {acceptIncognito: false} : undefined,
|
||||
autoReply: typeof autoReply === "string" ? {type: "text", text: autoReply} : autoReply,
|
||||
businessAddress: businessAddress || defaultBotAddressSettings.businessAddress || false
|
||||
businessAddress: businessAddress || defaultBotAddressSettings.businessAddress || false,
|
||||
chatLayout
|
||||
}
|
||||
const r = await this.sendChatCmd(CC.APISetAddressSettings.cmdString({userId, settings}))
|
||||
if (r.type !== "userContactLinkUpdated") {
|
||||
|
||||
@@ -82,7 +82,8 @@ function fullOptions(options: BotOptions): Required<BotOptions> {
|
||||
opts.addressSettings = {
|
||||
autoAccept: opts.addressSettings.autoAccept ?? defaultOpts.addressSettings.autoAccept,
|
||||
welcomeMessage: typeof welcomeMessage === "string" ? {type: "text", text: welcomeMessage} : welcomeMessage,
|
||||
businessAddress: opts.addressSettings.businessAddress ?? defaultOpts.addressSettings.businessAddress
|
||||
businessAddress: opts.addressSettings.businessAddress ?? defaultOpts.addressSettings.businessAddress,
|
||||
chatLayout: opts.addressSettings.chatLayout
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@ export function botAddressSettings({addressSettings}: T.UserContactLink): BotAdd
|
||||
return {
|
||||
autoAccept: addressSettings.autoAccept ? true : false,
|
||||
welcomeMessage: addressSettings.autoReply,
|
||||
businessAddress: addressSettings.businessAddress
|
||||
businessAddress: addressSettings.businessAddress,
|
||||
chatLayout: addressSettings.chatLayout
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,4 +127,32 @@ describe("run", () => {
|
||||
await runBot("calc.simplex", {updateAddress: false})
|
||||
expect(chat.apiSetUserDomain).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("updates the address settings when they changed", async () => {
|
||||
const chat = fakeChat()
|
||||
await runBot(undefined, {addressSettings: {welcomeMessage: "hello"}})
|
||||
expect(chat.apiSetAddressSettings).toHaveBeenCalledWith(1, {autoAccept: true, welcomeMessage: {type: "text", text: "hello"}, businessAddress: false})
|
||||
})
|
||||
|
||||
it("updates the address settings when the chat layout changed", async () => {
|
||||
const chat = fakeChat()
|
||||
await runBot(undefined, {addressSettings: {chatLayout: T.ChatLayout.Terminal}})
|
||||
expect(chat.apiSetAddressSettings).toHaveBeenCalledWith(1, {autoAccept: true, businessAddress: false, chatLayout: T.ChatLayout.Terminal})
|
||||
})
|
||||
|
||||
it("does not update the address settings when they are the same", async () => {
|
||||
const chat = fakeChat()
|
||||
chat.apiGetUserAddress.mockResolvedValue({...address, addressSettings: {...address.addressSettings, chatLayout: T.ChatLayout.Terminal}})
|
||||
await runBot(undefined, {addressSettings: {chatLayout: T.ChatLayout.Terminal}})
|
||||
expect(chat.apiSetAddressSettings).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe("apiSetAddressSettings", () => {
|
||||
it("writes the chat layout of the bot address settings", async () => {
|
||||
const sendChatCmd = jest.fn().mockResolvedValue({type: "userContactLinkUpdated"})
|
||||
await api.ChatApi.prototype.apiSetAddressSettings.call({sendChatCmd} as unknown as api.ChatApi, 1, {autoAccept: true, chatLayout: T.ChatLayout.Terminal})
|
||||
const cmd: string = sendChatCmd.mock.calls[0][0]
|
||||
expect(JSON.parse(cmd.slice(cmd.indexOf("{")))).toEqual({businessAddress: false, autoAccept: {acceptIncognito: false}, chatLayout: "terminal"})
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user