Import/Export final touches

This commit is contained in:
Michal Horejsek
2020-08-12 13:56:49 +02:00
parent 4f0af0fb02
commit 658ead9fb3
82 changed files with 451 additions and 450 deletions

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package cli
package cliie
import (
"fmt"

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package cli
package cliie
import (
"strings"

View File

@ -15,8 +15,8 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Package cli provides CLI interface of the Import/Export.
package cli
// Package cliie provides CLI interface of the Import-Export app.
package cliie
import (
"github.com/ProtonMail/proton-bridge/internal/events"
@ -68,7 +68,7 @@ func New( //nolint[funlen]
Aliases: []string{"cl"},
}
clearCmd.AddCmd(&ishell.Cmd{Name: "accounts",
Help: "remove all accounts from keychain. (aliases: k, keychain)",
Help: "remove all accounts from keychain. (aliases: a, k, keychain)",
Aliases: []string{"a", "k", "keychain"},
Func: fe.deleteAccounts,
})
@ -77,7 +77,7 @@ func New( //nolint[funlen]
// Check commands.
checkCmd := &ishell.Cmd{Name: "check", Help: "check internet connection or new version."}
checkCmd.AddCmd(&ishell.Cmd{Name: "updates",
Help: "check for Import/Export updates. (aliases: u, v, version)",
Help: "check for Import-Export updates. (aliases: u, v, version)",
Aliases: []string{"u", "version", "v"},
Func: fe.checkUpdates,
})
@ -134,7 +134,7 @@ func New( //nolint[funlen]
Completer: fe.completeUsernames,
})
// Import/Export commands.
// Import-Export commands.
importCmd := &ishell.Cmd{Name: "import",
Help: "import messages. (alias: imp)",
Aliases: []string{"imp"},
@ -167,7 +167,7 @@ func New( //nolint[funlen]
// System commands.
fe.AddCmd(&ishell.Cmd{Name: "restart",
Help: "restart the import/export.",
Help: "restart the Import-Export app.",
Func: fe.restart,
})
@ -190,7 +190,7 @@ func (f *frontendCLI) watchEvents() {
for {
select {
case errorDetails := <-errorCh:
f.Println("Import/Export failed:", errorDetails)
f.Println("Import-Export failed:", errorDetails)
case <-internetOffCh:
f.notifyInternetOff()
case <-internetOnCh:
@ -228,9 +228,9 @@ func (f *frontendCLI) Loop(credentialsError error) error {
}
f.Print(`
Welcome to ProtonMail Import/Export interactive shell
Welcome to ProtonMail Import-Export interactive shell
WARNING: CLI is experimental feature and does not cover all functionality yet.
WARNING: The CLI is an experimental feature and does not yet cover all functionality.
`)
f.Run()
return nil

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package cli
package cliie
import (
"fmt"

View File

@ -15,19 +15,15 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package cli
package cliie
import (
"github.com/abiosoft/ishell"
)
var (
currentPort = "" //nolint[gochecknoglobals]
)
func (f *frontendCLI) restart(c *ishell.Context) {
if f.yesNoQuestion("Are you sure you want to restart the Import/Export") {
f.Println("Restarting Import/Export...")
if f.yesNoQuestion("Are you sure you want to restart the Import-Export") {
f.Println("Restarting the Import-Export app...")
f.appRestart = true
f.Stop()
}
@ -37,7 +33,7 @@ func (f *frontendCLI) checkInternetConnection(c *ishell.Context) {
if f.ie.CheckConnection() == nil {
f.Println("Internet connection is available.")
} else {
f.Println("Can not contact the server, please check you internet connection.")
f.Println("Can not contact the server, please check your internet connection.")
}
}
@ -46,5 +42,5 @@ func (f *frontendCLI) printLogDir(c *ishell.Context) {
}
func (f *frontendCLI) printManual(c *ishell.Context) {
f.Println("More instructions about the Import/Export can be found at\n\n https://protonmail.com/support/categories/import-export/")
f.Println("More instructions about the Import-Export app can be found at\n\n https://protonmail.com/support/categories/import-export/")
}

View File

@ -15,13 +15,13 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package cli
package cliie
import (
"strings"
"github.com/ProtonMail/proton-bridge/internal/importexport"
"github.com/ProtonMail/proton-bridge/pkg/updates"
"github.com/ProtonMail/proton-bridge/internal/updates"
"github.com/abiosoft/ishell"
)
@ -47,7 +47,7 @@ func (f *frontendCLI) printLocalReleaseNotes(c *ishell.Context) {
}
func (f *frontendCLI) printReleaseNotes(versionInfo updates.VersionInfo) {
f.Println(bold("ProtonMail Import/Export "+versionInfo.Version), "\n")
f.Println(bold("ProtonMail Import-Export "+versionInfo.Version), "\n")
if versionInfo.ReleaseNotes != "" {
f.Println(bold("Release Notes"))
f.Println(versionInfo.ReleaseNotes)

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package cli
package cliie
import (
"strings"
@ -98,7 +98,7 @@ func (f *frontendCLI) notifyNeedUpgrade() {
func (f *frontendCLI) notifyCredentialsError() {
// Print in 80-column width.
f.Println("ProtonMail Import/Export is not able to detect a supported password manager")
f.Println("ProtonMail Import-Export is not able to detect a supported password manager")
f.Println("(pass, gnome-keyring). Please install and set up a supported password manager")
f.Println("and restart the application.")
}
@ -109,7 +109,7 @@ func (f *frontendCLI) notifyCertIssue() {
be insecure.
Description:
ProtonMail Import/Export was not able to establish a secure connection to Proton
ProtonMail Import-Export was not able to establish a secure connection to Proton
servers due to a TLS certificate error. This means your connection may
potentially be insecure and susceptible to monitoring by third parties.

View File

@ -76,7 +76,7 @@ func New( //nolint[funlen]
Func: fe.deleteCache,
})
clearCmd.AddCmd(&ishell.Cmd{Name: "accounts",
Help: "remove all accounts from keychain. (aliases: k, keychain)",
Help: "remove all accounts from keychain. (aliases: a, k, keychain)",
Aliases: []string{"a", "k", "keychain"},
Func: fe.deleteAccounts,
})

View File

@ -43,7 +43,7 @@ func (f *frontendCLI) checkInternetConnection(c *ishell.Context) {
if f.bridge.CheckConnection() == nil {
f.Println("Internet connection is available.")
} else {
f.Println("Can not contact the server, please check you internet connection.")
f.Println("Can not contact the server, please check your internet connection.")
}
}

View File

@ -21,7 +21,7 @@ import (
"strings"
"github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/pkg/updates"
"github.com/ProtonMail/proton-bridge/internal/updates"
"github.com/abiosoft/ishell"
)

View File

@ -458,7 +458,7 @@ Dialog {
if (progressbarImport.isFinished) return qsTr("Import finished","todo")
if (
go.progressDescription == gui.enums.progressInit ||
(go.progress == 0 && go.description=="")
(go.progress == 0 && go.progressDescription=="")
) return qsTr("Estimating the total number of messages","todo")
if (
go.progressDescription == gui.enums.progressLooping

View File

@ -43,6 +43,8 @@ Rectangle {
property string lastTargetFolder: "6" // Archive
property string lastTargetLabels: "" // no flag by default
property string sourceID : mboxID
property string sourceName : name
Rectangle {
id: line
@ -71,7 +73,7 @@ Rectangle {
Text {
id: folderIcon
text : gui.folderIcon(name, gui.enums.folderTypeFolder)
text : gui.folderIcon(root.sourceName, gui.enums.folderTypeFolder)
anchors.verticalCenter : parent.verticalCenter
color: root.isSourceSelected ? Style.main.text : Style.main.textDisabled
font {
@ -81,7 +83,7 @@ Rectangle {
}
Text {
text : name
text : root.sourceName
width: nameWidth
elide: Text.ElideRight
anchors.verticalCenter : parent.verticalCenter
@ -102,8 +104,8 @@ Rectangle {
SelectFolderMenu {
id: selectFolder
sourceID: mboxID
targets: transferRules.targetFolders(mboxID)
sourceID: root.sourceID
targets: transferRules.targetFolders(root.sourceID)
width: nameWidth
anchors.verticalCenter : parent.verticalCenter
enabled: root.isSourceSelected
@ -112,8 +114,8 @@ Rectangle {
}
SelectLabelsMenu {
sourceID: mboxID
targets: transferRules.targetLabels(mboxID)
sourceID: root.sourceID
targets: transferRules.targetLabels(root.sourceID)
width: nameWidth
anchors.verticalCenter : parent.verticalCenter
enabled: root.isSourceSelected
@ -130,7 +132,7 @@ Rectangle {
DateRangeMenu {
id: dateRangeMenu
sourceID: mboxID
sourceID: root.sourceID
sourceFromDate: fromDate
sourceToDate: toDate
@ -143,10 +145,10 @@ Rectangle {
function importToFolder(newTargetID) {
transferRules.addTargetID(mboxID,newTargetID)
transferRules.addTargetID(root.sourceID,newTargetID)
}
function toggleImport() {
transferRules.setIsRuleActive(mboxID, !root.isSourceSelected)
transferRules.setIsRuleActive(root.sourceID, !root.isSourceSelected)
}
}

View File

@ -110,7 +110,7 @@ Rectangle {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: {
if (listview.currentIndex<0) return 0
if (listview.currentItem === null) return 0
else return listview.currentItem.leftMargin1
}
}

View File

@ -112,7 +112,7 @@ Window {
rightMargin: innerWindowBorder
}
model: [
{ "title" : qsTr("Import/Export" , "title of tab that shows account list" ), "iconText": Style.fa.home },
{ "title" : qsTr("Import-Export" , "title of tab that shows account list" ), "iconText": Style.fa.home },
{ "title" : qsTr("Settings" , "title of tab that allows user to change settings" ), "iconText": Style.fa.cogs },
{ "title" : qsTr("Help" , "title of tab that shows the help menu" ), "iconText": Style.fa.life_ring }
]
@ -381,8 +381,9 @@ Window {
onClickedNo: popupMessage.hide()
onClickedOkay: popupMessage.hide()
onClickedCancel: popupMessage.hide()
onClickedYes: {
if (popupMessage.message == gui.areYouSureYouWantToQuit) Qt.quit()
if (popupMessage.text == gui.areYouSureYouWantToQuit) Qt.quit()
}
}
@ -461,8 +462,9 @@ Window {
(dialogExport.visible && dialogExport.currentIndex == 2 && go.progress!=1)
) {
popupMessage.buttonOkay .visible = false
popupMessage.buttonNo .visible = true
popupMessage.buttonYes .visible = true
popupMessage.buttonYes .visible = false
popupMessage.buttonQuit .visible = true
popupMessage.buttonCancel .visible = true
popupMessage.show ( gui.areYouSureYouWantToQuit )
return
}

View File

@ -58,7 +58,6 @@ ComboBox {
}
displayText: {
console.log("Target Menu current", view.currentItem, view.currentIndex)
if (view.currentIndex >= 0) {
if (!root.isFolderType) return Style.fa.tags + " " + qsTr("Add/Remove labels")

View File

@ -25,6 +25,7 @@ Rectangle {
color: Style.transparent
property alias text : message.text
property alias checkbox : checkbox
property alias buttonQuit : buttonQuit
property alias buttonOkay : buttonOkay
property alias buttonYes : buttonYes
property alias buttonNo : buttonNo
@ -89,13 +90,13 @@ Rectangle {
spacing: Style.dialog.spacing
anchors.horizontalCenter : parent.horizontalCenter
ButtonRounded { id : buttonQuit ; text : qsTr ( "Stop & quit", "" ) ; onClicked : root.clickedYes ( ) ; visible : false ; isOpaque : true ; color_main : Style.errorDialog.text ; color_minor : Style.dialog.textBlue ; }
ButtonRounded { id : buttonNo ; text : qsTr ( "No" , "Button No" ) ; onClicked : root.clickedNo ( ) ; visible : false ; isOpaque : false ; color_main : Style.errorDialog.text ; color_minor : Style.transparent ; }
ButtonRounded { id : buttonYes ; text : qsTr ( "Yes" , "Button Yes" ) ; onClicked : root.clickedYes ( ) ; visible : false ; isOpaque : true ; color_main : Style.errorDialog.text ; color_minor : Style.dialog.textBlue ; }
ButtonRounded { id : buttonRetry ; text : qsTr ( "Retry" , "Button Retry" ) ; onClicked : root.clickedRetry ( ) ; visible : false ; isOpaque : false ; color_main : Style.errorDialog.text ; color_minor : Style.transparent ; }
ButtonRounded { id : buttonSkip ; text : qsTr ( "Skip" , "Button Skip" ) ; onClicked : root.clickedSkip ( ) ; visible : false ; isOpaque : false ; color_main : Style.errorDialog.text ; color_minor : Style.transparent ; }
ButtonRounded { id : buttonCancel ; text : qsTr ( "Cancel" , "Button Cancel" ) ; onClicked : root.clickedCancel ( ) ; visible : false ; isOpaque : true ; color_main : Style.errorDialog.text ; color_minor : Style.dialog.textBlue ; }
ButtonRounded { id : buttonOkay ; text : qsTr ( "Okay" , "Button Okay" ) ; onClicked : root.clickedOkay ( ) ; visible : true ; isOpaque : true ; color_main : Style.errorDialog.text ; color_minor : Style.dialog.textBlue ; }
}
}
}

View File

@ -99,7 +99,7 @@ Window {
id: buttons
ListElement { title : "Show window" }
ListElement { title : "Logout cuthix" }
ListElement { title : "Logout" }
ListElement { title : "Internet on" }
ListElement { title : "Internet off" }
ListElement { title : "Macos" }
@ -143,8 +143,8 @@ Window {
case "Show window" :
go.showWindow();
break;
case "Logout cuthix" :
go.checkLoggedOut("cuthix");
case "Logout" :
go.checkLoggedOut("ie");
break;
case "Internet on" :
go.setConnectionStatus(true);
@ -223,10 +223,10 @@ Window {
ListModel{
id: accountsModel
ListElement{ account : "cuthix" ; status : "connected"; isExpanded: false; isCombinedAddressMode: false; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "cuto@pm.com;jaku@pm.com;DoYouKnowAboutAMovieCalledTheHorriblySlowMurderWithExtremelyInefficientWeapon@thatYouCanFindForExampleOnyoutube.com" }
ListElement{ account : "exteremelongnamewhichmustbeeladedinthemiddleoftheaddress@protonmail.com" ; status : "connected"; isExpanded: true; isCombinedAddressMode: true; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "cuto@pm.com;jaku@pm.com;hu@hu.hu" }
ListElement{ account : "cuthix2@protonmail.com" ; status : "disconnected"; isExpanded: false; isCombinedAddressMode: false; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "cuto@pm.com;jaku@pm.com;hu@hu.hu" }
ListElement{ account : "many@protonmail.com" ; status : "connected"; isExpanded: true; isCombinedAddressMode: true; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;cuto@pm.com;jaku@pm.com;hu@hu.hu;"}
ListElement{ account : "ie" ; status : "connected"; isExpanded: false; isCombinedAddressMode: false; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "ie@pm.com;jaku@pm.com;DoYouKnowAboutAMovieCalledTheHorriblySlowMurderWithExtremelyInefficientWeapon@thatYouCanFindForExampleOnyoutube.com" }
ListElement{ account : "exteremelongnamewhichmustbeeladedinthemiddleoftheaddress@protonmail.com" ; status : "connected"; isExpanded: true; isCombinedAddressMode: true; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "ie@pm.com;jaku@pm.com;hu@hu.hu" }
ListElement{ account : "ie2@protonmail.com" ; status : "disconnected"; isExpanded: false; isCombinedAddressMode: false; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "ie@pm.com;jaku@pm.com;hu@hu.hu" }
ListElement{ account : "many@protonmail.com" ; status : "connected"; isExpanded: true; isCombinedAddressMode: true; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;ie@pm.com;jaku@pm.com;hu@hu.hu;"}
}
ListModel{
@ -830,9 +830,9 @@ Window {
property string bugNotSent
property string bugReportSent
property string programTitle : "ProtonMail Import/Export Tool"
property string programTitle : "ProtonMail Import-Export App"
property string newversion : "q0.1.0"
property string landingPage : "https://jakub.cuth.sk/bridge"
property string landingPage : "https://landing.page"
property string changelog : "• Lorem ipsum dolor sit amet\n• consetetur sadipscing elitr,\n• sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\n• sed diam voluptua.\n• At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
//property string changelog : ""
property string bugfixes : "• lorem ipsum dolor sit amet;• consetetur sadipscing elitr;• sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat;• sed diam voluptua;• at vero eos et accusam et justo duo dolores et ea rebum;• stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet"

View File

@ -103,16 +103,6 @@ func PauseLong() {
time.Sleep(3 * time.Second)
}
func ParsePMAPIError(err error, code int) error {
/*
if err == pmapi.ErrAPINotReachable {
code = ErrNoInternet
}
return errors.NewFromError(code, err)
*/
return nil
}
// FIXME: Not working in test...
func WaitForEnter() {
log.Print("Press 'Enter' to continue...")

View File

@ -47,6 +47,18 @@ func (f *FrontendQt) LoadStructureForExport(addressOrID string) {
return
}
// Export has only one option to set time limits--by global time range.
// In case user changes file or because of some bug global time is saved
// to all rules, let's clear it, because there is no way to show it in
// GUI and user would be confused and see it does not work at all.
for _, rule := range f.transfer.GetRules() {
isActive := rule.Active
f.transfer.SetRule(rule.SourceMailbox, rule.TargetMailboxes, 0, 0)
if !isActive {
f.transfer.UnsetRule(rule.SourceMailbox)
}
}
f.TransferRules.setTransfer(f.transfer)
}
@ -65,55 +77,4 @@ func (f *FrontendQt) StartExport(rootPath, login, fileType string, attachEncrypt
f.transfer.SetSkipEncryptedMessages(!attachEncryptedBody)
progress := f.transfer.Start()
f.setProgressManager(progress)
/*
TODO
f.Qml.SetProgress(0.0)
f.Qml.SetProgressDescription(backend.ProgressInit)
f.Qml.SetTotal(0)
settings := backend.ExportSettings{
FilePath: fpath,
Login: login,
AttachEncryptedBody: attachEncryptedBody,
DateBegin: 0,
DateEnd: 0,
Labels: make(map[string]string),
}
if fileType == "EML" {
settings.FileTypeID = backend.EMLFormat
} else if fileType == "MBOX" {
settings.FileTypeID = backend.MBOXFormat
} else {
log.Errorln("Wrong file format:", fileType)
return
}
username, _, err := backend.ExtractUsername(login)
if err != nil {
log.Error("qtfrontend: cannot retrieve username from alias: ", err)
return
}
settings.User, err = backend.ExtractCurrentUser(username)
if err != nil && !errors.IsCode(err, errors.ErrUnlockUser) {
return
}
for _, entity := range f.PMStructure.entities {
if entity.IsFolderSelected {
settings.Labels[entity.FolderName] = entity.FolderId
}
}
settings.DateBegin = f.PMStructure.GlobalOptions.FromDate
settings.DateEnd = f.PMStructure.GlobalOptions.ToDate
settings.PM = backend.NewProcessManager()
f.setHandlers(settings.PM)
log.Debugln("start export", settings.FilePath)
go backend.Export(f.panicHandler, settings)
*/
}

View File

@ -59,10 +59,6 @@ func getTargetHashes(mboxes []transfer.Mailbox) (targetFolderID, targetLabelIDs
return
}
func isSystemMailbox(mbox transfer.Mailbox) bool {
return pmapi.IsSystemLabel(mbox.ID)
}
func newFolderInfo(mbox transfer.Mailbox, rule *transfer.Rule) *FolderInfo {
targetFolderID, targetLabelIDs := getTargetHashes(rule.TargetMailboxes)
@ -77,7 +73,7 @@ func newFolderInfo(mbox transfer.Mailbox, rule *transfer.Rule) *FolderInfo {
}
entry.FolderType = FolderTypeSystem
if !isSystemMailbox(mbox) {
if !pmapi.IsSystemLabel(mbox.ID) {
if mbox.IsExclusive {
entry.FolderType = FolderTypeFolder
} else {
@ -112,7 +108,7 @@ func (s *FolderStructure) saveRule(info *FolderInfo) error {
return s.transfer.SetRule(sourceMbox, targetMboxes, info.FromDate, info.ToDate)
}
func (s *FolderInfo) updateTgtLblIDs(targetLabelsSet map[string]struct{}) {
func (s *FolderInfo) updateTargetLabelIDs(targetLabelsSet map[string]struct{}) {
targets := []string{}
for key := range targetLabelsSet {
targets = append(targets, key)
@ -120,17 +116,13 @@ func (s *FolderInfo) updateTgtLblIDs(targetLabelsSet map[string]struct{}) {
s.TargetLabelIDs = strings.Join(targets, ";")
}
func (s *FolderInfo) clearTgtLblIDs() {
s.TargetLabelIDs = ""
}
func (s *FolderInfo) AddTargetLabel(targetID string) {
if targetID == "" {
return
}
targetLabelsSet := s.getSetOfLabels()
targetLabelsSet[targetID] = struct{}{}
s.updateTgtLblIDs(targetLabelsSet)
s.updateTargetLabelIDs(targetLabelsSet)
}
func (s *FolderInfo) RemoveTargetLabel(targetID string) {
@ -139,7 +131,7 @@ func (s *FolderInfo) RemoveTargetLabel(targetID string) {
}
targetLabelsSet := s.getSetOfLabels()
delete(targetLabelsSet, targetID)
s.updateTgtLblIDs(targetLabelsSet)
s.updateTargetLabelIDs(targetLabelsSet)
}
func (s *FolderInfo) IsType(askType string) bool {
@ -387,7 +379,7 @@ func (s *FolderStructure) setTargetFolderID(id, target string) {
s.changedEntityRole(i, i, TargetFolderID)
if target == "" { // do not import
before := info.TargetLabelIDs
info.clearTgtLblIDs()
info.TargetLabelIDs = ""
if err := s.saveRule(info); err != nil {
info.TargetLabelIDs = before
log.WithError(err).WithField("id", id).WithField("target", target).Error("Cannot set target")

View File

@ -29,9 +29,9 @@ import (
qtcommon "github.com/ProtonMail/proton-bridge/internal/frontend/qt-common"
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
"github.com/ProtonMail/proton-bridge/internal/transfer"
"github.com/ProtonMail/proton-bridge/internal/updates"
"github.com/ProtonMail/proton-bridge/pkg/config"
"github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/ProtonMail/proton-bridge/pkg/updates"
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/gui"
@ -185,7 +185,7 @@ func (f *FrontendQt) qtSetupQmlAndStructures() {
f.View.Load(core.NewQUrl3("qrc:/uiie.qml", 0))
// TODO set the first start flag
log.Error("Get FirstStart: Not implemented")
//log.Error("Get FirstStart: Not implemented")
//if prefs.Get(prefs.FirstStart) == "true" {
if false {
f.Qml.SetIsFirstStart(true)
@ -226,7 +226,6 @@ func (f *FrontendQt) QtExecute(Procedure func(*FrontendQt) error) error {
return err
}
log.Debug("Closing...")
log.Error("Set FirstStart: Not implemented")
//prefs.Set(prefs.FirstStart, "false")
return nil
}
@ -318,27 +317,31 @@ func (f *FrontendQt) setProgressManager(progress *transfer.Progress) {
f.Qml.ConnectCancelProcess(func() {
progress.Stop()
})
f.Qml.SetProgress(0)
go func() {
log.Trace("Start reading updates")
defer func() {
log.Trace("Finishing reading updates")
f.Qml.DisconnectPauseProcess()
f.Qml.DisconnectResumeProcess()
f.Qml.DisconnectCancelProcess()
f.Qml.SetProgress(1)
f.progress = nil
f.ErrorList.Progress = nil
}()
//TODO get log file (in old code it was here, but this is ugly place probably somewhere else)
updates := progress.GetUpdateChannel()
for range updates {
if progress.IsStopped() {
break
}
failed, imported, _, _, total := progress.GetCounts()
if total != 0 { // udate total
if total != 0 {
f.Qml.SetTotal(int(total))
}
f.Qml.SetProgressFails(int(failed))
f.Qml.SetProgressDescription(progress.PauseReason()) // TODO add description when changing folders?
f.Qml.SetProgressDescription(progress.PauseReason())
if total > 0 {
newProgress := float32(imported+failed) / float32(total)
if newProgress >= 0 && newProgress != f.Qml.Progress() {
@ -436,7 +439,7 @@ func (f *FrontendQt) getLocalVersionInfo() {
// LeastUsedColor is intended to return color for creating a new inbox or label.
func (f *FrontendQt) leastUsedColor() string {
if f.transfer == nil {
log.Errorln("Getting least used color before transfer exist.")
log.Warnln("Getting least used color before transfer exist.")
return "#7272a7"
}

View File

@ -74,6 +74,8 @@ func (f *FrontendQt) loadStructuresForImport() error {
}
func (f *FrontendQt) StartImport(email string) { // TODO email not needed
log.Trace("Starting import")
f.Qml.SetProgressDescription("init") // TODO use const
f.Qml.SetProgressFails(0)
f.Qml.SetProgress(0.0)

View File

@ -55,8 +55,8 @@ func newMboxList(t *TransferRules, rule *transfer.Rule, containsFolders bool) *M
m.log = log.
WithField("rule", m.rule.SourceMailbox.Hash()).
WithField("folders", m.containsFolders)
m.updateSelectedIndex()
m.EndResetModel()
m.itemsChanged(rule)
return m
}
@ -71,11 +71,6 @@ func (m *MboxList) rowCount(index *core.QModelIndex) int {
}
func (m *MboxList) roleNames() map[int]*core.QByteArray {
m.log.
WithField("isActive", MboxIsActive).
WithField("id", MboxID).
WithField("color", MboxColor).
Debug("role names")
return map[int]*core.QByteArray{
MboxIsActive: qtcommon.NewQByteArrayFromString("isActive"),
MboxID: qtcommon.NewQByteArrayFromString("mboxID"),
@ -88,17 +83,17 @@ func (m *MboxList) roleNames() map[int]*core.QByteArray {
func (m *MboxList) data(index *core.QModelIndex, role int) *core.QVariant {
allTargets := m.targetMailboxes()
i, valid := index.Row(), index.IsValid()
l := m.log.WithField("row", i).WithField("role", role)
l.Trace("called data()")
i := index.Row()
log := m.log.WithField("row", i).WithField("role", role)
log.Trace("Mbox data")
if !valid || i >= len(allTargets) {
l.WithField("row", i).Warning("Invalid index")
if i >= len(allTargets) {
log.Warning("Invalid index")
return core.NewQVariant()
}
if m.transfer == nil {
l.Warning("Requested mbox list data before transfer is connected")
log.Warning("Requested mbox list data before transfer is connected")
return qtcommon.NewQVariantString("")
}
@ -131,7 +126,7 @@ func (m *MboxList) data(index *core.QModelIndex, role int) *core.QVariant {
return qtcommon.NewQVariantString(mbox.Color)
default:
l.Error("Requested mbox list data with unknown role")
log.Error("Requested mbox list data with unknown role")
return qtcommon.NewQVariantString("")
}
}
@ -161,11 +156,10 @@ func (m *MboxList) filter(mailboxes []transfer.Mailbox) (filtered []transfer.Mai
func (m *MboxList) itemsChanged(rule *transfer.Rule) {
m.rule = rule
allTargets := m.targetMailboxes()
l := m.log.WithField("count", len(allTargets))
l.Trace("called itemChanged()")
defer func() {
l.WithField("selected", m.SelectedIndex()).Trace("index updated")
}()
m.log.WithField("count", len(allTargets)).Trace("Mbox items changed")
m.updateSelectedIndex()
// NOTE: Be careful with indices: If they are invalid the DataChanged
// signal will not be sent to QML e.g. `end == rowCount - 1`
@ -175,7 +169,10 @@ func (m *MboxList) itemsChanged(rule *transfer.Rule) {
changedRoles := []int{MboxIsActive}
m.DataChanged(begin, end, changedRoles)
}
}
func (m *MboxList) updateSelectedIndex() {
allTargets := m.targetMailboxes()
for index, targetMailbox := range allTargets {
for _, selectedTarget := range m.rule.TargetMailboxes {
if targetMailbox.Hash() == selectedTarget.Hash() {

View File

@ -15,7 +15,9 @@
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package qtcommon
// +build !nogui
package qtie
import (
"io/ioutil"

View File

@ -44,6 +44,7 @@ type TransferRules struct {
_ func(sourceID string, targetID string) `slot:"addTargetID,auto"`
_ func(sourceID string, targetID string) `slot:"removeTargetID,auto"`
// globalFromDate and globalToDate is just default value for GUI, always zero.
_ int `property:"globalFromDate"`
_ int `property:"globalToDate"`
_ bool `property:"isLabelGroupSelected"`
@ -90,21 +91,23 @@ func (t *TransferRules) roleNames() map[int]*core.QByteArray {
}
func (t *TransferRules) data(index *core.QModelIndex, role int) *core.QVariant {
i, valid := index.Row(), index.IsValid()
if !valid || i >= t.rowCount(index) {
log.WithField("row", i).Warning("Invalid index")
return core.NewQVariant()
}
i := index.Row()
allRules := t.transfer.GetRules()
log := log.WithField("row", i).WithField("role", role)
log.Trace("Transfer rules data")
if i >= len(allRules) {
log.Warning("Invalid index")
return core.NewQVariant()
}
if t.transfer == nil {
log.Warning("Requested transfer rules data before transfer is connected")
return qtcommon.NewQVariantString("")
}
rule := t.transfer.GetRules()[i]
rule := allRules[i]
switch role {
case MboxIsActive:
@ -160,6 +163,9 @@ func (t *TransferRules) setTransfer(transfer *transfer.Transfer) {
t.transfer = transfer
t.targetFoldersCache = make(map[string]*MboxList)
t.targetLabelsCache = make(map[string]*MboxList)
t.updateGroupSelection()
}
@ -196,7 +202,9 @@ func (t *TransferRules) targetLabels(sourceID string) *MboxList {
// Setters
func (t *TransferRules) setIsGroupActive(groupName string, isActive bool) {
wantExclusive := (groupName == FolderTypeLabel)
log.WithField("group", groupName).WithField("active", isActive).Trace("Setting group as active/inactive")
wantExclusive := (groupName == FolderTypeFolder)
for _, rule := range t.transfer.GetRules() {
if rule.SourceMailbox.IsExclusive != wantExclusive {
continue
@ -265,6 +273,7 @@ func (t *TransferRules) addTargetID(sourceID string, targetID string) {
newTargetMailboxes = append(newTargetMailboxes, *targetMailboxToAdd)
}
t.setRule(rule.SourceMailbox, newTargetMailboxes, rule.FromTime, rule.ToTime, []int{RuleTargetLabelColors})
t.updateTargetSelection(sourceID, targetMailboxToAdd.IsExclusive)
}
func (t *TransferRules) removeTargetID(sourceID string, targetID string) {
@ -286,10 +295,14 @@ func (t *TransferRules) removeTargetID(sourceID string, targetID string) {
}
}
t.setRule(rule.SourceMailbox, newTargetMailboxes, rule.FromTime, rule.ToTime, []int{RuleTargetLabelColors})
t.updateTargetSelection(sourceID, targetMailboxToRemove.IsExclusive)
}
// Helpers
// getRule returns rule for given source ID.
// WARN: Always get new rule after change because previous pointer points to
// outdated struct with old data.
func (t *TransferRules) getRule(sourceID string) *transfer.Rule {
mailbox := t.getMailbox(t.transfer.SourceMailboxes, sourceID)
if mailbox == nil {
@ -331,20 +344,19 @@ func (t *TransferRules) unsetRule(sourceMailbox transfer.Mailbox) {
}
func (t *TransferRules) ruleChanged(sourceMailbox transfer.Mailbox, changedRoles []int) {
for row, rule := range t.transfer.GetRules() {
allRules := t.transfer.GetRules()
for row, rule := range allRules {
if rule.SourceMailbox.Hash() != sourceMailbox.Hash() {
continue
}
t.targetFolders(sourceMailbox.Hash()).itemsChanged(rule)
t.targetLabels(sourceMailbox.Hash()).itemsChanged(rule)
index := t.Index(row, 0, core.NewQModelIndex())
if !index.IsValid() || row >= t.rowCount(index) {
if !index.IsValid() || row >= len(allRules) {
log.WithField("row", row).Warning("Invalid index")
return
}
log.WithField("row", row).Trace("Transfer rule changed")
t.DataChanged(index, index, changedRoles)
break
}
@ -375,3 +387,16 @@ func (t *TransferRules) updateGroupSelection() {
t.SetIsLabelGroupSelected(areAllLabelsSelected)
t.SetIsFolderGroupSelected(areAllFoldersSelected)
}
func (t *TransferRules) updateTargetSelection(sourceID string, updateFolderSelect bool) {
rule := t.getRule(sourceID)
if rule == nil {
return
}
if updateFolderSelect {
t.targetFolders(rule.SourceMailbox.Hash()).itemsChanged(rule)
} else {
t.targetLabels(rule.SourceMailbox.Hash()).itemsChanged(rule)
}
}

View File

@ -22,7 +22,6 @@ package qtie
import (
"runtime"
qtcommon "github.com/ProtonMail/proton-bridge/internal/frontend/qt-common"
"github.com/therecipe/qt/core"
)
@ -181,7 +180,7 @@ func (s *GoQMLInterface) SetFrontend(f *FrontendQt) {
s.ConnectStartExport(f.StartExport)
s.ConnectStartImport(f.StartImport)
s.ConnectCheckPathStatus(qtcommon.CheckPathStatus)
s.ConnectCheckPathStatus(CheckPathStatus)
s.ConnectStartUpdate(f.StartUpdate)

View File

@ -43,15 +43,13 @@ import (
"github.com/ProtonMail/proton-bridge/internal/frontend/qt-common"
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
"github.com/ProtonMail/proton-bridge/internal/preferences"
"github.com/ProtonMail/proton-bridge/internal/updates"
"github.com/ProtonMail/proton-bridge/pkg/config"
"github.com/ProtonMail/proton-bridge/pkg/ports"
"github.com/ProtonMail/proton-bridge/pkg/useragent"
"github.com/sirupsen/logrus"
//"github.com/ProtonMail/proton-bridge/pkg/keychain"
"github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/ProtonMail/proton-bridge/pkg/updates"
"github.com/sirupsen/logrus"
"github.com/kardianos/osext"
"github.com/skratchdot/open-golang/open"
"github.com/therecipe/qt/core"

View File

@ -22,8 +22,8 @@ import (
"github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/internal/importexport"
"github.com/ProtonMail/proton-bridge/internal/transfer"
"github.com/ProtonMail/proton-bridge/internal/updates"
"github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/ProtonMail/proton-bridge/pkg/updates"
)
// PanicHandler is an interface of a type that can be used to gracefully handle panics which occur.
@ -104,7 +104,7 @@ func (b *bridgeWrap) GetUser(query string) (User, error) {
return b.Bridge.GetUser(query)
}
// ImportExporter is an interface of import/export needed by frontend.
// ImportExporter is an interface of import-export needed by frontend.
type ImportExporter interface {
UserManager
@ -121,9 +121,9 @@ type importExportWrap struct {
*importexport.ImportExport
}
// NewImportExportWrap wraps import/export struct into local importExportWrap
// NewImportExportWrap wraps import-export struct into local importExportWrap
// to implement local interface.
// The problem is that Import/Export returns the importexport package's User
// The problem is that Import-Export returns the importexport package's User
// type. Every method which returns User therefore has to be overridden to
// fulfill the interface.
func NewImportExportWrap(ie *importexport.ImportExport) *importExportWrap { //nolint[golint]