Skip to content

fix(vnote): keep note order stable after pinning#374

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:develop/snipefrom
dengzhongyuan365-dev:bug-fix-6-17
Jun 17, 2026
Merged

fix(vnote): keep note order stable after pinning#374
deepin-bot[bot] merged 1 commit into
linuxdeepin:develop/snipefrom
dengzhongyuan365-dev:bug-fix-6-17

Conversation

@dengzhongyuan365-dev

@dengzhongyuan365-dev dengzhongyuan365-dev commented Jun 17, 2026

Copy link
Copy Markdown
Member

Use note ID as a tie-breaker when modified times are equal.

当修改时间相同时使用笔记ID作为兜底排序条件。

Log: 修复置顶笔记后同秒笔记顺序变化问题
PMS: BUG-366799
Influence: 修复后置顶笔记不会打乱同秒创建的其他笔记顺序,列表展示更稳定。

Summary by Sourcery

Bug Fixes:

  • Prevent pinned notes from reordering other notes created or modified in the same second by using note ID as a deterministic tiebreaker after modification time.

Use note ID as a tie-breaker when modified times are equal.

当修改时间相同时使用笔记ID作为兜底排序条件。

Log: 修复置顶笔记后同秒笔记顺序变化问题
PMS: BUG-366799
Influence: 修复后置顶笔记不会打乱同秒创建的其他笔记顺序,列表展示更稳定。
@sourcery-ai

sourcery-ai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Ensures stable note ordering by refining the comparator used for sorting notes: notes are still ordered by pin (top) status and modification time, but now use note ID as a final tie-breaker when modification times are equal, and ensures the updated ordering is applied when updating top status.

File-Level Changes

Change Details Files
Refined note sort comparator to add a deterministic tie-breaker using note ID when modify times are equal and clarified comparator logic.
  • Kept pinned notes ordered before non-pinned notes using the NOTE_ISTOP_KEY flag.
  • Reordered and clarified comparison steps to first compare pin status, then modification time in descending order, and finally note ID in descending order when modification times match.
  • Ensured QDateTime parsing for NOTE_MODIFY_TIME_KEY is performed before comparison and only used to check inequality before falling back to ID comparison.
  • Updated comparator comments to clearly describe sort semantics and the rationale for using note ID as a fallback to stabilize ordering of notes created/modified in the same second.
src/common/VNoteMainManager.cpp
Ensured the updated NoteCompare comparator is applied when updating note top status by explicitly sorting the note data list before locating the target note.
  • After building notesDataList in updateTop, added a std::sort call using NoteCompare to reapply the consistent ordering after top-state changes.
  • Left the subsequent std::find_if logic intact so that the correct note is located after re-sorting based on the refined comparator.
src/common/VNoteMainManager.cpp

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

@github-actions

Copy link
Copy Markdown
  • 敏感词检查失败, 检测到1个文件存在敏感词
详情
{
    "src/common/VNoteMainManager.cpp": [
        {
            "line": "            url = \"https://www.deepin.org/zh/agreement/privacy/\";",
            "line_number": 1363,
            "rule": "S35",
            "reason": "Url link | 20e2eab189"
        },
        {
            "line": "            url = \"https://www.uniontech.com/agreement/privacy-cn\";",
            "line_number": 1365,
            "rule": "S35",
            "reason": "Url link | 4850a00dd7"
        },
        {
            "line": "            url = \"https://www.deepin.org/en/agreement/privacy/\";",
            "line_number": 1369,
            "rule": "S35",
            "reason": "Url link | 38d42f63bf"
        },
        {
            "line": "            url = \"https://www.uniontech.com/agreement/privacy-en\";",
            "line_number": 1371,
            "rule": "S35",
            "reason": "Url link | f82409d3b5"
        }
    ]
}

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The comparator reparses NOTE_MODIFY_TIME_KEY into QDateTime on every comparison, which can be expensive during sort; consider precomputing and caching parsed timestamps (e.g., in the QVariantMap or a parallel structure) before calling std::sort.
  • In updateTop, the find_if still uses the raw "noteId" string while the comparator uses NOTE_ID_KEY; aligning these to consistently use the same key constant would reduce the risk of subtle key mismatches.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The comparator reparses NOTE_MODIFY_TIME_KEY into QDateTime on every comparison, which can be expensive during sort; consider precomputing and caching parsed timestamps (e.g., in the QVariantMap or a parallel structure) before calling std::sort.
- In updateTop, the find_if still uses the raw "noteId" string while the comparator uses NOTE_ID_KEY; aligning these to consistently use the same key constant would reduce the risk of subtle key mismatches.

## Individual Comments

