diff --git a/apple/Package.resolved b/apple/Package.resolved index f1ec532a..1b59c472 100644 --- a/apple/Package.resolved +++ b/apple/Package.resolved @@ -15,7 +15,7 @@ "kind" : "remoteSourceControl", "location" : "ssh://git@github.com/logseq/lui.git", "state" : { - "revision" : "5c8ee0bf82fde5257bfbe70562c8649a13c56c59" + "revision" : "d2b3b0739bf047a1df5d22d3f316a45e430a68bd" } }, { diff --git a/apple/Package.swift b/apple/Package.swift index 26daa2af..7f357177 100644 --- a/apple/Package.swift +++ b/apple/Package.swift @@ -34,7 +34,7 @@ let package = Package( .library(name: "LogseqChatModel", type: .dynamic, targets: ["LogseqChatModel"]), ], dependencies: [ - .package(url: "ssh://git@github.com/logseq/lui.git", revision: "5c8ee0bf82fde5257bfbe70562c8649a13c56c59"), + .package(url: "ssh://git@github.com/logseq/lui.git", revision: "d2b3b07"), .package(url: "https://github.com/gonzalezreal/swiftui-math", from: "0.1.0"), .package(url: "https://github.com/appstefan/highlightswift.git", from: "1.1.0") ], diff --git a/apple/Sources/LogseqChat/LGChatOverflowMenuExtension.swift b/apple/Sources/LogseqChat/LGChatOverflowMenuExtension.swift index 3d7c97a1..abdd9b13 100644 --- a/apple/Sources/LogseqChat/LGChatOverflowMenuExtension.swift +++ b/apple/Sources/LogseqChat/LGChatOverflowMenuExtension.swift @@ -34,27 +34,7 @@ private struct LGChatOverflowMenu: View { let context: LUIAppleExtensionViewContext var body: some View { - if settingsVisible && !pageActionsVisible { - Button { - emit("settings") - } label: { - ZStack { - Circle() - .stroke(lineWidth: 2) - Image(systemName: "gearshape") - .resizable() - .scaledToFit() - .frame(width: 16, height: 16) - } - .frame(width: 24, height: 24) - } - .frame(width: 44, height: 44) - .foregroundStyle(.primary) - .accessibilityLabel(Text("Settings", bundle: .module)) - .accessibilityIdentifier("button.connection") - } else { - menuBody - } + menuBody } private var menuBody: some View { diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index 2459c8ab..5cadff46 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -159,8 +159,8 @@ packages: dependency: "direct main" description: path: "platform/flutter" - ref: 5c8ee0bf82fde5257bfbe70562c8649a13c56c59 - resolved-ref: 5c8ee0bf82fde5257bfbe70562c8649a13c56c59 + ref: d2b3b0739bf047a1df5d22d3f316a45e430a68bd + resolved-ref: d2b3b0739bf047a1df5d22d3f316a45e430a68bd url: "ssh://git@github.com/logseq/lui.git" source: git version: "0.1.0" diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 5d746c1c..f4f99422 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: lui_flutter_backend: git: url: ssh://git@github.com/logseq/lui.git - ref: 5c8ee0bf82fde5257bfbe70562c8649a13c56c59 + ref: d2b3b0739bf047a1df5d22d3f316a45e430a68bd path: platform/flutter webview_flutter: ^4.14.1 diff --git a/logseq_chat.opam b/logseq_chat.opam index 71f7cc6b..fb9cc0a7 100644 --- a/logseq_chat.opam +++ b/logseq_chat.opam @@ -31,7 +31,7 @@ pin-depends: [ ["melange-transit-core.0.1.2" "git+https://github.com/logseq/melange-transit.git#main"] ["melange-transit-native.0.1.2" "git+https://github.com/logseq/melange-transit.git#main"] ["melange-transit-melange.0.1.2" "git+https://github.com/logseq/melange-transit.git#main"] - ["lui.0.1.0" "git+ssh://git@github.com/logseq/lui.git#5c8ee0bf82fde5257bfbe70562c8649a13c56c59"] + ["lui.0.1.0" "git+ssh://git@github.com/logseq/lui.git#d2b3b07"] ["drive.dev" "git+https://github.com/logseq/drive.git#7f407b07f18e68596cb0dcb3ba1781cb0572a2bb"] ["ocaml-signal.0.1.0" "git+https://github.com/logseq/ocaml-signal.git#b9cb81fc910519fc579a90960267acb851483bca"] ["mldoc.dev" "git+https://github.com/logseq/mldoc.git#553dea6ed8694352527a189747f787365469c9cb"] diff --git a/shared/src/logseq_chat/model.ml b/shared/src/logseq_chat/model.ml index 4c32d1e0..06878feb 100644 --- a/shared/src/logseq_chat/model.ml +++ b/shared/src/logseq_chat/model.ml @@ -1770,7 +1770,11 @@ let rec update (current : chat_model) action = enqueue_close_search_effects closed path | ExpandComposer -> { current with composer_expanded = true; composer_autofocus = true } - | FocusComposer -> { current with composer_autofocus = true } + | FocusComposer -> + (* autofocus is an edge-triggered focus request: toggling guarantees a + prop diff (and therefore a refocus edge) even when the flag already + reads true while the field is unfocused *) + { current with composer_autofocus = not current.composer_autofocus } | ApplyComposerDraft draft -> { current with composer_draft = draft } | ChangeComposerDraft draft -> let updated = diff --git a/shared/src/logseq_chat/view_composer.ml b/shared/src/logseq_chat/view_composer.ml index bd176836..6d133f79 100644 --- a/shared/src/logseq_chat/view_composer.ml +++ b/shared/src/logseq_chat/view_composer.ml @@ -1,6 +1,13 @@ open Lui_protocol open Lui_elements +let with_press handler (elem : t) : t = + fun context parent -> + let node = elem context parent in + enable context node PressEnabled; + register_press context node handler; + node + let attachment_menu send : t = context_menu [ @@ -213,23 +220,24 @@ let composer_view (context : Lui_ui.ui_context) model_source send : t = if_ ~test:(Signal.map View_base.composer_expanded_ model_source) (View_base.with_liquid_glass "rounded-rectangle" - (column ~grow:1.0 ~main:`end_ ~gap:0 - ~padding_horizontal: - (if Lui_ui.host context = FlutterHost then 12 else 16) - ~padding_vertical: - (if Lui_ui.host context = FlutterHost then 12 else 8) - ~background: - (if Lui_ui.host context = FlutterHost then - "surface-container-high" - else "glass-fallback") - ~corner_radius:24 + (with_press (press send Model.FocusComposer) + (column ~grow:1.0 ~main:`end_ ~gap:0 + ~padding_horizontal: + (if Lui_ui.host context = FlutterHost then 12 else 16) + ~padding_vertical: + (if Lui_ui.host context = FlutterHost then 12 else 8) + ~background: + (if Lui_ui.host context = FlutterHost then + "surface-container-high" + else "glass-fallback") + ~corner_radius:24 [ box ~height:6 ~accessibility_identifier:"spacer.composer.top" []; if_ ~test:(Signal.map View_base.composer_assets_present_ model_source) - (scroll ~height:140 + (scroll ~orientation:`horizontal ~height:140 [ row ~gap:8 [ @@ -287,7 +295,7 @@ let composer_view (context : Lui_ui.ui_context) model_source send : t = (reactive View_base.composer_send_disabled_ model_source) send; ]; - ])); + ]))); if_ ~test:(Signal.map View_base.composer_collapsed_ model_source) (collapsed_composer_button context send); diff --git a/shared/src/logseq_chat/view_screens.ml b/shared/src/logseq_chat/view_screens.ml index 6d9bb866..a6647254 100644 --- a/shared/src/logseq_chat/view_screens.ml +++ b/shared/src/logseq_chat/view_screens.ml @@ -494,6 +494,7 @@ let main_header_leading (context : Lui_ui.ui_context) model_source send : (Signal.map View_base.primary_sidebar_button_visible_ model_source) (button ~icon:(`app "sidebar-toggle") ~variant:`ghost ~size:`icon + ~width:44 ~height:44 ~label:"Open sidebar" ~accessibility_identifier:"button.sidebar" ~disabled_signal: diff --git a/shared/test/logseq_chat/app_test.ml b/shared/test/logseq_chat/app_test.ml index f628e999..5b04063a 100644 --- a/shared/test/logseq_chat/app_test.ml +++ b/shared/test/logseq_chat/app_test.ml @@ -4729,6 +4729,19 @@ let composer_draft_restore_focus_and_dismissal_are_owned_by_lg () = check_eq ~msg:"dismissal keeps the persisted capture text" dismissed.composer_draft "Later" +let composer_refocus_always_emits_an_autofocus_edge () = + let expanded = + Model.update (Model.initial ()) Model.ExpandComposer + in + (* the armed flag reads true but the host field may be unfocused; every + FocusComposer must still flip the prop so the edge reaches the host *) + let first = Model.update expanded Model.FocusComposer in + let second = Model.update first Model.FocusComposer in + check ~msg:"expanding arms the autofocus edge" expanded.composer_autofocus; + check ~msg:"a refocus request while armed flips the flag" + (not first.composer_autofocus); + check ~msg:"the next refocus request flips it back" second.composer_autofocus + let composer_renders_autofocus_and_native_outside_dismissal () = let application = App.create (ios_backend ()) in start application; @@ -8602,6 +8615,7 @@ let cases = case "hide-keyboard-optimistically-finishes-outliner-editing" hide_keyboard_optimistically_finishes_outliner_editing; case "outliner-return-handoff-retains-one-native-editor-node" outliner_return_handoff_retains_one_native_editor_node; case "composer-draft-restore-focus-and-dismissal-are-owned-by-lg" composer_draft_restore_focus_and_dismissal_are_owned_by_lg; + case "composer-refocus-always-emits-an-autofocus-edge" composer_refocus_always_emits_an_autofocus_edge; case "composer-renders-autofocus-and-native-outside-dismissal" composer_renders_autofocus_and_native_outside_dismissal; case "flutter-composer-uses-a-tonal-material-dock" flutter_composer_uses_a_tonal_material_dock; case "flutter-sidebar-uses-compact-material-drawer-metrics" flutter_sidebar_uses_compact_material_drawer_metrics;