seekia/gui/buildProfileGui_Physical.go
2024-08-11 12:31:40 +00:00

3035 lines
106 KiB
Go

package gui
// buildProfileGui_Physical.go implements pages to build the Physical portion of a user's mate profile
import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/canvas"
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/geneticReferences/traits"
import "seekia/resources/geneticReferences/monogenicDiseases"
import "seekia/resources/geneticReferences/polygenicDiseases"
import "seekia/internal/allowedText"
import "seekia/internal/genetics/companyAnalysis"
import "seekia/internal/genetics/myChosenAnalysis"
import "seekia/internal/genetics/myGenomes"
import "seekia/internal/genetics/myPeople"
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "seekia/internal/profiles/myLocalProfiles"
import "slices"
import "strings"
import "errors"
func setBuildMateProfileCategoryPage_Physical(window fyne.Window, previousPage func()){
currentPage := func(){ setBuildMateProfileCategoryPage_Physical(window, previousPage) }
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
sexButton := widget.NewButton(translate("Sex"), func(){
setBuildMateProfilePage_Sex(window, currentPage)
})
ageButton := widget.NewButton(translate("Age"), func(){
setBuildMateProfilePage_Age(window, currentPage)
})
ancestryCompositionButton := widget.NewButton("Ancestry Composition", func(){
setBuildMateProfilePage_23andMe_AncestryComposition(window, currentPage)
})
neanderthalVariantsButton := widget.NewButton("Neanderthal Variants", func(){
setBuildMateProfilePage_23andMe_NeanderthalVariants(window, currentPage)
})
maternalHaplogroupButton := widget.NewButton("Maternal Haplogroup", func(){
setBuildMateProfilePage_23andMe_Haplogroup(window, "Maternal", currentPage)
})
paternalHaplogroupButton := widget.NewButton("Paternal Haplogroup", func(){
setBuildMateProfilePage_23andMe_Haplogroup(window, "Paternal", currentPage)
})
geneticInformationButton := widget.NewButton(translate("Genetic Information"), func(){
setBuildMateProfilePage_GeneticInformation(window, currentPage)
})
heightButton := widget.NewButton(translate("Height"), func(){
setBuildMateProfilePage_Height(window, currentPage)
})
bodyButton := widget.NewButton(translate("Body"), func(){
setBuildMateProfilePage_Body(window, currentPage)
})
eyeColorButton := widget.NewButton(translate("Eye Color"), func(){
setBuildMateProfilePage_EyeColor(window, currentPage)
})
hairColorButton := widget.NewButton(translate("Hair Color"), func(){
setBuildMateProfilePage_HairColor(window, currentPage)
})
hairTextureButton := widget.NewButton(translate("Hair Texture"), func(){
setBuildMateProfilePage_HairTexture(window, currentPage)
})
skinColorButton := widget.NewButton(translate("Skin Color"), func(){
setBuildMateProfilePage_SkinColor(window, currentPage)
})
infectionsButton := widget.NewButton(translate("Infections"), func(){
setBuildMateProfilePage_Infections(window, currentPage)
})
buttonsGrid := container.NewGridWithColumns(1, sexButton, ageButton, ancestryCompositionButton, neanderthalVariantsButton, maternalHaplogroupButton, paternalHaplogroupButton, geneticInformationButton, heightButton, bodyButton, eyeColorButton, hairColorButton, hairTextureButton, skinColorButton, infectionsButton)
buttonsGridCentered := getContainerCentered(buttonsGrid)
buttonsGridPadded := container.NewPadded(buttonsGridCentered)
page := container.NewVBox(title, backButton, widget.NewSeparator(), buttonsGridPadded)
setPageContent(page, window)
}
func setBuildMateProfilePage_Sex(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_Sex(window, previousPage)}
pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Sex"))
sexDescription := widget.NewLabel(translate("What is your physical sex?"))
sexHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setSexExplainerPage(window, currentPage)
})
sexDescriptionRow := container.NewHBox(layout.NewSpacer(), sexDescription, sexHelpButton, layout.NewSpacer())
option1Translated := translate("Male")
option2Translated := translate("Female")
option3Translated := translate("Intersex Male")
option4Translated := translate("Intersex Female")
option5Translated := translate("Intersex")
untranslatedOptionsMap := map[string]string{
option1Translated: "Male",
option2Translated: "Female",
option3Translated: "Intersex Male",
option4Translated: "Intersex Female",
option5Translated: "Intersex",
}
sexSelectorOptions := []string{option1Translated, option2Translated, option3Translated, option4Translated, option5Translated}
sexSelector := widget.NewRadioGroup(sexSelectorOptions, func(response string){
if (response == ""){
err := myLocalProfiles.DeleteProfileData("Mate", "Sex")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
return
}
responseUntranslated, exists := untranslatedOptionsMap[response]
if (exists == false){
setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing response: " + response), currentPage)
return
}
err := myLocalProfiles.SetProfileData("Mate", "Sex", responseUntranslated)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
})
exists, currentSex, err := myLocalProfiles.GetProfileData("Mate", "Sex")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (exists == true){
if (currentSex != "Male" && currentSex != "Female" && currentSex != "Intersex Male" && currentSex != "Intersex Female" && currentSex != "Intersex"){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid Sex: " + currentSex), previousPage)
return
}
sexSelector.Selected = translate(currentSex)
}
sexSelectorCentered := getWidgetCentered(sexSelector)
sexNoResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "Sex")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), sexDescriptionRow, sexSelectorCentered, sexNoResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_AncestryComposition(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_23andMe_AncestryComposition(window, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("23andMe Ancestry Composition")
description := getLabelCentered("Enter your 23andMe ancestry location composition.")
exists, myAncestryCompositionAttribute, err := myLocalProfiles.GetProfileData("Mate", "23andMe_AncestryComposition")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (exists == false){
noCompositionFoundLabel := getBoldLabelCentered("No ancestry composition exists.")
addCompositionButton := getWidgetCentered(widget.NewButtonWithIcon("Add Composition", theme.ContentAddIcon(), func(){
emptyMapA := make(map[string]float64)
emptyMapB := make(map[string]float64)
emptyMapC := make(map[string]float64)
setBuildMateProfilePage_23andMe_EditAncestryComposition(window, emptyMapA, emptyMapB, emptyMapC, currentPage, currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), noCompositionFoundLabel, addCompositionButton)
setPageContent(page, window)
return
}
visibilityLabel := getBoldLabel("Visibility:")
visibilityOptions := []string{translate("Show On Profile"), translate("Hide From Profile")}
visibilitySelector := widget.NewSelect(visibilityOptions, func(newVisibility string){
getNewVisibilityStatus := func()string{
if (newVisibility == translate("Show On Profile")){
return "Yes"
}
return "No"
}
newVisibilityStatus := getNewVisibilityStatus()
err := myLocalProfiles.SetProfileData("Mate", "VisibilityStatus_23andMe_AncestryComposition", newVisibilityStatus)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
})
exists, visibilityStatus, err := myLocalProfiles.GetProfileData("Mate", "VisibilityStatus_23andMe_AncestryComposition")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (exists == true && visibilityStatus == "No"){
visibilitySelector.Selected = translate("Hide From Profile")
} else {
visibilitySelector.Selected = translate("Show On Profile")
}
profileVisibilityHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setMateProfileAttributeVisibilityExplainerPage(window, currentPage)
})
visibilitySelectorRow := container.NewHBox(layout.NewSpacer(), visibilityLabel, visibilitySelector, profileVisibilityHelpButton, layout.NewSpacer())
attributeIsValid, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, err := companyAnalysis.ReadAncestryCompositionAttribute_23andMe(true, myAncestryCompositionAttribute)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
if (attributeIsValid == false){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles 23andMe ancestry composition attribute is invalid."), currentPage)
return
}
editCompositionButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), func(){
setBuildMateProfilePage_23andMe_EditAncestryComposition(window, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, currentPage, currentPage)
})
noResponseButton := widget.NewButtonWithIcon("No Response", theme.CancelIcon(), func(){
setBuildMateProfilePage_23andMe_ConfirmDeleteAncestryComposition(window, currentPage, currentPage)
})
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, editCompositionButton, noResponseButton))
myCompositionLabel := getBoldLabelCentered("My Composition:")
myCompositionDisplay, err := get23andMeAncestryCompositionDisplay(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
header := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), visibilitySelectorRow, widget.NewSeparator(), buttonsGrid, widget.NewSeparator(), myCompositionLabel)
page := container.NewBorder(header, nil, nil, nil, myCompositionDisplay)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_ConfirmDeleteAncestryComposition(window fyne.Window, previousPage func(), nextPage func()){
currentPage := func(){setBuildMateProfilePage_23andMe_ConfirmDeleteAncestryComposition(window, previousPage, nextPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
description1 := getBoldLabelCentered("Delete Ancestry Composition?")
description2 := getLabelCentered("Confirm to delete your 23andMe ancestry composition?")
confirmButton := getWidgetCentered(widget.NewButtonWithIcon("Confirm", theme.ConfirmIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "23andMe_AncestryComposition")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
nextPage()
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, confirmButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_EditAncestryComposition(window fyne.Window, myContinentPercentagesMap map[string]float64, myRegionPercentagesMap map[string]float64, mySubregionPercentagesMap map[string]float64, previousPage func(), afterCompletePage func()){
currentPage := func(){setBuildMateProfilePage_23andMe_EditAncestryComposition(window, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, afterCompletePage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButtonFunction := func(){
confirmDialogCallbackFunction := func(response bool){
if (response == true){
previousPage()
}
}
dialogTitle := translate("Confirm Go Back")
dialogMessageA := getLabelCentered("Confirm to go back?")
dialogMessageB := getLabelCentered("You will lose any changes you made.")
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
}
backButton := getBackButtonCentered(backButtonFunction)
subtitle := getPageSubtitleCentered("Build 23andMe Ancestry Composition")
// We use this function to make changes and return to this page
currentPageWithNewPercentagesFunction := func(newContinentPercentagesMap map[string]float64, newRegionPercentagesMap map[string]float64, newSubregionPercentagesMap map[string]float64){
setBuildMateProfilePage_23andMe_EditAncestryComposition(window, newContinentPercentagesMap, newRegionPercentagesMap, newSubregionPercentagesMap, previousPage, afterCompletePage)
}
addLocationButton := widget.NewButtonWithIcon("Add Location", theme.ContentAddIcon(), func(){
setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, false, "", false, "", false, "", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, currentPage, currentPageWithNewPercentagesFunction)
})
if (len(myContinentPercentagesMap) == 0 && len(myRegionPercentagesMap) == 0 && len(mySubregionPercentagesMap) == 0){
addLocationButtonCentered := getWidgetCentered(addLocationButton)
noCompositionExistsLabel := getBoldLabelCentered("No locations added.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), addLocationButtonCentered, widget.NewSeparator(), noCompositionExistsLabel)
setPageContent(page, window)
return
}
deleteLocationButton := widget.NewButtonWithIcon("Delete Location", theme.DeleteIcon(), func(){
setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation(window, "Continent", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, currentPage, currentPageWithNewPercentagesFunction)
})
addAndDeleteLocationButtons := getContainerCentered(container.NewGridWithRows(1, addLocationButton, deleteLocationButton))
submitButton := getWidgetCentered(widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
inputsAreValid, newAncestryCompositionAttribute, err := companyAnalysis.CreateAncestryCompositionAttribute_23andMe(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
if (inputsAreValid == false){
dialogTitle := translate("Invalid Ancestry Composition")
dialogMessageA := getBoldLabelCentered(translate("The ancestry composition you entered is invalid."))
dialogMessageB := getLabelCentered(translate("All continent percentages must add to 100."))
dialogMessageC := getLabelCentered(translate("All region percentages must add up to their continent percentage."))
dialogMessageD := getLabelCentered(translate("All subregion percentages must add up to their region percentage."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC, dialogMessageD)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
setBuildMateProfilePage_23andMe_ConfirmUpdateAncestryComposition(window, newAncestryCompositionAttribute, currentPage, afterCompletePage)
}))
emptyLabel := widget.NewLabel("")
footer := container.NewVBox(widget.NewSeparator(), submitButton, emptyLabel)
myCompositionTree, err := get23andMeAncestryCompositionDisplay(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
header := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), addAndDeleteLocationButtons, widget.NewSeparator())
page := container.NewBorder(header, footer, nil, nil, myCompositionTree)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_ConfirmUpdateAncestryComposition(window fyne.Window, newAncestryCompositionAttribute string, previousPage func(), nextPage func()){
currentPage := func(){setBuildMateProfilePage_23andMe_ConfirmUpdateAncestryComposition(window, newAncestryCompositionAttribute, previousPage, nextPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
description1 := getBoldLabelCentered("Add Ancestry Composition?")
description2 := getLabelCentered("Confirm update your ancestry composition?")
description3 := getLabelCentered("This will be visible on your profile.")
confirmButton := getWidgetCentered(widget.NewButtonWithIcon("Confirm", theme.ConfirmIcon(), func(){
err := myLocalProfiles.SetProfileData("Mate", "23andMe_AncestryComposition", newAncestryCompositionAttribute)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
nextPage()
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, confirmButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(
window fyne.Window,
continentProvided bool,
currentContinent string,
regionProvided bool,
currentRegion string,
subregionProvided bool,
currentSubregion string,
myContinentPercentagesMap map[string]float64,
myRegionPercentagesMap map[string]float64,
mySubregionPercentagesMap map[string]float64,
previousPage func(),
nextPage func(map[string]float64, map[string]float64, map[string]float64)){
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Add 23andMe Ancestry Location")
getPageContent := func()(*fyne.Container, error){
continentLabel := getBoldLabel("Continent:")
allContinentsList := companyAnalysis.GetAncestryContinentsList_23andMe()
handleContinentSelectFunction := func(newContinent string){
if (continentProvided == true && newContinent == currentContinent){
return
}
setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, true, newContinent, false, "", false, "", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
}
continentSelector := widget.NewSelect(allContinentsList, handleContinentSelectFunction)
if (continentProvided == true){
continentSelector.Selected = currentContinent
}
continentRow := container.NewHBox(layout.NewSpacer(), continentLabel, continentSelector, layout.NewSpacer())
if (continentProvided == false){
pageContent := container.NewVBox(continentRow)
return pageContent, nil
}
percentageLabel := getBoldLabelCentered("Percentage:")
percentageEntry := widget.NewEntry()
percentageEntry.SetPlaceHolder("Enter percentage.")
percentageRow := getContainerCentered(container.NewGridWithRows(1, percentageLabel, percentageEntry))
showInvalidPercentageDialog := func(){
dialogTitle := translate("Invalid Percentage")
dialogMessageA := getLabelCentered(translate("The location percentage is invalid."))
dialogMessageB := getLabelCentered(translate("You must enter a number between 0 and 100."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
}
regionsList, err := companyAnalysis.GetAncestryContinentRegionsList_23andMe(currentContinent)
if (err != nil) { return nil, err }
if (len(regionsList) == 0){
submitButton := getWidgetCentered(widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
newPercentageRaw := percentageEntry.Text
newPercentage := strings.TrimSuffix(newPercentageRaw, "%")
newPercentageFloat64, err := helpers.ConvertStringToFloat64(newPercentage)
if (err != nil){
showInvalidPercentageDialog()
return
}
if (newPercentageFloat64 <= 0 || newPercentageFloat64 > 100){
showInvalidPercentageDialog()
return
}
addContinentFunction := func(){
myContinentPercentagesMap[currentContinent] = newPercentageFloat64
nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
}
existingPercentage, exists := myContinentPercentagesMap[currentContinent]
if (exists == false){
addContinentFunction()
return
}
// We allow user to confirm they want to overwrite existing value
currentPercentageString := helpers.ConvertFloat64ToStringRounded(existingPercentage, 1)
confirmDialogCallbackFunction := func(response bool){
if (response == true){
addContinentFunction()
}
}
dialogTitle := translate("Confirm Overwrite Existing")
dialogMessageA := getLabelCentered("You already have a percentage for " + currentContinent)
dialogMessageB := getLabelCentered("Current Percentage: " + currentPercentageString + "%")
dialogMessageC := getLabelCentered("Confirm to overwrite this percentage?")
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
}))
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), percentageRow, submitButton)
return pageContent, nil
}
regionLabel := getBoldLabel("Region:")
handleRegionSelectFunction := func(newRegion string){
if (regionProvided == true && currentRegion == newRegion){
return
}
setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, true, currentContinent, true, newRegion, false, "", myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
}
regionSelector := widget.NewSelect(regionsList, handleRegionSelectFunction)
if (regionProvided == true){
regionSelector.Selected = currentRegion
}
regionRow := container.NewHBox(layout.NewSpacer(), regionLabel, regionSelector, layout.NewSpacer())
if (regionProvided == false){
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow)
return pageContent, nil
}
subregionsList, err := companyAnalysis.GetAncestryRegionSubregionsList_23andMe(currentContinent, currentRegion)
if (err != nil) { return nil, err }
if (len(subregionsList) == 0){
submitButton := getWidgetCentered(widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
newPercentageRaw := percentageEntry.Text
newPercentage := strings.TrimSuffix(newPercentageRaw, "%")
newPercentageFloat64, err := helpers.ConvertStringToFloat64(newPercentage)
if (err != nil){
showInvalidPercentageDialog()
return
}
if (newPercentageFloat64 <= 0 || newPercentageFloat64 > 100){
showInvalidPercentageDialog()
return
}
addRegionFunction := func(){
myRegionPercentagesMap[currentRegion] = newPercentageFloat64
nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
}
existingPercentage, exists := myRegionPercentagesMap[currentRegion]
if (exists == false){
addRegionFunction()
return
}
// We allow user to confirm they want to overwrite existing value
currentPercentageString := helpers.ConvertFloat64ToStringRounded(existingPercentage, 1)
confirmDialogCallbackFunction := func(response bool){
if (response == true){
addRegionFunction()
}
}
dialogTitle := translate("Confirm Overwrite Existing")
dialogMessageA := getLabelCentered("You already have a percentage for " + currentRegion)
dialogMessageB := getLabelCentered("Current Percentage: " + currentPercentageString + "%")
dialogMessageC := getLabelCentered("Confirm to overwrite this percentage?")
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
}))
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow, widget.NewSeparator(), percentageRow, submitButton)
return pageContent, nil
}
subregionLabel := getBoldLabel("Subregion:")
handleSubregionSelectFunction := func(newSubregion string){
if (subregionProvided == true && currentSubregion == newSubregion){
return
}
setBuildMateProfilePage_23andMe_AncestryComposition_AddLocation(window, true, currentContinent, true, currentRegion, true, newSubregion, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
}
subregionSelector := widget.NewSelect(subregionsList, handleSubregionSelectFunction)
if (subregionProvided == true){
subregionSelector.Selected = currentSubregion
}
subregionRow := container.NewHBox(layout.NewSpacer(), subregionLabel, subregionSelector, layout.NewSpacer())
submitButton := getWidgetCentered(widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
if (subregionProvided == false){
dialogTitle := translate("Missing Subregion")
dialogMessage := getLabelCentered(translate("You must select a subregion."))
dialogContent := container.NewVBox(dialogMessage)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
newPercentageRaw := percentageEntry.Text
newPercentage := strings.TrimSuffix(newPercentageRaw, "%")
newPercentageFloat64, err := helpers.ConvertStringToFloat64(newPercentage)
if (err != nil){
showInvalidPercentageDialog()
return
}
if (newPercentageFloat64 <= 0 || newPercentageFloat64 > 100){
showInvalidPercentageDialog()
return
}
addSubregionFunction := func(){
mySubregionPercentagesMap[currentSubregion] = newPercentageFloat64
nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
}
existingPercentage, exists := mySubregionPercentagesMap[currentSubregion]
if (exists == false){
addSubregionFunction()
return
}
// We allow user to confirm they want to overwrite existing value
currentPercentageString := helpers.ConvertFloat64ToStringRounded(existingPercentage, 1)
confirmDialogCallbackFunction := func(response bool){
if (response == true){
addSubregionFunction()
}
}
dialogTitle := translate("Confirm Overwrite Existing")
dialogMessageA := getLabelCentered("You already have a percentage for " + currentSubregion)
dialogMessageB := getLabelCentered("Current Percentage: " + currentPercentageString + "%")
dialogMessageC := getLabelCentered("Confirm to overwrite this percentage?")
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
dialog.ShowCustomConfirm(dialogTitle, translate("Yes"), translate("No"), dialogContent, confirmDialogCallbackFunction, window)
}))
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow, widget.NewSeparator(), subregionRow, widget.NewSeparator(), percentageRow, submitButton)
return pageContent, nil
}
pageContent, err := getPageContent()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), pageContent)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation(
window fyne.Window,
locationType string,
myContinentPercentagesMap map[string]float64,
myRegionPercentagesMap map[string]float64,
mySubregionPercentagesMap map[string]float64,
previousPage func(),
nextPage func(map[string]float64, map[string]float64, map[string]float64)){
if (locationType != "Continent" && locationType != "Region" && locationType != "Subregion"){
setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation called with invalid locationType: " + locationType), previousPage)
return
}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
description := getLabelCentered("Select a location to delete.")
locationTypeLabel := getBoldLabelCentered("Location Type")
locationTypesList := []string{"Continent", "Region", "Subregion"}
handleLocationTypeSelectFunction := func(newLocationType string){
if (newLocationType == locationType){
return
}
setBuildMateProfilePage_23andMe_AncestryComposition_DeleteLocation(window, newLocationType, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, previousPage, nextPage)
}
locationTypeSelector := widget.NewSelect(locationTypesList, handleLocationTypeSelectFunction)
locationTypeSelector.Selected = locationType
locationTypeSelectorCentered := getWidgetCentered(locationTypeSelector)
// This function either returns a "No (locationType) Exists" label or the locations grid.
getLocationsSection := func()(*fyne.Container, error){
if (locationType == "Continent" && len(myContinentPercentagesMap) == 0){
locationsSection := getBoldLabelCentered("No continents exist.")
return locationsSection, nil
}
if (locationType == "Region" && len(myRegionPercentagesMap) == 0){
locationsSection := getBoldLabelCentered("No regions exist.")
return locationsSection, nil
}
if (locationType == "Subregion" && len(mySubregionPercentagesMap) == 0){
locationsSection := getBoldLabelCentered("No subregions exist.")
return locationsSection, nil
}
locationLabel := getItalicLabelCentered(locationType)
percentageLabel := getItalicLabelCentered("Percentage")
emptyLabel := widget.NewLabel("")
locationNameColumn := container.NewVBox(locationLabel, widget.NewSeparator())
locationPercentageColumn := container.NewVBox(percentageLabel, widget.NewSeparator())
deleteButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator())
addLocationRow := func(locationName string, locationPercentage float64)error{
locationNameLabel := getBoldLabelCentered(locationName)
locationPercentageString := helpers.ConvertFloat64ToStringRounded(locationPercentage, 1)
locationPercentageFormatted := locationPercentageString + "%"
locationPercentageLabel := getBoldLabelCentered(locationPercentageFormatted)
deleteLocationButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){
if (locationType == "Continent"){
delete(myContinentPercentagesMap, locationName)
} else if (locationType == "Region"){
delete(myRegionPercentagesMap, locationName)
} else if (locationType == "Subregion") {
delete(mySubregionPercentagesMap, locationName)
}
nextPage(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
})
locationNameColumn.Add(locationNameLabel)
locationPercentageColumn.Add(locationPercentageLabel)
deleteButtonsColumn.Add(deleteLocationButton)
locationNameColumn.Add(widget.NewSeparator())
locationPercentageColumn.Add(widget.NewSeparator())
deleteButtonsColumn.Add(widget.NewSeparator())
return nil
}
if (locationType == "Continent"){
for continentName, continentPercentage := range myContinentPercentagesMap{
err := addLocationRow(continentName, continentPercentage)
if (err != nil){ return nil, err }
}
} else if (locationType == "Region"){
for regionName, regionPercentage := range myRegionPercentagesMap{
err := addLocationRow(regionName, regionPercentage)
if (err != nil){ return nil, err }
}
} else if (locationType == "Subregion"){
for subregionName, subregionPercentage := range mySubregionPercentagesMap{
err := addLocationRow(subregionName, subregionPercentage)
if (err != nil){ return nil, err }
}
}
locationsGrid := container.NewHBox(layout.NewSpacer(), locationNameColumn, locationPercentageColumn, deleteButtonsColumn, layout.NewSpacer())
return locationsGrid, nil
}
locationsSection, err := getLocationsSection()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), locationTypeLabel, locationTypeSelectorCentered, widget.NewSeparator(), locationsSection)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_NeanderthalVariants(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_23andMe_NeanderthalVariants(window, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("23andMe - Neanderthal Variants"))
description := getLabelCentered(translate("Enter how many neanderthal variants you have."))
neanderthalVariantsEntry := widget.NewEntry()
variantCountExists, currentNeanderthalVariants, err := myLocalProfiles.GetProfileData("Mate", "23andMe_NeanderthalVariants")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (variantCountExists == true){
isValid, err := helpers.VerifyStringIsIntWithinRange(currentNeanderthalVariants, 0, 7462)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (isValid == false){
setErrorEncounteredPage(window, errors.New("MyLocalProfile contains invalid 23andMe neanderthalvariants."), previousPage)
return
}
neanderthalVariantsEntry.SetText(currentNeanderthalVariants)
} else {
neanderthalVariantsEntry.SetPlaceHolder(translate("Enter Variant Count"))
}
getCurrentNeanderthalVariantsCountLabel := func()fyne.Widget{
if (variantCountExists == false){
result := translate("No Response")
variantsLabel := getBoldItalicLabel(result)
return variantsLabel
}
variantsLabel := getBoldLabel(currentNeanderthalVariants)
return variantsLabel
}
currentVariantCountLabel := getCurrentNeanderthalVariantsCountLabel()
myVariantCountLabel := widget.NewLabel("My Variant Count:")
currentVariantsCountRow := container.NewHBox(layout.NewSpacer(), myVariantCountLabel, currentVariantCountLabel, layout.NewSpacer())
submitChangesButton := widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
newVariantsCount := neanderthalVariantsEntry.Text
isValid, err := helpers.VerifyStringIsIntWithinRange(newVariantsCount, 0, 7462)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
if (isValid == false){
neanderthalVariantsEntry.SetText("")
neanderthalVariantsEntry.SetPlaceHolder(translate("Enter Variant Count"))
dialogTitle := translate("Invalid Variant Count")
dialogMessageA := getLabelCentered(translate("Invalid neanderthal variants count entered."))
dialogMessageB := getLabelCentered(translate("You must provide a number between 0 and 7462 variants."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
err = myLocalProfiles.SetProfileData("Mate", "23andMe_NeanderthalVariants", newVariantsCount)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
variantsEntryWithSubmitButton := getContainerCentered(container.NewGridWithRows(1, neanderthalVariantsEntry, submitChangesButton))
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "23andMe_NeanderthalVariants")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description, widget.NewSeparator(), currentVariantsCountRow, widget.NewSeparator(), variantsEntryWithSubmitButton, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_23andMe_Haplogroup(window fyne.Window, maternalOrPaternal string, previousPage func()){
if (maternalOrPaternal != "Maternal" && maternalOrPaternal != "Paternal"){
setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_23andMe_Haplogroup called with invalid maternalOrPaternal: " + maternalOrPaternal), previousPage)
return
}
currentPage := func(){setBuildMateProfilePage_23andMe_Haplogroup(window, maternalOrPaternal, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("23andMe - " + maternalOrPaternal + " Haplogroup"))
maternalOrPaternalLowercase := strings.ToLower(maternalOrPaternal)
description1 := getLabelCentered("Choose your " + maternalOrPaternalLowercase + " haplogroup.")
description2 := getLabelCentered("If it is not listed, enter it in manually.")
getKnownHaplogroupsList := func()[]string{
if (maternalOrPaternal == "Maternal"){
maternalHaplogroupsList := companyAnalysis.GetKnownMaternalHaplogroupsList_23andMe()
return maternalHaplogroupsList
}
paternalHaplogroupsList := companyAnalysis.GetKnownPaternalHaplogroupsList_23andMe()
return paternalHaplogroupsList
}
knownHaplogroupsList := getKnownHaplogroupsList()
haplogroupEntry := widget.NewSelectEntry(knownHaplogroupsList)
attributeName := "23andMe_" + maternalOrPaternal + "Haplogroup"
haplogroupExists, currentHaplogroup, err := myLocalProfiles.GetProfileData("Mate", attributeName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (haplogroupExists == true){
if (len(currentHaplogroup) > 25){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid haplogroup: " + currentHaplogroup), previousPage)
return
}
haplogroupEntry.SetText(currentHaplogroup)
} else {
haplogroupEntry.SetPlaceHolder(translate("Select or enter haplogroup..."))
}
getCurrentHaplogroupLabel := func()fyne.Widget{
if (haplogroupExists == false){
result := translate("No Response")
haplogroupLabel := getBoldItalicLabel(result)
return haplogroupLabel
}
haplogroupLabel := getBoldLabel(currentHaplogroup)
return haplogroupLabel
}
currentHaplogroupLabel := getCurrentHaplogroupLabel()
myHaplogroupLabel := widget.NewLabel("My " + maternalOrPaternal + " Haplogroup:")
currentHaplogroupRow := container.NewHBox(layout.NewSpacer(), myHaplogroupLabel, currentHaplogroupLabel, layout.NewSpacer())
submitChangesButton := widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
newHaplogroup := haplogroupEntry.Text
if (newHaplogroup == ""){
title := translate("Invalid Haplogroup")
dialogMessageA := getLabelCentered(translate("Invalid haplogroup entered."))
dialogMessageB := getLabelCentered(translate("Your haplogroup cannot be empty."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
if (len(newHaplogroup) > 25){
haplogroupEntry.SetText("")
haplogroupEntry.SetPlaceHolder(translate("Select or enter haplogroup..."))
title := translate("Invalid Haplogroup")
dialogMessageA := getLabelCentered(translate("Invalid haplogroup entered."))
dialogMessageB := getLabelCentered(translate("It must be less than 25 bytes."))
dialogMessageC := getLabelCentered(translate("Contact the Seekia developers if this is too short to fit your haplogroup."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
isAllowed := allowedText.VerifyStringIsAllowed(newHaplogroup)
if (isAllowed == false){
title := translate("Invalid Haplogroup")
dialogMessageA := getLabelCentered(translate("Your haplogroup contains an invalid character."))
dialogMessageB := getLabelCentered(translate("It must be encoded in UTF-8."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
containsTabsOrNewlines := helpers.CheckIfStringContainsTabsOrNewlines(newHaplogroup)
if (containsTabsOrNewlines == true){
title := translate("Invalid Haplogroup")
dialogMessageA := getLabelCentered(translate("Your haplogroup contains a tab or a newline."))
dialogMessageB := getLabelCentered(translate("Remove the character and resubmit."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
err := myLocalProfiles.SetProfileData("Mate", attributeName, newHaplogroup)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
haplogroupEntryWithSubmitButton := getContainerCentered(container.NewGridWithRows(1, haplogroupEntry, submitChangesButton))
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", attributeName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentHaplogroupRow, widget.NewSeparator(), haplogroupEntryWithSubmitButton, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_Age(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_Age(window, previousPage)}
pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Age"))
description1 := getLabelCentered(translate("Enter your age. You must be at least 18."))
description2 := getLabelCentered(translate("You should update your age as you get older."))
ageEntry := widget.NewEntry()
ageExists, currentAge, err := myLocalProfiles.GetProfileData("Mate", "Age")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (ageExists == true){
isValid, err := helpers.VerifyStringIsIntWithinRange(currentAge, 18, 150)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (isValid == false){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid age."), previousPage)
return
}
ageEntry.SetText(currentAge)
} else {
ageEntry.SetPlaceHolder(translate("Enter Age"))
}
getCurrentAgeLabel := func()fyne.Widget{
if (ageExists == false){
result := translate("No Response")
ageLabel := getBoldItalicLabel(result)
return ageLabel
}
ageLabel := getBoldLabel(currentAge)
return ageLabel
}
currentAgeLabel := getCurrentAgeLabel()
myAgeLabel := widget.NewLabel("My Age:")
currentAgeRow := container.NewHBox(layout.NewSpacer(), myAgeLabel, currentAgeLabel, layout.NewSpacer())
submitChangesButton := widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
newAge := ageEntry.Text
isValid, err := helpers.VerifyStringIsIntWithinRange(newAge, 18, 150)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
if (isValid == false){
ageEntry.SetText("")
ageEntry.SetPlaceHolder(translate("Enter Age"))
title := translate("Invalid Age")
dialogMessageA := getLabelCentered(translate("Invalid age entered."))
dialogMessageB := getLabelCentered(translate("You must be at least 18 to use Seekia."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
err = myLocalProfiles.SetProfileData("Mate", "Age", newAge)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
ageEntryWithSubmitButton := getContainerCentered(container.NewGridWithRows(1, ageEntry, submitChangesButton))
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "Age")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentAgeRow, widget.NewSeparator(), ageEntryWithSubmitButton, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_GeneticInformation(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_GeneticInformation(window, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered(translate("Genetic Information"))
description1 := widget.NewLabel("You can display your genetic information on your profile.")
shareGeneticInfoHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setProfileGenomeInfoExplainerPage(window, currentPage)
})
description1Row := container.NewHBox(layout.NewSpacer(), description1, shareGeneticInfoHelpButton, layout.NewSpacer())
description2 := getLabelCentered("You must link your genome person to your profile.")
description3 := getLabelCentered("You can hide some or all of your genetic information.")
myGenomePersonIdentifierExists, myGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (myGenomePersonIdentifierExists == true){
personFound, _, _, _, err := myPeople.GetPersonInfo(myGenomePersonIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (personFound == false){
// Genome person was deleted
// We will delete the missing person and refresh the page
// We show a loading screen so the user can tell if this wrongfully keeps happening
setLoadingScreen(window, "Build Mate Profile - Physical", "Deleting old genome person identifier...")
err := myLocalProfiles.DeleteProfileData("Mate", "GenomePersonIdentifier")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentPage()
return
}
}
myPersonLabel := widget.NewLabel("My Person:")
getCurrentPersonNameLabel := func()(fyne.Widget, error){
if (myGenomePersonIdentifierExists == false){
noneLabel := getBoldItalicLabel(translate("None"))
return noneLabel, nil
}
personFound, personName, _, _, err := myPeople.GetPersonInfo(myGenomePersonIdentifier)
if (err != nil){ return nil, err }
if (personFound == false){
return nil, errors.New("Genome person not found after being found already.")
}
personNameLabel := getBoldLabel(personName)
return personNameLabel, nil
}
currentPersonNameLabel, err := getCurrentPersonNameLabel()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentPersonNameRow := container.NewHBox(layout.NewSpacer(), myPersonLabel, currentPersonNameLabel, layout.NewSpacer())
getChooseOrChangeButtonTextAndIcon := func()(string, fyne.Resource){
if (myGenomePersonIdentifierExists == false){
result := translate("Choose Person")
return result, theme.NavigateNextIcon()
}
result := translate("Change Person")
return result, theme.DocumentCreateIcon()
}
chooseOrChangeButtonText, chooseOrChangeButtonIcon := getChooseOrChangeButtonTextAndIcon()
chooseOrChangePersonButton := getWidgetCentered(widget.NewButtonWithIcon(chooseOrChangeButtonText, chooseOrChangeButtonIcon, func(){
setBuildMateProfilePage_EditGenomePerson(window, currentPage, currentPage)
}))
if (myGenomePersonIdentifierExists == false){
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1Row, description2, description3, widget.NewSeparator(), currentPersonNameRow, chooseOrChangePersonButton)
setPageContent(page, window)
return
}
currentlySharingLabel := getItalicLabelCentered("Currently Sharing:")
//Outputs:
// -int: Total number of monogenic diseases
// -int: Number of monogenic diseases being shared
// -error
getNumberOfMonogenicDiseasesBeingSharedInfo := func()(int, int, error){
monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
if (err != nil) { return 0, 0, err }
totalMonogenicDiseases := len(monogenicDiseaseNamesList)
totalMonogenicDiseasesBeingShared := 0
for _, diseaseName := range monogenicDiseaseNamesList{
shareDiseaseInfoAttributeName := "ShareMonogenicDiseaseInfo_" + diseaseName
currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", shareDiseaseInfoAttributeName)
if (err != nil){ return 0, 0, err }
if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
totalMonogenicDiseasesBeingShared += 1
}
}
return totalMonogenicDiseases, totalMonogenicDiseasesBeingShared, nil
}
//Outputs:
// -int: Total number of polygenic diseases
// -int: Number of polygenic diseases being shared
// -error
getNumberOfPolygenicDiseasesBeingSharedInfo := func()(int, int, error){
polygenicDiseaseNamesList, err := polygenicDiseases.GetPolygenicDiseaseNamesList()
if (err != nil) { return 0, 0, err }
totalPolygenicDiseases := len(polygenicDiseaseNamesList)
totalPolygenicDiseasesBeingShared := 0
for _, diseaseName := range polygenicDiseaseNamesList{
sharePolygenicDiseaseInfoAttributeName := "SharePolygenicDiseaseInfo_" + diseaseName
currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", sharePolygenicDiseaseInfoAttributeName)
if (err != nil){ return 0, 0, err }
if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
totalPolygenicDiseasesBeingShared += 1
}
}
return totalPolygenicDiseases, totalPolygenicDiseasesBeingShared, nil
}
//Outputs:
// -int: Total number of traits
// -int: Number of traits being shared
// -error
getNumberOfTraitsBeingSharedInfo := func()(int, int, error){
traitNamesList, err := traits.GetTraitNamesList()
if (err != nil) { return 0, 0, err }
totalTraits := len(traitNamesList)
totalTraitsBeingShared := 0
for _, traitName := range traitNamesList{
shareTraitInfoAttributeName := "ShareTraitInfo_" + traitName
currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", shareTraitInfoAttributeName)
if (err != nil){ return 0, 0, err }
if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
totalTraitsBeingShared += 1
}
}
return totalTraits, totalTraitsBeingShared, nil
}
totalMonogenicDiseases, numberOfMonogenicDiseasesBeingShared, err := getNumberOfMonogenicDiseasesBeingSharedInfo()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
totalPolygenicDiseases, numberOfPolygenicDiseasesBeingShared, err := getNumberOfPolygenicDiseasesBeingSharedInfo()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
totalTraits, numberOfTraitsBeingShared, err := getNumberOfTraitsBeingSharedInfo()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
totalMonogenicDiseasesString := helpers.ConvertIntToString(totalMonogenicDiseases)
numberOfMonogenicDiseasesBeingSharedString := helpers.ConvertIntToString(numberOfMonogenicDiseasesBeingShared)
numberOfMonogenicDiseasesBeingSharedLabel := getBoldLabelCentered("Monogenic Diseases: " + numberOfMonogenicDiseasesBeingSharedString + "/" + totalMonogenicDiseasesString)
totalPolygenicDiseasesString := helpers.ConvertIntToString(totalPolygenicDiseases)
numberOfPolygenicDiseasesBeingSharedString := helpers.ConvertIntToString(numberOfPolygenicDiseasesBeingShared)
numberOfPolygenicDiseasesBeingSharedLabel := getBoldLabelCentered("Polygenic Diseases: " + numberOfPolygenicDiseasesBeingSharedString + "/" + totalPolygenicDiseasesString)
totalTraitsString := helpers.ConvertIntToString(totalTraits)
numberOfTraitsBeingSharedString := helpers.ConvertIntToString(numberOfTraitsBeingShared)
numberOfTraitsBeingSharedLabel := getBoldLabelCentered("Traits: " + numberOfTraitsBeingSharedString + "/" + totalTraitsString)
changeVisibilityButton := getWidgetCentered(widget.NewButtonWithIcon("Change Visibility", theme.DocumentCreateIcon(), func(){
setBuildMateProfilePage_ChangeGeneticInformationVisibility(window, "MonogenicDiseases", currentPage)
}))
currentGenomeLabel := widget.NewLabel("Current Genome:")
getCurrentGenomeText := func()(string, error){
myGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(myGenomePersonIdentifier)
if (err != nil) { return "", err }
if (len(myGenomesMapList) == 0){
genomeText := translate("None")
return genomeText, nil
}
if (len(myGenomesMapList) == 1){
myGenomeMap := myGenomesMapList[0]
myGenomeCompanyName, exists := myGenomeMap["CompanyName"]
if (exists == false){
return "", errors.New("MyGenomesMapList is malformed: Genome map missing CompanyName")
}
return myGenomeCompanyName, nil
}
currentCombinedGenomeToUse, err := myChosenAnalysis.GetMyCombinedGenomeToUse()
if (err != nil){ return "", err }
result := translate(currentCombinedGenomeToUse)
return result, nil
}
currentGenomeText, err := getCurrentGenomeText()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentGenomeTextLabel := getBoldLabel(currentGenomeText)
currentGenomeRow := container.NewHBox(layout.NewSpacer(), currentGenomeLabel, currentGenomeTextLabel, layout.NewSpacer())
chooseGenomeButton := getWidgetCentered(widget.NewButtonWithIcon("Choose Genome", theme.DocumentCreateIcon(), func(){
setBuildMateProfilePage_ChooseGeneticInformationGenome(window, currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1Row, description2, description3, widget.NewSeparator(), currentPersonNameRow, chooseOrChangePersonButton, widget.NewSeparator(), currentlySharingLabel, numberOfMonogenicDiseasesBeingSharedLabel, numberOfPolygenicDiseasesBeingSharedLabel, numberOfTraitsBeingSharedLabel, changeVisibilityButton, widget.NewSeparator(), currentGenomeRow, chooseGenomeButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_EditGenomePerson(window fyne.Window, previousPage func(), nextPage func()){
currentPage := func(){setBuildMateProfilePage_EditGenomePerson(window, previousPage, nextPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Choose Genome Person")
description1 := getLabelCentered("Choose your genome person.")
description2 := getLabelCentered("You must first import your genome(s) on the Genetics page.")
description3 := getLabelCentered("As you import or remove genomes, the changes will be reflected in your profile.")
description4 := getLabelCentered("To avoid sharing information, you can hide some or all of your genetic information.")
description5 := getLabelCentered("Linking your genome person will enable you to view offspring analyses when viewing matches.")
myGenomePersonIdentifierExists, currentGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (myGenomePersonIdentifierExists == true){
personFound, _, _, _, err := myPeople.GetPersonInfo(currentGenomePersonIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (personFound == false){
// Genome person was deleted
// We will delete the missing person and refresh the page
// We show a loading screen so the user can tell if this wrongfully keeps happening
setLoadingScreen(window, "Build Mate Profile - Physical", "Deleting old genome person identifier...")
err := myLocalProfiles.DeleteProfileData("Mate", "GenomePersonIdentifier")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentPage()
return
}
}
getCurrentPersonNameLabel := func()(fyne.Widget, error){
if (myGenomePersonIdentifierExists == false){
result := translate("None")
noResponseLabel := getBoldItalicLabel(result)
return noResponseLabel, nil
}
personFound, personName, _, _, err := myPeople.GetPersonInfo(currentGenomePersonIdentifier)
if (err != nil){ return nil, err }
if (personFound == false){
return nil, errors.New("Genome person not found after being found already.")
}
personNameLabel := getBoldLabel(personName)
return personNameLabel, nil
}
currentPersonNameLabel, err := getCurrentPersonNameLabel()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentPersonLabel := widget.NewLabel("Current Person:")
currentPersonNameRow := container.NewHBox(layout.NewSpacer(), currentPersonLabel, currentPersonNameLabel, layout.NewSpacer())
getSelectGenomePersonSection := func()(*fyne.Container, error){
allMyGenomePeopleMapList, err := myPeople.GetMyGenomePeopleMapList()
if (err != nil){ return nil, err }
if (len(allMyGenomePeopleMapList) == 0){
noPeopleExistLabel := getBoldLabel("No People Exist.")
createAPersonLabel := getLabelCentered("Create a person and import their genomes on the Genetics page.")
selectPersonSection := container.NewVBox(noPeopleExistLabel, createAPersonLabel)
return selectPersonSection, nil
}
// Map Structure: Person Name -> Person Identifier
allGenomePersonNamesMap := make(map[string]string)
for _, personMap := range allMyGenomePeopleMapList{
personName, exists := personMap["PersonName"]
if (exists == false){
return nil, errors.New("MyGenomePeople map list is malformed: Item missing PersonName")
}
personIdentifier, exists := personMap["PersonIdentifier"]
if (exists == false){
return nil, errors.New("MyGenomePeople map list is malformed: Item missing PersonIdentifier")
}
_, exists = allGenomePersonNamesMap[personName]
if (exists == true){
return nil, errors.New("MyGenomePeople map list is malformed: Duplicate person names exist.")
}
allGenomePersonNamesMap[personName] = personIdentifier
}
allGenomePersonNamesList := helpers.GetListOfMapKeys(allGenomePersonNamesMap)
personSelector := widget.NewSelect(allGenomePersonNamesList, nil)
if (myGenomePersonIdentifierExists == true){
personFound, personName, _, _, err := myPeople.GetPersonInfo(currentGenomePersonIdentifier)
if (err != nil){ return nil, err }
if (personFound == false){
return nil, errors.New("Genome person not found after being found already.")
}
personSelector.Selected = personName
} else {
personSelector.PlaceHolder = translate("Select Person...")
}
submitButton := widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
newPersonName := personSelector.Selected
if (newPersonName == ""){
dialogTitle := translate("No Person Chosen")
dialogMessageA := getLabelCentered(translate("No person was chosen."))
dialogMessageB := getLabelCentered(translate("Select a person from the selector."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
newPersonIdentifier, exists := allGenomePersonNamesMap[newPersonName]
if (exists == false){
setErrorEncounteredPage(window, errors.New("New genome person identifier not found."), currentPage)
return
}
err := myLocalProfiles.SetProfileData("Mate", "GenomePersonIdentifier", newPersonIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
nextPage()
})
personSelectorWithSubmitButtonRow := container.NewHBox(layout.NewSpacer(), personSelector, submitButton, layout.NewSpacer())
removePersonButton := getWidgetCentered(widget.NewButtonWithIcon(translate("Remove Person"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "GenomePersonIdentifier")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
nextPage()
}))
selectGenomePersonSection := container.NewVBox(personSelectorWithSubmitButtonRow, removePersonButton)
return selectGenomePersonSection, nil
}
selectGenomePersonSection, err := getSelectGenomePersonSection()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), currentPersonNameRow, widget.NewSeparator(), selectGenomePersonSection)
setPageContent(page, window)
}
func setBuildMateProfilePage_ChangeGeneticInformationVisibility(window fyne.Window, informationCategory string, previousPage func()){
if (informationCategory != "MonogenicDiseases" && informationCategory != "PolygenicDiseases" && informationCategory != "Traits"){
setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_ChangeGeneticInformationVisibility called with invalid informationCategory: " + informationCategory), previousPage)
return
}
currentPage := func(){setBuildMateProfilePage_ChangeGeneticInformationVisibility(window, informationCategory, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Change Genetic Information Visibility")
description1 := getLabelCentered("Choose which information from your genome you want to share on your profile.")
description2 := getLabelCentered("You will still always be able to view offspring analyses for your matches.")
privacyWarningButton := getWidgetCentered(widget.NewButtonWithIcon("Privacy Warning", theme.WarningIcon(), func(){
setMateProfileGeneticInformationPrivacyWarningPage(window, currentPage)
}))
currentCategoryLabel := getItalicLabelCentered("Current Category:")
monogenicDiseasesTranslated := translate("Monogenic Diseases")
polygenicDiseasesTranslated := translate("Polygenic Diseases")
traitsTranslated := translate("Traits")
categoriesList := []string{monogenicDiseasesTranslated, polygenicDiseasesTranslated, traitsTranslated}
handleSelectFunction := func(newChoice string){
getNewCategory := func()string{
if (newChoice == monogenicDiseasesTranslated){
return "MonogenicDiseases"
}
if (newChoice == polygenicDiseasesTranslated){
return "PolygenicDiseases"
}
return "Traits"
}
newCategory := getNewCategory()
setBuildMateProfilePage_ChangeGeneticInformationVisibility(window, newCategory, previousPage)
}
categorySelector := widget.NewSelect(categoriesList, handleSelectFunction)
if (informationCategory == "MonogenicDiseases"){
categorySelector.Selected = monogenicDiseasesTranslated
} else if (informationCategory == "PolygenicDiseases"){
categorySelector.Selected = polygenicDiseasesTranslated
} else {
categorySelector.Selected = traitsTranslated
}
categorySelectorCentered := getWidgetCentered(categorySelector)
// This returns a list of all MonogenicDiseaseNames, PolygenicDiseaseNames, or TraitNames
getItemNamesList := func()([]string, error){
if (informationCategory == "MonogenicDiseases"){
monogenicDiseaseNamesList, err := monogenicDiseases.GetMonogenicDiseaseNamesList()
if (err != nil) { return nil, err }
return monogenicDiseaseNamesList, nil
}
if (informationCategory == "PolygenicDiseases"){
polygenicDiseaseNamesList, err := polygenicDiseases.GetPolygenicDiseaseNamesList()
if (err != nil) { return nil, err }
return polygenicDiseaseNamesList, nil
}
// informationCategory == "Traits"
traitNamesList, err := traits.GetTraitNamesList()
if (err != nil) { return nil, err }
return traitNamesList, nil
}
allItemNamesList, err := getItemNamesList()
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
getCategoryTypeShareInfoPrefix := func()string{
if (informationCategory == "MonogenicDiseases"){
return "ShareMonogenicDiseaseInfo_"
}
if (informationCategory == "PolygenicDiseases"){
return "SharePolygenicDiseaseInfo_"
}
return "ShareTraitInfo_"
}
categoryTypeShareInfoPrefix := getCategoryTypeShareInfoPrefix()
setAllItemShareAttributesToValue := func(yesOrNo string)error{
if (yesOrNo != "Yes" && yesOrNo != "No"){
return errors.New("setAllItemShareAttributesToValue called with invalid yesOrNo: " + yesOrNo)
}
for _, itemName := range allItemNamesList{
itemAttributeName := categoryTypeShareInfoPrefix + itemName
err := myLocalProfiles.SetProfileData("Mate", itemAttributeName, yesOrNo)
if (err != nil) { return err }
}
return nil
}
shareAllButton := widget.NewButtonWithIcon("Share All", theme.VisibilityIcon(), func(){
err := setAllItemShareAttributesToValue("Yes")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
hideAllButton := widget.NewButtonWithIcon("Hide All", theme.VisibilityOffIcon(), func(){
err := setAllItemShareAttributesToValue("No")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
shareAndHideButtons := getContainerCentered(container.NewGridWithRows(1, shareAllButton, hideAllButton))
getCategoryItemsGrid := func()(*fyne.Container, error){
getItemTypeName := func()string{
if (informationCategory == "MonogenicDiseases"){
result := translate("Monogenic Disease")
return result
}
if (informationCategory == "PolygenicDiseases"){
result := translate("Polygenic Disease")
return result
}
result := translate("Trait")
return result
}
itemTypeName := getItemTypeName()
itemTypeNameLabel := getItalicLabelCentered(itemTypeName + " " + translate("Name"))
shareInformationLabel := getItalicLabelCentered(translate("Share Information?"))
itemNameColumn := container.NewVBox(itemTypeNameLabel, widget.NewSeparator())
itemChecksColumn := container.NewVBox(shareInformationLabel, widget.NewSeparator())
for _, itemName := range allItemNamesList{
itemNameLabel := getBoldLabelCentered(itemName)
itemAttributeName := categoryTypeShareInfoPrefix + itemName
itemCheck := widget.NewCheck("", func(newResponse bool){
newValueString := helpers.ConvertBoolToYesOrNoString(newResponse)
err := myLocalProfiles.SetProfileData("Mate", itemAttributeName, newValueString)
if (err != nil) {
setErrorEncounteredPage(window, err, currentPage)
return
}
})
currentSharePreferenceExists, currentSharePreference, err := myLocalProfiles.GetProfileData("Mate", itemAttributeName)
if (err != nil){ return nil, err }
if (currentSharePreferenceExists == true && currentSharePreference == "Yes"){
itemCheck.Checked = true
}
itemCheckCentered := getWidgetCentered(itemCheck)
itemNameColumn.Add(itemNameLabel)
itemChecksColumn.Add(itemCheckCentered)
itemNameColumn.Add(widget.NewSeparator())
itemChecksColumn.Add(widget.NewSeparator())
}
itemsGrid := container.NewHBox(layout.NewSpacer(), itemNameColumn, itemChecksColumn, layout.NewSpacer())
return itemsGrid, nil
}
categoryItemsGrid, err := getCategoryItemsGrid()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, privacyWarningButton, widget.NewSeparator(), currentCategoryLabel, categorySelectorCentered, widget.NewSeparator(), shareAndHideButtons, widget.NewSeparator(), categoryItemsGrid)
setPageContent(page, window)
}
func setMateProfileGeneticInformationPrivacyWarningPage(window fyne.Window, previousPage func()){
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Genetic Information Privacy Warning")
description1 := getLabelCentered("By sharing genome information, users can read an analysis of an offspring created from you and them.")
description2 := getLabelCentered("When you share Polygenic Disease and Trait information, you are sharing specific locations on your genome.")
description3 := getLabelCentered("These locations represent a tiny fraction of your entire genome.")
description4 := getLabelCentered("These locations can still be used to create a unique genetic fingerprint, which can identify you.")
description5 := getLabelCentered("People will also be able to read your trait and polygenic disease risk information.")
description6 := getLabelCentered("For example, if you share Breast Cancer, users will know your Breast Cancer risk.")
description7 := getLabelCentered("When sharing Monogenic Disease information, you do not share specific locations.")
description8 := getLabelCentered("You instead share the probability of passing a monogenic disease variant to your offspring.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8)
setPageContent(page, window)
}
func setBuildMateProfilePage_ChooseGeneticInformationGenome(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_ChooseGeneticInformationGenome(window, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Choose Genetic Information Genome")
description1 := getLabelCentered("A single genome from your genetic analysis will be used for genetic calculations with other users.")
description2 := getLabelCentered("Your profile will also contain information from this genome if you choose to share any information.")
description3 := getLabelCentered("If you have only imported one genome, that will be the genome whose information is used.")
description4 := getLabelCentered("If you have multiple genomes, only 1 of the two combined genomes will be used.")
description5 := getLabelCentered("You can choose below which genome you want to use if you have imported multiple genomes.")
currentGenomeLabel := widget.NewLabel("Current Genome:")
myGenomePersonIdentifierExists, myGenomePersonIdentifier, err := myLocalProfiles.GetProfileData("Mate", "GenomePersonIdentifier")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (myGenomePersonIdentifierExists == false){
setErrorEncounteredPage(window, errors.New("setBuildMateProfilePage_ChooseGeneticInformationGenome called when genome person is not established."), previousPage)
return
}
currentCombinedGenomeToUse, err := myChosenAnalysis.GetMyCombinedGenomeToUse()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getCurrentGenomeText := func()(string, error){
myGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(myGenomePersonIdentifier)
if (err != nil) { return "", err }
if (len(myGenomesMapList) == 0){
genomeText := translate("None")
return genomeText, nil
}
if (len(myGenomesMapList) == 1){
myGenomeMap := myGenomesMapList[0]
myGenomeCompanyName, exists := myGenomeMap["CompanyName"]
if (exists == false){
return "", errors.New("MyGenomesMapList is malformed: Genome map missing CompanyName")
}
return myGenomeCompanyName, nil
}
result := translate(currentCombinedGenomeToUse)
return result, nil
}
currentGenomeText, err := getCurrentGenomeText()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentGenomeTextLabel := getBoldLabel(currentGenomeText)
currentGenomeRow := container.NewHBox(layout.NewSpacer(), currentGenomeLabel, currentGenomeTextLabel, layout.NewSpacer())
combinedGenomeToUseLabel := getItalicLabel("Combined Genome To Use:")
option1Translated := translate("Only Include Shared")
option2Translated := translate("Only Exclude Conflicts")
untranslatedOptionsMap := map[string]string{
option1Translated: "Only Include Shared",
option2Translated: "Only Exclude Conflicts",
}
selectorOptionsList := []string{option1Translated, option2Translated}
combinedGenomeSelector := widget.NewSelect(selectorOptionsList, func(newSelection string){
newSelectionUntranslated, exists := untranslatedOptionsMap[newSelection]
if (exists == false){
setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing selection: " + newSelection), currentPage)
return
}
err = myChosenAnalysis.SetMyCombinedGenomeToUse(newSelectionUntranslated)
if (err != nil) {
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
combinedGenomeSelector.Selected = translate(currentCombinedGenomeToUse)
combinedGenomeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setCombinedGenomesExplainerPage(window, currentPage)
})
combinedGenomeSelectorWithHelpButton := container.NewBorder(nil, nil, nil, combinedGenomeHelpButton, combinedGenomeSelector)
combinedGenomeSelectorWithLabel := getContainerCentered(container.NewGridWithColumns(1, combinedGenomeToUseLabel, combinedGenomeSelectorWithHelpButton))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, widget.NewSeparator(), currentGenomeRow, widget.NewSeparator(), combinedGenomeSelectorWithLabel)
setPageContent(page, window)
}
func setBuildMateProfilePage_Height(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_Height(window, previousPage)}
pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Height"))
description := getLabelCentered(translate("Enter your height."))
getCurrentMetricOrImperial := func()(string, error){
exists, metricOrImperial, err := globalSettings.GetSetting("MetricOrImperial")
if (err != nil) { return "", err }
if (exists == false){
return "Metric", nil
}
if (metricOrImperial != "Metric" && metricOrImperial != "Imperial"){
return "", errors.New("Malformed globalSettings: Invalid metricOrImperial: " + metricOrImperial)
}
return metricOrImperial, nil
}
currentMetricOrImperial, err := getCurrentMetricOrImperial()
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
changeMetricOrImperialButton, err := getMetricImperialSwitchButton(window, currentPage)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentUnitsLabel := getItalicLabel(translate("Current Units:"))
metricOrImperialRow := container.NewHBox(layout.NewSpacer(), currentUnitsLabel, changeMetricOrImperialButton, layout.NewSpacer())
currentHeightExists, currentHeightCentimeters, err := myLocalProfiles.GetProfileData("Mate", "Height")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getCurrentHeightLabel := func()(fyne.Widget, error){
if (currentHeightExists == false){
labelText := translate("No Response")
label := getBoldItalicLabel(labelText)
return label, nil
}
myHeightCentimetersFloat64, err := helpers.ConvertStringToFloat64(currentHeightCentimeters)
if (err != nil){
return nil, errors.New("MyLocalProfiles malformed: Contains invalid Height")
}
if (currentMetricOrImperial == "Metric"){
myHeightRounded := helpers.ConvertFloat64ToStringRounded(myHeightCentimetersFloat64, 2)
centimetersTranslated := translate("centimeters")
formattedResult := myHeightRounded + " " + centimetersTranslated
label := getBoldLabel(formattedResult)
return label, nil
}
feetInchesString, err := helpers.ConvertCentimetersToFeetInchesTranslatedString(myHeightCentimetersFloat64)
if (err != nil) { return nil, err }
label := getBoldLabel(feetInchesString)
return label, nil
}
currentHeightLabel, err := getCurrentHeightLabel()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
myHeightLabel := widget.NewLabel("My Height:")
currentHeightRow := container.NewHBox(layout.NewSpacer(), myHeightLabel, currentHeightLabel, layout.NewSpacer())
getEnterHeightRow := func()(*fyne.Container, error){
if (currentMetricOrImperial == "Metric"){
centimetersEntry := widget.NewEntry()
if (currentHeightExists == false){
centimetersEntry.SetPlaceHolder(translate("Enter Centimeters"))
} else {
centimetersEntry.SetText(currentHeightCentimeters)
}
centimetersSubmitButton := widget.NewButtonWithIcon(translate("Submit"), theme.ConfirmIcon(), func(){
newHeightCentimeters := centimetersEntry.Text
isValid, err := helpers.VerifyStringIsFloatWithinRange(newHeightCentimeters, 30, 400)
if (err != nil) {
setErrorEncounteredPage(window, err, currentPage)
return
}
if (isValid == false){
centimetersEntry.SetText("")
centimetersEntry.SetPlaceHolder(translate("Enter Centimeters"))
title := translate("Invalid Height")
dialogMessageA := getLabelCentered(translate("Invalid height entered."))
dialogMessageB := getLabelCentered(translate("Height must be between 30 and 400 centimeters."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
err = myLocalProfiles.SetProfileData("Mate", "Height", newHeightCentimeters)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
centimetersLabel := widget.NewLabel(translate("Centimeters"))
centimetersEntryWithLabel := container.NewGridWithRows(1, centimetersEntry, centimetersLabel)
enterHeightRow := container.NewHBox(layout.NewSpacer(), centimetersEntryWithLabel, centimetersSubmitButton, layout.NewSpacer())
return enterHeightRow, nil
}
// MetricOrImperial == "Imperial"
/// Feet + Inches
feetLabel := widget.NewLabel(translate("Feet"))
inchesLabel := widget.NewLabel(translate("Inches"))
feetEntry := widget.NewEntry()
inchesEntry := widget.NewEntry()
if (currentHeightExists == false){
feetEntry.SetPlaceHolder(translate("Enter Feet"))
inchesEntry.SetPlaceHolder(translate("Enter Inches"))
} else {
isValid, err := helpers.VerifyStringIsFloatWithinRange(currentHeightCentimeters, 30, 400)
if (err != nil) { return nil, err }
if (isValid == false){ return nil, errors.New("MyLocalProfiles is malformed: Contains invalid height.") }
currentHeightCentimetersFloat64, err := helpers.ConvertStringToFloat64(currentHeightCentimeters)
if (err != nil) { return nil, err }
currentHeightFeet, currentHeightInches, err := helpers.ConvertCentimetersToFeetInches(currentHeightCentimetersFloat64)
if (err != nil) { return nil, err }
currentHeightFeetString := helpers.ConvertIntToString(currentHeightFeet)
currentHeightInchesString := helpers.ConvertFloat64ToStringRounded(currentHeightInches, 1)
feetEntry.SetText(currentHeightFeetString)
inchesEntry.SetText(currentHeightInchesString)
}
feetInchesSubmitButton := widget.NewButtonWithIcon(translate("Submit"), theme.ConfirmIcon(), func(){
newHeightFeet := feetEntry.Text
newHeightInches := inchesEntry.Text
newHeightFeetInt, err := helpers.ConvertStringToInt(newHeightFeet)
if (err != nil){
title := translate("Invalid Height")
dialogMessageA := getLabelCentered(translate("Invalid feet entered."))
dialogMessageB := getLabelCentered(translate("Feet must be a number."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
newHeightInchesFloat64, err := helpers.ConvertStringToFloat64(newHeightInches)
if (err != nil){
title := translate("Invalid Height")
dialogMessageA := getLabelCentered(translate("Invalid inches entered."))
dialogMessageB := getLabelCentered(translate("Inches must be a number."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
newHeightCentimeters, err := helpers.ConvertFeetInchesToCentimeters(newHeightFeetInt, newHeightInchesFloat64)
if (err != nil){
title := translate("Invalid Height")
dialogMessageA := getLabelCentered(translate("Invalid height entered."))
dialogMessageB := getLabelCentered(translate("Height must be between 30 and 400 centimeters."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
if (newHeightCentimeters < 30 || newHeightCentimeters > 400){
title := translate("Invalid Height")
dialogMessageA := getLabelCentered(translate("Invalid height entered."))
dialogMessageB := getLabelCentered(translate("Height must be between 30 and 400 centimeters."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
newHeightCentimetersString := helpers.ConvertFloat64ToString(newHeightCentimeters)
err = myLocalProfiles.SetProfileData("Mate", "Height", newHeightCentimetersString)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
feetEntryWithLabel := container.NewGridWithRows(1, feetEntry, feetLabel)
inchesEntryWithLabel := container.NewGridWithRows(1, inchesEntry, inchesLabel)
feetInchesEntryRow := getContainerCentered(container.NewHBox(layout.NewSpacer(), feetEntryWithLabel, inchesEntryWithLabel, feetInchesSubmitButton, layout.NewSpacer()))
return feetInchesEntryRow, nil
}
enterHeightRow, err := getEnterHeightRow()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "Height")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description, widget.NewSeparator(), metricOrImperialRow, widget.NewSeparator(), currentHeightRow, widget.NewSeparator(), enterHeightRow, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_Body(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_Body(window, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Body")
description1 := getLabelCentered("Describe your body.")
description2 := getLabelCentered("Choose a value between 1 and 4 to describe each characteristic.")
description3 := getLabelCentered("1 = least fat/muscular human, 4 = most fat/muscular human.")
fatLabel := getBoldLabelCentered("Fat")
fatSelector := widget.NewSelect([]string{"1", "2", "3", "4"}, func(newChoice string){
err := myLocalProfiles.SetProfileData("Mate", "BodyFat", newChoice)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
})
fatSelector.PlaceHolder = "Select one..."
fatNoResponseButton := widget.NewButtonWithIcon("No Response", theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "BodyFat")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
fatColumn := container.NewVBox(fatLabel, fatSelector, fatNoResponseButton)
currentFatValueExists, currentFatValue, err := myLocalProfiles.GetProfileData("Mate", "BodyFat")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (currentFatValueExists == true){
fatSelector.Selected = currentFatValue
}
muscleLabel := getBoldLabelCentered("Muscle")
muscleSelector := widget.NewSelect([]string{"1", "2", "3", "4"}, func(newChoice string){
err := myLocalProfiles.SetProfileData("Mate", "BodyMuscle", newChoice)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
})
muscleSelector.PlaceHolder = "Select one..."
muscleNoResponseButton := widget.NewButtonWithIcon("No Response", theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "BodyMuscle")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
muscleColumn := container.NewVBox(muscleLabel, muscleSelector, muscleNoResponseButton)
currentMuscleValueExists, currentMuscleValue, err := myLocalProfiles.GetProfileData("Mate", "BodyMuscle")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (currentMuscleValueExists == true){
muscleSelector.Selected = currentMuscleValue
}
pageColumns := container.NewHBox(layout.NewSpacer(), widget.NewSeparator(), fatColumn, widget.NewSeparator(), muscleColumn, widget.NewSeparator(), layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), pageColumns)
setPageContent(page, window)
}
func setBuildMateProfilePage_EyeColor(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_EyeColor(window, previousPage)}
pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Eye Color"))
description1 := getLabelCentered(translate("Select your eye color."))
description2 := getLabelCentered(translate("Select more than 1 color if your eyes contain multiple colors."))
eyeColorExists, currentEyeColorAttribute, err := myLocalProfiles.GetProfileData("Mate", "EyeColor")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getCurrentEyeColorList := func()[]string{
if (eyeColorExists == false){
emptyList := make([]string, 0)
return emptyList
}
currentEyeColorList := strings.Split(currentEyeColorAttribute, "+")
return currentEyeColorList
}
currentEyeColorList := getCurrentEyeColorList()
if (len(currentEyeColorList) > 4){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid eye color attribute"), previousPage)
return
}
getCurrentEyeColorLabel := func()fyne.Widget{
if (eyeColorExists == false){
result := translate("No Response")
eyeColorLabel := getBoldItalicLabel(result)
return eyeColorLabel
}
currentEyeColorFormatted := strings.Join(currentEyeColorList, ", ")
eyeColorLabel := getBoldLabel(currentEyeColorFormatted)
return eyeColorLabel
}
currentEyeColorLabel := getCurrentEyeColorLabel()
myEyeColorLabel := widget.NewLabel("My Eye Color:")
currentEyeColorRow := container.NewHBox(layout.NewSpacer(), myEyeColorLabel, currentEyeColorLabel, layout.NewSpacer())
getEyeColorColumn := func(colorName string, colorsList []string)(*fyne.Container, error){
colorColumn := container.NewGridWithColumns(1)
for _, colorCode := range colorsList{
colorSquare, err := getColorSquareAsFyneImage(colorCode)
if (err != nil){ return nil, err }
colorSquare.FillMode = canvas.ImageFillStretch
colorColumn.Add(colorSquare)
}
chooseColorCheck := widget.NewCheck(colorName, func(newChoice bool){
getNewAttributeList := func()[]string{
if (newChoice == false){
newList, _ := helpers.DeleteAllMatchingItemsFromList(currentEyeColorList, colorName)
return newList
}
newList := helpers.AddItemToStringListAndAvoidDuplicate(currentEyeColorList, colorName)
return newList
}
newAttributeList := getNewAttributeList()
if (len(newAttributeList) == 0){
err := myLocalProfiles.DeleteProfileData("Mate", "EyeColor")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
newEyeColorAttribute := strings.Join(newAttributeList, "+")
err := myLocalProfiles.SetProfileData("Mate", "EyeColor", newEyeColorAttribute)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
colorSelected := slices.Contains(currentEyeColorList, colorName)
if (colorSelected == true){
chooseColorCheck.Checked = true
}
colorColumn.Add(chooseColorCheck)
return colorColumn, nil
}
//TODO: Add Gray
blueColorsList := []string{"4d71a6", "9fa8a8", "345269"}
greenColorsList := []string{"333b26", "6d712b", "505216"}
amberColorsList := []string{"6e5c18", "694c19", "684818"}
brownColorsList := []string{"522613", "47240f", "2a110c"}
blueEyeColorColumn, err := getEyeColorColumn("Blue", blueColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
greenEyeColorColumn, err := getEyeColorColumn("Green", greenColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
amberEyeColorColumn, err := getEyeColorColumn("Amber", amberColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
brownEyeColorColumn, err := getEyeColorColumn("Brown", brownColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
selectEyeColorGrid := getContainerCentered(container.NewGridWithColumns(4, blueEyeColorColumn, greenEyeColorColumn, amberEyeColorColumn, brownEyeColorColumn))
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "EyeColor")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentEyeColorRow, widget.NewSeparator(), selectEyeColorGrid, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_HairColor(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_HairColor(window, previousPage)}
pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Hair Color"))
description1 := getLabelCentered(translate("Select your natural hair color."))
description2 := getLabelCentered(translate("Select 2 colors if your hair color is an average of two colors."))
//TODO: What if hair is gray/white
// Users should probably select the color their hair was when they were a young adult. We should add gray or white as an option?
hairColorExists, currentHairColorAttribute, err := myLocalProfiles.GetProfileData("Mate", "HairColor")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getCurrentHairColorList := func()[]string{
if (hairColorExists == false){
emptyList := make([]string, 0)
return emptyList
}
currentHairColorList := strings.Split(currentHairColorAttribute, "+")
return currentHairColorList
}
currentHairColorList := getCurrentHairColorList()
if (len(currentHairColorList) > 4){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid hair color attribute: " + currentHairColorAttribute), previousPage)
return
}
getCurrentHairColorLabel := func()fyne.Widget{
if (hairColorExists == false){
result := translate("No Response")
hairColorLabel := getBoldItalicLabel(result)
return hairColorLabel
}
currentHairColorFormatted := strings.Join(currentHairColorList, "-")
hairColorLabel := getBoldLabel(currentHairColorFormatted)
return hairColorLabel
}
currentHairColorLabel := getCurrentHairColorLabel()
myHairColorLabel := widget.NewLabel("My Hair Color:")
currentHairColorRow := container.NewHBox(layout.NewSpacer(), myHairColorLabel, currentHairColorLabel, layout.NewSpacer())
getHairColorColumn := func(colorName string, colorsList []string)(*fyne.Container, error){
colorColumn := container.NewGridWithColumns(1)
for _, colorCode := range colorsList{
colorSquare, err := getColorSquareAsFyneImage(colorCode)
if (err != nil){ return nil, err }
colorSquare.FillMode = canvas.ImageFillStretch
colorColumn.Add(colorSquare)
}
chooseColorCheck := widget.NewCheck(colorName, func(newChoice bool){
getNewAttributeList := func()[]string{
if (newChoice == false){
newList, _ := helpers.DeleteAllMatchingItemsFromList(currentHairColorList, colorName)
return newList
}
newList := helpers.AddItemToStringListAndAvoidDuplicate(currentHairColorList, colorName)
return newList
}
newAttributeList := getNewAttributeList()
if (len(newAttributeList) > 2){
currentPage()
title := translate("Too Many Colors")
dialogMessageA := getLabelCentered(translate("You can only select two colors."))
dialogContent := container.NewVBox(dialogMessageA)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
if (len(newAttributeList) == 0){
err := myLocalProfiles.DeleteProfileData("Mate", "HairColor")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
newHairColorAttribute := strings.Join(newAttributeList, "+")
err := myLocalProfiles.SetProfileData("Mate", "HairColor", newHairColorAttribute)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
colorSelected := slices.Contains(currentHairColorList, colorName)
if (colorSelected == true){
chooseColorCheck.Checked = true
}
colorColumn.Add(chooseColorCheck)
return colorColumn, nil
}
blackColorsList := []string{"242424", "1d1719", "070300"}
brownColorsList := []string{"5d3629", "362219", "472c24"}
blondeColorsList := []string{"efd8a6", "edd096", "a57d4d"}
orangeColorsList := []string{"f5743a", "8c5125", "883713"}
blackHairColorColumn, err := getHairColorColumn("Black", blackColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
brownHairColorColumn, err := getHairColorColumn("Brown", brownColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
blondeHairColorColumn, err := getHairColorColumn("Blonde", blondeColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
orangeHairColorColumn, err := getHairColorColumn("Orange", orangeColorsList)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
selectHairColorGrid := getContainerCentered(container.NewGridWithColumns(4, blackHairColorColumn, brownHairColorColumn, blondeHairColorColumn, orangeHairColorColumn))
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "HairColor")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentHairColorRow, widget.NewSeparator(), selectHairColorGrid, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_HairTexture(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_HairTexture(window, previousPage)}
title := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Hair Texture"))
description := getLabelCentered(translate("Enter your natural hair texture."))
option1Translated := translate("1 - Straight Hair")
option2Translated := translate("2 - Slightly Wavy Hair")
option3Translated := translate("3 - Wavy Hair")
option4Translated := translate("4 - Big Curls")
option5Translated := translate("5 - Small Curls")
option6Translated := translate("6 - Very Tight Curls")
hairTextureOptionsMap := map[string]string{
option1Translated: "1",
option2Translated: "2",
option3Translated: "3",
option4Translated: "4",
option5Translated: "5",
option6Translated: "6",
}
hairTextureSelectorOptionsList := []string{option1Translated, option2Translated, option3Translated, option4Translated, option5Translated, option6Translated}
hairTextureSelector := widget.NewRadioGroup(hairTextureSelectorOptionsList, func(response string){
if (response == ""){
myLocalProfiles.DeleteProfileData("Mate", "HairTexture")
return
}
attributeValue, exists := hairTextureOptionsMap[response]
if (exists == false){
setErrorEncounteredPage(window, errors.New("hairTextureOptionsMap missing translated option: " + response), currentPage)
return
}
myLocalProfiles.SetProfileData("Mate", "HairTexture", attributeValue)
})
exists, currentHairTexture, err := myLocalProfiles.GetProfileData("Mate", "HairTexture")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (exists == true){
isValid, err := helpers.VerifyStringIsIntWithinRange(currentHairTexture, 1, 6)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (isValid == false){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles contains invalid hair texture: " + currentHairTexture), previousPage)
return
}
if (currentHairTexture == "1"){
hairTextureSelector.Selected = option1Translated
} else if (currentHairTexture == "2"){
hairTextureSelector.Selected = option2Translated
} else if (currentHairTexture == "3"){
hairTextureSelector.Selected = option3Translated
} else if (currentHairTexture == "4"){
hairTextureSelector.Selected = option4Translated
} else if (currentHairTexture == "5"){
hairTextureSelector.Selected = option5Translated
} else if (currentHairTexture == "6"){
hairTextureSelector.Selected = option6Translated
}
}
hairTextureSelectorCentered := getWidgetCentered(hairTextureSelector)
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
myLocalProfiles.DeleteProfileData("Mate", "HairTexture")
currentPage()
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description, widget.NewSeparator(), hairTextureSelectorCentered, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_SkinColor(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_SkinColor(window, previousPage)}
pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Skin Color"))
description1 := getLabelCentered(translate("Select your skin color."))
description2 := getLabelCentered(translate("This may be difficult because skin color changes under different conditions."))
description3 := getLabelCentered(translate("Try your best to choose the best option."))
description4 := getLabelCentered(translate("Users are reminded of this when choosing their skin color desires."))
mySkinColorExists, currentSkinColorAttribute, err := myLocalProfiles.GetProfileData("Mate", "SkinColor")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (mySkinColorExists == true){
currentSkinColorInt, err := helpers.ConvertStringToInt(currentSkinColorAttribute)
if (err != nil){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles SkinColor is invalid: " + currentSkinColorAttribute), previousPage)
return
}
if (currentSkinColorInt < 1 || currentSkinColorInt > 6){
setErrorEncounteredPage(window, errors.New("MyLocalProfiles SkinColor is invalid: " + currentSkinColorAttribute), previousPage)
return
}
}
getCurrentSkinColorLabel := func()fyne.Widget{
if (mySkinColorExists == false){
result := translate("No Response")
skinColorLabel := getBoldItalicLabel(result)
return skinColorLabel
}
skinColorLabel := getBoldLabel(currentSkinColorAttribute)
return skinColorLabel
}
currentSkinColorLabel := getCurrentSkinColorLabel()
mySkinColorLabel := widget.NewLabel("My Skin Color:")
currentSkinColorRow := container.NewHBox(layout.NewSpacer(), mySkinColorLabel, currentSkinColorLabel, layout.NewSpacer())
getSkinColorColumn := func(colorIdentifier string, colorCode string)(*fyne.Container, error){
colorSquare, err := getColorSquareAsFyneImage(colorCode)
if (err != nil){ return nil, err }
colorSquare.FillMode = canvas.ImageFillStretch
chooseColorCheck := widget.NewCheck(colorIdentifier, func(newChoice bool){
err := myLocalProfiles.DeleteProfileData("Mate", "SkinColor")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
err = myLocalProfiles.SetProfileData("Mate", "SkinColor", colorIdentifier)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
if (colorIdentifier == currentSkinColorAttribute){
chooseColorCheck.Checked = true
}
colorColumn := container.NewGridWithColumns(1, colorSquare, chooseColorCheck)
return colorColumn, nil
}
skinColorColumn_1, err := getSkinColorColumn("1", "f4e3da")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_2, err := getSkinColorColumn("2", "f5d6b9")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_3, err := getSkinColorColumn("3", "dabe91")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_4, err := getSkinColorColumn("4", "ba9175")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_5, err := getSkinColorColumn("5", "916244")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_6, err := getSkinColorColumn("6", "744d2d")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
selectSkinColorGrid := getContainerCentered(container.NewGridWithColumns(6, skinColorColumn_1, skinColorColumn_2, skinColorColumn_3, skinColorColumn_4, skinColorColumn_5, skinColorColumn_6))
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", "SkinColor")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), currentSkinColorRow, widget.NewSeparator(), selectSkinColorGrid, noResponseButton)
setPageContent(page, window)
}
func setBuildMateProfilePage_Infections(window fyne.Window, previousPage func()){
currentPage := func(){setBuildMateProfilePage_Infections(window, previousPage)}
pageTitle := getPageTitleCentered(translate("Build Mate Profile - Physical"))
backButton := getBackButtonCentered(previousPage)
pageSubtitle := getPageSubtitleCentered(translate("Infections"))
description := getLabelCentered(translate("Select the infections that you have."))
infectionNameColumn := container.NewVBox(widget.NewSeparator())
radioButtonsColumn := container.NewVBox(widget.NewSeparator())
noResponseButtonsColumn := container.NewVBox(widget.NewSeparator())
addInfectionRow := func(infectionName string, infectionAttributeName string)error{
infectionNameLabel := getBoldLabelCentered(infectionName)
yesTranslated := translate("Yes")
noTranslated := translate("No")
untranslatedOptionsMap := map[string]string{
yesTranslated: "Yes",
noTranslated: "No",
}
optionsList := []string{yesTranslated, noTranslated}
yesNoSelector := widget.NewRadioGroup(optionsList, func(response string){
if (response == ""){
_ = myLocalProfiles.DeleteProfileData("Mate", infectionAttributeName)
return
}
responseUntranslated, exists := untranslatedOptionsMap[response]
if (exists == false){
setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing response: " + response), currentPage)
return
}
_ = myLocalProfiles.SetProfileData("Mate", infectionAttributeName, responseUntranslated)
})
yesNoSelector.Horizontal = true
myCurrentStatusExists, myCurrentInfectionStatus, err := myLocalProfiles.GetProfileData("Mate", infectionAttributeName)
if (err != nil){ return err }
if (myCurrentStatusExists == true){
yesNoSelector.Selected = translate(myCurrentInfectionStatus)
}
noResponseButton := getWidgetCentered(widget.NewButtonWithIcon(translate("No Response"), theme.CancelIcon(), func(){
err := myLocalProfiles.DeleteProfileData("Mate", infectionAttributeName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
infectionNameColumn.Add(infectionNameLabel)
radioButtonsColumn.Add(yesNoSelector)
noResponseButtonsColumn.Add(noResponseButton)
infectionNameColumn.Add(widget.NewSeparator())
radioButtonsColumn.Add(widget.NewSeparator())
noResponseButtonsColumn.Add(widget.NewSeparator())
return nil
}
err := addInfectionRow("HIV", "HasHIV")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
err = addInfectionRow("Genital Herpes", "HasGenitalHerpes")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
infectionsGrid := container.NewHBox(layout.NewSpacer(), infectionNameColumn, radioButtonsColumn, noResponseButtonsColumn, layout.NewSpacer())
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), pageSubtitle, widget.NewSeparator(), description, widget.NewSeparator(), infectionsGrid)
setPageContent(page, window)
}