mirror of
https://github.com/logseq/logseq.git
synced 2026-04-24 14:14:55 +00:00
Revert "fix(mobile): blink when capture"
This reverts commit 3366155fad.
This commit is contained in:
@@ -44,23 +44,14 @@ public class LiquidTabsPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
|
||||
let systemImage = dict["systemImage"] as? String ?? "square"
|
||||
let roleStr = dict["role"] as? String ?? "normal"
|
||||
let role: LiquidTab.Role
|
||||
|
||||
switch roleStr {
|
||||
case "search":
|
||||
role = .search
|
||||
case "action":
|
||||
role = .action
|
||||
default:
|
||||
role = .normal
|
||||
}
|
||||
let role: LiquidTab.Role = (roleStr == "search") ? .search : .normal
|
||||
|
||||
return LiquidTab(id: id, title: title, systemImage: systemImage, role: role)
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.store.tabs = tabs
|
||||
if let firstId = tabs.first(where: { !$0.isActionButton })?.id ?? tabs.first?.id {
|
||||
if let firstId = tabs.first?.id {
|
||||
self.store.selectedId = firstId
|
||||
}
|
||||
}
|
||||
@@ -77,11 +68,6 @@ public class LiquidTabsPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if let tab = self.store.tab(for: id), tab.isActionButton {
|
||||
LiquidTabsPlugin.shared?.notifyTabSelected(id: id)
|
||||
return
|
||||
}
|
||||
|
||||
self.store.selectedId = id
|
||||
}
|
||||
|
||||
|
||||
@@ -121,19 +121,6 @@ private struct LiquidTabs26View: View {
|
||||
|
||||
private let maxMainTabs = 6
|
||||
|
||||
private func tab(for selection: LiquidTabsTabSelection) -> LiquidTab? {
|
||||
guard let id = store.tabId(for: selection) else { return nil }
|
||||
return store.tab(for: id)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func handleActionIfNeeded(selection: LiquidTabsTabSelection) -> Bool {
|
||||
guard let tab = tab(for: selection), tab.isActionButton else { return false }
|
||||
|
||||
LiquidTabsPlugin.shared?.notifyTabSelected(id: tab.id)
|
||||
return true
|
||||
}
|
||||
|
||||
// Proxy binding to intercept re-taps
|
||||
private var tabSelectionProxy: Binding<LiquidTabsTabSelection> {
|
||||
Binding(
|
||||
@@ -141,7 +128,7 @@ private struct LiquidTabs26View: View {
|
||||
set: { newValue in
|
||||
if newValue == selectedTab {
|
||||
handleRetap(on: newValue)
|
||||
} else if !handleActionIfNeeded(selection: newValue) {
|
||||
} else {
|
||||
selectedTab = newValue
|
||||
}
|
||||
}
|
||||
@@ -159,27 +146,24 @@ private struct LiquidTabs26View: View {
|
||||
|
||||
private func initialSelection() -> LiquidTabsTabSelection {
|
||||
if let id = store.selectedId,
|
||||
let tab = store.tab(for: id),
|
||||
!tab.isActionButton,
|
||||
let sel = store.selection(forId: id) {
|
||||
return sel
|
||||
}
|
||||
|
||||
if let firstIndex = store.tabs.prefix(maxMainTabs).firstIndex(where: { !$0.isActionButton }) {
|
||||
return .content(firstIndex)
|
||||
if !store.tabs.isEmpty {
|
||||
return .content(0)
|
||||
}
|
||||
|
||||
return .search
|
||||
}
|
||||
|
||||
private func focusSearchField() {
|
||||
// Drive focus (and keyboard) only through searchFocused.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
isSearchFocused = true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Body
|
||||
|
||||
var body: some View {
|
||||
if store.tabs.isEmpty {
|
||||
// bootstrap webview so JS can configure tabs
|
||||
@@ -191,46 +175,29 @@ private struct LiquidTabs26View: View {
|
||||
Color.logseqBackground.ignoresSafeArea()
|
||||
|
||||
TabView(selection: tabSelectionProxy) {
|
||||
// Dynamic main tabs – all use Tab(...)
|
||||
// Dynamic main tabs using Tab(...) API
|
||||
ForEach(Array(store.tabs.prefix(maxMainTabs).enumerated()),
|
||||
id: \.element.id) { index, tab in
|
||||
Tab(
|
||||
tab.title,
|
||||
systemImage: tab.systemImage,
|
||||
value: LiquidTabsTabSelection.content(index)
|
||||
tab.title,
|
||||
systemImage: tab.systemImage,
|
||||
value: LiquidTabsTabSelection.content(index)
|
||||
) {
|
||||
if tab.isActionButton {
|
||||
// Capture / action tab: no real content, acts like a plain button
|
||||
NavigationStack {
|
||||
VStack(spacing: 20) {
|
||||
Text("Capture")
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.bold)
|
||||
.padding(.top, 120)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(Color.logseqBackground)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
} else {
|
||||
NativeNavHost(navController: navController)
|
||||
.ignoresSafeArea()
|
||||
.background(Color.logseqBackground)
|
||||
}
|
||||
NativeNavHost(navController: navController)
|
||||
.ignoresSafeArea()
|
||||
.background(Color.logseqBackground)
|
||||
}
|
||||
}
|
||||
|
||||
// Search Tab
|
||||
Tab(value: .search, role: .search) {
|
||||
SearchTabHost26(
|
||||
navController: navController,
|
||||
selectedTab: $selectedTab,
|
||||
firstTabId: store.tabs.first?.id,
|
||||
store: store
|
||||
navController: navController,
|
||||
selectedTab: $selectedTab,
|
||||
firstTabId: store.tabs.first?.id,
|
||||
store: store
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
.searchable(
|
||||
@@ -282,6 +249,8 @@ private struct LiquidTabs26View: View {
|
||||
|
||||
switch newValue {
|
||||
case .search:
|
||||
// Every time we switch to the search tab, re-focus the search
|
||||
// field so the search bar auto-focuses and keyboard appears.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
|
||||
hackShowKeyboard = true
|
||||
}
|
||||
@@ -293,14 +262,13 @@ private struct LiquidTabs26View: View {
|
||||
focusSearchField()
|
||||
|
||||
case .content:
|
||||
// Leaving search tab – drop focus and stop hack keyboard.
|
||||
isSearchFocused = false
|
||||
hackShowKeyboard = false
|
||||
}
|
||||
}
|
||||
.onChange(of: store.selectedId) { newId in
|
||||
guard let id = newId,
|
||||
let tab = store.tab(for: id),
|
||||
!tab.isActionButton,
|
||||
let newSelection = store.selection(forId: id) else {
|
||||
return
|
||||
}
|
||||
@@ -314,7 +282,6 @@ private struct LiquidTabs26View: View {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Search host for 26+
|
||||
// Only responsible for cancel behaviour and tab switching.
|
||||
// It does NOT own the focus anymore.
|
||||
@@ -375,16 +342,11 @@ private struct LiquidTabs16View: View {
|
||||
|
||||
TabView(selection: Binding<String?>(
|
||||
get: {
|
||||
store.selectedId ?? store.tabs.first(where: { !$0.isActionButton })?.id ?? store.firstTab?.id
|
||||
store.selectedId ?? store.firstTab?.id
|
||||
},
|
||||
set: { newValue in
|
||||
guard let id = newValue else { return }
|
||||
|
||||
if let tab = store.tab(for: id), tab.isActionButton {
|
||||
LiquidTabsPlugin.shared?.notifyTabSelected(id: id)
|
||||
return
|
||||
}
|
||||
|
||||
// Re-tap: pop to root
|
||||
if id == store.selectedId {
|
||||
navController.popToRootViewController(animated: true)
|
||||
@@ -424,8 +386,7 @@ private struct LiquidTabs16View: View {
|
||||
}
|
||||
.onAppear {
|
||||
if store.selectedId == nil {
|
||||
store.selectedId = store.tabs.first(where: { !$0.isActionButton })?.id
|
||||
?? store.tabs.first?.id
|
||||
store.selectedId = store.tabs.first?.id
|
||||
}
|
||||
|
||||
let appearance = UITabBarAppearance()
|
||||
|
||||
@@ -10,20 +10,6 @@ struct LiquidTab: Identifiable, Equatable {
|
||||
enum Role {
|
||||
case normal
|
||||
case search
|
||||
case action
|
||||
}
|
||||
}
|
||||
|
||||
extension LiquidTab {
|
||||
/// Tabs that should behave like plain buttons instead of driving selection.
|
||||
/// Defaults to the existing capture tab unless explicitly marked as an action.
|
||||
var isActionButton: Bool {
|
||||
switch role {
|
||||
case .action:
|
||||
return true
|
||||
default:
|
||||
return id == "capture"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,5 +120,5 @@
|
||||
(configure-tabs
|
||||
[{:id "home" :title "Home" :systemImage "house" :role "normal"}
|
||||
{:id "favorites" :title "Favorites" :systemImage "star" :role "normal"}
|
||||
{:id "capture" :title "Capture" :systemImage "tray" :role "action"}
|
||||
{:id "capture" :title "Capture" :systemImage "tray" :role "normal"}
|
||||
{:id "settings" :title "Settings" :systemImage "gear" :role "normal"}]))
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[logseq.shui.popup.core :as shui-popup]
|
||||
[logseq.shui.ui :as shui]
|
||||
[mobile.state :as mobile-state]
|
||||
[promesa.core :as p]
|
||||
[rum.core :as rum]))
|
||||
|
||||
(defonce *last-popup? (atom nil))
|
||||
@@ -50,16 +49,10 @@
|
||||
(editor-handler/quick-add-open-last-block!))
|
||||
|
||||
dismissing?
|
||||
(let [capture? (mobile-state/quick-add-open?)]
|
||||
(when (some? @mobile-state/*popup-data)
|
||||
(p/do!
|
||||
(mobile-state/set-popup! nil)
|
||||
(reset! *last-popup-data nil)
|
||||
(.dismiss ^js mobile-util/native-editor-toolbar)
|
||||
(state/pub-event! [:mobile/clear-edit])
|
||||
(when capture?
|
||||
(when-let [tab @mobile-state/*tab]
|
||||
(mobile-state/set-tab! tab))))))
|
||||
(when (some? @mobile-state/*popup-data)
|
||||
(state/pub-event! [:mobile/clear-edit])
|
||||
(mobile-state/set-popup! nil)
|
||||
(reset! *last-popup-data nil))
|
||||
|
||||
:else
|
||||
nil)))
|
||||
|
||||
Reference in New Issue
Block a user