seekia/gui/desireStatisticsGui.go

551 lines
20 KiB
Go
Raw Normal View History

package gui
// desireStatisticsGui.go implements pages to view a user's desire statistics
import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/data/binding"
import "fyne.io/fyne/v2/layout"
import "fyne.io/fyne/v2/theme"
import "fyne.io/fyne/v2/widget"
import "seekia/internal/appMemory"
import "seekia/internal/desires/mateDesires"
import "seekia/internal/desires/myDesireStatistics"
import "seekia/internal/desires/myLocalDesires"
import "seekia/internal/helpers"
import "seekia/internal/network/appNetworkType/getAppNetworkType"
import "time"
import "errors"
// This page is used to view the statistics of a single desire
func setViewMyMateDesireStatisticsPage(window fyne.Window, desireTitle string, desireName string, showChartsButton bool, barOrDonutChart string, attributeName string, previousPage func()){
currentPage := func(){setViewMyMateDesireStatisticsPage(window, desireTitle, desireName, showChartsButton, barOrDonutChart, attributeName, previousPage)}
// We use a page identifier to uniquely identify this page and detect if the user is still viewing the page
// If the user leaves this page before the getStatistics goroutine is complete, once it completes, the page will not refresh
pageIdentifier, err := helpers.GetNewRandomHexString(16)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
appMemory.SetMemoryEntry("CurrentViewedPage", pageIdentifier)
checkIfPageHasChangedFunction := func()bool{
exists, currentViewedPage := appMemory.GetMemoryEntry("CurrentViewedPage")
if (exists == true && currentViewedPage == pageIdentifier){
return false
}
return true
}
title := getPageTitleCentered("My Desire Statistics - " + desireTitle)
backButton := getBackButtonCentered(previousPage)
viewChartsFunction := func(){
if (showChartsButton == false){
return
}
if (barOrDonutChart == "Bar"){
setViewUserAttributeStatisticsPage_BarChart(window, "Mate", attributeName, "Number Of Users", " Users", true, false, false, nil, false, nil, nil, currentPage)
return
}
if (barOrDonutChart == "Donut"){
setViewUserAttributeStatisticsPage_DonutChart(window, "Mate", attributeName, false, false, nil, false, nil, nil, currentPage)
return
}
setErrorEncounteredPage(window, errors.New("setViewMyMateDesireStatisticsPage called with invalid barOrDonutChart: " + barOrDonutChart), currentPage)
}
//Outputs:
// -bool: Desire is disabled
// -bool: Filter All is disabled
// -bool: Require Response is disabled
// -error
getDesireIsDisabledStatus := func()(bool, bool, bool, error){
getFilterAllIsEnabledBool := func()(bool, error){
exists, currentFilterAllSetting, err := myLocalDesires.GetDesire(desireName + "_FilterAll")
if (err != nil) { return false, err }
if (exists == true && currentFilterAllSetting == "Yes"){
return true, nil
}
return false, nil
}
filterAllIsEnabled, err := getFilterAllIsEnabledBool()
if (err != nil) { return false, false, false, err }
if (filterAllIsEnabled == true){
// Desire is enabled
return false, false, false, nil
}
// Most desires allow the user to enable Require Response, which filters user who did not respond
allowsRequireResponse, _ := mateDesires.CheckIfDesireAllowsRequireResponse(desireName)
if (allowsRequireResponse == false){
// Desire is disabled, no users will be filtered
return true, true, false, nil
}
getRequireResponseIsEnabledBool := func()(bool, error){
exists, currentRequireResponse, err := myLocalDesires.GetDesire(desireName + "_RequireResponse")
if (err != nil) { return false, err }
if (exists == true && currentRequireResponse == "Yes"){
return true, nil
}
return false, nil
}
requireResponseIsEnabled, err := getRequireResponseIsEnabledBool()
if (err != nil) { return false, false, false, err }
if (requireResponseIsEnabled == true){
// Desire is enabled, because we require a response
return false, false, false, nil
}
// FilterAll and RequireResponse are both disabled, thus the desire is disabled
return true, true, true, nil
}
desireIsDisabled, filterAllIsDisabled, requireResponseIsDisabled, err := getDesireIsDisabledStatus()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
if (desireIsDisabled == true){
getDisabledOptionsString := func()string{
if (filterAllIsDisabled == true && requireResponseIsDisabled == true){
return "Filter All or Require Response"
}
// filterAllIsDisabled == true && requireResponseIsDisabled == false
return "Filter All"
}
disabledOptionsString := getDisabledOptionsString()
description1 := getBoldLabelCentered("You do not have " + disabledOptionsString + " enabled for this desire.")
description2 := getLabelCentered("This means that all users will pass the desire.")
description3Label := getLabelCentered("Without " + disabledOptionsString + " enabled, the desire only impacts user match scores.")
filterOptionsHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
setDesireFilterOptionsExplainerPage(window, currentPage)
})
description3Row := container.NewHBox(layout.NewSpacer(), description3Label, filterOptionsHelpButton, layout.NewSpacer())
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3Row)
if (showChartsButton == true){
page.Add(widget.NewSeparator())
description4 := getLabelCentered("Visualize the distribution of user responses on a chart.")
page.Add(description4)
viewChartButton := getWidgetCentered(widget.NewButtonWithIcon("View Chart", theme.InfoIcon(), viewChartsFunction))
page.Add(viewChartButton)
}
setPageContent(page, window)
return
}
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
allIdentitiesStatisticsBinding := binding.NewString()
matchStatisticsBinding := binding.NewString()
updateBindingsFunction := func(){
statisticsFound := false
updateBindingsWithProgressEllipsesFunction := func(){
secondsElapsed := 0
for {
if (statisticsFound == true){
return
}
pageHasChanged := checkIfPageHasChangedFunction()
if (pageHasChanged == true){
return
}
if (secondsElapsed % 3 == 0){
allIdentitiesStatisticsBinding.Set("Loading.")
matchStatisticsBinding.Set("Loading.")
} else if (secondsElapsed %3 == 1){
allIdentitiesStatisticsBinding.Set("Loading..")
matchStatisticsBinding.Set("Loading..")
} else {
allIdentitiesStatisticsBinding.Set("Loading...")
matchStatisticsBinding.Set("Loading...")
}
time.Sleep(time.Second)
secondsElapsed += 1
}
}
go updateBindingsWithProgressEllipsesFunction()
totalNumberOfMateIdentities, numberOfMateIdentitiesWhoPassDesire, percentageOfMateIdentitiesWhoPassDesire, numberOfMatches, numberOfMatchesWhoPassDesire, percentageOfMatchesWhoPassDesire, err := myDesireStatistics.GetMyDesireStatistics(desireName, appNetworkType)
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
statisticsFound = true
totalNumberOfMateIdentitiesString := helpers.ConvertInt64ToString(totalNumberOfMateIdentities)
numberOfMateIdentitiesWhoPassDesireString := helpers.ConvertInt64ToString(numberOfMateIdentitiesWhoPassDesire)
percentageOfMateIdentiesWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfMateIdentitiesWhoPassDesire, 1)
numberOfMatchesString := helpers.ConvertInt64ToString(numberOfMatches)
numberOfMatchesWhoPassDesireString := helpers.ConvertInt64ToString(numberOfMatchesWhoPassDesire)
percentageOfMatchesWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfMatchesWhoPassDesire, 1)
allIdentitiesStatisticsString := numberOfMateIdentitiesWhoPassDesireString + "/" + totalNumberOfMateIdentitiesString + " = " + percentageOfMateIdentiesWhoPassDesireString + "%"
matchesStatisticsString := numberOfMatchesWhoPassDesireString + "/" + numberOfMatchesString + " = " + percentageOfMatchesWhoPassDesireString + "%"
allIdentitiesStatisticsBinding.Set(allIdentitiesStatisticsString)
matchStatisticsBinding.Set(matchesStatisticsString)
}
description1 := getLabelCentered("Below are your " + desireTitle + " desire statistics.")
description2 := getLabelCentered("They are the statistics of the users who pass your " + desireTitle + " desires.")
description3 := getLabelCentered("My Matches divides by the number of matches you would have without the desire.")
allUsersLabel := getBoldLabelCentered("All Users:")
allIdentitiesStatisticsLabel := getWidgetCentered(widget.NewLabelWithData(allIdentitiesStatisticsBinding))
myMatchesLabel := getBoldLabelCentered("My Matches:")
matchIdentitiesStatisticsLabel := getWidgetCentered(widget.NewLabelWithData(matchStatisticsBinding))
accuracyWarningButton := getWidgetCentered(widget.NewButtonWithIcon("Statistics Warning", theme.WarningIcon(), func(){
setMateDesireStatisticsWarningPage(window, currentPage)
}))
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), allUsersLabel, allIdentitiesStatisticsLabel, myMatchesLabel, matchIdentitiesStatisticsLabel, widget.NewSeparator(), accuracyWarningButton)
if (showChartsButton == true){
page.Add(widget.NewSeparator())
description4 := getLabelCentered("Visualize the distribution of users on a chart.")
page.Add(description4)
viewChartButton := getWidgetCentered(widget.NewButtonWithIcon("View Chart", theme.InfoIcon(), viewChartsFunction))
page.Add(viewChartButton)
}
setPageContent(page, window)
go updateBindingsFunction()
}
func setViewAllMyDesireStatisticsPage(window fyne.Window, statisticsReady bool, numberOfMateIdentities int64, numberOfMatches int64, statisticsItemsList []myDesireStatistics.DesireStatisticsItem, previousPage func()){
pageIdentifier, err := helpers.GetNewRandomHexString(16)
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
appMemory.SetMemoryEntry("CurrentViewedPage", pageIdentifier)
checkIfPageHasChangedFunction := func()bool{
exists, currentViewedPage := appMemory.GetMemoryEntry("CurrentViewedPage")
if (exists == true && currentViewedPage == pageIdentifier){
return false
}
return true
}
currentPage := func(){setViewAllMyDesireStatisticsPage(window, statisticsReady, numberOfMateIdentities, numberOfMatches, statisticsItemsList, previousPage)}
title := getPageTitleCentered("My Mate Desire Statistics")
backButton := getBackButtonCentered(previousPage)
if (statisticsReady == false){
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
if (err != nil) {
setErrorEncounteredPage(window, err, previousPage)
return
}
loadingTextBinding := binding.NewString()
loadingTextBinding.Set("Loading Statistics...")
loadingProgressBinding := binding.NewString()
loadingTextLabel := widget.NewLabelWithData(loadingTextBinding)
loadingTextLabel.TextStyle = getFyneTextStyle_Bold()
loadingTextLabelCentered := getWidgetCentered(loadingTextLabel)
loadingProgressLabel := getWidgetCentered(widget.NewLabelWithData(loadingProgressBinding))
calculateStatisticsAndRefreshPageFunction := func(){
progressIdentifier, _ := helpers.GetNewRandomHexString(16)
statisticsComplete := false
updateLoadingBindingFunction := func(){
startTime := time.Now().Unix()
for {
currentTime := time.Now().Unix()
secondsElapsed := currentTime - startTime
if (secondsElapsed % 3 == 0){
loadingTextBinding.Set("Loading Statistics.")
} else if (secondsElapsed % 3 == 1){
loadingTextBinding.Set("Loading Statistics..")
} else {
loadingTextBinding.Set("Loading Statistics...")
}
statusExists, newProgressStatus := appMemory.GetMemoryEntry(progressIdentifier)
if (statusExists == true){
loadingProgressBinding.Set(newProgressStatus)
}
pageHasChanged := checkIfPageHasChangedFunction()
if (pageHasChanged == true){
return
}
if (statisticsComplete == true){
return
}
time.Sleep(100 * time.Millisecond)
}
}
go updateLoadingBindingFunction()
numberOfMateIdentities, numberOfMatches, myDesireStatisticsItemsList, err := myDesireStatistics.GetAllMyDesireStatistics(progressIdentifier, appNetworkType)
if (err != nil) {
statisticsComplete = true
pageHasChanged := checkIfPageHasChangedFunction()
if (pageHasChanged == false){
setErrorEncounteredPage(window, err, previousPage)
}
return
}
statisticsComplete = true
pageHasChanged := checkIfPageHasChangedFunction()
if (pageHasChanged == false){
setViewAllMyDesireStatisticsPage(window, true, numberOfMateIdentities, numberOfMatches, myDesireStatisticsItemsList, previousPage)
}
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), loadingTextLabelCentered, loadingProgressLabel)
setPageContent(page, window)
go calculateStatisticsAndRefreshPageFunction()
return
}
setLoadingScreen(window, "My Mate Desire Statistics", "Loading desire statistics...")
getStatisticsSection := func()(*fyne.Container, error){
// These are the desires for which FilterAll and Require Response is disabled
// These desires will not filter any matches. They only effect match score
disabledDesiresList := make([]string, 0)
desireNameLabel := getItalicLabelCentered("Desire Name")
allUsersLabel := getItalicLabelCentered("All Users")
myMatchesLabel := getItalicLabelCentered("My Matches")
desireTitlesColumn := container.NewVBox(desireNameLabel, widget.NewSeparator())
allUsersColumn := container.NewVBox(allUsersLabel, widget.NewSeparator())
myMatchesColumn := container.NewVBox(myMatchesLabel, widget.NewSeparator())
numberOfMateIdentitiesString := helpers.ConvertInt64ToString(numberOfMateIdentities)
numberOfMatchesString := helpers.ConvertInt64ToString(numberOfMatches)
for _, desireObject := range statisticsItemsList{
desireName := desireObject.DesireName
numberOfUsersWhoPassDesire := desireObject.NumberOfUsersWhoPassDesire
percentageOfUsersWhoPassDesire := desireObject.PercentageOfUsersWhoPassDesire
numberOfDesireExcludedMatches := desireObject.NumberOfDesireExcludedMatches
percentageOfDesireExcludedMatchesWhoPassDesire := desireObject.PercentageOfDesireExcludedMatchesWhoPassDesire
desireTitle, err := mateDesires.GetDesireTitleFromDesireName(desireName)
if (err != nil){ return nil, err }
desireTitleTranslated := translate(desireTitle)
checkIfDesireIsDisabled := func()(bool, error){
exists, filterAllStatus, err := myLocalDesires.GetDesire(desireName + "_FilterAll")
if (err != nil) { return false, err }
if (exists == true && filterAllStatus == "Yes"){
return false, nil
}
requireResponseAllowed, _ := mateDesires.CheckIfDesireAllowsRequireResponse(desireName)
if (requireResponseAllowed == true){
exists, requireResponseStatus, err := myLocalDesires.GetDesire(desireName + "_RequireResponse")
if (err != nil) { return false, err }
if (exists == true && requireResponseStatus == "Yes"){
return false, nil
}
}
// Desire is disabled
// We use 99.9 because floating point is not exact, we really mean 100%.
if (percentageOfUsersWhoPassDesire < 99.9){
return false, errors.New("Disabled desire does not have a 100% pass rate: " + desireName)
}
return true, nil
}
desireIsDisabled, err := checkIfDesireIsDisabled()
if (err != nil) { return nil, err }
if (desireIsDisabled == true){
disabledDesiresList = append(disabledDesiresList, desireTitleTranslated)
continue
}
desireTitleLabel := getBoldLabelCentered(desireTitleTranslated)
numberOfUsersWhoPassDesireString := helpers.ConvertInt64ToString(numberOfUsersWhoPassDesire)
percentageOfUsersWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfUsersWhoPassDesire, 1)
numberOfDesireExcludedMatchesString := helpers.ConvertInt64ToString(numberOfDesireExcludedMatches)
percentageOfDesireExcludedMatchesWhoPassDesireString := helpers.ConvertFloat64ToStringRounded(percentageOfDesireExcludedMatchesWhoPassDesire, 1)
allUsersLabel := getBoldLabelCentered(numberOfUsersWhoPassDesireString + "/" + numberOfMateIdentitiesString + " = " + percentageOfUsersWhoPassDesireString + "%")
matchesLabel := getBoldLabelCentered(numberOfMatchesString + "/" + numberOfDesireExcludedMatchesString + " = " + percentageOfDesireExcludedMatchesWhoPassDesireString + "%")
desireTitlesColumn.Add(desireTitleLabel)
allUsersColumn.Add(allUsersLabel)
myMatchesColumn.Add(matchesLabel)
desireTitlesColumn.Add(widget.NewSeparator())
allUsersColumn.Add(widget.NewSeparator())
myMatchesColumn.Add(widget.NewSeparator())
}
numberOfDisabledDesires := len(disabledDesiresList)
if (numberOfDisabledDesires == len(statisticsItemsList)){
description1 := getBoldLabelCentered("All of your desires are disabled.")
description2 := getLabelCentered("None of your desires have Filter All or Require Response enabled.")
description3 := getLabelCentered("All users are your matches.")
viewDisabledDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("View Disabled Desires", theme.VisibilityIcon(), func(){
setViewAllMyDisabledDesiresPage(window, disabledDesiresList, currentPage)
}))
statisticsSection := container.NewVBox(description1, description2, description3, viewDisabledDesiresButton)
return statisticsSection, nil
}
description1 := getLabelCentered("Below are the percentages of users who pass each of your desires.")
description2 := getLabelCentered("My Matches divides by the number of matches you would have without the desire.")
accuracyWarningButton := getWidgetCentered(widget.NewButtonWithIcon("Statistics Warning", theme.WarningIcon(), func(){
setMateDesireStatisticsWarningPage(window, currentPage)
}))
statisticsGrid := container.NewHBox(layout.NewSpacer(), desireTitlesColumn, allUsersColumn, myMatchesColumn, layout.NewSpacer())
numberOfDisabledDesiresString := helpers.ConvertIntToString(numberOfDisabledDesires)
disabledDesiresDescription1 := getBoldLabelCentered("There are " + numberOfDisabledDesiresString + " desires with Filter All and Require Response disabled.")
disabledDesiresDescription2 := getLabelCentered("These desires do not filter any matches.")
viewDisabledDesiresButton := getWidgetCentered(widget.NewButtonWithIcon("View Disabled Desires", theme.VisibilityIcon(), func(){
setViewAllMyDisabledDesiresPage(window, disabledDesiresList, currentPage)
}))
statisticsSection := container.NewVBox(description1, description2, widget.NewSeparator(), accuracyWarningButton, widget.NewSeparator(), statisticsGrid, widget.NewSeparator(), disabledDesiresDescription1, disabledDesiresDescription2, viewDisabledDesiresButton)
return statisticsSection, nil
}
statisticsSection, err := getStatisticsSection()
if (err != nil){
setErrorEncounteredPage(window, err, previousPage)
return
}
page := container.NewVBox(title, backButton, widget.NewSeparator(), statisticsSection)
setPageContent(page, window)
}
func setViewAllMyDisabledDesiresPage(window fyne.Window, disabledDesiresList []string, previousPage func()){
title := getPageTitleCentered("My Mate Desire Statistics")
backButton := getBackButtonCentered(previousPage)
subtitle := getPageSubtitleCentered("Disabled Desires")
description1 := getLabelCentered("Below are your desires with Filter All and Require Response disabled.")
description2 := getLabelCentered("They will not filter any matches.")
description3 := getLabelCentered("They will only effect match scores.")
disabledDesiresGrid := container.NewGridWithColumns(2)
for _, desireTitle := range disabledDesiresList{
desireTitleLabel := getBoldLabelCentered(desireTitle)
disabledDesiresGrid.Add(desireTitleLabel)
}
disabledDesiresGridCentered := getContainerCentered(disabledDesiresGrid)
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), disabledDesiresGridCentered)
setPageContent(page, window)
}