package gui //desiresGui_General.go implements pages to view and manage a user's General mate desires, view all their desires, and manage their download desires import "fyne.io/fyne/v2" import "fyne.io/fyne/v2/container" import "fyne.io/fyne/v2/dialog" import "fyne.io/fyne/v2/layout" import "fyne.io/fyne/v2/theme" import "fyne.io/fyne/v2/widget" import "seekia/resources/worldLanguages" import "seekia/resources/worldLocations" import "seekia/internal/allowedText" import "seekia/internal/appMemory" import "seekia/internal/desires/mateDesires" import "seekia/internal/desires/myLocalDesires" import "seekia/internal/encoding" import "seekia/internal/globalSettings" import "seekia/internal/helpers" import "seekia/internal/network/myMateCriteria" import "seekia/internal/profiles/attributeDisplay" import "strings" import "errors" import "slices" func setDesiresPage(window fyne.Window){ appMemory.SetMemoryEntry("CurrentViewedPage", "Desires") currentPage := func(){setDesiresPage(window)} title := getPageTitleCentered(translate("My Mate Desires")) description1 := getLabelCentered(translate("Select your Mate desires.")) description2 := getLabelCentered(translate("Your desires are used to generate your matches.")) description3 := getLabelCentered(translate("These desires not shared on your profile.")) generalIcon, err := getFyneImageIcon("General") if (err != nil){ setErrorEncounteredPage(window, err, func(){setHomePage(window)}) return } generalButton := widget.NewButton(translate("General"), func(){ setChooseDesiresCategoryPage_General(window, currentPage) }) generalButtonWithIcon := container.NewGridWithRows(2, generalIcon, generalButton) physicalIcon, err := getFyneImageIcon("Person") if (err != nil){ setErrorEncounteredPage(window, err, func(){setHomePage(window)}) return } physicalButton := widget.NewButton(translate("Physical"), func(){ setChooseDesiresCategoryPage_Physical(window, currentPage) }) physicalButtonWithIcon := container.NewGridWithRows(2, physicalIcon, physicalButton) lifestyleIcon, err := getFyneImageIcon("Lifestyle") if (err != nil){ setErrorEncounteredPage(window, err, func(){setHomePage(window)}) return } lifestyleButton := widget.NewButton(translate("Lifestyle"), func(){ setChooseDesiresCategoryPage_Lifestyle(window, currentPage) }) lifestyleButtonWithIcon := container.NewGridWithRows(2, lifestyleIcon, lifestyleButton) mentalIcon, err := getFyneImageIcon("Mental") if (err != nil){ setErrorEncounteredPage(window, err, func(){setHomePage(window)}) return } mentalButton := widget.NewButton(translate("Mental"), func(){ setChooseDesiresCategoryPage_Mental(window, currentPage) }) mentalButtonWithIcon := container.NewGridWithRows(2, mentalIcon, mentalButton) categoriesRow := getContainerCentered(container.NewGridWithRows(1, generalButtonWithIcon, physicalButtonWithIcon, lifestyleButtonWithIcon, mentalButtonWithIcon)) allDesiresIcon, err := getFyneImageIcon("Choice") if (err != nil){ setErrorEncounteredPage(window, err, func(){setHomePage(window)}) return } viewAllDesiresButton := widget.NewButton("View All Desires", func(){ setViewAllMyDesiresPage(window, currentPage) }) viewAllDesiresButtonWithIcon := container.NewGridWithRows(2, allDesiresIcon, viewAllDesiresButton) statisticsIcon, err := getFyneImageIcon("Stats") if (err != nil){ setErrorEncounteredPage(window, err, func(){setHomePage(window)}) return } viewAllStatisticsButton := widget.NewButton("View All Statistics", func(){ setViewAllMyDesireStatisticsPage(window, false, 0, 0, nil, currentPage) }) viewAllStatisticsButtonWithIcon := container.NewGridWithColumns(1, statisticsIcon, viewAllStatisticsButton) viewAllButtonsRow := getContainerCentered(container.NewGridWithRows(1, viewAllDesiresButtonWithIcon, viewAllStatisticsButtonWithIcon)) downloadDesiresIcon, err := getFyneImageIcon("Host") if (err != nil){ setErrorEncounteredPage(window, err, func(){setHomePage(window)}) return } downloadDesiresButton := widget.NewButton("Download Desires", func(){ setManageMateDownloadDesiresPage(window, currentPage) }) downloadDesiresButtonWithIcon := getContainerCentered(container.NewGridWithRows(2, downloadDesiresIcon, downloadDesiresButton)) page := container.NewVBox(title, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), categoriesRow, widget.NewSeparator(), viewAllButtonsRow, widget.NewSeparator(), downloadDesiresButtonWithIcon) setPageContent(page, window) } func setChooseDesiresCategoryPage_General(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresCategoryPage_General(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) profileLanguageButton := widget.NewButton("Profile Language", func(){ setChooseDesiresPage_ProfileLanguage(window, currentPage) }) distanceButton := widget.NewButton("Distance", func(){ setChooseDesiresPage_Distance(window, currentPage) }) countryButton := widget.NewButton("Country", func(){ setChooseDesiresPage_Country(window, currentPage) }) sexualityButton := widget.NewButton("Sexuality", func(){ setChooseDesiresPage_Sexuality(window, currentPage) }) searchTermsButton := widget.NewButton("Search Terms", func(){ setChooseDesiresPage_SearchTerms(window, currentPage) }) chatButton := widget.NewButton("Chat", func(){ setChooseDesiresPage_Chat(window, currentPage) }) likedUsersButton := widget.NewButton("Liked Users", func(){ setChooseDesiresPage_LikedUsers(window, currentPage) }) ignoredUsersButton := widget.NewButton("Ignored Users", func(){ setChooseDesiresPage_IgnoredUsers(window, currentPage) }) contactsButton := widget.NewButton("Contacts", func(){ setChooseDesiresPage_Contacts(window, currentPage) }) buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, profileLanguageButton, distanceButton, countryButton, sexualityButton, searchTermsButton, chatButton, likedUsersButton, ignoredUsersButton, contactsButton)) buttonsGridPadded := container.NewPadded(buttonsGrid) page := container.NewVBox(title, backButton, widget.NewSeparator(), buttonsGridPadded) setPageContent(page, window) } func setChooseDesiresPage_ProfileLanguage(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_ProfileLanguage(window, previousPage)} title := getPageTitleCentered("My Mate Desires - General") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Profile Language") description1 := getLabelCentered("Choose your profile language desires.") description2 := getLabelCentered("A profile language is the language that a profile is written in.") description3 := getLabelCentered("Choose all of the languages you can read.") getSelectedLanguagesSection := func()(*fyne.Container, error){ getCurrentDesiredChoicesList := func()([]string, error){ currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("ProfileLanguage") 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 } addLanguageButton := getWidgetCentered(widget.NewButtonWithIcon("Add Language", theme.ContentAddIcon(), func(){ submitLanguageFunction := func(newLanguageIdentifier int, _ string)error{ newLanguageIdentifierString := helpers.ConvertIntToString(newLanguageIdentifier) newLanguageIdentifierBase64 := encoding.EncodeBytesToBase64String([]byte(newLanguageIdentifierString)) newLanguagesList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, newLanguageIdentifierBase64) newDesireString := strings.Join(newLanguagesList, "+") err = myLocalDesires.SetDesire("ProfileLanguage", newDesireString) if (err != nil){ return err } return nil } setChooseDesiresPage_AddLanguage(window, submitLanguageFunction, currentPage, currentPage) })) if (len(currentDesiredChoicesList) == 0){ noLanguagesLabel := getBoldLabelCentered("No Languages Selected.") selectedLanguagesSection := container.NewVBox(noLanguagesLabel, addLanguageButton) return selectedLanguagesSection, nil } myDesiredLanguagesLabel := getItalicLabelCentered("My Desired Languages:") languageNameColumn := container.NewVBox(widget.NewSeparator()) deleteButtonsColumn := container.NewVBox(widget.NewSeparator()) for _, languageIdentifierBase64 := range currentDesiredChoicesList{ languageIdentifierString, err := encoding.DecodeBase64StringToUnicodeString(languageIdentifierBase64) if (err != nil){ return nil, errors.New("My current profile language desire is malformed: Contains invalid language: " + languageIdentifierBase64) } languageIdentifier, err := helpers.ConvertStringToInt(languageIdentifierString) if (err != nil){ return nil, errors.New("My current profile language desire is malformed: Contains invalid language: " + languageIdentifierString) } languageObject, err := worldLanguages.GetLanguageObjectFromLanguageIdentifier(languageIdentifier) if (err != nil){ return nil, errors.New("My current profile language desire is malformed: Contains unknown language identifier: " + languageIdentifierString) } languageNamesList := languageObject.NamesList languageDescription := helpers.TranslateAndJoinStringListItems(languageNamesList, "/") languageDescriptionTrimmed, _, err := helpers.TrimAndFlattenString(languageDescription, 20) if (err != nil) { return nil, err } languageNameLabel := getBoldLabelCentered(languageDescriptionTrimmed) deleteLanguageButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){ newDesiredLanguagesList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, languageIdentifierBase64) if (len(newDesiredLanguagesList) == 0){ err := myLocalDesires.DeleteDesire("ProfileLanguage") if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() return } newDesireValueString := strings.Join(newDesiredLanguagesList, "+") err := myLocalDesires.SetDesire("ProfileLanguage", newDesireValueString) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() }) languageNameColumn.Add(languageNameLabel) deleteButtonsColumn.Add(deleteLanguageButton) languageNameColumn.Add(widget.NewSeparator()) deleteButtonsColumn.Add(widget.NewSeparator()) } languagesGrid := container.NewHBox(layout.NewSpacer(), languageNameColumn, deleteButtonsColumn, layout.NewSpacer()) selectedLanguagesSection := container.NewVBox(addLanguageButton, widget.NewSeparator(), myDesiredLanguagesLabel, languagesGrid) return selectedLanguagesSection, nil } selectedLanguagesSection, err := getSelectedLanguagesSection() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "ProfileLanguage", true) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Profile Language", "ProfileLanguage", true, "Bar", "ProfileLanguage", currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), selectedLanguagesSection, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton) setPageContent(page, window) } func setChooseDesiresPage_Distance(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_Distance(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered(translate("Distance")) description1 := getLabelCentered("Choose your desired user distance.") description2 := getLabelCentered("You must add a primary location to your profile to calculate distance.") 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 } getCurrentUnits := func()string{ if (myMetricOrImperial == "Metric"){ return "kilometers" } return "miles" } currentUnits := getCurrentUnits() // Distance is normally represented in metric // Metric is the standard, and Imperial is custom getUnitsAreCustomBool := func()bool{ if (myMetricOrImperial == "Metric"){ return false } return true } unitsAreCustomBool := getUnitsAreCustomBool() convertToMetricFunction := helpers.ConvertMilesToKilometers convertToImperialFunction := helpers.ConvertKilometersToMiles desireEditor, err := getDesireEditor_Numeric(window, currentPage, "Distance", 0, 20000, currentUnits, 2, unitsAreCustomBool, convertToMetricFunction, convertToImperialFunction, false, "", "", nil) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Distance", "Distance", true, "Bar", "Distance", currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), currentUnitsRow, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton) setPageContent(page, window) } func setChooseDesiresPage_Country(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_Country(window, previousPage)} title := getPageTitleCentered("My Mate Desires - General") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Country") description1 := getLabelCentered("Choose your country desires.") description2 := getLabelCentered("Select the countries where you want your matches to live in.") description3 := getLabelCentered("Most users should only use this desire if they live near a border.") description4 := getLabelCentered("Most users should only need to use the Distance desire.") getSelectedCountriesSection := func()(*fyne.Container, error){ getCurrentDesiredChoicesList := func()([]string, error){ currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("PrimaryLocationCountry") 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 } addCountryButton := getWidgetCentered(widget.NewButtonWithIcon("Add Country", theme.ContentAddIcon(), func(){ setChooseMateDesiresPage_ChooseCountry(window, currentPage, currentPage) })) if (len(currentDesiredChoicesList) == 0){ noCountriesLabel := getBoldLabelCentered("No Countries Selected.") selectedCountriesSection := container.NewVBox(noCountriesLabel, addCountryButton) return selectedCountriesSection, nil } myDesiredCountriesLabel := getItalicLabelCentered("My Desired Countries:") countryNameColumn := container.NewVBox(widget.NewSeparator()) deleteButtonsColumn := container.NewVBox(widget.NewSeparator()) for _, countryIdentifierBase64 := range currentDesiredChoicesList{ countryIdentifierString, err := encoding.DecodeBase64StringToUnicodeString(countryIdentifierBase64) if (err != nil){ return nil, errors.New("My current profile country desire is malformed: Contains invalid country: " + countryIdentifierBase64) } countryIdentifier, err := helpers.ConvertStringToInt(countryIdentifierString) if (err != nil){ return nil, errors.New("My current profile country desire is malformed: Contains invalid country: " + countryIdentifierString) } countryObject, err := worldLocations.GetCountryObjectFromCountryIdentifier(countryIdentifier) if (err != nil){ return nil, errors.New("My current profile country is malformed: Contains unknown country identifier: " + countryIdentifierString) } countryNamesList := countryObject.NamesList countryDescription := helpers.TranslateAndJoinStringListItems(countryNamesList, "/") countryNameLabel := getBoldLabelCentered(countryDescription) deleteCountryButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){ newDesiredCountriesList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, countryIdentifierBase64) if (len(newDesiredCountriesList) == 0){ err := myLocalDesires.DeleteDesire("PrimaryLocationCountry") if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() return } newDesireValueString := strings.Join(newDesiredCountriesList, "+") err := myLocalDesires.SetDesire("PrimaryLocationCountry", newDesireValueString) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() }) countryNameColumn.Add(countryNameLabel) deleteButtonsColumn.Add(deleteCountryButton) countryNameColumn.Add(widget.NewSeparator()) deleteButtonsColumn.Add(widget.NewSeparator()) } countriesGrid := container.NewHBox(layout.NewSpacer(), countryNameColumn, deleteButtonsColumn, layout.NewSpacer()) selectedCountriesSection := container.NewVBox(addCountryButton, widget.NewSeparator(), myDesiredCountriesLabel, countriesGrid) return selectedCountriesSection, nil } selectedCountriesSection, err := getSelectedCountriesSection() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "PrimaryLocationCountry", true) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Country", "PrimaryLocationCountry", true, "Donut", "PrimaryLocationCountry", currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), selectedCountriesSection, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton) setPageContent(page, window) } func setChooseMateDesiresPage_ChooseCountry(window fyne.Window, previousPage func(), nextPage func()){ currentPage := func(){setChooseMateDesiresPage_ChooseCountry(window, previousPage, nextPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered(translate("Add Country")) description1 := getLabelCentered("Choose the country to add.") allCountryObjectsList, err := worldLocations.GetAllCountryObjectsList() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } allTranslatedCountriesList := make([]string, 0, len(allCountryObjectsList)) // Map Structure: Country Description -> Country identifier countryIdentifiersMap := make(map[string]int) for _, countryObject := range allCountryObjectsList{ countryIdentifier := countryObject.Identifier countryNamesList := countryObject.NamesList countryDescription := helpers.TranslateAndJoinStringListItems(countryNamesList, "/") countryIdentifiersMap[countryDescription] = countryIdentifier allTranslatedCountriesList = append(allTranslatedCountriesList, countryDescription) } helpers.SortStringListToUnicodeOrder(allTranslatedCountriesList) onSelectedFunction := func(selectedCountryIndex int) { selectedCountryDescription := allTranslatedCountriesList[selectedCountryIndex] selectedCountryIdentifier, exists := countryIdentifiersMap[selectedCountryDescription] if (exists == false){ setErrorEncounteredPage(window, errors.New("countryIdentifiersMap missing country description."), currentPage) return } selectedCountryIdentifierString := helpers.ConvertIntToString(selectedCountryIdentifier) newCountryIdentifierBase64 := encoding.EncodeBytesToBase64String([]byte(selectedCountryIdentifierString)) getNewDesiredAttributeList := func()([]string, error){ currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("PrimaryLocationCountry") if (err != nil) { return nil, err } if (currentChoicesListExists == false){ newList := []string{newCountryIdentifierBase64} return newList, nil } //currentChoicesList is a "+" separated list of choices // Each choice option is encoded in base64 currentDesiredChoicesList := strings.Split(currentChoicesList, "+") newCountriesList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, newCountryIdentifierBase64) return newCountriesList, nil } newDesiredAttributeList, err := getNewDesiredAttributeList() if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } newDesireString := strings.Join(newDesiredAttributeList, "+") err = myLocalDesires.SetDesire("PrimaryLocationCountry", newDesireString) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } nextPage() } widgetList, err := getFyneWidgetListFromStringList(allTranslatedCountriesList, onSelectedFunction) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } header := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, widget.NewSeparator()) page := container.NewBorder(header, nil, nil, nil, widgetList) setPageContent(page, window) } func setChooseDesiresPage_Sexuality(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_Sexuality(window, previousPage)} title := getPageTitleCentered("My Mate Desires - General") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered(translate("Sexuality")) description1 := getLabelCentered("Choose the user sexualities that you desire.") description2 := getLabelCentered("This refers to which sexes the users are interested in.") description3 := getLabelCentered("For example, if you are Male, you should at least select Male.") option1Translated := translate("Male") option2Translated := translate("Female") option3Translated := translate("Male And Female") optionTitlesList := []string{option1Translated, option2Translated, option3Translated} optionNamesMap := map[string][]string{ option1Translated: []string{"Male"}, option2Translated: []string{"Female"}, option3Translated: []string{"Male And Female"}, } desireEditor, err := getDesireEditor_Choice(window, currentPage, "Sexuality", optionTitlesList, optionNamesMap, false, true, 1) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Sexuality", "Sexuality", true, "Donut", "Sexuality", 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_SearchTerms(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_SearchTerms(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Search Terms") description1 := getLabelCentered("Choose your desired search terms.") description2 := getLabelCentered("Seekia will search through each user's profile for your terms.") description3 := getLabelCentered("Each user's description, tags, hobbies, and beliefs will be searched.") description4 := getLabelCentered("A user's profile must contain at least 1 of your terms to pass the desire.") getSelectedSearchTermsSection := func()(*fyne.Container, error){ getCurrentDesiredChoicesList := func()([]string, error){ currentChoicesListExists, currentChoicesList, err := myLocalDesires.GetDesire("SearchTerms") 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 } addTermEntry := widget.NewEntry() addTermEntry.SetPlaceHolder("Enter term name...") addTermButton := getWidgetCentered(widget.NewButtonWithIcon("Add Term", theme.ContentAddIcon(), func(){ newTermName := addTermEntry.Text if (newTermName == ""){ return } isAllowed := allowedText.VerifyStringIsAllowed(newTermName) if (isAllowed == false){ title := translate("Invalid Term Name") dialogMessageA := getLabelCentered(translate("Your search term 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(title, translate("Close"), dialogContent, window) return } containsTabsOrNewlines := helpers.CheckIfStringContainsTabsOrNewlines(newTermName) if (containsTabsOrNewlines == true){ title := translate("Invalid Term Name") dialogMessageA := getLabelCentered(translate("Your search term contains a tab or a newline.")) dialogMessageB := getLabelCentered(translate("Remove the tab or newline and resubmit.")) dialogContent := container.NewVBox(dialogMessageA, dialogMessageB) dialog.ShowCustom(title, translate("Close"), dialogContent, window) return } termNameBase64 := encoding.EncodeBytesToBase64String([]byte(newTermName)) newDesireList := helpers.AddItemToStringListAndAvoidDuplicate(currentDesiredChoicesList, termNameBase64) newDesireAttributeValue := strings.Join(newDesireList, "+") err := myLocalDesires.SetDesire("SearchTerms", newDesireAttributeValue) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() })) addTermRow := getContainerCentered(container.NewGridWithRows(1, addTermEntry, addTermButton)) if (len(currentDesiredChoicesList) == 0){ noTermsExistLabel := getBoldLabelCentered("No Terms Exist.") selectedSearchTermsSection := container.NewVBox(addTermRow, widget.NewSeparator(), noTermsExistLabel) return selectedSearchTermsSection, nil } myDesiredTermsLabel := getItalicLabelCentered("My Desired Terms:") termNameColumn := container.NewVBox(widget.NewSeparator()) deleteButtonsColumn := container.NewVBox(widget.NewSeparator()) for _, termNameBase64 := range currentDesiredChoicesList{ termName, err := encoding.DecodeBase64StringToUnicodeString(termNameBase64) if (err != nil){ return nil, errors.New("My current search terms desire is malformed: Contains invalid term: " + termNameBase64) } termNameLabel := getBoldLabelCentered(termName) deleteTermButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func(){ newDesiredTermsList, _ := helpers.DeleteAllMatchingItemsFromList(currentDesiredChoicesList, termNameBase64) if (len(newDesiredTermsList) == 0){ err := myLocalDesires.DeleteDesire("SearchTerms") if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() return } newDesireValueString := strings.Join(newDesiredTermsList, "+") err := myLocalDesires.SetDesire("SearchTerms", newDesireValueString) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() }) termNameColumn.Add(termNameLabel) deleteButtonsColumn.Add(deleteTermButton) termNameColumn.Add(widget.NewSeparator()) deleteButtonsColumn.Add(widget.NewSeparator()) } termsGrid := container.NewHBox(layout.NewSpacer(), termNameColumn, deleteButtonsColumn, layout.NewSpacer()) selectedTermsSection := container.NewVBox(addTermRow, widget.NewSeparator(), myDesiredTermsLabel, termsGrid) return selectedTermsSection, nil } selectedTermsSection, err := getSelectedSearchTermsSection() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, "SearchTerms", false) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Search Terms", "SearchTerms", true, "Bar", "SearchTermsCount", currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), selectedTermsSection, widget.NewSeparator(), filterOptionsSection, widget.NewSeparator(), viewStatisticsButton) setPageContent(page, window) } func setChooseDesiresPage_Chat(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_Chat(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Chat Desires") description1 := getLabelCentered("Choose your chat desires.") hasMessagedMeButton := widget.NewButton("Has Messaged Me", func(){ setChooseDesiresPage_HasMessagedMe(window, currentPage) }) iHaveMessagedButton := widget.NewButton("I Have Messaged", func(){ setChooseDesiresPage_IHaveMessaged(window, currentPage) }) hasRejectedMeButton := widget.NewButton("Has Rejected Me", func(){ setChooseDesiresPage_HasRejectedMe(window, currentPage) }) hasAnsweredQuestionnaireButton := widget.NewButton("Has Answered Questionnaire", func(){ //TODO // We need to include the functionality to only show users who responded in a specified way // For example, if the user's question is: Do you like french fries?, and the user has 2 options: Yes/No, // the user should be able to filter users who answered with yes/no showUnderConstructionDialog(window) }) buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, hasMessagedMeButton, iHaveMessagedButton, hasRejectedMeButton, hasAnsweredQuestionnaireButton)) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, widget.NewSeparator(), buttonsGrid) setPageContent(page, window) } func setChooseDesiresPage_HasMessagedMe(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_HasMessagedMe(window, previousPage)} title := getPageTitleCentered("My Mate Desires - General") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Has Messaged Me") description1 := getLabelCentered("Use this desire to show or hide users who have messaged you.") description2 := getLabelCentered("Select the kind of users to include in your matches.") //TODO: Change this to HasGreetedMe? Currently, a user who has rejected us will be included by this desire option1Translated := translate("Has Messaged Me") option2Translated := translate("Has Not Messaged Me") optionTitlesList := []string{option1Translated, option2Translated} optionNamesMap := map[string][]string{ option1Translated: []string{"Yes"}, option2Translated: []string{"No"}, } desireEditor, err := getDesireEditor_Choice(window, currentPage, "HasMessagedMe", optionTitlesList, optionNamesMap, false, false, 1) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Has Messaged Me", "HasMessagedMe", true, "Donut", "HasMessagedMe", currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton) setPageContent(page, window) } func setChooseDesiresPage_IHaveMessaged(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_IHaveMessaged(window, previousPage)} title := getPageTitleCentered("My Mate Desires - General") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("I Have Messaged") description1 := getLabelCentered("Use this desire to show or hide users whom you have messaged.") description2 := getLabelCentered("Select the kind of users to include in your matches.") option1Translated := translate("I Have Messaged") option2Translated := translate("I Have Not Messaged") optionTitlesList := []string{option1Translated, option2Translated} optionNamesMap := map[string][]string{ option1Translated: []string{"Yes"}, option2Translated: []string{"No"}, } desireEditor, err := getDesireEditor_Choice(window, currentPage, "IHaveMessaged", optionTitlesList, optionNamesMap, false, false, 1) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "I Have Messaged", "IHaveMessaged", true, "Donut", "IHaveMessaged", currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton) setPageContent(page, window) } func setChooseDesiresPage_HasRejectedMe(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_HasRejectedMe(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Has Rejected Me") description1 := getLabelCentered("Use this desire to show or hide users who have rejected you.") description2 := getLabelCentered("These are users who sent you a message that they are not interested.") description3 := getLabelCentered("Select the kind of users to include in your matches.") option1Translated := translate("Has Rejected Me") option2Translated := translate("Has Not Rejected Me") optionTitlesList := []string{option1Translated, option2Translated} optionNamesMap := map[string][]string{ option1Translated: []string{"Yes"}, option2Translated: []string{"No"}, } desireEditor, err := getDesireEditor_Choice(window, currentPage, "HasRejectedMe", optionTitlesList, optionNamesMap, false, false, 1) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Has Rejected Me", "HasRejectedMe", true, "Donut", "HasRejectedMe", 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_LikedUsers(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_LikedUsers(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Liked Users") description1 := getLabelCentered("Use this desire to show or hide liked users.") description2 := getLabelCentered("A liked user is a user that you have added to your likes.") description3 := getLabelCentered("Select the kind of users to include in your matches.") option1Translated := translate("Liked") option2Translated := translate("Not Liked") optionTitlesList := []string{option1Translated, option2Translated} optionNamesMap := map[string][]string{ option1Translated: []string{"Yes"}, option2Translated: []string{"No"}, } desireEditor, err := getDesireEditor_Choice(window, currentPage, "IsLiked", optionTitlesList, optionNamesMap, false, false, 1) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Is Liked", "IsLiked", true, "Donut", "IsLiked", 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_IgnoredUsers(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_IgnoredUsers(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Ignored Users") description1 := getLabelCentered("Use this desire to show or hide ignored users.") description2 := getLabelCentered("An Ignored user is a user that you have ignored.") description3 := getLabelCentered("Select the kind of users to include in your matches.") option1Translated := translate("Ignored") option2Translated := translate("Not Ignored") optionTitlesList := []string{option1Translated, option2Translated} optionNamesMap := map[string][]string{ option1Translated: []string{"Yes"}, option2Translated: []string{"No"}, } desireEditor, err := getDesireEditor_Choice(window, currentPage, "IsIgnored", optionTitlesList, optionNamesMap, false, false, 1) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Is Ignored", "IsIgnored", true, "Donut", "IsIgnored", 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_Contacts(window fyne.Window, previousPage func()){ currentPage := func(){setChooseDesiresPage_Contacts(window, previousPage)} title := getPageTitleCentered(translate("My Mate Desires - General")) backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Contacts") description1 := getLabelCentered("Use this desire to show or hide your contacts.") description2 := getLabelCentered("These are users you have added to your contacts.") description3 := getLabelCentered("Select the kind of users to include in your matches.") option1Translated := translate("Is My Contact") option2Translated := translate("Is Not My Contact") optionTitlesList := []string{option1Translated, option2Translated} optionNamesMap := map[string][]string{ option1Translated: []string{"Yes"}, option2Translated: []string{"No"}, } desireEditor, err := getDesireEditor_Choice(window, currentPage, "IsMyContact", optionTitlesList, optionNamesMap, false, false, 1) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } viewStatisticsButton := getWidgetCentered(widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, "Is My Contact", "IsMyContact", true, "Donut", "IsMyContact", currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), desireEditor, widget.NewSeparator(), viewStatisticsButton) setPageContent(page, window) } // This function provides the editor to edit a choice desire // A choice desire is one where there are a some canonical choices available, and the potential for an "Other" choice // Inputs: // -fyne.Window // -func(): Current page // -string: Desire name // -[]string: Option titles list: What each check will show. Example: "1/5", "2/5", "3/5", "4/5", "5/5") // -map[string][]string: Option Title -> Option Names list (Example ("1/5" -> "1", "2/5" -> "2"...) // -bool: Show other choice: True if we want to show the "Other" option // -bool: Show the "Require Response" button (false for attributes which do not allow that option) // -int: Number of columns for the grid // Outputs: // -*fyne.Container // -error func getDesireEditor_Choice(window fyne.Window, currentPage func(), desireName string, optionTitlesList []string, optionsNamesMap map[string][]string, showOtherChoice bool, showRequireResponseButton bool, numberOfGridColumns int)(*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 (Except for "Other") currentDesiredChoicesList := strings.Split(currentChoicesList, "+") return currentDesiredChoicesList, nil } currentDesiredChoicesList, err := getCurrentDesiredChoicesList() if (err != nil) { return nil, err } selectButtonsGrid := container.NewGridWithColumns(numberOfGridColumns) for _, optionTitle := range optionTitlesList{ optionNamesList, exists := optionsNamesMap[optionTitle] if (exists == false){ return nil, errors.New("getDesireEditor_Choice called with optionsNamesMap missing optionTitle: " + optionTitle) } optionBase64NamesList := make([]string, 0, len(optionNamesList)) for _, optionName := range optionNamesList{ optionNameBase64 := encoding.EncodeBytesToBase64String([]byte(optionName)) optionBase64NamesList = append(optionBase64NamesList, optionNameBase64) } handleSelectFunction := 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 the option was already selected // The list should have had at least 1 item before emptyList := make([]string, 0) return emptyList } newAttributeList := make([]string, 0) for _, optionNameBase64 := range currentDesiredChoicesList{ // We see if this option name belongs to the current optionTitle // If it does, we remove it from our selected attributes list shouldDelete := slices.Contains(optionBase64NamesList, optionNameBase64) if (shouldDelete == false){ newAttributeList = append(newAttributeList, optionNameBase64) } } return newAttributeList } //selection == true newDesiredChoicesList := slices.Concat(currentDesiredChoicesList, optionBase64NamesList) duplicatesRemovedList := helpers.RemoveDuplicatesFromStringList(newDesiredChoicesList) return duplicatesRemovedList } 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() } optionSelectCheck := widget.NewCheck(optionTitle, handleSelectFunction) getChoiceIsSelectedBool := func()bool{ // Every option name associated with this choice must be selected for this choice to be considered selected for _, optionNameBase64 := range optionBase64NamesList{ listContainsItem := slices.Contains(currentDesiredChoicesList, optionNameBase64) if (listContainsItem == false){ return false } } return true } choiceIsSelected := getChoiceIsSelectedBool() if (choiceIsSelected == true){ optionSelectCheck.Checked = true } selectButtonsGrid.Add(optionSelectCheck) } if (showOtherChoice == true){ handleOtherSelectFunction := 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() } otherSelectCheck := widget.NewCheck("Other", handleOtherSelectFunction) otherIsSelected := slices.Contains(currentDesiredChoicesList, "Other") if (otherIsSelected == true){ otherSelectCheck.Checked = true } selectButtonsGrid.Add(otherSelectCheck) } selectButtonsGridCentered := getContainerCentered(selectButtonsGrid) filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, desireName, showRequireResponseButton) if (err != nil){ return nil, err } desireEditor := container.NewVBox(selectButtonsGridCentered, widget.NewSeparator(), filterOptionsSection) return desireEditor, nil } // This function provides the editor to edit a numeric attribute // The user can choose a minimum and maximum allowed value // Units are shown for each minimum/maximum value, and a secondary row of alternate units can optionally be shown func getDesireEditor_Numeric( window fyne.Window, currentPage func(), desireName string, minimumAllowed int64, maximumAllowed int64, currentUnits string, unitsRoundingPrecision int, unitsAreCustom bool, // This will be true if we need to convert the shown units convertToStandardFunction func(float64)(float64, error), convertToCustomFunction func(float64)(float64, error), showSecondaryForm bool, // Secondary form is an alternate representation of the bound. Example: Offspring variants secondaryFormTitle string, secondaryFormPrefix string, // A prefix to add to the secondary form representation. Example: "~" for offspring variants getSecondaryFormFunction func(float64)(float64, error))(*fyne.Container, error){ getBoundColumn := func(minimumOrMaximum string)(*fyne.Container, error){ if (minimumOrMaximum != "Minimum" && minimumOrMaximum != "Maximum"){ return nil, errors.New("getBoundColumn called with invalid minimumOrMaximum: " + minimumOrMaximum) } desireBoundName := desireName + "_" + minimumOrMaximum boundLabel := getBoldLabelCentered(minimumOrMaximum) myBoundExists, myCurrentBound, err := myLocalDesires.GetDesire(desireBoundName) if (err != nil) { return nil, err } getMyBoundSection := func()(*fyne.Container, error){ if (myBoundExists == false){ noneLabel := getBoldItalicLabelCentered(translate("None")) if (showSecondaryForm == false){ return noneLabel, nil } noneLabel2 := getBoldItalicLabelCentered(translate("None")) secondaryFormTitle := getItalicLabelCentered(secondaryFormTitle + ":") myBoundSection := container.NewVBox(noneLabel, widget.NewSeparator(), secondaryFormTitle, noneLabel2) return myBoundSection, nil } // This will convert the bound if unitsAreCustom is true getMyCurrentBound := func()(float64, error){ myBoundFloat64, err := helpers.ConvertStringToFloat64(myCurrentBound) if (err != nil){ return 0, errors.New("My " + desireName + " desire malformed: not float64: " + myCurrentBound) } if (unitsAreCustom == false){ return myBoundFloat64, nil } myBoundCustom, err := convertToCustomFunction(myBoundFloat64) if (err != nil){ return 0, errors.New("My " + desireName + " desire malformed: is negative: " + myCurrentBound) } return myBoundCustom, nil } myCurrentBound, err := getMyCurrentBound() if (err != nil){ return nil, err } myCurrentBoundString := helpers.ConvertFloat64ToStringRounded(myCurrentBound, unitsRoundingPrecision) myBoundLabelText := myCurrentBoundString + " " + translate(currentUnits) myBoundLabel := getBoldLabelCentered(myBoundLabelText) if (showSecondaryForm == false){ return myBoundLabel, nil } secondaryFormBound, err := getSecondaryFormFunction(myCurrentBound) if (err != nil){ return nil, err } secondaryFormBoundString := helpers.ConvertFloat64ToStringRounded(secondaryFormBound, unitsRoundingPrecision) secondaryFormTitle := getItalicLabelCentered(secondaryFormTitle + ":") mySecondaryFormBoundLabelText := secondaryFormPrefix + secondaryFormBoundString + " " + translate(currentUnits) mySecondaryFormBoundLabel := getBoldItalicLabelCentered(mySecondaryFormBoundLabelText) myBoundSection := container.NewVBox(myBoundLabel, widget.NewSeparator(), secondaryFormTitle, mySecondaryFormBoundLabel) return myBoundSection, nil } myBoundSection, err := getMyBoundSection() if (err != nil) { return nil, err } minimumOrMaximumLowercase := strings.ToLower(minimumOrMaximum) boundEntry := widget.NewEntry() if (myBoundExists == true){ getMyCurrentBoundString := func()(string, error){ myCurrentBoundFloat64, err := helpers.ConvertStringToFloat64(myCurrentBound) if (err != nil) { return "", errors.New("My desires malformed: Contains invalid numeric desire: " + desireName) } if (myCurrentBoundFloat64 < float64(minimumAllowed) || myCurrentBoundFloat64 > float64(maximumAllowed)) { return "", errors.New("My desires malformed: Contains invalid numeric desire: " + desireName) } if (unitsAreCustom == false){ myCurrentBoundRounded := helpers.ConvertFloat64ToStringRounded(myCurrentBoundFloat64, unitsRoundingPrecision) return myCurrentBoundRounded, nil } myCurrentBoundCustom, err := convertToCustomFunction(myCurrentBoundFloat64) if (err != nil){ return "", errors.New("My desires malformed: Contains invalid numeric desire: " + desireName) } myCurrentBoundCustomString := helpers.ConvertFloat64ToStringRounded(myCurrentBoundCustom, unitsRoundingPrecision) return myCurrentBoundCustomString, nil } myCurrentBoundString, err := getMyCurrentBoundString() if (err != nil) { return nil, err } boundEntry.SetText(myCurrentBoundString) } else { boundEntry.SetPlaceHolder(translate("Enter " + minimumOrMaximumLowercase + "...")) } saveBoundButton := widget.NewButtonWithIcon(translate("Save"), theme.ConfirmIcon(), func(){ newBound := boundEntry.Text if (newBound == ""){ err := myLocalDesires.DeleteDesire(desireBoundName) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() return } //TODO: If min is greater than max, or max is greater than min, show dialog and don't allow change newBoundFloat64, err := helpers.ConvertStringToFloat64(newBound) if (err != nil){ title := translate("Invalid Bound") dialogMessage := getLabelCentered(translate("Your bound must be a number.")) dialogContent := container.NewVBox(dialogMessage) dialog.ShowCustom(title, translate("Close"), dialogContent, window) return } getNewDesireBoundConverted := func()(float64, error){ if (unitsAreCustom == false){ return newBoundFloat64, nil } boundInStandardUnits, err := convertToStandardFunction(newBoundFloat64) if (err != nil){ return 0, errors.New("Invalid new numeric bound: " + err.Error()) } return boundInStandardUnits, nil } newDesireBoundConverted, err := getNewDesireBoundConverted() if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } if (newDesireBoundConverted < float64(minimumAllowed) || newDesireBoundConverted > float64(maximumAllowed)){ minimumAllowedString := helpers.ConvertInt64ToString(minimumAllowed) maximumAllowedString := helpers.ConvertInt64ToString(maximumAllowed) dialogTitle := translate("Invalid Desire") dialogMessage := getLabelCentered(translate("Your " + minimumOrMaximumLowercase + " must be a number between " + minimumAllowedString + " and " + maximumAllowedString + ".")) dialogContent := container.NewVBox(dialogMessage) dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window) return } newDesireBoundString := helpers.ConvertFloat64ToStringRounded(newDesireBoundConverted, unitsRoundingPrecision) err = myLocalDesires.SetDesire(desireBoundName, newDesireBoundString) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } currentPage() }) saveBoundButtonWithEntry := container.NewGridWithRows(1, boundEntry, saveBoundButton) 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(), myBoundSection, widget.NewSeparator(), saveBoundButtonWithEntry, deleteBoundButton)) return boundColumn, nil } minimumColumn, err := getBoundColumn("Minimum") if (err != nil){ return nil, err } maximumColumn, err := getBoundColumn("Maximum") if (err != nil){ return nil, err } boundColumns := getContainerCentered(container.NewGridWithRows(1, minimumColumn, maximumColumn)) filterOptionsSection, err := getDesireEditorFilterOptionsSection(window, currentPage, desireName, true) if (err != nil){ return nil, err } editorContent := container.NewVBox(boundColumns, widget.NewSeparator(), filterOptionsSection) return editorContent, nil } func getDesireEditorFilterOptionsSection(window fyne.Window, currentPage func(), desireName string, showRequireResponseButton bool)(*fyne.Container, error){ configureFiltersDescription := widget.NewLabel("Configure your desire filter options.") desireFilterOptionsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){ setDesireFilterOptionsExplainerPage(window, currentPage) }) desireFilterOptionsDescriptionRow := container.NewHBox(layout.NewSpacer(), configureFiltersDescription, desireFilterOptionsHelpButton, layout.NewSpacer()) getFilterAllButton := func()(fyne.Widget, error){ filterAllExists, currentFilterAllResponse, err := myLocalDesires.GetDesire(desireName + "_FilterAll") if (err != nil) { return nil, err } if (filterAllExists == true && currentFilterAllResponse == "Yes"){ button := widget.NewButtonWithIcon(translate("Filter All"), theme.CheckButtonCheckedIcon(), func(){ _ = myLocalDesires.SetDesire(desireName + "_FilterAll", "No") currentPage() }) return button, nil } button := widget.NewButtonWithIcon(translate("Filter All"), theme.CheckButtonIcon(), func(){ _ = myLocalDesires.SetDesire(desireName + "_FilterAll", "Yes") currentPage() }) return button, nil } filterAllButton, err := getFilterAllButton() if (err != nil) { return nil, err } if (showRequireResponseButton == false){ filterAllButtonCentered := getWidgetCentered(filterAllButton) filterOptionsSection := container.NewVBox(desireFilterOptionsDescriptionRow, filterAllButtonCentered) return filterOptionsSection, nil } getRequireResponseButton := func()(fyne.Widget, error){ requireResponseExists, currentRequireResponse, err := myLocalDesires.GetDesire(desireName + "_RequireResponse") if (err != nil) { return nil, err } if (requireResponseExists == true && currentRequireResponse == "Yes"){ button := widget.NewButtonWithIcon(translate("Require Response"), theme.CheckButtonCheckedIcon(), func(){ _ = myLocalDesires.SetDesire(desireName + "_RequireResponse", "No") currentPage() }) return button, nil } button := widget.NewButtonWithIcon(translate("Require Response"), theme.CheckButtonIcon(), func(){ _ = myLocalDesires.SetDesire(desireName + "_RequireResponse", "Yes") currentPage() }) return button, nil } requireResponseButton, err := getRequireResponseButton() if (err != nil) { return nil, err } filterSettingsButtonsGrid := getContainerCentered(container.NewGridWithColumns(1, filterAllButton, requireResponseButton)) filterOptionsSection := container.NewVBox(desireFilterOptionsDescriptionRow, filterSettingsButtonsGrid) return filterOptionsSection, nil } // This is a page to view all of a user's desires func setViewAllMyDesiresPage(window fyne.Window, previousPage func()){ setLoadingScreen(window, "My Mate Desires", "Loading My Mate Desires...") appMemory.SetMemoryEntry("CurrentViewedPage", "ViewAllMyDesires") currentPage := func(){setViewAllMyDesiresPage(window, previousPage)} title := getPageTitleCentered("My Mate Desires") backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Below are all of your mate desires.") getAllDesiresGrid := func()(*fyne.Container, error){ desireButtonsColumn := container.NewVBox(widget.NewSeparator()) desireNameAndDataColumn := container.NewVBox(widget.NewSeparator()) filterOptionChecksColumn := container.NewVBox(widget.NewSeparator()) getFilterOptionCheck := func(desireName string, optionType string)(fyne.Widget, error){ if (optionType != "FilterAll" && optionType != "RequireResponse"){ return nil, errors.New("getFilterOptionCheck called with invalid optionType: " + optionType) } filterOptionDesireName := desireName + "_" + optionType getOptionTitle := func()string{ if (optionType == "FilterAll"){ result := translate("Filter All") return result } result := translate("Require Response") return result } optionTitle := getOptionTitle() filterOptionCheck := widget.NewCheck(optionTitle, func(newSelection bool){ newSelectionString := helpers.ConvertBoolToYesOrNoString(newSelection) _ = myLocalDesires.SetDesire(filterOptionDesireName, newSelectionString) }) exists, currentValue, err := myLocalDesires.GetDesire(filterOptionDesireName) if (err != nil) { return nil, err } if (exists == true && currentValue == "Yes"){ filterOptionCheck.Checked = true } return filterOptionCheck, nil } addDesireRow_Numerical := func(desireTitle string, desireName string, editPage func(), barOrDonutChart string, attributeName string)error{ editDesireButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), editPage) desireTitleLabel := getBoldLabelCentered(desireTitle) getDesireValueLabel := func() (*fyne.Container, error){ minimumExists, desireMinimum, err := myLocalDesires.GetDesire(desireName + "_Minimum") if (err != nil) { return nil, err } maximumExists, desireMaximum, err := myLocalDesires.GetDesire(desireName + "_Maximum") if (err != nil) { return nil, err } if (minimumExists == false && maximumExists == false){ noPreferenceLabel := getItalicLabelCentered("No Preference") return noPreferenceLabel, nil } // We may have to format the desire value // For example: converting distance units from kilometers to miles _, attributeIsNumerical, formatDesireValuesFunction, desireValueUnits, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeName) if (err != nil) { return nil, err } if (attributeIsNumerical == false){ return nil, errors.New("addDesireRow_Numerical called with non-numerical attribute: " + attributeName) } getDesireRangeFormatted := func()(string, error){ if (minimumExists == true && maximumExists == false){ desireMinimumFormatted, err := formatDesireValuesFunction(desireMinimum) if (err != nil) { return "", err } result := desireMinimumFormatted + "+" return result, nil } if (minimumExists == false && maximumExists == true){ desireMaximumFormatted, err := formatDesireValuesFunction(desireMaximum) if (err != nil) { return "", err } result := "<" + desireMaximumFormatted return result, nil } desireMinimumFormatted, err := formatDesireValuesFunction(desireMinimum) if (err != nil) { return "", err } desireMaximumFormatted, err := formatDesireValuesFunction(desireMaximum) if (err != nil) { return "", err } result := desireMinimumFormatted + " - " + desireMaximumFormatted return result, nil } desireRangeFormatted, err := getDesireRangeFormatted() if (err != nil) { return nil, err } labelText := desireRangeFormatted + desireValueUnits minMaxLabel := getBoldItalicLabelCentered(labelText) return minMaxLabel, nil } desireValueLabel, err := getDesireValueLabel() if (err != nil) { return err } filterAllCheck, err := getFilterOptionCheck(desireName, "FilterAll") if (err != nil) { return err } requireResponseCheck, err := getFilterOptionCheck(desireName, "RequireResponse") if (err != nil) { return err } viewStatisticsButton := widget.NewButtonWithIcon("Stats", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, desireTitle, desireName, true, barOrDonutChart, attributeName, currentPage) }) desireButtonsColumn.Add(editDesireButton) desireButtonsColumn.Add(viewStatisticsButton) desireNameAndDataColumn.Add(desireTitleLabel) desireNameAndDataColumn.Add(desireValueLabel) filterOptionChecksColumn.Add(filterAllCheck) filterOptionChecksColumn.Add(requireResponseCheck) desireButtonsColumn.Add(widget.NewSeparator()) desireNameAndDataColumn.Add(widget.NewSeparator()) filterOptionChecksColumn.Add(widget.NewSeparator()) return nil } addDesireRow_Choice := func(desireTitle string, desireName string, editPage func(), barOrDonutChart string, attributeName string)error{ editDesireButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), editPage) desireTitleLabel := getBoldLabelCentered(desireTitle) getChoiceValueLabel := func()(*fyne.Container, error){ desireExists, desireChoicesList, err := myLocalDesires.GetDesire(desireName) if (err != nil) { return nil, err } if (desireExists == false){ noPreferenceLabel := getItalicLabelCentered(translate("No Preference")) return noPreferenceLabel, nil } // We may have to format the desired choices for readability // For example: Converting "1" -> "1/6" _, _, formatDesireValuesFunction, desireValueUnits, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeName) if (err != nil) { return nil, err } getLabelText := func()(string, error){ base64ChoicesList := strings.Split(desireChoicesList, "+") choicesList := make([]string, 0, len(base64ChoicesList)) for _, base64Choice := range base64ChoicesList{ choiceString, err := encoding.DecodeBase64StringToUnicodeString(base64Choice) if (err != nil) { return "", errors.New("My Desire choices list is malformed: Contains non-base64 choice: " + base64Choice) } choiceFormatted, err := formatDesireValuesFunction(choiceString) if (err != nil) { return "", err } choiceFormattedWithUnits := choiceFormatted + desireValueUnits choicesList = append(choicesList, choiceFormattedWithUnits) } choicesListJoined := strings.Join(choicesList, ", ") choicesListTrimmed, _, err := helpers.TrimAndFlattenString(choicesListJoined, 35) if (err != nil) { return "", err } return choicesListTrimmed, nil } labelText, err := getLabelText() if (err != nil) { return nil, err } desireValueLabel := getBoldItalicLabelCentered(labelText) return desireValueLabel, nil } choiceValueLabel, err := getChoiceValueLabel() if (err != nil) { return err } filterAllCheck, err := getFilterOptionCheck(desireName, "FilterAll") if (err != nil) { return err } requireResponseCheck, err := getFilterOptionCheck(desireName, "RequireResponse") if (err != nil) { return err } viewStatisticsButton := widget.NewButtonWithIcon("Stats", theme.InfoIcon(), func(){ setViewMyMateDesireStatisticsPage(window, desireTitle, desireName, true, barOrDonutChart, attributeName, currentPage) }) desireButtonsColumn.Add(editDesireButton) desireButtonsColumn.Add(viewStatisticsButton) desireNameAndDataColumn.Add(desireTitleLabel) desireNameAndDataColumn.Add(choiceValueLabel) filterOptionChecksColumn.Add(filterAllCheck) filterOptionChecksColumn.Add(requireResponseCheck) desireButtonsColumn.Add(widget.NewSeparator()) desireNameAndDataColumn.Add(widget.NewSeparator()) filterOptionChecksColumn.Add(widget.NewSeparator()) return nil } // This function is used for desires which are not choice/numerical, so their value cannot be displayed automatically //TODO: Add a function to format the desire value to something readable addDesireRow_Custom := func(desireTitle string, desireName string, editPage func())error{ editDesireButton := widget.NewButtonWithIcon("Edit", theme.DocumentCreateIcon(), editPage) desireTitleLabel := getBoldLabelCentered(desireTitle) getDesireValueLabel := func() (*fyne.Container, error){ desireExists, _, err := myLocalDesires.GetDesire(desireName) if (err != nil) { return nil, err } if (desireExists == false){ noPreferenceLabel := getItalicLabelCentered("No Preference") return noPreferenceLabel, nil } customLabel := getBoldItalicLabelCentered("Custom") return customLabel, nil } desireValueLabel, err := getDesireValueLabel() if (err != nil) { return err } filterAllCheck, err := getFilterOptionCheck(desireName, "FilterAll") if (err != nil) { return err } requireResponseCheck, err := getFilterOptionCheck(desireName, "RequireResponse") if (err != nil) { return err } desireButtonsColumn.Add(editDesireButton) desireButtonsColumn.Add(widget.NewLabel("")) desireNameAndDataColumn.Add(desireTitleLabel) desireNameAndDataColumn.Add(desireValueLabel) filterOptionChecksColumn.Add(filterAllCheck) filterOptionChecksColumn.Add(requireResponseCheck) desireButtonsColumn.Add(widget.NewSeparator()) desireNameAndDataColumn.Add(widget.NewSeparator()) filterOptionChecksColumn.Add(widget.NewSeparator()) return nil } editAgeDesirePage := func(){setChooseDesiresPage_Age(window, currentPage)} err := addDesireRow_Numerical("Age", "Age", editAgeDesirePage, "Bar", "Age") if (err != nil){ return nil, err } editHeightDesirePage := func(){setChooseDesiresPage_Height(window, currentPage)} err = addDesireRow_Numerical("Height", "Height", editHeightDesirePage, "Bar", "Height") if (err != nil){ return nil, err } editWealthDesirePage := func(){setChooseDesiresPage_Wealth(window, currentPage)} err = addDesireRow_Numerical("Wealth", "Wealth", editWealthDesirePage, "Bar", "WealthInGold") if (err != nil){ return nil, err } editSexDesirePage := func(){setChooseDesiresPage_Sex(window, currentPage)} err = addDesireRow_Choice("Sex", "Sex", editSexDesirePage, "Donut", "Sex") if (err != nil){ return nil, err } editProfileLanguageDesirePage := func(){setChooseDesiresPage_ProfileLanguage(window, currentPage)} err = addDesireRow_Choice("Profile Language", "ProfileLanguage", editProfileLanguageDesirePage, "Bar", "ProfileLanguage") if (err != nil){ return nil, err } editCountryDesirePage := func(){setChooseDesiresPage_Country(window, currentPage)} err = addDesireRow_Choice("Country", "PrimaryLocationCountry", editCountryDesirePage, "Donut", "PrimaryLocationCountry") if (err != nil){ return nil, err } editSearchTermsDesirePage := func(){setChooseDesiresPage_SearchTerms(window, currentPage)} err = addDesireRow_Choice("Search Terms", "SearchTerms", editSearchTermsDesirePage, "Donut", "SearchTermsCount") if (err != nil){ return nil, err } editHasMessagedMeDesirePage := func(){setChooseDesiresPage_HasMessagedMe(window, currentPage)} err = addDesireRow_Choice("Has Messaged Me", "HasMessagedMe", editHasMessagedMeDesirePage, "Donut", "HasMessagedMe") if (err != nil){ return nil, err } editIHaveMessagedDesirePage := func(){setChooseDesiresPage_IHaveMessaged(window, currentPage)} err = addDesireRow_Choice("I Have Messaged", "IHaveMessaged", editIHaveMessagedDesirePage, "Donut", "IHaveMessaged") if (err != nil){ return nil, err } editHasRejectedMeDesirePage := func(){setChooseDesiresPage_HasRejectedMe(window, currentPage)} err = addDesireRow_Choice("Has Rejected Me", "HasRejectedMe", editHasRejectedMeDesirePage, "Donut", "HasRejectedMe") if (err != nil){ return nil, err } editIsLikedDesirePage := func(){setChooseDesiresPage_LikedUsers(window, currentPage)} err = addDesireRow_Choice("Is Liked", "IsLiked", editIsLikedDesirePage, "Donut", "IsLiked") if (err != nil){ return nil, err } editIsIgnoredDesirePage := func(){setChooseDesiresPage_IgnoredUsers(window, currentPage)} err = addDesireRow_Choice("Is Ignored", "IsIgnored", editIsIgnoredDesirePage, "Donut", "IsIgnored") if (err != nil){ return nil, err } editIsMyContactDesirePage := func(){setChooseDesiresPage_Contacts(window, currentPage)} err = addDesireRow_Choice("Is My Contact", "IsMyContact", editIsMyContactDesirePage, "Donut", "IsMyContact") if (err != nil){ return nil, err } editDistanceDesirePage := func(){setChooseDesiresPage_Distance(window, currentPage)} err = addDesireRow_Numerical("Distance", "Distance", editDistanceDesirePage, "Bar", "Distance") if (err != nil){ return nil, err } editSexualityDesirePage := func(){setChooseDesiresPage_Sexuality(window, currentPage)} err = addDesireRow_Choice("Sexuality", "Sexuality", editSexualityDesirePage, "Donut", "Sexuality") if (err != nil){ return nil, err } editBodyFatDesirePage := func(){setChooseDesiresPage_BodyFat(window, currentPage)} err = addDesireRow_Choice("Body Fat", "BodyFat", editBodyFatDesirePage, "Donut", "BodyFat") if (err != nil){ return nil, err } editBodyMuscleDesirePage := func(){setChooseDesiresPage_BodyMuscle(window, currentPage)} err = addDesireRow_Choice("Body Muscle", "BodyMuscle", editBodyMuscleDesirePage, "Donut", "BodyMuscle") if (err != nil){ return nil, err } editEyeColorDesirePage := func(){setChooseDesiresPage_EyeColor(window, currentPage)} err = addDesireRow_Choice("Eye Color", "EyeColor", editEyeColorDesirePage, "Donut", "EyeColor") if (err != nil){ return nil, err } editSkinColorDesirePage := func(){setChooseDesiresPage_SkinColor(window, currentPage)} err = addDesireRow_Choice("Skin Color", "SkinColor", editSkinColorDesirePage, "Donut", "SkinColor") if (err != nil){ return nil, err } editHairColorDesirePage := func(){setChooseDesiresPage_HairColor(window, currentPage)} err = addDesireRow_Choice("Hair Color", "HairColor", editHairColorDesirePage, "Donut", "HairColor") if (err != nil){ return nil, err } editHairTextureDesirePage := func(){setChooseDesiresPage_HairTexture(window, currentPage)} err = addDesireRow_Choice("Hair Texture", "HairTexture", editHairTextureDesirePage, "Donut", "HairTexture") if (err != nil){ return nil, err } editHasHIVDesirePage := func(){setChooseDesiresPage_Infections(window, currentPage)} err = addDesireRow_Choice("Has HIV", "HasHIV", editHasHIVDesirePage, "Donut", "HasHIV") if (err != nil){ return nil, err } editHasGenitalHerpesDesirePage := func(){setChooseDesiresPage_Infections(window, currentPage)} err = addDesireRow_Choice("Has Genital Herpes", "HasGenitalHerpes", editHasGenitalHerpesDesirePage, "Donut", "HasGenitalHerpes") if (err != nil){ return nil, err } foodNamesList := []string{ "Fruit", "Vegetables", "Nuts", "Grains", "Dairy", "Seafood", "Beef", "Pork", "Poultry", "Eggs", "Beans", } for _, foodName := range foodNamesList{ foodRatingDesireTitle := foodName + " Rating" foodRatingDesireName := foodName + "Rating" editFoodRatingDesirePage := func(){setChooseDesiresPage_FoodRating(window, foodName, currentPage)} err = addDesireRow_Choice(foodRatingDesireTitle, foodRatingDesireName, editFoodRatingDesirePage, "Bar", foodRatingDesireName) if (err != nil){ return nil, err } } editFameDesirePage := func(){setChooseDesiresPage_Fame(window, currentPage)} err = addDesireRow_Choice("Fame", "Fame", editFameDesirePage, "Bar", "Fame") if (err != nil){ return nil, err } editAlcoholFrequencyDesirePage := func(){setChooseDesiresPage_DrugFrequency(window, "Alcohol", currentPage)} err = addDesireRow_Choice("Alcohol Frequency", "AlcoholFrequency", editAlcoholFrequencyDesirePage, "Bar", "AlcoholFrequency") if (err != nil){ return nil, err } editTobaccoFrequencyDesirePage := func(){setChooseDesiresPage_DrugFrequency(window, "Tobacco", currentPage)} err = addDesireRow_Choice("Tobacco Frequency", "TobaccoFrequency", editTobaccoFrequencyDesirePage, "Bar", "TobaccoFrequency") if (err != nil){ return nil, err } editCannabisFrequencyDesirePage := func(){setChooseDesiresPage_DrugFrequency(window, "Cannabis", currentPage)} err = addDesireRow_Choice("Cannabis Frequency", "CannabisFrequency", editCannabisFrequencyDesirePage, "Bar", "CannabisFrequency") if (err != nil){ return nil, err } editGenderIdentityDesirePage := func(){setChooseDesiresPage_GenderIdentity(window, currentPage)} err = addDesireRow_Choice("Gender Identity", "GenderIdentity", editGenderIdentityDesirePage, "Donut", "GenderIdentity") if (err != nil){ return nil, err } editPetsRatingDesirePage := func(){setChooseDesiresPage_Pets(window, currentPage)} err = addDesireRow_Choice("Pets Rating", "PetsRating", editPetsRatingDesirePage, "Bar", "PetsRating") if (err != nil){ return nil, err } editDogsRatingDesirePage := func(){setChooseDesiresPage_Pets(window, currentPage)} err = addDesireRow_Choice("Dogs Rating", "DogsRating", editDogsRatingDesirePage, "Bar", "DogsRating") if (err != nil){ return nil, err } editCatsRatingDesirePage := func(){setChooseDesiresPage_Pets(window, currentPage)} err = addDesireRow_Choice("Cats Rating", "CatsRating", editCatsRatingDesirePage, "Bar", "CatsRating") if (err != nil){ return nil, err } editOffspringProbabilityOfAnyMonogenicDiseaseDesirePage := func(){setChooseDesiresPage_MonogenicDiseases(window, currentPage)} err = addDesireRow_Numerical("Offspring Probability Of Any Monogenic Disease", "OffspringProbabilityOfAnyMonogenicDisease", editOffspringProbabilityOfAnyMonogenicDiseaseDesirePage, "Donut", "OffspringProbabilityOfAnyMonogenicDisease") if (err != nil){ return nil, err } edit23andMeMaternalHaplogroupDesirePage := func(){setChooseDesiresPage_23andMe_Haplogroup(window, "Maternal", currentPage)} err = addDesireRow_Choice("23andMe Maternal Haplogroup", "23andMe_MaternalHaplogroup", edit23andMeMaternalHaplogroupDesirePage, "Bar", "23andMe_MaternalHaplogroup") if (err != nil){ return nil, err } edit23andMePaternalHaplogroupDesirePage := func(){setChooseDesiresPage_23andMe_Haplogroup(window, "Paternal", currentPage)} err = addDesireRow_Choice("23andMe Paternal Haplogroup", "23andMe_PaternalHaplogroup", edit23andMePaternalHaplogroupDesirePage, "Bar", "23andMe_PaternalHaplogroup") if (err != nil){ return nil, err } edit23andMeNeanderthalVariantsDesirePage := func(){setChooseDesiresPage_23andMe_NeanderthalVariants(window, currentPage)} err = addDesireRow_Numerical("23andMe Neanderthal Variants", "23andMe_NeanderthalVariants", edit23andMeNeanderthalVariantsDesirePage, "Donut", "23andMe_NeanderthalVariants") if (err != nil){ return nil, err } edit23andMeAncestryCompositionDesirePage := func(){setChooseDesiresPage_23andMe_AncestryComposition(window, "User", currentPage)} err = addDesireRow_Custom("23andMe Ancestry Composition", "23andMe_AncestryComposition", edit23andMeAncestryCompositionDesirePage) if (err != nil){ return nil, err } editLanguageDesirePage := func(){setChooseDesiresPage_Language(window, currentPage)} err = addDesireRow_Custom("Language", "Language", editLanguageDesirePage) if (err != nil){ return nil, err } allDesiresGrid := container.NewHBox(layout.NewSpacer(), widget.NewSeparator(), desireButtonsColumn, widget.NewSeparator(), desireNameAndDataColumn, widget.NewSeparator(), filterOptionChecksColumn, widget.NewSeparator(), layout.NewSpacer()) return allDesiresGrid, nil } allDesiresGrid, err := getAllDesiresGrid() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), allDesiresGrid) setPageContent(page, window) } func setManageMateDownloadDesiresPage(window fyne.Window, previousPage func()){ currentPage := func(){setManageMateDownloadDesiresPage(window, previousPage)} title := getPageTitleCentered("My Mate Download Desires") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("My Mate Download Desires") description1 := getLabelCentered("Seekia downloads mate profiles from network hosts.") description2 := getLabelCentered("These are servers run by volunteers.") description3 := getLabelCentered("Your download desires are shared to hosts when you download profiles.") description4 := getLabelCentered("These desires limit the profiles you download.") description5 := getLabelCentered("You can choose how much information to share.") description6 := getLabelCentered("The more desires you share, the less time it will take to download profiles.") description7 := getLabelCentered("The hosts could be tracking this information, so more desires will reduce your privacy.") description8 := getLabelCentered("All profiles are downloaded over the Tor anonymity network.") chooseDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("Choose Desires", theme.NavigateNextIcon(), func(){ setChooseMateDownloadDesiresPage(window, currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, description7, description8, chooseDesiresButton) setPageContent(page, window) } func setChooseMateDownloadDesiresPage(window fyne.Window, previousPage func()){ setLoadingScreen(window, "Choose Mate Download Desires", "Loading Download Desires...") currentPage := func(){setChooseMateDownloadDesiresPage(window, previousPage)} title := getPageTitleCentered("Choose Mate Download Desires") backButton := getBackButtonCentered(previousPage) description1 := getLabelCentered("You will share the selected desires with Hosts when you download profiles.") description2 := getLabelCentered("These desires will not be displayed on your profile.") description3 := getLabelCentered("Each desire will only be shared if you have enabled Filter All or Require Response") description4 := getLabelCentered("Select each desire you are comfortable sharing with hosts.") //TODO: Add Help buttons to explain this better // User should understand that the hosts will not necessarily know who they are. // They will make requests over Tor, and their requestor fingerprint will be defined by these desires // Each shared desire will increase the entropy of a requestor's fingerprint // Most requestors will probably have a very unique fingerprint // // The challenge for malicious hosts will be to link a requestor fingerprint to a requestor's mate identity // This may be difficult or easy, depending on how similar the requestor's desires are to their own profile getDesiresGrid := func()(*fyne.Container, error){ desireTitlesColumn := container.NewVBox() desireSelectChecksColumn := container.NewVBox() desireNameLabel := getItalicLabelCentered("Desire Name:") shareDesireLabel := getItalicLabelCentered("Share Desire?") desireTitlesColumn.Add(desireNameLabel) desireSelectChecksColumn.Add(shareDesireLabel) desireTitlesColumn.Add(widget.NewSeparator()) desireSelectChecksColumn.Add(widget.NewSeparator()) allMyDownloadDesiresList := myMateCriteria.GetAllMyMateDownloadDesiresList() for _, desireName := range allMyDownloadDesiresList{ desireTitle, err := mateDesires.GetDesireTitleFromDesireName(desireName) if (err != nil) { return nil, err } desireTitleLabel := getBoldLabelCentered(translate(desireTitle)) getDesireSelectCheck := func()(fyne.Widget, error){ selectCheck := widget.NewCheck("", func(selected bool){ err := myMateCriteria.SetShareMyDesireStatus(desireName, selected) if (err != nil){ setErrorEncounteredPage(window, err, currentPage) return } }) isSelected, err := myMateCriteria.GetShareMyDesireStatus(desireName) if (err != nil){ return nil, err } if (isSelected == true){ selectCheck.Checked = true } return selectCheck, nil } desireSelectCheck, err := getDesireSelectCheck() if (err != nil) { return nil, err } desireSelectCheckCentered := getWidgetCentered(desireSelectCheck) desireTitlesColumn.Add(desireTitleLabel) desireSelectChecksColumn.Add(desireSelectCheckCentered) desireTitlesColumn.Add(widget.NewSeparator()) desireSelectChecksColumn.Add(widget.NewSeparator()) } desiresGrid := container.NewHBox(layout.NewSpacer(), desireTitlesColumn, desireSelectChecksColumn, layout.NewSpacer()) return desiresGrid, nil } desiresGrid, err := getDesiresGrid() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), desiresGrid) setPageContent(page, window) }