package gui // viewModeratorsGui.go implements a page to browse moderators import "fyne.io/fyne/v2" import "fyne.io/fyne/v2/widget" import "fyne.io/fyne/v2/container" import "fyne.io/fyne/v2/layout" import "fyne.io/fyne/v2/theme" import "fyne.io/fyne/v2/data/binding" import "seekia/internal/appMemory" import "seekia/internal/helpers" import "seekia/internal/identity" import "seekia/internal/moderation/viewedModerators" import "seekia/internal/mySettings" import "seekia/internal/network/appNetworkType/getAppNetworkType" import "seekia/internal/profiles/viewableProfiles" import "time" import "errors" func setViewModeratorsPage(window fyne.Window, previousPage func()){ appMemory.SetMemoryEntry("CurrentViewedPage", "ViewModerators") checkIfPageHasChangedFunction := func()bool{ exists, currentViewedPage := appMemory.GetMemoryEntry("CurrentViewedPage") if (exists == false || currentViewedPage != "ViewModerators"){ return true } return false } //TODO: Check if moderator/host mode is enabled // If not, many attributes cannot be displayed, and the list will be empty/outdated // Require either mode to be enabled to view moderators currentPage := func(){setViewModeratorsPage(window, previousPage)} title := getPageTitleCentered("Viewing Moderators") backButton := getBackButtonCentered(previousPage) filtersIcon, err := getFyneImageIcon("Desires") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } filtersButton := widget.NewButton("Filters", func(){ //TODO showUnderConstructionDialog(window) }) filtersButtonWithIcon := container.NewGridWithRows(2, filtersIcon, filtersButton) statsIcon, err := getFyneImageIcon("Stats") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } statsButton := widget.NewButton("Stats", func(){ //TODO showUnderConstructionDialog(window) }) statsButtonWithIcon := container.NewGridWithRows(2, statsIcon, statsButton) contactsIcon, err := getFyneImageIcon("Contacts") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } contactsButton := widget.NewButton("Contacts", func(){ setMyContactsPage(window, "Moderator", currentPage) }) contactsButtonWithIcon := container.NewGridWithRows(2, contactsIcon, contactsButton) controversyIcon, err := getFyneImageIcon("Controversy") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } controversyButton := widget.NewButton("Controversy", func(){ //TODO: A page to tune the controversy calculation showUnderConstructionDialog(window) }) controversyButtonWithIcon := container.NewGridWithRows(2, controversyIcon, controversyButton) pageButtonsRow := getContainerCentered(container.NewGridWithRows(1, filtersButtonWithIcon, statsButtonWithIcon, contactsButtonWithIcon, controversyButtonWithIcon)) currentSortByAttribute, err := viewedModerators.GetViewedModeratorsSortByAttribute() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } sortingByLabel := getBoldLabel(translate("Sorting By:")) getSortByAttributeTitle := func()string{ if (currentSortByAttribute == "IdentityScore"){ result := translate("Identity Score") return result } if (currentSortByAttribute == "NumberOfReviews"){ result := translate("Number Of Reviews") return result } if (currentSortByAttribute == "BanAdvocates"){ result := translate("Ban Advocates") return result } result := translate(currentSortByAttribute) return result } sortByAttributeTitle := getSortByAttributeTitle() sortByAttributeButton := widget.NewButton(sortByAttributeTitle, func(){ setSelectViewedModeratorsSortByAttributePage(window, currentPage) }) getSortDirectionButtonWithIcon := func()(fyne.Widget, error){ currentSortDirection, err := viewedModerators.GetViewedModeratorsSortDirection() if (err != nil){ return nil, err } if (currentSortDirection == "Ascending"){ button := widget.NewButtonWithIcon(translate("Ascending"), theme.MoveUpIcon(), func(){ appMemory.SetMemoryEntry("StopBuildViewedModeratorsYesNo", "Yes") _ = mySettings.SetSetting("ViewedModeratorsSortDirection", "Descending") _ = mySettings.SetSetting("ViewedModeratorsSortedStatus", "No") _ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0") currentPage() }) return button, nil } button := widget.NewButtonWithIcon(translate("Descending"), theme.MoveDownIcon(), func(){ appMemory.SetMemoryEntry("StopBuildViewedModeratorsYesNo", "Yes") _ = mySettings.SetSetting("ViewedModeratorsSortDirection", "Ascending") _ = mySettings.SetSetting("ViewedModeratorsSortedStatus", "No") _ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0") currentPage() }) return button, nil } sortByDirectionButton, err := getSortDirectionButtonWithIcon() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } sortByRow := container.NewHBox(layout.NewSpacer(), sortingByLabel, sortByAttributeButton, sortByDirectionButton, layout.NewSpacer()) appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } viewedModeratorsReady, err := viewedModerators.GetViewedModeratorsAreReadyStatus(appNetworkType) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } if (viewedModeratorsReady == false){ progressPercentageBinding := binding.NewFloat() sortingStatusBinding := binding.NewString() startUpdateModeratorsAndProgressBarProgress := func(){ err := viewedModerators.StartUpdatingViewedModerators(appNetworkType) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } sortingStatusBindingSet := false var encounteredError error for { pageHasChanged := checkIfPageHasChangedFunction() if (pageHasChanged == true){ appMemory.SetMemoryEntry("StopBuildViewedModeratorsYesNo", "Yes") return } buildEncounteredError, errorEncounteredString, buildIsStopped, viewedModeratorsAreReady, currentPercentageProgress, err := viewedModerators.GetViewedModeratorsBuildStatus(appNetworkType) if (err != nil){ encounteredError = err break } if (buildEncounteredError == true){ encounteredError = errors.New(errorEncounteredString) break } if (buildIsStopped == true){ return } if (viewedModeratorsAreReady == true){ progressPercentageBinding.Set(1) // We wait so that the loading bar will appear complete. time.Sleep(100 * time.Millisecond) currentPage() return } progressPercentageBinding.Set(currentPercentageProgress) if (currentPercentageProgress >= .50 && sortingStatusBindingSet == false){ numberOfModerators, err := viewedModerators.GetNumberOfGeneratedViewedModerators() if (err != nil) { encounteredError = err break } if (numberOfModerators != 0){ numberOfModeratorsString := helpers.ConvertIntToString(numberOfModerators) sortingStatusBinding.Set("Sorting " + numberOfModeratorsString + " Moderators...") } sortingStatusBindingSet = true } time.Sleep(100 * time.Millisecond) } // This will only be reached if an error occurred errorToShow := errors.New("Error encountered while generating viewed moderators: " + encounteredError.Error()) setErrorEncounteredPage(window, errorToShow, currentPage) } loadingLabel := getBoldLabelCentered("Loading Moderators...") loadingBar := getWidgetCentered(widget.NewProgressBarWithData(progressPercentageBinding)) loadingDetailsLabel := widget.NewLabelWithData(sortingStatusBinding) loadingDetailsLabel.TextStyle = getFyneTextStyle_Italic() loadingDetailsLabelCentered := getWidgetCentered(loadingDetailsLabel) page := container.NewVBox(title, backButton, widget.NewSeparator(), pageButtonsRow, widget.NewSeparator(), sortByRow, widget.NewSeparator(), loadingLabel, loadingBar, loadingDetailsLabelCentered) setPageContent(page, window) go startUpdateModeratorsAndProgressBarProgress() return } getResultsContainer := func()(*fyne.Container, error){ getRefreshResultsButtonText := func()(string, error){ needsRefresh, err := viewedModerators.CheckIfViewedModeratorsNeedsRefresh() if (err != nil) { return "", err } if (needsRefresh == false){ return "Refresh Results", nil } return "Refresh Results - Updates Available!", nil } refreshButtonText, err := getRefreshResultsButtonText() if (err != nil){ return nil, err } refreshResultsButton := getWidgetCentered(widget.NewButtonWithIcon(refreshButtonText, theme.ViewRefreshIcon(), func(){ _ = mySettings.SetSetting("ViewedModeratorsGeneratedStatus", "No") _ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0") currentPage() })) listIsReady, currentViewedModeratorsList, err := viewedModerators.GetViewedModeratorsList(appNetworkType) if (err != nil) { return nil, err } if (listIsReady == false){ return nil, errors.New("Viewed moderators list is not ready after earlier status check determined it was.") } numberOfViewedModerators := len(currentViewedModeratorsList) if (numberOfViewedModerators == 0){ noModeratorsFoundLabel := getBoldLabelCentered("No Moderators Found") numberOfFilters, err := viewedModerators.GetNumberOfActiveModeratorFilters() if (err != nil) { return nil, err } if (numberOfFilters == 0){ noModeratorsFoundWithRefreshButton := container.NewVBox(noModeratorsFoundLabel, refreshResultsButton) return noModeratorsFoundWithRefreshButton, nil } numberOfFiltersString := helpers.ConvertIntToString(numberOfFilters) getActiveFiltersText := func()string{ if (numberOfFilters == 1){ return "active filter" } return "active filters" } activeFiltersText := getActiveFiltersText() activeFiltersLabel := getLabelCentered(numberOfFiltersString + " " + activeFiltersText) noModeratorsFoundWithFiltersInfo := container.NewVBox(noModeratorsFoundLabel, activeFiltersLabel, refreshResultsButton) return noModeratorsFoundWithFiltersInfo, nil } getCurrentViewIndex := func()(int, error){ exists, viewIndexString, err := mySettings.GetSetting("ViewedModeratorsViewIndex") if (err != nil) { return 0, err } if (exists == false){ return 0, nil } viewIndex, err := helpers.ConvertStringToInt(viewIndexString) if (err != nil || viewIndex < 0) { return 0, nil } maximumViewIndex := numberOfViewedModerators-1 if (viewIndex > maximumViewIndex){ return maximumViewIndex, nil } return viewIndex, nil } viewIndex, err := getCurrentViewIndex() if (err != nil) { return nil, err } getNavigateToBeginningButton := func()fyne.Widget{ if (numberOfViewedModerators <= 5 || viewIndex == 0){ emptyButton := widget.NewButton(" ", nil) return emptyButton } goToBeginningButton := widget.NewButtonWithIcon("", theme.MediaSkipPreviousIcon(), func(){ _ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0") currentPage() }) return goToBeginningButton } getNavigateToEndButton := func()fyne.Widget{ emptyButton := widget.NewButton(" ", nil) if (numberOfViewedModerators <= 5){ return emptyButton } finalPageMinimumIndex := numberOfViewedModerators - 5 if (viewIndex >= finalPageMinimumIndex){ return emptyButton } goToEndButton := widget.NewButtonWithIcon("", theme.MediaSkipNextIcon(), func(){ finalPageIndexString := helpers.ConvertIntToString(finalPageMinimumIndex) _ = mySettings.SetSetting("ViewedModeratorsViewIndex", finalPageIndexString) currentPage() }) return goToEndButton } getNavigateLeftButton := func()fyne.Widget{ if (numberOfViewedModerators <= 5 || viewIndex == 0){ emptyButton := widget.NewButton(" ", nil) return emptyButton } leftButton := widget.NewButtonWithIcon("", theme.NavigateBackIcon(), func(){ newIndex := helpers.ConvertIntToString(viewIndex-5) _ = mySettings.SetSetting("ViewedModeratorsViewIndex", newIndex) currentPage() }) return leftButton } getNavigateRightButton := func()fyne.Widget{ emptyButton := widget.NewButton(" ", nil) if (numberOfViewedModerators <= 5){ return emptyButton } finalPageMinimumIndex := numberOfViewedModerators - 5 if (viewIndex >= finalPageMinimumIndex){ return emptyButton } rightButton := widget.NewButtonWithIcon("", theme.NavigateNextIcon(), func(){ newIndex := helpers.ConvertIntToString(viewIndex+5) _ = mySettings.SetSetting("ViewedModeratorsViewIndex", newIndex) currentPage() }) return rightButton } getViewingModeratorsInfoRow := func()*fyne.Container{ numberOfViewedModeratorsString := helpers.ConvertIntToString(numberOfViewedModerators) getModeratorOrModeratorsText := func()string{ if (numberOfViewedModerators == 1){ return "Moderator" } return "Moderators" } moderatorOrModeratorsText := getModeratorOrModeratorsText() numberOfViewedModeratorsLabel := getBoldLabel("Viewing " + numberOfViewedModeratorsString + " " + moderatorOrModeratorsText) if (numberOfViewedModerators <= 5){ viewingModeratorsInfoRow := getWidgetCentered(numberOfViewedModeratorsLabel) return viewingModeratorsInfoRow } navigateToBeginningButton := getNavigateToBeginningButton() navigateToEndButton := getNavigateToEndButton() navigateLeftButton := getNavigateLeftButton() navigateRightButton := getNavigateRightButton() viewingModeratorsInfoRow := container.NewHBox(layout.NewSpacer(), navigateToBeginningButton, navigateLeftButton, numberOfViewedModeratorsLabel, navigateRightButton, navigateToEndButton, layout.NewSpacer()) return viewingModeratorsInfoRow } viewingModeratorsInfoRow := getViewingModeratorsInfoRow() moderatorResultsContainer := container.NewVBox() if (viewIndex == 0){ moderatorResultsContainer.Add(refreshResultsButton) moderatorResultsContainer.Add(widget.NewSeparator()) } emptyLabelA := widget.NewLabel("") nameLabel := getItalicLabelCentered("Name") identityHashTitle := getItalicLabelCentered("Identity Hash") featuredAttributeTitle := getItalicLabelCentered(sortByAttributeTitle) emptyLabelB := widget.NewLabel("") resultIndexColumn := container.NewVBox(emptyLabelA, widget.NewSeparator()) nameColumn := container.NewVBox(nameLabel, widget.NewSeparator()) identityHashColumn := container.NewVBox(identityHashTitle, widget.NewSeparator()) featuredAttributeColumn := container.NewVBox(featuredAttributeTitle, widget.NewSeparator()) viewButtonsColumn := container.NewVBox(emptyLabelB, widget.NewSeparator()) viewIndexOnwardsModeratorIdentityHashesList := currentViewedModeratorsList[viewIndex:] for index, moderatorIdentityHash := range viewIndexOnwardsModeratorIdentityHashesList{ resultIndex := viewIndex + index + 1 resultIndexString := helpers.ConvertIntToString(resultIndex) resultIndexBoldLabel := getBoldLabel(resultIndexString + ".") profileExists, _, getAnyModeratorAttributeFunction, err := viewableProfiles.GetRetrieveAnyNewestViewableUserProfileAttributeFunction(moderatorIdentityHash, appNetworkType, true, true, true) if (err != nil) { return nil, err } if (profileExists == false) { // Profile has been deleted since results were generated continue } getUserName := func()(string, error){ exists, _, username, err := getAnyModeratorAttributeFunction("Username") if (err != nil) { return "", err } if (exists == false) { return "Anonymous", nil } theirUsernameTrimmed, _, err := helpers.TrimAndFlattenString(username, 15) if (err != nil) { return "", err } return theirUsernameTrimmed, nil } currentTheirUsername, err := getUserName() if (err != nil) { return nil, err } userNameLabel := getBoldLabelCentered(currentTheirUsername) moderatorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash) if (err != nil) { return nil, err } theirIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(moderatorIdentityHashString, 10) if (err != nil) { return nil, err } theirIdentityHashLabel := getBoldLabelCentered(theirIdentityHashTrimmed) getFeaturedAttributeValue := func()(string, error){ exists, _, featuredAttributeValue, err := getAnyModeratorAttributeFunction(currentSortByAttribute) if (err != nil) { return "", err } if (exists == false){ return "Unknown", nil } return featuredAttributeValue, nil } featuredAttributeValue, err := getFeaturedAttributeValue() if (err != nil) { return nil, err } featuredAttributeValueLabel := getBoldLabelCentered(featuredAttributeValue) viewModeratorButton := widget.NewButtonWithIcon("View", theme.VisibilityIcon(), func(){ setViewModeratorDetailsPage(window, moderatorIdentityHash, currentPage) }) resultIndexColumn.Add(resultIndexBoldLabel) nameColumn.Add(userNameLabel) identityHashColumn.Add(theirIdentityHashLabel) featuredAttributeColumn.Add(featuredAttributeValueLabel) viewButtonsColumn.Add(viewModeratorButton) resultIndexColumn.Add(widget.NewSeparator()) nameColumn.Add(widget.NewSeparator()) identityHashColumn.Add(widget.NewSeparator()) featuredAttributeColumn.Add(widget.NewSeparator()) viewButtonsColumn.Add(widget.NewSeparator()) if (index >= 4){ break } } moderatorResultsGrid := container.NewHBox(layout.NewSpacer(), resultIndexColumn, nameColumn, identityHashColumn, featuredAttributeColumn, viewButtonsColumn, layout.NewSpacer()) moderatorResultsContainer.Add(moderatorResultsGrid) viewedModeratorContainerScrollable := container.NewVScroll(moderatorResultsContainer) viewedModeratorContainerBoxed := getWidgetBoxed(viewedModeratorContainerScrollable) resultsContainer := container.NewBorder(viewingModeratorsInfoRow, nil, nil, nil, viewedModeratorContainerBoxed) return resultsContainer, nil } resultsContainer, err := getResultsContainer() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } header := container.NewVBox(title, backButton, widget.NewSeparator(), pageButtonsRow, widget.NewSeparator(), sortByRow, widget.NewSeparator()) page := container.NewBorder(header, nil, nil, nil, resultsContainer) setPageContent(page, window) } func setSelectViewedModeratorsSortByAttributePage(window fyne.Window, previousPage func()){ appMemory.SetMemoryEntry("CurrentViewedPage", "ViewedModeratorsSortBySelect") title := getPageTitleCentered("Select Sort By Attribute") backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Choose the attribute to sort the moderators by.") getSelectButton := func(attributeTitle string, attributeName string, sortDirection string) fyne.Widget{ button := widget.NewButton(attributeTitle, func(){ _ = mySettings.SetSetting("ViewedModeratorsSortedStatus", "No") _ = mySettings.SetSetting("ViewedModeratorsSortByAttribute", attributeName) _ = mySettings.SetSetting("ViewedModeratorsSortDirection", sortDirection) _ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0") previousPage() }) return button } identityScoreButton := getSelectButton("Identity Score", "IdentityScore", "Ascending") banAdvocatesButton := getSelectButton("Ban Advocates", "BanAdvocates", "Descending") controversyButton := getSelectButton("Controversy", "Controversy", "Ascending") numberOfReviewsButton := getSelectButton("Number Of Reviews", "NumberOfReviews", "Descending") buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, identityScoreButton, banAdvocatesButton, controversyButton, numberOfReviewsButton)) content := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), buttonsGrid) setPageContent(content, window) }