1822 lines
66 KiB
Go
1822 lines
66 KiB
Go
|
|
||
|
package gui
|
||
|
|
||
|
// manageGeneticsGui.go implements the pages to manage genome people/couples, and to create genetic analyses
|
||
|
// viewAnalysisGui_Person.go and viewAnalysisGui_Couple.go implement the code to view genetic analyses
|
||
|
|
||
|
import "fyne.io/fyne/v2"
|
||
|
import "fyne.io/fyne/v2/widget"
|
||
|
import "fyne.io/fyne/v2/theme"
|
||
|
import "fyne.io/fyne/v2/container"
|
||
|
import "fyne.io/fyne/v2/layout"
|
||
|
import "fyne.io/fyne/v2/dialog"
|
||
|
import "fyne.io/fyne/v2/data/binding"
|
||
|
|
||
|
import "seekia/internal/genetics/myGenomes"
|
||
|
import "seekia/internal/genetics/myPeople"
|
||
|
import "seekia/internal/genetics/myCouples"
|
||
|
import "seekia/internal/genetics/myAnalyses"
|
||
|
import "seekia/internal/genetics/readRawGenomes"
|
||
|
import "seekia/internal/genetics/sampleAnalyses"
|
||
|
import "seekia/internal/helpers"
|
||
|
import "seekia/internal/appMemory"
|
||
|
import "seekia/internal/localFilesystem"
|
||
|
|
||
|
import "time"
|
||
|
import "strings"
|
||
|
import "errors"
|
||
|
|
||
|
func setGeneticsPage(window fyne.Window){
|
||
|
|
||
|
currentPage := func(){setGeneticsPage(window)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics")
|
||
|
|
||
|
description1 := getLabelCentered("Seekia provides tools to analyze genomes.")
|
||
|
description2 := getLabelCentered("You can import raw genome files from multiple sequencing companies.")
|
||
|
description3 := getLabelCentered("You can share your genome information on your profile.")
|
||
|
description4 := getLabelCentered("When an analysis is created, the genomes are never sent or shared anywhere.")
|
||
|
|
||
|
managePeopleIcon, err := getFyneImageIcon("Person")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
managePeopleButton := widget.NewButton("Manage People", func(){
|
||
|
setManageGenomePeoplePage(window, currentPage)
|
||
|
})
|
||
|
managePeopleButtonWithIcon := container.NewGridWithColumns(1, managePeopleIcon, managePeopleButton)
|
||
|
|
||
|
analyzeCoupleIcon, err := getFyneImageIcon("Couple")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
analyzeCoupleButton := widget.NewButton("Analyze Couple", func(){
|
||
|
setManageCouplesPage(window, currentPage)
|
||
|
})
|
||
|
analyzeCoupleButtonWithIcon := container.NewGridWithColumns(1, analyzeCoupleIcon, analyzeCoupleButton)
|
||
|
|
||
|
buttonsRow := container.NewHBox(layout.NewSpacer(), managePeopleButtonWithIcon, analyzeCoupleButtonWithIcon, layout.NewSpacer())
|
||
|
|
||
|
viewSampleAnalysesIcon, err := getFyneImageIcon("Questionnaire")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, func(){setHomePage(window)})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
viewSampleAnalysesButton := widget.NewButton("View Sample Analyses", func(){setViewSampleGeneticAnalysesPage(window, currentPage)})
|
||
|
viewSampleAnalysesButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, viewSampleAnalysesIcon, viewSampleAnalysesButton))
|
||
|
|
||
|
page := container.NewVBox(title, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), buttonsRow, widget.NewSeparator(), viewSampleAnalysesButtonWithIcon)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setViewSampleGeneticAnalysesPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setViewSampleGeneticAnalysesPage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - View Sample Analyses")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Seekia can create genetic analyses from imported genome files.")
|
||
|
description2 := getLabelCentered("You can view example analyses on the pages below.")
|
||
|
|
||
|
personIcon, err := getFyneImageIcon("Person")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personAnalysisButton := widget.NewButton("Person Analysis", func(){
|
||
|
|
||
|
personIdentifier := "111111111111111111111111111111"
|
||
|
|
||
|
analysisMapList, err := sampleAnalyses.GetSamplePerson1Analysis()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setViewPersonGeneticAnalysisPage(window, personIdentifier, analysisMapList, 1, currentPage)
|
||
|
})
|
||
|
|
||
|
personAnalysisButtonWithIcon := container.NewGridWithColumns(1, personIcon, personAnalysisButton)
|
||
|
|
||
|
coupleIcon, err := getFyneImageIcon("Couple")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
coupleAnalysisButton := widget.NewButton("Couple Analysis", func(){
|
||
|
|
||
|
personAIdentifier := "111111111111111111111111111111"
|
||
|
personBIdentifier := "222222222222222222222222222222"
|
||
|
|
||
|
person1AnalysisMapList, err := sampleAnalyses.GetSamplePerson1Analysis()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
person2AnalysisMapList, err := sampleAnalyses.GetSamplePerson2Analysis()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
coupleAnalysisMapList, err := sampleAnalyses.GetSampleCoupleAnalysis()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setViewCoupleGeneticAnalysisPage(window, personAIdentifier, personBIdentifier, person1AnalysisMapList, person2AnalysisMapList, coupleAnalysisMapList, 1, 1, currentPage)
|
||
|
})
|
||
|
|
||
|
coupleAnalysisButtonWithIcon := container.NewGridWithColumns(1, coupleIcon, coupleAnalysisButton)
|
||
|
|
||
|
buttonsRow := container.NewHBox(layout.NewSpacer(), personAnalysisButtonWithIcon, coupleAnalysisButtonWithIcon, layout.NewSpacer())
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), buttonsRow)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setManageGenomePeoplePage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManageGenomePeoplePage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Manage People")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("A Person is used to organize genome files.")
|
||
|
description2 := getLabelCentered("You can import multiple genome files for the same person.")
|
||
|
|
||
|
createPersonButton := getWidgetCentered(widget.NewButtonWithIcon("Create Person", theme.ContentAddIcon(), func(){
|
||
|
setCreateGenomePersonPage(window, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
getPeopleContainer := func()(*fyne.Container, error){
|
||
|
|
||
|
peopleMapList, err := myPeople.GetMyGenomePeopleMapList()
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
if (len(peopleMapList) == 0){
|
||
|
|
||
|
noPeopleExistDescription := getBoldLabelCentered("No people found.")
|
||
|
return noPeopleExistDescription, nil
|
||
|
}
|
||
|
|
||
|
myPeopleLabel := getItalicLabelCentered("My People:")
|
||
|
|
||
|
manageButtonsGrid := container.NewGridWithColumns(1)
|
||
|
|
||
|
for _, personMap := range peopleMapList{
|
||
|
|
||
|
personNameString, exists := personMap["PersonName"]
|
||
|
if (exists == false) {
|
||
|
return nil, errors.New("Malformed GenomePeople map list: Item missing PersonName.")
|
||
|
}
|
||
|
|
||
|
personIdentifier, exists := personMap["PersonIdentifier"]
|
||
|
if (exists == false) {
|
||
|
return nil, errors.New("Malformed GenomePeople map list: Item missing PersonIdentifier.")
|
||
|
}
|
||
|
|
||
|
personNameTrimmed, _, err := helpers.TrimAndFlattenString(personNameString, 15)
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
managePersonButton := widget.NewButton(personNameTrimmed, func(){
|
||
|
setManageGenomePersonPage(window, personIdentifier, currentPage)
|
||
|
})
|
||
|
|
||
|
manageButtonsGrid.Add(managePersonButton)
|
||
|
}
|
||
|
|
||
|
buttonsGridCentered := getContainerCentered(manageButtonsGrid)
|
||
|
peopleContainer := container.NewVBox(myPeopleLabel, buttonsGridCentered)
|
||
|
|
||
|
return peopleContainer, nil
|
||
|
}
|
||
|
|
||
|
peopleContainer, err := getPeopleContainer()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), createPersonButton, widget.NewSeparator(), peopleContainer)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
func setCreateGenomePersonPage(window fyne.Window, previousPage func(), nextPage func()){
|
||
|
|
||
|
currentPage := func(){setCreateGenomePersonPage(window, previousPage, nextPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Genetics - Create Person"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Create a Person to manage genome files.")
|
||
|
|
||
|
enterNameDescription := getBoldLabelCentered("Enter Person Name:")
|
||
|
|
||
|
enterNameEntry := widget.NewEntry()
|
||
|
enterNameEntry.SetPlaceHolder(translate("Enter Name..."))
|
||
|
enterNameEntryBoxed := getWidgetBoxed(enterNameEntry)
|
||
|
|
||
|
enterNameDescriptionWithEntry := getContainerCentered(container.NewGridWithColumns(1, enterNameDescription, enterNameEntryBoxed))
|
||
|
|
||
|
option1Translated := translate("Male")
|
||
|
option2Translated := translate("Female")
|
||
|
option3Translated := translate("Intersex")
|
||
|
|
||
|
untranslatedOptionsMap := map[string]string{
|
||
|
option1Translated: "Male",
|
||
|
option2Translated: "Female",
|
||
|
option3Translated: "Intersex",
|
||
|
}
|
||
|
|
||
|
sexSelectorOptions := []string{option1Translated, option2Translated, option3Translated}
|
||
|
|
||
|
selectSexLabel := getBoldLabelCentered(translate("Select Sex:"))
|
||
|
sexSelector := widget.NewSelect(sexSelectorOptions, nil)
|
||
|
sexSelector.SetSelectedIndex(0)
|
||
|
sexSelectorCentered := getWidgetCentered(sexSelector)
|
||
|
|
||
|
createPersonButton := getWidgetCentered(widget.NewButtonWithIcon("Create Person", theme.ConfirmIcon(), func(){
|
||
|
|
||
|
newPersonName := enterNameEntry.Text
|
||
|
if (newPersonName == ""){
|
||
|
dialogTitle := translate("Missing Person Name.")
|
||
|
dialogMessageA := getLabelCentered("You must enter a name for this person.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
if (len(newPersonName) > 40){
|
||
|
dialogTitle := translate("Name Is Too Long.")
|
||
|
dialogMessageA := getLabelCentered("You must enter a name that is less than 40 characters.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personSexTranslated := sexSelector.Selected
|
||
|
|
||
|
personSex, exists := untranslatedOptionsMap[personSexTranslated]
|
||
|
if (exists == false) {
|
||
|
setErrorEncounteredPage(window, errors.New("untranslatedOptionsMap missing personSexTranslated: " + personSexTranslated), currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
duplicateNameExists, err := myPeople.AddPerson(newPersonName, personSex)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (duplicateNameExists == true){
|
||
|
dialogTitle := translate("Invalid Person Name.")
|
||
|
dialogMessageA := getLabelCentered("A Person with this name already exists.")
|
||
|
dialogMessageB := getLabelCentered("Enter a different name for the Person.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
nextPage()
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, widget.NewSeparator(), enterNameDescriptionWithEntry, selectSexLabel, sexSelectorCentered, createPersonButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
// This is a page to manage a genome Person
|
||
|
func setManageGenomePersonPage(window fyne.Window, personIdentifier string, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManageGenomePersonPage(window, personIdentifier, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Manage Person")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
personFound, personName, _, personSex, err := myPeople.GetPersonInfo(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setManageGenomePersonPage called with missing personIdentifier"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personNameLabel := getLabelCentered("Person Name:")
|
||
|
personNameText := getBoldLabelCentered(personName)
|
||
|
|
||
|
personSexLabel := getLabelCentered("Person Sex:")
|
||
|
personSexText := getBoldLabelCentered(personSex)
|
||
|
|
||
|
analyzeIcon, err := getFyneImageIcon("Stats")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
analyzeGeneticsButton := widget.NewButton("Analyze Genetics", func(){
|
||
|
setAnalyzePersonGeneticsPage(window, personIdentifier, currentPage)
|
||
|
})
|
||
|
analyzeGeneticsButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, analyzeIcon, analyzeGeneticsButton))
|
||
|
|
||
|
genomesIcon, err := getFyneImageIcon("Genome")
|
||
|
manageGenomesButton := widget.NewButton("Manage Genomes", func(){
|
||
|
setManagePersonGenomesPage(window, personIdentifier, currentPage)
|
||
|
})
|
||
|
manageGenomesButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, genomesIcon, manageGenomesButton))
|
||
|
|
||
|
renamePersonButton := widget.NewButtonWithIcon("Rename", theme.DocumentCreateIcon(), func(){
|
||
|
setRenameGenomePersonPage(window, personIdentifier, currentPage, currentPage)
|
||
|
})
|
||
|
changeSexButton := widget.NewButtonWithIcon("Change Sex", theme.DocumentCreateIcon(), func(){
|
||
|
//TODO
|
||
|
showUnderConstructionDialog(window)
|
||
|
})
|
||
|
deletePersonButton := widget.NewButtonWithIcon("Delete", theme.DeleteIcon(), func(){
|
||
|
setDeleteGenomePersonPage(window, personIdentifier, currentPage, previousPage)
|
||
|
})
|
||
|
|
||
|
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, renamePersonButton, changeSexButton, deletePersonButton))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), personNameLabel, personNameText, widget.NewSeparator(), personSexLabel, personSexText, widget.NewSeparator(), analyzeGeneticsButtonWithIcon, manageGenomesButtonWithIcon, widget.NewSeparator(), buttonsGrid)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setRenameGenomePersonPage(window fyne.Window, personIdentifier string, previousPage func(), nextPage func()){
|
||
|
|
||
|
currentPage := func(){setRenameGenomePersonPage(window, personIdentifier, previousPage, nextPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Rename Person")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
subtitle := getPageSubtitleCentered("Rename Person")
|
||
|
|
||
|
personFound, personName, _, personSex, err := myPeople.GetPersonInfo(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setRenameGenomePersonPage called with person who does not exist."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
currentNameLabel := widget.NewLabel("Current Name:")
|
||
|
currentNameText := getBoldLabel(personName)
|
||
|
|
||
|
currentNameRow := container.NewHBox(layout.NewSpacer(), currentNameLabel, currentNameText, layout.NewSpacer())
|
||
|
|
||
|
enterNameDescription := widget.NewLabel("Enter new name:")
|
||
|
|
||
|
newNameEntry := widget.NewEntry()
|
||
|
newNameEntry.SetPlaceHolder("Enter name...")
|
||
|
|
||
|
enterNameEntryWithDescription := getContainerCentered(container.NewGridWithColumns(1, enterNameDescription, newNameEntry))
|
||
|
|
||
|
renameButton := getWidgetCentered(widget.NewButtonWithIcon("Rename", theme.ConfirmIcon(), func(){
|
||
|
newName := newNameEntry.Text
|
||
|
if (newName == ""){
|
||
|
dialogTitle := translate("No Name Provided.")
|
||
|
dialogMessageA := getLabelCentered("You must enter a new name.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
if (len(newName) > 40){
|
||
|
dialogTitle := translate("Name Is Too Long.")
|
||
|
dialogMessageA := getLabelCentered("You must enter a name that is less than 40 characters.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
nameIsDuplicate, err := myPeople.EditPerson(personIdentifier, newName, personSex)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (nameIsDuplicate == true){
|
||
|
dialogTitle := translate("Name Already Exists.")
|
||
|
dialogMessageA := getLabelCentered("Another person already has this name.")
|
||
|
dialogMessageB := getLabelCentered("You must enter a unique name.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
nextPage()
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), currentNameRow, widget.NewSeparator(), enterNameEntryWithDescription, renameButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setDeleteGenomePersonPage(window fyne.Window, personIdentifier string, previousPage func(), nextPage func()){
|
||
|
|
||
|
currentPage := func(){setDeleteGenomePersonPage(window, personIdentifier, previousPage, nextPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Delete Person")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
subtitle := getPageSubtitleCentered("Delete Person")
|
||
|
|
||
|
personFound, personName, personCreatedTime, _, err := myPeople.GetPersonInfo(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setDeleteGenomePersonPage called with unknown person."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
description1 := getLabelCentered("Confirm to delete " + personName + "?")
|
||
|
|
||
|
createdTimeAgoText, err := helpers.ConvertUnixTimeToTimeAgoTranslated(personCreatedTime, false)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
description2 := getItalicLabelCentered("Person created " + createdTimeAgoText + ".")
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2)
|
||
|
|
||
|
//Outputs:
|
||
|
// -bool: Any couples/genomes exist for this person
|
||
|
// -*fyne.Container: label describing the couples and genomes that will be deleted
|
||
|
// -error
|
||
|
getPersonGenomesAndCouplesLabel := func()(bool, *fyne.Container, error){
|
||
|
|
||
|
allPersonGenomesList, err := myGenomes.GetAllPersonGenomesMapList(personIdentifier)
|
||
|
if (err != nil) { return false, nil, err }
|
||
|
|
||
|
numberOfPersonGenomes := len(allPersonGenomesList)
|
||
|
|
||
|
numberOfPersonCouples, err := myCouples.GetNumberOfCouplesForPerson(personIdentifier)
|
||
|
if (err != nil){ return false, nil, err }
|
||
|
|
||
|
if (numberOfPersonGenomes == 0 && numberOfPersonCouples == 0){
|
||
|
return false, nil, nil
|
||
|
}
|
||
|
|
||
|
numberOfPersonGenomesString := helpers.ConvertIntToString(numberOfPersonGenomes)
|
||
|
numberOfPersonCouplesString := helpers.ConvertIntToString(numberOfPersonCouples)
|
||
|
|
||
|
getGenomeOrGenomesText := func()string{
|
||
|
if (numberOfPersonGenomes == 1){
|
||
|
result := translate("genome")
|
||
|
return result
|
||
|
}
|
||
|
result := translate("genomes")
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
genomeOrGenomesText := getGenomeOrGenomesText()
|
||
|
|
||
|
getCoupleOrCouplesText := func()string{
|
||
|
|
||
|
if (numberOfPersonCouples == 1){
|
||
|
result := translate("couple")
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
result := translate("couples")
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
coupleOrCouplesText := getCoupleOrCouplesText()
|
||
|
|
||
|
if (numberOfPersonGenomes != 0 && numberOfPersonCouples != 0){
|
||
|
|
||
|
genomesAndCouplesText := numberOfPersonGenomesString + " " + genomeOrGenomesText + " & " + numberOfPersonCouplesString + " " + coupleOrCouplesText + "."
|
||
|
genomesAndCouplesLabel := getBoldLabelCentered(genomesAndCouplesText)
|
||
|
return true, genomesAndCouplesLabel, nil
|
||
|
}
|
||
|
|
||
|
if (numberOfPersonGenomes != 0){
|
||
|
|
||
|
genomesText := numberOfPersonGenomesString + " " + genomeOrGenomesText + "."
|
||
|
genomesLabel := getBoldLabelCentered(genomesText)
|
||
|
return true, genomesLabel, nil
|
||
|
}
|
||
|
|
||
|
couplesText := numberOfPersonCouplesString + " " + coupleOrCouplesText + "."
|
||
|
couplesLabel := getBoldLabelCentered(couplesText)
|
||
|
return true, couplesLabel, nil
|
||
|
}
|
||
|
|
||
|
anyGenomesOrCouplesExist, personGenomesAndCouplesLabel, err := getPersonGenomesAndCouplesLabel()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (anyGenomesOrCouplesExist == true){
|
||
|
|
||
|
deletionDescription := getLabelCentered("Deleting this person will delete:")
|
||
|
|
||
|
page.Add(widget.NewSeparator())
|
||
|
page.Add(deletionDescription)
|
||
|
page.Add(personGenomesAndCouplesLabel)
|
||
|
page.Add(widget.NewSeparator())
|
||
|
}
|
||
|
|
||
|
deleteButton := getWidgetCentered(widget.NewButtonWithIcon("Delete", theme.DeleteIcon(), func(){
|
||
|
|
||
|
err := myPeople.DeletePerson(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
nextPage()
|
||
|
}))
|
||
|
|
||
|
page.Add(deleteButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
// This function provides a page to manage a Person's genomes
|
||
|
func setManagePersonGenomesPage(window fyne.Window, personIdentifier string, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManagePersonGenomesPage(window, personIdentifier, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Manage Person Genomes")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Manage the person's genome files below.")
|
||
|
|
||
|
importGenomeButton := getWidgetCentered(widget.NewButtonWithIcon("Import Genome", theme.ContentAddIcon(), func(){
|
||
|
setImportRawGenomePage(window, personIdentifier, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
getPersonGenomesContainer := func()(*fyne.Container, error){
|
||
|
|
||
|
allGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(personIdentifier)
|
||
|
if (err != nil){ return nil, err }
|
||
|
|
||
|
if (len(allGenomesMapList) == 0){
|
||
|
noGenomesExistLabel := getBoldLabelCentered("No genomes exist.")
|
||
|
return noGenomesExistLabel, nil
|
||
|
}
|
||
|
|
||
|
indexColumn := container.NewVBox()
|
||
|
genomeNameColumn := container.NewVBox()
|
||
|
manageButtonColumn := container.NewVBox()
|
||
|
|
||
|
for index, genomeMap := range allGenomesMapList{
|
||
|
|
||
|
indexString := helpers.ConvertIntToString(index+1)
|
||
|
indexLabel := getBoldLabel(indexString + ".")
|
||
|
|
||
|
companyName, exists := genomeMap["CompanyName"]
|
||
|
if (exists == false){
|
||
|
return nil, errors.New("Malformed myGenomesMapList: Item missing CompanyName")
|
||
|
}
|
||
|
|
||
|
companyNameLabel := widget.NewLabel(companyName)
|
||
|
|
||
|
genomeIdentifier, exists := genomeMap["GenomeIdentifier"]
|
||
|
if (exists == false){
|
||
|
return nil, errors.New("Malformed myGenomesMapList: Item missing GenomeIdentifier")
|
||
|
}
|
||
|
|
||
|
manageButton := widget.NewButtonWithIcon("Manage", theme.VisibilityIcon(), func(){
|
||
|
setManageGenomePage(window, genomeIdentifier, currentPage)
|
||
|
})
|
||
|
|
||
|
indexColumn.Add(indexLabel)
|
||
|
genomeNameColumn.Add(companyNameLabel)
|
||
|
manageButtonColumn.Add(manageButton)
|
||
|
|
||
|
if (index != len(allGenomesMapList)-1){
|
||
|
indexColumn.Add(widget.NewSeparator())
|
||
|
genomeNameColumn.Add(widget.NewSeparator())
|
||
|
manageButtonColumn.Add(widget.NewSeparator())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
genomesContainer := container.NewHBox(layout.NewSpacer(), indexColumn, genomeNameColumn, manageButtonColumn, layout.NewSpacer())
|
||
|
|
||
|
return genomesContainer, nil
|
||
|
}
|
||
|
|
||
|
personGenomesContainer, err := getPersonGenomesContainer()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, importGenomeButton, widget.NewSeparator(), personGenomesContainer)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setImportRawGenomePage(window fyne.Window, personIdentifier string, previousPage func(), nextPage func()){
|
||
|
|
||
|
currentPage := func(){setImportRawGenomePage(window, personIdentifier, previousPage, nextPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Import Raw Genome")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Import a raw genome file below.")
|
||
|
description2 := getLabelCentered("You must export your raw data from a sequencing company.")
|
||
|
description3 := getLabelCentered("Supported Companies: 23andMe, AncestryDNA")
|
||
|
|
||
|
selectFileButton := getWidgetCentered(widget.NewButtonWithIcon("Select File", theme.FileIcon(), func(){
|
||
|
|
||
|
openFileCallbackFunction := func(file fyne.URIReadCloser, err error){
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (file == nil){
|
||
|
return
|
||
|
}
|
||
|
|
||
|
uriFilePath := file.URI().String()
|
||
|
|
||
|
filePath := strings.TrimPrefix(uriFilePath, "file://")
|
||
|
|
||
|
setLoadingScreen(window, "Importing Genome", "Importing genome file...")
|
||
|
|
||
|
fileExists, fileBytes, err := localFilesystem.GetFileContents(filePath)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (fileExists == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Unable to read chosen file: File not found."), currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
fileString := string(fileBytes)
|
||
|
|
||
|
fileIsValid, fileAlreadyExists, err := myGenomes.AddRawGenome(personIdentifier, fileString)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (fileIsValid == false){
|
||
|
currentPage()
|
||
|
dialogTitle := translate("Unable To Read File.")
|
||
|
dialogMessageA := getLabelCentered("Seekia was unable to read the selected genome file.")
|
||
|
dialogMessageB := getLabelCentered("Only 23andMe and AncestryDNA files are supported.")
|
||
|
dialogMessageC := getLabelCentered("More companies will be supported in the future.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB, dialogMessageC)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
if (fileAlreadyExists == true){
|
||
|
currentPage()
|
||
|
dialogTitle := translate("Genome Already Exists.")
|
||
|
dialogMessageA := getLabelCentered("The genome file you selected is already imported.")
|
||
|
dialogMessageB := getLabelCentered("You can only import the same file once for each Person.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA, dialogMessageB)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
nextPage()
|
||
|
}
|
||
|
dialog.ShowFileOpen(openFileCallbackFunction, window)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, selectFileButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
// This provides a page to manage a person's Genome
|
||
|
func setManageGenomePage(window fyne.Window, genomeIdentifier string, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManageGenomePage(window, genomeIdentifier, previousPage)}
|
||
|
|
||
|
setLoadingScreen(window, "Loading Genome", "Loading genome...")
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Manage Genome")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
genomeFound, personIdentifier, exportTime, importTime, isPhased, snpCount, companyName, importVersion, fileHash, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (genomeFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setManageGenomePage called with missing genomeIdentifier"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
currentImportVersion, err := readRawGenomes.GetCurrentCompanyImportVersion(companyName)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (importVersion != currentImportVersion){
|
||
|
// We will refresh the metadata for the genome
|
||
|
err := myGenomes.RefreshRawGenomeMetadata(genomeIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
currentPage()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
isPhasedString := helpers.ConvertBoolToYesOrNoString(isPhased)
|
||
|
snpCountString := helpers.ConvertInt64ToString(snpCount)
|
||
|
|
||
|
companyLabel := widget.NewLabel("Company:")
|
||
|
companyNameLabel := getBoldLabel(companyName)
|
||
|
|
||
|
companyNameRow := container.NewHBox(layout.NewSpacer(), companyLabel, companyNameLabel, layout.NewSpacer())
|
||
|
|
||
|
snpCountLabel := widget.NewLabel("SNP Count:")
|
||
|
snpCountText := getBoldLabel(snpCountString)
|
||
|
snpCountHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||
|
setGenomeSNPCountExplainerPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
snpCountRow := container.NewHBox(layout.NewSpacer(), snpCountLabel, snpCountText, snpCountHelpButton, layout.NewSpacer())
|
||
|
|
||
|
isPhasedLabel := widget.NewLabel("Is Phased:")
|
||
|
isPhasedText := getBoldLabel(isPhasedString)
|
||
|
isPhasedHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
||
|
setGenomePhasingExplainerPage(window, currentPage)
|
||
|
})
|
||
|
|
||
|
isPhasedRow := container.NewHBox(layout.NewSpacer(), isPhasedLabel, isPhasedText, isPhasedHelpButton, layout.NewSpacer())
|
||
|
|
||
|
fileHashTrimmed, _, err := helpers.TrimAndFlattenString(fileHash, 6)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
fileHashLabel := widget.NewLabel("File Hash: ")
|
||
|
fileHashText := getBoldLabel(fileHashTrimmed)
|
||
|
fileHashRow := container.NewHBox(layout.NewSpacer(), fileHashLabel, fileHashText, layout.NewSpacer())
|
||
|
|
||
|
exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(exportTime, false)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
exportedTimeLabel := getItalicLabelCentered("Exported from " + companyName + " " + exportTimeAgo + ".")
|
||
|
|
||
|
importedTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(importTime, false)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
importedTimeLabel := getItalicLabelCentered("Imported " + importedTimeAgo + ".")
|
||
|
|
||
|
deleteGenomeButton := getWidgetCentered(widget.NewButtonWithIcon("Delete Genome", theme.DeleteIcon(), func(){
|
||
|
setConfirmDeletePersonGenomePage(window, personIdentifier, genomeIdentifier, currentPage, previousPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), companyNameRow, snpCountRow, isPhasedRow, fileHashRow, widget.NewSeparator(), exportedTimeLabel, importedTimeLabel, widget.NewSeparator(), deleteGenomeButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setConfirmDeletePersonGenomePage(window fyne.Window, personIdentifier string, genomeIdentifier string, previousPage func(), nextPage func()){
|
||
|
|
||
|
currentPage := func(){setConfirmDeletePersonGenomePage(window, personIdentifier, genomeIdentifier, previousPage, nextPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Confirm Delete Genome")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getBoldLabelCentered("Delete Genome?")
|
||
|
|
||
|
description2 := getLabelCentered("This will delete this person's raw genome.")
|
||
|
description3 := getLabelCentered("You must run a new genetic analysis afterwards.")
|
||
|
|
||
|
genomeFound, genomePersonIdentifier, timeGenomeWasExported, timeGenomeWasImported, _, _, companyName, _, _, err := myGenomes.GetMyRawGenomeMetadata(genomeIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (genomeFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setDeletePersonGenomePage called with missing genome."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (genomePersonIdentifier != personIdentifier){
|
||
|
setErrorEncounteredPage(window, errors.New("Cannot delete genome: Genome person identifier does not match."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
exportTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasExported, false)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
exportedTimeLabel := getItalicLabelCentered("Exported from " + companyName + " " + exportTimeAgo + ".")
|
||
|
|
||
|
importedTimeAgo, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeGenomeWasImported, false)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
importedTimeLabel := getItalicLabelCentered("Imported " + importedTimeAgo + ".")
|
||
|
|
||
|
deleteButton := getWidgetCentered(widget.NewButtonWithIcon("Delete Genome", theme.DeleteIcon(), func(){
|
||
|
|
||
|
err := myGenomes.DeleteMyRawGenome(genomeIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
nextPage()
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), exportedTimeLabel, importedTimeLabel, widget.NewSeparator(), deleteButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setAnalyzePersonGeneticsPage(window fyne.Window, personIdentifier string, previousPage func()){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "AnalyzePersonGeneticsPage")
|
||
|
|
||
|
currentPage := func(){setAnalyzePersonGeneticsPage(window, personIdentifier, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered(translate("Genetics - Analyze Person Genetics"))
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered(translate("Analyze this person's genetics."))
|
||
|
|
||
|
personFound, personName, _, _, err := myPeople.GetPersonInfo(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setAnalyzePersonGeneticsPage called with missing person"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
allPersonRawGenomeIdentifiersList, err := myGenomes.GetAllPersonRawGenomeIdentifiersList(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (len(allPersonRawGenomeIdentifiersList) == 0){
|
||
|
noGenomesExistLabel := getBoldLabelCentered("No genomes found.")
|
||
|
description2 := getLabelCentered("You must import a genome to perform a genetic analysis.")
|
||
|
description3 := getLabelCentered("Go to the previous page and select Manage Genomes.")
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), noGenomesExistLabel, description2, description3)
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
anyAnalysisFound, newestAnalysisIdentifier, timeOfNewestAnalysis, newestAnalysisListOfGenomesAnalyzed, newerAnalysisVersionAvailable, err := myAnalyses.GetPersonNewestGeneticAnalysisInfo(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (anyAnalysisFound == false){
|
||
|
// We will skip to the ConfirmPerformAnalysis page
|
||
|
setConfirmPerformPersonAnalysisPage(window, personIdentifier, previousPage, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (newerAnalysisVersionAvailable == true){
|
||
|
|
||
|
description1 := getLabelCentered("A new analysis method is available!")
|
||
|
description2 := getLabelCentered("You must perform a new analysis to see your new results.")
|
||
|
|
||
|
performNewAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("Perform New Analysis", theme.NavigateNextIcon(), func(){
|
||
|
setConfirmPerformPersonAnalysisPage(window, personIdentifier, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), description1, description2, performNewAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// This will return true if a newer analysis can be performed using newly imported genomes
|
||
|
getAnalysisIsMissingGenomesBool := func()(bool, error){
|
||
|
|
||
|
genomesAreIdentical := helpers.CheckIfTwoListsContainIdenticalItems(allPersonRawGenomeIdentifiersList, newestAnalysisListOfGenomesAnalyzed)
|
||
|
if (genomesAreIdentical == false){
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
analysisIsMissingGenomes, err := getAnalysisIsMissingGenomesBool()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (analysisIsMissingGenomes == true){
|
||
|
|
||
|
description1 := getLabelCentered("You have imported/deleted a genome.")
|
||
|
description2 := getLabelCentered("You must perform a new analysis.")
|
||
|
performAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("Perform Analysis", theme.NavigateNextIcon(), func(){
|
||
|
setConfirmPerformPersonAnalysisPage(window, personIdentifier, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), description1, description2, performAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
analysisReadyLabel := getBoldLabelCentered("Genetic Analysis Complete!")
|
||
|
|
||
|
personAnalyzedLabel := widget.NewLabel("Person Analyzed:")
|
||
|
personNameLabel := getBoldLabel(personName)
|
||
|
personAnalyzedRow := container.NewHBox(layout.NewSpacer(), personAnalyzedLabel, personNameLabel, layout.NewSpacer())
|
||
|
|
||
|
numberOfGenomesInAnalysis := len(newestAnalysisListOfGenomesAnalyzed)
|
||
|
|
||
|
numberOfGenomesInAnalysisString := helpers.ConvertIntToString(numberOfGenomesInAnalysis)
|
||
|
|
||
|
numberOfGenomesInAnalysisLabel := widget.NewLabel("Number of genomes analyzed:")
|
||
|
numberOfGenomesInAnalysisText := getBoldLabel(numberOfGenomesInAnalysisString)
|
||
|
numberOfGenomesInAnalysisRow := container.NewHBox(layout.NewSpacer(), numberOfGenomesInAnalysisLabel, numberOfGenomesInAnalysisText, layout.NewSpacer())
|
||
|
|
||
|
timeAgoPerformed, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeOfNewestAnalysis, false)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
timeAgoPerformedLabel := getItalicLabelCentered("Analysis performed " + timeAgoPerformed + ".")
|
||
|
|
||
|
viewAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("View Analysis", theme.VisibilityIcon(), func(){
|
||
|
|
||
|
analysisFound, analysisMapList, err := myAnalyses.GetGeneticAnalysis(newestAnalysisIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (analysisFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Person analysis not found after being found already."), currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setViewPersonGeneticAnalysisPage(window, personIdentifier, analysisMapList, numberOfGenomesInAnalysis, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), analysisReadyLabel, personAnalyzedRow, numberOfGenomesInAnalysisRow, timeAgoPerformedLabel, viewAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setConfirmPerformPersonAnalysisPage(window fyne.Window, personIdentifier string, previousPage func(), pageToVisitAfter func()){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "ConfirmPerformGeneticAnalysisPage")
|
||
|
|
||
|
currentPage := func(){setConfirmPerformPersonAnalysisPage(window, personIdentifier, previousPage, pageToVisitAfter)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Perform Analysis")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
allPersonGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfPersonGenomes := len(allPersonGenomesMapList)
|
||
|
|
||
|
if (numberOfPersonGenomes == 0){
|
||
|
setErrorEncounteredPage(window, errors.New("setConfirmPerformPersonAnalysisPage called with person who has no genomes."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Now we check if there is an analysis running
|
||
|
|
||
|
anyProcessFound, processIdentifier, err := myAnalyses.GetPersonGeneticAnalysisProcessIdentifier(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (anyProcessFound == true){
|
||
|
|
||
|
processFound, processIsComplete, _, _, _, err := myAnalyses.GetAnalysisProcessInfo(processIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (processFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Genetic analysis process not found after being found already."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (processIsComplete == false){
|
||
|
|
||
|
// An analysis is already running.
|
||
|
|
||
|
description1 := getLabelCentered("A genetic analysis is already being generated.")
|
||
|
description2 := getLabelCentered("View the status of the analysis?")
|
||
|
|
||
|
viewStatusButton := getWidgetCentered(widget.NewButtonWithIcon("View Status", theme.VisibilityIcon(), func(){
|
||
|
setMonitorGeneticAnalysisGenerationPage(window, processIdentifier, currentPage, pageToVisitAfter)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, viewStatusButton)
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Existing analysis probably encountered error.
|
||
|
// We will just show a retry option.
|
||
|
}
|
||
|
|
||
|
description1 := getBoldLabelCentered("Perform genetic analysis?")
|
||
|
description2 := getLabelCentered("This will create an analysis of all of this person's genomes.")
|
||
|
description3 := getLabelCentered("It is performed offline and is not shared without your approval.")
|
||
|
|
||
|
startAnalysisFunction := func(){
|
||
|
|
||
|
newProcessIdentifier, err := myAnalyses.StartCreateNewPersonGeneticAnalysis(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setMonitorGeneticAnalysisGenerationPage(window, newProcessIdentifier, currentPage, pageToVisitAfter)
|
||
|
}
|
||
|
|
||
|
startAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("Start Analysis", theme.ConfirmIcon(), startAnalysisFunction))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, startAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
// This function provides a page to monitor an active analysis generation
|
||
|
func setMonitorGeneticAnalysisGenerationPage(window fyne.Window, processIdentifier string, previousPage func(), pageToVisitAfter func()){
|
||
|
|
||
|
pageIdentifier, err := helpers.GetNewRandomHexString(16)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, pageToVisitAfter)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", pageIdentifier)
|
||
|
|
||
|
checkIfPageHasChangedFunction := func()bool{
|
||
|
exists, currentViewedPage := appMemory.GetMemoryEntry("CurrentViewedPage")
|
||
|
if (exists == true && currentViewedPage == pageIdentifier){
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
title := getPageTitleCentered("Monitor Genetic Analysis Generation")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
processDetailsABinding := binding.NewString()
|
||
|
processDetailsBBinding := binding.NewString()
|
||
|
progressPercentageBinding := binding.NewFloat()
|
||
|
|
||
|
processDetailsABinding.Set("Genetic analysis is being generated...")
|
||
|
processDetailsBBinding.Set("You can leave this page.")
|
||
|
|
||
|
processDetailsALabel := widget.NewLabelWithData(processDetailsABinding)
|
||
|
processDetailsALabel.TextStyle = getFyneTextStyle_Bold()
|
||
|
processDetailsBLabel := widget.NewLabelWithData(processDetailsBBinding)
|
||
|
|
||
|
processDetailsALabelCentered := getWidgetCentered(processDetailsALabel)
|
||
|
processDetailsBLabelCentered := getWidgetCentered(processDetailsBLabel)
|
||
|
|
||
|
loadingBar := getWidgetCentered(widget.NewProgressBarWithData(progressPercentageBinding))
|
||
|
|
||
|
updateBindingsFunction := func(){
|
||
|
|
||
|
for{
|
||
|
|
||
|
pageHasChanged := checkIfPageHasChangedFunction()
|
||
|
if (pageHasChanged == true){
|
||
|
return
|
||
|
}
|
||
|
|
||
|
processFound, processIsComplete, processEncounteredError, errorEncounteredByProcess, processPercentageComplete, err := myAnalyses.GetAnalysisProcessInfo(processIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (processFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setMonitorGeneticAnalysisGenerationPage called with missing process"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (processIsComplete == false){
|
||
|
percentageCompleteFloat := float64(processPercentageComplete)/100
|
||
|
progressPercentageBinding.Set(percentageCompleteFloat)
|
||
|
time.Sleep(time.Millisecond * 50)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Process is complete
|
||
|
|
||
|
progressPercentageBinding.Set(1)
|
||
|
|
||
|
if (processEncounteredError == true){
|
||
|
processDetailsABinding.Set("Process Encountered Error!")
|
||
|
processDetailsBBinding.Set("ERROR: " + errorEncounteredByProcess.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
pageToVisitAfter()
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), processDetailsALabelCentered, processDetailsBLabelCentered, loadingBar)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
|
||
|
go updateBindingsFunction()
|
||
|
}
|
||
|
|
||
|
|
||
|
func setManageCouplesPage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManageCouplesPage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Manage Couples")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description1 := getLabelCentered("Perform a genetic analysis of a couple.")
|
||
|
|
||
|
createACoupleButton := getWidgetCentered(widget.NewButtonWithIcon("Create Couple", theme.ContentAddIcon(), func(){
|
||
|
setCreateCouplePage(window, currentPage)
|
||
|
}))
|
||
|
|
||
|
getManageMyCouplesContainer := func()(*fyne.Container, error){
|
||
|
|
||
|
myCouplesMapList, err := myCouples.GetMyGenomeCouplesMapList()
|
||
|
if (err != nil){ return nil, err }
|
||
|
|
||
|
if (len(myCouplesMapList) == 0){
|
||
|
|
||
|
noCouplesExistLabel := getBoldLabelCentered("No couples exist.")
|
||
|
|
||
|
return noCouplesExistLabel, nil
|
||
|
}
|
||
|
|
||
|
myCouplesText := getItalicLabelCentered("My Couples:")
|
||
|
|
||
|
manageButtonsGrid := container.NewGridWithColumns(1)
|
||
|
|
||
|
for _, coupleMap := range myCouplesMapList{
|
||
|
|
||
|
personAIdentifier, exists := coupleMap["PersonAIdentifier"]
|
||
|
if (exists == false) {
|
||
|
return nil, errors.New("Malformed myCoupleAnalysesMapList: Item missing personAIdentifier")
|
||
|
}
|
||
|
|
||
|
personBIdentifier, exists := coupleMap["PersonBIdentifier"]
|
||
|
if (exists == false) {
|
||
|
return nil, errors.New("Malformed myCoupleAnalysesMapList: Item missing personBIdentifier")
|
||
|
}
|
||
|
|
||
|
personFound, personAName, _, _, err := myPeople.GetPersonInfo(personAIdentifier)
|
||
|
if (err != nil) { return nil, err }
|
||
|
if (personFound == false){
|
||
|
return nil, errors.New("Couple person not found.")
|
||
|
}
|
||
|
|
||
|
personFound, personBName, _, _, err := myPeople.GetPersonInfo(personBIdentifier)
|
||
|
if (err != nil) { return nil, err }
|
||
|
if (personFound == false){
|
||
|
return nil, errors.New("Couple person not found.")
|
||
|
}
|
||
|
|
||
|
personANameTrimmed, _, err := helpers.TrimAndFlattenString(personAName, 15)
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
personBNameTrimmed, _, err := helpers.TrimAndFlattenString(personBName, 15)
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
coupleName := personANameTrimmed + " + " + personBNameTrimmed
|
||
|
|
||
|
manageCoupleButton := widget.NewButton(coupleName, func(){
|
||
|
setManageCouplePage(window, personAIdentifier, personBIdentifier, currentPage)
|
||
|
})
|
||
|
|
||
|
manageButtonsGrid.Add(manageCoupleButton)
|
||
|
}
|
||
|
|
||
|
manageButtonsGridCentered := getContainerCentered(manageButtonsGrid)
|
||
|
|
||
|
manageMyCouplesContainer := container.NewVBox(myCouplesText, manageButtonsGridCentered)
|
||
|
|
||
|
return manageMyCouplesContainer, nil
|
||
|
}
|
||
|
|
||
|
manageMyCouplesContainer, err := getManageMyCouplesContainer()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, widget.NewSeparator(), createACoupleButton, widget.NewSeparator(), manageMyCouplesContainer)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setCreateCouplePage(window fyne.Window, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setCreateCouplePage(window, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Create Couple")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
myGenomePeopleMapList, err := myPeople.GetMyGenomePeopleMapList()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (len(myGenomePeopleMapList) < 2){
|
||
|
|
||
|
description1 := getLabelCentered("You have created fewer than 2 people.")
|
||
|
description2 := getLabelCentered("You must create at least 2 people to create a couple.")
|
||
|
description3 := getLabelCentered("Create a new person on the Genetics - Manage People page.")
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
description1 := getLabelCentered("Choose 2 people to pair below.")
|
||
|
description2 := getLabelCentered("You can create new people on the Manage People page.")
|
||
|
|
||
|
selectedPeopleListBinding := binding.NewStringList()
|
||
|
|
||
|
getChoosePeopleGrid := func()(*fyne.Container, error){
|
||
|
|
||
|
getNumberOfGridColumns := func()int{
|
||
|
if (len(myGenomePeopleMapList) == 2){
|
||
|
return 2
|
||
|
}
|
||
|
return 3
|
||
|
}
|
||
|
|
||
|
numberOfGridColumns := getNumberOfGridColumns()
|
||
|
|
||
|
choosePeopleGrid := container.NewGridWithColumns(numberOfGridColumns)
|
||
|
|
||
|
for _, personMap := range myGenomePeopleMapList{
|
||
|
|
||
|
personIdentifier, exists := personMap["PersonIdentifier"]
|
||
|
if (exists == false){
|
||
|
return nil, errors.New("myGenomePeopleMapList contains item missing PersonIdentifier")
|
||
|
}
|
||
|
|
||
|
personName, exists := personMap["PersonName"]
|
||
|
if (exists == false){
|
||
|
return nil, errors.New("myGenomePeopleMapList contains item missing PersonName")
|
||
|
}
|
||
|
|
||
|
personNameTrimmed, _, err := helpers.TrimAndFlattenString(personName, 15)
|
||
|
if (err != nil) { return nil, err }
|
||
|
|
||
|
personCheck := widget.NewCheck(personNameTrimmed, func(response bool){
|
||
|
if (response == true){
|
||
|
err := selectedPeopleListBinding.Append(personIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
existingList, err := selectedPeopleListBinding.Get()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
newList, deletedAny := helpers.DeleteAllMatchingItemsFromStringList(existingList, personIdentifier)
|
||
|
if (deletedAny == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Person not found when trying to delete person from chosen people list."), currentPage)
|
||
|
return
|
||
|
}
|
||
|
err = selectedPeopleListBinding.Set(newList)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
personCheckBoxed := getWidgetBoxed(personCheck)
|
||
|
|
||
|
choosePeopleGrid.Add(personCheckBoxed)
|
||
|
}
|
||
|
|
||
|
choosePeopleGridCentered := getContainerCentered(choosePeopleGrid)
|
||
|
|
||
|
return choosePeopleGridCentered, nil
|
||
|
}
|
||
|
|
||
|
choosePeopleGrid, err := getChoosePeopleGrid()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
createCoupleButton := getWidgetCentered(widget.NewButtonWithIcon("Create Couple", theme.ConfirmIcon(), func(){
|
||
|
|
||
|
selectedPeopleList, err := selectedPeopleListBinding.Get()
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (len(selectedPeopleList) < 2){
|
||
|
|
||
|
dialogTitle := translate("Not Enough People Selected.")
|
||
|
dialogMessageA := getLabelCentered("You must select two people to create a couple.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
if (len(selectedPeopleList) > 2){
|
||
|
|
||
|
dialogTitle := translate("Too Many People Selected.")
|
||
|
dialogMessageA := getLabelCentered("You must select two people to create a couple.")
|
||
|
dialogContent := container.NewVBox(dialogMessageA)
|
||
|
dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personAIdentifier := selectedPeopleList[0]
|
||
|
personBIdentifier := selectedPeopleList[1]
|
||
|
|
||
|
_, err = myCouples.AddCouple(personAIdentifier, personBIdentifier)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setManageCouplePage(window, personAIdentifier, personBIdentifier, previousPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), choosePeopleGrid, createCoupleButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setManageCouplePage(window fyne.Window, personAIdentifier string, personBIdentifier string, previousPage func()){
|
||
|
|
||
|
currentPage := func(){setManageCouplePage(window, personAIdentifier, personBIdentifier, previousPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Manage Couple")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
personAFound, personAName, _, _, err := myPeople.GetPersonInfo(personAIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personAFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setManageCouplePage called with unknown personAIdentifier"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personBFound, personBName, _, _, err := myPeople.GetPersonInfo(personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personBFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setManageCouplePage called with unknown personBIdentifier"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
coupleNameLabel := getLabelCentered("Couple Name:")
|
||
|
coupleNameText := getBoldLabelCentered(personAName + " + " + personBName)
|
||
|
|
||
|
analyzeIcon, err := getFyneImageIcon("Stats")
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
analyzeGeneticsButton := widget.NewButton("Analyze Genetics", func(){
|
||
|
setAnalyzeCoupleGeneticsPage(window, personAIdentifier, personBIdentifier, currentPage)
|
||
|
})
|
||
|
analyzeGeneticsButtonWithIcon := getContainerCentered(container.NewGridWithColumns(1, analyzeIcon, analyzeGeneticsButton))
|
||
|
|
||
|
deleteCoupleButton := getWidgetCentered(widget.NewButtonWithIcon("Delete Couple", theme.DeleteIcon(), func(){
|
||
|
setDeleteCouplePage(window, personAIdentifier, personBIdentifier, currentPage, previousPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), coupleNameLabel, coupleNameText, widget.NewSeparator(), analyzeGeneticsButtonWithIcon, widget.NewSeparator(), deleteCoupleButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
func setDeleteCouplePage(window fyne.Window, personAIdentifier string, personBIdentifier string, previousPage func(), nextPage func()){
|
||
|
|
||
|
currentPage := func(){setDeleteCouplePage(window, personAIdentifier, personBIdentifier, previousPage, nextPage)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Delete Couple")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
subtitle := getPageSubtitleCentered("Delete Couple")
|
||
|
|
||
|
personAFound, personAName, _, _, err := myPeople.GetPersonInfo(personAIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personAFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setDeleteGenomeCouplePage called with unknown personAIdentifier"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personBFound, personBName, _, _, err := myPeople.GetPersonInfo(personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personBFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setDeleteGenomeCouplePage called with unknown personBIdentifier"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
description := getLabelCentered("Confirm to delete this couple?")
|
||
|
|
||
|
coupleName := personAName + " + " + personBName
|
||
|
|
||
|
coupleNameLabel := widget.NewLabel("Couple Name:")
|
||
|
coupleNameText := getBoldLabel(coupleName)
|
||
|
|
||
|
coupleNameRow := container.NewHBox(layout.NewSpacer(), coupleNameLabel, coupleNameText, layout.NewSpacer())
|
||
|
|
||
|
deleteButton := getWidgetCentered(widget.NewButtonWithIcon("Delete", theme.DeleteIcon(), func(){
|
||
|
|
||
|
err := myCouples.DeleteCouple(personAIdentifier, personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
nextPage()
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, coupleNameRow, deleteButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setAnalyzeCoupleGeneticsPage(window fyne.Window, inputPersonAIdentifier string, inputPersonBIdentifier string, previousPage func()){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "AnalyzeCoupleGeneticsPage")
|
||
|
|
||
|
currentPage := func(){setAnalyzeCoupleGeneticsPage(window, inputPersonAIdentifier, inputPersonBIdentifier, previousPage)}
|
||
|
|
||
|
// We have to sort the person identifiers so they are in the same order as they exist in the couple analysis
|
||
|
|
||
|
personAIdentifier, personBIdentifier, err := myAnalyses.GetPeopleIdentifiersSortedForCouple(inputPersonAIdentifier, inputPersonBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Analyze Couple Genetics")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
description := getLabelCentered("Analyze this couple's genetics.")
|
||
|
|
||
|
personAFound, personAName, _, _, err := myPeople.GetPersonInfo(personAIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personAFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setAnalyzeCoupleGeneticsPage called with missing person"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personBFound, personBName, _, _, err := myPeople.GetPersonInfo(personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (personBFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("setAnalyzeCoupleGeneticsPage called with missing person"), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
allPersonARawGenomeIdentifiersList, err := myGenomes.GetAllPersonRawGenomeIdentifiersList(personAIdentifier)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
allPersonBRawGenomeIdentifiersList, err := myGenomes.GetAllPersonRawGenomeIdentifiersList(personBIdentifier)
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if (len(allPersonARawGenomeIdentifiersList) == 0 || len(allPersonBRawGenomeIdentifiersList) == 0){
|
||
|
// At least one of the people is missing genomes
|
||
|
|
||
|
getGenomesMissingText := func()string{
|
||
|
if (len(allPersonARawGenomeIdentifiersList) == 0 && len(allPersonBRawGenomeIdentifiersList) == 0){
|
||
|
missingLabelText := personAName + " and " + personBName + " have no genomes."
|
||
|
return missingLabelText
|
||
|
}
|
||
|
if (len(allPersonARawGenomeIdentifiersList) == 0 && len(allPersonBRawGenomeIdentifiersList) != 0){
|
||
|
|
||
|
missingLabelText := personAName + " has no genomes."
|
||
|
return missingLabelText
|
||
|
}
|
||
|
// len(allPersonARawGenomeIdentifiersList) != 0 && len(allPersonBRawGenomeIdentifiersList) == 0){
|
||
|
|
||
|
missingLabelText := personBName + " has no genomes."
|
||
|
return missingLabelText
|
||
|
}
|
||
|
|
||
|
genomesMissingText := getGenomesMissingText()
|
||
|
|
||
|
noGenomesExistLabel := getBoldLabelCentered(genomesMissingText)
|
||
|
description2 := getLabelCentered("Each person must have at least 1 genome to perform a couple analysis.")
|
||
|
description3 := getLabelCentered("Go to the Manage Person page to import a genome for a person.")
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), noGenomesExistLabel, description2, description3)
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
anyPersonAAnalysisFound, newestPersonAAnalysisIdentifier, _, newestPersonAAnalysisListOfGenomesAnalyzed, newerPersonAAnalysisVersionAvailable, err := myAnalyses.GetPersonNewestGeneticAnalysisInfo(personAIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
anyPersonBAnalysisFound, newestPersonBAnalysisIdentifier, _, newestPersonBAnalysisListOfGenomesAnalyzed, newerPersonBAnalysisVersionAvailable, err := myAnalyses.GetPersonNewestGeneticAnalysisInfo(personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
anyCoupleAnalysisFound, newestCoupleAnalysisIdentifier, timeOfNewestAnalysis, newestCoupleAnalysisListOfGenomesAnalyzed_PersonA, newestCoupleAnalysisListOfGenomesAnalyzed_PersonB, newerCoupleAnalysisVersionAvailable, err := myAnalyses.GetCoupleNewestGeneticAnalysisInfo(personAIdentifier, personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (anyCoupleAnalysisFound == false || anyPersonAAnalysisFound == false || anyPersonBAnalysisFound == false){
|
||
|
// We will skip to the ConfirmPerformAnalysis page
|
||
|
setConfirmPerformCoupleAnalysisPage(window, personAIdentifier, personBIdentifier, previousPage, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (newerPersonAAnalysisVersionAvailable == true || newerPersonBAnalysisVersionAvailable == true || newerCoupleAnalysisVersionAvailable == true){
|
||
|
|
||
|
description1 := getLabelCentered("A new analysis method is available!")
|
||
|
description2 := getLabelCentered("You must perform a new analysis to see the couple's new results.")
|
||
|
|
||
|
performNewAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("Perform New Analysis", theme.NavigateNextIcon(), func(){
|
||
|
setConfirmPerformCoupleAnalysisPage(window, personAIdentifier, personBIdentifier, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), description1, description2, performNewAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// This will return true if a newer analysis can be performed using newly imported genomes
|
||
|
getAnalysisIsMissingGenomesBool := func()(bool, error){
|
||
|
|
||
|
genomesAreIdentical := helpers.CheckIfTwoListsContainIdenticalItems(allPersonARawGenomeIdentifiersList, newestPersonAAnalysisListOfGenomesAnalyzed)
|
||
|
if (genomesAreIdentical == false){
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
genomesAreIdentical = helpers.CheckIfTwoListsContainIdenticalItems(allPersonBRawGenomeIdentifiersList, newestPersonBAnalysisListOfGenomesAnalyzed)
|
||
|
if (genomesAreIdentical == false){
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
genomesAreIdentical = helpers.CheckIfTwoListsContainIdenticalItems(allPersonARawGenomeIdentifiersList, newestCoupleAnalysisListOfGenomesAnalyzed_PersonA)
|
||
|
if (genomesAreIdentical == false){
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
genomesAreIdentical = helpers.CheckIfTwoListsContainIdenticalItems(allPersonBRawGenomeIdentifiersList, newestCoupleAnalysisListOfGenomesAnalyzed_PersonB)
|
||
|
if (genomesAreIdentical == false){
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
analysisIsMissingGenomes, err := getAnalysisIsMissingGenomesBool()
|
||
|
if (err != nil) {
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (analysisIsMissingGenomes == true){
|
||
|
|
||
|
description1 := getLabelCentered("At least 1 person in the couple has imported/deleted a genome.")
|
||
|
description2 := getLabelCentered("A new analysis must be performed.")
|
||
|
performAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("Perform Analysis", theme.NavigateNextIcon(), func(){
|
||
|
setConfirmPerformCoupleAnalysisPage(window, personAIdentifier, personBIdentifier, currentPage, currentPage)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), description1, description2, performAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
analysisReadyLabel := getBoldLabelCentered("Genetic Analysis Complete!")
|
||
|
|
||
|
coupleAnalyzedLabel := widget.NewLabel("Couple Analyzed:")
|
||
|
coupleName := personAName + " + " + personBName
|
||
|
coupleNameLabel := getBoldLabel(coupleName)
|
||
|
personAnalyzedRow := container.NewHBox(layout.NewSpacer(), coupleAnalyzedLabel, coupleNameLabel, layout.NewSpacer())
|
||
|
|
||
|
numberOfPersonAGenomesInAnalysis := len(newestPersonAAnalysisListOfGenomesAnalyzed)
|
||
|
numberOfPersonBGenomesInAnalysis := len(newestPersonBAnalysisListOfGenomesAnalyzed)
|
||
|
|
||
|
timeAgoPerformed, err := helpers.ConvertUnixTimeToTimeAgoTranslated(timeOfNewestAnalysis, false)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
timeAgoPerformedLabel := getItalicLabelCentered("Analysis performed " + timeAgoPerformed + ".")
|
||
|
|
||
|
viewAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("View Analysis", theme.VisibilityIcon(), func(){
|
||
|
|
||
|
personAAnalysisFound, personAAnalysisMapList, err := myAnalyses.GetGeneticAnalysis(newestPersonAAnalysisIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (personAAnalysisFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Person analysis not found after being found already."), currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
personBAnalysisFound, personBAnalysisMapList, err := myAnalyses.GetGeneticAnalysis(newestPersonBAnalysisIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (personBAnalysisFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Person analysis not found after being found already."), currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
coupleAnalysisFound, coupleAnalysisMapList, err := myAnalyses.GetGeneticAnalysis(newestCoupleAnalysisIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, currentPage)
|
||
|
return
|
||
|
}
|
||
|
if (coupleAnalysisFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Couple analysis not found after being found already."), currentPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setViewCoupleGeneticAnalysisPage(window, personAIdentifier, personBIdentifier, personAAnalysisMapList, personBAnalysisMapList, coupleAnalysisMapList, numberOfPersonAGenomesInAnalysis, numberOfPersonBGenomesInAnalysis, currentPage)
|
||
|
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), analysisReadyLabel, personAnalyzedRow, timeAgoPerformedLabel, viewAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
func setConfirmPerformCoupleAnalysisPage(window fyne.Window, personAIdentifier string, personBIdentifier string, previousPage func(), pageToVisitAfter func()){
|
||
|
|
||
|
appMemory.SetMemoryEntry("CurrentViewedPage", "ConfirmPerformCoupleGeneticAnalysisPage")
|
||
|
|
||
|
currentPage := func(){setConfirmPerformCoupleAnalysisPage(window, personAIdentifier, personBIdentifier, previousPage, pageToVisitAfter)}
|
||
|
|
||
|
title := getPageTitleCentered("Genetics - Perform Couple Analysis")
|
||
|
|
||
|
backButton := getBackButtonCentered(previousPage)
|
||
|
|
||
|
allPersonAGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(personAIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfPersonAGenomes := len(allPersonAGenomesMapList)
|
||
|
|
||
|
if (numberOfPersonAGenomes == 0){
|
||
|
setErrorEncounteredPage(window, errors.New("setConfirmPerformCoupleAnalysisPage called with person who has no genomes."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
allPersonBGenomesMapList, err := myGenomes.GetAllPersonGenomesMapList(personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
numberOfPersonBGenomes := len(allPersonBGenomesMapList)
|
||
|
|
||
|
if (numberOfPersonBGenomes == 0){
|
||
|
setErrorEncounteredPage(window, errors.New("setConfirmPerformCoupleAnalysisPage called with person who has no genomes."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Now we check if there is an analysis running
|
||
|
|
||
|
anyProcessFound, processIdentifier, err := myAnalyses.GetCoupleGeneticAnalysisProcessIdentifier(personAIdentifier, personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (anyProcessFound == true){
|
||
|
|
||
|
processFound, processIsComplete, _, _, _, err := myAnalyses.GetAnalysisProcessInfo(processIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (processFound == false){
|
||
|
setErrorEncounteredPage(window, errors.New("Couple genetic analysis process not found after being found already."), previousPage)
|
||
|
return
|
||
|
}
|
||
|
if (processIsComplete == false){
|
||
|
|
||
|
// An analysis is runnning. We will display that on the page
|
||
|
|
||
|
description1 := getLabelCentered("A genetic analysis is already being generated.")
|
||
|
description2 := getLabelCentered("View the status of the analysis?")
|
||
|
|
||
|
viewStatusButton := getWidgetCentered(widget.NewButtonWithIcon("View Status", theme.VisibilityIcon(), func(){
|
||
|
setMonitorGeneticAnalysisGenerationPage(window, processIdentifier, currentPage, pageToVisitAfter)
|
||
|
}))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, viewStatusButton)
|
||
|
setPageContent(page, window)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Process probably encountered error
|
||
|
// We will show retry page
|
||
|
}
|
||
|
|
||
|
description1 := getBoldLabelCentered("Perform genetic analysis?")
|
||
|
description2 := getLabelCentered("This will create an analysis of the couple's genomes.")
|
||
|
|
||
|
startAnalysisFunction := func(){
|
||
|
|
||
|
newProcessIdentifier, err := myAnalyses.StartCreateNewCoupleGeneticAnalysis(personAIdentifier, personBIdentifier)
|
||
|
if (err != nil){
|
||
|
setErrorEncounteredPage(window, err, previousPage)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
setMonitorGeneticAnalysisGenerationPage(window, newProcessIdentifier, currentPage, pageToVisitAfter)
|
||
|
}
|
||
|
|
||
|
startAnalysisButton := getWidgetCentered(widget.NewButtonWithIcon("Start Analysis", theme.ConfirmIcon(), startAnalysisFunction))
|
||
|
|
||
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, startAnalysisButton)
|
||
|
|
||
|
setPageContent(page, window)
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|