1260 lines
39 KiB
Go
1260 lines
39 KiB
Go
|
package gui
|
||
|
|
||
|
// gui.go provides miscellaneous GUI functions
|
||
|
|
||
|
import "fyne.io/fyne/v2"
|
||
|
import "fyne.io/fyne/v2/widget"
|
||
|
import "fyne.io/fyne/v2/layout"
|
||
|
import "fyne.io/fyne/v2/dialog"
|
||
|
import "fyne.io/fyne/v2/theme"
|
||
|
import "fyne.io/fyne/v2/canvas"
|
||
|
import "fyne.io/fyne/v2/container"
|
||
|
|
||
|
import "seekia/internal/appMemory"
|
||
|
import "seekia/internal/appUsers"
|
||
|
import "seekia/internal/encoding"
|
||
|
import "seekia/internal/helpers"
|
||
|
import "seekia/internal/identity"
|
||
|
import "seekia/internal/mySettings"
|
||
|
import "seekia/internal/translation"
|
||
|
|
||
|
import "errors"
|
||
|
|
||
|
func getCustomFyneSize(shift int)fyne.Size{
|
||
|
|
||
|
normalStyle := fyne.TextStyle{
|
||
|
Bold: false,
|
||
|
Italic: false,
|
||
|
Monospace: false,
|
||
|
}
|
||
|
|
||
|
customSize := float32(30 + shift)
|
||
|
|
||
|
size := fyne.MeasureText("Standard", customSize, normalStyle)
|
||
|
|
||
|
return size
|
||
|
}
|
||
|
|
||
|
func getBoldLabel(text string) fyne.Widget{
|
||
|
|
||
|
titleStyle := fyne.TextStyle{
|
||
|
Bold: true,
|
||
|
Italic: false,
|
||
|
Monospace: false,
|
||
|
}
|
||
|
|
||
|
boldLabel := widget.NewLabelWithStyle(text, fyne.TextAlign(fyne.TextAlignCenter), titleStyle)
|
||
|
|
||
|
return boldLabel
|
||
|
}
|
||
|
|
||
|
func getBoldItalicLabel(text string) fyne.Widget{
|
||
|
|
||
|
titleStyle := fyne.TextStyle{
|
||
|
Bold: true,
|
||
|
Italic: true,
|
||
|
Monospace: false,
|
||
|
}
|
||
|
|
||
|
boldItalicLabel := widget.NewLabelWithStyle(text, fyne.TextAlign(fyne.TextAlignCenter), titleStyle)
|
||
|
|
||
|
return boldItalicLabel
|
||
|
}
|
||
|
|
||
|
func getItalicLabel(text string) fyne.Widget{
|
||
|
|
||
|
italicTextStyle := fyne.TextStyle{
|
||
|
Bold: false,
|
||
|
Italic: true,
|
||
|
Monospace: false,
|
||
|
}
|
||
|
|
||
|
italicLabel := widget.NewLabelWithStyle(text, fyne.TextAlign(fyne.TextAlignCenter), italicTextStyle)
|
||
|
|
||
|
return italicLabel
|
||
|
}
|
||
|
|
||
|
func getFyneTextStyle_Standard()fyne.TextStyle{
|
||
|
|
||
|
standardStyle := fyne.TextStyle{
|
||
|
Bold: false,
|
||
|
Italic: false,
|
||
|
Monospace: false,
|
||
|
}
|
||
|
|
||
|
return standardStyle
|
||
|
}
|
||
|
|
||
|
func getFyneTextStyle_Bold()fyne.TextStyle{
|
||
|
|
||
|
boldStyle := fyne.TextStyle{
|
||
|
Bold: true,
|
||
|
Italic: false,
|
||
|
Monospace: false,
|
||
|
}
|
||
|
|
||
|
return boldStyle
|
||
|
}
|
||
|
|
||
|
func getFyneTextStyle_Italic()fyne.TextStyle{
|
||
|
|
||
|
italicStyle := fyne.TextStyle{
|
||
|
Bold: false,
|
||
|
Italic: true,
|
||
|
Monospace: false,
|
||
|
}
|
||
|
|
||
|
return italicStyle
|
||
|
}
|
||
|
|
||
|
|
||
|
func getLabelCentered(text string) *fyne.Container{
|
||
|
|
||
|
label := widget.NewLabel(text)
|
||
|
labelCentered := container.NewHBox(layout.NewSpacer(), label, layout.NewSpacer())
|
||
|
|
||
|
return labelCentered
|
||
|
}
|
||
|
|
||
|
|
||
|
func getBoldLabelCentered(inputText string)*fyne.Container{
|
||
|
|
||
|
boldLabel := getBoldLabel(inputText)
|
||
|
|
||
|
boldLabelCentered := container.NewHBox(layout.NewSpacer(), boldLabel, layout.NewSpacer())
|
||
|
|
||
|
return boldLabelCentered
|
||
|
}
|
||
|
|
||
|
func getItalicLabelCentered(inputText string)*fyne.Container{
|
||
|
|
||
|
italicLabel := getItalicLabel(inputText)
|
||
|
|
||
|
italicLabelCentered := container.NewHBox(layout.NewSpacer(), italicLabel, layout.NewSpacer())
|
||
|
|
||
|
return italicLabelCentered
|
||
|
}
|
||
|
|
||
|
func getBoldItalicLabelCentered(inputText string)*fyne.Container{
|
||
|
|
||
|
boldItalicLabel := getBoldItalicLabel(inputText)
|
||
|
|
||
|
boldItalicLabelCentered := container.NewHBox(layout.NewSpacer(), boldItalicLabel, layout.NewSpacer())
|
||
|
return boldItalicLabelCentered
|
||
|
}
|
||
|
|
||
|
func getWidgetCentered(widget fyne.Widget)*fyne.Container{
|
||
|
|
||
|
widgetCentered := container.NewHBox(layout.NewSpacer(), widget, layout.NewSpacer())
|
||
|
|
||
|
return widgetCentered
|
||
|
}
|
||
|
|
||
|
|
||
|
func getContainerCentered(inputContainer *fyne.Container)*fyne.Container{
|
||
|
|
||
|
containerCentered := container.NewHBox(layout.NewSpacer(), inputContainer, layout.NewSpacer())
|
||
|
|
||
|
return containerCentered
|
||
|
}
|
||
|
|
||
|
|
||
|
func getFyneImageCentered(inputImage *canvas.Image) *fyne.Container{
|
||
|
|
||
|
imageCentered := container.NewHBox(layout.NewSpacer(), inputImage, layout.NewSpacer())
|
||
|
|
||
|
return imageCentered
|
||
|
}
|
||
|
|
||
|
func getPageTitleCentered(title string)(*fyne.Container){
|
||
|
|
||
|
textStyle := getFyneTextStyle_Bold()
|
||
|
|
||
|
currentApp := fyne.CurrentApp()
|
||
|
|
||
|
currentThemeVariant := currentApp.Settings().ThemeVariant()
|
||
|
|
||
|
currentThemeObject := currentApp.Settings().Theme()
|
||
|
|
||
|
// The .Color function is used to retrieve any specified color
|
||
|
// In this case, we are retrieving the current foreground color of the theme
|
||
|
// We have to include the theme variant to retrieve the color
|
||
|
textColor := currentThemeObject.Color(theme.ColorNameForeground, currentThemeVariant)
|
||
|
|
||
|
label := canvas.NewText(title, textColor)
|
||
|
label.TextSize = 17
|
||
|
label.TextStyle = textStyle
|
||
|
|
||
|
increasedPadding := container.NewPadded(label)
|
||
|
increasedPadding2 := container.NewPadded(increasedPadding)
|
||
|
|
||
|
pageTitleCentered := container.NewHBox(layout.NewSpacer(), increasedPadding2, layout.NewSpacer())
|
||
|
|
||
|
return pageTitleCentered
|
||
|
}
|
||
|
|
||
|
func getPageSubtitleCentered(subtitle string) *fyne.Container{
|
||
|
|
||
|
textStyle := getFyneTextStyle_Bold()
|
||
|
|
||
|
currentApp := fyne.CurrentApp()
|
||
|
|
||
|
currentThemeVariant := currentApp.Settings().ThemeVariant()
|
||
|
|
||
|
currentThemeObject := currentApp.Settings().Theme()
|
||
|
|
||
|
// The .Color function is used to retrieve any specified color
|
||
|
// In this case, we are retrieving the current foreground color of the theme
|
||
|
// We have to include the theme variant to retrieve the color
|
||
|
textColor := currentThemeObject.Color(theme.ColorNameForeground, currentThemeVariant)
|
||
|
|
||
|
label := canvas.NewText(subtitle, textColor)
|
||
|
label.TextSize = 16
|
||
|
label.TextStyle = textStyle
|
||
|
|
||
|
labelPadded1 := container.NewPadded(label)
|
||
|
labelPadded2 := container.NewPadded(labelPadded1)
|
||
|
|
||
|
pageSubtitleCentered := container.NewHBox(layout.NewSpacer(), labelPadded2, layout.NewSpacer())
|
||
|
|
||
|
return pageSubtitleCentered
|
||
|
}
|
||
|
|
||
|
func getBackButtonCentered(previousPage func())*fyne.Container{
|
||
|
|
||
|
backButton := getWidgetCentered(widget.NewButtonWithIcon(translate("Go Back"), theme.NavigateBackIcon(), previousPage))
|
||
|
|
||
|
return backButton
|
||
|
}
|
||
|
|
||
|
func getFyneImageBoxed(inputImage *canvas.Image) *fyne.Container{
|
||
|
|
||
|
boxedImage := container.NewBorder(widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), inputImage)
|
||
|
|
||
|
return boxedImage
|
||
|
}
|
||
|
|
||
|
func getContainerBoxed(inputContainer *fyne.Container) *fyne.Container{
|
||
|
|
||
|
boxedContainer := container.NewBorder(widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), inputContainer)
|
||
|
|
||
|
return boxedContainer
|
||
|
}
|
||
|
|
||
|
func getAppTabsBoxed(inputTabs *container.AppTabs) *fyne.Container{
|
||
|
|
||
|
boxedTabs := container.NewBorder(widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), inputTabs)
|
||
|
|
||
|
return boxedTabs
|
||
|
}
|
||
|
|
||
|
func getScrollContainerBoxed(inputScrollContainer *container.Scroll) *fyne.Container{
|
||
|
|
||
|
boxedContainer := container.NewBorder(widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), inputScrollContainer)
|
||
|
|
||
|
return boxedContainer
|
||
|
}
|
||
|
|
||
|
func getWidgetBoxed(inputWidget fyne.Widget) *fyne.Container{
|
||
|
|
||
|
boxedWidget := container.NewBorder(widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), widget.NewSeparator(), inputWidget)
|
||
|
|
||
|
return boxedWidget
|
||
|
}
|
||
|
|
||
|
func translate(text string) string{
|
||
|
|
||
|
result := translation.TranslateTextFromEnglishToMyLanguage(text)
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
func translateWithContext(text string, context string)string{
|
||
|
|
||
|
//TODO: We will use this to translate text that belongs to a specific context
|
||
|
// An example is 23andMe, which will have its own translations for text
|
||
|
// For this reason, we may end up having 2 identical texts that have different translations
|
||
|
|
||
|
return text
|
||
|
}
|
||
|
|
||
|
//TODO: Swap content and window parameters
|
||
|
func setPageContent(content *fyne.Container, window fyne.Window){
|
||
|
|
||
|
navbar, navbarLocation, err := getNavigationBar(window)
|
||
|
if (err != nil){
|
||
|
title := getPageTitleCentered("Failed to read from filesystem.")
|
||
|
description := getLabelCentered("Contact the Seekia developers to report this error.")
|
||
|
|
||
|
errorString := err.Error()
|
||
|
errorLabel := getLabelCentered(errorString)
|
||
|
|
||
|
page := container.NewVBox(title, description, errorLabel)
|
||
|
window.SetContent(page)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
contentScrollable := container.NewVScroll(content)
|
||
|
|
||
|
getPageContentWithNavbar := func()*fyne.Container{
|
||
|
if (navbarLocation == "Bottom"){
|
||
|
content := container.NewBorder(nil, navbar, nil, nil, contentScrollable)
|
||
|
return content
|
||
|
}
|
||
|
if (navbarLocation == "Left"){
|
||
|
content := container.NewBorder(nil, nil, navbar, nil, contentScrollable)
|
||
|
return content
|
||
|
}
|
||
|
if (navbarLocation == "Right"){
|
||
|
content := container.NewBorder(nil, nil, nil, navbar, contentScrollable)
|
||
|
return content
|
||
|
}
|
||
|
content := container.NewBorder(navbar, nil, nil, nil, contentScrollable)
|
||
|
return content
|
||
|
}
|
||
|
|
||
|
pageContentWithNavbar := getPageContentWithNavbar()
|
||
|
|
||
|
window.SetContent(pageContentWithNavbar)
|
||
|
}
|
||
|
|
||
|
//Outputs:
|
||
|
// -*fyne.Container: Navigation Bar
|
||
|
// -string: Navigation location ("Top"/"Bottom"/"Left"/"Right")
|
||
|
// -error
|
||
|
func getNavigationBar(window fyne.Window) (*fyne.Container, string, error){
|
||
|
|
||
|
geneticsIcon, err := getFyneImageIcon("Genome")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
hostIcon, err := getFyneImageIcon("Host")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
desiresIcon, err := getFyneImageIcon("Desires")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
matchesIcon, err := getFyneImageIcon("Mate")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
homeIcon, err := getFyneImageIcon("Home")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
profileIcon, err := getFyneImageIcon("Profile")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
moderateIcon, err := getFyneImageIcon("Moderate")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
chatIcon, err := getFyneImageIcon("Chat")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
settingsIcon, err := getFyneImageIcon("Settings")
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
geneticsButton := widget.NewButton(translate("Genetics"), func(){
|
||
|
setGeneticsPage(window)
|
||
|
})
|
||
|
desiresButton := widget.NewButton(translate("Desires"), func(){
|
||
|
setDesiresPage(window)
|
||
|
})
|
||
|
matchesButton := widget.NewButton(translate("Matches"), func(){
|
||
|
setMatchesPage(window)
|
||
|
})
|
||
|
homeButton := widget.NewButton(translate("Home"), func(){
|
||
|
setHomePage(window)
|
||
|
})
|
||
|
profileButton := widget.NewButton(translate("Profile"), func(){
|
||
|
setProfilePage(window, false, "", false, nil)
|
||
|
})
|
||
|
hostButton := widget.NewButton(translate("Host"), func(){
|
||
|
setHostPage(window, false, nil)
|
||
|
})
|
||
|
chatButton := widget.NewButton(translate("Chat"), func(){
|
||
|
setChatPage(window)
|
||
|
})
|
||
|
moderateButton := widget.NewButton(translate("Moderate"), func(){
|
||
|
setModeratePage(window, false, nil)
|
||
|
})
|
||
|
settingsButton := widget.NewButton(translate("Settings"), func(){
|
||
|
setSettingsPage(window)
|
||
|
})
|
||
|
|
||
|
geneticsButtonWithIcon := container.NewGridWithRows(2, geneticsIcon, geneticsButton)
|
||
|
desiresButtonWithIcon := container.NewGridWithRows(2, desiresIcon, desiresButton)
|
||
|
matchesButtonWithIcon := container.NewGridWithRows(2, matchesIcon, matchesButton)
|
||
|
homeButtonWithIcon := container.NewGridWithRows(2, homeIcon, homeButton)
|
||
|
profileButtonWithIcon := container.NewGridWithRows(2, profileIcon, profileButton)
|
||
|
hostButtonWithIcon := container.NewGridWithRows(2, hostIcon, hostButton)
|
||
|
chatButtonWithIcon := container.NewGridWithRows(2, chatIcon, chatButton)
|
||
|
moderateButtonWithIcon := container.NewGridWithRows(2, moderateIcon, moderateButton)
|
||
|
settingsButtonWithIcon := container.NewGridWithRows(2, settingsIcon, settingsButton)
|
||
|
|
||
|
getNavigationLocation := func()(string, error){
|
||
|
|
||
|
exists, navigationLocation, err := mySettings.GetSetting("NavigationBarLocation")
|
||
|
if (err != nil) { return "", err }
|
||
|
if (exists == false){
|
||
|
return "Top", nil
|
||
|
}
|
||
|
if (navigationLocation != "Top" && navigationLocation != "Bottom" && navigationLocation != "Left" && navigationLocation != "Right"){
|
||
|
return "", errors.New("Invalid NavigationBarLocation: " + navigationLocation)
|
||
|
}
|
||
|
return navigationLocation, nil
|
||
|
}
|
||
|
|
||
|
navigationLocation, err := getNavigationLocation()
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
getNavbarButtonsList := func()([]*fyne.Container, error){
|
||
|
|
||
|
_, showHostButton, err := mySettings.GetSetting("ShowHostButtonNavigation")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
_, showModerateButton, err := mySettings.GetSetting("ShowModerateButtonNavigation")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
if (showHostButton == "Yes" && showModerateButton == "Yes"){
|
||
|
|
||
|
itemsList := []*fyne.Container{homeButtonWithIcon, geneticsButtonWithIcon, profileButtonWithIcon, desiresButtonWithIcon, matchesButtonWithIcon, chatButtonWithIcon, hostButtonWithIcon, moderateButtonWithIcon, settingsButtonWithIcon}
|
||
|
|
||
|
return itemsList, nil
|
||
|
|
||
|
}
|
||
|
if (showHostButton != "Yes" && showModerateButton == "Yes"){
|
||
|
|
||
|
itemsList := []*fyne.Container{homeButtonWithIcon, geneticsButtonWithIcon, profileButtonWithIcon, desiresButtonWithIcon, matchesButtonWithIcon, chatButtonWithIcon, moderateButtonWithIcon, settingsButtonWithIcon }
|
||
|
|
||
|
return itemsList, nil
|
||
|
}
|
||
|
if (showHostButton == "Yes" && showModerateButton != "Yes"){
|
||
|
|
||
|
itemsList := []*fyne.Container{homeButtonWithIcon, geneticsButtonWithIcon, profileButtonWithIcon, desiresButtonWithIcon, matchesButtonWithIcon, chatButtonWithIcon, hostButtonWithIcon, settingsButtonWithIcon }
|
||
|
|
||
|
return itemsList, nil
|
||
|
}
|
||
|
|
||
|
// showHostButton != "Yes" && showModerateButton != "Yes"
|
||
|
|
||
|
itemsList := []*fyne.Container{homeButtonWithIcon, geneticsButtonWithIcon, profileButtonWithIcon, desiresButtonWithIcon, matchesButtonWithIcon, chatButtonWithIcon, settingsButtonWithIcon }
|
||
|
|
||
|
return itemsList, nil
|
||
|
}
|
||
|
|
||
|
navbarButtonsList, err := getNavbarButtonsList()
|
||
|
if (err != nil) { return nil, "", err }
|
||
|
|
||
|
if (navigationLocation == "Top" || navigationLocation == "Bottom"){
|
||
|
|
||
|
navbar := container.NewHBox()
|
||
|
navbar.Add(layout.NewSpacer())
|
||
|
|
||
|
for _, element := range navbarButtonsList{
|
||
|
navbar.Add(element)
|
||
|
}
|
||
|
navbar.Add(layout.NewSpacer())
|
||
|
|
||
|
navbarScrollable := container.NewHScroll(navbar)
|
||
|
|
||
|
if (navigationLocation == "Top"){
|
||
|
navbarWithSeparator := container.NewVBox(navbarScrollable, widget.NewSeparator())
|
||
|
|
||
|
return navbarWithSeparator, navigationLocation, nil
|
||
|
}
|
||
|
|
||
|
navbarWithSeparator := container.NewVBox(widget.NewSeparator(), navbarScrollable)
|
||
|
|
||
|
return navbarWithSeparator, navigationLocation, nil
|
||
|
}
|
||
|
if (navigationLocation == "Left" || navigationLocation == "Right"){
|
||
|
|
||
|
navbar := container.NewVBox()
|
||
|
navbar.Add(layout.NewSpacer())
|
||
|
|
||
|
for _, element := range navbarButtonsList{
|
||
|
navbar.Add(element)
|
||
|
}
|
||
|
navbar.Add(layout.NewSpacer())
|
||
|
|
||
|
navbarScrollable := container.NewVScroll(navbar)
|
||
|
|
||
|
if (navigationLocation == "Left"){
|
||
|
navbarWithSeparator := container.NewHBox(navbarScrollable, widget.NewSeparator())
|
||
|
|
||
|
return navbarWithSeparator, navigationLocation, nil
|
||
|
}
|
||
|
|
||
|
navbarWithSeparator := container.NewHBox(widget.NewSeparator(), navbarScrollable)
|
||
|
|
||
|
return navbarWithSeparator, navigationLocation, nil
|
||
|
}
|
||
|
|
||
|
return nil, "", errors.New("Invalid Navigation bar location: " + navigationLocation)
|
||
|
}
|
||
|
|
||
|
// This page is used when a new GUI page is being loaded, and concurrency is not being used
|
||
|
// When concurrency is being used, we give the user a GUI page where they can exit the page instead of waiting for the process to complete
|
||
|
// This screen should only be used when the time it takes to load will only be a few seconds
|
||
|
func setLoadingScreen(window fyne.Window, pageTitle string, loadingText string){
|
||
|
|
||
|
title := getPageTitleCentered(pageTitle)
|
||
|
|
||
|
loadingLabel := getWidgetCentered(getItalicLabel(loadingText))
|
||
|
progressBar := getWidgetCentered(widget.NewProgressBarInfinite())
|
||
|
|
||
|
pageContent := container.NewVBox(title, loadingLabel, progressBar)
|
||
|
|
||
|
page := container.NewCenter(pageContent)
|
||
|
|
||
|
window.SetContent(page)
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// This will only be used within the startup gui
|
||
|
func setErrorEncounteredPage_NoNavBar(window fyne.Window, err error, showBackButton bool, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered("Error Encountered")
|
||
|
|
||
|
header := container.NewVBox(title)
|
||
|
|
||
|
if (showBackButton == true){
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
header.Add(backButton)
|
||
|
}
|
||
|
|
||
|
header.Add(widget.NewSeparator())
|
||
|
|
||
|
description1 := getLabelCentered("Something went wrong. Report this error to Seekia developers.")
|
||
|
description2 := getBoldLabelCentered("Be aware that this error may contain sensitive information.")
|
||
|
description3 := getLabelCentered("Censor any sensitive information manually before sharing the error.")
|
||
|
|
||
|
header.Add(description1)
|
||
|
header.Add(description2)
|
||
|
header.Add(description3)
|
||
|
header.Add(widget.NewSeparator())
|
||
|
|
||
|
getErrorString := func()string{
|
||
|
if (err == nil){
|
||
|
return "No nav bar error encountered page called with nil error."
|
||
|
}
|
||
|
errorString := err.Error()
|
||
|
return errorString
|
||
|
}
|
||
|
|
||
|
errorString := getErrorString()
|
||
|
|
||
|
errorLabel := widget.NewLabel(errorString)
|
||
|
errorLabel.Wrapping = 3
|
||
|
errorLabel.Alignment = 1
|
||
|
errorLabel.TextStyle = getFyneTextStyle_Bold()
|
||
|
|
||
|
//TODO: Add copyable toggle
|
||
|
|
||
|
page := container.NewBorder(header, nil, nil, nil, errorLabel)
|
||
|
|
||
|
window.SetContent(page)
|
||
|
}
|
||
|
|
||
|
func setErrorEncounteredPage(window fyne.Window, err error, previousPage func()){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "ErrorEncounteredPage")
|
||
|
|
||
|
currentPage := func(){setErrorEncounteredPage(window, err, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Error Encountered")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Something went wrong. Report this error to Seekia developers.")
|
||
|
description2 := getBoldLabelCentered("Be aware that this error may contain sensitive information.")
|
||
|
description3 := getLabelCentered("Censor any sensitive information manually before sharing the error.")
|
||
|
|
||
|
getErrorString := func()string{
|
||
|
if (err == nil){
|
||
|
return "Error encountered page called with nil error."
|
||
|
}
|
||
|
errorString := err.Error()
|
||
|
return errorString
|
||
|
}
|
||
|
|
||
|
errorString := getErrorString()
|
||
|
|
||
|
errorStringTrimmed, _, _ := helpers.TrimAndFlattenString(errorString, 40)
|
||
|
|
||
|
errorLabel := getBoldLabelCentered(errorStringTrimmed)
|
||
|
|
||
|
viewTextButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
||
|
setViewTextPage(window, "Viewing Error", errorString, false, currentPage)
|
||
|
})
|
||
|
|
||
|
errorRow := container.NewHBox(layout.NewSpacer(), errorLabel, viewTextButton, layout.NewSpacer())
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), errorRow, widget.NewSeparator())
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func showUnderConstructionDialog(window fyne.Window){
|
||
|
|
||
|
dialogTitle := translate("Under Construction")
|
||
|
dialogMessageA := getLabelCentered(translate("Seekia is under construction."))
|
||
|
dialogMessageB := getLabelCentered(translate("This page/feature needs to be built."))
|
||
|
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
}
|
||
|
|
||
|
func setHomePage(window fyne.Window){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "Home")
|
||
|
|
||
|
currentPage := func(){setHomePage(window)}
|
||
|
|
||
|
title := getPageTitleCentered("Home")
|
||
|
|
||
|
welcomeTitle := getBoldLabelCentered("Welcome to Seekia!")
|
||
|
|
||
|
welcomeMessage := getLabelCentered("Seekia is a race aware mate discovery network.")
|
||
|
|
||
|
exists, currentUserName := appUsers.GetCurrentAppUserName()
|
||
|
if (exists == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setHomePage called with no signed-in user."), func(){setChooseAppUserPage(window)})
|
||
|
return
|
||
|
}
|
||
|
currentUserLabel := getBoldItalicLabel("Current User:")
|
||
|
|
||
|
changeUserButton := getWidgetCentered(widget.NewButtonWithIcon(currentUserName, theme.AccountIcon(), func(){
|
||
|
|
||
|
setLoadingScreen(window, "Signing Out", "Signing out...")
|
||
|
|
||
|
err := appUsers.SignOutOfAppUser()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage_NoNavBar(window, err, true, func(){setChooseAppUserPage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setChooseAppUserPage(window)
|
||
|
}))
|
||
|
|
||
|
currentUserRow := container.NewHBox(layout.NewSpacer(), currentUserLabel, changeUserButton, layout.NewSpacer())
|
||
|
|
||
|
helpIcon, err := getFyneImageIcon("Info")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
helpButton := widget.NewButton(translate("Help"), func(){
|
||
|
setHelpPage(window, currentPage)
|
||
|
})
|
||
|
helpButtonWithIcon := container.NewGridWithColumns(1, helpIcon, helpButton)
|
||
|
|
||
|
rulesIcon, err := getFyneImageIcon("Questionnaire")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
rulesButton := widget.NewButton("Rules", func(){
|
||
|
setViewSeekiaRulesPage(window, currentPage)
|
||
|
})
|
||
|
rulesButtonWithIcon := container.NewGridWithColumns(1, rulesIcon, rulesButton)
|
||
|
|
||
|
syncIcon, err := getFyneImageIcon("Sync")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
syncButton := widget.NewButton(translate("Sync"), func(){
|
||
|
setSyncPage(window, currentPage)
|
||
|
})
|
||
|
syncButtonWithIcon := container.NewGridWithRows(2, syncIcon, syncButton)
|
||
|
|
||
|
buttonsRow := getContainerCentered(container.NewGridWithRows(1, helpButtonWithIcon, rulesButtonWithIcon, syncButtonWithIcon))
|
||
|
|
||
|
description1 := getBoldLabelCentered("Learn how to use Seekia on the Help page.")
|
||
|
description2 := getLabelCentered("View the Seekia rules on the Rules page.")
|
||
|
description3 := getLabelCentered("Manage your connection to the Seekia network on the Sync page.")
|
||
|
|
||
|
seekiaLinkTitle := widget.NewLabel("Stay updated at:")
|
||
|
|
||
|
//TODO: Retrieve URL from parameters
|
||
|
// URL may need to be changed if it is lost or stolen
|
||
|
// Also add a page that shows .onion and .eth URLs
|
||
|
seekiaLink := getBoldLabel("Seekia.net")
|
||
|
|
||
|
seekiaVersion := getLabelCentered("Seekia Version 0.50")
|
||
|
|
||
|
seekiaLinkWithTitle := container.NewHBox(layout.NewSpacer(), seekiaLinkTitle, seekiaLink, layout.NewSpacer())
|
||
|
|
||
|
page := container.NewVBox(title, widget.NewSeparator(), welcomeTitle, welcomeMessage, widget.NewSeparator(), currentUserRow, widget.NewSeparator(), buttonsRow, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), seekiaLinkWithTitle, seekiaVersion)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setSelectLanguagePage(window fyne.Window, showNavigationBar bool, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered("Select Language")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("Choose your language.")
|
||
|
|
||
|
currentLanguage := translation.GetMyLanguage()
|
||
|
|
||
|
currentLanguageLabel := getBoldLabelCentered("Current Language:")
|
||
|
currentLanguageTextLabel := getLabelCentered(currentLanguage)
|
||
|
|
||
|
//TODO
|
||
|
|
||
|
comingSoonLabel := getBoldLabelCentered("More languages coming soon.")
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), currentLanguageLabel, currentLanguageTextLabel, widget.NewSeparator(), comingSoonLabel)
|
||
|
|
||
|
if (showNavigationBar == true){
|
||
|
setPageContent(page, window)
|
||
|
} else {
|
||
|
window.SetContent(page)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func setViewSeekiaRulesPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered("Seekia Rules")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getBoldLabelCentered("Unruleful content will be banned by the Seekia moderators.")
|
||
|
description2 := getLabelCentered("You can report rulebreaking content within the app.")
|
||
|
description3 := getLabelCentered("Identities, profiles and messages can be reported and banned.")
|
||
|
|
||
|
//TODO: Add more rules, and improve these rules.
|
||
|
// There should be a more descriptive page for moderators that has specific examples
|
||
|
|
||
|
spamDescription := widget.NewLabel("Selling or trading. Advertising or soliciting anything except yourself.")
|
||
|
spamAccordionItem := widget.NewAccordionItem("Spam", spamDescription)
|
||
|
|
||
|
nudityDescription := widget.NewLabel("Nudity and pornography.")
|
||
|
nudityAccordionItem := widget.NewAccordionItem("Nudity", nudityDescription)
|
||
|
|
||
|
dangerousDescription := widget.NewLabel("Threats, harrasment, and other dangerous content.")
|
||
|
dangerousAccordionItem := widget.NewAccordionItem("Dangerous Content", dangerousDescription)
|
||
|
|
||
|
illegalDescription := widget.NewLabel("Prostitution, drug trading, copyrighted content, and other unlawful content.")
|
||
|
illegalAccordionItem := widget.NewAccordionItem("Illegal Content", illegalDescription)
|
||
|
|
||
|
rulesAccordion := getContainerCentered(getWidgetBoxed(widget.NewAccordion(spamAccordionItem, nudityAccordionItem, dangerousAccordionItem, illegalAccordionItem)))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, rulesAccordion)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
// If profileTypeProvided == true, there is no ability to navigate between profile types
|
||
|
// If profileTypeProvided == false, you can navigate between profile types, and the result is saved in ProfilePageProfileType
|
||
|
func setProfilePage(window fyne.Window, profileTypeProvided bool, profileType string, previousPageProvided bool, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setProfilePage(window, profileTypeProvided, profileType, previousPageProvided, previousPage)}
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "Profile")
|
||
|
|
||
|
getModeratorModeEnabledStatus := func()(bool, error){
|
||
|
|
||
|
exists, moderatorModeStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
|
||
|
if (err != nil) { return false, err }
|
||
|
if (exists == true && moderatorModeStatus == "On"){
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
getHostModeEnabledStatus := func()(bool, error){
|
||
|
|
||
|
exists, hostModeStatus, err := mySettings.GetSetting("HostModeOnOffStatus")
|
||
|
if (err != nil) { return false, err }
|
||
|
if (exists == true && hostModeStatus == "On"){
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
moderatorModeEnabled, err := getModeratorModeEnabledStatus()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
hostModeEnabled, err := getHostModeEnabledStatus()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
getMyProfileType := func()(string, error){
|
||
|
|
||
|
if (profileTypeProvided == true){
|
||
|
|
||
|
if (profileType != "Mate" && profileType != "Host" && profileType != "Moderator"){
|
||
|
return "", errors.New("setProfilePage called with invalid profileType: " + profileType)
|
||
|
}
|
||
|
return profileType, nil
|
||
|
}
|
||
|
|
||
|
exists, myProfileType, err := mySettings.GetSetting("ProfilePageProfileType")
|
||
|
if (err != nil) { return "", err }
|
||
|
if (exists == false){
|
||
|
return "Mate", nil
|
||
|
}
|
||
|
if (myProfileType != "Mate" && myProfileType != "Host" && myProfileType != "Moderator"){
|
||
|
return "", errors.New("mySettings malformed: invalid ProfilePageProfileType: " + myProfileType)
|
||
|
}
|
||
|
|
||
|
if (myProfileType == "Moderator" && moderatorModeEnabled == false){
|
||
|
return "Mate", nil
|
||
|
}
|
||
|
if (myProfileType == "Host" && hostModeEnabled == false){
|
||
|
return "Mate", nil
|
||
|
}
|
||
|
|
||
|
return myProfileType, nil
|
||
|
}
|
||
|
|
||
|
myProfileType, err := getMyProfileType()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
title := getPageTitleCentered("My Profile")
|
||
|
|
||
|
page := container.NewVBox(title)
|
||
|
|
||
|
if (previousPageProvided == true){
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
page.Add(backButton)
|
||
|
}
|
||
|
|
||
|
profileTypeIcon, err := getIdentityTypeIcon(myProfileType, -10)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
getChangeProfileTypeButtonOrText := func()(fyne.Widget, error){
|
||
|
|
||
|
if (profileTypeProvided == true){
|
||
|
// The page does not offer a button to switch between profile types.
|
||
|
profileTypeLabel := getBoldLabel(myProfileType + " Profile")
|
||
|
return profileTypeLabel, nil
|
||
|
}
|
||
|
|
||
|
if (moderatorModeEnabled == false && hostModeEnabled == false){
|
||
|
|
||
|
mateLabel := getBoldLabel("Mate Profile")
|
||
|
return mateLabel, nil
|
||
|
}
|
||
|
|
||
|
changeProfileTypeButton := widget.NewButton(myProfileType + " Profile", func(){
|
||
|
getNextProfileType := func()string{
|
||
|
if (myProfileType == "Mate"){
|
||
|
|
||
|
if (moderatorModeEnabled == true){
|
||
|
return "Moderator"
|
||
|
}
|
||
|
|
||
|
return "Host"
|
||
|
}
|
||
|
if (myProfileType == "Moderator"){
|
||
|
if (hostModeEnabled == true){
|
||
|
return "Host"
|
||
|
}
|
||
|
return "Mate"
|
||
|
}
|
||
|
|
||
|
return "Mate"
|
||
|
}
|
||
|
|
||
|
nextProfileType := getNextProfileType()
|
||
|
|
||
|
err := mySettings.SetSetting("ProfilePageProfileType", nextProfileType)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
return changeProfileTypeButton, nil
|
||
|
}
|
||
|
|
||
|
changeProfileTypeButtonOrText, err := getChangeProfileTypeButtonOrText()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
changeProfileTypeButtonWithIcon := getContainerCentered(container.NewGridWithRows(2, profileTypeIcon, changeProfileTypeButtonOrText))
|
||
|
|
||
|
getDescriptionSection := func()*fyne.Container{
|
||
|
|
||
|
description1 := getLabelCentered("Manage your " + myProfileType + " profile.")
|
||
|
|
||
|
if (myProfileType == "Mate"){
|
||
|
description2 := getLabelCentered("Start by building your profile.")
|
||
|
description3 := getLabelCentered("Broadcast your profile once it is ready.")
|
||
|
description4 := getLabelCentered("You must rebroadcast your profile whenever you make changes.")
|
||
|
|
||
|
descriptionSection := container.NewVBox(description1, description2, description3, description4)
|
||
|
return descriptionSection
|
||
|
}
|
||
|
if (myProfileType == "Moderator"){
|
||
|
|
||
|
description2 := getLabelCentered("Building your Moderator profile is optional.")
|
||
|
description3 := getLabelCentered("You must rebroadcast your profile whenever you make changes.")
|
||
|
|
||
|
descriptionSection := container.NewVBox(description1, description2, description3)
|
||
|
return descriptionSection
|
||
|
}
|
||
|
|
||
|
// myProfileType = "Host"
|
||
|
description2 := getLabelCentered("Building your Host profile is optional.")
|
||
|
description3 := getLabelCentered("Your Host profile will be broadcast automatically.")
|
||
|
|
||
|
descriptionSection := container.NewVBox(description1, description2, description3)
|
||
|
return descriptionSection
|
||
|
}
|
||
|
|
||
|
descriptionSection := getDescriptionSection()
|
||
|
|
||
|
buildProfileIcon, err := getFyneImageIcon("Check")
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
profileIcon, err := getFyneImageIcon("Profile")
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
broadcastIcon, err := getFyneImageIcon("Broadcast")
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
buildProfileButton := widget.NewButton("Build", func(){
|
||
|
if (myProfileType == "Mate"){
|
||
|
setBuildMyMateProfilePage(window, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (myProfileType == "Moderator"){
|
||
|
setBuildMyModeratorProfilePage(window, currentPage)
|
||
|
return
|
||
|
}
|
||
|
setBuildMyHostProfilePage(window, currentPage)
|
||
|
})
|
||
|
buildProfileButtonWithIcon := container.NewGridWithRows(2, buildProfileIcon, buildProfileButton)
|
||
|
|
||
|
broadcastButton := widget.NewButton(translate("Broadcast"), func(){
|
||
|
if (myProfileType == "Host"){
|
||
|
//TODO: Add a custom broadcast page for Host where you can monitor the last time it was broadcast and deactivate
|
||
|
showUnderConstructionDialog(window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setBroadcastPage(window, myProfileType, currentPage)
|
||
|
})
|
||
|
broadcastButtonWithIcon := container.NewGridWithRows(2, broadcastIcon, broadcastButton)
|
||
|
|
||
|
viewProfileButton := widget.NewButton(translate("View"), func(){
|
||
|
setViewMyLocalOrPublicProfilePage(window, myProfileType, currentPage)
|
||
|
})
|
||
|
viewProfileButtonWithIcon := container.NewGridWithRows(2, profileIcon, viewProfileButton)
|
||
|
|
||
|
actionsGrid := container.NewGridWithRows(1, buildProfileButtonWithIcon, broadcastButtonWithIcon, viewProfileButtonWithIcon)
|
||
|
actionsSection := getContainerCentered(actionsGrid)
|
||
|
|
||
|
page.Add(widget.NewSeparator())
|
||
|
page.Add(changeProfileTypeButtonWithIcon)
|
||
|
page.Add(widget.NewSeparator())
|
||
|
page.Add(descriptionSection)
|
||
|
page.Add(widget.NewSeparator())
|
||
|
page.Add(actionsSection)
|
||
|
|
||
|
if (myProfileType == "Moderator"){
|
||
|
|
||
|
page.Add(widget.NewSeparator())
|
||
|
|
||
|
scoreIcon, err := getFyneImageIcon("Score")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
myScoreButton := widget.NewButton("My Score", func(){
|
||
|
setViewMyModeratorScorePage(window, currentPage)
|
||
|
})
|
||
|
myScoreButtonWithIcon := container.NewGridWithColumns(1, scoreIcon, myScoreButton)
|
||
|
|
||
|
reviewsIcon, err := getFyneImageIcon("Choice")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
myReviewsButton := widget.NewButton("My Reviews", func(){
|
||
|
setViewMyReviewsPage(window, "Profile", currentPage)
|
||
|
})
|
||
|
myReviewsButtonWithIcon := container.NewGridWithColumns(1, reviewsIcon, myReviewsButton)
|
||
|
|
||
|
moderatorButtonsRow := getContainerCentered(container.NewGridWithRows(1, myScoreButtonWithIcon, myReviewsButtonWithIcon))
|
||
|
|
||
|
page.Add(moderatorButtonsRow)
|
||
|
page.Add(widget.NewSeparator())
|
||
|
}
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
// This is a page to view an identity hash in its entirety, and a text entry to copy it
|
||
|
func setViewIdentityHashPage(window fyne.Window, identityHash [16]byte, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered("Viewing Identity Hash")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
identityHashString, _, err := identity.EncodeIdentityHashBytesToString(identityHash)
|
||
|
if (err != nil){
|
||
|
identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
|
||
|
setErrorEncounteredPage(window, errors.New("setViewIdentityHashPage called with invalid identity hash: " + identityHashHex), previousPage)
|
||
|
}
|
||
|
|
||
|
identityHashLabel := getBoldLabel(identityHashString)
|
||
|
identityHashLabelPadded := container.NewPadded(container.NewPadded(identityHashLabel))
|
||
|
|
||
|
identityHashEntry := widget.NewMultiLineEntry()
|
||
|
identityHashEntry.SetText(identityHashString)
|
||
|
identityHashEntry.OnChanged = func(_ string){
|
||
|
identityHashEntry.SetText(identityHashString)
|
||
|
}
|
||
|
identityHashEntryBoxed := getWidgetBoxed(identityHashEntry)
|
||
|
|
||
|
widener := widget.NewLabel(" ")
|
||
|
identityHashEntryWidened := getContainerCentered(container.NewGridWithColumns(1, identityHashEntryBoxed, widener))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), identityHashLabelPadded, identityHashEntryWidened)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
// This is a page to view an message/profile hash in its entirety, and a text entry to copy it
|
||
|
func setViewContentHashPage(window fyne.Window, hashType string, contentHash []byte, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered("Viewing " + hashType + " Hash")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
contentHashHex := encoding.EncodeBytesToHexString(contentHash)
|
||
|
|
||
|
contentHashLabel := getBoldLabel(contentHashHex)
|
||
|
contentHashLabelPadded := container.NewPadded(container.NewPadded(contentHashLabel))
|
||
|
|
||
|
contentHashEntry := widget.NewMultiLineEntry()
|
||
|
contentHashEntry.SetText(contentHashHex)
|
||
|
contentHashEntry.OnChanged = func(_ string){
|
||
|
contentHashEntry.SetText(contentHashHex)
|
||
|
}
|
||
|
contentHashEntry.Wrapping = 3
|
||
|
|
||
|
contentHashEntryBoxed := getWidgetBoxed(contentHashEntry)
|
||
|
|
||
|
widener := widget.NewLabel(" ")
|
||
|
contentHashEntryWidened := getContainerCentered(container.NewGridWithColumns(1, contentHashEntryBoxed, widener))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), contentHashLabelPadded, contentHashEntryWidened)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
//TODO: Make this page able to handle large amounts of text without crashing
|
||
|
// In the meantime, trim text that is too long to render
|
||
|
func setViewTextPage(window fyne.Window, pageTitle string, textToView string, viewCopyable bool, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered(pageTitle)
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
header := container.NewVBox(title, backButton, widget.NewSeparator())
|
||
|
|
||
|
getTextViewWidget := func()fyne.Widget{
|
||
|
|
||
|
if (viewCopyable == true){
|
||
|
|
||
|
textEntry := widget.NewMultiLineEntry()
|
||
|
textEntry.SetText(textToView)
|
||
|
textEntry.OnChanged = func(_ string){
|
||
|
textEntry.SetText(textToView)
|
||
|
}
|
||
|
textEntry.Wrapping = 3
|
||
|
|
||
|
return textEntry
|
||
|
}
|
||
|
|
||
|
textViewWidget := widget.NewLabel(textToView)
|
||
|
textViewWidget.Wrapping = 3
|
||
|
textViewWidget.Alignment = 1
|
||
|
|
||
|
return textViewWidget
|
||
|
}
|
||
|
|
||
|
textViewWidget := getTextViewWidget()
|
||
|
|
||
|
getChangeDisplayTypeButton := func()fyne.Widget{
|
||
|
|
||
|
if (viewCopyable == false){
|
||
|
|
||
|
viewCopyableButton := widget.NewButtonWithIcon("View Copyable", theme.ContentPasteIcon(), func(){
|
||
|
setViewTextPage(window, pageTitle, textToView, true, previousPage)
|
||
|
})
|
||
|
return viewCopyableButton
|
||
|
}
|
||
|
viewUncopyableButton := widget.NewButtonWithIcon("View Uncopyable", theme.VisibilityIcon(), func(){
|
||
|
setViewTextPage(window, pageTitle, textToView, false, previousPage)
|
||
|
})
|
||
|
return viewUncopyableButton
|
||
|
}
|
||
|
|
||
|
changeDisplayTypeButton := getChangeDisplayTypeButton()
|
||
|
|
||
|
changeDisplayTypeButtonCentered := getWidgetCentered(changeDisplayTypeButton)
|
||
|
|
||
|
page := container.NewBorder(header, changeDisplayTypeButtonCentered, nil, nil, textViewWidget)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setViewLinkPage(window fyne.Window, pageTitle string, textToView string, previousPage func()){
|
||
|
|
||
|
title := getPageTitleCentered(pageTitle)
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
header := container.NewVBox(title, backButton, widget.NewSeparator())
|
||
|
|
||
|
textEntry := widget.NewMultiLineEntry()
|
||
|
textEntry.SetText(textToView)
|
||
|
textEntry.OnChanged = func(_ string){
|
||
|
textEntry.SetText(textToView)
|
||
|
}
|
||
|
textEntry.Wrapping = 3
|
||
|
|
||
|
page := container.NewBorder(header, nil, nil, nil, textEntry)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func getCryptocurrencyAddressLabelWithCopyAndQRButtons(window fyne.Window, cryptocurrency string, cryptoAddress string, currentPage func())(*fyne.Container, error){
|
||
|
|
||
|
if (cryptocurrency != "Ethereum" && cryptocurrency != "Cardano"){
|
||
|
return nil, errors.New("getCryptocurrencyAddressLabelWithCopyAndQRButtons called with invalid cryptocurrency: " + cryptocurrency)
|
||
|
}
|
||
|
|
||
|
addressLabel := widget.NewMultiLineEntry()
|
||
|
addressLabel.SetText(cryptoAddress)
|
||
|
addressLabel.OnChanged = func(_ string){
|
||
|
addressLabel.SetText(cryptoAddress)
|
||
|
}
|
||
|
addressBox := getWidgetBoxed(addressLabel)
|
||
|
|
||
|
qrCodeImage, err := getFyneImageIcon("QR")
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
qrCodeButton := widget.NewButton("QR Code", func(){
|
||
|
|
||
|
title := translate(cryptocurrency + " QR Code")
|
||
|
|
||
|
//TODO: Add QR Code generation
|
||
|
dialogMessage := getLabelCentered("Under Construction")
|
||
|
|
||
|
dialog.ShowCustom(title, translate("Close"), dialogMessage, window)
|
||
|
})
|
||
|
|
||
|
qrCodeButtonWithIcon := getContainerBoxed(container.NewGridWithColumns(1, qrCodeImage, qrCodeButton))
|
||
|
|
||
|
clipboardIcon, err := getFyneImageIcon("Clipboard")
|
||
|
if (err != nil){ return nil, err }
|
||
|
|
||
|
currentClipboard := window.Clipboard()
|
||
|
|
||
|
getClipboardButtonText := func()string{
|
||
|
|
||
|
currentContent := currentClipboard.Content()
|
||
|
if (currentContent == cryptoAddress){
|
||
|
return "Copied!"
|
||
|
}
|
||
|
return "Copy"
|
||
|
}
|
||
|
|
||
|
clipboardButtonText := getClipboardButtonText()
|
||
|
copyToClipboardButton := widget.NewButton(clipboardButtonText, func(){
|
||
|
|
||
|
currentClipboard.SetContent(cryptoAddress)
|
||
|
currentPage()
|
||
|
})
|
||
|
|
||
|
clipboardButtonWithIcon := getContainerBoxed(container.NewGridWithColumns(1, clipboardIcon, copyToClipboardButton))
|
||
|
|
||
|
addressBoxWithClipboardQRRow := getContainerCentered(container.NewGridWithRows(1, qrCodeButtonWithIcon, addressBox, clipboardButtonWithIcon))
|
||
|
|
||
|
return addressBoxWithClipboardQRRow, nil
|
||
|
}
|
||
|
|
||
|
|
||
|
// This function creates a widget list from an input list of strings
|
||
|
// The onClickedFunction is called if any of the items are selected
|
||
|
//Inputs:
|
||
|
// -[]string: A list of the items
|
||
|
// -func(itemIndex int): The function that is called when an item is selected
|
||
|
// Outputs:
|
||
|
// -fyne.Widget: Widget list
|
||
|
// -error
|
||
|
func getFyneWidgetListFromStringList(inputList []string, onClickedFunction func(int))(fyne.Widget, error){
|
||
|
|
||
|
listLength := len(inputList)
|
||
|
|
||
|
if (listLength == 0){
|
||
|
return nil, errors.New("getFyneWidgetListFromStringList called with empty list.")
|
||
|
}
|
||
|
|
||
|
getListLength := func()int{
|
||
|
return listLength
|
||
|
}
|
||
|
|
||
|
createListItemFunction := func()fyne.CanvasObject{
|
||
|
listItem := container.NewHBox(layout.NewSpacer(), widget.NewLabel(""), layout.NewSpacer())
|
||
|
return listItem
|
||
|
}
|
||
|
updateListItemFunction := func(id widget.ListItemID, item fyne.CanvasObject){
|
||
|
itemName := inputList[id]
|
||
|
|
||
|
itemObjectsList := item.(*fyne.Container).Objects
|
||
|
|
||
|
itemLabel := itemObjectsList[1].(*widget.Label)
|
||
|
|
||
|
itemLabel.SetText(itemName)
|
||
|
}
|
||
|
|
||
|
widgetList := widget.NewList(getListLength, createListItemFunction, updateListItemFunction)
|
||
|
|
||
|
widgetList.OnSelected = func(itemIndex widget.ListItemID) {
|
||
|
onClickedFunction(itemIndex)
|
||
|
}
|
||
|
|
||
|
return widgetList, nil
|
||
|
}
|
||
|
|
||
|
|