Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/resolve all conflicts #5635

Merged
merged 28 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7b4245a
fix #include header style
mgallien Apr 28, 2023
1491c13
basic implementation of a dialog to resolve conflicts as a batch
mgallien Apr 28, 2023
396accd
feedback from design review
mgallien Apr 28, 2023
4bd93e3
more qml feedback
mgallien May 2, 2023
8f61d53
replace "OK" button by "Resolve conflicts" to help users
mgallien May 3, 2023
280094b
model: first step
mgallien May 2, 2023
72b78c9
replace "Sync now" button by "Solve all conflicts" for many conflicts
mgallien May 3, 2023
c118958
do not show many conflicts dialog for a single conflict
mgallien May 3, 2023
f799d8c
tune the pipes to really get a dialog to show for many conflicts
mgallien May 3, 2023
789ca72
plug models into the dialog
mgallien May 3, 2023
779cc3a
display icons for files when solving many conflicts
mgallien May 3, 2023
6efa9f8
prevent close of conflicts dialog on focus lost
mgallien May 4, 2023
2e501f0
add some margins at bottom of items in conflicts list view
mgallien May 4, 2023
30bba4c
fix automated tests
mgallien May 4, 2023
382a58c
allow the conflicts dialog to close
mgallien May 4, 2023
fa135a4
ensure the URL to mimetype icons are correct
mgallien May 4, 2023
8d52d4e
implement more feedback
mgallien May 4, 2023
739c56c
allow selecting conflict resolutions for many conflicts
mgallien May 12, 2023
230e2de
solve multiple conflicts from choose resolution
mgallien May 12, 2023
31e4ded
refactor common parts of conflict delegate into a separate component
mgallien May 16, 2023
635b1ec
define constants specific for font sizes in conflict dialog
mgallien May 16, 2023
b285b89
define minimum sizes of conflict dialogs in Style component
mgallien May 16, 2023
8d81257
improve translations for strings with placeholder to display numbers
mgallien May 16, 2023
5349395
model improvements
mgallien May 16, 2023
14bce6f
improve reliability of memeory management when creating conflicts dialog
mgallien May 16, 2023
8faab81
improve automated tests
mgallien May 16, 2023
8f60518
small qml cleanup to make code faster to read
mgallien May 16, 2023
6c7f810
improve code in activity list model
mgallien May 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,8 @@
<file>src/gui/tray/ListItemLineAndSubline.qml</file>
<file>src/gui/tray/TrayFoldersMenuButton.qml</file>
<file>src/gui/tray/TrayFolderListItem.qml</file>
<file>src/gui/ResolveConflictsDialog.qml</file>
<file>src/gui/ConflictDelegate.qml</file>
<file>src/gui/ConflictItemFileInfo.qml</file>
</qresource>
</RCC>
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ set(client_SRCS
userstatusselectormodel.cpp
emojimodel.h
emojimodel.cpp
syncconflictsmodel.h
syncconflictsmodel.cpp
fileactivitylistmodel.h
fileactivitylistmodel.cpp
filedetails/filedetails.h
Expand Down
86 changes: 86 additions & 0 deletions src/gui/ConflictDelegate.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2023 by Matthieu Gallien <matthieu.gallien@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

import QtQml 2.15
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import Style 1.0
import com.nextcloud.desktopclient 1.0
import "./tray"

Item {
id: root

required property string existingFileName
required property string existingSize
required property string conflictSize
required property string existingDate
required property string conflictDate
required property bool existingSelected
required property bool conflictSelected
required property url existingPreviewUrl
required property url conflictPreviewUrl
required property var model

EnforcedPlainTextLabel {
id: existingFileNameLabel

anchors.top: parent.top
anchors.left: parent.left

text: root.existingFileName

font.weight: Font.Bold
font.pixelSize: Style.fontPixelSizeResolveConflictsDialog
}

RowLayout {
anchors.top: existingFileNameLabel.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 8

ConflictItemFileInfo {
Layout.fillWidth: true
Layout.fillHeight: true

itemSelected: root.existingSelected
itemPreviewUrl: root.existingPreviewUrl
itemVersionLabel: qsTr('Local version')
itemDateLabel: root.existingDate
itemFileSizeLabel: root.existingSize

onSelectedChanged: function() {
model.existingSelected = itemSelected
}
}

ConflictItemFileInfo {
Layout.fillWidth: true
Layout.fillHeight: true

itemSelected: root.conflictSelected
itemPreviewUrl: root.conflictPreviewUrl
itemVersionLabel: qsTr('Server version')
itemDateLabel: root.conflictDate
itemFileSizeLabel: root.conflictSize

onSelectedChanged: function() {
model.conflictSelected = itemSelected
}
}
}
}
98 changes: 98 additions & 0 deletions src/gui/ConflictItemFileInfo.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2023 by Matthieu Gallien <matthieu.gallien@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

import QtQml 2.15
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import Style 1.0
import "./tray"

Item {
property alias itemSelected: selectItem.checked
property alias itemPreviewUrl: itemPreview.source
property alias itemVersionLabel: versionLabel.text
property alias itemDateLabel: dateLabel.text
property alias itemFileSizeLabel: fileSizeLabel.text

signal selectedChanged()

CheckBox {
id: selectItem

anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter

leftPadding: 0
spacing: 0

onToggled: function() {
selectedChanged()
}
}

Image {
id: itemPreview

anchors.left: selectItem.right
anchors.verticalCenter: parent.verticalCenter

width: 48
height: 48
sourceSize.width: 48
sourceSize.height: 48
}

ColumnLayout {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: itemPreview.right
anchors.right: parent.right
anchors.leftMargin: 10

spacing: 0

Item {
Layout.fillHeight: true
}

EnforcedPlainTextLabel {
id: versionLabel

Layout.fillWidth: true

font.pixelSize: Style.fontPixelSizeResolveConflictsDialog
}

EnforcedPlainTextLabel {
id: dateLabel

Layout.fillWidth: true

font.pixelSize: Style.fontPixelSizeResolveConflictsDialog
}

EnforcedPlainTextLabel {
id: fileSizeLabel

Layout.fillWidth: true

font.pixelSize: Style.fontPixelSizeResolveConflictsDialog
}

Item {
Layout.fillHeight: true
}
}
}
174 changes: 174 additions & 0 deletions src/gui/ResolveConflictsDialog.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright (C) 2023 by Matthieu Gallien <matthieu.gallien@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

import QtQml 2.15
import QtQuick 2.15
import QtQuick.Window 2.15 as QtWindow
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15
import Style 1.0
import com.nextcloud.desktopclient 1.0
import "./tray"

QtWindow.Window {
id: conflictsDialog

required property var allConflicts

flags: Qt.Window | Qt.Dialog
visible: true

width: Style.minimumWidthResolveConflictsDialog
height: Style.minimumHeightResolveConflictsDialog
minimumWidth: Style.minimumWidthResolveConflictsDialog
minimumHeight: Style.minimumHeightResolveConflictsDialog
title: qsTr('Solve sync conflicts')

onClosing: function(close) {
Systray.destroyDialog(self);
close.accepted = true
}

ColumnLayout {
anchors.fill: parent
anchors.leftMargin: 20
anchors.rightMargin: 20
anchors.bottomMargin: 20
anchors.topMargin: 20
spacing: 15
z: 2

EnforcedPlainTextLabel {
text: qsTr("%1 files in conflict", 'indicate the number of conflicts to resolve', delegateModel.count).arg(delegateModel.count)
font.bold: true
font.pixelSize: Style.bigFontPixelSizeResolveConflictsDialog
Layout.fillWidth: true
}

EnforcedPlainTextLabel {
text: qsTr("Choose if you want to keep the local version, server version, or both. If you choose both, the local file will have a number added to its name.")
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
font.pixelSize: Style.fontPixelSizeResolveConflictsDialog
Layout.fillWidth: true
Layout.topMargin: -15
}

RowLayout {
Layout.fillWidth: true
Layout.topMargin: 15

CheckBox {
id: selectExisting

Layout.fillWidth: true

text: qsTr('All local versions')

leftPadding: 0
implicitWidth: 100

font.pixelSize: Style.fontPixelSizeResolveConflictsDialog

checked: realModel.allExistingsSelected
onToggled: function() {
realModel.selectAllExisting(checked)
}
}

CheckBox {
id: selectConflict

Layout.fillWidth: true

text: qsTr('All server versions')

leftPadding: 0
implicitWidth: 100

font.pixelSize: Style.fontPixelSizeResolveConflictsDialog

checked: realModel.allConflictingSelected
onToggled: function() {
realModel.selectAllConflicting(checked)
}
}
}

Rectangle {
Layout.fillWidth: true
Layout.leftMargin: 5
Layout.rightMargin: 5
color: Style.menuBorder
height: 1
}

SyncConflictsModel {
id: realModel

conflictActivities: conflictsDialog.allConflicts
}

ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true

ScrollBar.horizontal.policy: ScrollBar.AlwaysOff

ListView {
id: conflictListView

model: DelegateModel {
id: delegateModel

model: realModel

delegate: ConflictDelegate {
width: conflictListView.contentItem.width
height: 100
}
}
}
}

DialogButtonBox {
Layout.fillWidth: true

Button {
text: qsTr("Resolve conflicts")
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
}
Button {
text: qsTr("Cancel")
DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
}

onAccepted: function() {
realModel.applySolution()
Systray.destroyDialog(conflictsDialog)
}

onRejected: function() {
Systray.destroyDialog(conflictsDialog)
}
}
}

Rectangle {
color: Theme.systemPalette.window
anchors.fill: parent
z: 1
}
}
1 change: 1 addition & 0 deletions src/gui/conflictsolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ConflictSolver : public QObject
KeepRemoteVersion,
KeepBothVersions
};
Q_ENUM(Solution);

explicit ConflictSolver(QWidget *parent = nullptr);

Expand Down
Loading