Skip to content

Conversation

@Ivy233
Copy link
Contributor

@Ivy233 Ivy233 commented Jan 19, 2026

通过改进位置切换逻辑,实现平滑的过渡动画:

  1. 在切换位置时,先保存新位置并临时恢复到旧位置
  2. 在旧位置播放隐藏动画
  3. 切换到新位置后,从隐藏状态播放显示动画
  4. 使用状态标志精确控制动画流程,避免闪烁和显示异常

这样可以确保任务栏在位置切换时不会出现空白区域、内容溢出或突然跳变的问题。

Log: 修复任务栏位置切换时的显示异常
PMS: BUG-346777

Summary by Sourcery

Improve dock position change handling to provide smooth hide/show transitions and avoid visual glitches when moving the taskbar.

Bug Fixes:

  • Fix visual glitches such as blank areas and incorrect visibility when changing the dock/taskbar position, especially with auto-hide enabled.

Enhancements:

  • Refine dock animation flow to distinguish between normal show/hide and position-change transitions, coordinating them via explicit state flags.
  • Centralize dock position change handling in a dedicated connections helper that manages restoring the old position, applying the new one, and triggering the appropriate animations.

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Ivy233

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 19, 2026

Reviewer's Guide

Refines the dock’s position-change handling by decoupling menu actions from animation callbacks and introducing a robust, state-driven animation flow that hides the dock at the old position, switches logical position, and then shows it at the new position without visual glitches.

Sequence diagram for dock position change animation flow

sequenceDiagram
    actor User
    participant MenuItem
    participant Applet
    participant Panel
    participant positionChangeConnections
    participant dockAnimation
    participant dock
    participant hideShowAnimation

    User->>MenuItem: select new position value
    MenuItem->>Applet: set position value
    Applet->>Panel: update position
    Panel-->>positionChangeConnections: onPositionChanged

    activate positionChangeConnections
    positionChangeConnections->>positionChangeConnections: check isRestoringPosition
    alt isRestoringPosition true
        positionChangeConnections-->>positionChangeConnections: return (ignore change)
    else isRestoringPosition false
        positionChangeConnections->>positionChangeConnections: savedNewPosition = Panel.position
        positionChangeConnections->>positionChangeConnections: isRestoringPosition = true
        positionChangeConnections->>Applet: position = previousPosition
        positionChangeConnections->>positionChangeConnections: isRestoringPosition = false
        positionChangeConnections->>dockAnimation: stop
        positionChangeConnections->>hideShowAnimation: stop
        positionChangeConnections->>dockAnimation: isPositionChanging = true
        positionChangeConnections->>Panel: read hideState
        positionChangeConnections->>dock: read visible
        alt Panel.hideState is Hide and dock not visible
            positionChangeConnections->>dockAnimation: isPositionChanging = false
            positionChangeConnections->>positionChangeConnections: handlePositionChangeAfterHide
        else dock is visible
            positionChangeConnections->>dockAnimation: startAnimation(false)
        end
    end
    deactivate positionChangeConnections

    rect rgb(230,230,255)
    dockAnimation-->>dockAnimation: onStopped
    alt isPositionChanging true and isShowing false
        dockAnimation->>dockAnimation: isPositionChanging = false
        dockAnimation->>positionChangeConnections: handlePositionChangeAfterHide
    else isShowing true
        dockAnimation->>Panel: read hideState
        alt Panel.hideState is Hide
            dockAnimation->>hideTimer: start
        end
    end
    end

    rect rgb(230,255,230)
    positionChangeConnections->>positionChangeConnections: handlePositionChangeAfterHide
    positionChangeConnections->>positionChangeConnections: update previousPosition
    positionChangeConnections->>Applet: position = savedNewPosition
    positionChangeConnections->>positionChangeConnections: savedNewPosition = -1
    positionChangeConnections->>Panel: changeDragAreaAnchor
    positionChangeConnections->>Panel: requestClosePopup
    positionChangeConnections->>dockAnimation: configure dockTransform for hidden offset
    positionChangeConnections->>dockAnimation: startAnimation(true)
    end
Loading

Updated class diagram for dockAnimation and positionChangeConnections

