seekia/gui/desiresGui_Physical.go

2325 lines
88 KiB
Go

package gui
// desiresGui_Physical.go implements pages to manage a user's Physical mate desires
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/internal/allowedText"
import "seekia/internal/desires/mateDesires"
import "seekia/internal/desires/myLocalDesires"
import "seekia/internal/encoding"
import "seekia/internal/genetics/companyAnalysis"
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "seekia/internal/profiles/myLocalProfiles"
import "strings"
import "errors"
import "slices"
func setChooseDesiresCategoryPage_Physical(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresCategoryPage_Physical(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
sexButton := widget.NewButton(translate("Sex"), func(){
setChooseDesiresPage_Sex(window, currentPage)
})
ageButton := widget.NewButton(translate("Age"), func(){
setChooseDesiresPage_Age(window, currentPage)
})
ancestryCompositionButton := widget.NewButton("Ancestry Composition", func(){
setChooseDesiresPage_23andMe_AncestryComposition(window, "User", currentPage)
})
neanderthalVariantsButton := widget.NewButton("Neanderthal Variants", func(){
setChooseDesiresPage_23andMe_NeanderthalVariants(window, currentPage)
})
maternalHaplogroupButton := widget.NewButton("Maternal Haplogroup", func(){
setChooseDesiresPage_23andMe_Haplogroup(window, "Maternal", currentPage)
})
paternalHaplogroupButton := widget.NewButton("Paternal Haplogroup", func(){
setChooseDesiresPage_23andMe_Haplogroup(window, "Paternal", currentPage)
})
monogenicDiseasesButton := widget.NewButton("Monogenic Diseases", func(){
setChooseDesiresPage_MonogenicDiseases(window, currentPage)
})
polygenicDiseasesButton := widget.NewButton("Polygenic Diseases", func(){
//TODO: Filter based on minimum variants tested
// Users will be able to sort matches based on lowest overall disease risk
showUnderConstructionDialog(window)
})
geneticTraitsButton := widget.NewButton("Genetic Traits", func(){
//TODO: Filter based on number of variants tested
// Users will be able to sort matches based on highest probability of blue eyes, brown eyes, straight hair, curly hair, etc..
// Also, users should be able to filter based on outcome points for each trait outcome
showUnderConstructionDialog(window)
})
heightButton := widget.NewButton(translate("Height"), func(){
setChooseDesiresPage_Height(window, currentPage)
})
bodyFatButton := widget.NewButton(translate("Body Fat"), func(){
setChooseDesiresPage_BodyFat(window, currentPage)
})
bodyMuscleButton := widget.NewButton(translate("Body Muscle"), func(){
setChooseDesiresPage_BodyMuscle(window, currentPage)
})
eyeColorButton := widget.NewButton(translate("Eye Color"), func(){
setChooseDesiresPage_EyeColor(window, currentPage)
})
hairColorButton := widget.NewButton(translate("Hair Color"), func(){
setChooseDesiresPage_HairColor(window, currentPage)
})
hairTextureButton := widget.NewButton(translate("Hair Texture"), func(){
setChooseDesiresPage_HairTexture(window, currentPage)
})
skinColorButton := widget.NewButton(translate("Skin Color"), func(){
setChooseDesiresPage_SkinColor(window, currentPage)
})
infectionsButton := widget.NewButton(translate("Infections"), func(){
setChooseDesiresPage_Infections(window, currentPage)
})
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, sexButton, ageButton, ancestryCompositionButton, neanderthalVariantsButton, maternalHaplogroupButton, paternalHaplogroupButton, monogenicDiseasesButton, polygenicDiseasesButton, geneticTraitsButton, heightButton, bodyFatButton, bodyMuscleButton, eyeColorButton, hairColorButton, hairTextureButton, skinColorButton, infectionsButton))
buttonsGridPadded := container.NewPadded(buttonsGrid)
page := container.NewVBox(title, backButton, widget.NewSeparator(), buttonsGridPadded)
setPageContent(page, window)
}
func setChooseDesiresPage_Sex(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_Sex(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered(translate("Sex"))
descriptionText := widget.NewLabel("Choose the sex(es) that you desire.")
sexHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setSexExplainerPage(window, currentPage)
})
descriptionRow := container.NewHBox(layout.NewSpacer(), descriptionText, sexHelpButton, layout.NewSpacer())
optionTitlesList := []string{translate("Male"), translate("Female"), translate("Intersex Male"), translate("Intersex Female"), translate("Intersex")}
optionNamesMap := make(map[string][]string)
optionNamesMap[translate("Male")] = []string{"Male"}
optionNamesMap[translate("Female")] = []string{"Female"}
optionNamesMap[translate("Intersex Male")] = []string{"Intersex Male"}
optionNamesMap[translate("Intersex Female")] = []string{"Intersex Female"}
optionNamesMap[translate("Intersex")] = []string{"Intersex"}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "Sex", optionTitlesList, optionNamesMap, false, true, 2)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Sex", "Sex", true, "Donut", "Sex", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), descriptionRow, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_23andMe_AncestryComposition(window fyne.Window, userOrOffspring string, previousPage func()){
currentPage := func(){setChooseDesiresPage_23andMe_AncestryComposition(window, userOrOffspring, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Ancestry Composition")
description1 := getLabelCentered("Choose your ancestry composition desires.")
description2 := getLabelCentered("Each location is represented by a desired percentage range.")
getRestrictiveModeIsEnabledBool := func()(bool, error){
myDesireExists, restrictiveModeEnabled, err := myLocalDesires.GetDesire("23andMe_AncestryComposition_RestrictiveModeEnabled")
if (err != nil) { return false, err }
if (myDesireExists == true && restrictiveModeEnabled == "Yes"){
return true, nil
}
return false, nil
}
restrictiveModeIsEnabled, err := getRestrictiveModeIsEnabledBool()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
restrictiveModeCheck := widget.NewCheck("Restrictive Mode", func(response bool){
newValue := helpers.ConvertBoolToYesOrNoString(response)
err := myLocalDesires.SetDesire("23andMe_AncestryComposition_RestrictiveModeEnabled", newValue)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
restrictiveModeCheck.Checked = restrictiveModeIsEnabled
restrictiveModeHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setAncestryCompositionDesireRestrictiveModeExplainerPage(window, currentPage)
})
restrictiveModeRow := container.NewHBox(layout.NewSpacer(), restrictiveModeCheck, restrictiveModeHelpButton, layout.NewSpacer())
chooseLocationDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("Choose Location Desires", theme.NavigateNextIcon(), func(){
setChooseDesiresPage_23andMe_ViewAncestryComposition(window, restrictiveModeIsEnabled, "User", currentPage)
}))
getDesireName := func()string{
if (restrictiveModeIsEnabled == false){
return "23andMe_AncestryComposition"
}
return "23andMe_AncestryComposition_Restrictive"
}
desireName := getDesireName()
filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, desireName, true)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getDesireTitle := func()string{
if (restrictiveModeIsEnabled == false){
return "23andMe Ancestry Composition"
}
return "23andMe Ancestry Composition (Restrictive)"
}
desireTitle := getDesireTitle()
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, desireTitle, desireName, false, "", "", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), restrictiveModeRow, widget.NewSeparator(), chooseLocationDesiresButton, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_23andMe_ViewAncestryComposition(window fyne.Window, restrictiveModeIsEnabled bool, userOrOffspring string, previousPage func()){
currentPage := func(){setChooseDesiresPage_23andMe_ViewAncestryComposition(window, restrictiveModeIsEnabled, userOrOffspring, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
getSubtitleText := func()string{
if (restrictiveModeIsEnabled == false){
return "23andMe - Ancestry Composition"
}
return "23andMe - Ancestry Composition (Restrictive)"
}
subtitleText := getSubtitleText()
subtitle := getPageSubtitleCentered(subtitleText)
description1 := getLabelCentered("You can toggle between viewing your user or offspring desires.")
description2Label := widget.NewLabel("Your offspring desires are calculated using your profile ancestry composition.")
offspringAncestryCompositionHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringAncestryCompositionExplainerPage(window, currentPage)
})
description2Row := container.NewHBox(layout.NewSpacer(), description2Label, offspringAncestryCompositionHelpButton, layout.NewSpacer())
userOrOffspringList := []string{"User", "Offspring"}
userOrOffspringSelector := widget.NewSelect(userOrOffspringList, func(newUserOrOffspring string){
setChooseDesiresPage_23andMe_ViewAncestryComposition(window, restrictiveModeIsEnabled, newUserOrOffspring, previousPage)
})
userOrOffspringSelector.Selected = userOrOffspring
userOrOffspringSelectorCentered := getWidgetCentered(userOrOffspringSelector)
getDesireName := func()string{
if (restrictiveModeIsEnabled == false){
return "23andMe_AncestryComposition"
}
return "23andMe_AncestryComposition_Restrictive"
}
desireName := getDesireName()
modifyDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("Modify Desires", theme.DocumentCreateIcon(), func(){
setChooseDesiresPage_23andMe_EditAncestryComposition(window, restrictiveModeIsEnabled, false, "", false, "", false, "", currentPage)
}))
myDesireExists, myDesiredAncestryComposition, err := myLocalDesires.GetDesire(desireName)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (myDesireExists == false){
noLocationsAddedLabel := getBoldLabelCentered("No locations added.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2Row, widget.NewSeparator(), userOrOffspringSelectorCentered, widget.NewSeparator(), noLocationsAddedLabel, modifyDesiresButton)
setPageContent(page, window)
return
}
//Outputs:
// -bool: My ancestry composition exists
// -map[string]float64: My continent percentages map
// -map[string]float64: My region percentages map
// -map[string]float64: My subregion percentages map
// -error
getMyAncestryCompositionMaps := func()(bool, map[string]float64, map[string]float64, map[string]float64, error){
myAncestryCompositionExists, myCurrentAncestryComposition, err := myLocalProfiles.GetProfileData("Mate", "23andMe_AncestryComposition")
if (err != nil){ return false, nil, nil, nil, err }
if (myAncestryCompositionExists == false){
return false, nil, nil, nil, nil
}
attributeIsValid, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, err := companyAnalysis.ReadAncestryCompositionAttribute_23andMe(true, myCurrentAncestryComposition)
if (err != nil) { return false, nil, nil, nil, err }
if (attributeIsValid == false){
return false, nil, nil, nil, errors.New("MyLocalProfiles contains invalid 23andMe ancestry composition attribute: " + myCurrentAncestryComposition)
}
mapsAreValid, myFilledContinentPercentagesMap, myFilledRegionPercentagesMap, myFilledSubregionPercentagesMap, err := companyAnalysis.AddMissingParentsToAncestryCompositionMaps_23andMe(myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap)
if (err != nil){ return false, nil, nil, nil, err }
if (mapsAreValid == false){
return false, nil, nil, nil, errors.New("ReadAncestryCompositionAttribute_23andMe not verifying maps.")
}
return true, myFilledContinentPercentagesMap, myFilledRegionPercentagesMap, myFilledSubregionPercentagesMap, nil
}
myAncestryCompositionExists, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, err := getMyAncestryCompositionMaps()
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
if (userOrOffspring == "Offspring" && myAncestryCompositionExists == false){
description3 := getBoldLabelCentered("Your ancestry composition does not exist.")
description4 := getLabelCentered("To view your offspring desires, you must add your ancestry composition.")
description5 := getLabelCentered("Add it on the Build Profile - Physical - Ancestry Composition page.")
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2Row, widget.NewSeparator(), modifyDesiresButton, widget.NewSeparator(), userOrOffspringSelectorCentered, widget.NewSeparator(), description3, description4, description5)
setPageContent(page, window)
return
}
//Outputs:
// -map[string][]string: Location description -> List of sub-locations descriptions
// -error
getDesiredLocationTreeMap := func()(map[string][]string, error){
myContinentMinimumBoundsMap, myContinentMaximumBoundsMap, myRegionMinimumBoundsMap, myRegionMaximumBoundsMap, mySubregionMinimumBoundsMap, mySubregionMaximumBoundsMap, err := mateDesires.ReadAncestryCompositionDesire_23andMe(myDesiredAncestryComposition)
if (err != nil){
return nil, errors.New("MyLocalDesires contains invalid ancestry composition desire: " + err.Error())
}
// This function will convert the range to an offspring range (if userOrOffspring == "Offspring")
getLocationDescription := func(locationType string, locationName string, userMinimumDesiredBound float64, userMaximumDesiredBound float64)(string, error){
if (locationType != "Continent" && locationType != "Region" && locationType != "Subregion"){
return "", errors.New("getLocationDescription called with invalid locationType: " + locationType)
}
getMinimumAndMaximumBounds := func()(float64, float64){
if (userOrOffspring == "User"){
return userMinimumDesiredBound, userMaximumDesiredBound
}
// We calculate offspring range
getMyLocationPercentage := func()float64{
if (locationType == "Continent"){
myPercentage, exists := myContinentPercentagesMap[locationName]
if (exists == false){
return 0
}
return myPercentage
}
if (locationType == "Region"){
myPercentage, exists := myRegionPercentagesMap[locationName]
if (exists == false){
return 0
}
return myPercentage
}
// locationType == "Subregion
myPercentage, exists := mySubregionPercentagesMap[locationName]
if (exists == false){
return 0
}
return myPercentage
}
myLocationPercentage := getMyLocationPercentage()
offspringMinimumBound := (userMinimumDesiredBound + myLocationPercentage)/2
offspringMaximumBound := (userMaximumDesiredBound + myLocationPercentage)/2
return offspringMinimumBound, offspringMaximumBound
}
minimumDesiredBound, maximumDesiredBound := getMinimumAndMaximumBounds()
minimumDesiredBoundString := helpers.ConvertFloat64ToStringRounded(minimumDesiredBound, 1)
maximumDesiredBoundString := helpers.ConvertFloat64ToStringRounded(maximumDesiredBound, 1)
if (minimumDesiredBoundString == maximumDesiredBoundString){
locationDescription := locationName + ": " + minimumDesiredBoundString + "%"
return locationDescription, nil
}
locationDescription := locationName + ": " + minimumDesiredBoundString + "-" + maximumDesiredBoundString + "%"
return locationDescription, nil
}
// We now build the tree map
// This is used to display a fyne tree widget
// Each item is mapped to a list of child items
// The "" item represents the root of the tree
treeMap := make(map[string][]string)
// This list will store the desired continent descriptions
desiredContinentsList := make([]string, 0)
allContinentsList := companyAnalysis.GetAncestryContinentsList_23andMe()
for _, continentName := range allContinentsList{
continentRegionsList, err := companyAnalysis.GetAncestryContinentRegionsList_23andMe(continentName)
if (err != nil){
return nil, errors.New("GetAncestryContinentRegionsList_23andMe missing continent regions: " + continentName)
}
if (len(continentRegionsList) == 0){
// Continent has no sublocations
// We see if we desire it
minimumDesiredRange, exists := myContinentMinimumBoundsMap[continentName]
if (exists == false){
// We do not desire this continent
continue
}
maximumDesiredRange, exists := myContinentMaximumBoundsMap[continentName]
if (exists == false){
return nil, errors.New("myContinentMinimumBoundsMap contains continent, myContinentMaximumBoundsMap does not.")
}
continentDescription, err := getLocationDescription("Continent", continentName, minimumDesiredRange, maximumDesiredRange)
if (err != nil) { return nil, err }
desiredContinentsList = append(desiredContinentsList, continentDescription)
continue
}
// These represent the minimum and maximum desired ranges for this continent
// For example, if the user desires Japanese between 0-50%, and Korean between 50-100%, we say they desire East Asian from 0-100%
// This list will store the desired region descriptions for this continent
desiredContinentRegionsList := make([]string, 0)
continentMinimumDesiredBound := float64(100)
continentMaximumDesiredBound := float64(0)
for _, regionName := range continentRegionsList{
regionSubregionsList, err := companyAnalysis.GetAncestryRegionSubregionsList_23andMe(continentName, regionName)
if (err != nil){
return nil, errors.New("GetAncestryRegionSubregionsList_23andMe missing region subregions: " + regionName)
}
if (len(regionSubregionsList) == 0){
// This region has no sublocations
// Check if we desire it
regionMinimumDesiredBound, exists := myRegionMinimumBoundsMap[regionName]
if (exists == false){
// We do not desire this region
continue
}
regionMaximumDesiredBound, exists := myRegionMaximumBoundsMap[regionName]
if (exists == false){
return nil, errors.New("myRegionMinimumBoundsMap contains region name, myRegionMaximumBoundsMap does not.")
}
if (regionMinimumDesiredBound < continentMinimumDesiredBound){
continentMinimumDesiredBound = regionMinimumDesiredBound
}
if (regionMaximumDesiredBound > continentMaximumDesiredBound){
continentMaximumDesiredBound = regionMaximumDesiredBound
}
regionDescription, err := getLocationDescription("Region", regionName, regionMinimumDesiredBound, regionMaximumDesiredBound)
if (err != nil) { return nil, err }
desiredContinentRegionsList = append(desiredContinentRegionsList, regionDescription)
continue
}
// This list will store the descriptions for our desired subregions of this region
desiredRegionSubregionsList := make([]string, 0)
regionMinimumDesiredBound := float64(100)
regionMaximumDesiredBound := float64(0)
for _, subregionName := range regionSubregionsList{
// All subregions have no sublocations
// We see if we desire this subregion
subregionMinimumDesiredBound, exists := mySubregionMinimumBoundsMap[subregionName]
if (exists == false){
// We do not desire this subregion
continue
}
subregionMaximumDesiredBound, exists := mySubregionMaximumBoundsMap[subregionName]
if (exists == false){
return nil, errors.New("subregionMinimumBoundsMap contains subregion name, subregionMaximumBoundsMap does not.")
}
if (subregionMinimumDesiredBound < continentMinimumDesiredBound){
continentMinimumDesiredBound = subregionMinimumDesiredBound
}
if (subregionMaximumDesiredBound > continentMaximumDesiredBound){
continentMaximumDesiredBound = subregionMaximumDesiredBound
}
if (subregionMinimumDesiredBound < regionMinimumDesiredBound){
regionMinimumDesiredBound = subregionMinimumDesiredBound
}
if (subregionMaximumDesiredBound > regionMaximumDesiredBound){
regionMaximumDesiredBound = subregionMaximumDesiredBound
}
subregionDescription, err := getLocationDescription("Subregion", subregionName, subregionMinimumDesiredBound, subregionMaximumDesiredBound)
if (err != nil) { return nil, err }
desiredRegionSubregionsList = append(desiredRegionSubregionsList, subregionDescription)
}
if (len(desiredRegionSubregionsList) != 0){
regionDescription, err := getLocationDescription("Region", regionName, regionMinimumDesiredBound, regionMaximumDesiredBound)
if (err != nil) { return nil, err }
desiredContinentRegionsList = append(desiredContinentRegionsList, regionDescription)
treeMap[regionDescription] = desiredRegionSubregionsList
}
}
if (len(desiredContinentRegionsList) != 0){
continentDescription, err := getLocationDescription("Continent", continentName, continentMinimumDesiredBound, continentMaximumDesiredBound)
if (err != nil) { return nil, err }
desiredContinentsList = append(desiredContinentsList, continentDescription)
treeMap[continentDescription] = desiredContinentRegionsList
}
}
treeMap[""] = desiredContinentsList
return treeMap, nil
}
desiredLocationTreeMap, err := getDesiredLocationTreeMap()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
locationDesireWidgetTree := widget.NewTreeWithStrings(desiredLocationTreeMap)
locationDesireWidgetTree.OpenAllBranches()
header := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2Row, widget.NewSeparator(), modifyDesiresButton, widget.NewSeparator(), userOrOffspringSelectorCentered, widget.NewSeparator())
page := container.NewBorder(header, nil, nil, nil, locationDesireWidgetTree)
setPageContent(page, window)
}
func setChooseDesiresPage_23andMe_EditAncestryComposition(
window fyne.Window,
restrictiveModeIsEnabled bool,
continentProvided bool,
currentContinent string,
regionProvided bool,
currentRegion string,
subregionProvided bool,
currentSubregion string,
previousPage func()){
currentPage := func(){setChooseDesiresPage_23andMe_EditAncestryComposition(window, restrictiveModeIsEnabled, continentProvided, currentContinent, regionProvided, currentRegion, subregionProvided, currentSubregion, previousPage)}
title := getPageTitleCentered("My Mate Desires - Physical")
backButton := getBackButtonCentered(previousPage)
getSubtitleText := func()string{
if (restrictiveModeIsEnabled == true){
return "23andMe Ancestry Composition (Restrictive)"
}
return "23andMe Ancestry Composition"
}
subtitleText := getSubtitleText()
subtitle := getPageSubtitleCentered(subtitleText)
description := getLabelCentered("Choose the percentage range for each location you desire.")
getPageContent := func()(*fyne.Container, error){
getRangeEditor := func(locationType string)(*fyne.Container, error){
if (locationType != "Continent" && locationType != "Region" && locationType != "Subregion"){
return nil, errors.New("getRangeEditor called with invalid locationType: " + locationType)
}
getDesireName := func()string{
if (restrictiveModeIsEnabled == false){
return "23andMe_AncestryComposition"
}
return "23andMe_AncestryComposition_Restrictive"
}
desireName := getDesireName()
//Outputs:
// -map[string]float64: Continent minimum bounds map
// -map[string]float64: Continent maximum bounds map
// -map[string]float64: Region minimum bounds map
// -map[string]float64: Region maximum bounds map
// -map[string]float64: Subregion minimum bounds map
// -map[string]float64: Subregion maximum bounds map
// -error
getMyDesiredAncestryCompositionMaps := func()(map[string]float64, map[string]float64, map[string]float64, map[string]float64, map[string]float64, map[string]float64, error){
myDesireExists, myDesiredAncestryComposition, err := myLocalDesires.GetDesire(desireName)
if (err != nil){ return nil, nil, nil, nil, nil, nil, err }
if (myDesireExists == false){
emptyMap1 := make(map[string]float64)
emptyMap2 := make(map[string]float64)
emptyMap3 := make(map[string]float64)
emptyMap4 := make(map[string]float64)
emptyMap5 := make(map[string]float64)
emptyMap6 := make(map[string]float64)
return emptyMap1, emptyMap2, emptyMap3, emptyMap4, emptyMap5, emptyMap6, nil
}
myContinentMinimumBoundsMap, myContinentMaximumBoundsMap, myRegionMinimumBoundsMap, myRegionMaximumBoundsMap, mySubregionMinimumBoundsMap, mySubregionMaximumBoundsMap, err := mateDesires.ReadAncestryCompositionDesire_23andMe(myDesiredAncestryComposition)
if (err != nil){
return nil, nil, nil, nil, nil, nil, errors.New("MyLocalDesires contains invalid " + desireName + " desire: " + err.Error())
}
return myContinentMinimumBoundsMap, myContinentMaximumBoundsMap, myRegionMinimumBoundsMap, myRegionMaximumBoundsMap, mySubregionMinimumBoundsMap, mySubregionMaximumBoundsMap, nil
}
myContinentMinimumBoundsMap, myContinentMaximumBoundsMap, myRegionMinimumBoundsMap, myRegionMaximumBoundsMap, mySubregionMinimumBoundsMap, mySubregionMaximumBoundsMap, err := getMyDesiredAncestryCompositionMaps()
if (err != nil){ return nil, err }
// Outputs:
// -bool: Range bounds exist (any desire exists for current location)
// -float64: Minimum bound
// -float64: Maximum bound
// -error
getMyDesiredRangeBounds := func()(bool, float64, float64, error){
if (locationType == "Continent"){
continentMinimumBound, exists := myContinentMinimumBoundsMap[currentContinent]
if (exists == false){
return false, 0, 0, nil
}
continentMaximumBound, exists := myContinentMaximumBoundsMap[currentContinent]
if (exists == false){
return false, 0, 0, errors.New("myContinentMinimumBoundsMap contains continent, maximumBoundsMap does not: " + currentContinent)
}
return true, continentMinimumBound, continentMaximumBound, nil
}
if (locationType == "Region"){
regionMinimumBound, exists := myRegionMinimumBoundsMap[currentRegion]
if (exists == false){
return false, 0, 0, nil
}
regionMaximumBound, exists := myRegionMaximumBoundsMap[currentRegion]
if (exists == false){
return false, 0, 0, errors.New("myRegionMinimumBoundsMap contains region, maximumBoundsMap does not: " + currentRegion)
}
return true, regionMinimumBound, regionMaximumBound, nil
}
// locationType == "Subregion"
subregionMinimumBound, exists := mySubregionMinimumBoundsMap[currentSubregion]
if (exists == false){
return false, 0, 0, nil
}
subregionMaximumBound, exists := mySubregionMaximumBoundsMap[currentSubregion]
if (exists == false){
return false, 0, 0, errors.New("mySubregionMinimumBoundsMap contains subregion, maximumBoundsMap does not: " + currentSubregion)
}
return true, subregionMinimumBound, subregionMaximumBound, nil
}
myDesireExists, myMinimumBound, myMaximumBound, err := getMyDesiredRangeBounds()
if (err != nil){ return nil, err }
getMyDesireDisplaySection := func()(*fyne.Container, error){
myDesireTitle := getItalicLabelCentered("My Desire:")
getMyDesireText := func()string{
if (myDesireExists == false){
return "None"
}
myMinimumBoundString := helpers.ConvertFloat64ToStringRounded(myMinimumBound, 1)
myMaximumBoundString := helpers.ConvertFloat64ToStringRounded(myMaximumBound, 1)
if (myMinimumBoundString == myMaximumBoundString){
result := myMinimumBoundString + "%"
return result
}
result := myMinimumBoundString + "-" + myMaximumBoundString + "%"
return result
}
myDesireText := getMyDesireText()
myDesireLabel := getBoldLabelCentered(myDesireText)
if (myDesireExists == false){
displaySection := container.NewVBox(myDesireTitle, myDesireLabel)
return displaySection, nil
}
// We check to see if we should display offspring range
myAncestryCompositionExists, myCurrentAncestryComposition, err := myLocalProfiles.GetProfileData("Mate", "23andMe_AncestryComposition")
if (err != nil){ return nil, err }
if (myAncestryCompositionExists == false){
// We have not added our ancestry composition
// Thus, we cannot determine the offspring location composition
displaySection := container.NewVBox(myDesireTitle, myDesireLabel)
return displaySection, nil
}
// This returns the percentage of the location that we are, as described in our profile
getMyLocationPercentage := func()(float64, error){
attributeIsValid, myContinentPercentagesMap, myRegionPercentagesMap, mySubregionPercentagesMap, err := companyAnalysis.ReadAncestryCompositionAttribute_23andMe(true, myCurrentAncestryComposition)
if (err != nil) { return 0, err }
if (attributeIsValid == false){
return 0, errors.New("MyLocalProfiles contains invalid 23andMe ancestry composition attribute: " + myCurrentAncestryComposition)
}
if (locationType == "Continent"){
myPercentage, exists := myContinentPercentagesMap[currentContinent]
if (exists == false){
return 0, nil
}
return myPercentage, nil
}
if (locationType == "Region"){
myPercentage, exists := myRegionPercentagesMap[currentRegion]
if (exists == false){
return 0, nil
}
return myPercentage, nil
}
// LocationType == "Subregion"
myPercentage, exists := mySubregionPercentagesMap[currentSubregion]
if (exists == false){
return 0, nil
}
return myPercentage, nil
}
myLocationPercentage, err := getMyLocationPercentage()
if (err != nil){ return nil, err }
offspringMinimumBound := (myLocationPercentage + myMinimumBound)/2
offspringMaximumBound := (myLocationPercentage + myMaximumBound)/2
offspringMinimumBoundString := helpers.ConvertFloat64ToStringRounded(offspringMinimumBound, 1)
offspringMaximumBoundString := helpers.ConvertFloat64ToStringRounded(offspringMaximumBound, 1)
getOffspringDesiredRangeString := func()string{
if (offspringMinimumBoundString == offspringMaximumBoundString){
result := offspringMinimumBoundString + "%"
return result
}
result := offspringMinimumBoundString + "-" + offspringMaximumBoundString + "%"
return result
}
offspringDesiredRangeString := getOffspringDesiredRangeString()
offspringRangeLabel := getItalicLabelCentered("(My Offspring: ~" + offspringDesiredRangeString + ")")
displaySection := container.NewVBox(myDesireTitle, myDesireLabel, offspringRangeLabel)
return displaySection, nil
}
myDesireDisplaySection, err := getMyDesireDisplaySection()
if (err != nil) { return nil, err }
minimumLabel := getBoldLabelCentered("Minimum:")
minimumEntry := widget.NewEntry()
if (myDesireExists == true){
myMinimumBoundString := helpers.ConvertFloat64ToStringRounded(myMinimumBound, 1)
minimumEntry.Text = myMinimumBoundString
} else {
minimumEntry.SetPlaceHolder("Enter Minimum...")
}
minimumEntryBoxed := getWidgetBoxed(minimumEntry)
minimumEntryColumn := container.NewGridWithColumns(1, minimumLabel, minimumEntryBoxed)
maximumLabel := getBoldLabelCentered("Maximum:")
maximumEntry := widget.NewEntry()
if (myDesireExists == true){
myMaximumBoundString := helpers.ConvertFloat64ToStringRounded(myMaximumBound, 1)
maximumEntry.Text = myMaximumBoundString
} else {
maximumEntry.SetPlaceHolder("Enter Maximum...")
}
maximumEntryBoxed := getWidgetBoxed(maximumEntry)
maximumEntryColumn := container.NewGridWithColumns(1, maximumLabel, maximumEntryBoxed)
minimumMaximumEntryColumnsRow := getContainerCentered(container.NewGridWithRows(1, minimumEntryColumn, maximumEntryColumn))
submitButton := getWidgetCentered(widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
newMinimum := minimumEntry.Text
newMaximum := maximumEntry.Text
newMinimumBoundFloat64, err := helpers.ConvertStringToFloat64(newMinimum)
if (err != nil) {
dialogTitle := translate("Invalid Minimum Bound")
dialogMessageA := getLabelCentered(translate("Your minimum bound is invalid."))
dialogMessageB := getLabelCentered(translate("It must be a number between 0 and 100."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
newMaximumBoundFloat64, err := helpers.ConvertStringToFloat64(newMaximum)
if (err != nil) {
dialogTitle := translate("Invalid Maximum Bound")
dialogMessageA := getLabelCentered(translate("Your maximum bound is invalid."))
dialogMessageB := getLabelCentered(translate("It must be a number between 0 and 100."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
if (newMinimumBoundFloat64 < 0 || newMinimumBoundFloat64 > 100){
dialogTitle := translate("Invalid Minimum Bound")
dialogMessageA := getLabelCentered(translate("Your minimum bound is invalid."))
dialogMessageB := getLabelCentered(translate("It must be a number between 0 and 100."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
if (newMaximumBoundFloat64 < 0 || newMaximumBoundFloat64 > 100){
dialogTitle := translate("Invalid Maximum Bound")
dialogMessageA := getLabelCentered(translate("Your maximum bound is invalid."))
dialogMessageB := getLabelCentered(translate("It must be a number between 0 and 100."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
if (newMinimumBoundFloat64 > newMaximumBoundFloat64){
dialogTitle := translate("Invalid Range")
dialogMessageA := getLabelCentered(translate("Your range is invalid."))
dialogMessageB := getLabelCentered(translate("The minimum must be less than the maximum."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
if (newMinimumBoundFloat64 == 0 && newMaximumBoundFloat64 == 100){
dialogTitle := translate("Invalid Range")
dialogMessageA := getLabelCentered(translate("Your range is invalid."))
dialogMessageB := getLabelCentered(translate("You cannot set a desired range of 0-100%."))
dialogMessageC := getLabelCentered(translate("All users will pass this range."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
if (locationType == "Continent"){
myContinentMinimumBoundsMap[currentContinent] = newMinimumBoundFloat64
myContinentMaximumBoundsMap[currentContinent] = newMaximumBoundFloat64
} else if (locationType == "Region"){
myRegionMinimumBoundsMap[currentRegion] = newMinimumBoundFloat64
myRegionMaximumBoundsMap[currentRegion] = newMaximumBoundFloat64
} else {
// locationType == "Subregion"
mySubregionMinimumBoundsMap[currentSubregion] = newMinimumBoundFloat64
mySubregionMaximumBoundsMap[currentSubregion] = newMaximumBoundFloat64
}
newDesireValue, err := mateDesires.CreateAncestryCompositionDesire_23andMe(myContinentMinimumBoundsMap, myContinentMaximumBoundsMap, myRegionMinimumBoundsMap, myRegionMaximumBoundsMap, mySubregionMinimumBoundsMap, mySubregionMaximumBoundsMap)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
err = myLocalDesires.SetDesire(desireName, newDesireValue)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
noDesireButton := getWidgetCentered(widget.NewButtonWithIcon("No Desire", theme.CancelIcon(), func(){
if (locationType == "Continent"){
delete(myContinentMinimumBoundsMap, currentContinent)
delete(myContinentMaximumBoundsMap, currentContinent)
} else if (locationType == "Region"){
delete(myRegionMinimumBoundsMap, currentRegion)
delete(myRegionMaximumBoundsMap, currentRegion)
} else {
// locationType == "Subregion"
delete(mySubregionMinimumBoundsMap, currentSubregion)
delete(mySubregionMaximumBoundsMap, currentSubregion)
}
if (len(myContinentMinimumBoundsMap) == 0 && len(myContinentMaximumBoundsMap) == 0 && len(myRegionMinimumBoundsMap) == 0 && len(myRegionMaximumBoundsMap) == 0 && len(mySubregionMinimumBoundsMap) == 0 && len(mySubregionMaximumBoundsMap) == 0){
err := myLocalDesires.DeleteDesire(desireName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
newDesireValue, err := mateDesires.CreateAncestryCompositionDesire_23andMe(myContinentMinimumBoundsMap, myContinentMaximumBoundsMap, myRegionMinimumBoundsMap, myRegionMaximumBoundsMap, mySubregionMinimumBoundsMap, mySubregionMaximumBoundsMap)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
err = myLocalDesires.SetDesire(desireName, newDesireValue)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
rangeEditor := container.NewVBox(myDesireDisplaySection, widget.NewSeparator(), minimumMaximumEntryColumnsRow, submitButton, noDesireButton)
return rangeEditor, nil
}
continentLabel := getBoldLabel("Continent:")
allContinentsList := companyAnalysis.GetAncestryContinentsList_23andMe()
handleContinentSelectFunction := func(newContinent string){
if (continentProvided == true && newContinent == currentContinent){
return
}
setChooseDesiresPage_23andMe_EditAncestryComposition(window, restrictiveModeIsEnabled, true, newContinent, false, "", false, "", previousPage)
}
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
}
regionsList, err := companyAnalysis.GetAncestryContinentRegionsList_23andMe(currentContinent)
if (err != nil) { return nil, err }
if (len(regionsList) == 0){
rangeEditor, err := getRangeEditor("Continent")
if (err != nil) { return nil, err }
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), rangeEditor)
return pageContent, nil
}
regionLabel := getBoldLabel("Region:")
handleRegionSelectFunction := func(newRegion string){
if (regionProvided == true && currentRegion == newRegion){
return
}
setChooseDesiresPage_23andMe_EditAncestryComposition(window, restrictiveModeIsEnabled, true, currentContinent, true, newRegion, false, "", previousPage)
}
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){
rangeEditor, err := getRangeEditor("Region")
if (err != nil) { return nil, err }
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow, widget.NewSeparator(), rangeEditor)
return pageContent, nil
}
subregionLabel := getBoldLabel("Subregion:")
handleSubregionSelectFunction := func(newSubregion string){
if (subregionProvided == true && currentSubregion == newSubregion){
return
}
setChooseDesiresPage_23andMe_EditAncestryComposition(window, restrictiveModeIsEnabled, true, currentContinent, true, currentRegion, true, newSubregion, previousPage)
}
subregionSelector := widget.NewSelect(subregionsList, handleSubregionSelectFunction)
if (subregionProvided == true){
subregionSelector.Selected = currentSubregion
}
subregionRow := container.NewHBox(layout.NewSpacer(), subregionLabel, subregionSelector, layout.NewSpacer())
if (subregionProvided == false){
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow, widget.NewSeparator(), subregionRow)
return pageContent, nil
}
rangeEditor, err := getRangeEditor("Subregion")
if (err != nil) { return nil, err }
pageContent := container.NewVBox(continentRow, widget.NewSeparator(), regionRow, widget.NewSeparator(), subregionRow, widget.NewSeparator(), rangeEditor)
return pageContent, nil
}
pageContent, err := getPageContent()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), pageContent)
setPageContent(page, window)
}
func setChooseDesiresPage_23andMe_NeanderthalVariants(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_23andMe_NeanderthalVariants(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Neanderthal Variants")
description1 := getLabelCentered("Choose your neanderthal variant desires.")
description2 := getLabelCentered("Enter the neanderthal variant count you desire in your matches.")
description3 := getLabelCentered("The data is provided by 23andMe.")
description4 := getLabelCentered("More companies will be added soon.")
myVariantCountExists, myCurrentNeanderthalVariants, err := myLocalProfiles.GetProfileData("Mate", "23andMe_NeanderthalVariants")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getOffspringVariantsCount := func(userVariantsCount float64)(float64, error){
if (myVariantCountExists == false){
return 0, errors.New("Trying to get offspring neanderthal variants count when my count does not exist.")
}
myVariantsCountFloat64, err := helpers.ConvertStringToFloat64(myCurrentNeanderthalVariants)
if (err != nil) {
return 0, errors.New("MyLocalProfile neanderthal variants count is invalid: " + myCurrentNeanderthalVariants)
}
offspringVariantsCount := (userVariantsCount + myVariantsCountFloat64)/2
return offspringVariantsCount, nil
}
desireEditor, err := getDesireEditor_Numeric(window, currentPage, "23andMe_NeanderthalVariants", 0, 7462, "variants", 0, false, nil, nil, myVariantCountExists, "My Offspring", "~", getOffspringVariantsCount)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "23andMe Neanderthal Variants", "23andMe_NeanderthalVariants", true, "Bar", "23andMe_NeanderthalVariants", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_23andMe_Haplogroup(window fyne.Window, maternalOrPaternal string, previousPage func()){
if (maternalOrPaternal != "Maternal" && maternalOrPaternal != "Paternal"){
setErrorEncounteredPage(window, errors.New("setChooseDesiresPage_23andMe_Haplogroup called with invalid maternalOrPaternal: " + maternalOrPaternal), previousPage)
return
}
currentPage := func(){setChooseDesiresPage_23andMe_Haplogroup(window, maternalOrPaternal, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered(maternalOrPaternal + " Haplogroup")
maternalOrPaternalLowercase := strings.ToLower(maternalOrPaternal)
description1 := getLabelCentered("Choose your " + maternalOrPaternalLowercase + " haplogroup desires.")
description2 := getLabelCentered("Add each " + maternalOrPaternalLowercase + " haplogroup you desire.")
description3 := getLabelCentered("You can choose from the known haplogroups, or enter ones that are not listed.")
description4 := getLabelCentered("The haplogroups are provided by 23andMe. More companies will be added soon.")
desireName := "23andMe_" + maternalOrPaternal + "Haplogroup"
getSelectedHaplogroupsSection := func()(*fyne.Container, error){
getCurrentDesiredChoicesList := func()([]string, error){
currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire(desireName)
if (err != nil) { return nil, err }
if (currentChoicesListExists == false){
emptyList := make([]string, 0)
return emptyList, nil
}
//currentChoicesList is a "+" separated list of choices
// Each choice option is encoded in base64
currentDesiredChoicesList := strings.Split(currentChoicesList, "+")
return currentDesiredChoicesList, nil
}
currentDesiredChoicesList, err := getCurrentDesiredChoicesList()
if (err != nil) { return nil, err }
getKnownHaplogroupsList := func()[]string{
if (maternalOrPaternal == "Maternal"){
maternalHaplogroupsList := companyAnalysis.GetKnownMaternalHaplogroupsList_23andMe()
return maternalHaplogroupsList
}
paternalHaplogroupsList := companyAnalysis.GetKnownPaternalHaplogroupsList_23andMe()
return paternalHaplogroupsList
}
knownHaplogroupsList := getKnownHaplogroupsList()
haplogroupEntry := widget.NewSelectEntry(knownHaplogroupsList)
haplogroupEntry.SetPlaceHolder("Enter haplogroup...")
addHaplogroupButton := getWidgetCentered(widget.NewButtonWithIcon("Add Haplogroup", theme.ContentAddIcon(), func(){
newHaplogroupName := haplogroupEntry.Text
if (newHaplogroupName == ""){
return
}
isAllowed := allowedText.VerifyStringIsAllowed(newHaplogroupName)
if (isAllowed == false){
dialogTitle := translate("Invalid Haplogroup Name")
dialogMessageA := getLabelCentered(translate("Your haplogroup contains an invalid character."))
dialogMessageB := getLabelCentered(translate("It must be encoded in UTF-8."))
dialogMessageC := getLabelCentered(translate("Remove this character and resubmit."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
containsTabsOrNewlines := helpers.CheckIfStringContainsTabsOrNewlines(newHaplogroupName)
if (containsTabsOrNewlines == true){
dialogTitle := translate("Invalid Haplogroup Name")
dialogMessageA := getLabelCentered(translate("Your haplogroup contains a tab or a newline."))
dialogMessageB := getLabelCentered(translate("Remove the tab or newline and resubmit."))
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
if (len(newHaplogroupName) > 25){
currentBytesLengthString := helpers.ConvertIntToString(len(newHaplogroupName))
dialogTitle := translate("Invalid Haplogroup Name")
dialogMessageA := getLabelCentered(translate("Your haplogroup name is too long."))
dialogMessageB := getLabelCentered(translate("It cannot exceed 25 bytes."))
dialogMessageC := getLabelCentered(translate("Current Length:") + " " + currentBytesLengthString)
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
return
}
haplogroupNameBase64 := encoding.EncodeBytesToBase64String([]byte(newHaplogroupName))
newDesireList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, haplogroupNameBase64)
newDesireAttributeValue := strings.Join(newDesireList, "+")
err := myLocalDesires.SetDesire(desireName, newDesireAttributeValue)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
}))
addHaplogroupRow := getContainerCentered(container.NewGridWithRows(1, haplogroupEntry, addHaplogroupButton))
otherSelectCheck := widget.NewCheck("Allow Other", func(selection bool){
//Outputs:
// -[]string: New desire attribute list (list of base64 option names)
getNewDesireAttributeList := func()[]string{
if (selection == false){
if (len(currentDesiredChoicesList) == 0){
// This should not happen, because "Other" had to have been selected for it to be deselected
emptyList := make([]string, 0)
return emptyList
}
newAttributeList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, "Other")
return newAttributeList
}
//selection == true
newAttributeList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, "Other")
return newAttributeList
}
newDesireAttributeList := getNewDesireAttributeList()
if (len(newDesireAttributeList) == 0){
err := myLocalDesires.DeleteDesire(desireName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
newDesireAttribute := strings.Join(newDesireAttributeList, "+")
err := myLocalDesires.SetDesire(desireName, newDesireAttribute)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
otherIsSelected := slices.Contains(currentDesiredChoicesList, "Other")
if (otherIsSelected == true){
otherSelectCheck.Checked = true
}
allowOtherHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setAllowOtherExplainerPage(window, currentPage)
})
otherSelectCheckRow := container.NewHBox(layout.NewSpacer(), otherSelectCheck, allowOtherHelpButton, layout.NewSpacer())
checkIfAnyHaplogroupsAreSelected := func()bool{
if (len(currentDesiredChoicesList) == 0){
return false
}
if (len(currentDesiredChoicesList) == 1){
onlySelection := currentDesiredChoicesList[0]
if (onlySelection == "Other"){
return false
}
}
return true
}
anyHaplogroupsAreSelected := checkIfAnyHaplogroupsAreSelected()
if (anyHaplogroupsAreSelected == false){
noHaplogroupsExistLabel := getBoldLabelCentered("No Haplogroups Chosen.")
selectedHaplogroupsSection := container.NewVBox(addHaplogroupRow, widget.NewSeparator(), noHaplogroupsExistLabel, widget.NewSeparator(), otherSelectCheckRow)
return selectedHaplogroupsSection, nil
}
myDesiredHaplogroupsLabel := getItalicLabelCentered("My Desired Haplogroups:")
haplogroupNameColumn := container.NewVBox(widget.NewSeparator())
deleteButtonsColumn := container.NewVBox(widget.NewSeparator())
for _, haplogroupNameBase64 := range currentDesiredChoicesList{
if (haplogroupNameBase64 == "Other"){
continue
}
haplogroupName, err := encoding.DecodeBase64StringToUnicodeString(haplogroupNameBase64)
if (err != nil){
return nil, errors.New("My current profile " + maternalOrPaternal + " haplogroup desire is malformed: Contains invalid haplogroup: " + haplogroupNameBase64)
}
haplogroupNameLabel := getBoldLabelCentered(haplogroupName)
deleteHaplogroupButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){
newDesiredHaplogroupsList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, haplogroupNameBase64)
if (len(newDesiredHaplogroupsList) == 0){
err := myLocalDesires.DeleteDesire(desireName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
newDesireValueString := strings.Join(newDesiredHaplogroupsList, "+")
err := myLocalDesires.SetDesire(desireName, newDesireValueString)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
haplogroupNameColumn.Add(haplogroupNameLabel)
deleteButtonsColumn.Add(deleteHaplogroupButton)
haplogroupNameColumn.Add(widget.NewSeparator())
deleteButtonsColumn.Add(widget.NewSeparator())
}
haplogroupsGrid := container.NewHBox(layout.NewSpacer(), haplogroupNameColumn, deleteButtonsColumn, layout.NewSpacer())
selectedHaplogroupsSection := container.NewVBox(addHaplogroupRow, widget.NewSeparator(), myDesiredHaplogroupsLabel, haplogroupsGrid, widget.NewSeparator(), otherSelectCheckRow)
return selectedHaplogroupsSection, nil
}
selectedHaplogroupsSection, err := getSelectedHaplogroupsSection()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, desireName, true)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "23andMe " + maternalOrPaternal + " Haplogroup", desireName, true, "Bar", desireName, currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), selectedHaplogroupsSection, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_Age(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_Age(window, previousPage)}
pageTitle := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered(translate("Age"))
description := getLabelCentered("Choose your age desires.")
desireEditor, err := getDesireEditor_Numeric(window, currentPage, "Age", 18, 200, "Years", 0, false, nil, nil, false, "", "", nil)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Age", "Age", true, "Bar", "Age", currentPage)
}))
page := container.NewVBox(pageTitle, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_MonogenicDiseases(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_MonogenicDiseases(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("My Offspring Monogenic Disease Desires")
description1 := getLabelCentered("Choose your offspring monogenic disease probability desires.")
description2 := getLabelCentered("You must link your genome person on the Build Profile - Genetic Analysis page.")
description3 := getLabelCentered("This desire will filter users based upon the probability that your offspring will have any monogenic disease.")
description4 := widget.NewLabel("If you use genetic testing, you can ensure your offspring will not have any monogenic diseases.")
geneticTestingHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setGeneticTestingExplainerPage(window, currentPage)
})
description4Row := container.NewHBox(layout.NewSpacer(), description4, geneticTestingHelpButton, layout.NewSpacer())
description5 := getBoldLabel("Choose the monogenic disease probability for your offspring that you desire.")
desireHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setOffspringMonogenicDiseaseProbabilityDesireExplainerPage(window, currentPage)
})
description5Row := container.NewHBox(layout.NewSpacer(), description5, desireHelpButton, layout.NewSpacer())
description6 := getLabelCentered("Be aware that if you select 0%, all users with dominant monogenic diseases will be filtered.")
description7 := getLabelCentered("You should not select 0% if you have a dominant monogenic disease.")
getCurrentDesireStatus := func()(string, error){
currentValueExists, currentValue, err := myLocalDesires.GetDesire("OffspringProbabilityOfAnyMonogenicDisease_Maximum")
if (err != nil){ return "", err }
if (currentValueExists == false || currentValue == "100"){
result := translate("0-100% (No Preference)")
return result, nil
}
if (currentValue == "99"){
return "0-99%", nil
}
if (currentValue != "0"){
return "", errors.New("MyLocalDesires malformed: Invalid OffspringProbabilityOfAnyMonogenicDisease_Maximum: " + currentValue)
}
return "0%", nil
}
currentDesireStatus, err := getCurrentDesireStatus()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
myDesireLabel := widget.NewLabel("My Desire:")
currentStatusText := getBoldLabel(currentDesireStatus)
currentStatusRow := container.NewHBox(layout.NewSpacer(), myDesireLabel, currentStatusText, layout.NewSpacer())
desireOptionsList := []string{"0%", "0-99%", "0-100%"}
desireSelector := widget.NewSelect(desireOptionsList, func(newSelection string){
if (newSelection == "0-100%"){
err = myLocalDesires.DeleteDesire("OffspringProbabilityOfAnyMonogenicDisease_Maximum")
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
getNewMaximumBound := func()string{
if (newSelection == "0%"){
return "0"
}
// newSelection == "0-99%"
return "99"
}
newMaximumBound := getNewMaximumBound()
err = myLocalDesires.SetDesire("OffspringProbabilityOfAnyMonogenicDisease_Maximum", newMaximumBound)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
if (currentDesireStatus == translate("0-100% (No Preference)")){
desireSelector.Selected = "0-100%"
} else {
desireSelector.Selected = currentDesireStatus
}
desireSelectorCentered := getWidgetCentered(desireSelector)
filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "OffspringProbabilityOfAnyMonogenicDisease", false)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Offspring Has Any Monogenic Disease Probability", "OffspringProbabilityOfAnyMonogenicDisease", true, "Donut", "OffspringProbabilityOfAnyMonogenicDisease", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4Row, widget.NewSeparator(), description5Row, description6, description7, widget.NewSeparator(), currentStatusRow, desireSelectorCentered, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_Height(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_Height(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Height")
description := getLabelCentered("Choose your desired height.")
metricOrImperialSwitchButton, err := getMetricImperialSwitchButton(window, currentPage)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
currentUnitsLabel := getItalicLabel("Current Units:")
currentUnitsRow := container.NewHBox(layout.NewSpacer(), currentUnitsLabel, metricOrImperialSwitchButton, layout.NewSpacer())
getMyMetricOrImperial := 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
}
myMetricOrImperial, err := getMyMetricOrImperial()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
getBoundColumn := func(minimumOrMaximum string)(*fyne.Container, error){
if (minimumOrMaximum != "Minimum" && minimumOrMaximum != "Maximum"){
return nil, errors.New("getBoundColumn called with invalid minimumOrMaximum: " + minimumOrMaximum)
}
desireBoundName := "Height_" + minimumOrMaximum
boundLabel := getBoldLabelCentered(minimumOrMaximum)
myBoundExists, myCurrentBound, err := myLocalDesires.GetDesire(desireBoundName)
if (err != nil) { return nil, err }
getMyBoundLabel := func()(*fyne.Container, error){
if (myBoundExists == false){
noneLabel := getBoldItalicLabelCentered(translate("None"))
return noneLabel, nil
}
myCurrentBoundFloat64, err := helpers.ConvertStringToFloat64(myCurrentBound)
if (err != nil) {
return nil, errors.New("My current height " + minimumOrMaximum + " desire is invalid: " + myCurrentBound)
}
if (myMetricOrImperial == "Metric"){
myCurrentBoundRounded := helpers.ConvertFloat64ToStringRounded(myCurrentBoundFloat64, 2)
myBoundLabel := getBoldLabelCentered(myCurrentBoundRounded + " " + translate("centimeters"))
return myBoundLabel, nil
}
feetInchesString, err := helpers.ConvertCentimetersToFeetInchesTranslatedString(myCurrentBoundFloat64)
if (err != nil) { return nil, err }
myBoundLabel := getBoldLabelCentered(feetInchesString)
return myBoundLabel, nil
}
myBoundLabel, err := getMyBoundLabel()
if (err != nil){ return nil, err }
minimumOrMaximumLowercase := strings.ToLower(minimumOrMaximum)
//Outputs:
// -fyne.Container: Bound entry (either metric or imperial)
// -fyne.Widget: Submit button
// -error
getBoundEntryAndSubmitButton := func()(*fyne.Container, fyne.Widget, error){
if (myMetricOrImperial == "Metric"){
boundEntry := widget.NewEntry()
boundEntryBoxed := getWidgetBoxed(boundEntry)
if (myBoundExists == true){
currentBoundFloat64, err := helpers.ConvertStringToFloat64(myCurrentBound)
if (err != nil) { return nil, nil, err }
if (currentBoundFloat64 < 30 || currentBoundFloat64 > 400) {
return nil, nil, errors.New("My desires malformed: Contains invalid height desire: " + myCurrentBound)
}
myCurrentBoundRounded := helpers.ConvertFloat64ToStringRounded(currentBoundFloat64, 2)
boundEntry.SetText(myCurrentBoundRounded)
} else {
boundEntry.SetPlaceHolder(translate("Enter " + minimumOrMaximumLowercase + "..."))
}
saveBoundButton := widget.NewButtonWithIcon(translate("Save"), theme.ConfirmIcon(), func(){
newHeightBound := boundEntry.Text
if (newHeightBound == ""){
err := myLocalDesires.DeleteDesire(desireBoundName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
//TODO: If min is greater than max, delete min
newHeightBoundFloat64, err := helpers.ConvertStringToFloat64(newHeightBound)
if (err != nil){
title := translate("Invalid " + minimumOrMaximum + " Height")
dialogMessage := getLabelCentered(translate("Your height bound must be a number."))
dialogContent := container.NewVBox(dialogMessage)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
if (newHeightBoundFloat64 < 30 || newHeightBoundFloat64 > 400){
title := translate("Invalid " + minimumOrMaximum + " Height")
dialogMessage := getLabelCentered(translate("Your height desire must be a number between 30 and 400."))
dialogContent := container.NewVBox(dialogMessage)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
err = myLocalDesires.SetDesire(desireBoundName, newHeightBound)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
return boundEntryBoxed, saveBoundButton, nil
}
feetEntry := widget.NewEntry()
inchesEntry := widget.NewEntry()
feetLabel := getBoldLabel(translate("feet"))
inchesLabel := getBoldLabel(translate("inches"))
entryRow := container.NewGridWithRows(1, feetEntry, feetLabel, inchesEntry, inchesLabel)
if (myBoundExists == true){
currentBoundFloat64, err := helpers.ConvertStringToFloat64(myCurrentBound)
if (err != nil) { return nil, nil, err }
if (currentBoundFloat64 < 30 || currentBoundFloat64 > 400) {
return nil, nil, errors.New("My desires malformed: Contains invalid height desire: " + myCurrentBound)
}
feetInt, inchesFloat, err := helpers.ConvertCentimetersToFeetInches(currentBoundFloat64)
if (err != nil) {
return nil, nil, errors.New("My desires malformed: Contains invalid height desire: " + myCurrentBound)
}
feetString := helpers.ConvertIntToString(feetInt)
inchesString := helpers.ConvertFloat64ToStringRounded(inchesFloat, 1)
feetEntry.SetText(feetString)
inchesEntry.SetText(inchesString)
} else {
feetEntry.SetPlaceHolder(translate("Enter " + minimumOrMaximumLowercase + "..."))
inchesEntry.SetPlaceHolder(translate("Enter " + minimumOrMaximumLowercase + "..."))
}
saveBoundButton := widget.NewButtonWithIcon(translate("Save"), theme.ConfirmIcon(), func(){
newHeightFeetBound := feetEntry.Text
newHeightInchesBound := inchesEntry.Text
if (newHeightFeetBound == "" && newHeightInchesBound == ""){
err := myLocalDesires.DeleteDesire(desireBoundName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
return
}
newFeetBoundInt, err := helpers.ConvertStringToInt(newHeightFeetBound)
if (err != nil){
title := translate("Invalid " + minimumOrMaximum + " Feet")
dialogMessage := getLabelCentered(translate("Your feet bound must be a number."))
dialogContent := container.NewVBox(dialogMessage)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
newInchesBoundFloat64, err := helpers.ConvertStringToFloat64(newHeightInchesBound)
if (err != nil){
title := translate("Invalid " + minimumOrMaximum + " Inches")
dialogMessage := getLabelCentered(translate("Your inches bound must be a number."))
dialogContent := container.NewVBox(dialogMessage)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
newCentimetersBound, err := helpers.ConvertFeetInchesToCentimeters(newFeetBoundInt, newInchesBoundFloat64)
if (err != nil){
title := translate("Invalid " + minimumOrMaximum + " Height")
dialogMessage := getLabelCentered(translate("Your height bound must be a positive number."))
dialogContent := container.NewVBox(dialogMessage)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
if (newCentimetersBound < 30 || newCentimetersBound > 400){
title := translate("Invalid " + minimumOrMaximum + " Height")
dialogMessage := getLabelCentered(translate("Your height bound must be between 30 and 400 centimeters."))
dialogContent := container.NewVBox(dialogMessage)
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
return
}
newCentimetersBoundString := helpers.ConvertFloat64ToString(newCentimetersBound)
err = myLocalDesires.SetDesire(desireBoundName, newCentimetersBoundString)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
return entryRow, saveBoundButton, nil
}
boundEntryRow, saveBoundButton, err := getBoundEntryAndSubmitButton()
if (err != nil){ return nil, err }
deleteBoundButton := widget.NewButtonWithIcon(translate("No Preference"), theme.CancelIcon(), func(){
if (myBoundExists == false){
return
}
err := myLocalDesires.DeleteDesire(desireBoundName)
if (err != nil){
setErrorEncounteredPage(window, err, currentPage)
return
}
currentPage()
})
boundColumn := getContainerCentered(container.NewVBox(boundLabel, widget.NewSeparator(), myBoundLabel, widget.NewSeparator(), boundEntryRow, saveBoundButton, deleteBoundButton))
return boundColumn, nil
}
minimumColumn, err := getBoundColumn("Minimum")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
maximumColumn, err := getBoundColumn("Maximum")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
boundColumns := getContainerCentered(container.NewGridWithRows(1, minimumColumn, maximumColumn))
filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "Height", true)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Height", "Height", true, "Bar", "Height", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), currentUnitsRow, widget.NewSeparator(), boundColumns, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_BodyFat(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_BodyFat(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Body Fat")
description1 := getLabelCentered("Choose your body fat desires.")
description2 := getLabelCentered("Select each rating which you desire.")
description3 := getLabelCentered("1/4 = Least body fat, 4/4 = Most body fat.")
optionTitlesList := []string{"1/4", "2/4", "3/4", "4/4"}
optionNamesMap := map[string][]string{
"1/4": []string{"1"},
"2/4": []string{"2"},
"3/4": []string{"3"},
"4/4": []string{"4"},
}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "BodyFat", optionTitlesList, optionNamesMap, false, true, 1)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Body Fat", "BodyFat", true, "Donut", "BodyFat", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_BodyMuscle(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_BodyMuscle(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Body Muscle")
description1 := getLabelCentered("Choose your body muscle desires.")
description2 := getLabelCentered("Select each rating which you desire.")
description3 := getLabelCentered("1/4 = Least body muscle, 4/4 = Most body muscle.")
optionTitlesList := []string{"1/4", "2/4", "3/4", "4/4"}
optionNamesMap := map[string][]string{
"1/4": []string{"1"},
"2/4": []string{"2"},
"3/4": []string{"3"},
"4/4": []string{"4"},
}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "BodyMuscle", optionTitlesList, optionNamesMap, false, true, 1)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Body Muscle", "BodyMuscle", true, "Donut", "BodyMuscle", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_EyeColor(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_EyeColor(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Eye Color")
description1 := getLabelCentered("Choose your eye color desires.")
description2 := getLabelCentered("Select each eye color that you desire.")
optionTitlesList := []string{"Blue", "Green", "Brown", "Amber", "Blue+Green", "Blue+Brown", "Blue+Amber", "Amber+Brown", "Green+Brown", "Green+Amber", "Green+Amber+Brown", "Blue+Amber+Brown", "Blue+Green+Brown", "Blue+Green+Amber", "Blue+Green+Amber+Brown"}
optionNamesMap := make(map[string][]string)
optionNamesMap["Blue"] = []string{"Blue"}
optionNamesMap["Green"] = []string{"Green"}
optionNamesMap["Brown"] = []string{"Brown"}
optionNamesMap["Amber"] = []string{"Amber"}
optionNamesMap["Blue+Green"] = []string{"Blue+Green", "Green+Blue"}
optionNamesMap["Blue+Brown"] = []string{"Blue+Brown", "Brown+Blue"}
optionNamesMap["Blue+Amber"] = []string{"Blue+Amber", "Amber+Blue"}
optionNamesMap["Amber+Brown"] = []string{"Amber+Brown", "Brown+Amber"}
optionNamesMap["Green+Brown"] = []string{"Green+Brown", "Brown+Green"}
optionNamesMap["Green+Amber"] = []string{"Green+Amber", "Amber+Green"}
optionNamesMap["Green+Amber+Brown"] = []string{"Green+Amber+Brown", "Green+Brown+Amber", "Amber+Green+Brown", "Amber+Brown+Green", "Brown+Amber+Green", "Brown+Green+Amber"}
optionNamesMap["Blue+Amber+Brown"] = []string{"Blue+Amber+Brown", "Blue+Brown+Amber", "Amber+Blue+Brown", "Amber+Brown+Blue", "Brown+Amber+Blue", "Brown+Blue+Amber"}
optionNamesMap["Blue+Green+Brown"] = []string{"Blue+Green+Brown", "Blue+Brown+Green", "Green+Blue+Brown", "Green+Brown+Blue", "Brown+Green+Blue", "Brown+Blue+Green"}
optionNamesMap["Blue+Green+Amber"] = []string{"Blue+Green+Amber", "Blue+Amber+Green", "Green+Blue+Amber", "Green+Amber+Blue", "Amber+Green+Blue", "Amber+Blue+Green"}
optionNamesMap["Blue+Green+Amber+Brown"] = []string{"Blue+Green+Brown+Amber", "Blue+Green+Amber+Brown", "Blue+Brown+Green+Amber", "Blue+Brown+Amber+Green", "Blue+Amber+Green+Brown", "Blue+Amber+Brown+Green", "Green+Blue+Brown+Amber", "Green+Blue+Amber+Brown", "Green+Brown+Blue+Amber", "Green+Brown+Amber+Blue", "Green+Amber+Blue+Brown", "Green+Amber+Brown+Blue", "Brown+Blue+Green+Amber", "Brown+Blue+Amber+Green", "Brown+Green+Blue+Amber", "Brown+Green+Amber+Blue", "Brown+Amber+Blue+Green", "Brown+Amber+Green+Blue", "Amber+Blue+Green+Brown", "Amber+Blue+Brown+Green", "Amber+Green+Blue+Brown", "Amber+Green+Brown+Blue", "Amber+Brown+Blue+Green", "Amber+Brown+Green+Blue"}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "EyeColor", optionTitlesList, optionNamesMap, false, true, 2)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Eye Color", "EyeColor", true, "Donut", "EyeColor", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_HairColor(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_HairColor(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Hair Color")
description1 := getLabelCentered("Choose your natural hair color desires.")
description2 := getLabelCentered("Select each natural hair color that you desire.")
optionTitlesList := []string{"Black", "Brown", "Blonde", "Orange", "Black+Brown", "Black+Blonde", "Black+Orange", "Brown+Blonde", "Brown+Orange", "Blonde+Orange"}
//TODO: Add color guide page, so users can see the colors
// We already have this on the Build Profile page for hair/eye color
optionNamesMap := make(map[string][]string)
optionNamesMap["Black"] = []string{"Black"}
optionNamesMap["Brown"] = []string{"Brown"}
optionNamesMap["Blonde"] = []string{"Blonde"}
optionNamesMap["Orange"] = []string{"Orange"}
optionNamesMap["Black+Brown"] = []string{"Black+Brown", "Brown+Black"}
optionNamesMap["Black+Blonde"] = []string{"Black+Blonde", "Blonde+Black"}
optionNamesMap["Black+Orange"] = []string{"Black+Orange", "Orange+Black"}
optionNamesMap["Brown+Blonde"] = []string{"Brown+Blonde", "Blonde+Brown"}
optionNamesMap["Brown+Orange"] = []string{"Brown+Orange", "Orange+Brown"}
optionNamesMap["Blonde+Orange"] = []string{"Blonde+Orange", "Orange+Blonde"}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "HairColor", optionTitlesList, optionNamesMap, false, true, 2)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Hair Color", "HairColor", true, "Donut", "HairColor", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_HairTexture(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_HairTexture(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Hair Texture")
description1 := getLabelCentered("Choose your hair texture desires.")
description2 := getLabelCentered("Select each hair texture that you desire.")
// These descriptions are taken from 23andMe.
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")
optionTitlesList := []string{option1Translated, option2Translated, option3Translated, option4Translated, option5Translated, option6Translated}
optionNamesMap := map[string][]string{
option1Translated: []string{"1"},
option2Translated: []string{"2"},
option3Translated: []string{"3"},
option4Translated: []string{"4"},
option5Translated: []string{"5"},
option6Translated: []string{"6"},
}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "HairTexture", optionTitlesList, optionNamesMap, false, true, 1)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Hair Texture", "HairTexture", true, "Donut", "HairTexture", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_SkinColor(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_SkinColor(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Skin Color")
description1 := getLabelCentered("Choose your skin color desires.")
description2 := getLabelCentered("Select each skin color that you desire.")
description3 := getLabelCentered("Skin color can change under different conditions.")
description4 := getLabelCentered("You may want to select multiple options to account for this.")
getSkinColorExampleColumn := func(colorIdentifier string, colorCode string)(*fyne.Container, error){
colorSquare, err := getColorSquareAsFyneImage(colorCode)
if (err != nil){ return nil, err }
colorSquare.FillMode = canvas.ImageFillStretch
colorIdentifierLabel := getBoldLabelCentered(colorIdentifier)
colorColumn := container.NewGridWithColumns(1, colorSquare, colorIdentifierLabel)
return colorColumn, nil
}
skinColorColumn_1, err := getSkinColorExampleColumn("1", "f4e3da")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_2, err := getSkinColorExampleColumn("2", "f5d6b9")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_3, err := getSkinColorExampleColumn("3", "dabe91")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_4, err := getSkinColorExampleColumn("4", "ba9175")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_5, err := getSkinColorExampleColumn("5", "916244")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorColumn_6, err := getSkinColorExampleColumn("6", "744d2d")
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
skinColorExamplesRow := container.NewHBox(layout.NewSpacer(), skinColorColumn_1, skinColorColumn_2, skinColorColumn_3, skinColorColumn_4, skinColorColumn_5, skinColorColumn_6, layout.NewSpacer())
optionTitlesList := []string{"1", "2", "3", "4", "5", "6"}
optionNamesMap := map[string][]string{
"1": []string{"1"},
"2": []string{"2"},
"3": []string{"3"},
"4": []string{"4"},
"5": []string{"5"},
"6": []string{"6"},
}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "SkinColor", optionTitlesList, optionNamesMap, false, true, 6)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Skin Color", "SkinColor", true, "Donut", "SkinColor", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), skinColorExamplesRow, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_Infections(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_Infections(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Infections")
description1 := getLabelCentered("Choose your infection desires.")
hivButton := widget.NewButton("HIV", func(){
setChooseDesiresPage_HIV(window, currentPage)
})
genitalHerpesButton := widget.NewButton("Genital Herpes", func(){
setChooseDesiresPage_GenitalHerpes(window, currentPage)
})
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, hivButton, genitalHerpesButton))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, widget.NewSeparator(), buttonsGrid)
setPageContent(page, window)
}
func setChooseDesiresPage_HIV(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_HIV(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("HIV")
description1 := getLabelCentered("Choose your HIV desires.")
description2 := getLabelCentered("Select each option which you desire.")
description3 := getLabelCentered("Positive = Has disease, Negative = Does not have disease.")
optionTitlesList := []string{"HIV Positive", "HIV Negative"}
optionNamesMap := map[string][]string{
"HIV Positive": []string{"Yes"},
"HIV Negative": []string{"No"},
}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "HasHIV", optionTitlesList, optionNamesMap, false, true, 1)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Has HIV", "HasHIV", true, "Donut", "HasHIV", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}
func setChooseDesiresPage_GenitalHerpes(window fyne.Window, previousPage func()){
currentPage := func(){setChooseDesiresPage_GenitalHerpes(window, previousPage)}
title := getPageTitleCentered(translate("My Mate Desires - Physical"))
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Genital Herpes")
description1 := getLabelCentered("Choose your Genital Herpes desires.")
description2 := getLabelCentered("Select each option which you desire.")
description3 := getLabelCentered("Positive = Has disease, Negative = Does not have disease.")
optionTitlesList := []string{"Genital Herpes Positive", "Genital Herpes Negative"}
optionNamesMap := map[string][]string{
"Genital Herpes Positive": []string{"Yes"},
"Genital Herpes Negative": []string{"No"},
}
desireEditor, err := getDesireEditor_Choice(window, currentPage, "HasGenitalHerpes", optionTitlesList, optionNamesMap, false, true, 1)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
setViewMyMateDesireStatisticsPage(window, "Has Genital Herpes", "HasGenitalHerpes", true, "Donut", "HasGenitalHerpes", currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton)
setPageContent(page, window)
}