1883 lines
64 KiB
Go
1883 lines
64 KiB
Go
|
package gui
|
||
|
|
||
|
// settingsGui.go implements pages to manage a user's settings and user data
|
||
|
|
||
|
import "fyne.io/fyne/v2"
|
||
|
import "fyne.io/fyne/v2/container"
|
||
|
import "fyne.io/fyne/v2/dialog"
|
||
|
import "fyne.io/fyne/v2/layout"
|
||
|
import "fyne.io/fyne/v2/theme"
|
||
|
import "fyne.io/fyne/v2/widget"
|
||
|
|
||
|
import "seekia/resources/currencies"
|
||
|
|
||
|
import "seekia/internal/appMemory"
|
||
|
import "seekia/internal/encoding"
|
||
|
import "seekia/internal/globalSettings"
|
||
|
import "seekia/internal/helpers"
|
||
|
import "seekia/internal/identity"
|
||
|
import "seekia/internal/localFilesystem"
|
||
|
import "seekia/internal/logger"
|
||
|
import "seekia/internal/messaging/chatMessageStorage"
|
||
|
import "seekia/internal/messaging/myChatMessages"
|
||
|
import "seekia/internal/moderation/reportStorage"
|
||
|
import "seekia/internal/moderation/reviewStorage"
|
||
|
import "seekia/internal/myIdentity"
|
||
|
import "seekia/internal/mySeedPhrases"
|
||
|
import "seekia/internal/mySettings"
|
||
|
import "seekia/internal/network/appNetworkType/getAppNetworkType"
|
||
|
import "seekia/internal/network/appNetworkType/setAppNetworkType"
|
||
|
import "seekia/internal/network/myBroadcasts"
|
||
|
import "seekia/internal/profiles/profileStorage"
|
||
|
import "seekia/internal/seedPhrase"
|
||
|
|
||
|
import "errors"
|
||
|
|
||
|
func setSettingsPage(window fyne.Window){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "Settings")
|
||
|
|
||
|
currentPage := func(){setSettingsPage(window)}
|
||
|
|
||
|
title := getPageTitleCentered("Settings")
|
||
|
|
||
|
description := getLabelCentered("Manage your Seekia settings.")
|
||
|
|
||
|
myDataButton := widget.NewButton("My Data", func(){
|
||
|
setSettingsPage_MyData(window, currentPage)
|
||
|
})
|
||
|
|
||
|
themesButton := widget.NewButton("Themes", func(){
|
||
|
setChooseAppThemePage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
navigationButton := widget.NewButton("Navigation", func(){
|
||
|
setNavigationSettingsPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
contentFilteringButton := widget.NewButton("Content Filtering", func(){
|
||
|
setContentFilteringSettingsPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
networkSettingsButton := widget.NewButton("Network", func(){
|
||
|
setManageNetworkSettingsPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
storageSettingsButton := widget.NewButton("Storage", func(){
|
||
|
setManageStoragePage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
toolsButton := widget.NewButton("Tools", func(){
|
||
|
setToolsPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
languageButton := widget.NewButton("Language", func(){
|
||
|
setSelectLanguagePage(window, true, currentPage)
|
||
|
})
|
||
|
|
||
|
logsButton := widget.NewButton("Logs", func(){
|
||
|
setViewLogsPage(window, "General", currentPage)
|
||
|
})
|
||
|
|
||
|
developerButton := widget.NewButton("Developer", func(){
|
||
|
setViewDeveloperSettingsPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
buttonGrid := getContainerCentered(container.NewGridWithColumns(1, myDataButton, themesButton, navigationButton, contentFilteringButton, networkSettingsButton, storageSettingsButton, toolsButton, languageButton, logsButton, developerButton))
|
||
|
|
||
|
pageContent := container.NewVBox(title, widget.NewSeparator(), description, widget.NewSeparator(), buttonGrid)
|
||
|
|
||
|
setPageContent(pageContent, window)
|
||
|
}
|
||
|
|
||
|
func getMetricImperialSwitchButton(window fyne.Window, currentPage func())(fyne.Widget, error){
|
||
|
|
||
|
currentUnitsExist, currentUnits, err := globalSettings.GetSetting("MetricOrImperial")
|
||
|
if (err != nil){ return nil, err }
|
||
|
|
||
|
getSwitchButton := func()fyne.Widget{
|
||
|
|
||
|
if (currentUnitsExist == false || currentUnits == "Metric"){
|
||
|
|
||
|
button := widget.NewButton(translate("Metric"), func(){
|
||
|
err := globalSettings.SetSetting("MetricOrImperial", "Imperial")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
currentPage()
|
||
|
})
|
||
|
return button
|
||
|
}
|
||
|
|
||
|
button := widget.NewButton(translate("Imperial"), func(){
|
||
|
|
||
|
err := globalSettings.SetSetting("MetricOrImperial", "Metric")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
return button
|
||
|
}
|
||
|
|
||
|
switchButton := getSwitchButton()
|
||
|
|
||
|
return switchButton, nil
|
||
|
}
|
||
|
|
||
|
|
||
|
func setSettingsPage_MyData(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setSettingsPage_MyData(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("My Data")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
myIdentityHashesButton := widget.NewButton("My Identity Hashes", func(){
|
||
|
setViewMyIdentityHashesPage(window, "Mate", currentPage)
|
||
|
})
|
||
|
|
||
|
mySeedPhrasesButton := widget.NewButton("My Seed Phrases", func(){
|
||
|
setViewMySeedPhrasesPage(window, "Mate", currentPage)
|
||
|
})
|
||
|
|
||
|
deleteIdentityButton := widget.NewButton("Delete Identity", func(){
|
||
|
setDeleteMyIdentityPage(window, "Mate", currentPage)
|
||
|
})
|
||
|
|
||
|
importIdentityButton := widget.NewButton("Import Identity", func(){
|
||
|
setImportMyIdentityPage(window, "Mate", currentPage)
|
||
|
})
|
||
|
|
||
|
exportDataButton := widget.NewButton("Export Data", func(){
|
||
|
//TODO
|
||
|
// Page to export user data
|
||
|
// This should export the UserData folder(s) to a folder, and that data should be able to be imported to a new device
|
||
|
// The GUI should give options on which data to export
|
||
|
showUnderConstructionDialog(window)
|
||
|
})
|
||
|
|
||
|
importDataButton := widget.NewButton("Import Data", func(){
|
||
|
//TODO
|
||
|
// On import, user should be able to select which elements to import, and any conflicts with existing data should be shown
|
||
|
// When importing chat keys, we must make sure to prune the user's undecryptable message hashes list
|
||
|
// The new keys should be used to attempt to decrypt those messages again (if they still exist on the network)
|
||
|
showUnderConstructionDialog(window)
|
||
|
})
|
||
|
|
||
|
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, myIdentityHashesButton, mySeedPhrasesButton, deleteIdentityButton, importIdentityButton, exportDataButton, importDataButton))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), buttonsGrid)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setViewMySeedPhrasesPage(window fyne.Window, myIdentityType string, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered(translate("My Seed Phrase"))
|
||
|
|
||
|
currentPage := func(){setViewMySeedPhrasesPage(window, myIdentityType, previousPage)}
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Your seed phrase can recover your " + myIdentityType + " identity on any device.")
|
||
|
description2 := getLabelCentered("Write it down to prevent the loss of your identity.")
|
||
|
description3 := getBoldLabelCentered("Do not share your seed phrases!")
|
||
|
|
||
|
identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
getIdentityTypeLabelOrChangeButton := func()(fyne.Widget, error){
|
||
|
|
||
|
getHostModeEnabledBool := func()(bool, error){
|
||
|
exists, hostModeOnOffStatus, err := mySettings.GetSetting("HostModeOnOffStatus")
|
||
|
if (err != nil) { return false, err }
|
||
|
if (exists == true && hostModeOnOffStatus == "On"){
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
getModeratorModeEnabledBool := func()(bool, error){
|
||
|
exists, moderatorModeOnOffStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
|
||
|
if (err != nil) { return false, err }
|
||
|
if (exists == true && moderatorModeOnOffStatus == "On"){
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
hostModeEnabled, err := getHostModeEnabledBool()
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
moderatorModeEnabled, err := getModeratorModeEnabledBool()
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
hostIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Host")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
moderatorIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Moderator")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
if (hostModeEnabled == false && hostIdentityExists == false && moderatorModeEnabled == false && moderatorIdentityExists == false){
|
||
|
|
||
|
// Mate identity is the only identity to show
|
||
|
|
||
|
mateLabel := getBoldLabel("Mate")
|
||
|
return mateLabel, nil
|
||
|
}
|
||
|
|
||
|
getNextIdentityType := func()string{
|
||
|
|
||
|
if (myIdentityType == "Mate"){
|
||
|
|
||
|
if (hostModeEnabled == true || hostIdentityExists == true){
|
||
|
return "Host"
|
||
|
}
|
||
|
|
||
|
return "Moderator"
|
||
|
}
|
||
|
if (myIdentityType == "Host"){
|
||
|
|
||
|
if (moderatorModeEnabled == true || moderatorIdentityExists == true){
|
||
|
return "Moderator"
|
||
|
}
|
||
|
|
||
|
return "Mate"
|
||
|
}
|
||
|
|
||
|
return "Mate"
|
||
|
}
|
||
|
|
||
|
nextIdentityType := getNextIdentityType()
|
||
|
|
||
|
changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
|
||
|
setViewMySeedPhrasesPage(window, nextIdentityType, previousPage)
|
||
|
})
|
||
|
|
||
|
return changeIdentityTypeButton, nil
|
||
|
}
|
||
|
|
||
|
identityTypeLabelOrChangeButton, err := getIdentityTypeLabelOrChangeButton()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
identityTypeLabelOrChangeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, identityTypeLabelOrChangeButton))
|
||
|
|
||
|
currentSeedPhraseExists, currentSeedPhrase, err := mySeedPhrases.GetMySeedPhrase(myIdentityType)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (currentSeedPhraseExists == false) {
|
||
|
|
||
|
identityDoesNotExistLabel := getBoldLabelCentered("Your " + myIdentityType + " identity does not exist.")
|
||
|
|
||
|
createIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Create Identity", theme.NavigateNextIcon(), func(){
|
||
|
setChooseNewIdentityHashPage(window, myIdentityType, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, identityDoesNotExistLabel, createIdentityButton, widget.NewSeparator())
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
seedPhraseLabel := widget.NewMultiLineEntry()
|
||
|
seedPhraseLabel.Wrapping = 3
|
||
|
seedPhraseLabel.SetText(currentSeedPhrase)
|
||
|
seedPhraseLabel.OnChanged = func(_ string){
|
||
|
seedPhraseLabel.SetText(currentSeedPhrase)
|
||
|
}
|
||
|
seedPhraseLabelBoxed := getWidgetBoxed(seedPhraseLabel)
|
||
|
|
||
|
widener := widget.NewLabel(" ")
|
||
|
seedPhraseBoxWidened := getContainerCentered(container.NewGridWithColumns(1, seedPhraseLabelBoxed, widener))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, seedPhraseBoxWidened)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setViewMyIdentityHashesPage(window fyne.Window, myIdentityType string, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setViewMyIdentityHashesPage(window, myIdentityType, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("My Identity Hashes"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("All users of Seekia have a unique identity hash.")
|
||
|
description2 := getLabelCentered("Share your identity hash to advertise your identity.")
|
||
|
|
||
|
identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
getIdentityTypeLabelOrChangeButton := func()(fyne.Widget, error){
|
||
|
|
||
|
getHostModeEnabledBool := func()(bool, error){
|
||
|
exists, hostModeOnOffStatus, err := mySettings.GetSetting("HostModeOnOffStatus")
|
||
|
if (err != nil) { return false, err }
|
||
|
if (exists == true && hostModeOnOffStatus == "On"){
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
getModeratorModeEnabledBool := func()(bool, error){
|
||
|
exists, moderatorModeOnOffStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
|
||
|
if (err != nil) { return false, err }
|
||
|
if (exists == true && moderatorModeOnOffStatus == "On"){
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
hostModeEnabled, err := getHostModeEnabledBool()
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
moderatorModeEnabled, err := getModeratorModeEnabledBool()
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
hostIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Host")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
moderatorIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Moderator")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
if (hostModeEnabled == false && hostIdentityExists == false && moderatorModeEnabled == false && moderatorIdentityExists == false){
|
||
|
|
||
|
// Mate identity is the only identity to show
|
||
|
mateLabel := getBoldLabel("Mate")
|
||
|
return mateLabel, nil
|
||
|
}
|
||
|
|
||
|
getNextIdentityType := func()string{
|
||
|
|
||
|
if (myIdentityType == "Mate"){
|
||
|
|
||
|
if (hostModeEnabled == true || hostIdentityExists == true){
|
||
|
return "Host"
|
||
|
}
|
||
|
return "Moderator"
|
||
|
}
|
||
|
|
||
|
if (myIdentityType == "Host"){
|
||
|
|
||
|
if (moderatorModeEnabled == true || moderatorIdentityExists == true){
|
||
|
return "Moderator"
|
||
|
}
|
||
|
return "Mate"
|
||
|
}
|
||
|
return "Mate"
|
||
|
}
|
||
|
|
||
|
nextIdentityType := getNextIdentityType()
|
||
|
|
||
|
changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
|
||
|
setViewMyIdentityHashesPage(window, nextIdentityType, previousPage)
|
||
|
})
|
||
|
|
||
|
return changeIdentityTypeButton, nil
|
||
|
}
|
||
|
|
||
|
identityTypeLabelOrChangeButton, err := getIdentityTypeLabelOrChangeButton()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
identityTypeLabelOrChangeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, identityTypeLabelOrChangeButton))
|
||
|
|
||
|
currentIdentityHashExists, currentIdentityHash, err := myIdentity.GetMyIdentityHash(myIdentityType)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (currentIdentityHashExists == false) {
|
||
|
|
||
|
identityDoesNotExistLabel := getBoldLabelCentered("Your " + myIdentityType + " identity does not exist.")
|
||
|
|
||
|
createIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Create Identity", theme.NavigateNextIcon(), func(){
|
||
|
setChooseNewIdentityHashPage(window, myIdentityType, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, identityDoesNotExistLabel, createIdentityButton, widget.NewSeparator())
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(currentIdentityHash)
|
||
|
if (err != nil){
|
||
|
currentIdentityHashHex := encoding.EncodeBytesToHexString(currentIdentityHash[:])
|
||
|
setErrorEncounteredPage(window, errors.New("GetMyIdentityHash returning invalid myIdentityHash: " + currentIdentityHashHex), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
identityHashLabel := widget.NewMultiLineEntry()
|
||
|
identityHashLabel.SetText(currentIdentityHashString)
|
||
|
identityHashLabel.OnChanged = func(_ string){
|
||
|
identityHashLabel.SetText(currentIdentityHashString)
|
||
|
}
|
||
|
identityHashLabelBoxed := getWidgetBoxed(identityHashLabel)
|
||
|
|
||
|
boxWidener := widget.NewLabel(" ")
|
||
|
identityHashBoxWidened := getContainerCentered(container.NewGridWithColumns(1, identityHashLabelBoxed, boxWidener))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, identityHashBoxWidened)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setDeleteMyIdentityPage(window fyne.Window, myIdentityType string, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setDeleteMyIdentityPage(window, myIdentityType, previousPage)}
|
||
|
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Host" && myIdentityType != "Moderator"){
|
||
|
setErrorEncounteredPage(window, errors.New("setDeleteMyIdentityPage called with invalid identity type: " + myIdentityType), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Delete Identity"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
getDescriptionSection := func()*fyne.Container{
|
||
|
|
||
|
description1 := getLabelCentered("This page allows you to delete your " + myIdentityType + " identity.")
|
||
|
|
||
|
if (myIdentityType == "Host"){
|
||
|
description2 := getLabelCentered("You will lose your host identity balance and account credit.")
|
||
|
description3 := getLabelCentered("Write down your seed phrase to keep access to your identity and credit.")
|
||
|
description4 := getLabelCentered("Disable your profile before doing this.")
|
||
|
descriptionSection := container.NewVBox(description1, description2, description3, description4)
|
||
|
return descriptionSection
|
||
|
}
|
||
|
if (myIdentityType == "Moderator"){
|
||
|
description2 := getLabelCentered("You will lose your identity score and account credit.")
|
||
|
description3 := getLabelCentered("This will also delete your message history.")
|
||
|
description4 := getLabelCentered("Write down your seed phrase to keep access to your identity and credit.")
|
||
|
descriptionSection := container.NewVBox(description1, description2, description3, description4)
|
||
|
return descriptionSection
|
||
|
}
|
||
|
|
||
|
description2 := getLabelCentered("This will delete your messages, identity balance, and account credit.")
|
||
|
description3 := getLabelCentered("Write down your seed phrase to keep access to your identity and credit.")
|
||
|
description4 := getLabelCentered("Disable your profile before doing this.")
|
||
|
descriptionSection := container.NewVBox(description1, description2, description3, description4)
|
||
|
|
||
|
return descriptionSection
|
||
|
}
|
||
|
|
||
|
descriptionSection := getDescriptionSection()
|
||
|
|
||
|
getIdentityTypeLabelOrChangeButton := func()(fyne.Widget, error){
|
||
|
|
||
|
hostIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Host")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
moderatorIdentityExists, _, err := mySeedPhrases.GetMySeedPhrase("Moderator")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
if (myIdentityType == "Mate" && hostIdentityExists == false && moderatorIdentityExists == false){
|
||
|
mateLabel := getBoldLabel("Mate")
|
||
|
return mateLabel, nil
|
||
|
}
|
||
|
|
||
|
getNextIdentityType := func()string{
|
||
|
|
||
|
if (myIdentityType == "Mate"){
|
||
|
if (hostIdentityExists == true){
|
||
|
return "Host"
|
||
|
}
|
||
|
return "Moderator"
|
||
|
}
|
||
|
if (myIdentityType == "Host"){
|
||
|
if (moderatorIdentityExists == true){
|
||
|
return "Moderator"
|
||
|
}
|
||
|
}
|
||
|
return "Mate"
|
||
|
}
|
||
|
|
||
|
nextIdentityType := getNextIdentityType()
|
||
|
|
||
|
changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
|
||
|
setDeleteMyIdentityPage(window, nextIdentityType, previousPage)
|
||
|
})
|
||
|
|
||
|
return changeIdentityTypeButton, nil
|
||
|
}
|
||
|
|
||
|
identityTypeLabelOrChangeButton, err := getIdentityTypeLabelOrChangeButton()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
identityTypeLabelOrChangeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, identityTypeLabelOrChangeButton))
|
||
|
|
||
|
identityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash(myIdentityType)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (identityExists == false){
|
||
|
|
||
|
// This is only reached if the user has just deleted this identity
|
||
|
|
||
|
description4 := getBoldLabelCentered("Your " + myIdentityType + " identity does not exist.")
|
||
|
description5 := getLabelCentered("There is no identity to delete.")
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, description4, description5, widget.NewSeparator())
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
identityHashTrimmed, _, err := helpers.TrimAndFlattenString(myIdentityHashString, 10)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentIdentityHashText := widget.NewLabel("Current Identity:")
|
||
|
identityHashLabel := getBoldLabel(identityHashTrimmed)
|
||
|
myIdentityHashRow := getContainerCentered(container.NewHBox(currentIdentityHashText, identityHashLabel))
|
||
|
|
||
|
deleteIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Delete Identity", theme.DeleteIcon(), func(){
|
||
|
setConfirmDeleteMyIdentityPage(window, myIdentityType, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), descriptionSection, widget.NewSeparator(), identityTypeLabelOrChangeButtonWithIcon, myIdentityHashRow, deleteIdentityButton, widget.NewSeparator())
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setConfirmDeleteMyIdentityPage(window fyne.Window, myIdentityType string, previousPage func(), nextPage func()){
|
||
|
|
||
|
title := getPageTitleCentered("Confirm Delete " + myIdentityType + " Identity")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
identityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash(myIdentityType)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (identityExists == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setConfirmDeleteMyIdentityPage called with missing identity."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
subtitle := getPageSubtitleCentered("Delete your " + myIdentityType + " identity?")
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator())
|
||
|
|
||
|
if (myIdentityType == "Mate"){
|
||
|
|
||
|
description2 := getBoldLabelCentered(translate("You will lose access to your identity balance and account credit."))
|
||
|
description3 := getBoldLabelCentered(translate("This will delete your chat messages and decryption keys."))
|
||
|
description4 := getLabelCentered(translate("Write down your seed phrase to retain your identity and account credit."))
|
||
|
description5 := getLabelCentered(translate("Export your data to save your chat messages and decryption keys."))
|
||
|
|
||
|
page.Add(description2)
|
||
|
page.Add(description3)
|
||
|
page.Add(description4)
|
||
|
page.Add(description5)
|
||
|
|
||
|
} else if (myIdentityType == "Host"){
|
||
|
|
||
|
description2 := getBoldLabelCentered(translate("You will lose access to your identity balance and account credit."))
|
||
|
description3 := getLabelCentered(translate("Write down your seed phrase to retain your identity and account credit."))
|
||
|
|
||
|
page.Add(description2)
|
||
|
page.Add(description3)
|
||
|
|
||
|
} else if (myIdentityType == "Moderator"){
|
||
|
|
||
|
description2 := getBoldLabelCentered(translate("You will lose access to your identity score and account credit."))
|
||
|
description3 := getBoldLabelCentered(translate("This will delete your chat messages and decryption keys."))
|
||
|
description4 := getLabelCentered(translate("Write down your seed phrase to retain your identity and account credit."))
|
||
|
description5 := getLabelCentered(translate("Export your data to save your chat messages and decryption keys."))
|
||
|
|
||
|
page.Add(description2)
|
||
|
page.Add(description3)
|
||
|
page.Add(description4)
|
||
|
page.Add(description5)
|
||
|
}
|
||
|
|
||
|
description5 := getLabelCentered("This will not delete your local profile.")
|
||
|
page.Add(description5)
|
||
|
|
||
|
page.Add(widget.NewSeparator())
|
||
|
|
||
|
if (myIdentityType != "Host"){
|
||
|
|
||
|
//Outputs:
|
||
|
// -int: Number of messages to delete
|
||
|
// -int: Number of conversations to delete
|
||
|
getMessagesToDeleteInfo := func(networkType byte)(int, int, error){
|
||
|
|
||
|
updateProgressFunction := func(_ int)error{
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
myChatMessagesMapList, err := myChatMessages.GetUpdatedMyChatMessagesMapList(myIdentityType, networkType, updateProgressFunction)
|
||
|
if (err != nil) { return 0, 0, err }
|
||
|
|
||
|
numberOfMessagesToDelete := len(myChatMessagesMapList)
|
||
|
|
||
|
//Map Structure: Recipient Identity Hash -> Nothing
|
||
|
conversationRecipientsMap := make(map[string]struct{})
|
||
|
|
||
|
for _, messageMap := range myChatMessagesMapList{
|
||
|
theirIdentityHash, exists := messageMap["TheirIdentityHash"]
|
||
|
if (exists == false) {
|
||
|
return 0, 0, errors.New("Malformed myChatMessages map list: Item missing TheirIdentityHash")
|
||
|
}
|
||
|
|
||
|
conversationRecipientsMap[theirIdentityHash] = struct{}{}
|
||
|
}
|
||
|
|
||
|
numberOfConversationsToDelete := len(conversationRecipientsMap)
|
||
|
|
||
|
return numberOfMessagesToDelete, numberOfConversationsToDelete, nil
|
||
|
}
|
||
|
|
||
|
numberOfMessagesToDelete_Network1, numberOfConversationsToDelete_Network1, err := getMessagesToDeleteInfo(1)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfMessagesToDelete_Network2, numberOfConversationsToDelete_Network2, err := getMessagesToDeleteInfo(2)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfMessagesToDelete := numberOfMessagesToDelete_Network1 + numberOfMessagesToDelete_Network2
|
||
|
numberOfConversationsToDelete := numberOfConversationsToDelete_Network1 + numberOfConversationsToDelete_Network2
|
||
|
|
||
|
if (numberOfMessagesToDelete != 0){
|
||
|
|
||
|
thisWillDeleteLabel := widget.NewLabel("This will delete")
|
||
|
|
||
|
numberOfMessagesString := helpers.ConvertIntToString(numberOfMessagesToDelete)
|
||
|
numberOfMessagesLabel := getBoldLabel(numberOfMessagesString)
|
||
|
|
||
|
getMessageOrMessagesText := func()string{
|
||
|
if (numberOfMessagesToDelete == 1){
|
||
|
return "message"
|
||
|
}
|
||
|
return "messages"
|
||
|
}
|
||
|
messageOrMessagesText := getMessageOrMessagesText()
|
||
|
messagesAndLabel := widget.NewLabel(messageOrMessagesText + " and")
|
||
|
|
||
|
numberOfConversationsString := helpers.ConvertIntToString(numberOfConversationsToDelete)
|
||
|
numberOfConversationsLabel := getBoldLabel(numberOfConversationsString)
|
||
|
|
||
|
getConversationOrConversationsText := func()string{
|
||
|
if (numberOfConversationsToDelete == 1){
|
||
|
return "conversation"
|
||
|
}
|
||
|
return "conversations"
|
||
|
}
|
||
|
conversationOrConversationsText := getConversationOrConversationsText()
|
||
|
conversationsLabel := widget.NewLabel(conversationOrConversationsText)
|
||
|
|
||
|
chatDeleteWarningRow := container.NewHBox(layout.NewSpacer(), thisWillDeleteLabel, numberOfMessagesLabel, messagesAndLabel, numberOfConversationsLabel, conversationsLabel, layout.NewSpacer())
|
||
|
|
||
|
page.Add(chatDeleteWarningRow)
|
||
|
page.Add(widget.NewSeparator())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//TODO: Show account credit balance
|
||
|
|
||
|
if (myIdentityType == "Mate"){
|
||
|
description6 := getLabelCentered("Disable your profile before doing this on the Profile - Broadcast page.")
|
||
|
description7 := getLabelCentered("Otherwise, it will automatically expire from the network in 3 months.")
|
||
|
|
||
|
page.Add(description6)
|
||
|
page.Add(description7)
|
||
|
page.Add(widget.NewSeparator())
|
||
|
|
||
|
} else if (myIdentityType == "Host"){
|
||
|
|
||
|
description6 := getLabelCentered("Disable your profile before doing this on the Profile - Broadcast page.")
|
||
|
description7 := getLabelCentered("Otherwise, users will keep trying to connect to your inactive host address.")
|
||
|
//TODO: Retrieve true expiration time from parameters
|
||
|
description8 := getLabelCentered("This should stop after 6 hours, when your profile expires.")
|
||
|
|
||
|
page.Add(description6)
|
||
|
page.Add(description7)
|
||
|
page.Add(description8)
|
||
|
page.Add(widget.NewSeparator())
|
||
|
}
|
||
|
|
||
|
deleteIdentityFunction := func()error{
|
||
|
|
||
|
err := myBroadcasts.DeleteMyBroadcastProfiles(myIdentityHash)
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
if (myIdentityType != "Host"){
|
||
|
|
||
|
err := myChatMessages.DeleteMyChatMessagesMapList(myIdentityType)
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
err = mySettings.SetSetting(myIdentityType + "ChatConversationsGeneratedStatus", "No")
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
//TODO: Delete secret inboxes
|
||
|
//TODO: Delete saved message cipher keys
|
||
|
//TODO: Delete everything else relevant
|
||
|
}
|
||
|
|
||
|
err = mySeedPhrases.DeleteMySeedPhrase(myIdentityType)
|
||
|
if (err != nil) { return err }
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
confirmDeleteIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Delete Identity", theme.DeleteIcon(), func(){
|
||
|
err := deleteIdentityFunction()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
}
|
||
|
nextPage()
|
||
|
}))
|
||
|
|
||
|
page.Add(confirmDeleteIdentityButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setImportMyIdentityPage(window fyne.Window, myIdentityType string, previousPage func()){
|
||
|
|
||
|
if (myIdentityType != "Mate" && myIdentityType != "Host" && myIdentityType != "Moderator"){
|
||
|
setErrorEncounteredPage(window, errors.New("setImportMyIdentityPage called with invalid identity type: " + myIdentityType), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentPage := func(){setImportMyIdentityPage(window, myIdentityType, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Import Identity"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("Import your " + myIdentityType + " identity from a seed phrase.")
|
||
|
|
||
|
getNextIdentityType := func()string{
|
||
|
if (myIdentityType == "Mate"){
|
||
|
return "Host"
|
||
|
}
|
||
|
if (myIdentityType == "Host"){
|
||
|
return "Moderator"
|
||
|
}
|
||
|
return "Mate"
|
||
|
}
|
||
|
|
||
|
nextIdentityType := getNextIdentityType()
|
||
|
|
||
|
identityTypeIcon, err := getIdentityTypeIcon(myIdentityType, -10)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
changeIdentityTypeButton := widget.NewButton(myIdentityType, func(){
|
||
|
setImportMyIdentityPage(window, nextIdentityType, previousPage)
|
||
|
})
|
||
|
|
||
|
changeIdentityTypeButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, identityTypeIcon, changeIdentityTypeButton))
|
||
|
|
||
|
identityExists, _, err := mySeedPhrases.GetMySeedPhrase(myIdentityType)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (identityExists == true){
|
||
|
|
||
|
description2 := getBoldLabelCentered("Your " + myIdentityType + " identity exists.")
|
||
|
description3 := getLabelCentered("You must delete it before restoring a new identity.")
|
||
|
description4 := getLabelCentered("Delete your identity on the Settings - My Data - Delete Identity page")
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), changeIdentityTypeButtonWithIcon, description2, description3, description4)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
seedPhraseEntry := widget.NewMultiLineEntry()
|
||
|
seedPhraseEntry.Wrapping = 3
|
||
|
seedPhraseEntry.SetPlaceHolder(translate("Enter seed phrase to import..."))
|
||
|
|
||
|
seedPhraseEntryBoxed := getWidgetBoxed(seedPhraseEntry)
|
||
|
|
||
|
submitSeedButton := getWidgetCentered(widget.NewButtonWithIcon(translate("Import " + myIdentityType + " Identity"), theme.UploadIcon(), func(){
|
||
|
|
||
|
newSeedPhrase := seedPhraseEntry.Text
|
||
|
|
||
|
seedPhraseIsValid := seedPhrase.VerifySeedPhrase(newSeedPhrase)
|
||
|
if (seedPhraseIsValid == false){
|
||
|
dialogTitle := translate("Invalid Seed Phrase")
|
||
|
dialogMessageA := getLabelCentered("Your seed phrase is invalid.")
|
||
|
dialogMessageB := getLabelCentered("A Seekia seed phrase is 15 words long.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err = mySeedPhrases.SetMySeedPhrase(myIdentityType, newSeedPhrase)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
setViewMySeedPhrasesPage(window, myIdentityType, previousPage)
|
||
|
}))
|
||
|
|
||
|
widener := widget.NewLabel(" ")
|
||
|
heightener := widget.NewLabel("")
|
||
|
submitSeedButtonWithWidener := container.NewVBox(submitSeedButton, widener, heightener)
|
||
|
|
||
|
entryWithSubmitSeedButton := getContainerCentered(container.NewGridWithColumns(1, seedPhraseEntryBoxed, submitSeedButtonWithWidener))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), changeIdentityTypeButtonWithIcon, entryWithSubmitSeedButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setChooseAppThemePage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setChooseAppThemePage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("App Themes"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("Choose your Seekia app theme.")
|
||
|
|
||
|
getThemeButtonsGrid := func()(*fyne.Container, error){
|
||
|
|
||
|
getCurrentAppTheme := func()(string, error){
|
||
|
|
||
|
exists, currentTheme, err := globalSettings.GetSetting("AppTheme")
|
||
|
if (err != nil){ return "", err }
|
||
|
if (exists == false){
|
||
|
return "Light", nil
|
||
|
}
|
||
|
return currentTheme, nil
|
||
|
}
|
||
|
|
||
|
currentAppTheme, err := getCurrentAppTheme()
|
||
|
if (err != nil){ return nil, err }
|
||
|
|
||
|
getThemeButtonWithIcon := func(themeName string, themeIconName string)(*fyne.Container, error){
|
||
|
|
||
|
themeIcon, err := getFyneImageIcon(themeIconName)
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
chooseThemeButton := widget.NewButton(translate(themeName), func(){
|
||
|
|
||
|
_ = globalSettings.SetSetting("AppTheme", themeName)
|
||
|
|
||
|
customTheme, _ := getCustomFyneTheme(themeName)
|
||
|
|
||
|
app := fyne.CurrentApp()
|
||
|
|
||
|
app.Settings().SetTheme(customTheme)
|
||
|
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
if (themeName == currentAppTheme){
|
||
|
chooseThemeButton.Importance = widget.HighImportance
|
||
|
}
|
||
|
|
||
|
buttonWithIcon := getContainerCentered(container.NewGridWithColumns(1, themeIcon, chooseThemeButton))
|
||
|
|
||
|
return buttonWithIcon, nil
|
||
|
}
|
||
|
|
||
|
lightThemeButton, err := getThemeButtonWithIcon("Light", "Sun")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
darkThemeButton, err := getThemeButtonWithIcon("Dark", "Moon")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
loveThemeButton, err := getThemeButtonWithIcon("Love", "Mate")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
oceanThemeButton, err := getThemeButtonWithIcon("Ocean", "Ocean")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
buttonsGrid := container.NewGridWithColumns(2, lightThemeButton, darkThemeButton, loveThemeButton, oceanThemeButton)
|
||
|
|
||
|
return buttonsGrid, nil
|
||
|
}
|
||
|
|
||
|
themeButtonsGrid, err := getThemeButtonsGrid()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
themeButtonsGridCentered := getContainerCentered(themeButtonsGrid)
|
||
|
|
||
|
//TODO: Add a way to create a custom theme within the GUI
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), themeButtonsGridCentered)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setNavigationSettingsPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setNavigationSettingsPage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Navigation Settings"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("Manage your navigation settings.")
|
||
|
|
||
|
showButtonTextColumn := container.NewVBox()
|
||
|
showButtonChecksColumn := container.NewVBox()
|
||
|
|
||
|
addShowButtonCheckRow := func(showButtonText string, settingName string)error{
|
||
|
|
||
|
showButtonTextLabel := getBoldLabelCentered(showButtonText)
|
||
|
|
||
|
showButtonCheck := widget.NewCheck("", func(selected bool){
|
||
|
|
||
|
yesOrNoString := helpers.ConvertBoolToYesOrNoString(selected)
|
||
|
|
||
|
err := mySettings.SetSetting(settingName, yesOrNoString)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
exists, showButtonCurrent, err := mySettings.GetSetting(settingName)
|
||
|
if (err != nil) { return err }
|
||
|
if (exists == true && showButtonCurrent == "Yes"){
|
||
|
showButtonCheck.Checked = true
|
||
|
}
|
||
|
|
||
|
showButtonTextColumn.Add(showButtonTextLabel)
|
||
|
showButtonChecksColumn.Add(showButtonCheck)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
err := addShowButtonCheckRow("Show Host Button", "ShowHostButtonNavigation")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
showButtonTextColumn.Add(widget.NewSeparator())
|
||
|
showButtonChecksColumn.Add(widget.NewSeparator())
|
||
|
|
||
|
err = addShowButtonCheckRow("Show Moderate Button", "ShowModerateButtonNavigation")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
showButtonChecksGrid := container.NewHBox(layout.NewSpacer(), showButtonTextColumn, showButtonChecksColumn, layout.NewSpacer())
|
||
|
|
||
|
navigationLocationLabel := getLabelCentered("Navigation Bar Location:")
|
||
|
|
||
|
getMyCurrentNavigationBarLocation := func()(string, error){
|
||
|
|
||
|
exists, currentNavigationLocation, err := mySettings.GetSetting("NavigationBarLocation")
|
||
|
if (err != nil){ return "", err }
|
||
|
if (exists == false){
|
||
|
return "Top", nil
|
||
|
}
|
||
|
|
||
|
if (currentNavigationLocation != "Top" && currentNavigationLocation != "Bottom" && currentNavigationLocation != "Left" && currentNavigationLocation != "Right"){
|
||
|
return "", errors.New("Invalid navigation bar location: " + currentNavigationLocation)
|
||
|
}
|
||
|
|
||
|
return currentNavigationLocation, nil
|
||
|
}
|
||
|
|
||
|
currentNavigationLocation, err := getMyCurrentNavigationBarLocation()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
option1Translated := translate("Top")
|
||
|
option2Translated := translate("Bottom")
|
||
|
option3Translated := translate("Left")
|
||
|
option4Translated := translate("Right")
|
||
|
|
||
|
untranslatedOptionsMap := map[string]string{
|
||
|
option1Translated: "Top",
|
||
|
option2Translated: "Bottom",
|
||
|
option3Translated: "Left",
|
||
|
option4Translated: "Right",
|
||
|
}
|
||
|
|
||
|
locationOptionsList := []string{option1Translated, option2Translated, option3Translated, option4Translated}
|
||
|
|
||
|
locationSelector := widget.NewSelect(locationOptionsList, func(response string){
|
||
|
|
||
|
responseUntranslated, exists := untranslatedOptionsMap[response]
|
||
|
if (exists == false){
|
||
|
setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing response: " + response), currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (responseUntranslated == currentNavigationLocation){
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err = mySettings.SetSetting("NavigationBarLocation", responseUntranslated)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
locationSelector.Selected = currentNavigationLocation
|
||
|
|
||
|
locationSelectorCentered := getWidgetCentered(locationSelector)
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), showButtonChecksGrid, widget.NewSeparator(), navigationLocationLabel, locationSelectorCentered)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setContentFilteringSettingsPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setContentFilteringSettingsPage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Content Filtering Settings"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("Manage your content filtering settings.")
|
||
|
|
||
|
pixelateImagesButton := getWidgetCentered(widget.NewButton("Pixelate Images", func(){
|
||
|
setManagePixelateImagesSettingPage(window, currentPage)
|
||
|
}))
|
||
|
|
||
|
// TODO: Add ability to mute/block/censor words?
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), pixelateImagesButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setManagePixelateImagesSettingPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManagePixelateImagesSettingPage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Pixelate Images Setting")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Seekia can pixelate the images you receive in messages.")
|
||
|
description2 := getLabelCentered("You must slowly reveal the image by incrementally depixelating the image.")
|
||
|
description3 := getLabelCentered("If you are not afraid of seeing unreviewed images, you can disable this feature.")
|
||
|
|
||
|
getCurrentStatus := func()(string, error){
|
||
|
|
||
|
exists, currentSetting, err := mySettings.GetSetting("PixelateImagesOnOffStatus")
|
||
|
if (err != nil) { return "", err }
|
||
|
if (exists == false){
|
||
|
return "On", nil
|
||
|
}
|
||
|
return currentSetting, nil
|
||
|
}
|
||
|
|
||
|
currentStatus, err := getCurrentStatus()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentStatusTitle := widget.NewLabel("Current Status: ")
|
||
|
currentStatusLabel := getBoldLabel(currentStatus)
|
||
|
|
||
|
currentStatusRow := container.NewHBox(layout.NewSpacer(), currentStatusTitle, currentStatusLabel, layout.NewSpacer())
|
||
|
|
||
|
getEnableOrDisableButton := func()fyne.Widget{
|
||
|
|
||
|
if (currentStatus == "On"){
|
||
|
|
||
|
disableButton := widget.NewButton("Disable", func(){
|
||
|
err := mySettings.SetSetting("PixelateImagesOnOffStatus", "Off")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
return disableButton
|
||
|
}
|
||
|
|
||
|
enableButton := widget.NewButton("Enable", func(){
|
||
|
err := mySettings.SetSetting("PixelateImagesOnOffStatus", "On")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
return enableButton
|
||
|
}
|
||
|
|
||
|
enableOrDisableButton := getEnableOrDisableButton()
|
||
|
|
||
|
enableOrDisableButtonCentered := getWidgetCentered(enableOrDisableButton)
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), currentStatusRow, enableOrDisableButtonCentered)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setManageNetworkSettingsPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "ManageNetworkConnection")
|
||
|
|
||
|
title := getPageTitleCentered("Manage Network Connection")
|
||
|
|
||
|
//TODO
|
||
|
// Enable download profiles over clearnet mode
|
||
|
// This should not be possible for messages, only profiles
|
||
|
// Disable Tor mode (if using system-wide tor proxy already, such as Whonix. We can autodetect if user is using Whonix)
|
||
|
// Add HiddenServiceOnly mode so users can only download messages over .onion rather than using exit nodes to access clearnet hosts?
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getBoldLabelCentered("Under Construction")
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setManageStoragePage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
setLoadingScreen(window, "Manage Storage", "Loading Manage Storage Page...")
|
||
|
|
||
|
currentPage := func(){setManageStoragePage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Manage Storage"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
getAllowedStorageGigabytes := func()(float64, error){
|
||
|
|
||
|
exists, allowedStorageSpaceString, err := globalSettings.GetSetting("AllowedStorageSpace")
|
||
|
if (err != nil){ return 0, err }
|
||
|
if (exists == false){
|
||
|
|
||
|
//We default to 10 gigabytes
|
||
|
|
||
|
return 10, nil
|
||
|
}
|
||
|
allowedStorageSpaceFloat, err := helpers.ConvertStringToFloat64(allowedStorageSpaceString)
|
||
|
if (err != nil){
|
||
|
return 0, errors.New("MySettings contains invalid AllowedStorageSpace: " + allowedStorageSpaceString)
|
||
|
}
|
||
|
|
||
|
return allowedStorageSpaceFloat, nil
|
||
|
}
|
||
|
|
||
|
allowedStorageSpace, err := getAllowedStorageGigabytes()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
databaseDirectory, err := localFilesystem.GetAppDatabaseFolderPath()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
databaseSizeBytes, err := localFilesystem.GetFolderSizeInBytes(databaseDirectory)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// TODO: Change to use actual gigabyte size
|
||
|
databaseSizeGigabytes := float64(databaseSizeBytes)/1000000000
|
||
|
|
||
|
allowedStorageSpaceString := helpers.ConvertFloat64ToStringRounded(allowedStorageSpace, 2)
|
||
|
|
||
|
databaseSizeString := helpers.ConvertFloat64ToStringRounded(databaseSizeGigabytes, 1)
|
||
|
|
||
|
percentageOfSpaceUsed := (databaseSizeGigabytes/allowedStorageSpace)*100
|
||
|
|
||
|
percentageOfSpaceUsedString := helpers.ConvertFloat64ToStringRounded(percentageOfSpaceUsed, 0)
|
||
|
|
||
|
spaceUsedTitle := getLabelCentered("Storage Space Used:")
|
||
|
spaceUsedLabel := getBoldLabelCentered(databaseSizeString + "/" + allowedStorageSpaceString + " gigabytes" + " (" + percentageOfSpaceUsedString + "%)")
|
||
|
|
||
|
numberOfStoredProfiles, err := profileStorage.GetNumberOfStoredProfiles()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfStoredProfilesString := helpers.ConvertInt64ToString(numberOfStoredProfiles)
|
||
|
numberOfStoredProfilesLabel := widget.NewLabel("Stored Profiles:")
|
||
|
numberOfStoredProfilesText := getBoldLabel(numberOfStoredProfilesString)
|
||
|
numberOfStoredProfilesRow := container.NewHBox(layout.NewSpacer(), numberOfStoredProfilesLabel, numberOfStoredProfilesText, layout.NewSpacer())
|
||
|
|
||
|
numberOfStoredMessages, err := chatMessageStorage.GetNumberOfStoredMessages()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfStoredMessagesString := helpers.ConvertInt64ToString(numberOfStoredMessages)
|
||
|
|
||
|
numberOfStoredMessagesLabel := widget.NewLabel("Stored Messages:")
|
||
|
numberOfStoredMessagesText := getBoldLabel(numberOfStoredMessagesString)
|
||
|
numberOfStoredMessagesRow := container.NewHBox(layout.NewSpacer(), numberOfStoredMessagesLabel, numberOfStoredMessagesText, layout.NewSpacer())
|
||
|
|
||
|
numberOfStoredReviews, err := reviewStorage.GetNumberOfStoredReviews()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfStoredReviewsString := helpers.ConvertInt64ToString(numberOfStoredReviews)
|
||
|
|
||
|
numberOfStoredReviewsLabel := widget.NewLabel("Stored Reviews:")
|
||
|
numberOfStoredReviewsText := getBoldLabel(numberOfStoredReviewsString)
|
||
|
numberOfStoredReviewsRow := container.NewHBox(layout.NewSpacer(), numberOfStoredReviewsLabel, numberOfStoredReviewsText, layout.NewSpacer())
|
||
|
|
||
|
numberOfStoredReports, err := reportStorage.GetNumberOfStoredReports()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfStoredReportsString := helpers.ConvertInt64ToString(numberOfStoredReports)
|
||
|
|
||
|
numberOfStoredReportsLabel := widget.NewLabel("Stored Reports:")
|
||
|
numberOfStoredReportsText := getBoldLabel(numberOfStoredReportsString)
|
||
|
numberOfStoredReportsRow := container.NewHBox(layout.NewSpacer(), numberOfStoredReportsLabel, numberOfStoredReportsText, layout.NewSpacer())
|
||
|
|
||
|
|
||
|
freeUpSpaceButton := widget.NewButton("Free Up Space", func(){
|
||
|
//TODO: A page to manually prune data
|
||
|
// This should also be happening automatically by backgroundJobs
|
||
|
showUnderConstructionDialog(window)
|
||
|
})
|
||
|
|
||
|
allowedSpaceButton := widget.NewButton("Manage Allowed Space", func(){
|
||
|
setManageAllowedStorageSpacePage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
changeDownloadsDirectoryButton := widget.NewButton("Change Database Location", func(){
|
||
|
setManageDatabaseLocationPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, freeUpSpaceButton, allowedSpaceButton, changeDownloadsDirectoryButton))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), spaceUsedTitle, spaceUsedLabel, widget.NewSeparator(), numberOfStoredProfilesRow, numberOfStoredMessagesRow, numberOfStoredReviewsRow, numberOfStoredReportsRow, widget.NewSeparator(), buttonsGrid)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setManageAllowedStorageSpacePage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManageAllowedStorageSpacePage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Manage Allowed Storage Space"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("Select the amount of storage space Seekia is allowed to use.")
|
||
|
|
||
|
getCurrentAllowedSpace := func()(float64, error){
|
||
|
|
||
|
exists, currentAllowedStorageSpace, err := globalSettings.GetSetting("AllowedStorageSpace")
|
||
|
if (err != nil){ return 0, err }
|
||
|
if (exists == false){
|
||
|
// Default to 10 GB
|
||
|
return 10, nil
|
||
|
}
|
||
|
|
||
|
currentAllowedSpaceFloat64, err := helpers.ConvertStringToFloat64(currentAllowedStorageSpace)
|
||
|
if (err != nil) {
|
||
|
return 0, errors.New("MyGlobalSettings Malformed: Contains invalid AllowedStorageSpace: " + currentAllowedStorageSpace)
|
||
|
}
|
||
|
|
||
|
return currentAllowedSpaceFloat64, nil
|
||
|
}
|
||
|
|
||
|
currentAllowedSpaceFloat64, err := getCurrentAllowedSpace()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentAllowedSpaceString := helpers.ConvertFloat64ToStringRounded(currentAllowedSpaceFloat64, 2)
|
||
|
|
||
|
allowedStorageSpaceLabel := getLabelCentered("Allowed storage space:")
|
||
|
allowedStorageSpaceText := getBoldLabelCentered(currentAllowedSpaceString + " gigabytes")
|
||
|
|
||
|
allowedStorageSpaceGigabytesText := getLabelCentered("Enter a new allowed amount in gigabytes:")
|
||
|
|
||
|
allowedStorageSpaceEntry := widget.NewEntry()
|
||
|
allowedStorageSpaceEntry.Text = currentAllowedSpaceString
|
||
|
|
||
|
allowedStorageSpaceSubmitButton := widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
|
||
|
|
||
|
newSize := allowedStorageSpaceEntry.Text
|
||
|
|
||
|
if (newSize == ""){
|
||
|
dialogTitle := translate("Invalid Size.")
|
||
|
dialogMessage := getLabelCentered(translate("Your must enter a new allowed amount."))
|
||
|
dialogContent := container.NewVBox(dialogMessage)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
newSizeFloat64, err := helpers.ConvertStringToFloat64(newSize)
|
||
|
if (err != nil){
|
||
|
dialogTitle := translate("Invalid Size.")
|
||
|
dialogMessage := getLabelCentered(translate("Your new maximum size must be a number."))
|
||
|
dialogContent := container.NewVBox(dialogMessage)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (newSizeFloat64 < 3){
|
||
|
dialogTitle := translate("Invalid Size.")
|
||
|
dialogMessage := getLabelCentered(translate("Your new maximum size must be at least 3 GB."))
|
||
|
dialogContent := container.NewVBox(dialogMessage)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err = globalSettings.SetSetting("AllowedStorageSpace", newSize)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
allowedStorageSpaceEntryRow := getContainerCentered(container.NewGridWithRows(1, allowedStorageSpaceEntry, allowedStorageSpaceSubmitButton))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), allowedStorageSpaceLabel, allowedStorageSpaceText, widget.NewSeparator(), allowedStorageSpaceGigabytesText, allowedStorageSpaceEntryRow)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setManageDatabaseLocationPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManageDatabaseLocationPage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Manage Database Location"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Use this page to change the location of the Seekia database.")
|
||
|
description2 := getLabelCentered("After changing the location, close Seekia.")
|
||
|
description3 := getLabelCentered("Then, you must manually move the existing database folder contents to the new location.")
|
||
|
description4 := getLabelCentered("Upon starting Seekia again, all existing data should be available.")
|
||
|
description5 := getLabelCentered("If you don't copy the folder, you will still retain your user data.")
|
||
|
|
||
|
databaseDirectory, err := localFilesystem.GetAppDatabaseFolderPath()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentLocationLabel := getLabelCentered("Current Database Directory:")
|
||
|
|
||
|
currentLocationText := getBoldLabelCentered(databaseDirectory)
|
||
|
|
||
|
resetLocation := widget.NewButtonWithIcon("Reset To Original", theme.ContentUndoIcon(), func(){
|
||
|
|
||
|
confirmDialogCallbackFunction := func(response bool){
|
||
|
if (response == false){
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err := globalSettings.DeleteSetting("DatabaseFolderpath")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentPage()
|
||
|
}
|
||
|
|
||
|
dialogTitle := translate("Confirm Reset Database Location?")
|
||
|
dialogMessageA := getLabelCentered("Confirm to reset the database location?")
|
||
|
dialogMessageB := getLabelCentered("You must restart Seekia for the change to take effect.")
|
||
|
dialogMessageC := getLabelCentered("Move your existing database to the new location before starting Seekia again.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
|
||
|
dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
|
||
|
})
|
||
|
|
||
|
selectNewLocationButton := widget.NewButtonWithIcon("Select New Location", theme.FolderIcon(), func(){
|
||
|
|
||
|
folderOpenCallbackFunction := func(folderObject fyne.ListableURI, err error){
|
||
|
|
||
|
if (err != nil) {
|
||
|
title := translate("Failed To Open Folder Path.")
|
||
|
dialogMessage := getLabelCentered(translate("Report this error to Seekia developers: " + err.Error()))
|
||
|
dialogContent := container.NewVBox(dialogMessage)
|
||
|
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (folderObject == nil){
|
||
|
return
|
||
|
}
|
||
|
|
||
|
folderPath := folderObject.Path()
|
||
|
|
||
|
err = globalSettings.SetSetting("DatabaseFolderpath", folderPath)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
currentPage()
|
||
|
}
|
||
|
|
||
|
dialog.ShowFolderOpen(folderOpenCallbackFunction, window)
|
||
|
})
|
||
|
|
||
|
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, resetLocation, selectNewLocationButton))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), currentLocationLabel, currentLocationText, widget.NewSeparator(), buttonsGrid)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
/*
|
||
|
func setSyncSettingsPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered(translate("Sync Settings"))
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
underConstructionLabel := getBoldLabelCentered("Under construction.")
|
||
|
|
||
|
//TODO
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), underConstructionLabel)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
func setChangeAppCurrencyPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
getCurrentCurrencyFunction := func()(string, error){
|
||
|
|
||
|
exists, currentAppCurrency, err := globalSettings.GetSetting("Currency")
|
||
|
if (err != nil) { return "", err }
|
||
|
if (exists == false){
|
||
|
return "USD", nil
|
||
|
}
|
||
|
|
||
|
return currentAppCurrency, nil
|
||
|
}
|
||
|
|
||
|
onSelectFunction := func(newCurrencyCode string)error{
|
||
|
|
||
|
err := globalSettings.SetSetting("Currency", newCurrencyCode)
|
||
|
if (err != nil){ return err }
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
setChooseCurrencyPage(window, getCurrentCurrencyFunction, onSelectFunction, previousPage)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setChooseCurrencyPage(window fyne.Window, getCurrentCurrencyFunction func()(string, error), onSelectFunction func(string)error, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setChooseCurrencyPage(window, getCurrentCurrencyFunction, onSelectFunction, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Choose Currency"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
currentCurrencyCode, err := getCurrentCurrencyFunction()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentCurrencyName, currentCurrencySymbol, err := currencies.GetCurrencyInfoFromCurrencyCode(currentCurrencyCode)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentCurrencyLabel := getLabelCentered("Current Currency:")
|
||
|
currentCurrencyText := getBoldLabelCentered(currentCurrencySymbol + " - " + currentCurrencyName + " - " + currentCurrencyCode)
|
||
|
|
||
|
chooseCurrencyLabel := getItalicLabelCentered("Choose Currency:")
|
||
|
|
||
|
allCurrencyObjectsList, err := currencies.GetCurrencyObjectsList()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
allCurrencyDescriptionsList := make([]string, 0, len(allCurrencyObjectsList))
|
||
|
allCurrencyCodesList := make([]string, 0, len(allCurrencyObjectsList))
|
||
|
|
||
|
for _, currencyObject := range allCurrencyObjectsList{
|
||
|
|
||
|
currencyName := currencyObject.Name
|
||
|
currencySymbol := currencyObject.Symbol
|
||
|
currencyCode := currencyObject.Code
|
||
|
|
||
|
currencyNameTranslated := translate(currencyName)
|
||
|
|
||
|
currencyDescription := currencySymbol + " - " + currencyNameTranslated + " - " + currencyCode
|
||
|
|
||
|
allCurrencyDescriptionsList = append(allCurrencyDescriptionsList, currencyDescription)
|
||
|
allCurrencyCodesList = append(allCurrencyCodesList, currencyCode)
|
||
|
}
|
||
|
|
||
|
onSelectedFunction := func(currencyIndex int) {
|
||
|
|
||
|
selectedCurrencyCode := allCurrencyCodesList[currencyIndex]
|
||
|
|
||
|
err := onSelectFunction(selectedCurrencyCode)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentPage()
|
||
|
}
|
||
|
|
||
|
widgetList, err := getFyneWidgetListFromStringList(allCurrencyDescriptionsList, onSelectedFunction)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
header := container.NewVBox(title, backButton, widget.NewSeparator(), currentCurrencyLabel, currentCurrencyText, widget.NewSeparator(), chooseCurrencyLabel, widget.NewSeparator())
|
||
|
|
||
|
page := container.NewBorder(header, nil, nil, nil, widgetList)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setViewLogsPage(window fyne.Window, logType string, previousPage func()){
|
||
|
|
||
|
if (logType != "General" && logType != "Network" && logType != "BackgroundJobs"){
|
||
|
setErrorEncounteredPage(window, errors.New("setViewLogsPage called with invalid logType: " + logType), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentPage := func(){setViewLogsPage(window, logType, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Logs")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("View Seekia logs.")
|
||
|
|
||
|
logTypeLabel := getBoldLabelCentered("Log Type:")
|
||
|
|
||
|
logTypesList := []string{translate("General"), translate("Network"), translate("Background Jobs")}
|
||
|
|
||
|
logTypeSelector := widget.NewSelect(logTypesList, func(selection string){
|
||
|
|
||
|
if (selection == translate("General")){
|
||
|
|
||
|
setViewLogsPage(window, "General", previousPage)
|
||
|
|
||
|
} else if (selection == translate("Network")){
|
||
|
|
||
|
setViewLogsPage(window, "Network", previousPage)
|
||
|
|
||
|
} else if (selection == translate("Background Jobs")){
|
||
|
|
||
|
setViewLogsPage(window, "BackgroundJobs", previousPage)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
if (logType == "General"){
|
||
|
|
||
|
logTypeSelector.Selected = translate("General")
|
||
|
|
||
|
} else if (logType == "Network"){
|
||
|
|
||
|
logTypeSelector.Selected = translate("Network")
|
||
|
|
||
|
} else if (logType == "BackgroundJobs"){
|
||
|
|
||
|
logTypeSelector.Selected = translate("Background Jobs")
|
||
|
}
|
||
|
|
||
|
logTypeSelectorCentered := getWidgetCentered(logTypeSelector)
|
||
|
|
||
|
logList, err := logger.GetLogList(logType)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (len(logList) == 0){
|
||
|
|
||
|
noLogsExistLabel := getBoldLabelCentered("No log entries exist.")
|
||
|
|
||
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), logTypeLabel, logTypeSelectorCentered, widget.NewSeparator(), noLogsExistLabel, refreshButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
trimmedLogList := make([]string, 0, len(logList))
|
||
|
|
||
|
for _, logText := range logList{
|
||
|
|
||
|
trimmedText, _, err := helpers.TrimAndFlattenString(logText, 30)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
trimmedLogList = append(trimmedLogList, trimmedText)
|
||
|
}
|
||
|
|
||
|
onClickedFunction := func(selectedIndex int){
|
||
|
|
||
|
logText := logList[selectedIndex]
|
||
|
|
||
|
setViewTextPage(window, "Viewing Log", logText, false, currentPage)
|
||
|
}
|
||
|
|
||
|
logsWidgetList, err := getFyneWidgetListFromStringList(logList, onClickedFunction)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
||
|
|
||
|
header := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), logTypeLabel, logTypeSelectorCentered, widget.NewSeparator())
|
||
|
|
||
|
page := container.NewBorder(header, refreshButton, nil, nil, logsWidgetList)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setViewDeveloperSettingsPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setViewDeveloperSettingsPage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Developer Settings")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
networkTypeButton := getWidgetCentered(widget.NewButton("Network Type", func(){
|
||
|
setViewAppNetworkTypePage(window, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), networkTypeButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setViewAppNetworkTypePage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setViewAppNetworkTypePage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Network Type")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Your Seekia application can interact with different network types.")
|
||
|
description2 := getLabelCentered("There are 2 network types: Mainnet and Testnet 1.")
|
||
|
description3 := getLabelCentered("You can change your app network type to interact with a different network.")
|
||
|
description4 := getLabelCentered("You should use Testnet 1 when testing new releases of Seekia before they are versioned.")
|
||
|
|
||
|
currentNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
getCurrentNetworkTypeString := func()(string, error){
|
||
|
if (currentNetworkType == 1){
|
||
|
return "Mainnet", nil
|
||
|
}
|
||
|
if (currentNetworkType == 2){
|
||
|
return "Testnet 1", nil
|
||
|
}
|
||
|
|
||
|
currentNetworkTypeString := helpers.ConvertByteToString(currentNetworkType)
|
||
|
|
||
|
return "", errors.New("GetAppNetworkType returning invalid network type: " + currentNetworkTypeString)
|
||
|
}
|
||
|
|
||
|
currentNetworkTypeString, err := getCurrentNetworkTypeString()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentNetworkTypeLabel := widget.NewLabel("Current Network Type:")
|
||
|
|
||
|
currentNetworkTypeText := getBoldLabel(currentNetworkTypeString)
|
||
|
|
||
|
currentNetworkTypeRow := container.NewHBox(layout.NewSpacer(), currentNetworkTypeLabel, currentNetworkTypeText, layout.NewSpacer())
|
||
|
|
||
|
changeNetworkTypeButton := getWidgetCentered(widget.NewButtonWithIcon("Change Network Type", theme.NavigateNextIcon(), func(){
|
||
|
setChooseNewAppNetworkTypePage(window, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), currentNetworkTypeRow, widget.NewSeparator(), changeNetworkTypeButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setChooseNewAppNetworkTypePage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered("Choose Network Type")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Choose your new network type.")
|
||
|
description2 := getLabelCentered("This change will impact your matches and chat conversations.")
|
||
|
description3 := getLabelCentered("Your client will automatically delete content for other network types from the database.")
|
||
|
description4 := getLabelCentered("Your broadcasted content and messages will not be deleted.")
|
||
|
description5 := getLabelCentered("This change will take effect for all of your app users.")
|
||
|
|
||
|
currentNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
chooseMainnetButton := widget.NewButton("Mainnet", func(){
|
||
|
if (currentNetworkType == 1){
|
||
|
dialogTitle := translate("Cannot Change Network Type")
|
||
|
dialogMessageA := getLabelCentered("This network type is already your current app network type.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setChangeAppNetworkTypePage(window, 1, previousPage)
|
||
|
})
|
||
|
if (currentNetworkType == 1){
|
||
|
chooseMainnetButton.Importance = widget.HighImportance
|
||
|
}
|
||
|
|
||
|
chooseTestnet1Button := widget.NewButton("Testnet 1", func(){
|
||
|
if (currentNetworkType == 2){
|
||
|
dialogTitle := translate("Cannot Change Network Type")
|
||
|
dialogMessageA := getLabelCentered("This network type is already your current app network type.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setChangeAppNetworkTypePage(window, 2, previousPage)
|
||
|
})
|
||
|
|
||
|
if (currentNetworkType == 2){
|
||
|
chooseTestnet1Button.Importance = widget.HighImportance
|
||
|
}
|
||
|
|
||
|
chooseNetworkTypesGrid := getContainerCentered(container.NewGridWithColumns(1, chooseMainnetButton, chooseTestnet1Button))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), chooseNetworkTypesGrid)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setChangeAppNetworkTypePage(window fyne.Window, newAppNetworkType byte, nextPage func()){
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(newAppNetworkType)
|
||
|
if (isValid == false){
|
||
|
newAppNetworkTypeString := helpers.ConvertByteToString(newAppNetworkType)
|
||
|
setErrorEncounteredPage(window, errors.New("setChangeAppNetworkTypePage called with invalid newAppNetworkType: " + newAppNetworkTypeString), nextPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
title := getPageTitleCentered("Changing Network Type")
|
||
|
|
||
|
description := getLabelCentered("Changing network type...")
|
||
|
|
||
|
progressBar := getWidgetCentered(widget.NewProgressBarInfinite())
|
||
|
|
||
|
page := container.NewVBox(title, widget.NewSeparator(), description, progressBar)
|
||
|
|
||
|
window.SetContent(page)
|
||
|
|
||
|
err := setAppNetworkType.SetAppNetworkType(newAppNetworkType)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, nextPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
nextPage()
|
||
|
}
|
||
|
|
||
|
|
||
|
|