classDiagram
    class DockAnimation {
        bool useTransformBasedAnimation
        bool isShowing
        bool isPositionChanging
        var target
        string animProperty
        startAnimation(show)
        stop()
        onStopped()
    }

    class PositionChangeConnections {
        int previousPosition
        int savedNewPosition
        bool isRestoringPosition
        onPositionChanged()
        handlePositionChangeAfterHide()
        onDockSizeChanged()
        onCompleted()
    }

    class Dock {
        bool visible
        bool useColumnLayout
        int width
        int height
    }

    class DockTransform {
        int x
        int y
    }

    class Panel {
        int position
        int dockSize
        int hideState
        requestClosePopup()
        changeDragAreaAnchor()
    }

    class Applet {
        int position
    }

    DockAnimation --> Dock : animates
    DockAnimation --> DockTransform : uses
    PositionChangeConnections --> DockAnimation : controls
    PositionChangeConnections --> Panel : updates
    PositionChangeConnections --> Applet : restores_and_applies_position
    PositionChangeConnections --> DockTransform : sets_hidden_offset
    Panel --> Dock : configures_size
Loading

Flow diagram for dock position change and animation states

flowchart TD
    A[User changes dock position via menu] --> B[Panel.position changes]
    B --> C[onPositionChanged in positionChangeConnections]

    C --> D{isRestoringPosition}
    D -->|true| E[Return, ignore change]
    D -->|false| F[Save savedNewPosition from Panel.position]

    F --> G[Set isRestoringPosition = true]
    G --> H[Restore Applet.position to previousPosition]
    H --> I[Set isRestoringPosition = false]

    I --> J[Stop dockAnimation and hideShowAnimation]
    J --> K[Set dockAnimation.isPositionChanging = true]

    K --> L{Panel.hideState is Hide and dock not visible}
    L -->|true| M[Set dockAnimation.isPositionChanging = false]
    M --> N[handlePositionChangeAfterHide]
    L -->|false| O["startAnimation(false) for hide"]

    O --> P[dockAnimation onStopped]
    P --> Q{isPositionChanging and not isShowing}
    Q -->|true| R[Set isPositionChanging = false]
    R --> N
    Q -->|false| S{isShowing and Panel.hideState is Hide}
    S -->|true| T[start hideTimer]
    S -->|false| U[End]

    N --> V{savedNewPosition is valid}
    V -->|false| U
    V -->|true| W[Set previousPosition = savedNewPosition]
    W --> X[Apply Applet.position = savedNewPosition]
    X --> Y[Reset savedNewPosition = -1]
    Y --> Z[changeDragAreaAnchor and requestClosePopup]
    Z --> AA[Set dockTransform to hidden offset based on position]
    AA --> AB["startAnimation(true) for show"]
    AB --> AC[dockAnimation onStopped with isShowing true]
    AC --> AD{Panel.hideState is Hide}
    AD -->|true| T
    AD -->|false| U
Loading

File-Level Changes

Change Details Files
Introduce state-driven dock animation flow with explicit handling for position-change sequences.
  • Add isPositionChanging flag to the dockAnimation object to distinguish between normal show/hide and position-change-driven animations.
  • Extend dockAnimation.onStopped to either continue the position-change workflow after a hide animation or trigger auto-hide after a show animation when appropriate.
  • Ensure running animations are stopped and relevant hide/show animations are coordinated around position changes.
panels/dock/package/main.qml
Rework position menu handling so it no longer couples the UI toggle directly to animation callbacks.
  • Simplify ActionButton.onTriggered to only update the underlying Applet property and keep the checked state bound to that property.
  • Remove the previous positionChangeCallback pattern that connected to dockAnimation.onStopped and started animations from the menu layer.
panels/dock/package/main.qml
Centralize and harden dock position-change logic using a dedicated Connections block that orchestrates hide-at-old / show-at-new behavior.
  • Track previousPosition, savedNewPosition, and an isRestoringPosition guard to safely perform temporary position restoration without re-entrancy issues.
  • On position change, temporarily restore the dock to its previous position, stop any running animations, mark a position-change in progress, and either directly finalize the change when the dock is already hidden or start a hide animation otherwise.
  • Implement handlePositionChangeAfterHide to apply the new position, update drag area anchors, close popups, preset transform offsets to the hidden state based on dock orientation, and then run the show animation from the correct off-screen position.
  • Initialize previousPosition on component completion so the first position change has a valid baseline.
