2024-04-11 15:51:56 +02:00
package gui
// viewProfileGui.go implements pages to view user profiles
import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/canvas"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/dialog"
import "fyne.io/fyne/v2/layout"
import "fyne.io/fyne/v2/theme"
import "fyne.io/fyne/v2/widget"
import "seekia/resources/worldLanguages"
import "seekia/resources/worldLocations"
2024-08-15 14:14:23 +02:00
import "seekia/resources/trainedPredictionModels"
2024-04-11 15:51:56 +02:00
import "seekia/resources/geneticReferences/monogenicDiseases"
import "seekia/resources/geneticReferences/polygenicDiseases"
import "seekia/resources/geneticReferences/traits"
import "seekia/internal/appMemory"
import "seekia/internal/encoding"
import "seekia/internal/genetics/companyAnalysis"
2024-06-15 02:43:01 +02:00
import "seekia/internal/genetics/createCoupleGeneticAnalysis"
import "seekia/internal/genetics/createPersonGeneticAnalysis"
2024-06-05 06:10:35 +02:00
import "seekia/internal/genetics/locusValue"
2024-04-11 15:51:56 +02:00
import "seekia/internal/genetics/myChosenAnalysis"
import "seekia/internal/genetics/myPeople"
import "seekia/internal/genetics/readGeneticAnalysis"
import "seekia/internal/globalSettings"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/imagery"
import "seekia/internal/mateQuestionnaire"
import "seekia/internal/moderation/moderatorRanking"
import "seekia/internal/moderation/trustedViewableStatus"
import "seekia/internal/moderation/verifiedStickyStatus"
import "seekia/internal/myIdentity"
import "seekia/internal/network/appNetworkType/getAppNetworkType"
import "seekia/internal/network/fundedStatus"
import "seekia/internal/network/myBroadcasts"
import "seekia/internal/profiles/attributeDisplay"
import "seekia/internal/profiles/calculatedAttributes"
import "seekia/internal/profiles/myLocalProfiles"
import "seekia/internal/profiles/myProfileExports"
import "seekia/internal/profiles/myProfileStatus"
import "seekia/internal/profiles/profileStorage"
import "seekia/internal/profiles/readProfiles"
import "seekia/internal/profiles/viewableProfiles"
import "slices"
import "strings"
import "image"
import "time"
import "errors"
// This page will show user the difference between local/public and let them choose
func setViewMyLocalOrPublicProfilePage ( window fyne . Window , myProfileType string , previousPage func ( ) ) {
setLoadingScreen ( window , "Loading My Profile" , "Loading..." )
if ( myProfileType != "Mate" && myProfileType != "Host" && myProfileType != "Moderator" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMyLocalOrPublicProfilePage called with invalid profile type: " + myProfileType ) , previousPage )
return
}
currentPage := func ( ) { setViewMyLocalOrPublicProfilePage ( window , myProfileType , previousPage ) }
title := getPageTitleCentered ( translate ( "View My Profile" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( "View My " + myProfileType + " Profile" )
myIdentityExists , _ , err := myIdentity . GetMyIdentityHash ( myProfileType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( myIdentityExists == false ) {
description1 := getBoldLabelCentered ( "Your " + myProfileType + " identity does not exist." )
description2 := getLabelCentered ( "Create your " + myProfileType + " identity below." )
createIdentityButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Create Identity" , theme . NavigateNextIcon ( ) , func ( ) {
setChooseNewIdentityHashPage ( window , myProfileType , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , createIdentityButton )
setPageContent ( page , window )
return
}
description1 := getLabelCentered ( "Choose which profile to view." )
description2 := getLabelCentered ( "Your Local profile is the profile stored on your computer." )
description3 := getLabelCentered ( "Your Public profile is the most recent profile that you have broadcasted." )
localIcon , err := getFyneImageIcon ( "Local" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
publicIcon , err := getFyneImageIcon ( "Broadcast" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
viewLocalProfileButton := widget . NewButton ( "Local" , func ( ) {
setViewMyProfilePage ( window , myProfileType , "Local" , currentPage )
} )
viewPublicProfileButton := widget . NewButton ( "Public" , func ( ) {
setViewMyProfilePage ( window , myProfileType , "Public" , currentPage )
} )
viewLocalButtonWithIcon := container . NewGridWithColumns ( 1 , localIcon , viewLocalProfileButton )
viewPublicButtonWithIcon := container . NewGridWithColumns ( 1 , publicIcon , viewPublicProfileButton )
buttonsRow := container . NewHBox ( layout . NewSpacer ( ) , viewLocalButtonWithIcon , viewPublicButtonWithIcon , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , description3 , widget . NewSeparator ( ) , buttonsRow , widget . NewSeparator ( ) )
setPageContent ( page , window )
}
func setViewMyProfilePage ( window fyne . Window , myProfileType string , localOrPublic string , previousPage func ( ) ) {
if ( myProfileType != "Mate" && myProfileType != "Host" && myProfileType != "Moderator" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMyProfilePage called with invalid myProfileType: " + myProfileType ) , previousPage )
return
}
if ( localOrPublic != "Local" && localOrPublic != "Public" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMyProfilePage called with invalid localOrPublic: " + localOrPublic ) , previousPage )
return
}
currentPage := func ( ) { setViewMyProfilePage ( window , myProfileType , localOrPublic , previousPage ) }
title := getPageTitleCentered ( "View My Profile" )
backButton := getBackButtonCentered ( previousPage )
myIdentityExists , myIdentityHash , err := myIdentity . GetMyIdentityHash ( myProfileType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( myIdentityExists == false ) {
description1 := getBoldLabelCentered ( "Your " + myProfileType + " identity does not exist." )
description2 := getLabelCentered ( "Create your " + myProfileType + " identity below." )
createIdentityButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Create Identity" , theme . NavigateNextIcon ( ) , func ( ) {
setChooseNewIdentityHashPage ( window , myProfileType , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , createIdentityButton )
setPageContent ( page , window )
return
}
if ( myProfileType == "Mate" ) {
myGenomePersonIdentifierExists , myGenomePersonIdentifier , err := myLocalProfiles . GetProfileData ( "Mate" , "GenomePersonIdentifier" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( myGenomePersonIdentifierExists == true ) {
anyGenomesExist , personAnalysisIsReady , _ , err := myPeople . CheckIfPersonAnalysisIsReady ( myGenomePersonIdentifier )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( anyGenomesExist == true && personAnalysisIsReady == false ) {
description1 := getBoldLabelCentered ( translate ( "Your profile contains a linked genome person." ) )
description2 := getLabelCentered ( translate ( "You need to perform your genetic analysis." ) )
description3 := getLabelCentered ( translate ( "Only the information you choose will be shared in your profile." ) )
performAnalysisButton := getWidgetCentered ( widget . NewButtonWithIcon ( translate ( "Perform Analysis" ) , theme . NavigateNextIcon ( ) , func ( ) {
setConfirmPerformPersonAnalysisPage ( window , myGenomePersonIdentifier , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , performAnalysisButton )
setPageContent ( page , window )
return
}
}
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
err = myProfileExports . UpdateMyExportedProfile ( myProfileType , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
profileFound , profileHash , _ , rawProfileMap , err := myProfileExports . GetMyExportedProfile ( myProfileType , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( profileFound == false ) {
setErrorEncounteredPage ( window , errors . New ( "My exported profile not found after exporting." ) , previousPage )
return
}
getAnyLocalProfileAttributeFunction , err := calculatedAttributes . GetRetrieveAnyProfileAttributeIncludingCalculatedFunction ( 1 , rawProfileMap )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
exists , _ , iAmDisabled , err := getAnyLocalProfileAttributeFunction ( "Disabled" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( exists == true && iAmDisabled == "Yes" ) {
description1 := getBoldLabelCentered ( "Your " + myProfileType + " profile is disabled." )
description2 := getLabelCentered ( "Re-enable it on the Broadcast page." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 )
setPageContent ( page , window )
return
}
if ( localOrPublic == "Local" ) {
setViewUserProfilePage ( window , true , profileHash , 0 , getAnyLocalProfileAttributeFunction , previousPage )
return
}
// localOrPublic == "Public"
identityExists , broadcastProfileExists , publicProfileHash , getAnyPublicProfileAttributeFunction , err := myBroadcasts . GetRetrieveAnyAttributeFromMyBroadcastProfileFunction ( myIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( identityExists == false ) {
setErrorEncounteredPage ( window , errors . New ( "My identity not found after being found already." ) , previousPage )
return
}
if ( broadcastProfileExists == false ) {
description1 := getBoldLabelCentered ( "Your public profile does not exist." )
description2 := getLabelCentered ( "You have not broadcast your profile." )
description3 := getLabelCentered ( "Broadcast your profile on the Profile - Broadcast page." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 )
setPageContent ( page , window )
return
}
myIdentityExists , myProfileIsActive , err := myProfileStatus . GetMyProfileIsActiveStatus ( myIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( myIdentityExists == false ) {
setErrorEncounteredPage ( window , errors . New ( "My identity not found after being found already." ) , previousPage )
return
}
if ( myProfileIsActive == false ) {
description1 := getBoldLabelCentered ( "Your public profile has expired." )
description2 := getLabelCentered ( "You must broadcast your profile again." )
description3 := getLabelCentered ( "Broadcast your profile on the Profile - Broadcast page." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 )
setPageContent ( page , window )
return
}
setViewUserProfilePage ( window , true , publicProfileHash , 0 , getAnyPublicProfileAttributeFunction , previousPage )
}
func setViewPeerProfilePageFromIdentityHash ( window fyne . Window , peerIdentityHash [ 16 ] byte , previousPage func ( ) ) {
setLoadingScreen ( window , "View Profile" , "Loading Profile..." )
currentPage := func ( ) { setViewPeerProfilePageFromIdentityHash ( window , peerIdentityHash , previousPage ) }
title := getPageTitleCentered ( translate ( "View Profile" ) )
backButton := getBackButtonCentered ( previousPage )
userIdentityType , err := identity . GetIdentityTypeFromIdentityHash ( peerIdentityHash )
if ( err != nil ) {
peerIdentityHashHex := encoding . EncodeBytesToHexString ( peerIdentityHash [ : ] )
setErrorEncounteredPage ( window , errors . New ( "setViewPeerProfilePageFromIdentityHash called with invalid peerIdentityHash: " + peerIdentityHashHex ) , previousPage )
return
}
// We only allow unknown viewable status profiles to be viewed if the user profile type is host/moderator
getAllowUnknownStatusBool := func ( ) bool {
if ( userIdentityType == "Mate" ) {
return false
}
return true
}
allowUnknownStatusBool := getAllowUnknownStatusBool ( )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
viewableProfileExists , profileHash , getAnyAttributeFromViewableProfileFunction , err := viewableProfiles . GetRetrieveAnyNewestViewableUserProfileAttributeFunction ( peerIdentityHash , appNetworkType , true , allowUnknownStatusBool , true )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( viewableProfileExists == true ) {
// The user has a viewable profile.
// We display it.
setViewUserProfilePage ( window , false , profileHash , 0 , getAnyAttributeFromViewableProfileFunction , previousPage )
return
}
// Viewable profile does not exist
// We check to see if any profile exists
//Outputs:
// -bool: Viewable status is known
// -bool: Identity Is Viewable status
// -error
getIdentityIsViewableStickyStatus := func ( ) ( bool , bool , error ) {
// First try verified status, then try trusted if verified is not available
downloadingRequiredReviews , networkParametersExist , stickyConsensusEstablished , identityIsViewableStatus , err := verifiedStickyStatus . GetVerifiedIdentityIsViewableStickyStatus ( peerIdentityHash , appNetworkType )
if ( err != nil ) { return false , false , err }
if ( downloadingRequiredReviews == true && networkParametersExist == true && stickyConsensusEstablished == true ) {
return true , identityIsViewableStatus , nil
}
statusIsKnown , identityIsViewable , _ , err := trustedViewableStatus . GetTrustedIdentityIsViewableStatus ( peerIdentityHash , appNetworkType )
if ( err != nil ) { return false , false , err }
if ( statusIsKnown == true ) {
return true , identityIsViewable , nil
}
return false , false , nil
}
identityViewableStatusIsKnown , identityIsViewableStatus , err := getIdentityIsViewableStickyStatus ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
theirNewestProfileExists , newestProfileVersion , newestProfileHash , _ , _ , newestProfileRawMap , err := profileStorage . GetNewestUserProfile ( peerIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( theirNewestProfileExists == false ) {
// Their profile does not exist.
downloadProfileFunction := func ( ) { setDownloadMissingUserProfilePage ( window , peerIdentityHash , true , true , previousPage , currentPage , previousPage ) }
if ( identityViewableStatusIsKnown == true && identityIsViewableStatus == false ) {
description1 := getLabelCentered ( "This user is banned." )
description2 := getLabelCentered ( "You do not have their profile downloaded." )
description3 := getLabelCentered ( "Do you want to try to download their profile?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . ConfirmIcon ( ) , downloadProfileFunction ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
// Identity is not banned. Profile does not exist
// We check if user's identity is known to be expired.
statusIsKnown , identityIsFunded , err := fundedStatus . GetIdentityIsFundedStatus ( peerIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( statusIsKnown == true && identityIsFunded == false ) {
// Identity is known to be expired
description1 := getBoldLabelCentered ( "This user's identity is expired." )
description2 := getLabelCentered ( "Their profile is expired from the network." )
description3 := getLabelCentered ( "You can try to update this status to see if the user's identity is funded." )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , func ( ) {
//TODO:
// Use manualDownloads to update the user identity's funded status
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , updateButton )
setPageContent ( page , window )
return
}
// We will commence profile download without any prompt.
downloadProfileFunction ( )
return
}
// We know their profile exists, but it is not viewable
// For host/moderator profiles, this must mean that the profile/identity is banned
// For mate profiles, it could also mean that we have not downloaded the profile's sticky viewable status
getAnyNewestProfileAttributeFunction , err := calculatedAttributes . GetRetrieveAnyProfileAttributeIncludingCalculatedFunction ( newestProfileVersion , newestProfileRawMap )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
viewNewestProfileFunction := func ( ) { setViewUserProfilePage ( window , false , newestProfileHash , 0 , getAnyNewestProfileAttributeFunction , previousPage ) }
_ , newestProfileIsDisabled , err := readProfiles . ReadProfileHashMetadata ( newestProfileHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( newestProfileIsDisabled == true ) {
// Their newest profile is disabled.
// The user must be banned.
// We can show it to the user.
viewNewestProfileFunction ( )
return
}
if ( identityViewableStatusIsKnown == true && identityIsViewableStatus == false ) {
description1 := getBoldLabelCentered ( "This user is banned." )
description2 := getLabelCentered ( "Do you want to view their profile anyway?" )
viewProfileButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Profile" , theme . VisibilityIcon ( ) , viewNewestProfileFunction ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , viewProfileButton )
setPageContent ( page , window )
return
}
if ( userIdentityType == "Host" || userIdentityType == "Moderator" ) {
// Host/moderator profiles are not considered unviewable until they are banned, or their author is banned.
// An unreviewed host/moderator profile is considered viewable.
// We already checked to see if the user's identity is banned
// Therefore, we know that this profile is banned.
description1 := getBoldLabelCentered ( "This user's profile is banned." )
description2 := getLabelCentered ( "Do you want to view their profile anyway?" )
viewProfileButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Profile" , theme . VisibilityIcon ( ) , viewNewestProfileFunction ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , viewProfileButton )
setPageContent ( page , window )
return
}
// userIdentityType == "Mate"
// We know the user's identity is either viewable or unknown
// We check to see if mate profile is viewable
//Outputs:
// -bool: Profile metadata found
// -bool: Viewable Status is known
// -bool: Profile is viewable
// -error
getNewestProfileIsViewableStatus := func ( ) ( bool , bool , bool , error ) {
profileIsDisabled , profileMetadataIsKnown , profileNetworkType , profileIdentityHash , downloadingRequiredReviews , networkParametersExist , stickyConsensusEstablished , profileIsViewableStatus , err := verifiedStickyStatus . GetVerifiedProfileIsViewableStickyStatus ( newestProfileHash )
if ( err != nil ) { return false , false , false , err }
if ( profileIsDisabled == true ) {
return false , false , false , errors . New ( "GetVerifiedProfileIsViewableStickyStatus returning different profileIsDisabled status than ReadProfileHashMetadata." )
}
if ( profileMetadataIsKnown == false ) {
// Profile metadata must have been deleted after earlier check.
return false , false , false , nil
}
if ( profileNetworkType != appNetworkType ) {
return false , false , false , errors . New ( "GetVerifiedProfileIsViewableStickyStatus returning different networkType than requested from GetNewestUserProfile." )
}
if ( profileIdentityHash != peerIdentityHash ) {
return false , false , false , errors . New ( "GetVerifiedProfileIsViewableStickyStatus returning different profileIdentityHash" )
}
if ( downloadingRequiredReviews == true && networkParametersExist == true && stickyConsensusEstablished == true ) {
return true , true , profileIsViewableStatus , nil
}
return true , false , false , nil
}
newestProfileMetadataFound , profileViewableStatusIsKnown , profileIsViewableStatus , err := getNewestProfileIsViewableStatus ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( newestProfileMetadataFound == false ) {
// This should only happen if the profile metadata was deleted after our earlier check
// We show a loading screen so this issue can be identified if it is because of an error
setLoadingScreen ( window , "Loading Profile" , "Looking for profile..." )
time . Sleep ( time . Second )
currentPage ( )
return
}
if ( profileViewableStatusIsKnown == true && profileIsViewableStatus == false ) {
description1 := getBoldLabelCentered ( "This user's profile is not viewable." )
description2 := getLabelCentered ( "It may be banned, or not yet approved." )
description3 := getLabelCentered ( "Do you still want to view it?" )
viewProfileButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Profile" , theme . VisibilityIcon ( ) , viewNewestProfileFunction ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , viewProfileButton )
setPageContent ( page , window )
return
}
// We know the profile is not considered viewable
// We know the identity is not banned, or its status is unknown
// We know the profile is not known to be unviewable
// Therefore, the profile viewable status must be unknown
description1 := getBoldLabelCentered ( "This user's profile has an unknown moderation status." )
description2 := getLabelCentered ( "Do you still want to view their profile?" )
description3 := getLabelCentered ( "If not, you must wait for Seekia to download the profile's moderation status." )
description4 := getLabelCentered ( "After the download, you will know if the profile is banned or viewable." )
description5 := getLabelCentered ( "This will happen automatically in the background." )
description6 := getLabelCentered ( "Refresh the page to check if the status is downloaded." )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , currentPage ) )
viewProfileButton := widget . NewButtonWithIcon ( "View Profile" , theme . VisibilityIcon ( ) , viewNewestProfileFunction )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , viewProfileButton , widget . NewSeparator ( ) , description3 , description4 , description5 , description6 , refreshButton )
setPageContent ( page , window )
}
func setViewUserProfilePage ( window fyne . Window , profileIsMine bool , profileHash [ 28 ] byte , currentImageIndex int , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
pageIdentifier , err := helpers . GetNewRandomHexString ( 16 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
appMemory . SetMemoryEntry ( "CurrentViewedPage" , pageIdentifier )
getTitleText := func ( ) string {
if ( profileIsMine == true ) {
return "Viewing My Profile"
}
return "Viewing Profile"
}
titleText := getTitleText ( )
setLoadingScreen ( window , titleText , "Loading Profile..." )
currentPage := func ( ) { setViewUserProfilePage ( window , profileIsMine , profileHash , currentImageIndex , getAnyUserProfileAttributeFunction , previousPage ) }
userIdentityHashExists , _ , userIdentityHashString , err := getAnyUserProfileAttributeFunction ( "IdentityHash" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( userIdentityHashExists == false ) {
setErrorEncounteredPage ( window , errors . New ( "Failed to get user profile IdentityHash" ) , previousPage )
return
}
userIdentityHash , userProfileType , err := identity . ReadIdentityHashString ( userIdentityHashString )
if ( err != nil ) {
setErrorEncounteredPage ( window , errors . New ( "getAnyUserProfileAttributeFunction returning invalid IdentityHash: " + userIdentityHashString ) , previousPage )
return
}
title := getPageTitleCentered ( titleText )
backButton := getBackButtonCentered ( previousPage )
getProfileIsDisabledStatus := func ( ) ( bool , error ) {
exists , _ , disabledAttribute , err := getAnyUserProfileAttributeFunction ( "Disabled" )
if ( err != nil ) { return false , err }
if ( exists == true && disabledAttribute == "Yes" ) {
return true , nil
}
return false , nil
}
userIsDisabled , err := getProfileIsDisabledStatus ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( userIsDisabled == true ) {
description1 := getBoldLabelCentered ( "User Is Disabled." )
getDescription2Text := func ( ) string {
if ( profileIsMine == true ) {
result := translate ( "You have disabled your profile." )
return result
}
result := translate ( "This user has disabled their profile." )
return result
}
description2Text := getDescription2Text ( )
description2 := getLabelCentered ( description2Text )
theirIdentityHashLabel := getItalicLabelCentered ( "User Identity Hash:" )
theirIdentityHashText := getBoldLabelCentered ( userIdentityHashString )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , theirIdentityHashLabel , theirIdentityHashText )
if ( profileIsMine == false ) {
page . Add ( widget . NewSeparator ( ) )
actionsButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Actions" , theme . ContentRedoIcon ( ) , func ( ) {
setViewPeerActionsPage ( window , userIdentityHash , currentPage )
} ) )
page . Add ( actionsButton )
}
setPageContent ( page , window )
return
}
getProfileContainer := func ( ) ( * fyne . Container , error ) {
chatButton := widget . NewButtonWithIcon ( "Chat" , theme . MailComposeIcon ( ) , func ( ) {
if ( profileIsMine == true ) {
dialogTitle := translate ( "Chat Inaccessible" )
dialogMessageA := getLabelCentered ( translate ( "You are viewing your own profile." ) )
dialogMessageB := getLabelCentered ( translate ( "You cannot chat with yourself." ) )
dialogContent := container . NewVBox ( dialogMessageA , dialogMessageB )
dialog . ShowCustom ( dialogTitle , translate ( "Close" ) , dialogContent , window )
return
}
setViewAConversationPage ( window , userIdentityHash , true , currentPage )
} )
actionsButton := widget . NewButtonWithIcon ( "Actions" , theme . ContentRedoIcon ( ) , func ( ) {
if ( profileIsMine == true ) {
dialogTitle := translate ( "Peer Actions Inaccessible" )
dialogMessageA := getLabelCentered ( translate ( "You are viewing your own profile." ) )
dialogMessageB := getLabelCentered ( translate ( "You cannot access the peer actions page for your own identity." ) )
dialogContent := container . NewVBox ( dialogMessageA , dialogMessageB )
dialog . ShowCustom ( dialogTitle , translate ( "Close" ) , dialogContent , window )
return
}
setViewPeerActionsPage ( window , userIdentityHash , currentPage )
} )
topRowLeftButtonsColumn := container . NewGridWithColumns ( 1 , chatButton , actionsButton )
getPhotosColumnWithNavigationButtons := func ( ) ( * fyne . Container , error ) {
imageObjectsList := make ( [ ] image . Image , 0 )
if ( userProfileType == "Mate" ) {
exists , _ , webpPhotosAttribute , err := getAnyUserProfileAttributeFunction ( "Photos" )
if ( err != nil ) { return nil , err }
if ( exists == true ) {
webpPhotosList := strings . Split ( webpPhotosAttribute , "+" )
for _ , base64Image := range webpPhotosList {
imageObject , err := imagery . ConvertWEBPBase64StringToCroppedDownsizedImageObject ( base64Image )
if ( err != nil ) { return nil , err }
imageObjectsList = append ( imageObjectsList , imageObject )
}
}
}
getAvatarEmojiIdentifier := func ( ) ( int , error ) {
exists , _ , emojiIdentifier , err := getAnyUserProfileAttributeFunction ( "Avatar" )
if ( err != nil ) { return 0 , err }
if ( exists == false ) {
// This is the avatar for users who have not selected an avatar
return 2929 , nil
}
emojiIdentifierInt , err := helpers . ConvertStringToInt ( emojiIdentifier )
if ( err != nil ) {
return 0 , errors . New ( "User profile is malformed: Invalid avatar: " + emojiIdentifier )
}
return emojiIdentifierInt , nil
}
avatarEmojiIdentifier , err := getAvatarEmojiIdentifier ( )
if ( err != nil ) { return nil , err }
avatarImage , err := getEmojiImageObject ( avatarEmojiIdentifier )
if ( err != nil ) { return nil , err }
imageObjectsList = append ( imageObjectsList , avatarImage )
numberOfImages := len ( imageObjectsList )
getImageIndex := func ( ) int {
if ( currentImageIndex <= 0 ) {
return 0
}
finalIndex := numberOfImages - 1
if ( currentImageIndex >= finalIndex ) {
return finalIndex
}
return currentImageIndex
}
imageIndex := getImageIndex ( )
currentImage := imageObjectsList [ imageIndex ]
currentFyneImage := canvas . NewImageFromImage ( currentImage )
currentFyneImage . FillMode = canvas . ImageFillContain
currentFyneImage . SetMinSize ( getCustomFyneSize ( 30 ) )
getNavigationWithZoomRow := func ( ) * fyne . Container {
zoomButton := widget . NewButtonWithIcon ( "" , theme . ZoomInIcon ( ) , func ( ) {
setViewFullpageImagesWithNavigationPage ( window , imageObjectsList , imageIndex , currentPage )
} )
if ( numberOfImages == 1 ) {
zoomButtonRow := getWidgetCentered ( zoomButton )
return zoomButtonRow
}
getBackButton := func ( ) fyne . Widget {
if ( imageIndex <= 0 ) {
button := widget . NewButton ( "" , nil )
return button
}
button := widget . NewButtonWithIcon ( "" , theme . NavigateBackIcon ( ) , func ( ) {
newImageIndex := imageIndex - 1
setViewUserProfilePage ( window , profileIsMine , profileHash , newImageIndex , getAnyUserProfileAttributeFunction , previousPage )
} )
return button
}
getNextButton := func ( ) fyne . Widget {
if ( imageIndex >= numberOfImages - 1 ) {
button := widget . NewButton ( "" , nil )
return button
}
newImageIndex := imageIndex + 1
button := widget . NewButtonWithIcon ( "" , theme . NavigateNextIcon ( ) , func ( ) {
setViewUserProfilePage ( window , profileIsMine , profileHash , newImageIndex , getAnyUserProfileAttributeFunction , previousPage )
} )
return button
}
backButton := getBackButton ( )
nextButton := getNextButton ( )
navigationWithZoomRow := getContainerCentered ( container . NewGridWithRows ( 1 , backButton , zoomButton , nextButton ) )
return navigationWithZoomRow
}
navigationWithZoomRow := getNavigationWithZoomRow ( )
currentFyneImageBoxed := container . NewHBox ( layout . NewSpacer ( ) , currentFyneImage , layout . NewSpacer ( ) )
imagesColumn := container . NewVBox ( currentFyneImageBoxed , navigationWithZoomRow )
return imagesColumn , nil
}
photosColumnWithNavButtons , err := getPhotosColumnWithNavigationButtons ( )
if ( err != nil ) { return nil , err }
profileDetailsButton := widget . NewButtonWithIcon ( "Details" , theme . InfoIcon ( ) , func ( ) {
setViewUserProfilePage_ProfileDetails ( window , profileHash , getAnyUserProfileAttributeFunction , currentPage )
} )
reportProfileButton := widget . NewButtonWithIcon ( "Report" , theme . WarningIcon ( ) , func ( ) {
if ( profileIsMine == true ) {
dialogTitle := translate ( "Reporting Inaccessible" )
dialogMessageA := getLabelCentered ( translate ( "You are viewing your own profile." ) )
dialogMessageB := getLabelCentered ( translate ( "You cannot report your own profile." ) )
dialogContent := container . NewVBox ( dialogMessageA , dialogMessageB )
dialog . ShowCustom ( dialogTitle , translate ( "Close" ) , dialogContent , window )
return
}
//TODO
showUnderConstructionDialog ( window )
} )
topRowRightButtonsColumn := container . NewGridWithColumns ( 1 , profileDetailsButton , reportProfileButton )
topRow := container . NewHBox ( layout . NewSpacer ( ) , topRowLeftButtonsColumn , widget . NewSeparator ( ) , photosColumnWithNavButtons , widget . NewSeparator ( ) , topRowRightButtonsColumn , layout . NewSpacer ( ) )
identityHashTitle := widget . NewLabel ( "Identity Hash:" )
identityHashLabel := getBoldLabel ( userIdentityHashString )
viewIdentityHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewIdentityHashPage ( window , userIdentityHash , currentPage )
} )
identityHashRow := container . NewHBox ( layout . NewSpacer ( ) , identityHashTitle , identityHashLabel , viewIdentityHashButton , layout . NewSpacer ( ) )
profileContentContainer := container . NewVBox ( topRow , widget . NewSeparator ( ) , identityHashRow )
usernameTitle := widget . NewLabel ( "Username:" )
getUsernameLabel := func ( ) ( fyne . Widget , error ) {
exists , _ , usernameString , err := getAnyUserProfileAttributeFunction ( "Username" )
if ( err != nil ) { return nil , err }
if ( exists == false ) {
anonymousLabel := getBoldItalicLabel ( translate ( "Anonymous" ) )
return anonymousLabel , nil
}
usernameLabel := getBoldLabel ( usernameString )
return usernameLabel , nil
}
usernameLabel , err := getUsernameLabel ( )
if ( err != nil ) { return nil , err }
usernameRow := container . NewHBox ( layout . NewSpacer ( ) , usernameTitle , usernameLabel , layout . NewSpacer ( ) )
profileContentContainer . Add ( usernameRow )
if ( profileIsMine == false && userProfileType == "Mate" ) {
exists , _ , matchScore , err := getAnyUserProfileAttributeFunction ( "MatchScore" )
if ( err != nil ) { return nil , err }
if ( exists == false ) {
return nil , errors . New ( "Unable to retrieve mate user match score." )
}
matchScoreTitle := widget . NewLabel ( "Match Score:" )
matchScoreLabel := getBoldLabel ( matchScore )
viewMatchScoreDetailsButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
// This page describes which desires a user fulfills
setViewUserMatchScoreBreakdownPage ( window , userIdentityHash , currentPage )
} )
matchScoreRow := container . NewHBox ( layout . NewSpacer ( ) , matchScoreTitle , matchScoreLabel , viewMatchScoreDetailsButton , layout . NewSpacer ( ) )
profileContentContainer . Add ( matchScoreRow )
distanceTranslated , _ , formatDistanceFunction , distanceUnits , unavailableDistanceText , err := attributeDisplay . GetProfileAttributeDisplayInfo ( "Distance" )
if ( err != nil ) { return nil , err }
distanceTitle := getLabelCentered ( distanceTranslated + ":" )
getDistanceLabel := func ( ) ( fyne . Widget , error ) {
exists , _ , distanceKilometersString , err := getAnyUserProfileAttributeFunction ( "Distance" )
if ( err != nil ) { return nil , err }
if ( exists == false ) {
distanceLabel := getBoldItalicLabel ( unavailableDistanceText )
return distanceLabel , nil
}
distanceFormatted , err := formatDistanceFunction ( distanceKilometersString )
if ( err != nil ) { return nil , err }
distanceLabel := getBoldLabel ( distanceFormatted + distanceUnits )
return distanceLabel , nil
}
distanceLabel , err := getDistanceLabel ( )
if ( err != nil ) { return nil , err }
distanceRow := container . NewHBox ( layout . NewSpacer ( ) , distanceTitle , distanceLabel , layout . NewSpacer ( ) )
profileContentContainer . Add ( distanceRow )
}
if ( userProfileType == "Moderator" ) {
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) { return nil , err }
rankingKnown , moderatorRank , totalNumberOfModerators , err := moderatorRanking . GetModeratorRanking ( userIdentityHash , appNetworkType )
if ( err != nil ) { return nil , err }
getModeratorRankText := func ( ) string {
if ( rankingKnown == false ) {
result := translate ( "Unknown" )
return result
}
moderatorRankString := helpers . ConvertIntToString ( moderatorRank )
totalNumberOfModeratorsString := helpers . ConvertIntToString ( totalNumberOfModerators )
moderatorRankText := moderatorRankString + "/" + totalNumberOfModeratorsString
return moderatorRankText
}
moderatorRankText := getModeratorRankText ( )
moderatorRankTitle := widget . NewLabel ( translate ( "Moderator Rank" ) + ":" )
moderatorRankLabel := getBoldLabel ( moderatorRankText )
moderatorRankRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorRankTitle , moderatorRankLabel , layout . NewSpacer ( ) )
profileContentContainer . Add ( moderatorRankRow )
}
if ( userProfileType == "Mate" ) {
ageTitle := widget . NewLabel ( "Age:" )
getAgeLabel := func ( ) ( fyne . Widget , error ) {
exists , _ , ageString , err := getAnyUserProfileAttributeFunction ( "Age" )
if ( err != nil ) { return nil , err }
if ( exists == false ) {
noResponseLabel := getBoldItalicLabel ( translate ( "No Response" ) )
return noResponseLabel , nil
}
ageLabel := getBoldLabel ( ageString )
return ageLabel , nil
}
ageLabel , err := getAgeLabel ( )
if ( err != nil ) { return nil , err }
ageRow := container . NewHBox ( layout . NewSpacer ( ) , ageTitle , ageLabel , layout . NewSpacer ( ) )
profileContentContainer . Add ( ageRow )
}
getProfileCategorySelectButtons := func ( ) ( * fyne . Container , error ) {
generalIcon , err := getFyneImageIcon ( "General" )
if ( err != nil ) { return nil , err }
generalButton := widget . NewButton ( "General" , func ( ) {
setViewUserProfilePage_Category ( window , profileIsMine , "General" , getAnyUserProfileAttributeFunction , currentPage )
} )
generalButtonWithIcon := container . NewGridWithRows ( 2 , generalIcon , generalButton )
if ( userProfileType == "Host" || userProfileType == "Moderator" ) {
categorySelectButtonsRow := getContainerCentered ( generalButtonWithIcon )
return categorySelectButtonsRow , nil
}
physicalIcon , err := getFyneImageIcon ( "Person" )
if ( err != nil ) { return nil , err }
physicalButton := widget . NewButton ( "Physical" , func ( ) {
setViewUserProfilePage_Category ( window , profileIsMine , "Physical" , getAnyUserProfileAttributeFunction , currentPage )
} )
physicalButtonWithIcon := container . NewGridWithRows ( 2 , physicalIcon , physicalButton )
lifestyleIcon , err := getFyneImageIcon ( "Lifestyle" )
if ( err != nil ) { return nil , err }
lifestyleButton := widget . NewButton ( "Lifestyle" , func ( ) {
setViewUserProfilePage_Category ( window , profileIsMine , "Lifestyle" , getAnyUserProfileAttributeFunction , currentPage )
} )
lifestyleButtonWithIcon := container . NewGridWithRows ( 2 , lifestyleIcon , lifestyleButton )
mentalIcon , err := getFyneImageIcon ( "Mental" )
if ( err != nil ) { return nil , err }
mentalButton := widget . NewButton ( "Mental" , func ( ) {
setViewUserProfilePage_Category ( window , profileIsMine , "Mental" , getAnyUserProfileAttributeFunction , currentPage )
} )
mentalButtonWithIcon := container . NewGridWithRows ( 2 , mentalIcon , mentalButton )
categoriesRow := getContainerCentered ( container . NewGridWithRows ( 1 , generalButtonWithIcon , physicalButtonWithIcon , lifestyleButtonWithIcon , mentalButtonWithIcon ) )
return categoriesRow , nil
}
selectProfileCategoryButtonsRow , err := getProfileCategorySelectButtons ( )
if ( err != nil ) { return nil , err }
profileContentContainer . Add ( widget . NewSeparator ( ) )
profileContentContainer . Add ( selectProfileCategoryButtonsRow )
profileContentContainer . Add ( widget . NewSeparator ( ) )
return profileContentContainer , nil
}
profileContent , err := getProfileContainer ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , profileContent )
setPageContent ( page , window )
}
func setViewUserProfilePage_ProfileDetails ( window fyne . Window , profileHash [ 28 ] byte , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
currentPage := func ( ) { setViewUserProfilePage_ProfileDetails ( window , profileHash , getAnyUserProfileAttributeFunction , previousPage ) }
title := getPageTitleCentered ( translate ( "View Profile Details" ) )
backButton := getBackButtonCentered ( previousPage )
getPageContent := func ( ) ( * fyne . Container , error ) {
profileHashLabel := widget . NewLabel ( "Profile Hash:" )
profileHashHex := encoding . EncodeBytesToHexString ( profileHash [ : ] )
profileHashTrimmed , _ , err := helpers . TrimAndFlattenString ( profileHashHex , 20 )
if ( err != nil ) { return nil , err }
profileHashTrimmedLabel := getBoldLabel ( profileHashTrimmed )
viewProfileHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewContentHashPage ( window , "Profile" , profileHash [ : ] , currentPage )
} )
profileHashRow := container . NewHBox ( layout . NewSpacer ( ) , profileHashLabel , profileHashTrimmedLabel , viewProfileHashButton , layout . NewSpacer ( ) )
2024-06-11 06:59:06 +02:00
exists , _ , profileCreationTimeString , err := getAnyUserProfileAttributeFunction ( "CreationTime" )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
if ( exists == false ) {
2024-06-11 06:59:06 +02:00
return nil , errors . New ( "setViewUserProfilePage_ProfileDetails called with profile missing CreationTime" )
2024-04-11 15:51:56 +02:00
}
2024-06-11 06:59:06 +02:00
profileCreationTime , err := helpers . ConvertCreationTimeStringToInt64 ( profileCreationTimeString )
2024-04-11 15:51:56 +02:00
if ( err != nil ) {
2024-06-11 06:59:06 +02:00
return nil , errors . New ( "setViewUserProfilePage_ProfileDetails called with profile with invalid CreationTime: " + profileCreationTimeString )
2024-04-11 15:51:56 +02:00
}
2024-06-11 06:59:06 +02:00
creationTimeLabel := widget . NewLabel ( "Creation Time:" )
2024-04-11 15:51:56 +02:00
2024-06-11 06:59:06 +02:00
creationTimeString := helpers . ConvertUnixTimeToTranslatedTime ( profileCreationTime )
2024-04-11 15:51:56 +02:00
2024-06-11 06:59:06 +02:00
creationTimeAgoString , err := helpers . ConvertUnixTimeToTimeFromNowTranslated ( profileCreationTime , true )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
2024-06-11 06:59:06 +02:00
creationTimeText := getBoldLabel ( creationTimeString + " (" + creationTimeAgoString + ")" )
2024-04-11 15:51:56 +02:00
2024-06-11 06:59:06 +02:00
creationTimeWarningButton := widget . NewButtonWithIcon ( "" , theme . WarningIcon ( ) , func ( ) {
2024-04-11 15:51:56 +02:00
title := translate ( "Creation Time Warning" )
dialogMessageA := getLabelCentered ( "Profile creation times are not verified." )
dialogMessageB := getLabelCentered ( "They can be faked by the profile author." )
dialogContent := container . NewVBox ( dialogMessageA , dialogMessageB )
dialog . ShowCustom ( title , translate ( "Close" ) , dialogContent , window )
} )
2024-06-11 06:59:06 +02:00
creationTimeRow := container . NewHBox ( layout . NewSpacer ( ) , creationTimeLabel , creationTimeText , creationTimeWarningButton , layout . NewSpacer ( ) )
2024-04-11 15:51:56 +02:00
exists , profileVersion , profileType , err := getAnyUserProfileAttributeFunction ( "ProfileType" )
if ( err != nil ) { return nil , err }
if ( exists == false ) {
return nil , errors . New ( "getAnyUserProfileAttributeFunction called and ProfileType not found" )
}
profileTypeLabel := widget . NewLabel ( "Profile Type:" )
profileTypeText := getBoldLabel ( profileType )
profileTypeRow := container . NewHBox ( layout . NewSpacer ( ) , profileTypeLabel , profileTypeText , layout . NewSpacer ( ) )
profileVersionLabel := widget . NewLabel ( "Profile Version:" )
profileVersionString := helpers . ConvertIntToString ( profileVersion )
profileVersionText := getBoldLabel ( profileVersionString )
profileVersionRow := container . NewHBox ( layout . NewSpacer ( ) , profileVersionLabel , profileVersionText , layout . NewSpacer ( ) )
//TODO: Add moderation details (if profile/identity is banned)
//TODO: Show when identity/profile will expire, and allow user to send funds to increase the user's identity balance/score
//TODO: Save raw profile button (will save it as a txt file)
2024-06-11 06:59:06 +02:00
pageContent := container . NewVBox ( profileHashRow , widget . NewSeparator ( ) , creationTimeRow , widget . NewSeparator ( ) , profileTypeRow , widget . NewSeparator ( ) , profileVersionRow )
2024-04-11 15:51:56 +02:00
return pageContent , nil
}
pageContent , err := getPageContent ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , pageContent )
setPageContent ( page , window )
}
func setViewUserProfilePage_Category ( window fyne . Window , profileIsMine bool , categoryName string , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
if ( categoryName != "General" && categoryName != "Physical" && categoryName != "Lifestyle" && categoryName != "Mental" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewUserProfilePage_Category called with invalid profile category: " + categoryName ) , previousPage )
return
}
currentPage := func ( ) { setViewUserProfilePage_Category ( window , profileIsMine , categoryName , getAnyUserProfileAttributeFunction , previousPage ) }
title := getPageTitleCentered ( "View Profile - " + categoryName )
backButton := getBackButtonCentered ( previousPage )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) )
addAttributeRow := func ( attributeName string ) error {
attributeTitle , _ , formatAttributeValue , attributeUnits , missingValueText , err := attributeDisplay . GetProfileAttributeDisplayInfo ( attributeName )
if ( err != nil ) { return err }
attributeTitleLabel := widget . NewLabel ( attributeTitle + ":" )
exists , _ , attributeValue , err := getAnyUserProfileAttributeFunction ( attributeName )
if ( err != nil ) { return err }
if ( exists == false ) {
attributeValueLabel := getBoldItalicLabel ( missingValueText )
attributeRow := container . NewHBox ( layout . NewSpacer ( ) , attributeTitleLabel , attributeValueLabel , layout . NewSpacer ( ) )
page . Add ( attributeRow )
return nil
}
attributeValueFormatted , err := formatAttributeValue ( attributeValue )
if ( err != nil ) { return err }
attributeValueFormattedWithUnits := attributeValueFormatted + attributeUnits
attributeValueTrimmed , anyChangesOccurred , err := helpers . TrimAndFlattenString ( attributeValueFormattedWithUnits , 25 )
if ( err != nil ) { return err }
if ( anyChangesOccurred == false ) {
attributeValueLabel := getBoldLabel ( attributeValueFormattedWithUnits )
attributeRow := container . NewHBox ( layout . NewSpacer ( ) , attributeTitleLabel , attributeValueLabel , layout . NewSpacer ( ) )
page . Add ( attributeRow )
return nil
}
attributeValueTrimmedLabel := getBoldLabel ( attributeValueTrimmed )
viewAttributeValueButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing " + attributeTitle , attributeValueFormattedWithUnits , false , currentPage )
} )
attributeValueRow := container . NewHBox ( layout . NewSpacer ( ) , attributeTitleLabel , attributeValueTrimmedLabel , viewAttributeValueButton , layout . NewSpacer ( ) )
page . Add ( attributeValueRow )
return nil
}
addAttributesFunction := func ( ) error {
if ( categoryName == "General" ) {
exists , _ , userProfileType , err := getAnyUserProfileAttributeFunction ( "ProfileType" )
if ( err != nil ) { return err }
if ( exists == false ) {
return errors . New ( "getAnyUserProfileAttributeFunction not able to find ProfileType" )
}
if ( userProfileType == "Mate" ) {
locationButton := widget . NewButton ( "Location" , func ( ) {
setViewMateProfilePage_Location ( window , getAnyUserProfileAttributeFunction , currentPage )
} )
questionnaireButton := widget . NewButton ( "Questionnaire" , func ( ) {
setViewMateProfilePage_Questionnaire ( window , profileIsMine , getAnyUserProfileAttributeFunction , currentPage )
} )
tagsButton := widget . NewButton ( "Tags" , func ( ) {
setViewMateProfilePage_Tags ( window , getAnyUserProfileAttributeFunction , currentPage )
} )
buttonsGrid := getContainerCentered ( container . NewGridWithColumns ( 1 , locationButton , questionnaireButton , tagsButton ) )
page . Add ( buttonsGrid )
page . Add ( widget . NewSeparator ( ) )
}
err = addAttributeRow ( "Description" )
if ( err != nil ) { return err }
err = addAttributeRow ( "Username" )
if ( err != nil ) { return err }
if ( userProfileType == "Mate" ) {
err = addAttributeRow ( "Sexuality" )
if ( err != nil ) { return err }
}
return nil
}
if ( categoryName == "Physical" ) {
racialSimilarityButton := widget . NewButton ( "Racial Similarity" , func ( ) {
setViewMateProfilePage_RacialSimilarity ( window , getAnyUserProfileAttributeFunction , currentPage )
} )
ancestryCompositionButton := widget . NewButton ( "Ancestry Composition" , func ( ) {
setViewMateProfilePage_AncestryComposition ( window , "User" , getAnyUserProfileAttributeFunction , currentPage )
} )
haplogroupsButton := widget . NewButton ( "Haplogroups" , func ( ) {
setViewMateProfilePage_Haplogroups ( window , getAnyUserProfileAttributeFunction , currentPage )
} )
neanderthalVariantsButton := widget . NewButton ( "Neanderthal Variants" , func ( ) {
setViewMateProfilePage_NeanderthalVariants ( window , getAnyUserProfileAttributeFunction , currentPage )
} )
totalDiseaseRiskButton := widget . NewButton ( "Total Disease Risk" , func ( ) {
setViewMateProfilePage_TotalDiseaseRisk ( window , getAnyUserProfileAttributeFunction , currentPage )
} )
monogenicDiseasesButton := widget . NewButton ( "Monogenic Diseases" , func ( ) {
setViewMateProfilePage_MonogenicDiseases ( window , "Offspring" , getAnyUserProfileAttributeFunction , currentPage )
} )
polygenicDiseasesButton := widget . NewButton ( "Polygenic Diseases" , func ( ) {
setViewMateProfilePage_PolygenicDiseases ( window , "Offspring" , getAnyUserProfileAttributeFunction , currentPage )
} )
geneticTraitsButton := widget . NewButton ( "Genetic Traits" , func ( ) {
2024-07-19 19:16:28 +02:00
setViewMateProfilePage_GeneticTraits ( window , getAnyUserProfileAttributeFunction , currentPage )
2024-04-11 15:51:56 +02:00
} )
buttonsGrid := getContainerCentered ( container . NewGridWithColumns ( 2 , racialSimilarityButton , totalDiseaseRiskButton , ancestryCompositionButton , monogenicDiseasesButton , haplogroupsButton , polygenicDiseasesButton , neanderthalVariantsButton , geneticTraitsButton ) )
page . Add ( buttonsGrid )
page . Add ( widget . NewSeparator ( ) )
err := addAttributeRow ( "Age" )
if ( err != nil ) { return err }
err = addAttributeRow ( "Sex" )
if ( err != nil ) { return err }
err = addAttributeRow ( "Height" )
if ( err != nil ) { return err }
page . Add ( widget . NewSeparator ( ) )
err = addAttributeRow ( "EyeColor" )
if ( err != nil ) { return err }
err = addAttributeRow ( "SkinColor" )
if ( err != nil ) { return err }
err = addAttributeRow ( "HairColor" )
if ( err != nil ) { return err }
err = addAttributeRow ( "HairTexture" )
if ( err != nil ) { return err }
page . Add ( widget . NewSeparator ( ) )
err = addAttributeRow ( "BodyFat" )
if ( err != nil ) { return err }
err = addAttributeRow ( "BodyMuscle" )
if ( err != nil ) { return err }
page . Add ( widget . NewSeparator ( ) )
err = addAttributeRow ( "HasHIV" )
if ( err != nil ) { return err }
err = addAttributeRow ( "HasGenitalHerpes" )
if ( err != nil ) { return err }
return nil
}
if ( categoryName == "Lifestyle" ) {
dietButton := getWidgetCentered ( widget . NewButton ( "Diet" , func ( ) {
setViewMateProfilePage_Diet ( window , getAnyUserProfileAttributeFunction , currentPage )
} ) )
page . Add ( dietButton )
page . Add ( widget . NewSeparator ( ) )
err := addAttributeRow ( "Hobbies" )
if ( err != nil ) { return err }
err = addAttributeRow ( "WealthInGold" )
if ( err != nil ) { return err }
err = addAttributeRow ( "Job" )
if ( err != nil ) { return err }
err = addAttributeRow ( "Fame" )
if ( err != nil ) { return err }
page . Add ( widget . NewSeparator ( ) )
err = addAttributeRow ( "AlcoholFrequency" )
if ( err != nil ) { return err }
err = addAttributeRow ( "TobaccoFrequency" )
if ( err != nil ) { return err }
err = addAttributeRow ( "CannabisFrequency" )
if ( err != nil ) { return err }
return nil
}
if ( categoryName == "Mental" ) {
languageButton := getWidgetCentered ( widget . NewButton ( "Language" , func ( ) {
setViewMateProfilePage_Language ( window , getAnyUserProfileAttributeFunction , currentPage )
} ) )
page . Add ( languageButton )
page . Add ( widget . NewSeparator ( ) )
err := addAttributeRow ( "Beliefs" )
if ( err != nil ) { return err }
err = addAttributeRow ( "GenderIdentity" )
if ( err != nil ) { return err }
page . Add ( widget . NewSeparator ( ) )
err = addAttributeRow ( "PetsRating" )
if ( err != nil ) { return err }
err = addAttributeRow ( "DogsRating" )
if ( err != nil ) { return err }
err = addAttributeRow ( "CatsRating" )
if ( err != nil ) { return err }
return nil
}
return errors . New ( "setViewUserProfilePage_Category called with invalid profile category: " + categoryName )
}
err := addAttributesFunction ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page . Add ( widget . NewSeparator ( ) )
setPageContent ( page , window )
}
func setViewMateProfilePage_Location ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
setLoadingScreen ( window , "View Profile - General" , "Loading user location..." )
title := getPageTitleCentered ( "View Profile - General" )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Location" ) )
//Outputs:
// -bool: Location exists
// -*fyne.Container
// -error
getLocationColumn := func ( locationRank string ) ( bool , * fyne . Container , error ) {
if ( locationRank != "Primary" && locationRank != "Secondary" ) {
return false , nil , errors . New ( "getLocationColumn called with invalid locationRank: " + locationRank )
}
exists , _ , locationLatitudeString , err := getAnyUserProfileAttributeFunction ( locationRank + "LocationLatitude" )
if ( err != nil ) { return false , nil , err }
if ( exists == false ) {
return false , nil , nil
}
exists , _ , locationLongitudeString , err := getAnyUserProfileAttributeFunction ( locationRank + "LocationLongitude" )
if ( err != nil ) { return false , nil , err }
if ( exists == false ) {
return false , nil , errors . New ( "setViewMateProfilePage_Location called with profile containing " + locationRank + "LocationLatitude but missing " + locationRank + "LocationLongitude" )
}
locationLatitudeFloat64 , err := helpers . ConvertStringToFloat64 ( locationLatitudeString )
if ( err != nil ) {
return false , nil , errors . New ( "setViewMateProfilePage_Location called with profile containing invalid LocationLatitude: " + locationLatitudeString )
}
locationLongitudeFloat64 , err := helpers . ConvertStringToFloat64 ( locationLongitudeString )
if ( err != nil ) {
return false , nil , errors . New ( "setViewMateProfilePage_Location called with profile containing invalid LocationLongitude: " + locationLongitudeString )
}
locationRankLabel := getBoldLabelCentered ( locationRank )
locationCountryExists , _ , locationCountryIdentifier , err := getAnyUserProfileAttributeFunction ( locationRank + "LocationCountry" )
if ( err != nil ) { return false , nil , err }
getCountryTextLabel := func ( ) ( fyne . Widget , error ) {
if ( locationCountryExists == false ) {
noneLabel := getBoldItalicLabel ( translate ( "None" ) )
return noneLabel , nil
}
locationCountryIdentifierInt , err := helpers . ConvertStringToInt ( locationCountryIdentifier )
if ( err != nil ) { return nil , err }
countryObject , err := worldLocations . GetCountryObjectFromCountryIdentifier ( locationCountryIdentifierInt )
if ( err != nil ) { return nil , err }
countryNamesList := countryObject . NamesList
countryDescription := helpers . TranslateAndJoinStringListItems ( countryNamesList , "/" )
countryTextLabel := getBoldLabel ( translate ( countryDescription ) )
return countryTextLabel , nil
}
countryTextLabel , err := getCountryTextLabel ( )
if ( err != nil ) { return false , nil , err }
countryLabel := getLabelCentered ( "Country:" )
coordinatesLabel := getLabelCentered ( "Coordinates:" )
locationCoordinatesLabel := getBoldLabel ( locationLatitudeString + "°, " + locationLongitudeString + "°" )
cityLabel := getLabelCentered ( "City:" )
getCityContent := func ( ) ( * fyne . Container , error ) {
// We will either find the exact city or the closest city
cityName , cityState , cityCountryIdentifier , cityDistanceKilometers , err := worldLocations . GetClosestCityFromCoordinates ( locationLatitudeFloat64 , locationLongitudeFloat64 )
if ( err != nil ) { return nil , err }
if ( cityDistanceKilometers == 0 ) {
locationCityFormatted := cityName + ", " + cityState
locationCityLabel := getBoldLabelCentered ( locationCityFormatted )
return locationCityLabel , nil
}
currentUnitsExist , currentUnits , err := globalSettings . GetSetting ( "MetricOrImperial" )
if ( err != nil ) { return nil , err }
getNearbyCityDistanceFormattedString := func ( ) ( string , error ) {
if ( currentUnitsExist == true && currentUnits == "Imperial" ) {
distanceMiles , err := helpers . ConvertKilometersToMiles ( cityDistanceKilometers )
if ( err != nil ) { return "" , err }
distanceMilesString := helpers . ConvertFloat64ToStringRounded ( distanceMiles , 1 )
result := distanceMilesString + " miles"
return result , nil
}
distanceKilometersString := helpers . ConvertFloat64ToStringRounded ( cityDistanceKilometers , 1 )
result := distanceKilometersString + " kilometers"
return result , nil
}
nearbyCityDistanceFormattedString , err := getNearbyCityDistanceFormattedString ( )
if ( err != nil ) { return nil , err }
getNearbyCityNameFormatted := func ( ) ( string , error ) {
if ( locationCountryExists == true ) {
locationCountryIdentifierInt , err := helpers . ConvertStringToInt ( locationCountryIdentifier )
if ( err != nil ) { return "" , err }
if ( cityCountryIdentifier == locationCountryIdentifierInt ) {
result := cityName + ", " + cityState
return result , nil
}
}
countryObject , err := worldLocations . GetCountryObjectFromCountryIdentifier ( cityCountryIdentifier )
if ( err != nil ) { return "" , err }
countryNamesList := countryObject . NamesList
countryDescription := helpers . TranslateAndJoinStringListItems ( countryNamesList , "/" )
result := cityName + ", " + cityState + ", " + countryDescription
return result , nil
}
nearbyCityNameFormatted , err := getNearbyCityNameFormatted ( )
if ( err != nil ) { return nil , err }
nearbyCityNameFormattedAndTrimmed , _ , err := helpers . TrimAndFlattenString ( nearbyCityNameFormatted , 40 )
if ( err != nil ) { return nil , err }
locationDistanceLabel := getBoldLabelCentered ( nearbyCityDistanceFormattedString + " from" )
locationCityNameLabel := getBoldLabelCentered ( nearbyCityNameFormattedAndTrimmed )
cityInfoContainer := container . NewVBox ( locationDistanceLabel , locationCityNameLabel )
return cityInfoContainer , nil
}
cityContent , err := getCityContent ( )
if ( err != nil ) { return false , nil , err }
locationColumn := container . NewVBox ( locationRankLabel , widget . NewSeparator ( ) , countryLabel , countryTextLabel , widget . NewSeparator ( ) , coordinatesLabel , locationCoordinatesLabel , widget . NewSeparator ( ) , cityLabel , cityContent )
return true , locationColumn , nil
}
primaryLocationExists , primaryLocationColumn , err := getLocationColumn ( "Primary" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( primaryLocationExists == false ) {
noLocationsLabel := getBoldLabelCentered ( "This user has no locations." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , noLocationsLabel )
setPageContent ( page , window )
return
}
locationColumnsGrid := container . NewGridWithRows ( 1 , primaryLocationColumn )
secondaryLocationExists , secondaryLocationColumn , err := getLocationColumn ( "Secondary" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( secondaryLocationExists == true ) {
locationColumnsGrid . Add ( secondaryLocationColumn )
}
locationColumnsGridCentered := getContainerCentered ( locationColumnsGrid )
getDescriptionText := func ( ) string {
if ( secondaryLocationExists == false ) {
result := translate ( "Below is the user's location." )
return result
}
result := translate ( "Below are the user's locations." )
return result
}
descriptionText := getDescriptionText ( )
description := getLabelCentered ( descriptionText )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , locationColumnsGridCentered )
setPageContent ( page , window )
}
func setViewMateProfilePage_Questionnaire ( window fyne . Window , profileIsMine bool , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
currentPage := func ( ) { setViewMateProfilePage_Questionnaire ( window , profileIsMine , getAnyUserProfileAttributeFunction , previousPage ) }
title := getPageTitleCentered ( translate ( "View Profile - General" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Questionnaire" ) )
questionnaireExists , _ , questionnaireString , err := getAnyUserProfileAttributeFunction ( "Questionnaire" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( questionnaireExists == false ) {
description := getBoldLabelCentered ( "This user does not have a questionnaire." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description )
setPageContent ( page , window )
return
}
description1 := getLabelCentered ( "This user has a questionnaire." )
description2 := getLabelCentered ( "You can take their questionnaire and send them your responses." )
questionnaireObject , err := mateQuestionnaire . ReadQuestionnaireString ( questionnaireString )
if ( err != nil ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMateProfilePage_Questionnaire called with profile containing invalid questionnaire." ) , previousPage )
return
}
numberOfQuestions := len ( questionnaireObject )
numberOfQuestionsString := helpers . ConvertIntToString ( numberOfQuestions )
numberOfQuestionsLabel := widget . NewLabel ( "Number of questions:" )
numberOfQuestionsText := getBoldLabel ( numberOfQuestionsString )
numberOfQuestionsRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfQuestionsLabel , numberOfQuestionsText , layout . NewSpacer ( ) )
exists , _ , userIdentityHashString , err := getAnyUserProfileAttributeFunction ( "IdentityHash" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( exists == false ) {
setErrorEncounteredPage ( window , errors . New ( "getAnyUserProfileAttributeFunction failed to get IdentityHash" ) , previousPage )
return
}
userIdentityHash , _ , err := identity . ReadIdentityHashString ( userIdentityHashString )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
//TODO: Show if user has already taken the questionnaire
submitQuestionnairePage := func ( questionnaireResponse string , prevPage func ( ) ) {
if ( profileIsMine == true ) {
dialogTitle := translate ( "Cannot Submit Questionnaire" )
dialogMessageA := getLabelCentered ( translate ( "You are viewing your own profile." ) )
dialogMessageB := getLabelCentered ( translate ( "You cannot submit a response to your own questionnaire." ) )
dialogContent := container . NewVBox ( dialogMessageA , dialogMessageB )
dialog . ShowCustom ( dialogTitle , translate ( "Close" ) , dialogContent , window )
return
}
setSubmitQuestionnairePage ( window , userIdentityHash , questionnaireResponse , prevPage , currentPage )
}
takeQuestionnaireButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Take Questionnaire" , theme . DocumentCreateIcon ( ) , func ( ) {
emptyMap := make ( map [ string ] string )
setTakeQuestionnairePage ( window , questionnaireObject , 0 , emptyMap , currentPage , submitQuestionnairePage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , numberOfQuestionsRow , takeQuestionnaireButton )
setPageContent ( page , window )
}
func setViewMateProfilePage_Tags ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
title := getPageTitleCentered ( translate ( "View Profile - General" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Tags" ) )
anyTagsExist , _ , tagsAttribute , err := getAnyUserProfileAttributeFunction ( "Tags" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( anyTagsExist == false ) {
description := getBoldLabelCentered ( "This user has no tags." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description )
setPageContent ( page , window )
return
}
description := getLabelCentered ( "Below are the user's tags." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) )
tagsList := strings . Split ( tagsAttribute , "+&" )
for _ , tagName := range tagsList {
tagLabel := getBoldLabelCentered ( tagName )
page . Add ( tagLabel )
}
setPageContent ( page , window )
}
func setViewMateProfilePage_Haplogroups ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Haplogroups" ) )
description1 := getLabelCentered ( translate ( "Below are the user's haplogroups." ) )
description2 := getLabelCentered ( "These are reported by 23andMe. More companies will be added." )
userMaternalHaplogroupExists , _ , userMaternalHaplogroup_23andMe , err := getAnyUserProfileAttributeFunction ( "23andMe_MaternalHaplogroup" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
maternalHaplogroupLabel := widget . NewLabel ( "Maternal Haplogroup:" )
getMaternalHalogroupText := func ( ) fyne . Widget {
if ( userMaternalHaplogroupExists == false ) {
noResponseLabel := getBoldItalicLabel ( "No Response" )
return noResponseLabel
}
maternalHaplogroupLabel := getBoldLabel ( userMaternalHaplogroup_23andMe )
return maternalHaplogroupLabel
}
maternalHaplogroupText := getMaternalHalogroupText ( )
userMaternalHaplogroupRow := container . NewHBox ( layout . NewSpacer ( ) , maternalHaplogroupLabel , maternalHaplogroupText , layout . NewSpacer ( ) )
userPaternalHaplogroupExists , _ , userPaternalHaplogroup_23andMe , err := getAnyUserProfileAttributeFunction ( "23andMe_PaternalHaplogroup" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
paternalHaplogroupLabel := widget . NewLabel ( "Paternal Haplogroup:" )
getPaternalHalogroupText := func ( ) fyne . Widget {
if ( userPaternalHaplogroupExists == false ) {
noResponseLabel := getBoldItalicLabel ( "No Response" )
return noResponseLabel
}
paternalHaplogroupLabel := getBoldLabel ( userPaternalHaplogroup_23andMe )
return paternalHaplogroupLabel
}
paternalHaplogroupText := getPaternalHalogroupText ( )
userPaternalHaplogroupRow := container . NewHBox ( layout . NewSpacer ( ) , paternalHaplogroupLabel , paternalHaplogroupText , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , userMaternalHaplogroupRow , userPaternalHaplogroupRow )
//Outputs:
// -bool: Offspring maternal haplogroup is known
// -string: Offspring maternal haplogroup
// -bool: Offspring paternal haplogroup is known
// -string: Offspring paternal haplogroup is known
// -error
getOffspringHaplogroups := func ( ) ( bool , string , bool , string , error ) {
isKnown , _ , isSameSex , err := getAnyUserProfileAttributeFunction ( "IsSameSex" )
if ( err != nil ) { return false , "" , false , "" , err }
if ( isKnown == true && isSameSex == "Yes" ) {
return false , "" , false , "" , nil
}
mySexExists , mySex , err := myLocalProfiles . GetProfileData ( "Mate" , "Sex" )
if ( err != nil ) { return false , "" , false , "" , err }
userSexExists , _ , userSex , err := getAnyUserProfileAttributeFunction ( "Sex" )
if ( err != nil ) { return false , "" , false , "" , err }
if ( mySexExists == false && userSexExists == false ) {
return false , "" , false , "" , nil
}
//Outputs:
// -bool: Haplogroup is known
// -string: Offspring maternal haplogroup
// -error
getOffspringMaternalHaplogroup := func ( ) ( bool , string , error ) {
if ( mySexExists == true ) {
if ( mySex == "Female" || mySex == "Intersex Female" ) {
exists , myMaternalHaplogroup , err := myLocalProfiles . GetProfileData ( "Mate" , "23andMe_MaternalHaplogroup" )
if ( err != nil ) { return false , "" , err }
if ( exists == false ) {
return false , "" , nil
}
return true , myMaternalHaplogroup , nil
}
}
if ( userSexExists == true ) {
if ( userSex == "Female" || userSex == "Intersex Female" ) {
if ( userMaternalHaplogroupExists == true ) {
return true , userMaternalHaplogroup_23andMe , nil
}
}
}
return false , "" , nil
}
offspringMaternalHaplogroupIsKnown , offspringMaternalHaplogroup , err := getOffspringMaternalHaplogroup ( )
if ( err != nil ) { return false , "" , false , "" , err }
//Outputs:
// -bool: Haplogroup is known
// -string: Offspring paternal haplogroup
// -error
getOffspringPaternalHaplogroup := func ( ) ( bool , string , error ) {
if ( mySexExists == true ) {
if ( mySex == "Male" || mySex == "Intersex Male" ) {
exists , myPaternalHaplogroup , err := myLocalProfiles . GetProfileData ( "Mate" , "23andMe_PaternalHaplogroup" )
if ( err != nil ) { return false , "" , err }
if ( exists == false ) {
return false , "" , nil
}
return true , myPaternalHaplogroup , nil
}
}
if ( userSexExists == true ) {
if ( userSex == "Male" || userSex == "Intersex Male" ) {
if ( userPaternalHaplogroupExists == true ) {
return true , userPaternalHaplogroup_23andMe , nil
}
}
}
return false , "" , nil
}
offspringPaternalHaplogroupIsKnown , offspringPaternalHaplogroup , err := getOffspringPaternalHaplogroup ( )
if ( err != nil ) { return false , "" , false , "" , err }
return offspringMaternalHaplogroupIsKnown , offspringMaternalHaplogroup , offspringPaternalHaplogroupIsKnown , offspringPaternalHaplogroup , nil
}
offspringMaternalHaplogroupIsKnown , offspringMaternalHaplogroup , offspringPaternalHaplogroupIsKnown , offspringPaternalHaplogroup , err := getOffspringHaplogroups ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( offspringMaternalHaplogroupIsKnown == true || offspringPaternalHaplogroupIsKnown == true ) {
page . Add ( widget . NewSeparator ( ) )
offspringDescription := getLabelCentered ( "Below are the haplogroups of an offspring created from you and the user." )
page . Add ( offspringDescription )
page . Add ( widget . NewSeparator ( ) )
offspringMaternalHaplogroupLabel := widget . NewLabel ( "Offspring Maternal Haplogroup:" )
getOffspringMaternalHaplogroupText := func ( ) fyne . Widget {
if ( offspringMaternalHaplogroupIsKnown == false ) {
unknownLabel := getBoldItalicLabel ( "Unknown" )
return unknownLabel
}
haplogroupLabel := getBoldLabel ( offspringMaternalHaplogroup )
return haplogroupLabel
}
offspringMaternalHaplogroupText := getOffspringMaternalHaplogroupText ( )
offspringMaternalHaplogroupRow := container . NewHBox ( layout . NewSpacer ( ) , offspringMaternalHaplogroupLabel , offspringMaternalHaplogroupText , layout . NewSpacer ( ) )
page . Add ( offspringMaternalHaplogroupRow )
offspringPaternalHaplogroupLabel := widget . NewLabel ( "Offspring Paternal Haplogroup:" )
getOffspringPaternalHaplogroupText := func ( ) fyne . Widget {
if ( offspringPaternalHaplogroupIsKnown == false ) {
unknownLabel := getBoldItalicLabel ( "Unknown" )
return unknownLabel
}
haplogroupLabel := getBoldLabel ( offspringPaternalHaplogroup )
return haplogroupLabel
}
offspringPaternalHaplogroupText := getOffspringPaternalHaplogroupText ( )
offspringPaternalHaplogroupRow := container . NewHBox ( layout . NewSpacer ( ) , offspringPaternalHaplogroupLabel , offspringPaternalHaplogroupText , layout . NewSpacer ( ) )
page . Add ( offspringPaternalHaplogroupRow )
}
setPageContent ( page , window )
}
func setViewMateProfilePage_NeanderthalVariants ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Neanderthal Variants" ) )
description1 := getLabelCentered ( "Below is the user's neanderthal variant count." )
description2 := getLabelCentered ( "The information comes from 23andMe. More companies will be added." )
userResponseExists , _ , userNeanderthalVariants , err := getAnyUserProfileAttributeFunction ( "23andMe_NeanderthalVariants" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
getUserNeanderthalVariantsLabel := func ( ) fyne . Widget {
if ( userResponseExists == false ) {
noResponseLabel := getBoldItalicLabel ( translate ( "No Response" ) )
2024-06-07 04:16:54 +02:00
return noResponseLabel
2024-04-11 15:51:56 +02:00
}
userNeanderthalVariantsLabel := getBoldLabel ( userNeanderthalVariants + " variants" )
return userNeanderthalVariantsLabel
}
userNeanderthalVariantsLabel := getUserNeanderthalVariantsLabel ( )
neanderthalVariantsLabel := widget . NewLabel ( "Neanderthal Variants:" )
neanderthalVariantsRow := container . NewHBox ( layout . NewSpacer ( ) , neanderthalVariantsLabel , userNeanderthalVariantsLabel , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , neanderthalVariantsRow )
isSameSexIsKnown , _ , isSameSex , err := getAnyUserProfileAttributeFunction ( "IsSameSex" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( isSameSexIsKnown == true && isSameSex == "Yes" ) {
setPageContent ( page , window )
return
}
offspringNeanderthalVariantsKnown , _ , offspringNeanderthalVariants , err := getAnyUserProfileAttributeFunction ( "23andMe_OffspringNeanderthalVariants" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( offspringNeanderthalVariantsKnown == false ) {
setPageContent ( page , window )
return
}
page . Add ( widget . NewSeparator ( ) )
offspringDescription := getLabelCentered ( "Below is the estimated neanderthal variant count of an offspring created from you and this user." )
page . Add ( offspringDescription )
offspringNeanderthalVariantsLabel := widget . NewLabel ( "Offspring Neanderthal Variants:" )
offspringNeanderthalVariantsText := getBoldLabel ( offspringNeanderthalVariants + " variants" )
offspringNeanderthalVariantsRow := container . NewHBox ( layout . NewSpacer ( ) , offspringNeanderthalVariantsLabel , offspringNeanderthalVariantsText , layout . NewSpacer ( ) )
page . Add ( offspringNeanderthalVariantsRow )
setPageContent ( page , window )
}
func setViewMateProfilePage_RacialSimilarity ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Racial Similarity" ) )
description := getLabelCentered ( "This page describes the racial similarity between you and the user." )
//TODO: Add help pages to explain results
racialSimilarityTitle := widget . NewLabel ( "Racial Similarity:" )
getRacialSimilarityText := func ( ) ( string , error ) {
similarityIsKnown , _ , racialSimilarity , err := getAnyUserProfileAttributeFunction ( "RacialSimilarity" )
if ( err != nil ) { return "" , err }
if ( similarityIsKnown == false ) {
result := translate ( "Unknown" )
return result , nil
}
return racialSimilarity , nil
}
racialSimilarityText , err := getRacialSimilarityText ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
racialSimilarityLabel := getBoldLabel ( racialSimilarityText )
racialSimilarityHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
racialSimilarityRow := container . NewHBox ( layout . NewSpacer ( ) , racialSimilarityTitle , racialSimilarityLabel , racialSimilarityHelpButton , layout . NewSpacer ( ) )
getRacialSimilarityBreakdownGrid_Traits := func ( ) ( * fyne . Container , error ) {
//TODO: A button for each trait to see what the our and the user's trait value is
traitNameHeader := getItalicLabelCentered ( "Trait Name" )
traitSimilarityHeader := getItalicLabelCentered ( "Trait Similarity" )
geneticSimilarityHeader := getItalicLabelCentered ( "Genetic Similarity" )
numberOfTestedLociHeader := getItalicLabelCentered ( "Number Of Tested Loci" )
traitNamesColumn := container . NewVBox ( traitNameHeader , widget . NewSeparator ( ) )
traitSimilarityColumn := container . NewVBox ( traitSimilarityHeader , widget . NewSeparator ( ) )
geneticSimilarityColumn := container . NewVBox ( geneticSimilarityHeader , widget . NewSeparator ( ) )
numberOfTestedLociColumn := container . NewVBox ( numberOfTestedLociHeader , widget . NewSeparator ( ) )
addSimilarityRow := func ( traitName string , traitSimilarityAttributeName string , geneticSimilarityAttributeName string , numberOfSimilarAllelesAttributeName string ) error {
traitTitleLabel := getBoldLabelCentered ( translate ( traitName ) )
traitNamesColumn . Add ( traitTitleLabel )
if ( traitName == "Facial Structure" ) {
// This trait's similarity cannot be calculated yet
// This feature is planned to be added - it will compare the faces in user profile photos.
dashLabel := getItalicLabelCentered ( "-" )
traitSimilarityColumn . Add ( dashLabel )
} else {
traitSimilarityIsKnown , _ , attributeValue , err := getAnyUserProfileAttributeFunction ( traitSimilarityAttributeName )
if ( err != nil ) { return err }
if ( traitSimilarityIsKnown == false ) {
unknownLabel := getItalicLabelCentered ( "Unknown" )
traitSimilarityColumn . Add ( unknownLabel )
} else {
similarityFormatted := attributeValue + "%"
similarityLabel := getBoldLabelCentered ( similarityFormatted )
traitSimilarityColumn . Add ( similarityLabel )
}
}
// We figure out how many loci exist for this trait
traitObject , err := traits . GetTraitObject ( traitName )
if ( err != nil ) { return err }
traitLociList := traitObject . LociList
2024-07-19 19:16:28 +02:00
quantityOfTraitLoci := len ( traitLociList )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfTraitLociString := helpers . ConvertIntToString ( quantityOfTraitLoci )
2024-04-11 15:51:56 +02:00
geneticSimilarityIsKnown , _ , attributeValue , err := getAnyUserProfileAttributeFunction ( geneticSimilarityAttributeName )
if ( err != nil ) { return err }
if ( geneticSimilarityIsKnown == false ) {
unknownLabel := getItalicLabelCentered ( "Unknown" )
geneticSimilarityColumn . Add ( unknownLabel )
2024-07-19 19:16:28 +02:00
quantityOfTestedLociText := "0/" + quantityOfTraitLociString
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfTestedLociLabel := getBoldLabelCentered ( quantityOfTestedLociText )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
numberOfTestedLociColumn . Add ( quantityOfTestedLociLabel )
2024-04-11 15:51:56 +02:00
} else {
similarityFormatted := attributeValue + "%"
similarityLabel := getBoldLabelCentered ( similarityFormatted )
geneticSimilarityColumn . Add ( similarityLabel )
attributeIsKnown , _ , numberOfSimilarAllelesValue , err := getAnyUserProfileAttributeFunction ( numberOfSimilarAllelesAttributeName )
if ( err != nil ) { return err }
if ( attributeIsKnown == false ) {
return errors . New ( "User profile contains " + geneticSimilarityAttributeName + " but is missing " + numberOfSimilarAllelesAttributeName )
}
// numberOfSimilarAllelesValue is represented by (number of shared alleles)/(number of tested alleles)
// Example: "52/60"
// We extract the denominator
_ , numberOfTestedAllelesString , delimeterFound := strings . Cut ( numberOfSimilarAllelesValue , "/" )
if ( delimeterFound == false ) {
return errors . New ( "User profile contains invalid " + numberOfSimilarAllelesAttributeName + ": " + numberOfSimilarAllelesValue )
}
numberOfTestedAlleles , err := helpers . ConvertStringToInt ( numberOfTestedAllelesString )
if ( err != nil ) {
return errors . New ( "User profile contains invalid " + numberOfSimilarAllelesAttributeName + ": " + numberOfSimilarAllelesValue )
}
// Each locus has 2 alleles (this will change once we include sex chromosome locations)
numberOfTestedLoci := numberOfTestedAlleles / 2
numberOfTestedLociString := helpers . ConvertIntToString ( numberOfTestedLoci )
2024-07-19 19:16:28 +02:00
numberOfTestedLociLabelText := numberOfTestedLociString + "/" + quantityOfTraitLociString
2024-04-11 15:51:56 +02:00
numberOfTestedLociLabel := getBoldLabelCentered ( numberOfTestedLociLabelText )
numberOfTestedLociColumn . Add ( numberOfTestedLociLabel )
}
traitNamesColumn . Add ( widget . NewSeparator ( ) )
traitSimilarityColumn . Add ( widget . NewSeparator ( ) )
geneticSimilarityColumn . Add ( widget . NewSeparator ( ) )
numberOfTestedLociColumn . Add ( widget . NewSeparator ( ) )
return nil
}
err = addSimilarityRow ( "Eye Color" , "EyeColorSimilarity" , "EyeColorGenesSimilarity" , "EyeColorGenesSimilarity_NumberOfSimilarAlleles" )
if ( err != nil ) { return nil , err }
err = addSimilarityRow ( "Hair Color" , "HairColorSimilarity" , "HairColorGenesSimilarity" , "HairColorGenesSimilarity_NumberOfSimilarAlleles" )
if ( err != nil ) { return nil , err }
err = addSimilarityRow ( "Skin Color" , "SkinColorSimilarity" , "SkinColorGenesSimilarity" , "SkinColorGenesSimilarity_NumberOfSimilarAlleles" )
if ( err != nil ) { return nil , err }
err = addSimilarityRow ( "Hair Texture" , "HairTextureSimilarity" , "HairTextureGenesSimilarity" , "HairTextureGenesSimilarity_NumberOfSimilarAlleles" )
if ( err != nil ) { return nil , err }
err = addSimilarityRow ( "Facial Structure" , "" , "FacialStructureGenesSimilarity" , "FacialStructureGenesSimilarity_NumberOfSimilarAlleles" )
if ( err != nil ) { return nil , err }
similarityGrid := container . NewHBox ( layout . NewSpacer ( ) , traitNamesColumn , traitSimilarityColumn , geneticSimilarityColumn , numberOfTestedLociColumn , layout . NewSpacer ( ) )
return similarityGrid , nil
}
racialSimilarityBreakdownGrid_Traits , err := getRacialSimilarityBreakdownGrid_Traits ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
getRacialSimilarityBreakdownGrid_GeneticAttributes := func ( ) ( * fyne . Container , error ) {
attributeTitleHeader := getItalicLabelCentered ( "Genetic Attribute Name" )
twentyThreeAndMeHeader := getItalicLabelCentered ( "23andMe" )
attributeTitleColumn := container . NewVBox ( attributeTitleHeader , widget . NewSeparator ( ) )
similarityColumn_23andMe := container . NewVBox ( twentyThreeAndMeHeader , widget . NewSeparator ( ) )
addSimilarityRow := func ( attributeTitle string , attributeName_23andMe string ) error {
attributeTitleLabel := getBoldLabelCentered ( translate ( attributeTitle ) )
attributeTitleColumn . Add ( attributeTitleLabel )
similarityIsKnown , _ , attributeValue , err := getAnyUserProfileAttributeFunction ( attributeName_23andMe )
if ( err != nil ) { return err }
if ( similarityIsKnown == false ) {
unknownLabel := getItalicLabelCentered ( "Unknown" )
similarityColumn_23andMe . Add ( unknownLabel )
} else {
similarityFormatted := attributeValue + "%"
similarityLabel := getBoldLabelCentered ( similarityFormatted )
similarityColumn_23andMe . Add ( similarityLabel )
}
attributeTitleColumn . Add ( widget . NewSeparator ( ) )
similarityColumn_23andMe . Add ( widget . NewSeparator ( ) )
return nil
}
err = addSimilarityRow ( "Ancestral Similarity" , "23andMe_AncestralSimilarity" )
if ( err != nil ) { return nil , err }
err = addSimilarityRow ( "Maternal Haplogroup Similarity" , "23andMe_MaternalHaplogroupSimilarity" )
if ( err != nil ) { return nil , err }
err = addSimilarityRow ( "Paternal Haplogroup Similarity" , "23andMe_PaternalHaplogroupSimilarity" )
if ( err != nil ) { return nil , err }
//TODO: Add neanderthal variants similarity?
similarityGrid := container . NewHBox ( layout . NewSpacer ( ) , attributeTitleColumn , similarityColumn_23andMe , layout . NewSpacer ( ) )
return similarityGrid , nil
}
racialSimilarityBreakdownGrid_GeneticAttributes , err := getRacialSimilarityBreakdownGrid_GeneticAttributes ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , racialSimilarityRow , widget . NewSeparator ( ) , racialSimilarityBreakdownGrid_Traits , widget . NewSeparator ( ) , racialSimilarityBreakdownGrid_GeneticAttributes )
setPageContent ( page , window )
}
func setViewMateProfilePage_AncestryComposition ( window fyne . Window , userOrOffspring string , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
if ( userOrOffspring != "User" && userOrOffspring != "Offspring" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMateProfilePage_AncestryComposition called with invalid userOrOffspring: " + userOrOffspring ) , previousPage )
return
}
currentPage := func ( ) { setViewMateProfilePage_AncestryComposition ( window , userOrOffspring , getAnyUserProfileAttributeFunction , previousPage ) }
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Ancestry Composition" ) )
description1 := getLabelCentered ( "Below is the ancestry location composition for this user." )
description2 := getLabelCentered ( "The information is provided by 23andMe. More companies will be added." )
userAncestryCompositionExists , _ , userAncestryCompositionAttribute , err := getAnyUserProfileAttributeFunction ( "23andMe_AncestryComposition" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( userAncestryCompositionExists == false ) {
noAncestryComposition := getBoldLabelCentered ( "This user has no ancestry composition." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , noAncestryComposition )
setPageContent ( page , window )
return
}
description3Label := getLabelCentered ( "Choose if you want to view the composition of the user or the offspring between you and the user." )
offspringAncestryCompositionHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setOffspringAncestryCompositionExplainerPage ( window , currentPage )
} )
description3Row := container . NewHBox ( layout . NewSpacer ( ) , description3Label , offspringAncestryCompositionHelpButton , layout . NewSpacer ( ) )
handleSelectFunction := func ( newUserOrOffspring string ) {
if ( newUserOrOffspring == userOrOffspring ) {
return
}
setViewMateProfilePage_AncestryComposition ( window , newUserOrOffspring , getAnyUserProfileAttributeFunction , previousPage )
}
userOrOffspringList := [ ] string { "User" , "Offspring" }
userOrOffspringSelector := widget . NewSelect ( userOrOffspringList , handleSelectFunction )
userOrOffspringSelector . Selected = userOrOffspring
userOrOffspringSelectorCentered := getWidgetCentered ( userOrOffspringSelector )
header := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , description3Row , userOrOffspringSelectorCentered , widget . NewSeparator ( ) )
if ( userOrOffspring == "User" ) {
attributeIsValid , continentPercentagesMap , regionPercentagesMap , subregionPercentagesMap , err := companyAnalysis . ReadAncestryCompositionAttribute_23andMe ( true , userAncestryCompositionAttribute )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( attributeIsValid == false ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMateProfilePage_AncestryComposition called with getAnyUserProfileAttributeFunction returning invalid userAncestryCompositionAttribute" ) , previousPage )
return
}
userCompositionDisplay , err := get23andMeAncestryCompositionDisplay ( continentPercentagesMap , regionPercentagesMap , subregionPercentagesMap )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewBorder ( header , nil , nil , nil , userCompositionDisplay )
setPageContent ( page , window )
return
}
//userOrOffspring == "Offspring"
myAncestryCompositionExists , myAncestryCompositionAttribute , err := myLocalProfiles . GetProfileData ( "Mate" , "23andMe_AncestryComposition" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( myAncestryCompositionExists == false ) {
description4 := getBoldLabelCentered ( "Your ancestry location composition does not exist." )
description5 := getLabelCentered ( "Add your ancestry composition to view your offspring's ancestry composition." )
description6 := getLabelCentered ( "You can do this on the Build Profile - Physical - Ancestry Composition page." )
page := container . NewVBox ( header , description4 , description5 , description6 )
setPageContent ( page , window )
return
}
offspringContinentPercentagesMap , offspringRegionPercentagesMap , offspringSubregionPercentagesMap , err := companyAnalysis . GetOffspringAncestryComposition_23andMe ( myAncestryCompositionAttribute , userAncestryCompositionAttribute )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
offspringAncestryCompositionDisplay , err := get23andMeAncestryCompositionDisplay ( offspringContinentPercentagesMap , offspringRegionPercentagesMap , offspringSubregionPercentagesMap )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewBorder ( header , nil , nil , nil , offspringAncestryCompositionDisplay )
setPageContent ( page , window )
}
// This is a page to view the total monogenic disease risk for a user's offspring
func setViewMateProfilePage_TotalDiseaseRisk ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
2024-08-13 15:25:47 +02:00
setLoadingScreen ( window , "View Profile - Physical" , "Computing Genetic Analysis..." )
2024-04-11 15:51:56 +02:00
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Total Disease Risk" ) )
description1 := getLabelCentered ( "This page describes the total disease risk for this user." )
description2 := getLabelCentered ( "You must link your genome person in the Build Profile menu to see offspring disease information." )
offspringProbabilityOfAnyMonogenicDiseaseTitle := widget . NewLabel ( "Offspring Probability Of Any Monogenic Disease:" )
getOffspringProbabilityOfAnyMonogenicDiseaseLabel := func ( ) ( fyne . Widget , error ) {
probabilityIsKnown , _ , offspringProbabilityOfAnyMonogenicDisease , err := getAnyUserProfileAttributeFunction ( "OffspringProbabilityOfAnyMonogenicDisease" )
if ( err != nil ) { return nil , err }
if ( probabilityIsKnown == false ) {
unknownLabel := getItalicLabel ( translate ( "Unknown" ) )
return unknownLabel , nil
}
probabilityFormatted := offspringProbabilityOfAnyMonogenicDisease + "%"
probabilityLabel := getBoldLabel ( probabilityFormatted )
return probabilityLabel , nil
}
offspringProbabilityOfAnyMonogenicDiseaseLabel , err := getOffspringProbabilityOfAnyMonogenicDiseaseLabel ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
offspringProbabilityOfAnyMonogenicDiseaseRow := container . NewHBox ( layout . NewSpacer ( ) , offspringProbabilityOfAnyMonogenicDiseaseTitle , offspringProbabilityOfAnyMonogenicDiseaseLabel , layout . NewSpacer ( ) )
getNumberOfOffspringMonogenicDiseasesTested := func ( ) ( int , error ) {
attributeIsKnown , _ , totalNumberOfMonogenicDiseasesTestedString , err := getAnyUserProfileAttributeFunction ( "OffspringProbabilityOfAnyMonogenicDisease_NumberOfDiseasesTested" )
if ( err != nil ) { return 0 , err }
if ( attributeIsKnown == false ) {
return 0 , nil
}
totalNumberOfMonogenicDiseasesTested , err := helpers . ConvertStringToInt ( totalNumberOfMonogenicDiseasesTestedString )
if ( err != nil ) {
return 0 , errors . New ( "getAnyUserProfileAttributeFunction returning invalid OffspringProbabilityOfAnyMonogenicDisease_NumberOfDiseasesTested value: " + totalNumberOfMonogenicDiseasesTestedString )
}
return totalNumberOfMonogenicDiseasesTested , nil
}
numberOfOffspringMonogenicDiseasesTested , err := getNumberOfOffspringMonogenicDiseasesTested ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
allMonogenicDiseaseNamesList , err := monogenicDiseases . GetMonogenicDiseaseNamesList ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
totalNumberOfMonogenicDiseases := len ( allMonogenicDiseaseNamesList )
totalNumberOfMonogenicDiseasesString := helpers . ConvertIntToString ( totalNumberOfMonogenicDiseases )
numberOfOffspringMonogenicDiseasesTestedString := helpers . ConvertIntToString ( numberOfOffspringMonogenicDiseasesTested )
numberOfOffspringMonogenicDiseasesTestedLabelText := numberOfOffspringMonogenicDiseasesTestedString + "/" + totalNumberOfMonogenicDiseasesString
numberOfOffspringMonogenicDiseasesTestedTitle := widget . NewLabel ( "Number Of Offspring Monogenic Diseases Tested:" )
numberOfOffspringMonogenicDiseasesTestedLabel := getBoldLabel ( numberOfOffspringMonogenicDiseasesTestedLabelText )
numberOfOffspringMonogenicDiseasesTestedRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfOffspringMonogenicDiseasesTestedTitle , numberOfOffspringMonogenicDiseasesTestedLabel , layout . NewSpacer ( ) )
userTotalPolygenicDiseaseRiskScoreTitle := widget . NewLabel ( "User Total Polygenic Disease Risk Score:" )
getUserTotalPolygenicDiseaseRiskScoreLabel := func ( ) ( fyne . Widget , error ) {
riskScoreIsKnown , _ , userTotalPolygenicDiseaseRiskScore , err := getAnyUserProfileAttributeFunction ( "TotalPolygenicDiseaseRiskScore" )
if ( err != nil ) { return nil , err }
if ( riskScoreIsKnown == false ) {
unknownLabel := getItalicLabel ( translate ( "Unknown" ) )
return unknownLabel , nil
}
riskScoreFormatted := userTotalPolygenicDiseaseRiskScore + "/100"
riskScoreLabel := getBoldLabel ( riskScoreFormatted )
return riskScoreLabel , nil
}
userTotalPolygenicDiseaseRiskScoreLabel , err := getUserTotalPolygenicDiseaseRiskScoreLabel ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
userTotalPolygenicDiseaseRiskScoreRow := container . NewHBox ( layout . NewSpacer ( ) , userTotalPolygenicDiseaseRiskScoreTitle , userTotalPolygenicDiseaseRiskScoreLabel , layout . NewSpacer ( ) )
getNumberOfUserPolygenicDiseasesTested := func ( ) ( int , error ) {
attributeIsKnown , _ , totalNumberOfPolygenicDiseasesTestedString , err := getAnyUserProfileAttributeFunction ( "TotalPolygenicDiseaseRiskScore_NumberOfDiseasesTested" )
if ( err != nil ) { return 0 , err }
if ( attributeIsKnown == false ) {
return 0 , nil
}
totalNumberOfPolygenicDiseasesTested , err := helpers . ConvertStringToInt ( totalNumberOfPolygenicDiseasesTestedString )
if ( err != nil ) {
return 0 , errors . New ( "getAnyUserProfileAttributeFunction returning invalid TotalPolygenicDiseaseRiskScore_NumberOfDiseasesTested value: " + totalNumberOfPolygenicDiseasesTestedString )
}
return totalNumberOfPolygenicDiseasesTested , nil
}
numberOfUserPolygenicDiseasesTested , err := getNumberOfUserPolygenicDiseasesTested ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
allPolygenicDiseaseNamesList , err := polygenicDiseases . GetPolygenicDiseaseNamesList ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
2024-08-13 15:25:47 +02:00
// We count up every disease that has a prediction model
totalNumberOfPolygenicDiseases := 0
for _ , diseaseName := range allPolygenicDiseaseNamesList {
2024-08-15 14:14:23 +02:00
predictionModelExists := trainedPredictionModels . CheckIfAttributeNeuralNetworkExists ( diseaseName )
2024-08-13 15:25:47 +02:00
if ( predictionModelExists == true ) {
totalNumberOfPolygenicDiseases += 1
}
}
2024-04-11 15:51:56 +02:00
totalNumberOfPolygenicDiseasesString := helpers . ConvertIntToString ( totalNumberOfPolygenicDiseases )
numberOfUserPolygenicDiseasesTestedString := helpers . ConvertIntToString ( numberOfUserPolygenicDiseasesTested )
numberOfUserPolygenicDiseasesTestedLabelText := numberOfUserPolygenicDiseasesTestedString + "/" + totalNumberOfPolygenicDiseasesString
numberOfUserPolygenicDiseasesTestedTitle := widget . NewLabel ( "Number Of User Polygenic Diseases Tested:" )
numberOfUserPolygenicDiseasesTestedLabel := getBoldLabel ( numberOfUserPolygenicDiseasesTestedLabelText )
numberOfUserPolygenicDiseasesTestedRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfUserPolygenicDiseasesTestedTitle , numberOfUserPolygenicDiseasesTestedLabel , layout . NewSpacer ( ) )
offspringTotalPolygenicDiseaseRiskScoreTitle := widget . NewLabel ( "Offspring Total Polygenic Disease Risk Score:" )
getOffspringTotalPolygenicDiseaseRiskScoreLabel := func ( ) ( fyne . Widget , error ) {
riskScoreIsKnown , _ , offspringTotalPolygenicDiseaseRiskScore , err := getAnyUserProfileAttributeFunction ( "OffspringTotalPolygenicDiseaseRiskScore" )
if ( err != nil ) { return nil , err }
if ( riskScoreIsKnown == false ) {
unknownLabel := getItalicLabel ( translate ( "Unknown" ) )
return unknownLabel , nil
}
riskScoreFormatted := offspringTotalPolygenicDiseaseRiskScore + "/100"
riskScoreLabel := getBoldLabel ( riskScoreFormatted )
return riskScoreLabel , nil
}
offspringTotalPolygenicDiseaseRiskScoreLabel , err := getOffspringTotalPolygenicDiseaseRiskScoreLabel ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
offspringTotalPolygenicDiseaseRiskScoreRow := container . NewHBox ( layout . NewSpacer ( ) , offspringTotalPolygenicDiseaseRiskScoreTitle , offspringTotalPolygenicDiseaseRiskScoreLabel , layout . NewSpacer ( ) )
getNumberOfOffspringPolygenicDiseasesTested := func ( ) ( int , error ) {
attributeIsKnown , _ , totalNumberOfPolygenicDiseasesTestedString , err := getAnyUserProfileAttributeFunction ( "OffspringTotalPolygenicDiseaseRiskScore_NumberOfDiseasesTested" )
if ( err != nil ) { return 0 , err }
if ( attributeIsKnown == false ) {
return 0 , nil
}
totalNumberOfPolygenicDiseasesTested , err := helpers . ConvertStringToInt ( totalNumberOfPolygenicDiseasesTestedString )
if ( err != nil ) {
return 0 , errors . New ( "getAnyUserProfileAttributeFunction returning invalid OffspringTotalPolygenicDiseaseRiskScore_NumberOfDiseasesTested value: " + totalNumberOfPolygenicDiseasesTestedString )
}
return totalNumberOfPolygenicDiseasesTested , nil
}
numberOfOffspringPolygenicDiseasesTested , err := getNumberOfOffspringPolygenicDiseasesTested ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
numberOfOffspringPolygenicDiseasesTestedString := helpers . ConvertIntToString ( numberOfOffspringPolygenicDiseasesTested )
numberOfOffspringPolygenicDiseasesTestedLabelText := numberOfOffspringPolygenicDiseasesTestedString + "/" + totalNumberOfPolygenicDiseasesString
numberOfOffspringPolygenicDiseasesTestedTitle := widget . NewLabel ( "Number Of Offspring Polygenic Diseases Tested:" )
numberOfOffspringPolygenicDiseasesTestedLabel := getBoldLabel ( numberOfOffspringPolygenicDiseasesTestedLabelText )
numberOfOffspringPolygenicDiseasesTestedRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfOffspringPolygenicDiseasesTestedTitle , numberOfOffspringPolygenicDiseasesTestedLabel , layout . NewSpacer ( ) )
//TODO: Add help buttons
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , offspringProbabilityOfAnyMonogenicDiseaseRow , numberOfOffspringMonogenicDiseasesTestedRow , widget . NewSeparator ( ) , userTotalPolygenicDiseaseRiskScoreRow , numberOfUserPolygenicDiseasesTestedRow , widget . NewSeparator ( ) , offspringTotalPolygenicDiseaseRiskScoreRow , numberOfOffspringPolygenicDiseasesTestedRow )
setPageContent ( page , window )
}
func setViewMateProfilePage_MonogenicDiseases ( window fyne . Window , userOrOffspring string , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
currentPage := func ( ) { setViewMateProfilePage_MonogenicDiseases ( window , userOrOffspring , getAnyUserProfileAttributeFunction , previousPage ) }
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Monogenic Diseases" ) )
description1 := getLabelCentered ( "Below is the monogenic disease analysis for this user." )
description2 := getLabelCentered ( "You can choose to view the analysis of the user or an offspring between you and the user." )
description3 := getLabelCentered ( "You must link your genome person in the Build Profile menu to see full offspring information." )
handleSelectButton := func ( newUserOrOffspring string ) {
if ( userOrOffspring == newUserOrOffspring ) {
return
}
setViewMateProfilePage_MonogenicDiseases ( window , newUserOrOffspring , getAnyUserProfileAttributeFunction , previousPage )
}
userOrOffspringSelector := widget . NewSelect ( [ ] string { "User" , "Offspring" } , handleSelectButton )
userOrOffspringSelector . Selected = userOrOffspring
userOrOffspringSelectorCentered := getWidgetCentered ( userOrOffspringSelector )
//TODO: Sort to show highest risk diseases first. All other diseases should be in normal order
getDiseasesInfoGrid := func ( ) ( * fyne . Container , error ) {
2024-06-07 04:16:54 +02:00
emptyLabel1 := widget . NewLabel ( "" )
emptyLabel2 := widget . NewLabel ( "" )
2024-04-11 15:51:56 +02:00
2024-06-07 04:16:54 +02:00
emptyLabel3 := widget . NewLabel ( "" )
2024-04-11 15:51:56 +02:00
diseaseNameLabel := getItalicLabelCentered ( "Disease Name" )
2024-06-07 04:16:54 +02:00
emptyLabel4 := widget . NewLabel ( "" )
userHasDiseaseLabel := getItalicLabelCentered ( "User Has Disease" )
2024-04-11 15:51:56 +02:00
userProbabilityOfLabelA := getItalicLabelCentered ( "User Probability Of" )
passingVariantLabel := getItalicLabelCentered ( "Passing Variant" )
userNumberOfLabel := getItalicLabelCentered ( "User Number Of" )
variantsTestedLabelA := getItalicLabelCentered ( "Variants Tested" )
offspringProbabilityOfLabelA := getItalicLabelCentered ( "Offspring Probability Of" )
havingDiseaseLabel := getItalicLabelCentered ( "Having Disease" )
offspringProbabilityOfLabelB := getItalicLabelCentered ( "Offspring Probability Of" )
havingVariantLabel := getItalicLabelCentered ( "Having Variant" )
offspringNumberOfLabel := getItalicLabelCentered ( "Offspring Number Of" )
variantsTestedLabelB := getItalicLabelCentered ( "Variants Tested" )
2024-06-07 04:16:54 +02:00
diseaseInfoButtonsColumn := container . NewVBox ( emptyLabel1 , emptyLabel2 , widget . NewSeparator ( ) )
diseaseNameColumn := container . NewVBox ( emptyLabel3 , diseaseNameLabel , widget . NewSeparator ( ) )
userHasDiseaseColumn := container . NewVBox ( emptyLabel4 , userHasDiseaseLabel , widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
userProbabilityOfPassingVariantColumn := container . NewVBox ( userProbabilityOfLabelA , passingVariantLabel , widget . NewSeparator ( ) )
userNumberOfVariantsTestedColumn := container . NewVBox ( userNumberOfLabel , variantsTestedLabelA , widget . NewSeparator ( ) )
offspringProbabilityOfHavingDiseaseColumn := container . NewVBox ( offspringProbabilityOfLabelA , havingDiseaseLabel , widget . NewSeparator ( ) )
offspringProbabilityOfHavingAVariantColumn := container . NewVBox ( offspringProbabilityOfLabelB , havingVariantLabel , widget . NewSeparator ( ) )
offspringNumberOfVariantsTestedColumn := container . NewVBox ( offspringNumberOfLabel , variantsTestedLabelB , widget . NewSeparator ( ) )
2024-06-02 10:43:39 +02:00
myPersonChosen , myGenomesExist , myAnalysisIsReady , myAnalysisObject , myGenomeIdentifier , _ , err := myChosenAnalysis . GetMyChosenMateGeneticAnalysis ( )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
monogenicDiseaseObjectsList , err := monogenicDiseases . GetMonogenicDiseaseObjectsList ( )
if ( err != nil ) { return nil , err }
for _ , diseaseObject := range monogenicDiseaseObjectsList {
monogenicDiseaseName := diseaseObject . DiseaseName
diseaseIsDominantOrRecessive := diseaseObject . DominantOrRecessive
diseaseVariantsList := diseaseObject . VariantsList
numberOfDiseaseVariants := len ( diseaseVariantsList )
//Outputs:
// -bool: User disease info exists
2024-06-07 04:16:54 +02:00
// -bool: User has the disease
2024-04-11 15:51:56 +02:00
// -int: User probability of passing a disease variant (0-100)
// -int: User number of variants tested
// -error
2024-06-07 04:16:54 +02:00
getUserDiseaseInfo := func ( ) ( bool , bool , int , int , error ) {
2024-04-11 15:51:56 +02:00
diseaseNameWithUnderscores := strings . ReplaceAll ( monogenicDiseaseName , " " , "_" )
probabilityOfPassingAVariantAttributeName := "MonogenicDisease_" + diseaseNameWithUnderscores + "_ProbabilityOfPassingAVariant"
numberOfVariantsTestedAttributeName := "MonogenicDisease_" + diseaseNameWithUnderscores + "_NumberOfVariantsTested"
2024-06-07 04:16:54 +02:00
userDiseaseInfoExists , _ , userProbabilityOfPassingDiseaseVariantString , err := getAnyUserProfileAttributeFunction ( probabilityOfPassingAVariantAttributeName )
if ( err != nil ) { return false , false , 0 , 0 , err }
2024-04-11 15:51:56 +02:00
if ( userDiseaseInfoExists == false ) {
2024-06-07 04:16:54 +02:00
return false , false , 0 , 0 , nil
2024-04-11 15:51:56 +02:00
}
2024-06-07 04:16:54 +02:00
userProbabilityOfPassingDiseaseVariant , err := helpers . ConvertStringToInt ( userProbabilityOfPassingDiseaseVariantString )
2024-04-11 15:51:56 +02:00
if ( err != nil ) {
2024-06-07 04:16:54 +02:00
return false , false , 0 , 0 , errors . New ( "setViewMateProfilePage_MonogenicDiseases called with profile containing invalid probabilityOfPassingAVariant: " + userProbabilityOfPassingDiseaseVariantString )
2024-04-11 15:51:56 +02:00
}
2024-06-07 04:16:54 +02:00
getUserHasDiseaseBool := func ( ) bool {
if ( diseaseIsDominantOrRecessive == "Dominant" ) {
if ( userProbabilityOfPassingDiseaseVariant != 0 ) {
return true
}
return false
}
// diseaseIsDominantOrRecessive == "Recessive"
if ( userProbabilityOfPassingDiseaseVariant == 100 ) {
return true
}
return false
}
userHasDisease := getUserHasDiseaseBool ( )
2024-04-11 15:51:56 +02:00
userVariantsTestedExists , _ , userNumberOfVariantsTested , err := getAnyUserProfileAttributeFunction ( numberOfVariantsTestedAttributeName )
2024-06-07 04:16:54 +02:00
if ( err != nil ) { return false , false , 0 , 0 , err }
2024-04-11 15:51:56 +02:00
if ( userVariantsTestedExists == false ) {
2024-06-07 04:16:54 +02:00
return false , false , 0 , 0 , errors . New ( "setViewMateProfilePage_MonogenicDiseases called with user profile containing probabilityOfPassingAVariant but not numberOfVariantsTested" )
2024-04-11 15:51:56 +02:00
}
userNumberOfVariantsTestedInt , err := helpers . ConvertStringToInt ( userNumberOfVariantsTested )
if ( err != nil ) {
2024-06-07 04:16:54 +02:00
return false , false , 0 , 0 , errors . New ( "setViewMateProfilePage_MonogenicDiseases called with profile containing invalid numberOfVariantsTested: " + userNumberOfVariantsTested )
2024-04-11 15:51:56 +02:00
}
2024-06-07 04:16:54 +02:00
return true , userHasDisease , userProbabilityOfPassingDiseaseVariant , userNumberOfVariantsTestedInt , nil
2024-04-11 15:51:56 +02:00
}
2024-06-07 04:16:54 +02:00
userDiseaseInfoExists , userHasDisease , userProbabilityOfPassingAVariant , userNumberOfVariantsTested , err := getUserDiseaseInfo ( )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
//Outputs:
// -bool: My disease info exists
// -int: My probability of passing a disease variant
// -int: Number of variants tested
// -error
getMyDiseaseInfo := func ( ) ( bool , int , int , error ) {
if ( myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false ) {
return false , 0 , 0 , nil
}
2024-06-02 10:43:39 +02:00
diseaseInfoIsKnown , _ , probabilityOfPassingADiseaseVariant , _ , numberOfVariantsTested , _ , _ , _ , err := readGeneticAnalysis . GetPersonMonogenicDiseaseInfoFromGeneticAnalysis ( myAnalysisObject , monogenicDiseaseName , myGenomeIdentifier )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return false , 0 , 0 , err }
2024-06-02 10:43:39 +02:00
if ( diseaseInfoIsKnown == false ) {
2024-04-11 15:51:56 +02:00
return false , 0 , 0 , nil
}
return true , probabilityOfPassingADiseaseVariant , numberOfVariantsTested , nil
}
myDiseaseInfoExists , myProbabilityOfPassingAVariant , myNumberOfVariantsTested , err := getMyDiseaseInfo ( )
if ( err != nil ) { return nil , err }
2024-06-15 02:43:01 +02:00
probabilityOffspringHasDiseaseIsKnown , probabilityOffspringHasDisease , probabilityOffspringHasVariantIsKnown , probabilityOffspringHasVariant , err := createCoupleGeneticAnalysis . GetOffspringMonogenicDiseaseProbabilities ( diseaseIsDominantOrRecessive , userDiseaseInfoExists , userProbabilityOfPassingAVariant , myDiseaseInfoExists , myProbabilityOfPassingAVariant )
2024-06-02 10:43:39 +02:00
if ( err != nil ) { return nil , err }
2024-04-11 15:51:56 +02:00
2024-06-07 04:16:54 +02:00
getUserHasDiseaseString := func ( ) string {
if ( userDiseaseInfoExists == false ) {
return "Unknown"
}
userHasDiseaseString := helpers . ConvertBoolToYesOrNoString ( userHasDisease )
return userHasDiseaseString
}
userHasDiseaseString := getUserHasDiseaseString ( )
2024-04-11 15:51:56 +02:00
getUserProbabilityOfPassingAVariantString := func ( ) string {
if ( userDiseaseInfoExists == false ) {
return "Unknown"
}
userProbabilityOfPassingAVariantString := helpers . ConvertIntToString ( userProbabilityOfPassingAVariant )
resultFormatted := userProbabilityOfPassingAVariantString + "%"
return resultFormatted
}
userProbabilityOfPassingAVariantString := getUserProbabilityOfPassingAVariantString ( )
getUserNumberOfVariantsTestedString := func ( ) string {
numberOfDiseaseVariantsString := helpers . ConvertIntToString ( numberOfDiseaseVariants )
if ( userDiseaseInfoExists == false ) {
result := "0/" + numberOfDiseaseVariantsString
return result
}
userNumberOfVariantsTestedString := helpers . ConvertIntToString ( userNumberOfVariantsTested )
resultFormatted := userNumberOfVariantsTestedString + "/" + numberOfDiseaseVariantsString
return resultFormatted
}
userNumberOfVariantsTestedString := getUserNumberOfVariantsTestedString ( )
getOffspringProbabilityOfHavingDiseaseString := func ( ) string {
2024-06-02 10:43:39 +02:00
if ( probabilityOffspringHasDiseaseIsKnown == false ) {
2024-04-11 15:51:56 +02:00
result := translate ( "Unknown" )
return result
}
2024-06-02 10:43:39 +02:00
offspringProbabilityOfHavingDiseaseString := helpers . ConvertIntToString ( probabilityOffspringHasDisease )
2024-04-11 15:51:56 +02:00
resultFormatted := offspringProbabilityOfHavingDiseaseString + "%"
return resultFormatted
}
offspringProbabilityOfHavingDiseaseString := getOffspringProbabilityOfHavingDiseaseString ( )
2024-06-02 10:43:39 +02:00
getOffspringProbabilityOfHavingAVariantFormatted := func ( ) string {
2024-04-11 15:51:56 +02:00
2024-06-02 10:43:39 +02:00
if ( probabilityOffspringHasVariantIsKnown == false ) {
2024-04-11 15:51:56 +02:00
result := translate ( "Unknown" )
return result
}
2024-06-02 10:43:39 +02:00
offspringProbabilityOfHavingAVariantString := helpers . ConvertIntToString ( probabilityOffspringHasVariant )
2024-04-11 15:51:56 +02:00
resultFormatted := offspringProbabilityOfHavingAVariantString + "%"
return resultFormatted
}
2024-06-02 10:43:39 +02:00
offspringProbabilityOfHavingAVariantFormatted := getOffspringProbabilityOfHavingAVariantFormatted ( )
2024-04-11 15:51:56 +02:00
2024-06-02 10:43:39 +02:00
totalNumberOfOffspringDiseaseVariantsString := helpers . ConvertIntToString ( numberOfDiseaseVariants * 2 )
offspringNumberOfVariantsTested := userNumberOfVariantsTested + myNumberOfVariantsTested
offspringNumberOfVariantsTestedString := helpers . ConvertIntToString ( offspringNumberOfVariantsTested )
offspringNumberOfVariantsTestedFormatted := offspringNumberOfVariantsTestedString + "/" + totalNumberOfOffspringDiseaseVariantsString
2024-04-11 15:51:56 +02:00
viewDiseaseInfoButton := widget . NewButtonWithIcon ( "" , theme . InfoIcon ( ) , func ( ) {
setViewMonogenicDiseaseDetailsPage ( window , monogenicDiseaseName , currentPage )
} )
diseaseNameLabel := getBoldLabelCentered ( monogenicDiseaseName )
2024-06-07 04:16:54 +02:00
userHasDiseaseLabel := getBoldLabelCentered ( userHasDiseaseString )
2024-04-11 15:51:56 +02:00
userProbabilityOfPassingAVariantLabel := getBoldLabelCentered ( userProbabilityOfPassingAVariantString )
userNumberOfVariantsTestedLabel := getBoldLabelCentered ( userNumberOfVariantsTestedString )
offspringProbabilityOfHavingDiseaseLabel := getBoldLabelCentered ( offspringProbabilityOfHavingDiseaseString )
2024-06-02 10:43:39 +02:00
offspringProbabilityOfHavingAVariantLabel := getBoldLabelCentered ( offspringProbabilityOfHavingAVariantFormatted )
offspringNumberOfVariantsTestedLabel := getBoldLabelCentered ( offspringNumberOfVariantsTestedFormatted )
2024-04-11 15:51:56 +02:00
diseaseInfoButtonsColumn . Add ( viewDiseaseInfoButton )
diseaseNameColumn . Add ( diseaseNameLabel )
2024-06-07 04:16:54 +02:00
userHasDiseaseColumn . Add ( userHasDiseaseLabel )
2024-04-11 15:51:56 +02:00
userProbabilityOfPassingVariantColumn . Add ( userProbabilityOfPassingAVariantLabel )
userNumberOfVariantsTestedColumn . Add ( userNumberOfVariantsTestedLabel )
offspringProbabilityOfHavingDiseaseColumn . Add ( offspringProbabilityOfHavingDiseaseLabel )
offspringProbabilityOfHavingAVariantColumn . Add ( offspringProbabilityOfHavingAVariantLabel )
offspringNumberOfVariantsTestedColumn . Add ( offspringNumberOfVariantsTestedLabel )
diseaseInfoButtonsColumn . Add ( widget . NewSeparator ( ) )
diseaseNameColumn . Add ( widget . NewSeparator ( ) )
2024-06-07 04:16:54 +02:00
userHasDiseaseColumn . Add ( widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
userProbabilityOfPassingVariantColumn . Add ( widget . NewSeparator ( ) )
userNumberOfVariantsTestedColumn . Add ( widget . NewSeparator ( ) )
offspringProbabilityOfHavingDiseaseColumn . Add ( widget . NewSeparator ( ) )
offspringProbabilityOfHavingAVariantColumn . Add ( widget . NewSeparator ( ) )
offspringNumberOfVariantsTestedColumn . Add ( widget . NewSeparator ( ) )
}
2024-06-07 04:16:54 +02:00
userHasDiseaseHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setPersonHasMonogenicDiseaseExplainerPage ( window , currentPage )
} )
2024-04-11 15:51:56 +02:00
probabilityOfPassingVariantHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setPersonProbabilityOfPassingVariantExplainerPage ( window , currentPage )
} )
numberOfVariantsTestedHelpButtonA := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setNumberOfTestedVariantsExplainerPage ( window , currentPage )
} )
numberOfVariantsTestedHelpButtonB := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setNumberOfTestedVariantsExplainerPage ( window , currentPage )
} )
probabilityOfHavingDiseaseHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setOffspringProbabilityOfHavingMonogenicDiseaseExplainerPage ( window , currentPage )
} )
probabilityOfHavingAVariantHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setOffspringProbabilityOfHavingVariantExplainerPage ( window , currentPage )
} )
2024-06-07 04:16:54 +02:00
userHasDiseaseColumn . Add ( userHasDiseaseHelpButton )
2024-04-11 15:51:56 +02:00
userProbabilityOfPassingVariantColumn . Add ( probabilityOfPassingVariantHelpButton )
userNumberOfVariantsTestedColumn . Add ( numberOfVariantsTestedHelpButtonA )
offspringProbabilityOfHavingDiseaseColumn . Add ( probabilityOfHavingDiseaseHelpButton )
offspringProbabilityOfHavingAVariantColumn . Add ( probabilityOfHavingAVariantHelpButton )
offspringNumberOfVariantsTestedColumn . Add ( numberOfVariantsTestedHelpButtonB )
if ( userOrOffspring == "User" ) {
2024-06-07 04:16:54 +02:00
diseasesInfoGrid := container . NewHBox ( layout . NewSpacer ( ) , diseaseInfoButtonsColumn , diseaseNameColumn , userHasDiseaseColumn , userProbabilityOfPassingVariantColumn , userNumberOfVariantsTestedColumn , layout . NewSpacer ( ) )
2024-04-11 15:51:56 +02:00
return diseasesInfoGrid , nil
}
diseasesInfoGrid := container . NewHBox ( layout . NewSpacer ( ) , diseaseInfoButtonsColumn , diseaseNameColumn , offspringProbabilityOfHavingDiseaseColumn , offspringProbabilityOfHavingAVariantColumn , offspringNumberOfVariantsTestedColumn , layout . NewSpacer ( ) )
return diseasesInfoGrid , nil
}
diseasesInfoGrid , err := getDiseasesInfoGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , description3 , widget . NewSeparator ( ) , userOrOffspringSelectorCentered , widget . NewSeparator ( ) , diseasesInfoGrid )
setPageContent ( page , window )
}
func setViewMateProfilePage_PolygenicDiseases ( window fyne . Window , userOrOffspring string , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
2024-08-13 15:25:47 +02:00
if ( userOrOffspring == "Offspring" ) {
setLoadingScreen ( window , "View Profile - Physical" , "Computing Genetic Analysis..." )
}
2024-04-11 15:51:56 +02:00
currentPage := func ( ) { setViewMateProfilePage_PolygenicDiseases ( window , userOrOffspring , getAnyUserProfileAttributeFunction , previousPage ) }
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Polygenic Diseases" ) )
description1 := getLabelCentered ( "Below is the polygenic disease risk analysis for this user." )
description2 := getLabelCentered ( "You can choose to view the analysis of the user or an offspring between you and the user." )
description3 := getLabelCentered ( "You must link your genome person in the Build Profile menu to see offspring information." )
handleSelectButton := func ( newUserOrOffspring string ) {
if ( userOrOffspring == newUserOrOffspring ) {
return
}
setViewMateProfilePage_PolygenicDiseases ( window , newUserOrOffspring , getAnyUserProfileAttributeFunction , previousPage )
}
userOrOffspringSelector := widget . NewSelect ( [ ] string { "User" , "Offspring" } , handleSelectButton )
userOrOffspringSelector . Selected = userOrOffspring
userOrOffspringSelectorCentered := getWidgetCentered ( userOrOffspringSelector )
getDiseaseInfoGrid := func ( ) ( * fyne . Container , error ) {
diseaseNameLabel := getItalicLabelCentered ( "Disease Name" )
userRiskScoreLabel := getItalicLabelCentered ( "User Risk Score" )
offspringRiskScoreLabel := getItalicLabelCentered ( "Offspring Risk Score" )
2024-08-13 15:25:47 +02:00
confidenceRangeLabel := getItalicLabelCentered ( "Confidence Range" )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
emptyLabel1 := widget . NewLabel ( "" )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
emptyLabel2 := widget . NewLabel ( "" )
2024-06-07 02:04:13 +02:00
2024-08-13 15:25:47 +02:00
diseaseNameColumn := container . NewVBox ( diseaseNameLabel , widget . NewSeparator ( ) )
userRiskScoreColumn := container . NewVBox ( userRiskScoreLabel , widget . NewSeparator ( ) )
offspringRiskScoreColumn := container . NewVBox ( offspringRiskScoreLabel , widget . NewSeparator ( ) )
confidenceRangeColumn := container . NewVBox ( confidenceRangeLabel , widget . NewSeparator ( ) )
viewSampleOffspringsChartButtonsColumn := container . NewVBox ( emptyLabel1 , widget . NewSeparator ( ) )
viewDiseaseInfoButtonsColumn := container . NewVBox ( emptyLabel2 , widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
//Outputs:
// -map[int64]locusValue.LocusValue
// -error
getMyGenomeLocusValuesMap := func ( ) ( map [ int64 ] locusValue . LocusValue , error ) {
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
if ( userOrOffspring == "User" ) {
// We don't need to retrieve our locus values map
emptyMap := make ( map [ int64 ] locusValue . LocusValue )
return emptyMap , nil
}
myPersonChosen , myGenomesExist , myAnalysisIsReady , myAnalysisObject , myGenomeIdentifier , _ , err := myChosenAnalysis . GetMyChosenMateGeneticAnalysis ( )
if ( err != nil ) { return nil , err }
if ( myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false ) {
emptyMap := make ( map [ int64 ] locusValue . LocusValue )
return emptyMap , nil
}
_ , _ , _ , _ , myGenomesMap , err := readGeneticAnalysis . GetMetadataFromPersonGeneticAnalysis ( myAnalysisObject )
if ( err != nil ) { return nil , err }
myGenomeLocusValuesMap , exists := myGenomesMap [ myGenomeIdentifier ]
if ( exists == false ) {
return nil , errors . New ( "GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier." )
}
return myGenomeLocusValuesMap , nil
}
myGenomeLocusValuesMap , err := getMyGenomeLocusValuesMap ( )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
2024-08-13 15:25:47 +02:00
getConfidenceRangeLabel := func ( analysisExists bool , predictionConfidenceRangesMap map [ int ] float64 ) ( fyne . Widget , error ) {
if ( analysisExists == false ) {
result := widget . NewLabel ( "Unknown" )
return result , nil
}
// This is a list of the percentage accuracies in the map
// For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be
// accurate within that range
confidenceRangePercentagesList := helpers . GetListOfMapKeys ( predictionConfidenceRangesMap )
// We sort the list so the percentage is always the same upon refreshing the page
slices . Sort ( confidenceRangePercentagesList )
closestToEightyPercentage , err := helpers . GetClosestIntInList ( confidenceRangePercentagesList , 80 )
if ( err != nil ) { return nil , err }
closestToEightyPercentageConfidenceDistance , exists := predictionConfidenceRangesMap [ closestToEightyPercentage ]
if ( exists == false ) {
return nil , errors . New ( "GetListOfMapKeys returning list of elements which contains element which is not in the map." )
}
closestConfidenceDistanceString := helpers . ConvertFloat64ToStringRounded ( closestToEightyPercentageConfidenceDistance , 2 )
closestToEightyPercentageString := helpers . ConvertIntToString ( closestToEightyPercentage )
confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)"
confidenceRangeLabel := getBoldLabel ( confidenceRangeLabelValueFormatted )
return confidenceRangeLabel , nil
}
2024-04-11 15:51:56 +02:00
diseaseObjectsList , err := polygenicDiseases . GetPolygenicDiseaseObjectsList ( )
if ( err != nil ) { return nil , err }
for _ , diseaseObject := range diseaseObjectsList {
diseaseName := diseaseObject . DiseaseName
diseaseLociList := diseaseObject . LociList
2024-08-15 14:14:23 +02:00
predictionModelExists := trainedPredictionModels . CheckIfAttributeNeuralNetworkExists ( diseaseName )
2024-08-13 15:25:47 +02:00
if ( predictionModelExists == false ) {
// Prediction is not possible for this disease
continue
2024-06-07 02:04:13 +02:00
}
2024-08-13 15:25:47 +02:00
diseaseNameLabel := getBoldLabelCentered ( diseaseName )
2024-06-07 02:04:13 +02:00
2024-08-14 13:25:25 +02:00
userDiseaseLocusValuesMap , err := calculatedAttributes . GetUserGenomeLocusValuesMapFromProfile ( diseaseLociList , getAnyUserProfileAttributeFunction )
if ( err != nil ) { return nil , err }
2024-04-11 15:51:56 +02:00
if ( userOrOffspring == "User" ) {
2024-08-13 15:25:47 +02:00
neuralNetworkExists , analysisExists , userDiseaseRiskScore , predictionConfidenceRangesMap , _ , _ , err := createPersonGeneticAnalysis . GetPersonGenomePolygenicDiseaseAnalysis ( diseaseObject , userDiseaseLocusValuesMap , true )
if ( err != nil ) { return nil , err }
if ( neuralNetworkExists == false ) {
return nil , errors . New ( "GetPersonGenomePolygenicDiseaseAnalysis claims model doesn't exist when we already checked." )
2024-06-07 02:04:13 +02:00
}
2024-08-13 15:25:47 +02:00
getUserDiseaseRiskScoreLabel := func ( ) fyne . Widget {
2024-06-07 02:04:13 +02:00
2024-08-13 15:25:47 +02:00
if ( analysisExists == false ) {
2024-06-07 02:04:13 +02:00
2024-08-13 15:25:47 +02:00
result := widget . NewLabel ( translate ( "Unknown" ) )
2024-06-07 02:04:13 +02:00
2024-08-13 15:25:47 +02:00
return result
}
2024-06-07 02:04:13 +02:00
2024-08-13 15:25:47 +02:00
userRiskScoreString := helpers . ConvertIntToString ( userDiseaseRiskScore )
riskScoreFormatted := userRiskScoreString + "/10"
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
riskScoreLabel := getBoldLabel ( riskScoreFormatted )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
return riskScoreLabel
2024-04-11 15:51:56 +02:00
}
2024-08-13 15:25:47 +02:00
userDiseaseRiskScoreLabel := getUserDiseaseRiskScoreLabel ( )
userDiseaseRiskScoreLabelCentered := getWidgetCentered ( userDiseaseRiskScoreLabel )
userRiskScoreColumn . Add ( userDiseaseRiskScoreLabelCentered )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeLabel , err := getConfidenceRangeLabel ( analysisExists , predictionConfidenceRangesMap )
if ( err != nil ) { return nil , err }
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeLabelCentered := getWidgetCentered ( confidenceRangeLabel )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeColumn . Add ( confidenceRangeLabelCentered )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
} else if ( userOrOffspring == "Offspring" ) {
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
neuralNetworkExists , anyOffspringLociKnown , offspringDiseaseRiskScore , predictionConfidenceRangesMap , offspringSampleRiskScoresList , offspringQuantityOfLociKnown , _ , err := createCoupleGeneticAnalysis . GetOffspringPolygenicDiseaseAnalysis ( diseaseObject , myGenomeLocusValuesMap , userDiseaseLocusValuesMap )
if ( err != nil ) { return nil , err }
if ( neuralNetworkExists == false ) {
return nil , errors . New ( "GetOffspringPolygenicDiseaseAnalysis claims that neural network doesn't exist when we already checked." )
2024-06-02 10:43:39 +02:00
}
2024-08-13 15:25:47 +02:00
getOffspringDiseaseRiskScoreLabel := func ( ) fyne . Widget {
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
if ( anyOffspringLociKnown == false ) {
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
result := widget . NewLabel ( translate ( "Unknown" ) )
return result
}
2024-06-07 02:04:13 +02:00
2024-08-13 15:25:47 +02:00
offspringRiskScoreString := helpers . ConvertIntToString ( offspringDiseaseRiskScore )
riskScoreFormatted := offspringRiskScoreString + "/10"
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
riskScoreLabel := getBoldLabel ( riskScoreFormatted )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
return riskScoreLabel
2024-04-11 15:51:56 +02:00
}
2024-08-13 15:25:47 +02:00
offspringDiseaseRiskScoreLabel := getOffspringDiseaseRiskScoreLabel ( )
offspringDiseaseRiskScoreLabelCentered := getWidgetCentered ( offspringDiseaseRiskScoreLabel )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
offspringRiskScoreColumn . Add ( offspringDiseaseRiskScoreLabelCentered )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeLabel , err := getConfidenceRangeLabel ( anyOffspringLociKnown , predictionConfidenceRangesMap )
if ( err != nil ) { return nil , err }
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeLabelCentered := getWidgetCentered ( confidenceRangeLabel )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeColumn . Add ( confidenceRangeLabelCentered )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
viewSampleOffspringsChartButton := widget . NewButtonWithIcon ( "" , theme . InfoIcon ( ) , func ( ) {
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
setViewPolygenicDiseaseSampleOffspringRiskScoresChart ( window , diseaseName , offspringSampleRiskScoresList , offspringQuantityOfLociKnown , currentPage )
} )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
viewSampleOffspringsChartButtonsColumn . Add ( viewSampleOffspringsChartButton )
2024-04-11 15:51:56 +02:00
}
2024-08-13 15:25:47 +02:00
viewDiseaseDetailsButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
2024-04-11 15:51:56 +02:00
} )
2024-08-13 15:25:47 +02:00
diseaseNameColumn . Add ( diseaseNameLabel )
viewDiseaseInfoButtonsColumn . Add ( viewDiseaseDetailsButton )
diseaseNameColumn . Add ( widget . NewSeparator ( ) )
userRiskScoreColumn . Add ( widget . NewSeparator ( ) )
offspringRiskScoreColumn . Add ( widget . NewSeparator ( ) )
confidenceRangeColumn . Add ( widget . NewSeparator ( ) )
viewSampleOffspringsChartButtonsColumn . Add ( widget . NewSeparator ( ) )
viewDiseaseInfoButtonsColumn . Add ( widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
}
2024-08-13 15:25:47 +02:00
userRiskScoreHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setPolygenicDiseaseRiskScoreExplainerPage ( window , currentPage )
2024-04-11 15:51:56 +02:00
} )
2024-08-13 15:25:47 +02:00
userRiskScoreColumn . Add ( userRiskScoreHelpButton )
offspringRiskScoreHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setOffspringPolygenicDiseaseRiskScoreExplainerPage ( window , currentPage )
2024-04-11 15:51:56 +02:00
} )
2024-08-13 15:25:47 +02:00
offspringRiskScoreColumn . Add ( offspringRiskScoreHelpButton )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
showUnderConstructionDialog ( window )
//TODO
} )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeColumn . Add ( confidenceRangeHelpButton )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
if ( userOrOffspring == "User" ) {
diseaseInfoGrid := container . NewHBox ( layout . NewSpacer ( ) , diseaseNameColumn , userRiskScoreColumn , confidenceRangeColumn , viewDiseaseInfoButtonsColumn , layout . NewSpacer ( ) )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
return diseaseInfoGrid , nil
2024-04-11 15:51:56 +02:00
}
2024-08-13 15:25:47 +02:00
diseaseInfoGrid := container . NewHBox ( layout . NewSpacer ( ) , diseaseNameColumn , offspringRiskScoreColumn , confidenceRangeColumn , viewSampleOffspringsChartButtonsColumn , viewDiseaseInfoButtonsColumn , layout . NewSpacer ( ) )
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
return diseaseInfoGrid , nil
2024-04-11 15:51:56 +02:00
}
2024-08-13 15:25:47 +02:00
diseaseInfoGrid , err := getDiseaseInfoGrid ( )
2024-04-11 15:51:56 +02:00
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
2024-08-13 15:25:47 +02:00
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , description3 , widget . NewSeparator ( ) , userOrOffspringSelectorCentered , widget . NewSeparator ( ) , diseaseInfoGrid )
2024-04-11 15:51:56 +02:00
setPageContent ( page , window )
}
2024-08-13 15:25:47 +02:00
2024-07-19 19:16:28 +02:00
func setViewMateProfilePage_GeneticTraits ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
currentPage := func ( ) { setViewMateProfilePage_GeneticTraits ( window , getAnyUserProfileAttributeFunction , previousPage ) }
2024-04-11 15:51:56 +02:00
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Genetic Traits" ) )
2024-07-19 19:16:28 +02:00
description1 := getLabelCentered ( "Choose if you want to view Discrete traits or Numeric traits." )
description2 := getLabelCentered ( "Discrete traits are traits which have discrete outcomes, such as Eye Color" )
description3 := getLabelCentered ( "Numeric traits are traits with numeric outcomes, such as Height." )
discreteTraitsButton := widget . NewButton ( "Discrete Traits" , func ( ) {
setViewMateProfilePage_DiscreteGeneticTraits ( window , "Offspring" , getAnyUserProfileAttributeFunction , currentPage )
} )
numericTraitsButton := widget . NewButton ( "Numeric Traits" , func ( ) {
2024-08-09 16:23:37 +02:00
setViewMateProfilePage_NumericGeneticTraits ( window , "Offspring" , getAnyUserProfileAttributeFunction , currentPage )
2024-07-19 19:16:28 +02:00
} )
buttonsGrid := getContainerCentered ( container . NewGridWithColumns ( 1 , discreteTraitsButton , numericTraitsButton ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , description3 , widget . NewSeparator ( ) , buttonsGrid )
setPageContent ( page , window )
}
func setViewMateProfilePage_DiscreteGeneticTraits ( window fyne . Window , userOrOffspring string , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
if ( userOrOffspring != "User" && userOrOffspring != "Offspring" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMateProfilePage_DiscreteGeneticTraits called with invalid userOrOffspring: " + userOrOffspring ) , previousPage )
return
}
if ( userOrOffspring == "Offspring" ) {
setLoadingScreen ( window , "View Profile - Physical" , "Computing Genetic Analysis..." )
}
currentPage := func ( ) { setViewMateProfilePage_DiscreteGeneticTraits ( window , userOrOffspring , getAnyUserProfileAttributeFunction , previousPage ) }
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Discrete Genetic Traits" ) )
description1 := getLabelCentered ( "Below is the discrete genetic trait analysis for this user." )
2024-04-11 15:51:56 +02:00
description2 := getLabelCentered ( "You can choose to view the analysis of the user or an offspring between you and the user." )
description3 := getLabelCentered ( "You must link your genome person in the Build Profile menu to see offspring information." )
handleSelectButton := func ( newUserOrOffspring string ) {
if ( userOrOffspring == newUserOrOffspring ) {
return
}
2024-07-19 19:16:28 +02:00
setViewMateProfilePage_DiscreteGeneticTraits ( window , newUserOrOffspring , getAnyUserProfileAttributeFunction , previousPage )
2024-04-11 15:51:56 +02:00
}
userOrOffspringSelector := widget . NewSelect ( [ ] string { "User" , "Offspring" } , handleSelectButton )
2024-07-19 19:16:28 +02:00
userOrOffspringSelector . Selected = userOrOffspring
2024-04-11 15:51:56 +02:00
userOrOffspringSelectorCentered := getWidgetCentered ( userOrOffspringSelector )
getTraitsInfoGrid := func ( ) ( * fyne . Container , error ) {
2024-07-19 19:16:28 +02:00
myPersonChosen , myGenomesExist , myAnalysisIsReady , myAnalysisObject , myGenomeIdentifier , _ , err := myChosenAnalysis . GetMyChosenMateGeneticAnalysis ( )
if ( err != nil ) { return nil , err }
//Outputs:
// -map[int64]locusValue.LocusValue
// -error
getMyGenomeLocusValuesMap := func ( ) ( map [ int64 ] locusValue . LocusValue , error ) {
if ( myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false ) {
emptyMap := make ( map [ int64 ] locusValue . LocusValue )
return emptyMap , nil
}
_ , _ , _ , _ , myGenomesMap , err := readGeneticAnalysis . GetMetadataFromPersonGeneticAnalysis ( myAnalysisObject )
if ( err != nil ) { return nil , err }
myGenomeLocusValuesMap , exists := myGenomesMap [ myGenomeIdentifier ]
if ( exists == false ) {
return nil , errors . New ( "GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier." )
}
return myGenomeLocusValuesMap , nil
}
myGenomeLocusValuesMap , err := getMyGenomeLocusValuesMap ( )
if ( err != nil ) { return nil , err }
emptyLabel1 := widget . NewLabel ( "" )
2024-04-11 15:51:56 +02:00
traitNameLabel := getItalicLabelCentered ( "Trait Name" )
2024-07-19 19:16:28 +02:00
emptyLabel2 := widget . NewLabel ( "" )
userPredictedOutcomeTitle := getItalicLabelCentered ( "User Predicted Outcome" )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
emptyLabel3 := widget . NewLabel ( "" )
offspringOutcomeProbabilitiesLabel := getItalicLabelCentered ( "Offspring Outcome Probabilities" )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLabel1 := getItalicLabelCentered ( "Quantity Of" )
lociKnownLabel := getItalicLabelCentered ( "Loci Known" )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
emptyLabel4 := widget . NewLabel ( "" )
emptyLabel5 := widget . NewLabel ( "" )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
traitNameColumn := container . NewVBox ( emptyLabel1 , traitNameLabel , widget . NewSeparator ( ) )
userPredictedOutcomeColumn := container . NewVBox ( emptyLabel2 , userPredictedOutcomeTitle , widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
offspringOutcomeProbabilitiesColumn := container . NewVBox ( emptyLabel3 , offspringOutcomeProbabilitiesLabel , widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownColumn := container . NewVBox ( quantityOfLabel1 , lociKnownLabel , widget . NewSeparator ( ) )
viewTraitDetailsButtonsColumn := container . NewVBox ( emptyLabel4 , emptyLabel5 , widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
traitObjectsList , err := traits . GetTraitObjectsList ( )
if ( err != nil ) { return nil , err }
for _ , traitObject := range traitObjectsList {
traitName := traitObject . TraitName
2024-07-19 19:16:28 +02:00
traitIsDiscreteOrNumeric := traitObject . DiscreteOrNumeric
if ( traitIsDiscreteOrNumeric != "Discrete" ) {
continue
}
2024-04-11 15:51:56 +02:00
traitRulesList := traitObject . RulesList
totalNumberOfTraitRules := len ( traitRulesList )
2024-07-19 19:16:28 +02:00
traitLociList := traitObject . LociList
numberOfTraitLoci := len ( traitLociList )
if ( totalNumberOfTraitRules == 0 && numberOfTraitLoci == 0 ) {
2024-04-11 15:51:56 +02:00
// We are not able to analyze these traits yet
continue
}
2024-08-15 14:14:23 +02:00
traitNeuralNetworkExists := trainedPredictionModels . CheckIfAttributeNeuralNetworkExists ( traitName )
2024-07-19 19:16:28 +02:00
if ( traitNeuralNetworkExists == false && totalNumberOfTraitRules == 0 ) {
// We are not able to analyze these traits yet
continue
}
2024-04-11 15:51:56 +02:00
traitNameText := getBoldLabelCentered ( translate ( traitName ) )
traitNameColumn . Add ( traitNameText )
viewTraitDetailsButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
2024-07-19 19:16:28 +02:00
if ( traitNeuralNetworkExists == true ) {
//TODO
showUnderConstructionDialog ( window )
} else {
setViewMateProfilePage_DiscreteTraitRules ( window , traitName , userOrOffspring , getAnyUserProfileAttributeFunction , currentPage )
}
2024-04-11 15:51:56 +02:00
} )
viewTraitDetailsButtonsColumn . Add ( viewTraitDetailsButton )
2024-06-07 02:04:13 +02:00
// We construct the user's trait locus values map
2024-08-14 13:25:25 +02:00
userTraitLocusValuesMap , err := calculatedAttributes . GetUserGenomeLocusValuesMapFromProfile ( traitLociList , getAnyUserProfileAttributeFunction )
if ( err != nil ) { return nil , err }
2024-06-07 02:04:13 +02:00
2024-07-19 19:16:28 +02:00
if ( userOrOffspring == "User" ) {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
if ( traitNeuralNetworkExists == true ) {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
traitNeuralNetworkExists , anyLocusValuesAreKnown , predictedOutcome , _ , quantityOfLociKnown , _ , err := createPersonGeneticAnalysis . GetGenomeDiscreteTraitAnalysis_NeuralNetwork ( traitObject , userTraitLocusValuesMap , true )
if ( err != nil ) { return nil , err }
if ( traitNeuralNetworkExists == false ) {
return nil , errors . New ( "GetGenomeTraitAnalysis_NeuralNetwork claims neural network doesn't exist for trait, but we already checked." )
}
if ( anyLocusValuesAreKnown == false ) {
unknownLabel := getItalicLabelCentered ( translate ( "Unknown" ) )
userPredictedOutcomeColumn . Add ( unknownLabel )
} else {
predictedOutcomeLabel := getBoldLabelCentered ( predictedOutcome )
userPredictedOutcomeColumn . Add ( predictedOutcomeLabel )
}
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
totalNumberOfLociString := helpers . ConvertIntToString ( numberOfTraitLoci )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownString := helpers . ConvertIntToString ( quantityOfLociKnown )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalNumberOfLociString
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownLabel := getBoldLabelCentered ( quantityOfLociKnownFormatted )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownColumn . Add ( quantityOfLociKnownLabel )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
} else {
// We use the rules-based analysis
anyRulesExist , _ , quantityOfLociKnown_Rules , _ , predictedOutcomeIsKnown , predictedOutcome , err := createPersonGeneticAnalysis . GetGenomeDiscreteTraitAnalysis_Rules ( traitObject , userTraitLocusValuesMap , true )
if ( err != nil ) { return nil , err }
if ( anyRulesExist == false ) {
return nil , errors . New ( "GetGenomeTraitAnalysis_Rules claims no rules exist when we already checked." )
2024-04-11 15:51:56 +02:00
}
2024-07-19 19:16:28 +02:00
if ( predictedOutcomeIsKnown == false ) {
unknownLabel := getItalicLabelCentered ( "Unknown" )
userPredictedOutcomeColumn . Add ( unknownLabel )
} else {
predictedOutcomeLabel := getBoldLabelCentered ( predictedOutcome )
userPredictedOutcomeColumn . Add ( predictedOutcomeLabel )
}
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
traitLociList_Rules := traitObject . LociList_Rules
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
totalQuantityOfLoci := len ( traitLociList_Rules )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownString := helpers . ConvertIntToString ( quantityOfLociKnown_Rules )
totalQuantityOfLociString := helpers . ConvertIntToString ( totalQuantityOfLoci )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered ( quantityOfLociKnownFormatted )
quantityOfLociKnownColumn . Add ( quantityOfLociKnownLabel )
2024-04-11 15:51:56 +02:00
}
2024-07-19 19:16:28 +02:00
} else {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
// userOrOffspring == "Offspring"
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
if ( traitNeuralNetworkExists == true ) {
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
neuralNetworkExists , anyLociKnown , outcomeProbabilitiesMap , _ , quantityOfLociKnown , _ , err := createCoupleGeneticAnalysis . GetOffspringDiscreteTraitAnalysis_NeuralNetwork ( traitObject , userTraitLocusValuesMap , myGenomeLocusValuesMap )
2024-07-19 19:16:28 +02:00
if ( err != nil ) { return nil , err }
if ( neuralNetworkExists == false ) {
2024-08-13 15:25:47 +02:00
return nil , errors . New ( "GetOffspringDiscreteTraitAnalysis_NeuralNetwork claiming that neural network doesn't exist when we already checked." )
2024-07-19 19:16:28 +02:00
}
2024-06-02 10:43:39 +02:00
2024-07-19 19:16:28 +02:00
totalNumberOfLociString := helpers . ConvertIntToString ( numberOfTraitLoci )
2024-06-02 10:43:39 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownString := helpers . ConvertIntToString ( quantityOfLociKnown )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalNumberOfLociString
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownLabel := getBoldLabelCentered ( quantityOfLociKnownFormatted )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownColumn . Add ( quantityOfLociKnownLabel )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
if ( anyLociKnown == false ) {
unknownLabel := getItalicLabelCentered ( "Unknown" )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
offspringOutcomeProbabilitiesColumn . Add ( unknownLabel )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
} else {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
outcomesList := helpers . GetListOfMapKeys ( outcomeProbabilitiesMap )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
// We sort the outcomes in alphabetical order so they show up the same way each time
slices . Sort ( outcomesList )
quantityOfAddedItems := 0
for _ , outcomeName := range outcomesList {
outcomeProbability , exists := outcomeProbabilitiesMap [ outcomeName ]
if ( exists == false ) {
return nil , errors . New ( "GetListOfMapKeys returning element which doesn't exist in map." )
}
if ( outcomeProbability == 0 ) {
continue
}
2024-06-02 10:43:39 +02:00
2024-07-19 19:16:28 +02:00
outcomeProbabilityString := helpers . ConvertIntToString ( outcomeProbability )
outcomeProbabilityLabelText := outcomeName + ": " + outcomeProbabilityString + "%"
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
outcomeProbabilityLabel := getBoldLabelCentered ( outcomeProbabilityLabelText )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
offspringOutcomeProbabilitiesColumn . Add ( outcomeProbabilityLabel )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfAddedItems += 1
if ( quantityOfAddedItems > 1 ) {
// We add whitespace for the other columns
traitNameColumn . Add ( widget . NewLabel ( "" ) )
quantityOfLociKnownColumn . Add ( widget . NewLabel ( "" ) )
viewTraitDetailsButtonsColumn . Add ( widget . NewLabel ( "" ) )
}
2024-04-11 15:51:56 +02:00
}
}
2024-07-19 19:16:28 +02:00
} else {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
// We use the rules-based analysis
2024-04-11 15:51:56 +02:00
2024-08-13 15:25:47 +02:00
anyRulesExist , rulesAnalysisExists , _ , offspringQuantityOfLociKnown , _ , outcomeProbabilitiesMap , err := createCoupleGeneticAnalysis . GetOffspringDiscreteTraitAnalysis_Rules ( traitObject , myGenomeLocusValuesMap , userTraitLocusValuesMap )
2024-07-19 19:16:28 +02:00
if ( err != nil ) { return nil , err }
if ( anyRulesExist == false ) {
2024-08-13 15:25:47 +02:00
return nil , errors . New ( "GetOffspringDiscreteTraitAnalysis_Rules claiming that no rules exist when we already checked." )
2024-07-19 19:16:28 +02:00
}
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
lociList_Rules := traitObject . LociList_Rules
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
totalQuantityOfLoci := len ( lociList_Rules )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownString := helpers . ConvertIntToString ( offspringQuantityOfLociKnown )
totalQuantityOfLociString := helpers . ConvertIntToString ( totalQuantityOfLoci )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfLociKnownFormatted := quantityOfLociKnownString + "/" + totalQuantityOfLociString
quantityOfLociKnownLabel := getBoldLabelCentered ( quantityOfLociKnownFormatted )
quantityOfLociKnownColumn . Add ( quantityOfLociKnownLabel )
if ( rulesAnalysisExists == false ) {
unknownLabel := getItalicLabelCentered ( translate ( "Unknown" ) )
offspringOutcomeProbabilitiesColumn . Add ( unknownLabel )
} else {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
outcomesList := helpers . GetListOfMapKeys ( outcomeProbabilitiesMap )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
// We sort the outcomes in alphabetical order so they show up the same way each time
slices . Sort ( outcomesList )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
quantityOfAddedItems := 0
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
for _ , outcomeName := range outcomesList {
outcomeProbability , exists := outcomeProbabilitiesMap [ outcomeName ]
if ( exists == false ) {
return nil , errors . New ( "GetListOfMapKeys returning element which doesn't exist in map." )
}
if ( outcomeProbability == 0 ) {
continue
}
outcomeProbabilityString := helpers . ConvertIntToString ( outcomeProbability )
outcomeProbabilityLabelText := outcomeName + ": " + outcomeProbabilityString + "%"
outcomeProbabilityLabel := getBoldLabelCentered ( outcomeProbabilityLabelText )
offspringOutcomeProbabilitiesColumn . Add ( outcomeProbabilityLabel )
quantityOfAddedItems += 1
if ( quantityOfAddedItems > 1 ) {
// We add whitespace for the other columns
traitNameColumn . Add ( widget . NewLabel ( "" ) )
quantityOfLociKnownColumn . Add ( widget . NewLabel ( "" ) )
viewTraitDetailsButtonsColumn . Add ( widget . NewLabel ( "" ) )
}
2024-04-11 15:51:56 +02:00
}
}
}
}
2024-06-02 10:43:39 +02:00
2024-04-11 15:51:56 +02:00
traitNameColumn . Add ( widget . NewSeparator ( ) )
2024-07-19 19:16:28 +02:00
userPredictedOutcomeColumn . Add ( widget . NewSeparator ( ) )
offspringOutcomeProbabilitiesColumn . Add ( widget . NewSeparator ( ) )
quantityOfLociKnownColumn . Add ( widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
viewTraitDetailsButtonsColumn . Add ( widget . NewSeparator ( ) )
}
2024-07-19 19:16:28 +02:00
if ( userOrOffspring == "User" ) {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
predictedOutcomeHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
//TODO
showUnderConstructionDialog ( window )
} )
userPredictedOutcomeColumn . Add ( predictedOutcomeHelpButton )
} else {
// userOrOffspring == "Offspring"
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
outcomeProbabilitiesHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
offspringOutcomeProbabilitiesColumn . Add ( outcomeProbabilitiesHelpButton )
}
quantityOfLociKnownHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
2024-04-11 15:51:56 +02:00
} )
2024-07-19 19:16:28 +02:00
quantityOfLociKnownColumn . Add ( quantityOfLociKnownHelpButton )
traitsInfoGrid := container . NewHBox ( layout . NewSpacer ( ) , traitNameColumn )
2024-04-11 15:51:56 +02:00
if ( userOrOffspring == "User" ) {
2024-07-19 19:16:28 +02:00
traitsInfoGrid . Add ( userPredictedOutcomeColumn )
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
} else {
// userOrOffspring == "Offspring"
traitsInfoGrid . Add ( offspringOutcomeProbabilitiesColumn )
2024-04-11 15:51:56 +02:00
}
2024-07-19 19:16:28 +02:00
traitsInfoGrid . Add ( quantityOfLociKnownColumn )
traitsInfoGrid . Add ( viewTraitDetailsButtonsColumn )
traitsInfoGrid . Add ( layout . NewSpacer ( ) )
2024-04-11 15:51:56 +02:00
return traitsInfoGrid , nil
}
traitsInfoGrid , err := getTraitsInfoGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , description3 , widget . NewSeparator ( ) , userOrOffspringSelectorCentered , widget . NewSeparator ( ) , traitsInfoGrid )
setPageContent ( page , window )
}
2024-07-19 19:16:28 +02:00
func setViewMateProfilePage_DiscreteTraitRules ( window fyne . Window , traitName string , userOrOffspring string , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
currentPage := func ( ) { setViewMateProfilePage_DiscreteTraitRules ( window , traitName , userOrOffspring , getAnyUserProfileAttributeFunction , previousPage ) }
2024-04-11 15:51:56 +02:00
title := getPageTitleCentered ( "View Profile - Physical" )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( userOrOffspring + " Trait Rules" )
traitNameLabel := widget . NewLabel ( "Trait Name:" )
traitNameText := getBoldLabel ( traitName )
viewTraitInfoButton := widget . NewButtonWithIcon ( "" , theme . InfoIcon ( ) , func ( ) {
setViewTraitDetailsPage ( window , traitName , currentPage )
} )
traitNameRow := container . NewHBox ( layout . NewSpacer ( ) , traitNameLabel , traitNameText , viewTraitInfoButton , layout . NewSpacer ( ) )
//Outputs:
2024-06-05 06:10:35 +02:00
// -bool: Any trait locus value exists for this myself
// -map[int64]locusValue.LocusValue: My locus values map
2024-04-11 15:51:56 +02:00
// -error
2024-07-19 19:16:28 +02:00
getMyGenomeLocusValuesMap := func ( ) ( bool , map [ int64 ] locusValue . LocusValue , error ) {
2024-04-11 15:51:56 +02:00
2024-06-05 06:10:35 +02:00
myPersonChosen , myGenomesExist , myAnalysisIsReady , myAnalysisObject , myGenomeIdentifier , _ , err := myChosenAnalysis . GetMyChosenMateGeneticAnalysis ( )
if ( err != nil ) { return false , nil , err }
2024-04-11 15:51:56 +02:00
2024-06-05 06:10:35 +02:00
if ( myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false ) {
// Without my genome person chosen, all offspring rule probabilities are unknown
return false , nil , nil
}
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
_ , _ , _ , _ , myGenomesMap , err := readGeneticAnalysis . GetMetadataFromPersonGeneticAnalysis ( myAnalysisObject )
if ( err != nil ) { return false , nil , err }
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
myGenomeMap , exists := myGenomesMap [ myGenomeIdentifier ]
if ( exists == false ) {
return false , nil , errors . New ( "GetMyChosenMateGeneticAnalysis returning analysis which does not contain genome matching myGenomeIdentifier" )
2024-06-05 06:10:35 +02:00
}
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
return true , myGenomeMap , nil
2024-06-05 06:10:35 +02:00
}
2024-07-19 19:16:28 +02:00
anyMyLocusValuesExist , myLocusValuesMap , err := getMyGenomeLocusValuesMap ( )
2024-06-05 06:10:35 +02:00
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
traitObject , err := traits . GetTraitObject ( traitName )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
2024-07-19 19:16:28 +02:00
traitLociList_Rules := traitObject . LociList_Rules
2024-06-05 06:10:35 +02:00
traitRulesList := traitObject . RulesList
2024-07-19 19:16:28 +02:00
if ( len ( traitRulesList ) == 0 ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMateProfilePage_DiscreteTraitRules called with trait which has no rules." ) , previousPage )
return
}
2024-06-05 06:10:35 +02:00
//Outputs:
// -bool: Any trait locus value exists for this user
// -map[int64]locusValue.LocusValue: User locus values map
// -error
getUserTraitLocusValuesMap := func ( ) ( bool , map [ int64 ] locusValue . LocusValue , error ) {
// We construct the user's trait locus values map
2024-08-05 09:11:10 +02:00
2024-08-14 13:25:25 +02:00
userTraitLocusValuesMap , err := calculatedAttributes . GetUserGenomeLocusValuesMapFromProfile ( traitLociList_Rules , getAnyUserProfileAttributeFunction )
if ( err != nil ) { return false , nil , err }
2024-06-05 06:10:35 +02:00
if ( len ( userTraitLocusValuesMap ) == 0 ) {
return false , nil , nil
2024-04-11 15:51:56 +02:00
}
2024-06-05 06:10:35 +02:00
return true , userTraitLocusValuesMap , nil
2024-04-11 15:51:56 +02:00
}
2024-06-05 06:10:35 +02:00
anyUserTraitLocusValueExists , userTraitLocusValuesMap , err := getUserTraitLocusValuesMap ( )
if ( err != nil ) {
2024-04-11 15:51:56 +02:00
setErrorEncounteredPage ( window , err , previousPage )
return
}
2024-06-05 06:10:35 +02:00
//Outputs:
// -bool: Any offspring probability of passing rule is known
// -map[[3]byte]int: Offspring probability of passing rules map
// Map Structure: Rule Identifier -> Probability offspring will pass rule (0-100%)
// -error
getOffspringProbabilityOfPassingRulesMap := func ( ) ( bool , map [ [ 3 ] byte ] int , error ) {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
if ( anyMyLocusValuesExist == false || anyUserTraitLocusValueExists == false ) {
2024-06-05 06:10:35 +02:00
return false , nil , nil
2024-04-11 15:51:56 +02:00
}
2024-08-13 15:25:47 +02:00
anyRulesExist , anyOffspringRulesTested , _ , _ , offspringProbabilityOfPassingRulesMap , _ , err := createCoupleGeneticAnalysis . GetOffspringDiscreteTraitAnalysis_Rules ( traitObject , myLocusValuesMap , userTraitLocusValuesMap )
2024-06-05 06:10:35 +02:00
if ( err != nil ) { return false , nil , err }
2024-07-19 19:16:28 +02:00
if ( anyRulesExist == false ) {
2024-08-13 15:25:47 +02:00
return false , nil , errors . New ( "GetOffspringDiscreteTraitAnalysis_Rules claiming no trait rules exist when we already checked." )
2024-07-19 19:16:28 +02:00
}
2024-06-05 06:10:35 +02:00
if ( anyOffspringRulesTested == false ) {
return false , nil , nil
}
2024-04-11 15:51:56 +02:00
2024-06-05 06:10:35 +02:00
return true , offspringProbabilityOfPassingRulesMap , nil
2024-04-11 15:51:56 +02:00
}
2024-06-05 06:10:35 +02:00
anyOffspringProbabilityOfPassingRuleIsKnown , offspringProbabilityOfPassingRulesMap , err := getOffspringProbabilityOfPassingRulesMap ( )
if ( err != nil ) {
2024-04-11 15:51:56 +02:00
setErrorEncounteredPage ( window , err , previousPage )
return
}
2024-06-05 06:10:35 +02:00
getNumberOfRulesTested := func ( ) ( int , error ) {
2024-04-11 15:51:56 +02:00
2024-06-05 06:10:35 +02:00
if ( userOrOffspring == "Offspring" ) {
if ( anyOffspringProbabilityOfPassingRuleIsKnown == false ) {
return 0 , nil
}
2024-04-11 15:51:56 +02:00
2024-06-05 06:10:35 +02:00
numberOfRulesTested := len ( offspringProbabilityOfPassingRulesMap )
2024-04-11 15:51:56 +02:00
2024-06-05 06:10:35 +02:00
return numberOfRulesTested , nil
}
2024-06-07 02:04:13 +02:00
if ( anyUserTraitLocusValueExists == false ) {
return 0 , nil
}
2024-06-05 06:10:35 +02:00
2024-04-11 15:51:56 +02:00
numberOfRulesTested := 0
for _ , ruleObject := range traitRulesList {
ruleLociList := ruleObject . LociList
2024-07-19 19:16:28 +02:00
ruleStatusIsKnown , _ , err := createPersonGeneticAnalysis . GetGenomePassesDiscreteTraitRuleStatus ( ruleLociList , userTraitLocusValuesMap , true )
2024-06-05 06:10:35 +02:00
if ( err != nil ) { return 0 , err }
if ( ruleStatusIsKnown == true ) {
numberOfRulesTested += 1
2024-04-11 15:51:56 +02:00
}
}
return numberOfRulesTested , nil
}
numberOfRulesTested , err := getNumberOfRulesTested ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
rulesTestedLabel := widget . NewLabel ( "Rules Tested:" )
2024-06-05 06:10:35 +02:00
totalNumberOfTraitRules := len ( traitRulesList )
2024-04-11 15:51:56 +02:00
numberOfRulesTestedString := helpers . ConvertIntToString ( numberOfRulesTested )
totalNumberOfTraitRulesString := helpers . ConvertIntToString ( totalNumberOfTraitRules )
numberOfRulesTestedFormatted := numberOfRulesTestedString + "/" + totalNumberOfTraitRulesString
numberOfRulesTestedLabel := getBoldLabel ( numberOfRulesTestedFormatted )
numberOfRulesTestedHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
if ( userOrOffspring == "User" ) {
2024-07-19 19:16:28 +02:00
setDiscreteTraitQuantityOfRulesTestedExplainerPage ( window , currentPage )
2024-04-11 15:51:56 +02:00
} else {
2024-07-19 19:16:28 +02:00
setOffspringDiscreteTraitQuantityOfRulesTestedExplainerPage ( window , currentPage )
2024-04-11 15:51:56 +02:00
}
} )
numberOfRulesTestedRow := container . NewHBox ( layout . NewSpacer ( ) , rulesTestedLabel , numberOfRulesTestedLabel , numberOfRulesTestedHelpButton , layout . NewSpacer ( ) )
getRulesGrid := func ( ) ( * fyne . Container , error ) {
//TODO: Sort results
viewRuleInfoButtonsColumn := container . NewVBox ( )
ruleIdentifierColumn := container . NewVBox ( )
ruleEffectsColumn := container . NewVBox ( )
userPassesRuleColumn := container . NewVBox ( )
offspringProbabilityOfPassingRuleColumn := container . NewVBox ( )
if ( userOrOffspring == "Offspring" ) {
// We need this because the header row is 2 rows tall when userOrOffspring == "Offspring"
// Otherwise, it is 1 row tall
emptyLabelA := widget . NewLabel ( "" )
emptyLabelB := widget . NewLabel ( "" )
emptyLabelC := widget . NewLabel ( "" )
emptyLabelD := widget . NewLabel ( "" )
viewRuleInfoButtonsColumn . Add ( emptyLabelA )
ruleIdentifierColumn . Add ( emptyLabelB )
ruleEffectsColumn . Add ( emptyLabelC )
userPassesRuleColumn . Add ( emptyLabelD )
}
offspringProbabilityOfTitle := getItalicLabelCentered ( "Offspring Probability Of" )
offspringProbabilityOfPassingRuleColumn . Add ( offspringProbabilityOfTitle )
emptyLabelE := widget . NewLabel ( "" )
ruleIdentifierTitle := getItalicLabelCentered ( "Rule Identifier" )
ruleEffectsTitle := getItalicLabelCentered ( "Rule Effects" )
userPassesRuleTitle := getItalicLabelCentered ( "User Passes Rule" )
passingRuleTitle := getItalicLabelCentered ( "Passing Rule" )
viewRuleInfoButtonsColumn . Add ( emptyLabelE )
ruleIdentifierColumn . Add ( ruleIdentifierTitle )
ruleEffectsColumn . Add ( ruleEffectsTitle )
userPassesRuleColumn . Add ( userPassesRuleTitle )
offspringProbabilityOfPassingRuleColumn . Add ( passingRuleTitle )
viewRuleInfoButtonsColumn . Add ( widget . NewSeparator ( ) )
ruleIdentifierColumn . Add ( widget . NewSeparator ( ) )
ruleEffectsColumn . Add ( widget . NewSeparator ( ) )
userPassesRuleColumn . Add ( widget . NewSeparator ( ) )
offspringProbabilityOfPassingRuleColumn . Add ( widget . NewSeparator ( ) )
for _ , ruleObject := range traitRulesList {
2024-06-05 06:10:35 +02:00
ruleIdentifierHex := ruleObject . RuleIdentifier
ruleIdentifier , err := encoding . DecodeHexStringTo3ByteArray ( ruleIdentifierHex )
if ( err != nil ) { return nil , err }
2024-04-11 15:51:56 +02:00
ruleLociList := ruleObject . LociList
getUserPassesRuleString := func ( ) ( string , error ) {
2024-07-19 19:16:28 +02:00
userRuleStatusIsKnown , userPassesRule , err := createPersonGeneticAnalysis . GetGenomePassesDiscreteTraitRuleStatus ( ruleLociList , userTraitLocusValuesMap , true )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return "" , err }
if ( userRuleStatusIsKnown == false ) {
result := translate ( "Unknown" )
return result , nil
}
userPassesRuleString := helpers . ConvertBoolToYesOrNoString ( userPassesRule )
userPassesRuleTranslated := translate ( userPassesRuleString )
return userPassesRuleTranslated , nil
}
userPassesRuleString , err := getUserPassesRuleString ( )
if ( err != nil ) { return nil , err }
getOffspringProbabilityOfPassingRuleString := func ( ) ( string , error ) {
2024-06-05 06:10:35 +02:00
if ( anyOffspringProbabilityOfPassingRuleIsKnown == false ) {
result := translate ( "Unknown" )
return result , nil
}
probabilityOfPassingRule , probabilityIsKnown := offspringProbabilityOfPassingRulesMap [ ruleIdentifier ]
2024-04-11 15:51:56 +02:00
if ( probabilityIsKnown == false ) {
result := translate ( "Unknown" )
return result , nil
}
2024-06-05 06:10:35 +02:00
2024-04-11 15:51:56 +02:00
ruleProbabilityString := helpers . ConvertIntToString ( probabilityOfPassingRule )
ruleProbabilityFormatted := ruleProbabilityString + "%"
return ruleProbabilityFormatted , nil
}
offspringProbabilityOfPassingRuleString , err := getOffspringProbabilityOfPassingRuleString ( )
if ( err != nil ) { return nil , err }
// We add all of the columns except for the rule effects column
// We do this because the rule effects column may be multiple rows tall
viewRuleInfoButton := widget . NewButtonWithIcon ( "" , theme . InfoIcon ( ) , func ( ) {
2024-07-19 19:16:28 +02:00
setViewDiscreteTraitRuleDetailsPage ( window , traitName , ruleIdentifierHex , currentPage )
2024-04-11 15:51:56 +02:00
} )
2024-06-05 06:10:35 +02:00
ruleIdentifierLabel := getBoldLabelCentered ( ruleIdentifierHex )
2024-04-11 15:51:56 +02:00
userPassesRuleLabel := getBoldLabelCentered ( userPassesRuleString )
offspringProbabilityOfPassingRuleLabel := getBoldLabelCentered ( offspringProbabilityOfPassingRuleString )
viewRuleInfoButtonsColumn . Add ( viewRuleInfoButton )
ruleIdentifierColumn . Add ( ruleIdentifierLabel )
userPassesRuleColumn . Add ( userPassesRuleLabel )
offspringProbabilityOfPassingRuleColumn . Add ( offspringProbabilityOfPassingRuleLabel )
traitOutcomesList := traitObject . OutcomesList
ruleOutcomePointsMap := ruleObject . OutcomePointsMap
// We have to sort the outcome names so they always show up in the same order
outcomeNamesListSorted := helpers . CopyAndSortStringListToUnicodeOrder ( traitOutcomesList )
addedOutcomes := 0
for _ , outcomeName := range outcomeNamesListSorted {
outcomeChange , exists := ruleOutcomePointsMap [ outcomeName ]
if ( exists == false ) {
// This rule does not effect this outcome. Skip
continue
}
getOutcomeEffectString := func ( ) string {
outcomeChangeString := helpers . ConvertIntToString ( outcomeChange )
if ( outcomeChange < 0 ) {
return outcomeChangeString
}
outcomeEffect := "+" + outcomeChangeString
return outcomeEffect
}
outcomeEffect := getOutcomeEffectString ( )
outcomeRow := getBoldLabelCentered ( outcomeName + ": " + outcomeEffect )
ruleEffectsColumn . Add ( outcomeRow )
if ( addedOutcomes > 0 ) {
emptyLabelA := widget . NewLabel ( "" )
emptyLabelB := widget . NewLabel ( "" )
emptyLabelC := widget . NewLabel ( "" )
emptyLabelD := widget . NewLabel ( "" )
viewRuleInfoButtonsColumn . Add ( emptyLabelA )
ruleIdentifierColumn . Add ( emptyLabelB )
userPassesRuleColumn . Add ( emptyLabelC )
offspringProbabilityOfPassingRuleColumn . Add ( emptyLabelD )
}
addedOutcomes += 1
}
viewRuleInfoButtonsColumn . Add ( widget . NewSeparator ( ) )
ruleIdentifierColumn . Add ( widget . NewSeparator ( ) )
ruleEffectsColumn . Add ( widget . NewSeparator ( ) )
userPassesRuleColumn . Add ( widget . NewSeparator ( ) )
offspringProbabilityOfPassingRuleColumn . Add ( widget . NewSeparator ( ) )
}
ruleEffectsHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
2024-07-19 19:16:28 +02:00
setDiscreteTraitRuleOutcomeEffectsExplainerPage ( window , currentPage )
2024-04-11 15:51:56 +02:00
} )
userPassesRuleHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
2024-07-19 19:16:28 +02:00
setPersonPassesDiscreteTraitRuleExplainerPage ( window , currentPage )
2024-04-11 15:51:56 +02:00
} )
offspringProbabilityOfPassingRuleHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setOffspringProbabilityOfPassingTraitRuleExplainerPage ( window , currentPage )
} )
ruleEffectsColumn . Add ( ruleEffectsHelpButton )
userPassesRuleColumn . Add ( userPassesRuleHelpButton )
offspringProbabilityOfPassingRuleColumn . Add ( offspringProbabilityOfPassingRuleHelpButton )
if ( userOrOffspring == "User" ) {
rulesGrid := container . NewHBox ( layout . NewSpacer ( ) , viewRuleInfoButtonsColumn , ruleIdentifierColumn , ruleEffectsColumn , userPassesRuleColumn , layout . NewSpacer ( ) )
return rulesGrid , nil
}
rulesGrid := container . NewHBox ( layout . NewSpacer ( ) , viewRuleInfoButtonsColumn , ruleIdentifierColumn , ruleEffectsColumn , offspringProbabilityOfPassingRuleColumn , layout . NewSpacer ( ) )
return rulesGrid , nil
}
rulesGrid , err := getRulesGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , traitNameRow , numberOfRulesTestedRow , widget . NewSeparator ( ) , rulesGrid )
setPageContent ( page , window )
}
2024-08-09 16:23:37 +02:00
func setViewMateProfilePage_NumericGeneticTraits ( window fyne . Window , userOrOffspring string , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
if ( userOrOffspring != "User" && userOrOffspring != "Offspring" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMateProfilePage_NumericGeneticTraits called with invalid userOrOffspring: " + userOrOffspring ) , previousPage )
return
}
if ( userOrOffspring == "Offspring" ) {
setLoadingScreen ( window , "View Profile - Physical" , "Computing Genetic Analysis..." )
}
2024-08-13 15:25:47 +02:00
currentPage := func ( ) { setViewMateProfilePage_NumericGeneticTraits ( window , userOrOffspring , getAnyUserProfileAttributeFunction , previousPage ) }
2024-08-09 16:23:37 +02:00
title := getPageTitleCentered ( translate ( "View Profile - Physical" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Numeric Genetic Traits" ) )
description1 := getLabelCentered ( "Below is the numeric genetic trait analysis for this user." )
description2 := getLabelCentered ( "You can choose to view the analysis of the user or an offspring between you and the user." )
description3 := getLabelCentered ( "You must link your genome person in the Build Profile menu to see offspring information." )
handleSelectButton := func ( newUserOrOffspring string ) {
if ( userOrOffspring == newUserOrOffspring ) {
return
}
setViewMateProfilePage_NumericGeneticTraits ( window , newUserOrOffspring , getAnyUserProfileAttributeFunction , previousPage )
}
userOrOffspringSelector := widget . NewSelect ( [ ] string { "User" , "Offspring" } , handleSelectButton )
userOrOffspringSelector . Selected = userOrOffspring
userOrOffspringSelectorCentered := getWidgetCentered ( userOrOffspringSelector )
getTraitsInfoGrid := func ( ) ( * fyne . Container , error ) {
//Outputs:
// -map[int64]locusValue.LocusValue
// -error
getMyGenomeLocusValuesMap := func ( ) ( map [ int64 ] locusValue . LocusValue , error ) {
2024-08-13 15:25:47 +02:00
if ( userOrOffspring == "User" ) {
// We don't need to retrieve our locus values map
emptyMap := make ( map [ int64 ] locusValue . LocusValue )
return emptyMap , nil
}
myPersonChosen , myGenomesExist , myAnalysisIsReady , myAnalysisObject , myGenomeIdentifier , _ , err := myChosenAnalysis . GetMyChosenMateGeneticAnalysis ( )
if ( err != nil ) { return nil , err }
2024-08-09 16:23:37 +02:00
if ( myPersonChosen == false || myGenomesExist == false || myAnalysisIsReady == false ) {
emptyMap := make ( map [ int64 ] locusValue . LocusValue )
return emptyMap , nil
}
_ , _ , _ , _ , myGenomesMap , err := readGeneticAnalysis . GetMetadataFromPersonGeneticAnalysis ( myAnalysisObject )
if ( err != nil ) { return nil , err }
myGenomeLocusValuesMap , exists := myGenomesMap [ myGenomeIdentifier ]
if ( exists == false ) {
return nil , errors . New ( "GetMyChosenMateGeneticAnalysis returning analysis which is missing genome with myGenomeIdentifier." )
}
return myGenomeLocusValuesMap , nil
}
myGenomeLocusValuesMap , err := getMyGenomeLocusValuesMap ( )
if ( err != nil ) { return nil , err }
traitNameLabel := getItalicLabelCentered ( "Trait Name" )
userPredictedOutcomeTitle := getItalicLabelCentered ( "User Predicted Outcome" )
offspringPredictedOutcomeTitle := getItalicLabelCentered ( "Offspring Predicted Outcome" )
confidenceRangeTitle := getItalicLabelCentered ( "Confidence Range" )
2024-08-13 15:25:47 +02:00
emptyLabel1 := widget . NewLabel ( "" )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
emptyLabel2 := widget . NewLabel ( "" )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
traitNameColumn := container . NewVBox ( traitNameLabel , widget . NewSeparator ( ) )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
userPredictedOutcomeColumn := container . NewVBox ( userPredictedOutcomeTitle , widget . NewSeparator ( ) )
offspringPredictedOutcomeColumn := container . NewVBox ( offspringPredictedOutcomeTitle , widget . NewSeparator ( ) )
predictionConfidenceRangeColumn := container . NewVBox ( confidenceRangeTitle , widget . NewSeparator ( ) )
viewSampleOffspringsButtonsColumn := container . NewVBox ( emptyLabel1 , widget . NewSeparator ( ) )
viewTraitDetailsButtonsColumn := container . NewVBox ( emptyLabel2 , widget . NewSeparator ( ) )
getConfidenceRangeLabel := func ( traitObject traits . Trait , analysisExists bool , predictionConfidenceRangesMap map [ int ] float64 ) ( fyne . Widget , error ) {
if ( analysisExists == false ) {
result := widget . NewLabel ( "Unknown" )
return result , nil
}
// This is a list of the percentage accuracies in the map
// For example: 80% == The distance from the prediction you must travel for 80% of the predictions to be
// accurate within that range
confidenceRangePercentagesList := helpers . GetListOfMapKeys ( predictionConfidenceRangesMap )
// We sort the list so the percentage is always the same upon refreshing the page
slices . Sort ( confidenceRangePercentagesList )
closestToEightyPercentage , err := helpers . GetClosestIntInList ( confidenceRangePercentagesList , 80 )
if ( err != nil ) { return nil , err }
closestToEightyPercentageConfidenceDistance , exists := predictionConfidenceRangesMap [ closestToEightyPercentage ]
if ( exists == false ) {
return nil , errors . New ( "GetListOfMapKeys returning list of elements which contains element which is not in the map." )
}
outcomeFormatter := traitObject . NumericValueFormatter
closestConfidenceDistanceString , err := outcomeFormatter ( closestToEightyPercentageConfidenceDistance , false )
if ( err != nil ) { return nil , err }
closestToEightyPercentageString := helpers . ConvertIntToString ( closestToEightyPercentage )
confidenceRangeLabelValueFormatted := "+/- " + closestConfidenceDistanceString + " (" + closestToEightyPercentageString + "%)"
confidenceRangeLabel := getBoldLabel ( confidenceRangeLabelValueFormatted )
return confidenceRangeLabel , nil
}
2024-08-09 16:23:37 +02:00
traitObjectsList , err := traits . GetTraitObjectsList ( )
if ( err != nil ) { return nil , err }
for _ , traitObject := range traitObjectsList {
traitName := traitObject . TraitName
2024-08-13 15:25:47 +02:00
2024-08-09 16:23:37 +02:00
traitIsDiscreteOrNumeric := traitObject . DiscreteOrNumeric
if ( traitIsDiscreteOrNumeric != "Numeric" ) {
continue
}
traitLociList := traitObject . LociList
numberOfTraitLoci := len ( traitLociList )
if ( numberOfTraitLoci == 0 ) {
// We are not able to analyze these traits
continue
}
2024-08-15 14:14:23 +02:00
traitNeuralNetworkExists := trainedPredictionModels . CheckIfAttributeNeuralNetworkExists ( traitName )
2024-08-09 16:23:37 +02:00
if ( traitNeuralNetworkExists == false ) {
// We are not able to analyze these traits yet
continue
}
traitNameText := getBoldLabelCentered ( translate ( traitName ) )
// We construct the user's trait locus values map
2024-08-14 13:25:25 +02:00
userTraitLocusValuesMap , err := calculatedAttributes . GetUserGenomeLocusValuesMapFromProfile ( traitLociList , getAnyUserProfileAttributeFunction )
if ( err != nil ) { return nil , err }
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
getPredictedOutcomeLabel := func ( analysisExists bool , predictedOutcome float64 ) ( fyne . Widget , error ) {
2024-08-09 16:23:37 +02:00
if ( analysisExists == false ) {
unknownLabel := widget . NewLabel ( "Unknown" )
2024-08-13 15:25:47 +02:00
return unknownLabel , nil
2024-08-09 16:23:37 +02:00
}
2024-08-13 15:25:47 +02:00
outcomeFormatter := traitObject . NumericValueFormatter
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
predictedOutcomeFormatted , err := outcomeFormatter ( predictedOutcome , true )
if ( err != nil ) { return nil , err }
2024-08-09 16:23:37 +02:00
predictedOutcomeLabel := getBoldLabel ( predictedOutcomeFormatted )
2024-08-13 15:25:47 +02:00
return predictedOutcomeLabel , nil
2024-08-09 16:23:37 +02:00
}
2024-08-13 15:25:47 +02:00
if ( userOrOffspring == "User" ) {
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
traitNeuralNetworkExists , anyLocusValuesAreKnown , predictedOutcome , predictionAccuracyRangesMap , _ , _ , err := createPersonGeneticAnalysis . GetGenomeNumericTraitAnalysis ( traitObject , userTraitLocusValuesMap , true )
if ( err != nil ) { return nil , err }
if ( traitNeuralNetworkExists == false ) {
return nil , errors . New ( "GetGenomeNumericTraitAnalysis claims neural network doesn't exist for trait, but we already checked." )
2024-08-09 16:23:37 +02:00
}
2024-08-13 15:25:47 +02:00
predictedOutcomeLabel , err := getPredictedOutcomeLabel ( anyLocusValuesAreKnown , predictedOutcome )
if ( err != nil ) { return nil , err }
predictedOutcomeLabelCentered := getWidgetCentered ( predictedOutcomeLabel )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
userPredictedOutcomeColumn . Add ( predictedOutcomeLabelCentered )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeLabel , err := getConfidenceRangeLabel ( traitObject , anyLocusValuesAreKnown , predictionAccuracyRangesMap )
2024-08-09 16:23:37 +02:00
if ( err != nil ) { return nil , err }
2024-08-13 15:25:47 +02:00
confidenceRangeLabelCentered := getWidgetCentered ( confidenceRangeLabel )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
predictionConfidenceRangeColumn . Add ( confidenceRangeLabelCentered )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
} else {
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
// userOrOffspring == "Offspring"
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
neuralNetworkExists , anyLociKnown , predictedOutcome , predictionAccuracyRangesMap , sampleOffspringOutcomesList , quantityOfLociKnown , _ , err := createCoupleGeneticAnalysis . GetOffspringNumericTraitAnalysis ( traitObject , userTraitLocusValuesMap , myGenomeLocusValuesMap )
if ( err != nil ) { return nil , err }
if ( neuralNetworkExists == false ) {
return nil , errors . New ( "GetOffspringNumericTraitAnalysis claiming that neural network doesn't exist when we already checked." )
}
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
predictedOutcomeLabel , err := getPredictedOutcomeLabel ( anyLociKnown , predictedOutcome )
if ( err != nil ) { return nil , err }
predictedOutcomeLabelCentered := getWidgetCentered ( predictedOutcomeLabel )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
offspringPredictedOutcomeColumn . Add ( predictedOutcomeLabelCentered )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeLabel , err := getConfidenceRangeLabel ( traitObject , anyLociKnown , predictionAccuracyRangesMap )
if ( err != nil ) { return nil , err }
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
confidenceRangeLabelCentered := getWidgetCentered ( confidenceRangeLabel )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
predictionConfidenceRangeColumn . Add ( confidenceRangeLabelCentered )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
viewSampleOffspringsButton := widget . NewButtonWithIcon ( "" , theme . InfoIcon ( ) , func ( ) {
setViewNumericTraitSampleOffspringOutcomesChart ( window , traitName , sampleOffspringOutcomesList , quantityOfLociKnown , currentPage )
} )
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
viewSampleOffspringsButtonsColumn . Add ( viewSampleOffspringsButton )
}
2024-08-09 16:23:37 +02:00
viewTraitDetailsButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
traitNameColumn . Add ( traitNameText )
viewTraitDetailsButtonsColumn . Add ( viewTraitDetailsButton )
traitNameColumn . Add ( widget . NewSeparator ( ) )
userPredictedOutcomeColumn . Add ( widget . NewSeparator ( ) )
offspringPredictedOutcomeColumn . Add ( widget . NewSeparator ( ) )
predictionConfidenceRangeColumn . Add ( widget . NewSeparator ( ) )
2024-08-13 15:25:47 +02:00
viewSampleOffspringsButtonsColumn . Add ( widget . NewSeparator ( ) )
2024-08-09 16:23:37 +02:00
viewTraitDetailsButtonsColumn . Add ( widget . NewSeparator ( ) )
}
2024-08-13 15:25:47 +02:00
predictedOutcomeHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
2024-08-09 16:23:37 +02:00
2024-08-13 15:25:47 +02:00
//TODO
showUnderConstructionDialog ( window )
} )
2024-08-09 16:23:37 +02:00
predictionConfidenceRangeHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
2024-08-13 15:25:47 +02:00
predictionConfidenceRangeColumn . Add ( predictionConfidenceRangeHelpButton )
2024-08-09 16:23:37 +02:00
traitsInfoGrid := container . NewHBox ( layout . NewSpacer ( ) , traitNameColumn )
if ( userOrOffspring == "User" ) {
2024-08-13 15:25:47 +02:00
userPredictedOutcomeColumn . Add ( predictedOutcomeHelpButton )
2024-08-09 16:23:37 +02:00
traitsInfoGrid . Add ( userPredictedOutcomeColumn )
} else {
// userOrOffspring == "Offspring"
2024-08-13 15:25:47 +02:00
offspringPredictedOutcomeColumn . Add ( predictedOutcomeHelpButton )
2024-08-09 16:23:37 +02:00
traitsInfoGrid . Add ( offspringPredictedOutcomeColumn )
}
traitsInfoGrid . Add ( predictionConfidenceRangeColumn )
2024-08-13 15:25:47 +02:00
if ( userOrOffspring == "Offspring" ) {
traitsInfoGrid . Add ( viewSampleOffspringsButtonsColumn )
}
2024-08-09 16:23:37 +02:00
traitsInfoGrid . Add ( viewTraitDetailsButtonsColumn )
traitsInfoGrid . Add ( layout . NewSpacer ( ) )
return traitsInfoGrid , nil
}
traitsInfoGrid , err := getTraitsInfoGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , description3 , widget . NewSeparator ( ) , userOrOffspringSelectorCentered , widget . NewSeparator ( ) , traitsInfoGrid )
setPageContent ( page , window )
}
2024-04-11 15:51:56 +02:00
func setViewMateProfilePage_Diet ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
title := getPageTitleCentered ( translate ( "View Profile - Lifestyle" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( "Diet" )
description := getLabelCentered ( "Below are the user's food ratings." )
foodNameTitle := getItalicLabelCentered ( "Food Name" )
ratingTitle := getItalicLabelCentered ( "Rating" )
foodNameColumn := container . NewVBox ( foodNameTitle , widget . NewSeparator ( ) )
foodRatingColumn := container . NewVBox ( ratingTitle , widget . NewSeparator ( ) )
foodsList := [ ] string { "Fruit" , "Vegetables" , "Nuts" , "Grains" , "Dairy" , "Seafood" , "Beef" , "Pork" , "Poultry" , "Eggs" , "Beans" }
for _ , foodName := range foodsList {
foodAttributeName := foodName + "Rating"
ratingExists , _ , foodRating , err := getAnyUserProfileAttributeFunction ( foodAttributeName )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
foodNameLabel := getBoldLabelCentered ( foodName )
getRatingLabel := func ( ) * fyne . Container {
if ( ratingExists == false ) {
2024-06-07 02:04:13 +02:00
result := getBoldItalicLabelCentered ( translate ( "No Response" ) )
2024-04-11 15:51:56 +02:00
return result
}
result := getBoldLabelCentered ( foodRating + "/10" )
return result
}
ratingLabel := getRatingLabel ( )
foodNameColumn . Add ( foodNameLabel )
foodRatingColumn . Add ( ratingLabel )
foodNameColumn . Add ( widget . NewSeparator ( ) )
foodRatingColumn . Add ( widget . NewSeparator ( ) )
}
foodsGrid := container . NewHBox ( layout . NewSpacer ( ) , foodNameColumn , foodRatingColumn , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , foodsGrid )
setPageContent ( page , window )
}
func setViewMateProfilePage_Language ( window fyne . Window , getAnyUserProfileAttributeFunction func ( string ) ( bool , int , string , error ) , previousPage func ( ) ) {
title := getPageTitleCentered ( translate ( "View Profile - Mental" ) )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( translate ( "Language" ) )
description := getLabelCentered ( "Below describes the language(s) the user can speak." )
userLanguagesExist , _ , userLanguageAttribute , err := getAnyUserProfileAttributeFunction ( "Language" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( userLanguagesExist == false ) {
noLanguagesExistLabel := getBoldLabelCentered ( "This user's profile has no languages listed." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , noLanguagesExistLabel )
setPageContent ( page , window )
return
}
getLanguagesGrid := func ( ) ( * fyne . Container , error ) {
//TODO: Sort by fluency
languageTitle := getItalicLabelCentered ( "Language" )
fluencyTitle := getItalicLabelCentered ( "Fluency" )
languageNameColumn := container . NewVBox ( languageTitle , widget . NewSeparator ( ) )
languageFluencyColumn := container . NewVBox ( fluencyTitle , widget . NewSeparator ( ) )
languageItemsList := strings . Split ( userLanguageAttribute , "+&" )
worldLanguageObjectsMap , err := worldLanguages . GetWorldLanguageObjectsMap ( )
if ( err != nil ) { return nil , err }
for _ , languageItem := range languageItemsList {
languageName , languageRating , delimiterFound := strings . Cut ( languageItem , "$" )
if ( delimiterFound == false ) {
return nil , errors . New ( "setViewMateProfilePage_Language called with profile containing invalid language attribute item: " + languageItem )
}
getLanguageNameFormatted := func ( ) string {
// We only translate if language name is canonical
_ , languageIsCanonical := worldLanguageObjectsMap [ languageName ]
if ( languageIsCanonical == false ) {
return languageName
}
languageNameTranslated := translate ( languageName )
return languageNameTranslated
}
languageNameFormatted := getLanguageNameFormatted ( )
languageFluencyFormatted := languageRating + "/5"
languageNameLabel := getBoldLabelCentered ( languageNameFormatted )
languageFluencyLabel := getBoldLabelCentered ( languageFluencyFormatted )
languageNameColumn . Add ( languageNameLabel )
languageFluencyColumn . Add ( languageFluencyLabel )
languageNameColumn . Add ( widget . NewSeparator ( ) )
languageFluencyColumn . Add ( widget . NewSeparator ( ) )
}
languagesGrid := container . NewHBox ( layout . NewSpacer ( ) , languageNameColumn , languageFluencyColumn , layout . NewSpacer ( ) )
return languagesGrid , nil
}
languagesGrid , err := getLanguagesGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , languagesGrid )
setPageContent ( page , window )
}
// We use this to view an ancestry composition for moderation/comparing profile changes
func setViewUser23andMeAncestryCompositionPage ( window fyne . Window , inputAncestryCompositionAttribute string , previousPage func ( ) ) {
title := getPageTitleCentered ( "Viewing 23andMe Ancestry Composition" )
backButton := getBackButtonCentered ( previousPage )
attributeIsValid , continentPercentagesMap , regionPercentagesMap , subregionPercentagesMap , err := companyAnalysis . ReadAncestryCompositionAttribute_23andMe ( true , inputAncestryCompositionAttribute )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( attributeIsValid == false ) {
setErrorEncounteredPage ( window , errors . New ( "setViewUser23andMeAncestryCompositionPage called with invalid inputAncestryCompositionAttribute" ) , previousPage )
return
}
userCompositionDisplay , err := get23andMeAncestryCompositionDisplay ( continentPercentagesMap , regionPercentagesMap , subregionPercentagesMap )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
header := container . NewVBox ( title , backButton , widget . NewSeparator ( ) )
page := container . NewBorder ( header , nil , nil , nil , userCompositionDisplay )
setPageContent ( page , window )
}
func get23andMeAncestryCompositionDisplay ( inputContinentPercentagesMap map [ string ] float64 , inputRegionPercentagesMap map [ string ] float64 , inputSubregionPercentagesMap map [ string ] float64 ) ( fyne . Widget , error ) {
mapsAreValid , continentPercentagesMap , regionPercentagesMap , subregionPercentagesMap , err := companyAnalysis . AddMissingParentsToAncestryCompositionMaps_23andMe ( inputContinentPercentagesMap , inputRegionPercentagesMap , inputSubregionPercentagesMap )
if ( err != nil ) { return nil , err }
if ( mapsAreValid == false ) {
return nil , errors . New ( "get23andMeAncestryCompositionDisplay called with invalid ancestry location maps." )
}
// This map is used to create a fyne tree widget
// Each item maps to a list of child items
treeMap := make ( map [ string ] [ ] string )
continentsList := make ( [ ] string , 0 , len ( continentPercentagesMap ) )
// Map Structure: Continent Description -> Continent percentage
continentDescriptionPercentagesMap := make ( map [ string ] float64 )
for continentName , continentPercentage := range continentPercentagesMap {
continentPercentageString := helpers . ConvertFloat64ToStringRounded ( continentPercentage , 1 )
continentDescription := continentName + " - " + continentPercentageString + "%"
continentDescriptionPercentagesMap [ continentDescription ] = continentPercentage
continentsList = append ( continentsList , continentDescription )
currentContinentRegionsList := make ( [ ] string , 0 )
allContinentRegionsList , err := companyAnalysis . GetAncestryContinentRegionsList_23andMe ( continentName )
if ( err != nil ) {
return nil , errors . New ( "continentPercentagesMap contains invalid continent." )
}
// Map Structure: Region Description -> Region percentage
regionDescriptionPercentagesMap := make ( map [ string ] float64 )
for regionName , regionPercentage := range regionPercentagesMap {
regionIsRelevant := slices . Contains ( allContinentRegionsList , regionName )
if ( regionIsRelevant == false ) {
continue
}
regionPercentageString := helpers . ConvertFloat64ToStringRounded ( regionPercentage , 1 )
regionDescription := regionName + " - " + regionPercentageString + "%"
regionDescriptionPercentagesMap [ regionDescription ] = regionPercentage
currentContinentRegionsList = append ( currentContinentRegionsList , regionDescription )
allRegionSubregionsList , err := companyAnalysis . GetAncestryRegionSubregionsList_23andMe ( continentName , regionName )
if ( err != nil ) { return nil , err }
currentRegionSubregionsList := make ( [ ] string , 0 , len ( subregionPercentagesMap ) )
// Map Structure: Subregion description -> Subregion percentage
subregionDescriptionPercentagesMap := make ( map [ string ] float64 )
for subregionName , subregionPercentage := range subregionPercentagesMap {
subregionIsRelevant := slices . Contains ( allRegionSubregionsList , subregionName )
if ( subregionIsRelevant == false ) {
continue
}
subregionPercentageString := helpers . ConvertFloat64ToStringRounded ( subregionPercentage , 1 )
subregionDescription := subregionName + " - " + subregionPercentageString + "%"
subregionDescriptionPercentagesMap [ subregionDescription ] = subregionPercentage
currentRegionSubregionsList = append ( currentRegionSubregionsList , subregionDescription )
}
// We sort region subregions list
// We sort them from highest to lowest in percentage.
2024-07-19 19:16:28 +02:00
compareSubregionsFunction := func ( subregion1Description string , subregion2Description string ) int {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
if ( subregion1Description == subregion2Description ) {
2024-04-11 15:51:56 +02:00
panic ( "compareSubregionsFunction called with identical subregion descriptions." )
}
2024-07-19 19:16:28 +02:00
subregion1Percentage , exists := subregionDescriptionPercentagesMap [ subregion1Description ]
2024-04-11 15:51:56 +02:00
if ( exists == false ) {
panic ( "subregionPercentagesMap missing subregion during sort." )
}
2024-07-19 19:16:28 +02:00
subregion2Percentage , exists := subregionDescriptionPercentagesMap [ subregion2Description ]
2024-04-11 15:51:56 +02:00
if ( exists == false ) {
panic ( "subregionPercentagesMap missing subregion during sort." )
}
2024-07-19 19:16:28 +02:00
if ( subregion1Percentage == subregion2Percentage ) {
2024-04-11 15:51:56 +02:00
// We sort subregions in unicode order
2024-07-19 19:16:28 +02:00
if ( subregion1Description < subregion2Description ) {
2024-04-11 15:51:56 +02:00
return - 1
}
return 1
}
2024-07-19 19:16:28 +02:00
if ( subregion1Percentage > subregion2Percentage ) {
2024-04-11 15:51:56 +02:00
return - 1
}
return 1
}
slices . SortFunc ( currentRegionSubregionsList , compareSubregionsFunction )
treeMap [ regionDescription ] = currentRegionSubregionsList
}
// We sort continent regions list by highest to lowest percentage.
2024-07-19 19:16:28 +02:00
compareRegionsFunction := func ( region1Description string , region2Description string ) int {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
if ( region1Description == region2Description ) {
2024-04-11 15:51:56 +02:00
panic ( "compareRegionsFunction called with identical regions." )
}
2024-07-19 19:16:28 +02:00
region1Percentage , exists := regionDescriptionPercentagesMap [ region1Description ]
2024-04-11 15:51:56 +02:00
if ( exists == false ) {
panic ( "regionPercentagesMap missing subregion during sort." )
}
2024-07-19 19:16:28 +02:00
region2Percentage , exists := regionDescriptionPercentagesMap [ region2Description ]
2024-04-11 15:51:56 +02:00
if ( exists == false ) {
panic ( "regionPercentagesMap missing subregion during sort." )
}
2024-07-19 19:16:28 +02:00
if ( region1Percentage == region2Percentage ) {
2024-04-11 15:51:56 +02:00
// We sort regions in unicode order
2024-07-19 19:16:28 +02:00
if ( region1Description < region2Description ) {
2024-04-11 15:51:56 +02:00
return - 1
}
return 1
}
2024-07-19 19:16:28 +02:00
if ( region1Percentage > region2Percentage ) {
2024-04-11 15:51:56 +02:00
return - 1
}
2024-07-19 19:16:28 +02:00
2024-04-11 15:51:56 +02:00
return 1
}
slices . SortFunc ( currentContinentRegionsList , compareRegionsFunction )
treeMap [ continentDescription ] = currentContinentRegionsList
}
// We sort root list by highest to lowest proportions
2024-07-19 19:16:28 +02:00
compareContinentsFunction := func ( continent1Description string , continent2Description string ) int {
2024-04-11 15:51:56 +02:00
2024-07-19 19:16:28 +02:00
if ( continent1Description == continent2Description ) {
2024-04-11 15:51:56 +02:00
panic ( "compareContinentsFunction called with identical continents." )
}
2024-07-19 19:16:28 +02:00
continent1Percentage , exists := continentDescriptionPercentagesMap [ continent1Description ]
2024-04-11 15:51:56 +02:00
if ( exists == false ) {
panic ( "Continent percentage not found when sorting root list." )
}
2024-07-19 19:16:28 +02:00
continent2Percentage , exists := continentDescriptionPercentagesMap [ continent2Description ]
2024-04-11 15:51:56 +02:00
if ( exists == false ) {
panic ( "Continent percentage not found when sorting root list." )
}
2024-07-19 19:16:28 +02:00
if ( continent1Percentage == continent2Percentage ) {
2024-04-11 15:51:56 +02:00
// We sort continents in unicode order
2024-07-19 19:16:28 +02:00
if ( continent1Description < continent2Description ) {
2024-04-11 15:51:56 +02:00
return - 1
}
return 1
}
2024-07-19 19:16:28 +02:00
if ( continent1Percentage > continent2Percentage ) {
2024-04-11 15:51:56 +02:00
return - 1
}
return 1
}
slices . SortFunc ( continentsList , compareContinentsFunction )
treeMap [ "" ] = continentsList
resultTree := widget . NewTreeWithStrings ( treeMap )
resultTree . OpenAllBranches ( )
return resultTree , nil
}