### Comment 1
<location path="src/common/VNoteMainManager.cpp" line_range="859-861" />
<code_context>
         notesDataList.append(data);
     }
+
     std::sort(notesDataList.begin(), notesDataList.end(), NoteCompare());
+
     auto it = std::find_if(notesDataList.begin(), notesDataList.end(), [id](const QVariantMap &item)->bool {
         return item.value("noteId").toInt() == id;
     });
</code_context>
<issue_to_address>
**issue (bug_risk):** Use NOTE_ID_KEY instead of the literal "noteId" to keep the key usage consistent.

Immediately after inserting `NOTE_ID_KEY` into `data`, the predicate still uses the literal "noteId". If `NOTE_ID_KEY` ever changes, `find_if` will stop finding the correct entry. Use `NOTE_ID_KEY` in the predicate as well:

```cpp
auto it = std::find_if(notesDataList.begin(), notesDataList.end(), [id](const QVariantMap &item)->bool {
    return item.value(NOTE_ID_KEY).toInt() == id;
});
```
</issue_to_address>

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.

Comment thread src/common/VNoteMainManager.cpp
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengzhongyuan365-dev, lzwind

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

@dengzhongyuan365-dev

Copy link
Copy Markdown
Member Author

/forcemerge

@deepin-bot

deepin-bot Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

This pr force merged! (status: unstable)

@deepin-bot deepin-bot Bot merged commit 1941317 into linuxdeepin:develop/snipe Jun 17, 2026
19 of 21 checks passed
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:100分

■ 【总体评价】

代码完美修复了笔记列表排序不稳定问题,逻辑严谨且无任何缺陷
逻辑正确、结构优化、性能无损且无安全漏洞,不予扣分

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓

修复了 std::sort 在比较条件不构成严格弱序时导致的排序不稳定问题。原代码在修改时间相同时返回 false,导致等价元素顺序不确定;新代码在 VNoteMainManager.cpp 的 NoteCompare 仿函数中引入 ID 降序作为最终判定条件,确保了严格弱序关系,彻底消除了同秒创建笔记的顺序抖动。
建议:当前逻辑已完善,保持现状即可。

  • 2.代码质量(优秀)✓

消除了不必要的 else 分支,采用早返回模式降低了代码嵌套层级。注释从机械的“比较 isTop 字段”升级为准确描述业务意图的“置顶笔记排在普通笔记前面”,并在 updateTop 函数调用排序前后增加了合理的空行,极大提升了可读性。
建议:当前代码质量已达到优秀标准,无需额外修改。

  • 3.代码性能(高效)✓

增加了一次 toInt() 调用与整数比较操作,排序算法的时间复杂度仍维持在 O(N log N),仅存在极微小的常数项增长。对于笔记列表这种典型的小规模数据集而言,该开销完全在可忽略范围内,未引入任何不必要的系统调用或资源消耗。
建议:无需优化。

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码仅涉及内存中 QVariantMap 数据的读取与基础类型比较,未涉及任何外部输入解析、文件系统操作、命令执行或网络通信,攻击面为零,无安全风险。
建议:无需安全修复,当前实现安全可靠。

■ 【改进建议代码示例】

// 虽然当前代码已非常优秀,但可进一步增加对异常时间数据的容错处理,提升健壮性
struct NoteCompare {
    bool operator()(const QVariantMap &a, const QVariantMap &b) const {
        // 置顶笔记排在普通笔记前面
        bool aIsTop = a.value(NOTE_ISTOP_KEY).toBool();
        bool bIsTop = b.value(NOTE_ISTOP_KEY).toBool();

        if (aIsTop != bIsTop) {
            return aIsTop > bIsTop;
        }

        // 相同置顶状态下,按最近修改时间降序排列
        QDateTime aModifyTime = QDateTime::fromString(a.value(NOTE_MODIFY_TIME_KEY).toString(), "yyyy-MM-dd hh:mm:ss");
        QDateTime bModifyTime = QDateTime::fromString(b.value(NOTE_MODIFY_TIME_KEY).toString(), "yyyy-MM-dd hh:mm:ss");

        // 增加时间有效性检查,防止底层数据损坏导致解析出无效时间
        if (aModifyTime.isValid() && bModifyTime.isValid()) {
            if (aModifyTime != bModifyTime) {
                return aModifyTime > bModifyTime;
            }
        } else if (aModifyTime.isValid() != bModifyTime.isValid()) {
            // 有效时间优先于无效时间
            return aModifyTime.isValid();
        }

        // 修改时间相同或无效时,按笔记ID降序避免同秒创建的笔记顺序不稳定
        return a.value(NOTE_ID_KEY).toInt() > b.value(NOTE_ID_KEY).toInt();
    }
};

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.

3 participants