panels/dock/package/main.qml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The dockAnimation.isPositionChanging flag is only reset in onStopped and the early-return path for hidden docks; if the animation is interrupted (e.g., by another position change or a manual stop()), this flag may remain true and affect later animations—consider centralizing state reset so all code paths that stop animations clear this flag consistently.
  • In the Connections handler for onPositionChanged, the isRestoringPosition flag is set and immediately cleared after assigning Applet.position; this relies on synchronous behavior of the signal emission—if this logic ever changes or other async work is added, it may become brittle, so consider scoping the restore logic into a helper that manages the flag with a clearer critical section.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `dockAnimation.isPositionChanging` flag is only reset in `onStopped` and the early-return path for hidden docks; if the animation is interrupted (e.g., by another position change or a manual `stop()`), this flag may remain true and affect later animations—consider centralizing state reset so all code paths that stop animations clear this flag consistently.
- In the `Connections` handler for `onPositionChanged`, the `isRestoringPosition` flag is set and immediately cleared after assigning `Applet.position`; this relies on synchronous behavior of the signal emission—if this logic ever changes or other async work is added, it may become brittle, so consider scoping the restore logic into a helper that manages the flag with a clearer critical section.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Ivy233 Ivy233 force-pushed the fix-dock-position-transform branch from 9b5c6fe to fffc65c Compare January 20, 2026 06:41
@Ivy233 Ivy233 changed the title fix: 修复任务栏位置切换时的显示异常 fix: Fixed display issues when switching taskbar positions Jan 21, 2026
@Ivy233 Ivy233 force-pushed the fix-dock-position-transform branch from fffc65c to 72c38ac Compare January 21, 2026 02:20
@BLumia BLumia requested review from 18202781743 and BLumia January 22, 2026 05:21
@deepin-bot
Copy link

deepin-bot bot commented Jan 23, 2026

TAG Bot

New tag: 2.0.27
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1401

Improve position switching logic with smooth transition animations:
1. Save new position and temporarily restore to old position when switching
2. Play hide animation at old position
3. Switch to new position and play show animation from hidden state
4. Use state flags to precisely control animation flow and avoid flickering

This ensures the dock doesn't show blank areas, content overflow, or sudden jumps during position changes.

Log: Fix display issues when switching dock position
PMS: BUG-346777
@Ivy233 Ivy233 force-pushed the fix-dock-position-transform branch from 72c38ac to b19836d Compare January 23, 2026 09:18
@deepin-ci-robot
Copy link

deepin pr auto review

这份代码是对 Dock(任务栏)面板位置切换动画逻辑的重构,主要目的是解决切换位置时可能出现的闪烁、空白区域或动画不连贯的问题。整体来看,代码逻辑比之前更加清晰,通过引入状态标志位(isPositionChanging)和集中处理位置变更逻辑(positionChangeConnections),改善了代码的可维护性。

以下是对该 git diff 的详细审查意见,分为语法逻辑、代码质量、代码性能和代码安全四个方面:

1. 语法逻辑

  • 状态管理逻辑清晰
    • 引入 isPositionChanging 标志位,有效地将"位置切换"这一复杂操作与普通的显示/隐藏操作区分开来。
    • positionChangeConnections 对象封装了位置变更的所有逻辑,避免了在多个 onTriggered 回调中分散处理,逻辑流向更易读:触发切换 -> 回退位置并隐藏 -> 动画结束 -> 应用新位置并显示
  • 动画结束后的回调处理
    • dockAnimationonStopped 中,根据 isPositionChanging 判断是执行位置切换后的显示逻辑,还是执行普通的自动隐藏逻辑。这个判断逻辑是合理的。
  • 潜在的竞态条件
    • ConnectionsonPositionChanged 中,代码试图通过 Applet.position = previousPosition 来强制回退位置以播放隐藏动画。这里存在一个微妙的逻辑风险:如果 Applet 绑定了 Panel.position,或者 Panel 内部有防抖/过滤逻辑,强制设置回旧位置可能会再次触发 onPositionChanged 信号,导致死循环或逻辑混乱。
    • 改进建议:虽然代码中使用了 isRestoringPosition 标志位来防止递归,但在 QML 的属性绑定系统中,这种手动干预双向绑定的方式比较脆弱。建议确认 Applet.position 的写入是否真的会触发 Panel.positiononPositionChanged。如果不会,isRestoringPosition 可以移除以简化逻辑;如果会,目前的做法是可行的,但需确保 isRestoringPosition 的重置时机绝对可靠(目前看起来是在同步代码中,是安全的)。

