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.

通过改进位置切换逻辑,实现平滑的过渡动画:
1. 在切换位置时,先保存新位置并临时恢复到旧位置
2. 在旧位置播放隐藏动画
3. 切换到新位置后,从隐藏状态播放显示动画
4. 使用状态标志精确控制动画流程,避免闪烁和显示异常

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

Log: 修复任务栏位置切换时的显示异常
PMS: BUG-346777
@Ivy233 Ivy233 force-pushed the fix-dock-position-transform branch from 9b5c6fe to fffc65c Compare January 20, 2026 06:41
@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要实现了 Dock(任务栏)在切换位置时的平滑过渡动画,通过先隐藏旧位置的 Dock,再在新位置显示 Dock 的方式来避免视觉上的突变。

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

1. 语法逻辑

  • 状态管理逻辑复杂,存在竞态条件风险

    • onPositionChanged 中,代码通过 isRestoringPosition 标志位来防止递归调用(即设置 Applet.position 触发 onPositionChanged)。虽然逻辑上可行,但依赖外部状态标志来控制信号处理流比较脆弱。
    • savedNewPosition 的重置时机是在 handlePositionChangeAfterHide 中。如果在动画结束前再次触发位置变更,或者 onStopped 信号因某种原因未触发,savedNewPosition 可能残留旧值,导致后续行为异常。
    • 改进建议:考虑使用一个简单的状态机来管理位置切换过程(例如:Idle -> Hiding -> Changing -> Showing),这比使用多个布尔标志和整数变量更清晰,也能更好地处理异步事件。
  • 动画属性初始化时机

    • handlePositionChangeAfterHide 中,根据 useTransformBasedAnimation 设置 dockTransform 的坐标。这看起来是为了让 Dock 从“隐藏”的位置滑入。然而,startAnimation(true) 内部通常会处理初始状态。如果这里手动设置了坐标,需要确保与 startAnimation 的内部逻辑不冲突,否则可能会出现跳帧。
    • 改进建议:确认 startAnimation(true) 的逻辑是否包含重置 dockTransform。如果包含,这里的显式赋值可能是多余的;如果不包含,建议封装为一个 prepareToShow() 函数,保持逻辑解耦。

2. 代码质量

  • 变量命名与封装

    • positionChangeConnections 对象中混入了逻辑处理函数(onPositionChanged, handlePositionChangeAfterHide)和状态属性(previousPosition, savedNewPosition)。虽然 QML 的 Connections 允许这样做,但这降低了代码的可读性和可维护性。
    • 改进建议:将位置切换的逻辑提取到一个单独的 Qt Object 或 JS 对象中,专门负责管理状态和动画序列,Connections 仅作为信号的入口。
  • 代码复用

    • handlePositionChangeAfterHide 中计算 hideOffset 的逻辑(判断左右/上下)可能与 dockAnimation 中的动画逻辑重复。
    • 改进建议:将计算偏移量的逻辑封装为公共函数或属性,避免硬编码逻辑分散在多处。
  • 魔法数字

    • savedNewPosition: -1 使用了 -1 作为“未设置”的标记。
    • 改进建议:如果 Applet.position 是枚举类型(通常非负),使用 -1 尚可,但最好定义一个常量 InvalidPosition 或使用可空类型(如果环境支持)来提高可读性。

3. 代码性能

  • 频繁的属性绑定与解绑

    • 原代码(diff 中删除的部分)使用了 disconnectconnect 来处理回调。新代码虽然移除了这部分,但引入了 dockAnimation.isPositionChanging 标志位在 onStopped 中进行判断。这比动态连接信号要好,因为频繁的 connect/disconnect 会产生微小的性能开销。
    • 改进建议:目前的实现方式在性能上是可以接受的。
  • 动画停止操作

    • onPositionChanged 中调用了 dockAnimation.stop()hideShowAnimation.stop()。这是必要的,可以防止动画队列堆积。

4. 代码安全

  • 空值检查

    • handlePositionChangeAfterHide 开头有 if (savedNewPosition === -1) return;,这是一个很好的防御性编程实践,防止在无效状态下执行逻辑。
  • 外部状态依赖

    • 代码高度依赖 Panel.positionApplet.positionPanel.hideState 等外部状态。如果这些状态在动画过程中被其他逻辑修改,可能会导致状态不一致。
    • 改进建议:在位置切换动画开始时,可以考虑暂时禁用其他可能干扰 Dock 状态的输入或逻辑(如果架构允许),或者增加更多的状态检查。

总结与重构建议

这段代码修复了切换位置时的闪烁和空白区域问题,逻辑上比之前更完整,但状态管理略显分散。

建议重构方向
将位置切换的逻辑封装成一个独立的组件或对象,例如 PositionTransitionManager

// 伪代码示例
QtObject {
    id: positionManager
    enum State { Idle, Hiding, Changing, Showing }
    property int state: State.Idle
    property int pendingPosition: -1

    function requestPositionChange(newPos) {
        if (state !== State.Idle) return; // 或者处理队列
        
        state = State.Hiding;
        pendingPosition = newPos;
        dockAnimation.startAnimation(false); // 开始隐藏
    }

    // Connections 或者 dockAnimation.onStopped 调用
    function onAnimationFinished() {
        if (state === State.Hiding) {
            state = State.Changing;
            applyPositionChange(); // 应用新位置
            state = State.Showing;
            dockAnimation.startAnimation(true); // 开始显示
        } else if (state === State.Showing) {
            state = State.Idle;
        }
    }
}

这样可以清晰地控制流程,避免在 Connections 中混杂过多的状态变量,也更容易调试和维护。

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