2. 代码质量

  • 可读性提升
    • MutuallyExclusiveMenuItem 组件得到了极大的简化。原本复杂的 positionChangeCallback 被移除,现在它只负责触发属性变更。这使得组件职责更加单一。
    • 将位置切换的核心逻辑移至 Connections 块中,使得 main.qml 的顶层结构更清晰。
  • 魔法数字
    • handlePositionChangeAfterHide 中使用了 -1 作为 savedNewPosition 的初始值和重置值。虽然这是常见的做法,但定义一个常量(如 InvalidPosition)会让代码意图更明确。
  • 注释
    • 代码中的注释(如 // Ignore position changes triggered by our own restore operation)非常有帮助,解释了复杂的控制流,应予以保留。

3. 代码性能

  • 动画控制
    • dockAnimation.stop()hideShowAnimation.stop() 的调用是必要的,防止动画队列堆积。
  • 属性绑定与频繁写入
    • onPositionChanged 中,短时间内对 Applet.position 进行了两次写入(先写旧值,动画结束后写新值)。这在逻辑上是必须的,但需注意 AppletPanel 的属性监听器中是否有重计算或 IO 操作,避免引起性能抖动。
  • Transform 操作
    • handlePositionChangeAfterHide 中,根据布局方向手动设置 dockTransform.x/y。这比直接修改几何属性性能要好,符合 QML 最佳实践。

4. 代码安全

  • 边界检查
    • handlePositionChangeAfterHide 函数开头检查了 if (savedNewPosition === -1) return;。这是一个很好的防御性编程实践,防止因信号时序问题导致的无效操作。
  • 状态一致性
    • 代码依赖 Panel.hideStatedock.visible 来判断当前状态。如果在动画播放期间,外部其他组件修改了这些状态,可能会导致 isPositionChanging 状态无法正确复位,从而卡死在某个中间状态。
    • 改进建议:可以考虑增加一个超时机制或者状态机,确保 isPositionChanging 不会因为异常情况永远保持为 true

总结与具体改进建议

这份代码在逻辑和结构上是一个不错的改进。为了进一步完善,建议进行以下微调:

  1. 定义常量:将 -1 替换为有意义的常量。

    // 在文件顶部或某个配置对象中定义
    readonly property int invalidPosition: -1
    // ...
    property int savedNewPosition: invalidPosition
    // ...
    if (savedNewPosition === invalidPosition) return;
  2. Transform 计算封装handlePositionChangeAfterHide 中的 Transform 计算逻辑略显冗长,可以提取为函数或利用三元表达式简化,或者利用已有的 dockAnimation.animProperty 逻辑(如果适用)。

    // 示例简化
    function setTransformToHidden() {
        if (!dockAnimation.useTransformBasedAnimation) {
            dockTransform.x = 0;
            dockTransform.y = 0;
            return;
        }
        var isLeftOrTop = (Applet.position === Dock.Left || Applet.position === Dock.Top);
        var offset = isLeftOrTop ? -Panel.dockSize : Panel.dockSize;
        
        if (dock.useColumnLayout) { // 垂直布局,改变 X
            dockTransform.x = offset;
            dockTransform.y = 0;
        } else { // 水平布局,改变 Y
            dockTransform.x = 0;
            dockTransform.y = offset;
        }
    }
    // 在 handlePositionChangeAfterHide 中调用
    setTransformToHidden();
  3. 递归调用的鲁棒性:虽然 isRestoringPosition 解决了递归问题,但为了绝对安全,可以将恢复位置的操作包裹在 Qt.callLater 中,确保当前事件循环处理完毕后再执行,进一步避免潜在的属性引擎冲突。

    // 在 onPositionChanged 中
    isRestoringPosition = true;
    // 使用 Qt.callLater 确保在当前堆帧清空后执行
    Qt.callLater(function() {
        Applet.position = previousPosition;
        isRestoringPosition = false;
    });

    注意:使用 Qt.callLater 可能会改变动画的触发时机,需要测试确认是否影响动画流畅度。如果当前同步执行没有问题,保持现状即可。

总体而言,这是一个稳健的修改方案,主要解决了用户体验问题,代码结构也更加合理。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants