2024-04-11 15:51:56 +02:00
package gui
// moderatorGui.go implements pages for moderators to review and browse content and identities, and to manage their own reviews.
//TODO: Add moderate full profiles page
//TODO: Add page to view my hidden content
import "fyne.io/fyne/v2"
import "fyne.io/fyne/v2/canvas"
import "fyne.io/fyne/v2/container"
import "fyne.io/fyne/v2/dialog"
import "fyne.io/fyne/v2/layout"
import "fyne.io/fyne/v2/theme"
import "fyne.io/fyne/v2/widget"
import "seekia/internal/appMemory"
import "seekia/internal/badgerDatabase"
import "seekia/internal/contentMetadata"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import "seekia/internal/imagery"
import "seekia/internal/messaging/chatMessageStorage"
import "seekia/internal/moderation/bannedModeratorConsensus"
import "seekia/internal/moderation/moderatorRanking"
import "seekia/internal/moderation/myHiddenContent"
import "seekia/internal/moderation/myIdentityScore"
import "seekia/internal/moderation/myReviews"
import "seekia/internal/moderation/mySkippedContent"
import "seekia/internal/moderation/myUnreviewed"
import "seekia/internal/moderation/readReviews"
import "seekia/internal/moderation/reportStorage"
import "seekia/internal/moderation/reviewStorage"
import "seekia/internal/moderation/verifiedVerdict"
import "seekia/internal/myIdentity"
import "seekia/internal/mySettings"
import "seekia/internal/network/appNetworkType/getAppNetworkType"
import "seekia/internal/network/backgroundDownloads"
import "seekia/internal/profiles/attributeDisplay"
import "seekia/internal/profiles/calculatedAttributes"
import "seekia/internal/profiles/myProfileStatus"
import "seekia/internal/profiles/profileFormat"
import "seekia/internal/profiles/profileStorage"
import "seekia/internal/profiles/readProfiles"
import "slices"
import "bytes"
import "strings"
import "time"
import "errors"
func setModeratePage ( window fyne . Window , previousPageExists bool , previousPage func ( ) ) {
appMemory . SetMemoryEntry ( "CurrentViewedPage" , "Moderate" )
currentPage := func ( ) { setModeratePage ( window , previousPageExists , previousPage ) }
homePage := func ( ) { setHomePage ( window ) }
title := getPageTitleCentered ( "Moderate" )
page := container . NewVBox ( title )
if ( previousPageExists == true ) {
backButton := getBackButtonCentered ( previousPage )
page . Add ( backButton )
}
page . Add ( widget . NewSeparator ( ) )
description := getLabelCentered ( "Be a Seekia moderator." )
page . Add ( description )
page . Add ( widget . NewSeparator ( ) )
rulesIcon , err := getFyneImageIcon ( "Info" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
profileIcon , err := getFyneImageIcon ( "Profile" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
settingsIcon , err := getFyneImageIcon ( "Settings" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
moderatorsIcon , err := getFyneImageIcon ( "Users" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
statsIcon , err := getFyneImageIcon ( "Stats" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
contentIcon , err := getFyneImageIcon ( "Choice" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
manageProfileButton := widget . NewButton ( "Profile" , func ( ) {
setProfilePage ( window , true , "Moderator" , true , currentPage )
} )
manageProfileButtonWithIcon := container . NewGridWithColumns ( 1 , profileIcon , manageProfileButton )
moderatorSettingsButton := widget . NewButton ( "Settings" , func ( ) {
setModeratorSettingsPage ( window , currentPage )
} )
moderatorSettingsButtonWithIcon := container . NewGridWithColumns ( 1 , settingsIcon , moderatorSettingsButton )
rulesButton := widget . NewButton ( "Rules" , func ( ) {
setViewSeekiaRulesPage ( window , currentPage )
//TODO: Create a rules page for moderators, explaining how to be a moderator
} )
rulesButtonWithIcon := container . NewGridWithColumns ( 1 , rulesIcon , rulesButton )
moderatorsButton := widget . NewButton ( "Mods" , func ( ) {
setViewModeratorsPage ( window , currentPage )
} )
moderatorsButtonWithIcon := container . NewGridWithColumns ( 1 , moderatorsIcon , moderatorsButton )
statsButton := widget . NewButton ( "Stats" , func ( ) {
// TODO: Page to show statistics about the user's moderator reviews, and moderation statistics of the entire network
// Example: Unreviewed profiles, number of banned profiles, and more
showUnderConstructionDialog ( window )
} )
statsButtonWithIcon := container . NewGridWithColumns ( 1 , statsIcon , statsButton )
contentButton := widget . NewButton ( "Content" , func ( ) {
setBrowseContentPage ( window , currentPage )
} )
contentButtonWithIcon := container . NewGridWithColumns ( 1 , contentIcon , contentButton )
buttonsRow := getContainerCentered ( container . NewGridWithRows ( 1 , rulesButtonWithIcon , manageProfileButtonWithIcon , moderatorSettingsButtonWithIcon , moderatorsButtonWithIcon , statsButtonWithIcon , contentButtonWithIcon ) )
page . Add ( buttonsRow )
page . Add ( widget . NewSeparator ( ) )
exists , moderatorModeStatus , err := mySettings . GetSetting ( "ModeratorModeOnOffStatus" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
if ( exists == false || moderatorModeStatus == "Off" ) {
description1 := getBoldLabelCentered ( "You must enable moderator mode to moderate." )
description2 := getLabelCentered ( "Enable it on the Settings page." )
page . Add ( description1 )
page . Add ( description2 )
setPageContent ( page , window )
return
}
identityExists , myIdentityHash , err := myIdentity . GetMyIdentityHash ( "Moderator" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
if ( identityExists == false ) {
description1 := getBoldLabelCentered ( "Your moderator identity does not exist." )
description2 := getLabelCentered ( "You must choose an identity." )
description3 := getLabelCentered ( "This is how users of Seekia will identify you." )
chooseIdentityButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Choose Identity" , theme . NavigateNextIcon ( ) , func ( ) {
setChooseNewIdentityHashPage ( window , "Moderator" , currentPage , currentPage )
} ) )
page . Add ( description1 )
page . Add ( description2 )
page . Add ( description3 )
page . Add ( chooseIdentityButton )
setPageContent ( page , window )
return
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
identityExists , iAmOnlineStatus , err := myProfileStatus . GetMyProfileIsActiveStatus ( myIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
if ( identityExists == false ) {
setErrorEncounteredPage ( window , errors . New ( "My identity not found after being found already." ) , homePage )
return
}
if ( iAmOnlineStatus == false ) {
description1 := getBoldLabelCentered ( "Your Moderator profile is offline." )
description2 := getLabelCentered ( "Broadcast your profile on the Profile - Broadcast page." )
page . Add ( description1 )
page . Add ( description2 )
setPageContent ( page , window )
return
}
//TODO: Check for moderation parameters
moderateDescriptionA := getBoldLabelCentered ( "You are ready to moderate." )
moderateDescriptionB := getLabelCentered ( "Choose the type of content to moderate." )
page . Add ( moderateDescriptionA )
page . Add ( moderateDescriptionB )
page . Add ( widget . NewSeparator ( ) )
mateIcon , err := getFyneImageIcon ( "Mate" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
mateButton := widget . NewButton ( "Mate Profiles" , func ( ) {
setChooseProfileContentToModeratePage ( window , "Mate" , currentPage )
} )
mateColumn := container . NewGridWithColumns ( 1 , mateIcon , mateButton )
hostIcon , err := getFyneImageIcon ( "Host" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
hostButton := widget . NewButton ( "Host Profiles" , func ( ) {
setChooseProfileContentToModeratePage ( window , "Host" , currentPage )
} )
hostColumn := container . NewGridWithColumns ( 1 , hostIcon , hostButton )
moderatorIcon , err := getFyneImageIcon ( "Moderate" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
moderatorButton := widget . NewButton ( "Moderator Profiles" , func ( ) {
setChooseProfileContentToModeratePage ( window , "Moderator" , currentPage )
} )
moderatorColumn := container . NewGridWithColumns ( 1 , moderatorIcon , moderatorButton )
profilesRow := getContainerCentered ( container . NewGridWithRows ( 1 , mateColumn , hostColumn , moderatorColumn ) )
page . Add ( profilesRow )
textMessagesImage , err := getFyneImageIcon ( "InspectText" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
textMessagesButton := widget . NewButton ( "Text Messages" , func ( ) {
setModerateMessagesPage ( window , "Text" , false , [ 26 ] byte { } , currentPage )
} )
textMessagesColumn := container . NewGridWithColumns ( 1 , textMessagesImage , textMessagesButton )
imageMessagesIcon , err := getFyneImageIcon ( "Photo" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
imageMessagesButton := widget . NewButton ( "Image Messages" , func ( ) {
setModerateMessagesPage ( window , "Image" , false , [ 26 ] byte { } , currentPage )
} )
imageMessagesColumn := container . NewGridWithColumns ( 1 , imageMessagesIcon , imageMessagesButton )
messageButtonsRow := getContainerCentered ( container . NewGridWithRows ( 1 , textMessagesColumn , imageMessagesColumn ) )
page . Add ( messageButtonsRow )
identitiesIcon , err := getFyneImageIcon ( "Profile" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , homePage )
return
}
identitiesButton := widget . NewButton ( "Identities" , func ( ) {
setModerateIdentitiesPage ( window , currentPage )
} )
identitiesColumn := getContainerCentered ( container . NewGridWithColumns ( 1 , identitiesIcon , identitiesButton ) )
page . Add ( identitiesColumn )
setPageContent ( page , window )
}
func setChooseProfileContentToModeratePage ( window fyne . Window , profileType string , previousPage func ( ) ) {
setLoadingScreen ( window , "Moderate " + profileType + " Profiles" , "Loading profiles..." )
currentPage := func ( ) { setChooseProfileContentToModeratePage ( window , profileType , previousPage ) }
title := getPageTitleCentered ( "Moderate " + profileType + " Profiles" )
backButton := getBackButtonCentered ( previousPage )
//TODO: Check if we are moderating profiles of this profileType
description := getLabelCentered ( "Choose a profile attribute to moderate (under construction)." )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
moderateFullProfilesButton := getWidgetCentered ( widget . NewButton ( "Moderate Full Profiles" , func ( ) {
//TODO: A page to moderate full profiles, which have at least 1 full profile ban.
// This page will show profiles whose full profile has been banned.
// This is necessary, because profiles which have been fully banned must be fully approved to undo the effect of the ban.
// Approving all of the profile's attributes individually is cumbersome, and takes up more space in the form of reviews.
// Also, viewing a full profile is necessary when the full profile has been banned, because
// whatever is unruleful about the profile can't be isolated to a single attribute.
// If it could be isolated to a single attribute, the moderator would have banned that attribute, not the full profile
// The exception is with malicious moderators, who could abuse this feature to waste
// the time of moderators by banning many full profiles.
showUnderConstructionDialog ( window )
} ) )
nameLabel := getItalicLabelCentered ( "Name" )
isCanonicalLabel := getItalicLabelCentered ( "Is Canonical" )
anyUnreviewedLabel := getItalicLabelCentered ( "Any Unreviewed?" )
emptyLabel := widget . NewLabel ( "" )
attributeNamesColumn := container . NewVBox ( nameLabel , widget . NewSeparator ( ) )
attributeIsCanonicalColumn := container . NewVBox ( isCanonicalLabel , widget . NewSeparator ( ) )
anyUnreviewedExistColumn := container . NewVBox ( anyUnreviewedLabel , widget . NewSeparator ( ) )
viewAttributeButtonsColumn := container . NewVBox ( emptyLabel , widget . NewSeparator ( ) )
addAttributeRow := func ( attributeName string , attributeIsCanonical bool , attributeIdentifier int ) error {
attributeIsCanonicalString := helpers . ConvertBoolToYesOrNoString ( attributeIsCanonical )
anyExist , _ , _ , _ , err := myUnreviewed . GetMyHighestPriorityUnreviewedProfileAttributeHash ( profileType , attributeIdentifier , appNetworkType )
if ( err != nil ) { return err }
getAnyUnreviewedExistLabel := func ( ) * fyne . Container {
if ( anyExist == false ) {
noLabel := getLabelCentered ( translate ( "No" ) )
return noLabel
}
yesLabel := getBoldLabelCentered ( translate ( "Yes" ) )
return yesLabel
}
anyUnreviewedExistLabel := getAnyUnreviewedExistLabel ( )
attributeNameLabel := getBoldLabelCentered ( attributeName )
attributeIsCanonicalLabel := getBoldLabelCentered ( attributeIsCanonicalString )
viewAttributeButton := widget . NewButtonWithIcon ( "" , theme . NavigateNextIcon ( ) , func ( ) {
setModerateProfileAttributesPage ( window , profileType , attributeIdentifier , false , [ 27 ] byte { } , [ 28 ] byte { } , [ 16 ] byte { } , currentPage )
} )
attributeNamesColumn . Add ( attributeNameLabel )
attributeIsCanonicalColumn . Add ( attributeIsCanonicalLabel )
anyUnreviewedExistColumn . Add ( anyUnreviewedExistLabel )
viewAttributeButtonsColumn . Add ( viewAttributeButton )
attributeNamesColumn . Add ( widget . NewSeparator ( ) )
attributeIsCanonicalColumn . Add ( widget . NewSeparator ( ) )
anyUnreviewedExistColumn . Add ( widget . NewSeparator ( ) )
viewAttributeButtonsColumn . Add ( widget . NewSeparator ( ) )
return nil
}
addAttributeRows := func ( ) error {
if ( profileType == "Mate" ) {
err := addAttributeRow ( "Photos" , false , 18 )
if ( err != nil ) { return err }
}
err := addAttributeRow ( "Username" , false , 10 )
if ( err != nil ) { return err }
err = addAttributeRow ( "Description" , false , 9 )
if ( err != nil ) { return err }
if ( profileType == "Mate" ) {
err := addAttributeRow ( "Age" , true , 8 )
if ( err != nil ) { return err }
err = addAttributeRow ( "Sex" , true , 7 )
if ( err != nil ) { return err }
err = addAttributeRow ( "Height" , true , 6 )
if ( err != nil ) { return err }
}
//TODO: Add more attributes
return nil
}
err = addAttributeRows ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
isCanonicalHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setAttributeIsCanonicalExplainerPage ( window , currentPage )
} )
anyUnreviewedExistHelpButton := widget . NewButtonWithIcon ( "" , theme . QuestionIcon ( ) , func ( ) {
setAnyUnreviewedAttributesExistExplainerPage ( window , currentPage )
} )
attributeIsCanonicalColumn . Add ( isCanonicalHelpButton )
anyUnreviewedExistColumn . Add ( anyUnreviewedExistHelpButton )
attributeGrid := container . NewHBox ( layout . NewSpacer ( ) , attributeNamesColumn , attributeIsCanonicalColumn , anyUnreviewedExistColumn , viewAttributeButtonsColumn , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , moderateFullProfilesButton , widget . NewSeparator ( ) , attributeGrid )
setPageContent ( page , window )
}
// This page is used by a moderator to browse their unreviewed profile attributes, review the content, and submit a verdict
// It provides skip and hide buttons, and serve new attributes to review to the moderator
func setModerateProfileAttributesPage ( window fyne . Window , profileType string , attributeIdentifier int , attributeProvided bool , attributeHash [ 27 ] byte , attributeProfileHash [ 28 ] byte , attributeAuthorIdentityHash [ 16 ] byte , previousPage func ( ) ) {
setLoadingScreen ( window , "Moderating Attributes" , "Loading attribute..." )
currentPage := func ( ) { setModerateProfileAttributesPage ( window , profileType , attributeIdentifier , attributeProvided , attributeHash , attributeProfileHash , attributeAuthorIdentityHash , previousPage ) }
refreshPageWithNewContent := func ( ) { setModerateProfileAttributesPage ( window , profileType , attributeIdentifier , false , [ 27 ] byte { } , [ 28 ] byte { } , [ 16 ] byte { } , previousPage ) }
title := getPageTitleCentered ( "Moderating Attributes" )
backButton := getBackButtonCentered ( previousPage )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( attributeProvided == false ) {
attributeExists , newAttributeHash , newAttributeProfileHash , newAttributeAuthorIdentityHash , err := myUnreviewed . GetMyHighestPriorityUnreviewedProfileAttributeHash ( profileType , attributeIdentifier , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( attributeExists == false ) {
attributeName , err := profileFormat . GetAttributeNameFromAttributeIdentifier ( attributeIdentifier )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
description1 := getBoldLabelCentered ( "No " + attributeName + " attributes remaining to moderate." )
description2 := getLabelCentered ( "Check back later for new attributes to review." )
//TODO: Add check for if space is full, and add description to say to increase space allowed for moderation content
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 )
setPageContent ( page , window )
return
}
setModerateProfileAttributesPage ( window , profileType , attributeIdentifier , true , newAttributeHash , newAttributeProfileHash , newAttributeAuthorIdentityHash , previousPage )
return
}
viewAttributeDetailsButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Attribute Details" , theme . VisibilityIcon ( ) , func ( ) {
setViewAttributeModerationDetailsPage ( window , attributeHash , currentPage )
} ) )
profileExists , profileBytes , err := profileStorage . GetStoredProfile ( attributeProfileHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( profileExists == false ) {
// Profile must have been deleted after myUnreviewed found it
// We will refresh page and show loading screen so we can tell if this is happening
setLoadingScreen ( window , "Moderating Attributes" , "Trying to find attribute..." )
time . Sleep ( time . Second )
refreshPageWithNewContent ( )
return
}
attributeName , err := profileFormat . GetAttributeNameFromAttributeIdentifier ( attributeIdentifier )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
attributeTitle , _ , _ , _ , _ , err := attributeDisplay . GetProfileAttributeDisplayInfo ( attributeName )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
attributeNameLabel := widget . NewLabel ( "Attribute Name:" )
attributeTitleLabel := getBoldLabel ( attributeTitle )
attributeTitleRow := container . NewHBox ( layout . NewSpacer ( ) , attributeNameLabel , attributeTitleLabel , layout . NewSpacer ( ) )
attributeDisplayContainer , err := getProfileAttributeDisplayForModeration ( window , attributeName , attributeIdentifier , profileBytes , currentPage )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
appNetworkTypeString := helpers . ConvertByteToString ( appNetworkType )
attributeHashHex := encoding . EncodeBytesToHexString ( attributeHash [ : ] )
submitAttributeReview := func ( verdict string , reasonExists bool , reason string ) error {
newReviewMap := map [ string ] string {
"NetworkType" : appNetworkTypeString ,
"ReviewedHash" : attributeHashHex ,
"Verdict" : verdict ,
}
if ( reasonExists == true ) {
newReviewMap [ "Reason" ] = reason
}
myIdentityExists , err := myReviews . CreateAndBroadcastMyReview ( newReviewMap )
if ( err != nil ) { return err }
if ( myIdentityExists == false ) {
return errors . New ( "My moderator identity not found when trying to submit review." )
}
return nil
}
submitBanIdentityReview := func ( reasonExists bool , reason string ) error {
attributeAuthorString , _ , err := identity . EncodeIdentityHashBytesToString ( attributeAuthorIdentityHash )
if ( err != nil ) { return err }
attributeProfileHashHex := encoding . EncodeBytesToHexString ( attributeProfileHash [ : ] )
identityReviewMap := map [ string ] string {
"NetworkType" : appNetworkTypeString ,
"ReviewedHash" : attributeAuthorString ,
"Verdict" : "Ban" ,
"ErrantAttributes" : attributeHashHex ,
"ErrantProfiles" : attributeProfileHashHex ,
}
if ( reasonExists == true ) {
identityReviewMap [ "Reason" ] = reason
}
myIdentityExists , err := myReviews . CreateAndBroadcastMyReview ( identityReviewMap )
if ( err != nil ) { return err }
if ( myIdentityExists == false ) {
return errors . New ( "My moderator identity not found when trying to submit review." )
}
return nil
}
approveAttributeWithReasonFunction := func ( reasonExists bool , reason string ) error {
err := submitAttributeReview ( "Approve" , reasonExists , reason )
if ( err != nil ) { return err }
return nil
}
banAttributeWithReasonFunction := func ( reasonExists bool , reason string ) error {
err := submitAttributeReview ( "Ban" , reasonExists , reason )
if ( err != nil ) { return err }
return nil
}
banAttributeAndIdentityWithReasonFunction := func ( reasonExists bool , reason string ) error {
err := submitAttributeReview ( "Ban" , reasonExists , reason )
if ( err != nil ) { return err }
err = submitBanIdentityReview ( reasonExists , reason )
if ( err != nil ) { return err }
return nil
}
approveAttributeButton := widget . NewButtonWithIcon ( "Approve Attribute" , theme . ConfirmIcon ( ) , func ( ) {
setEnterReasonAndSubmitReviewPage ( window , "Submit Approve Review" , "Approve Attribute" , "Approve" , approveAttributeWithReasonFunction , currentPage , refreshPageWithNewContent )
} )
banAttributeButton := widget . NewButtonWithIcon ( "Ban Attribute" , theme . CancelIcon ( ) , func ( ) {
setEnterReasonAndSubmitReviewPage ( window , "Submit Ban Review" , "Ban Attribute" , "Ban" , banAttributeWithReasonFunction , currentPage , refreshPageWithNewContent )
} )
banAttributeAndIdentityButton := widget . NewButtonWithIcon ( "Ban Attribute And Identity" , theme . CancelIcon ( ) , func ( ) {
setEnterReasonAndSubmitReviewPage ( window , "Submit Ban Reviews" , "Ban Attribute And Identity" , "Ban" , banAttributeAndIdentityWithReasonFunction , currentPage , refreshPageWithNewContent )
} )
reviewButtonsColumn := getContainerCentered ( container . NewGridWithColumns ( 1 , approveAttributeButton , banAttributeButton , banAttributeAndIdentityButton ) )
skipButton := widget . NewButtonWithIcon ( "Skip" , theme . MediaFastForwardIcon ( ) , func ( ) {
// This will skip this attribute. It will be moved to the back of the myUnreviewed queue
err := mySkippedContent . AddAttributeToMySkippedAttributesMap ( attributeHash , attributeAuthorIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , currentPage )
return
}
refreshPageWithNewContent ( )
} )
hideButton := widget . NewButtonWithIcon ( "Hide" , theme . VisibilityOffIcon ( ) , func ( ) {
setConfirmHideContentPage ( window , attributeHash [ : ] , attributeAuthorIdentityHash , currentPage , refreshPageWithNewContent )
} )
skipAndHideButtonsColumn := getContainerCentered ( container . NewGridWithColumns ( 1 , skipButton , hideButton ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , viewAttributeDetailsButton , widget . NewSeparator ( ) , attributeTitleRow , widget . NewSeparator ( ) , attributeDisplayContainer , widget . NewSeparator ( ) , reviewButtonsColumn , widget . NewSeparator ( ) , skipAndHideButtonsColumn )
setPageContent ( page , window )
}
// This page is used by a moderator to browse their unreviewed messages, review their content, and submit a verdict
func setModerateMessagesPage ( window fyne . Window , imageOrText string , messageProvided bool , messageHash [ 26 ] byte , previousPage func ( ) ) {
currentPage := func ( ) { setModerateMessagesPage ( window , imageOrText , messageProvided , messageHash , previousPage ) }
refreshPageWithNewContent := func ( ) { setModerateMessagesPage ( window , imageOrText , false , [ 26 ] byte { } , previousPage ) }
title := getPageTitleCentered ( "Moderating Messages" )
backButton := getBackButtonCentered ( previousPage )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( messageProvided == false ) {
exists , moderatingMessages , err := mySettings . GetSetting ( "ModerateMessagesOnOffStatus" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( exists == false || moderatingMessages != "On" ) {
description1 := getBoldLabelCentered ( "You are not moderating messages." )
description2 := getLabelCentered ( "You must enable message moderation mode." )
enableButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable" , theme . NavigateNextIcon ( ) , func ( ) {
setManageModerateMessagesModePage ( window , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , enableButton )
setPageContent ( page , window )
return
}
setLoadingScreen ( window , "Moderate Messages" , "Loading message..." )
messageExists , newMessageHash , err := myUnreviewed . GetMyHighestPriorityUnreviewedMessageHash ( appNetworkType , imageOrText )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( messageExists == false ) {
description1 := getBoldLabelCentered ( "No messages remain to moderate." )
description2 := getLabelCentered ( "Check back later for new messages." )
//TODO: Add check for if space is full, and add message to say to increase space allowed for moderation content
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 )
setPageContent ( page , window )
return
}
setModerateMessagesPage ( window , imageOrText , true , newMessageHash , previousPage )
return
}
viewMessageDetailsButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Message Details" , theme . VisibilityIcon ( ) , func ( ) {
setViewMessageModerationDetailsPage ( window , messageHash , currentPage )
} ) )
//Outputs:
// -bool: Necessary information found to display message
// -[16]byte: Message author
// -[32]byte: Message cipher key
// -string: Message communication
// -error
getMessageMetadata := func ( ) ( bool , [ 16 ] byte , [ 32 ] byte , string , error ) {
messageExists , cipherKeyFound , ableToDecrypt , messageCipherKey , senderIdentityHash , messageCommunication , err := chatMessageStorage . GetDecryptedMessageForModeration ( messageHash )
if ( err != nil ) { return false , [ 16 ] byte { } , [ 32 ] byte { } , "" , err }
if ( messageExists == false ) {
// We cannot review messages which we do not have downloaded
// Message may have been deleted after earlier check
return false , [ 16 ] byte { } , [ 32 ] byte { } , "" , nil
}
if ( cipherKeyFound == false ) {
// No valid reviews/reports exist for this message.
// myUnreviewed should have checked this before.
// Report could have been deleted.
return false , [ 16 ] byte { } , [ 32 ] byte { } , "" , nil
}
if ( ableToDecrypt == false ) {
// myUnreviewed should have checked for this
return false , [ 16 ] byte { } , [ 32 ] byte { } , "" , errors . New ( "myUnreviewed returning message that cannot be read." )
}
return true , senderIdentityHash , messageCipherKey , messageCommunication , nil
}
messageInfoFound , senderIdentityHash , messageCipherKey , messageCommunication , err := getMessageMetadata ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( messageInfoFound == false ) {
// We will refresh page and show loading screen so we can tell if this is happening
setLoadingScreen ( window , "Moderate Messages" , "Trying to find message..." )
time . Sleep ( time . Second )
refreshPageWithNewContent ( )
return
}
messageContentContainer , err := getMessageDisplayForModeration ( window , messageCommunication , currentPage )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
appNetworkTypeString := helpers . ConvertByteToString ( appNetworkType )
messageHashHex := encoding . EncodeBytesToHexString ( messageHash [ : ] )
submitMessageReview := func ( verdict string , reasonExists bool , reason string ) error {
messageCipherKeyHex := encoding . EncodeBytesToHexString ( messageCipherKey [ : ] )
newReviewMap := map [ string ] string {
"NetworkType" : appNetworkTypeString ,
"ReviewedHash" : messageHashHex ,
"MessageCipherKey" : messageCipherKeyHex ,
"Verdict" : verdict ,
}
if ( reasonExists == true ) {
newReviewMap [ "Reason" ] = reason
}
myIdentityExists , err := myReviews . CreateAndBroadcastMyReview ( newReviewMap )
if ( err != nil ) { return err }
if ( myIdentityExists == false ) {
return errors . New ( "My moderator identity not found when trying to submit review." )
}
return nil
}
submitBanIdentityReview := func ( reasonExists bool , reason string ) error {
senderIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( senderIdentityHash )
if ( err != nil ) { return err }
identityReviewMap := map [ string ] string {
"NetworkType" : appNetworkTypeString ,
"ReviewedHash" : senderIdentityHashString ,
"Verdict" : "Ban" ,
"ErrantMessages" : messageHashHex ,
}
if ( reasonExists == true ) {
identityReviewMap [ "Reason" ] = reason
}
myIdentityExists , err := myReviews . CreateAndBroadcastMyReview ( identityReviewMap )
if ( err != nil ) { return err }
if ( myIdentityExists == false ) {
return errors . New ( "My moderator identity not found when trying to submit review." )
}
return nil
}
approveMessageWithReasonFunction := func ( reasonExists bool , reason string ) error {
err := submitMessageReview ( "Approve" , reasonExists , reason )
if ( err != nil ) { return err }
return nil
}
banMessageWithReasonFunction := func ( reasonExists bool , reason string ) error {
err := submitMessageReview ( "Ban" , reasonExists , reason )
if ( err != nil ) { return err }
return nil
}
banMessageAndIdentityWithReasonFunction := func ( reasonExists bool , reason string ) error {
err := submitMessageReview ( "Ban" , reasonExists , reason )
if ( err != nil ) { return err }
err = submitBanIdentityReview ( reasonExists , reason )
if ( err != nil ) { return err }
return nil
}
approveMessageButton := widget . NewButtonWithIcon ( "Approve Message" , theme . ConfirmIcon ( ) , func ( ) {
setEnterReasonAndSubmitReviewPage ( window , "Submit Approve Review" , "Approve Message" , "Approve" , approveMessageWithReasonFunction , currentPage , refreshPageWithNewContent )
} )
banMessageButton := widget . NewButtonWithIcon ( "Ban Message" , theme . CancelIcon ( ) , func ( ) {
setEnterReasonAndSubmitReviewPage ( window , "Submit Ban Review" , "Ban Message" , "Ban" , banMessageWithReasonFunction , currentPage , refreshPageWithNewContent )
} )
banMessageAndSenderButton := widget . NewButtonWithIcon ( "Ban Message And Sender" , theme . CancelIcon ( ) , func ( ) {
setEnterReasonAndSubmitReviewPage ( window , "Submit Ban Reviews" , "Ban Message and Sender" , "Ban" , banMessageAndIdentityWithReasonFunction , currentPage , refreshPageWithNewContent )
} )
reviewButtonsColumn := getContainerCentered ( container . NewGridWithColumns ( 1 , approveMessageButton , banMessageButton , banMessageAndSenderButton ) )
skipButton := widget . NewButtonWithIcon ( "Skip" , theme . MediaFastForwardIcon ( ) , func ( ) {
// This will skip this attribute. It will be moved to the back of the myUnreviewed queue
err := mySkippedContent . AddMessageToMySkippedMessagesMap ( messageHash , senderIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , currentPage )
return
}
refreshPageWithNewContent ( )
} )
hideButton := widget . NewButtonWithIcon ( "Hide" , theme . VisibilityOffIcon ( ) , func ( ) {
setConfirmHideContentPage ( window , messageHash [ : ] , senderIdentityHash , currentPage , refreshPageWithNewContent )
} )
skipAndHideButtonsColumn := getContainerCentered ( container . NewGridWithColumns ( 1 , skipButton , hideButton ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , viewMessageDetailsButton , widget . NewSeparator ( ) , messageContentContainer , widget . NewSeparator ( ) , reviewButtonsColumn , widget . NewSeparator ( ) , skipAndHideButtonsColumn )
setPageContent ( page , window )
}
// This will hide the profile/message/attribute permanently so it does not show up anymore
// This is useful if the content is in a language the user does not understand
func setConfirmHideContentPage ( window fyne . Window , contentHash [ ] byte , authorIdentityHash [ 16 ] byte , previousPage func ( ) , pageToVisitAfter func ( ) ) {
currentPage := func ( ) { setConfirmHideContentPage ( window , contentHash , authorIdentityHash , previousPage , pageToVisitAfter ) }
contentType , err := helpers . GetContentTypeFromContentHash ( contentHash )
if ( err != nil ) {
contentHashHex := encoding . EncodeBytesToHexString ( contentHash )
setErrorEncounteredPage ( window , errors . New ( "setConfirmHideContentPage called with invalid contentHash: " + contentHashHex ) , previousPage )
return
}
if ( contentType != "Message" && contentType != "Profile" && contentType != "Attribute" ) {
contentHashHex := encoding . EncodeBytesToHexString ( contentHash )
setErrorEncounteredPage ( window , errors . New ( "setConfirmHideContentPage called with invalid contentHash: " + contentHashHex ) , previousPage )
return
}
title := getPageTitleCentered ( "Confirm Hide " + contentType )
backButton := getBackButtonCentered ( previousPage )
description1 := getBoldLabelCentered ( "Confirm Hide " + contentType + "?" )
description2 := getLabelCentered ( "This will prevent this " + contentType + " from showing up in your moderation queue." )
description3 := getLabelCentered ( "This is useful when you don't want to review the " + contentType + "." )
description4 := getLabelCentered ( "For example, the " + contentType + " may be written in a language you don't understand." )
confirmButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Confirm" , theme . ConfirmIcon ( ) , func ( ) {
if ( contentType == "Message" ) {
if ( len ( contentHash ) != 26 ) {
contentHashHex := encoding . EncodeBytesToHexString ( contentHash )
setErrorEncounteredPage ( window , errors . New ( "GetContentTypeFromContentHash returning Message for different length content hash: " + contentHashHex ) , currentPage )
return
}
messageHash := [ 26 ] byte ( contentHash )
err := myHiddenContent . AddMessageToMyHiddenMessagesMap ( messageHash , authorIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , currentPage )
return
}
} else if ( contentType == "Profile" ) {
if ( len ( contentHash ) != 28 ) {
contentHashHex := encoding . EncodeBytesToHexString ( contentHash )
setErrorEncounteredPage ( window , errors . New ( "GetContentTypeFromContentHash returning Profile for different length content hash: " + contentHashHex ) , currentPage )
return
}
profileHash := [ 28 ] byte ( contentHash )
err := myHiddenContent . AddProfileToMyHiddenProfilesMap ( profileHash , authorIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , currentPage )
return
}
} else if ( contentType == "Attribute" ) {
if ( len ( contentHash ) != 27 ) {
contentHashHex := encoding . EncodeBytesToHexString ( contentHash )
setErrorEncounteredPage ( window , errors . New ( "GetContentTypeFromContentHash returning Attribute for different length content hash: " + contentHashHex ) , currentPage )
return
}
attributeHash := [ 27 ] byte ( contentHash )
err := myHiddenContent . AddAttributeToMyHiddenAttributesMap ( attributeHash , authorIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , currentPage )
return
}
}
pageToVisitAfter ( )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , confirmButton )
setPageContent ( page , window )
}
func setEnterReasonAndSubmitReviewPage ( window fyne . Window , pageTitle string , actionName string , verdict string , submitFunctionWithReason func ( bool , string ) error , previousPage func ( ) , pageToVisitAfter func ( ) ) {
title := getPageTitleCentered ( pageTitle )
backButton := getBackButtonCentered ( previousPage )
actionLabel := getItalicLabelCentered ( "Action:" )
actionDescription := getBoldLabelCentered ( actionName )
enterReasonLabel := getLabelCentered ( "Enter " + verdict + " Reason (Optional):" )
reasonEntry := widget . NewMultiLineEntry ( )
reasonEntry . SetPlaceHolder ( "Enter reason..." )
reasonEntryBoxed := getWidgetBoxed ( reasonEntry )
submitButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Submit" , theme . ConfirmIcon ( ) , func ( ) {
reason := reasonEntry . Text
if ( reason == "" ) {
err := submitFunctionWithReason ( false , "" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
} else {
err := submitFunctionWithReason ( true , reason )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
}
pageToVisitAfter ( )
} ) )
widener := widget . NewLabel ( " " )
submitButtonWithWidener := container . NewGridWithColumns ( 1 , submitButton , widener )
entryWithSubmitButton := getContainerCentered ( container . NewGridWithColumns ( 1 , reasonEntryBoxed , submitButtonWithWidener ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , actionLabel , actionDescription , widget . NewSeparator ( ) , enterReasonLabel , entryWithSubmitButton )
setPageContent ( page , window )
}
func setViewProfileForModerationPage ( window fyne . Window , profileHash [ 28 ] byte , previousPage func ( ) ) {
currentPage := func ( ) { setViewProfileForModerationPage ( window , profileHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Profile" )
backButton := getBackButtonCentered ( previousPage )
profileHashTitle := widget . NewLabel ( "Profile Hash:" )
profileHashHex := encoding . EncodeBytesToHexString ( profileHash [ : ] )
profileHashTrimmed , _ , err := helpers . TrimAndFlattenString ( profileHashHex , 10 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
profileHashLabel := getBoldLabel ( profileHashTrimmed )
viewProfileHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewContentHashPage ( window , "Profile" , profileHash [ : ] , currentPage )
} )
profileHashRow := container . NewHBox ( layout . NewSpacer ( ) , profileHashTitle , profileHashLabel , viewProfileHashButton , layout . NewSpacer ( ) )
getProfileDisplayContainer := func ( ) ( * fyne . Container , error ) {
profileExists , profileBytes , err := profileStorage . GetStoredProfile ( profileHash )
if ( err != nil ) { return nil , err }
if ( profileExists == false ) {
description1 := getBoldLabelCentered ( "Profile not downloaded." )
description2 := getLabelCentered ( "Try to download?" )
downloadButton := getWidgetCentered ( widget . NewButton ( "Download" , func ( ) {
setDownloadContentFromHashPage ( window , "Profile" , profileHash [ : ] , currentPage )
} ) )
content := container . NewVBox ( description1 , description2 , downloadButton )
return content , nil
}
ableToRead , currentProfileHash , profileVersion , _ , profileIdentityHash , _ , _ , rawProfileMap , err := readProfiles . ReadProfileAndHash ( false , profileBytes )
if ( err != nil ) { return nil , err }
if ( ableToRead == false ) {
return nil , errors . New ( "Database corrupt: Contains invalid profile." )
}
if ( profileHash != currentProfileHash ) {
return nil , errors . New ( "Database corrupt: Profile hash does not match entry key" )
}
profileAuthorLabel := widget . NewLabel ( "Profile Author:" )
profileIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( profileIdentityHash )
if ( err != nil ) { return nil , err }
profileIdentityHashLabel := getBoldLabel ( profileIdentityHashString )
profileIdentityHashRow := container . NewHBox ( layout . NewSpacer ( ) , profileAuthorLabel , profileIdentityHashLabel , layout . NewSpacer ( ) )
getAnyProfileAttributeFunction , err := calculatedAttributes . GetRetrieveAnyProfileAttributeIncludingCalculatedFunction ( profileVersion , rawProfileMap )
if ( err != nil ) { return nil , err }
viewProfileButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Profile" , theme . VisibilityIcon ( ) , func ( ) {
setViewUserProfilePage ( window , false , profileHash , 0 , getAnyProfileAttributeFunction , currentPage )
} ) )
profileDisplayWithInfo := container . NewVBox ( profileIdentityHashRow , viewProfileButton )
return profileDisplayWithInfo , nil
}
profileDisplayContainer , err := getProfileDisplayContainer ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , profileHashRow , profileDisplayContainer )
setPageContent ( page , window )
}
// This page allows a moderator to view a profile attribute value
// It is different from setModerateProfileAttributesPage,
// which allows the moderator to review the attribute, provides skip/hide buttons, and serves
// the next attribute to review
func setViewProfileAttributeForModerationPage ( window fyne . Window , attributeHash [ 27 ] byte , previousPage func ( ) ) {
currentPage := func ( ) { setViewProfileAttributeForModerationPage ( window , attributeHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Profile Attribute" )
backButton := getBackButtonCentered ( previousPage )
attributeHashTitle := widget . NewLabel ( "Attribute Hash:" )
attributeHashHex := encoding . EncodeBytesToHexString ( attributeHash [ : ] )
attributeHashTrimmed , _ , err := helpers . TrimAndFlattenString ( attributeHashHex , 10 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
attributeHashLabel := getBoldLabel ( attributeHashTrimmed )
viewAttributeHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewContentHashPage ( window , "Attribute" , attributeHash [ : ] , currentPage )
} )
attributeHashRow := container . NewHBox ( layout . NewSpacer ( ) , attributeHashTitle , attributeHashLabel , viewAttributeHashButton , layout . NewSpacer ( ) )
// We have to find the profile hash that the attribute belongs to
// If we cannot find any profiles with this attribute, we will offer the user to try to download profiles for this attribute hash
attributeMetadataFound , attributeIdentifier , _ , _ , _ , profileFound , _ , profileBytes , err := profileStorage . GetProfileAttributeMetadataAndProfile ( attributeHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( attributeMetadataFound == false || profileFound == false ) {
description1 := getBoldLabelCentered ( "You do not have this profile attribute downloaded." )
description2 := getLabelCentered ( "Try to download it?" )
description3 := getLabelCentered ( "It may not exist on the network anymore." )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , attributeHashRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
attributeName , err := profileFormat . GetAttributeNameFromAttributeIdentifier ( attributeIdentifier )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
attributeTitle , _ , _ , _ , _ , err := attributeDisplay . GetProfileAttributeDisplayInfo ( attributeName )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
attributeNameLabel := widget . NewLabel ( "Attribute Name:" )
attributeTitleLabel := getBoldLabel ( attributeTitle )
attributeTitleRow := container . NewHBox ( layout . NewSpacer ( ) , attributeNameLabel , attributeTitleLabel , layout . NewSpacer ( ) )
attributeDisplayContainer , err := getProfileAttributeDisplayForModeration ( window , attributeName , attributeIdentifier , profileBytes , currentPage )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , attributeHashRow , widget . NewSeparator ( ) , attributeTitleRow , widget . NewSeparator ( ) , attributeDisplayContainer )
setPageContent ( page , window )
}
func setViewMessageForModerationPage ( window fyne . Window , messageHash [ 26 ] byte , previousPage func ( ) ) {
currentPage := func ( ) { setViewMessageForModerationPage ( window , messageHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Message" )
backButton := getBackButtonCentered ( previousPage )
messageHashHex := encoding . EncodeBytesToHexString ( messageHash [ : ] )
messageHashTitle := widget . NewLabel ( "Message Hash:" )
messageHashTrimmed , _ , err := helpers . TrimAndFlattenString ( messageHashHex , 10 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
messageHashLabel := getBoldLabel ( messageHashTrimmed )
viewMessageHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewContentHashPage ( window , "Message" , messageHash [ : ] , currentPage )
} )
messageHashRow := container . NewHBox ( layout . NewSpacer ( ) , messageHashTitle , messageHashLabel , viewMessageHashButton , layout . NewSpacer ( ) )
messageExists , cipherKeyFound , ableToDecrypt , _ , senderIdentityHash , messageCommunication , err := chatMessageStorage . GetDecryptedMessageForModeration ( messageHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( messageExists == false ) {
description1 := getBoldLabelCentered ( "Message not downloaded." )
description2 := getLabelCentered ( "Try to download?" )
downloadButton := getWidgetCentered ( widget . NewButton ( "Download" , func ( ) {
setDownloadContentFromHashPage ( window , "Message" , messageHash [ : ] , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , description1 , description2 , downloadButton )
setPageContent ( page , window )
return
}
if ( cipherKeyFound == false ) {
// No valid reviews/reports exist for message hash. User can try to download
description1 := getBoldLabelCentered ( "No reviews or reports for message found." )
description2 := getLabelCentered ( "Without a review/report, the contents are encrypted." )
description3 := getLabelCentered ( "Try to download reviews/reports?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , messageHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
if ( ableToDecrypt == false ) {
description1 := getBoldLabelCentered ( "Message is corrupt." )
description2 := getLabelCentered ( "It was created by a malicious user." )
description3 := getLabelCentered ( "It cannot be decrypted." )
description4 := getLabelCentered ( "No moderator should be able to approve it." )
description5 := getLabelCentered ( "Any moderators who have approved the message will be automatically banned." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , description5 )
setPageContent ( page , window )
return
}
senderIdentityHashTitle := widget . NewLabel ( "Sender Identity Hash:" )
senderIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( senderIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
senderIdentityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( senderIdentityHashString , 10 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
senderIdentityHashLabel := getBoldLabel ( senderIdentityHashTrimmed )
viewSenderIdentityHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewIdentityHashPage ( window , senderIdentityHash , currentPage )
} )
senderIdentityHashRow := container . NewHBox ( layout . NewSpacer ( ) , senderIdentityHashTitle , senderIdentityHashLabel , viewSenderIdentityHashButton , layout . NewSpacer ( ) )
messageContentLabel := getBoldItalicLabelCentered ( "Message Content:" )
messageContentContainer , err := getMessageDisplayForModeration ( window , messageCommunication , currentPage )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , senderIdentityHashRow , widget . NewSeparator ( ) , messageContentLabel , messageContentContainer )
setPageContent ( page , window )
}
// This function will return a container to display a profile attribute
func getProfileAttributeDisplayForModeration ( window fyne . Window , attributeName string , attributeIdentifier int , profileBytes [ ] byte , currentPage func ( ) ) ( * fyne . Container , error ) {
ableToRead , _ , _ , _ , _ , profileIsDisabled , rawProfileMap , err := readProfiles . ReadProfile ( false , profileBytes )
if ( err != nil ) { return nil , err }
if ( ableToRead == false ) {
return nil , errors . New ( "getProfileAttributeDisplayForModeration called with invalid profile." )
}
if ( profileIsDisabled == true ) {
return nil , errors . New ( "getProfileAttributeDisplayForModeration called with disabled profile." )
}
exists , attributeValue , err := readProfiles . GetFormattedProfileAttributeFromRawProfileMap ( rawProfileMap , attributeName )
if ( err != nil ) { return nil , err }
if ( exists == false ) {
attributeIdentifierString := helpers . ConvertIntToString ( attributeIdentifier )
return nil , errors . New ( "getProfileAttributeDisplayForModeration called with profile missing attribute: " + attributeIdentifierString )
}
_ , _ , formatValueFunction , attributeUnits , _ , err := attributeDisplay . GetProfileAttributeDisplayInfo ( attributeName )
if ( err != nil ) { return nil , err }
if ( attributeName == "Photos" ) {
photosBase64List := strings . Split ( attributeValue , "+" )
if ( len ( photosBase64List ) == 0 ) {
return nil , errors . New ( "Verified mate profile has an empty photos list" )
}
getNumberOfImagesGridColumns := func ( ) int {
if ( len ( photosBase64List ) == 1 ) {
return 1
}
if ( len ( photosBase64List ) == 2 ) {
return 2
}
return 3
}
numberOfImagesGridColumns := getNumberOfImagesGridColumns ( )
imagesGrid := container . NewGridWithColumns ( numberOfImagesGridColumns )
for _ , base64Photo := range photosBase64List {
goImage , err := imagery . ConvertWebpBase64StringToImageObject ( base64Photo )
if ( err != nil ) { return nil , err }
viewImageButton := widget . NewButtonWithIcon ( "" , theme . ZoomInIcon ( ) , func ( ) {
setViewFullpageImagePage ( window , goImage , currentPage )
} )
fyneImage := canvas . NewImageFromImage ( goImage )
fyneImage . FillMode = canvas . ImageFillContain
imageSize := getCustomFyneSize ( 10 )
fyneImage . SetMinSize ( imageSize )
viewImageButtonCentered := getWidgetCentered ( viewImageButton )
imageWithFullpageButton := container . NewVBox ( fyneImage , viewImageButtonCentered )
imagesGrid . Add ( imageWithFullpageButton )
}
imagesGridCentered := getContainerCentered ( imagesGrid )
return imagesGridCentered , nil
}
//TODO: Add more attributes that need a custom display, such as 23andMe_AncestryComposition
attributeValueFormatted , err := formatValueFunction ( attributeValue )
if ( err != nil ) { return nil , err }
attributeValueTrimmed , _ , err := helpers . TrimAndFlattenString ( attributeValueFormatted , 20 )
if ( err != nil ) { return nil , err }
viewTextButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Attribute" , attributeValueFormatted , false , currentPage )
} )
valueLabel := widget . NewLabel ( "Value:" )
attributeValueLabel := getBoldLabel ( attributeValueTrimmed + " " + attributeUnits )
attributeValueRow := container . NewHBox ( layout . NewSpacer ( ) , valueLabel , attributeValueLabel , viewTextButton , layout . NewSpacer ( ) )
return attributeValueRow , nil
}
func getMessageDisplayForModeration ( window fyne . Window , messageCommunication string , currentPage func ( ) ) ( * fyne . Container , error ) {
isImageMessage := strings . HasPrefix ( messageCommunication , ">!>Photo=" )
if ( isImageMessage == true ) {
imageBase64Webp := strings . TrimPrefix ( messageCommunication , ">!>Photo=" )
goImage , err := imagery . ConvertWEBPBase64StringToCroppedDownsizedImageObject ( imageBase64Webp )
if ( err != nil ) { return nil , err }
viewImageButton := getWidgetCentered ( widget . NewButtonWithIcon ( "" , theme . ZoomInIcon ( ) , func ( ) {
setViewFullpageImagePage ( window , goImage , currentPage )
} ) )
fyneImage := canvas . NewImageFromImage ( goImage )
fyneImage . FillMode = canvas . ImageFillContain
imageSize := getCustomFyneSize ( 20 )
fyneImage . SetMinSize ( imageSize )
imageCentered := getFyneImageCentered ( fyneImage )
contentDisplayContainer := container . NewVBox ( imageCentered , viewImageButton )
return contentDisplayContainer , nil
}
//imageOrText == "Text"
communicationTrimmed , _ , err := helpers . TrimAndFlattenString ( messageCommunication , 25 )
if ( err != nil ) { return nil , err }
communicationLabel := getLabelCentered ( communicationTrimmed )
viewCommunicationButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Message" , messageCommunication , false , currentPage )
} )
viewTextRow := container . NewHBox ( layout . NewSpacer ( ) , communicationLabel , viewCommunicationButton , layout . NewSpacer ( ) )
return viewTextRow , nil
}
func setDownloadContentFromHashPage ( window fyne . Window , contentType string , contentHash [ ] byte , previousPage func ( ) ) {
//TODO: Make sure the content has not expired from the network, and is not banned (in which case it will not exist on the network)
}
func setModerateIdentitiesPage ( window fyne . Window , previousPage func ( ) ) {
currentPage := func ( ) { setModerateIdentitiesPage ( window , previousPage ) }
title := getPageTitleCentered ( "Moderate Identities" )
backButton := getBackButtonCentered ( previousPage )
description := getLabelCentered ( "Choose a method to moderate user identities." )
viewControversialContentButton := widget . NewButton ( "View Controversial Content" , func ( ) {
_ = mySettings . SetSetting ( "ViewedContentSortByAttribute" , "Controversy" )
_ = mySettings . SetSetting ( "ViewedContentSortDirection" , "Descending" )
_ = mySettings . SetSetting ( "ViewedContentGeneratedStatus" , "No" )
_ = mySettings . SetSetting ( "ViewedContentViewIndex" , "0" )
setBrowseContentPage ( window , currentPage )
} )
viewControversialModeratorsButton := widget . NewButton ( "View Controversial Moderators" , func ( ) {
_ = mySettings . SetSetting ( "ViewedModeratorsSortByAttribute" , "Controversy" )
_ = mySettings . SetSetting ( "ViewedModeratorsSortDirection" , "Descending" )
_ = mySettings . SetSetting ( "ViewedModeratorsGeneratedStatus" , "No" )
_ = mySettings . SetSetting ( "ViewedModeratorsViewIndex" , "0" )
setViewModeratorsPage ( window , currentPage )
} )
viewMostBannedModeratorsButton := widget . NewButton ( "View Most Banned Moderators" , func ( ) {
_ = mySettings . SetSetting ( "ViewedModeratorsSortByAttribute" , "BanAdvocates" )
_ = mySettings . SetSetting ( "ViewedModeratorsSortDirection" , "Descending" )
_ = mySettings . SetSetting ( "ViewedModeratorsGeneratedStatus" , "No" )
_ = mySettings . SetSetting ( "ViewedModeratorsViewIndex" , "0" )
setViewModeratorsPage ( window , currentPage )
} )
viewMostReportedModeratorsButton := widget . NewButton ( "View Most Reported Moderators" , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
viewMostBannedHostsButton := widget . NewButton ( "View Most Banned Hosts" , func ( ) {
_ = mySettings . SetSetting ( "ViewedHostsSortByAttribute" , "BanAdvocates" )
_ = mySettings . SetSetting ( "ViewedHostsSortDirection" , "Descending" )
_ = mySettings . SetSetting ( "ViewedHostsGeneratedStatus" , "No" )
_ = mySettings . SetSetting ( "ViewedHostsViewIndex" , "0" )
setViewHostsPage ( window , currentPage )
} )
buttonsGrid := getContainerCentered ( container . NewGridWithColumns ( 1 , viewControversialContentButton , viewControversialModeratorsButton , viewMostBannedModeratorsButton , viewMostReportedModeratorsButton , viewMostBannedHostsButton ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description , buttonsGrid )
setPageContent ( page , window )
}
// This page allows moderators to view the moderation status of an identity
func setViewIdentityModerationDetailsPage ( window fyne . Window , identityHash [ 16 ] byte , previousPage func ( ) ) {
setLoadingScreen ( window , "View Moderation Details" , "Loading details..." )
currentPage := func ( ) { setViewIdentityModerationDetailsPage ( window , identityHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Moderation Details - Identity" )
backButton := getBackButtonCentered ( previousPage )
identityHashLabel := widget . NewLabel ( "Identity Hash:" )
identityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( identityHash )
if ( err != nil ) {
identityHashHex := encoding . EncodeBytesToHexString ( identityHash [ : ] )
setErrorEncounteredPage ( window , errors . New ( "setViewIdentityModerationDetailsPage called with invalid identity hash: " + identityHashHex ) , previousPage )
return
}
identityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( identityHashString , 10 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
viewIdentityHashButton := widget . NewButton ( identityHashTrimmed , func ( ) {
setViewIdentityHashPage ( window , identityHash , currentPage )
} )
identityHashRow := container . NewHBox ( layout . NewSpacer ( ) , identityHashLabel , viewIdentityHashButton , layout . NewSpacer ( ) )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
downloadingRequiredReviews , parametersExist , identityIsBannedConsensus , numberOfBanAdvocates , banScoreSum , _ , err := verifiedVerdict . GetVerifiedIdentityVerdict ( identityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
getModeratorConsensusRow := func ( ) * fyne . Container {
moderatorConsensusLabel := widget . NewLabel ( "Moderator Consensus:" )
if ( downloadingRequiredReviews == false || parametersExist == false ) {
verdictConsensusLabel := getBoldLabel ( "Unknown" )
moderatorConsensusRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorConsensusLabel , verdictConsensusLabel , layout . NewSpacer ( ) )
return moderatorConsensusRow
}
getConsensusVerdictString := func ( ) string {
if ( identityIsBannedConsensus == false ) {
return "Not Banned"
}
return "Banned"
}
consensusVerdictString := getConsensusVerdictString ( )
verdictConsensusLabel := getBoldLabel ( consensusVerdictString )
moderatorConsensusRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorConsensusLabel , verdictConsensusLabel , layout . NewSpacer ( ) )
return moderatorConsensusRow
}
moderatorConsensusRow := getModeratorConsensusRow ( )
getMyVerdict := func ( ) ( string , error ) {
myIdentityExists , iHaveBanned , err := myReviews . GetMyNewestIdentityModerationVerdict ( identityHash , appNetworkType )
if ( err != nil ) { return "" , err }
if ( myIdentityExists == false || iHaveBanned == false ) {
return "None" , nil
}
return "Ban" , nil
}
myVerdict , err := getMyVerdict ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
myVerdictLabel := widget . NewLabel ( "My Verdict:" )
myVerdictText := getBoldLabel ( myVerdict )
//TODO: Add button to change my verdict, and see when my verdict was authored.
myVerdictRow := container . NewHBox ( layout . NewSpacer ( ) , myVerdictLabel , myVerdictText , layout . NewSpacer ( ) )
//TODO: Add button to view identity sticky status and verdict history
if ( downloadingRequiredReviews == false ) {
description1 := getBoldLabelCentered ( "This identity is outside of your moderation range." )
description2 := getLabelCentered ( "We cannot determine the moderation consensus." )
description3 := getLabelCentered ( "Do you want to download the reviews to view the consensus?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , identityHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , identityHashRow , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
if ( parametersExist == false ) {
description1 := getLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for the parameters to be downloaded." )
viewStatusButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Status" , theme . VisibilityIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , identityHashRow , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , viewStatusButton )
setPageContent ( page , window )
return
}
numberBanString := helpers . ConvertIntToString ( numberOfBanAdvocates )
banAdvocatesLabel := widget . NewLabel ( "Ban Advocates:" )
numberBanLabel := getBoldLabel ( numberBanString )
numberBanRow := container . NewHBox ( layout . NewSpacer ( ) , banAdvocatesLabel , numberBanLabel , layout . NewSpacer ( ) )
banScoreString := helpers . ConvertFloat64ToStringRounded ( banScoreSum , 2 )
banScoreLabel := getLabelCentered ( "Ban Score:" )
banScoreText := getBoldLabel ( banScoreString )
banScoreRow := container . NewHBox ( layout . NewSpacer ( ) , banScoreLabel , banScoreText , layout . NewSpacer ( ) )
viewReviewerVerdictsButton := getWidgetCentered ( widget . NewButton ( "View Reviewers" , func ( ) {
setViewIdentityReviewerVerdictsPage ( window , identityHash , 0 , currentPage )
} ) )
numberOfReports , err := reportStorage . GetNumberOfReportsForReportedHash ( identityHash [ : ] , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
numberOfReportsString := helpers . ConvertInt64ToString ( numberOfReports )
numberOfReportsLabel := widget . NewLabel ( "Number of reports:" )
numberOfReportsText := getBoldLabel ( numberOfReportsString )
numberOfReportsRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfReportsLabel , numberOfReportsText , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , identityHashRow , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , numberBanRow , banScoreRow , viewReviewerVerdictsButton , widget . NewSeparator ( ) , numberOfReportsRow )
if ( numberOfReports != 0 ) {
viewReportsButton := getWidgetCentered ( widget . NewButton ( "View Reports" , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page . Add ( viewReportsButton )
}
page . Add ( widget . NewSeparator ( ) )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , currentPage ) )
page . Add ( updateButton )
setPageContent ( page , window )
}
// This page allows moderators to view the moderation status of a profile
func setViewProfileModerationDetailsPage ( window fyne . Window , profileHash [ 28 ] byte , previousPage func ( ) ) {
setLoadingScreen ( window , "View Moderation Details" , "Loading details..." )
currentPage := func ( ) { setViewProfileModerationDetailsPage ( window , profileHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Moderation Details - Profile" )
backButton := getBackButtonCentered ( previousPage )
profileHashLabel := widget . NewLabel ( "Profile Hash:" )
profileHashHex := encoding . EncodeBytesToHexString ( profileHash [ : ] )
profileHashTrimmed , _ , err := helpers . TrimAndFlattenString ( profileHashHex , 6 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
viewProfileHashButton := widget . NewButton ( profileHashTrimmed , func ( ) {
setViewContentHashPage ( window , "Profile" , profileHash [ : ] , currentPage )
} )
profileHashRow := container . NewHBox ( layout . NewSpacer ( ) , profileHashLabel , viewProfileHashButton , layout . NewSpacer ( ) )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
profileIsDisabled , profileMetadataIsKnown , _ , profileNetworkType , profileIdentityHash , _ , downloadingRequiredReviews , parametersExist , profileVerdict , numberOfApproveAdvocates , numberOfBanAdvocates , approveScoreSum , banScoreSum , _ , _ , _ , _ , _ , _ , _ , _ , _ , err := verifiedVerdict . GetVerifiedProfileVerdict ( profileHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( profileMetadataIsKnown == true ) {
if ( profileNetworkType != appNetworkType ) {
setErrorEncounteredPage ( window , errors . New ( "setViewProfileModerationDetailsPage called with profile for different network type." ) , previousPage )
return
}
}
getProfileAuthorRow := func ( ) ( * fyne . Container , error ) {
profileAuthorLabel := widget . NewLabel ( "Profile Author:" )
if ( profileMetadataIsKnown == false ) {
unknownLabel := getBoldLabel ( "Unknown" )
profileAuthorRow := container . NewHBox ( layout . NewSpacer ( ) , profileAuthorLabel , unknownLabel , layout . NewSpacer ( ) )
return profileAuthorRow , nil
}
profileIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( profileIdentityHash )
if ( err != nil ) { return nil , err }
profileIdentityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( profileIdentityHashString , 10 )
if ( err != nil ) { return nil , err }
viewProfileIdentityHashButton := widget . NewButton ( profileIdentityHashTrimmed , func ( ) {
setViewIdentityModerationDetailsPage ( window , profileIdentityHash , currentPage )
} )
profileAuthorRow := container . NewHBox ( layout . NewSpacer ( ) , profileAuthorLabel , viewProfileIdentityHashButton , layout . NewSpacer ( ) )
return profileAuthorRow , nil
}
profileAuthorRow , err := getProfileAuthorRow ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( profileIsDisabled == true ) {
description1 := getBoldLabelCentered ( "This profile is disabled." )
description2 := getLabelCentered ( "It cannot be banned." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , profileHashRow , widget . NewSeparator ( ) , profileAuthorRow , widget . NewSeparator ( ) , description1 , description2 )
setPageContent ( page , window )
return
}
getModeratorConsensusRow := func ( ) * fyne . Container {
moderatorConsensusLabel := widget . NewLabel ( "Moderator Consensus:" )
if ( profileMetadataIsKnown == false || downloadingRequiredReviews == false || parametersExist == false ) {
verdictConsensusLabel := getBoldLabel ( "Unknown" )
moderatorConsensusRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorConsensusLabel , verdictConsensusLabel , layout . NewSpacer ( ) )
return moderatorConsensusRow
}
verdictConsensusLabel := getBoldLabel ( profileVerdict )
moderatorConsensusRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorConsensusLabel , verdictConsensusLabel , layout . NewSpacer ( ) )
return moderatorConsensusRow
}
moderatorConsensusRow := getModeratorConsensusRow ( )
getMyVerdict := func ( ) ( string , error ) {
if ( profileIsDisabled == true ) {
return "None" , nil
}
myIdentityExists , profileIsDisabledB , profileMetadataExists , myReviewExists , myReviewVerdict , err := myReviews . GetMyNewestProfileModerationVerdict ( profileHash , true )
if ( err != nil ) { return "" , err }
if ( myIdentityExists == false ) {
return "None" , nil
}
if ( profileIsDisabled != profileIsDisabledB ) {
return "" , errors . New ( "GetMyNewestProfileModerationVerdict returning different profileIsDisabled status than GetVerifiedProfileVerdict." )
}
if ( profileMetadataExists == false ) {
return "Unknown" , nil
}
if ( myReviewExists == false ) {
return "None" , nil
}
return myReviewVerdict , nil
}
myVerdict , err := getMyVerdict ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
myVerdictLabel := widget . NewLabel ( "My Verdict:" )
myVerdictText := getBoldLabel ( myVerdict )
myVerdictRow := container . NewHBox ( layout . NewSpacer ( ) , myVerdictLabel , myVerdictText , layout . NewSpacer ( ) )
//TODO: Add button to view profile sticky status and verdict history
if ( profileMetadataIsKnown == false ) {
// We do not have the required profile
// We can attempt to download it.
description1 := getLabelCentered ( "This profile is not downloaded." )
description2 := getLabelCentered ( "It must be downloaded to know its moderation status." )
description3 := getLabelCentered ( "You can try to download it, but it may have been deleted from the network." )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
//TODO: Add a way to also download profile's reviews/reports at the same time so we can quickly determine verdict
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , profileHashRow , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
viewProfileButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Profile" , theme . VisibilityIcon ( ) , func ( ) {
setViewProfileForModerationPage ( window , profileHash , currentPage )
} ) )
viewAttributesButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Attributes" , theme . VisibilityIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
if ( downloadingRequiredReviews == false ) {
description1 := getLabelCentered ( "This profile is outside of your moderation range." )
description2 := getLabelCentered ( "We cannot determine the moderation consensus." )
description3 := getLabelCentered ( "Do you want to download the reviews to view the consensus?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , profileHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , profileHashRow , widget . NewSeparator ( ) , profileAuthorRow , viewProfileButton , widget . NewSeparator ( ) , viewAttributesButton , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
if ( parametersExist == false ) {
description1 := getLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for the parameters to be downloaded." )
viewStatusButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Status" , theme . VisibilityIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , profileHashRow , widget . NewSeparator ( ) , profileAuthorRow , widget . NewSeparator ( ) , viewProfileButton , widget . NewSeparator ( ) , viewAttributesButton , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , viewStatusButton )
setPageContent ( page , window )
return
}
numberApproveString := helpers . ConvertIntToString ( numberOfApproveAdvocates )
approveAdvocatesLabel := widget . NewLabel ( "Approve Advocates:" )
numberApproveLabel := getBoldLabel ( numberApproveString )
numberApproveRow := container . NewHBox ( layout . NewSpacer ( ) , approveAdvocatesLabel , numberApproveLabel , layout . NewSpacer ( ) )
numberBanString := helpers . ConvertIntToString ( numberOfBanAdvocates )
banAdvocatesLabel := widget . NewLabel ( "Ban Advocates:" )
numberBanLabel := getBoldLabel ( numberBanString )
numberBanRow := container . NewHBox ( layout . NewSpacer ( ) , banAdvocatesLabel , numberBanLabel , layout . NewSpacer ( ) )
approveScoreString := helpers . ConvertFloat64ToStringRounded ( approveScoreSum , 2 )
approveScoreLabel := getLabelCentered ( "Approve Score:" )
approveScoreText := getBoldLabel ( approveScoreString )
approveScoreRow := container . NewHBox ( layout . NewSpacer ( ) , approveScoreLabel , approveScoreText , layout . NewSpacer ( ) )
banScoreString := helpers . ConvertFloat64ToStringRounded ( banScoreSum , 2 )
banScoreLabel := getLabelCentered ( "Ban Score:" )
banScoreText := getBoldLabel ( banScoreString )
banScoreRow := container . NewHBox ( layout . NewSpacer ( ) , banScoreLabel , banScoreText , layout . NewSpacer ( ) )
viewReviewerVerdictsButton := getWidgetCentered ( widget . NewButton ( "View Reviewers" , func ( ) {
setViewProfileReviewerVerdictsPage ( window , profileHash , 0 , currentPage )
} ) )
numberOfReports , err := reportStorage . GetNumberOfReportsForReportedHash ( profileHash [ : ] , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
numberOfReportsString := helpers . ConvertInt64ToString ( numberOfReports )
numberOfReportsLabel := widget . NewLabel ( "Number of reports:" )
numberOfReportsText := getBoldLabel ( numberOfReportsString )
numberOfReportsRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfReportsLabel , numberOfReportsText , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , profileHashRow , widget . NewSeparator ( ) , profileAuthorRow , widget . NewSeparator ( ) , viewProfileButton , widget . NewSeparator ( ) , viewAttributesButton , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , numberApproveRow , numberBanRow , approveScoreRow , banScoreRow , viewReviewerVerdictsButton , widget . NewSeparator ( ) , numberOfReportsRow )
if ( numberOfReports != 0 ) {
viewReportsButton := getWidgetCentered ( widget . NewButton ( "View Reports" , func ( ) {
//TODO
} ) )
page . Add ( viewReportsButton )
}
page . Add ( widget . NewSeparator ( ) )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , func ( ) {
currentPage ( )
} ) )
page . Add ( updateButton )
setPageContent ( page , window )
}
// This page allows moderators to view the moderation status of a profile attribute
func setViewAttributeModerationDetailsPage ( window fyne . Window , attributeHash [ 27 ] byte , previousPage func ( ) ) {
setLoadingScreen ( window , "View Moderation Details" , "Loading details..." )
currentPage := func ( ) { setViewAttributeModerationDetailsPage ( window , attributeHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Moderation Details - Attribute" )
backButton := getBackButtonCentered ( previousPage )
attributeHashLabel := widget . NewLabel ( "Attribute Hash:" )
attributeHashHex := encoding . EncodeBytesToHexString ( attributeHash [ : ] )
attributeHashTrimmed , _ , err := helpers . TrimAndFlattenString ( attributeHashHex , 6 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
viewAttributeHashButton := widget . NewButton ( attributeHashTrimmed , func ( ) {
setViewContentHashPage ( window , "Attribute" , attributeHash [ : ] , currentPage )
} )
attributeHashRow := container . NewHBox ( layout . NewSpacer ( ) , attributeHashLabel , viewAttributeHashButton , layout . NewSpacer ( ) )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
attributeMetadataIsKnown , _ , attributeAuthor , attributeNetworkType , attributeProfileHashesList , err := profileStorage . GetProfileAttributeMetadata ( attributeHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( attributeMetadataIsKnown == true ) {
if ( appNetworkType != attributeNetworkType ) {
setErrorEncounteredPage ( window , errors . New ( "setViewAttributeModerationDetailsPage called with attribute belonging to different appNetworkType." ) , previousPage )
return
}
}
getAttributeAuthorRow := func ( ) ( * fyne . Container , error ) {
attributeAuthorLabel := widget . NewLabel ( "Attribute Author:" )
if ( attributeMetadataIsKnown == false ) {
unknownLabel := getBoldLabel ( "Unknown" )
attributeAuthorRow := container . NewHBox ( layout . NewSpacer ( ) , attributeAuthorLabel , unknownLabel , layout . NewSpacer ( ) )
return attributeAuthorRow , nil
}
attributeAuthorString , _ , err := identity . EncodeIdentityHashBytesToString ( attributeAuthor )
if ( err != nil ) { return nil , err }
authorIdentityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( attributeAuthorString , 10 )
if ( err != nil ) { return nil , err }
viewAttributeAuthorButton := widget . NewButton ( authorIdentityHashTrimmed , func ( ) {
setViewIdentityModerationDetailsPage ( window , attributeAuthor , currentPage )
} )
attributeAuthorRow := container . NewHBox ( layout . NewSpacer ( ) , attributeAuthorLabel , viewAttributeAuthorButton , layout . NewSpacer ( ) )
return attributeAuthorRow , nil
}
attributeAuthorRow , err := getAttributeAuthorRow ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
getMyVerdict := func ( ) ( string , error ) {
myIdentityExists , attributeMetadataKnown , myReviewExists , myReviewVerdict , _ , err := myReviews . GetMyNewestProfileAttributeModerationVerdict ( attributeHash , true )
if ( err != nil ) { return "" , err }
if ( myIdentityExists == false ) {
return "None" , nil
}
if ( attributeMetadataKnown == false ) {
// Metadata must have been recently deleted
return "Unknown" , nil
}
if ( myReviewExists == false ) {
return "None" , nil
}
return myReviewVerdict , nil
}
myVerdict , err := getMyVerdict ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
myVerdictLabel := widget . NewLabel ( "My Verdict:" )
myVerdictText := getBoldLabel ( myVerdict )
myVerdictRow := container . NewHBox ( layout . NewSpacer ( ) , myVerdictLabel , myVerdictText , layout . NewSpacer ( ) )
if ( attributeMetadataIsKnown == false ) {
// We do not have a profile containing this attribute
// We can attempt to download it.
description1 := getLabelCentered ( "This attribute is not downloaded." )
description2 := getLabelCentered ( "It must be downloaded to know its moderation status." )
description3 := getLabelCentered ( "You can try to download it, but it may have been deleted from the network." )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
//TODO: Add a way to also download reviews/reports at the same time so we can determine attribute verdict quickly
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , attributeHashRow , widget . NewSeparator ( ) , attributeAuthorRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
viewAttributeButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Attribute" , theme . VisibilityIcon ( ) , func ( ) {
setViewProfileAttributeForModerationPage ( window , attributeHash , currentPage )
} ) )
viewAttributeProfilesButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Attribute Profiles" , theme . VisibilityIcon ( ) , func ( ) {
//TODO: A list of profiles the attribute belongs to.
showUnderConstructionDialog ( window )
} ) )
downloadingRequiredReviews , err := backgroundDownloads . CheckIfAppCanDetermineIdentityVerdicts ( attributeAuthor )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( downloadingRequiredReviews == false ) {
description1 := getLabelCentered ( "This attribute's author is outside of your moderation range." )
description2 := getLabelCentered ( "We cannot determine the moderation consensus." )
description3 := getLabelCentered ( "Do you want to download the reviews to view the consensus?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , attributeAuthor [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , attributeHashRow , widget . NewSeparator ( ) , attributeAuthorRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , viewAttributeButton , viewAttributeProfilesButton , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
//TODO: Check for parameters
parametersExist := true
if ( parametersExist == false ) {
description1 := getLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for the parameters to download." )
description3 := getLabelCentered ( "Once they download, you will be able to see who has reviewed the attribute." )
viewStatusButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Status" , theme . VisibilityIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , currentPage ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , attributeHashRow , widget . NewSeparator ( ) , attributeAuthorRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , viewAttributeButton , viewAttributeProfilesButton , widget . NewSeparator ( ) , description1 , description2 , description3 , viewStatusButton , refreshButton )
setPageContent ( page , window )
return
}
attributeApproveAdvocatesMap , attributeBanAdvocatesMap , err := reviewStorage . GetProfileAttributeVerdictMaps ( attributeHash , attributeNetworkType , true , attributeProfileHashesList )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
numberOfApproveAdvocates := len ( attributeApproveAdvocatesMap )
numberOfBanAdvocates := len ( attributeBanAdvocatesMap )
numberApproveString := helpers . ConvertIntToString ( numberOfApproveAdvocates )
approveAdvocatesLabel := widget . NewLabel ( "Approve Advocates:" )
numberApproveLabel := getBoldLabel ( numberApproveString )
numberApproveRow := container . NewHBox ( layout . NewSpacer ( ) , approveAdvocatesLabel , numberApproveLabel , layout . NewSpacer ( ) )
numberBanString := helpers . ConvertIntToString ( numberOfBanAdvocates )
banAdvocatesLabel := widget . NewLabel ( "Ban Advocates:" )
numberBanLabel := getBoldLabel ( numberBanString )
numberBanRow := container . NewHBox ( layout . NewSpacer ( ) , banAdvocatesLabel , numberBanLabel , layout . NewSpacer ( ) )
viewReviewerVerdictsButton := getWidgetCentered ( widget . NewButton ( "View Reviewers" , func ( ) {
setViewAttributeReviewerVerdictsPage ( window , attributeHash , 0 , currentPage )
} ) )
numberOfReports , err := reportStorage . GetNumberOfReportsForReportedHash ( attributeHash [ : ] , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
numberOfReportsString := helpers . ConvertInt64ToString ( numberOfReports )
numberOfReportsLabel := widget . NewLabel ( "Number of reports:" )
numberOfReportsText := getBoldLabel ( numberOfReportsString )
numberOfReportsRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfReportsLabel , numberOfReportsText , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , attributeHashRow , widget . NewSeparator ( ) , attributeAuthorRow , widget . NewSeparator ( ) , viewAttributeButton , viewAttributeProfilesButton , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , numberApproveRow , numberBanRow , viewReviewerVerdictsButton , widget . NewSeparator ( ) , numberOfReportsRow )
if ( numberOfReports != 0 ) {
viewReportsButton := getWidgetCentered ( widget . NewButton ( "View Reports" , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page . Add ( viewReportsButton )
}
page . Add ( widget . NewSeparator ( ) )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , currentPage ) )
page . Add ( updateButton )
setPageContent ( page , window )
}
// This page allows moderators to view the moderation status of a message
func setViewMessageModerationDetailsPage ( window fyne . Window , messageHash [ 26 ] byte , previousPage func ( ) ) {
setLoadingScreen ( window , "View Moderation Details" , "Loading details..." )
currentPage := func ( ) { setViewMessageModerationDetailsPage ( window , messageHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Moderation Details - Message" )
backButton := getBackButtonCentered ( previousPage )
messageHashLabel := widget . NewLabel ( "Message Hash:" )
messageHashHex := encoding . EncodeBytesToHexString ( messageHash [ : ] )
messageHashTrimmed , _ , err := helpers . TrimAndFlattenString ( messageHashHex , 6 )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
viewMessageHashButton := widget . NewButton ( messageHashTrimmed , func ( ) {
setViewContentHashPage ( window , "Message" , messageHash [ : ] , currentPage )
} )
messageHashRow := container . NewHBox ( layout . NewSpacer ( ) , messageHashLabel , viewMessageHashButton , layout . NewSpacer ( ) )
//TODO: Add button to view message sticky status and message verdict history
getMessageAuthorRow := func ( ) ( * fyne . Container , error ) {
messageAuthorLabel := widget . NewLabel ( "Message Author:" )
messageExists , messageCipherKeyFound , messageIsDecryptable , _ , messageAuthorIdentityHash , _ , err := chatMessageStorage . GetDecryptedMessageForModeration ( messageHash )
if ( err != nil ) { return nil , err }
if ( messageExists == false || messageCipherKeyFound == false || messageIsDecryptable == false ) {
//TODO: Show user if message is not decryptable, in which case, author must be malicious
unknownLabel := getBoldLabel ( "Unknown" )
messageAuthorRow := container . NewHBox ( layout . NewSpacer ( ) , messageAuthorLabel , unknownLabel , layout . NewSpacer ( ) )
return messageAuthorRow , nil
}
messageAuthorIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( messageAuthorIdentityHash )
if ( err != nil ) { return nil , err }
messageAuthorIdentityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( messageAuthorIdentityHashString , 10 )
if ( err != nil ) { return nil , err }
viewMessageAuthorIdentityHashButton := widget . NewButton ( messageAuthorIdentityHashTrimmed , func ( ) {
setViewIdentityModerationDetailsPage ( window , messageAuthorIdentityHash , currentPage )
} )
messageAuthorRow := container . NewHBox ( layout . NewSpacer ( ) , messageAuthorLabel , viewMessageAuthorIdentityHashButton , layout . NewSpacer ( ) )
return messageAuthorRow , nil
}
messageAuthorRow , err := getMessageAuthorRow ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
messageMetadataIsKnown , _ , messageNetworkType , _ , _ , downloadingRequiredReviews , parametersExist , messageVerdict , numberOfApproveAdvocates , numberOfBanAdvocates , approveScoreSum , banScoreSum , _ , _ , err := verifiedVerdict . GetVerifiedMessageVerdict ( messageHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( messageMetadataIsKnown == true ) {
if ( appNetworkType != messageNetworkType ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMessageModerationDetailsPage called with message belonging to different appNetworkType." ) , previousPage )
return
}
}
getModeratorConsensusRow := func ( ) * fyne . Container {
moderatorConsensusLabel := widget . NewLabel ( "Moderator Consensus:" )
if ( messageMetadataIsKnown == false || downloadingRequiredReviews == false || parametersExist == false ) {
verdictConsensusLabel := getBoldItalicLabel ( "Unknown" )
moderatorConsensusRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorConsensusLabel , verdictConsensusLabel , layout . NewSpacer ( ) )
return moderatorConsensusRow
}
verdictConsensusLabel := getBoldLabel ( messageVerdict )
moderatorConsensusRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorConsensusLabel , verdictConsensusLabel , layout . NewSpacer ( ) )
return moderatorConsensusRow
}
moderatorConsensusRow := getModeratorConsensusRow ( )
getMyVerdict := func ( ) ( string , error ) {
myIdentityExists , messageMetadataExists , myReviewExists , myReviewVerdict , err := myReviews . GetMyNewestMessageModerationVerdict ( messageHash )
if ( err != nil ) { return "" , err }
if ( myIdentityExists == false ) {
return "None" , nil
}
if ( messageMetadataExists == false ) {
return "Unknown" , nil
}
if ( myReviewExists == false ) {
return "None" , nil
}
return myReviewVerdict , nil
}
myVerdict , err := getMyVerdict ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
myVerdictLabel := widget . NewLabel ( "My Verdict:" )
myVerdictText := getBoldLabel ( myVerdict )
myVerdictRow := container . NewHBox ( layout . NewSpacer ( ) , myVerdictLabel , myVerdictText , layout . NewSpacer ( ) )
if ( messageMetadataIsKnown == false ) {
// We do not have the required message
// We can attempt to download it.
description1 := getBoldLabelCentered ( "This message is not downloaded." )
description2 := getLabelCentered ( "It must be downloaded to know its moderation status." )
description3 := getLabelCentered ( "You can try to download it, but it may have been deleted from the network." )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
//TODO: Add a way to also download reviews/reports at the same time, so we can determine message verdict quickly
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , messageAuthorRow , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
viewMessageButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Message" , theme . VisibilityIcon ( ) , func ( ) {
setViewMessageForModerationPage ( window , messageHash , currentPage )
} ) )
if ( downloadingRequiredReviews == false ) {
description1 := getLabelCentered ( "This message is outside of your moderation range." )
description2 := getLabelCentered ( "We cannot determine the moderation consensus." )
description3 := getLabelCentered ( "Do you want to download the reviews to view the consensus?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , messageHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , messageAuthorRow , widget . NewSeparator ( ) , viewMessageButton , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , description3 , downloadButton )
setPageContent ( page , window )
return
}
if ( parametersExist == false ) {
description1 := getLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for the parameters to be downloaded." )
viewStatusButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Status" , theme . VisibilityIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , messageAuthorRow , widget . NewSeparator ( ) , viewMessageButton , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , description1 , description2 , viewStatusButton )
setPageContent ( page , window )
return
}
numberApproveString := helpers . ConvertIntToString ( numberOfApproveAdvocates )
approveAdvocatesLabel := widget . NewLabel ( "Approve Advocates:" )
numberApproveLabel := getBoldLabel ( numberApproveString )
numberApproveRow := container . NewHBox ( layout . NewSpacer ( ) , approveAdvocatesLabel , numberApproveLabel , layout . NewSpacer ( ) )
numberBanString := helpers . ConvertIntToString ( numberOfBanAdvocates )
banAdvocatesLabel := widget . NewLabel ( "Ban Advocates:" )
numberBanLabel := getBoldLabel ( numberBanString )
numberBanRow := container . NewHBox ( layout . NewSpacer ( ) , banAdvocatesLabel , numberBanLabel , layout . NewSpacer ( ) )
approveScoreString := helpers . ConvertFloat64ToStringRounded ( approveScoreSum , 2 )
approveScoreLabel := getLabelCentered ( "Approve Score:" )
approveScoreText := getBoldLabel ( approveScoreString )
approveScoreRow := container . NewHBox ( layout . NewSpacer ( ) , approveScoreLabel , approveScoreText , layout . NewSpacer ( ) )
banScoreString := helpers . ConvertFloat64ToStringRounded ( banScoreSum , 2 )
banScoreLabel := getLabelCentered ( "Ban Score:" )
banScoreText := getBoldLabel ( banScoreString )
banScoreRow := container . NewHBox ( layout . NewSpacer ( ) , banScoreLabel , banScoreText , layout . NewSpacer ( ) )
viewReviewerVerdictsButton := getWidgetCentered ( widget . NewButton ( "View Reviewers" , func ( ) {
setViewMessageReviewerVerdictsPage ( window , messageHash , 0 , currentPage )
} ) )
numberOfReports , err := reportStorage . GetNumberOfReportsForReportedHash ( messageHash [ : ] , messageNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
numberOfReportsString := helpers . ConvertInt64ToString ( numberOfReports )
numberOfReportsLabel := widget . NewLabel ( "Number of reports:" )
numberOfReportsText := getBoldLabel ( numberOfReportsString )
numberOfReportsRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfReportsLabel , numberOfReportsText , layout . NewSpacer ( ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , messageHashRow , widget . NewSeparator ( ) , messageAuthorRow , widget . NewSeparator ( ) , viewMessageButton , widget . NewSeparator ( ) , moderatorConsensusRow , widget . NewSeparator ( ) , myVerdictRow , widget . NewSeparator ( ) , numberApproveRow , numberBanRow , approveScoreRow , banScoreRow , viewReviewerVerdictsButton , widget . NewSeparator ( ) , numberOfReportsRow )
if ( numberOfReports != 0 ) {
viewReportsButton := getWidgetCentered ( widget . NewButton ( "View Reports" , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page . Add ( viewReportsButton )
}
page . Add ( widget . NewSeparator ( ) )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , currentPage ) )
page . Add ( updateButton )
setPageContent ( page , window )
}
func setDownloadReviewsAndReportsForReviewedHashPage ( window fyne . Window , reviewedHash [ ] byte , previousPage func ( ) , pageToVisitAfter func ( ) ) {
//TODO: This page must also wait for moderator identity hashes from newly downloaded reviews to be downloaded
// This page must also make sure that the content is downloaded
showUnderConstructionDialog ( window )
}
// This page will show all moderators who have banned the identity
func setViewIdentityReviewerVerdictsPage ( window fyne . Window , identityHash [ 16 ] byte , viewIndex int , previousPage func ( ) ) {
setLoadingScreen ( window , "View Identity Ban Advocates" , "Loading verdicts..." )
currentPage := func ( ) { setViewIdentityReviewerVerdictsPage ( window , identityHash , viewIndex , previousPage ) }
title := getPageTitleCentered ( "View Identity Ban Advocates" )
backButton := getBackButtonCentered ( previousPage )
downloadingRequiredReviews , err := backgroundDownloads . CheckIfAppCanDetermineIdentityVerdicts ( identityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( downloadingRequiredReviews == false ) {
description1 := getBoldLabelCentered ( "This identity is outside of your moderator range." )
description2 := getLabelCentered ( "Download the reviews for this identity?" )
downloadButton := getWidgetCentered ( widget . NewButton ( "Download" , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , identityHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , downloadButton )
setPageContent ( page , window )
return
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
banAdvocatesMap , err := reviewStorage . GetIdentityBanAdvocatesMap ( identityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( len ( banAdvocatesMap ) == 0 ) {
noReviewersDescription := getBoldLabelCentered ( "No moderators have banned this identity." )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , currentPage ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , noReviewersDescription , updateButton )
setPageContent ( page , window )
return
}
description := getLabelCentered ( "Below are the moderators who have banned the identity." )
//TODO: Navigation buttons and pages
//Outputs:
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
// -bool: Parameters exist
// -*fyne.Container: Reviewer verdicts grid
// -error
getReviewerVerdictsGrid := func ( ) ( bool , bool , * fyne . Container , error ) {
notBannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
bannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
for moderatorIdentityHash , _ := range banAdvocatesMap {
requiredDataIsBeingDownloaded , parametersExist , isBanned , err := bannedModeratorConsensus . GetModeratorIsBannedStatus ( false , moderatorIdentityHash , appNetworkType )
if ( err != nil ) { return false , false , nil , err }
if ( requiredDataIsBeingDownloaded == false ) {
return false , parametersExist , nil , nil
}
if ( parametersExist == false ) {
return true , false , nil , nil
}
if ( isBanned == true ) {
bannedReviewersList = append ( bannedReviewersList , moderatorIdentityHash )
} else {
notBannedReviewersList = append ( notBannedReviewersList , moderatorIdentityHash )
}
}
err := helpers . SortIdentityHashListToUnicodeOrder ( notBannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
err = helpers . SortIdentityHashListToUnicodeOrder ( bannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
allReviewersListSorted := slices . Concat ( notBannedReviewersList , bannedReviewersList )
//TODO: Add pages and navigation
emptyLabelA := widget . NewLabel ( "" )
moderatorLabel := getItalicLabelCentered ( "Moderator" )
isBannedLabel := getItalicLabelCentered ( "Is Banned" )
reasonLabel := getItalicLabelCentered ( "Reason" )
emptyLabelC := widget . NewLabel ( "" )
viewModeratorButtonsColumn := container . NewVBox ( emptyLabelA , widget . NewSeparator ( ) )
moderatorIdentityHashColumn := container . NewVBox ( moderatorLabel , widget . NewSeparator ( ) )
moderatorIsBannedColumn := container . NewVBox ( isBannedLabel , widget . NewSeparator ( ) )
reasonColumn := container . NewVBox ( reasonLabel , widget . NewSeparator ( ) )
viewReviewButtonsColumn := container . NewVBox ( emptyLabelC , widget . NewSeparator ( ) )
for _ , moderatorIdentityHash := range allReviewersListSorted {
viewModeratorButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewModeratorDetailsPage ( window , moderatorIdentityHash , currentPage )
} )
moderatorIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( moderatorIdentityHash )
if ( err != nil ) { return false , false , nil , err }
identityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( moderatorIdentityHashString , 10 )
if ( err != nil ) { return false , false , nil , err }
identityHashLabel := getBoldLabelCentered ( identityHashTrimmed )
moderatorIsBannedBool := slices . Contains ( bannedReviewersList , moderatorIdentityHash )
moderatorIsBanned := helpers . ConvertBoolToYesOrNoString ( moderatorIsBannedBool )
moderatorIsBannedTranslated := translate ( moderatorIsBanned )
moderatorIsBannedLabel := getBoldLabelCentered ( moderatorIsBannedTranslated )
reviewFound , newestReviewBytes , _ , err := reviewStorage . GetModeratorNewestIdentityReview ( moderatorIdentityHash , identityHash , appNetworkType )
if ( err != nil ) { return false , false , nil , err }
if ( reviewFound == false ) {
// Review was deleted or changed after reviewers were retrieved
continue
}
ableToRead , reviewHash , _ , reviewNetworkType , retrievedModeratorIdentityHash , _ , _ , currentReviewedHash , reviewVerdict , reviewMap , err := readReviews . ReadReviewAndHash ( false , newestReviewBytes )
if ( err != nil ) { return false , false , nil , err }
if ( ableToRead == false ) {
return false , false , nil , errors . New ( "GetModeratorNewestIdentityReview returning invalid review." )
}
if ( reviewNetworkType != appNetworkType ) {
return false , false , nil , errors . New ( "GetModeratorNewestIdentityReview returning review of different networkType." )
}
if ( moderatorIdentityHash != retrievedModeratorIdentityHash ) {
return false , false , nil , errors . New ( "GetModeratorNewestIdentityReview returning review by different moderator." )
}
areEqual := bytes . Equal ( currentReviewedHash , identityHash [ : ] )
if ( areEqual == false ) {
return false , false , nil , errors . New ( "GetModeratorNewestIdentityReview returning review for different reviewedHash." )
}
if ( reviewVerdict != "Ban" ) {
return false , false , nil , errors . New ( "GetModeratorNewestIdentityReview returning non-Ban review: " + reviewVerdict )
}
getViewReasonButtonOrText := func ( ) ( * fyne . Container , error ) {
reasonString , exists := reviewMap [ "Reason" ]
if ( exists == false ) {
noneLabel := getBoldLabelCentered ( translate ( "None" ) )
return noneLabel , nil
}
viewReasonButton := getWidgetCentered ( widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Verdict Reason" , reasonString , false , currentPage )
} ) )
return viewReasonButton , nil
}
viewReasonButtonOrText , err := getViewReasonButtonOrText ( )
if ( err != nil ) { return false , false , nil , err }
viewReviewButton := widget . NewButtonWithIcon ( "View Review" , theme . VisibilityIcon ( ) , func ( ) {
setViewReviewDetailsPage ( window , reviewHash , currentPage )
} )
viewModeratorButtonsColumn . Add ( viewModeratorButton )
moderatorIdentityHashColumn . Add ( identityHashLabel )
moderatorIsBannedColumn . Add ( moderatorIsBannedLabel )
reasonColumn . Add ( viewReasonButtonOrText )
viewReviewButtonsColumn . Add ( viewReviewButton )
viewModeratorButtonsColumn . Add ( widget . NewSeparator ( ) )
moderatorIdentityHashColumn . Add ( widget . NewSeparator ( ) )
moderatorIsBannedColumn . Add ( widget . NewSeparator ( ) )
reasonColumn . Add ( widget . NewSeparator ( ) )
viewReviewButtonsColumn . Add ( widget . NewSeparator ( ) )
}
reviewsGrid := container . NewHBox ( layout . NewSpacer ( ) , viewModeratorButtonsColumn , moderatorIdentityHashColumn , moderatorIsBannedColumn , reasonColumn , viewReviewButtonsColumn , layout . NewSpacer ( ) )
return true , true , reviewsGrid , nil
}
moderatorModeEnabled , parametersExist , verdictsGrid , err := getReviewerVerdictsGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( moderatorModeEnabled == false ) {
description1 := getBoldLabelCentered ( "Moderator mode is disabled." )
description2 := getLabelCentered ( "You must enable moderator mode to view the reviewer verdicts." )
enableModeratorModeButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable Moderator Mode" , theme . NavigateNextIcon ( ) , func ( ) {
setManageModeratorModePage ( window , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , enableModeratorModeButton )
setPageContent ( page , window )
return
}
if ( parametersExist == false ) {
description1 := getBoldLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for them to download." )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , currentPage ) )
//TODO: Add button to view progress
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , refreshButton )
setPageContent ( page , window )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , verdictsGrid )
setPageContent ( page , window )
}
// This page will show all moderators who have banned/approved the profile
func setViewProfileReviewerVerdictsPage ( window fyne . Window , profileHash [ 28 ] byte , viewIndex int , previousPage func ( ) ) {
setLoadingScreen ( window , "View Profile Verdicts" , "Loading verdicts..." )
currentPage := func ( ) { setViewProfileReviewerVerdictsPage ( window , profileHash , viewIndex , previousPage ) }
title := getPageTitleCentered ( "View Profile Verdicts" )
backButton := getBackButtonCentered ( previousPage )
_ , profileIsDisabled , err := readProfiles . ReadProfileHashMetadata ( profileHash )
if ( err != nil ) {
profileHashHex := encoding . EncodeBytesToHexString ( profileHash [ : ] )
setErrorEncounteredPage ( window , errors . New ( "setViewProfileReviewerVerdictsPage called with invalid profileHash: " + profileHashHex ) , previousPage )
return
}
if ( profileIsDisabled == true ) {
description1 := getBoldLabelCentered ( "This profile is disabled." )
description2 := getLabelCentered ( "It cannot be reviewed." )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 )
setPageContent ( page , window )
return
}
profileMetadataIsKnown , _ , profileNetworkType , profileIdentityHash , _ , _ , _ , profileAttributeHashesMap , err := contentMetadata . GetProfileMetadata ( profileHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( profileMetadataIsKnown == false ) {
description1 := getLabelCentered ( "The profile is not downloaded." )
description2 := getLabelCentered ( "You must download it to view its reviews." )
description3 := getLabelCentered ( "It may not be possible if the profile has been deleted from the network." )
description4 := getLabelCentered ( "Try to download the profile?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , downloadButton )
setPageContent ( page , window )
return
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( profileNetworkType != appNetworkType ) {
setErrorEncounteredPage ( window , errors . New ( "setViewProfileReviewerVerdictsPage called with profile belonging to different networkType." ) , previousPage )
return
}
downloadingRequiredReviews , err := backgroundDownloads . CheckIfAppCanDetermineIdentityVerdicts ( profileIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( downloadingRequiredReviews == false ) {
description1 := getBoldLabelCentered ( "This profile's author is outside of your moderator range." )
description2 := getLabelCentered ( "Download the reviews for this profile?" )
downloadButton := getWidgetCentered ( widget . NewButton ( "Download" , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , profileHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , downloadButton )
setPageContent ( page , window )
return
}
profileAttributeHashesList := helpers . GetListOfMapValues ( profileAttributeHashesMap )
approveAdvocatesMap , banAdvocatesMap , err := reviewStorage . GetProfileVerdictMaps ( profileHash , profileNetworkType , true , profileAttributeHashesList )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( len ( approveAdvocatesMap ) == 0 && len ( banAdvocatesMap ) == 0 ) {
noReviewersDescription := getLabelCentered ( "No moderators have reviewed the profile." )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , currentPage ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , noReviewersDescription , updateButton )
setPageContent ( page , window )
return
}
description := getLabelCentered ( "Below are the moderators who have reviewed the profile." )
//TODO: Navigation pages and buttons
//Outputs:
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
// -bool: Parameters exist
// -*fyne.Container: Reviewer verdicts grid
// -error
getReviewerVerdictsGrid := func ( ) ( bool , bool , * fyne . Container , error ) {
approveAdvocatesList := helpers . GetListOfMapKeys ( approveAdvocatesMap )
banAdvocatesList := helpers . GetListOfMapKeys ( banAdvocatesMap )
allReviewersList := slices . Concat ( approveAdvocatesList , banAdvocatesList )
notBannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
bannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
for _ , moderatorIdentityHash := range allReviewersList {
requiredDataIsBeingDownloaded , parametersExist , isBanned , err := bannedModeratorConsensus . GetModeratorIsBannedStatus ( false , moderatorIdentityHash , profileNetworkType )
if ( err != nil ) { return false , false , nil , err }
if ( requiredDataIsBeingDownloaded == false ) {
return false , parametersExist , nil , nil
}
if ( parametersExist == false ) {
return true , false , nil , nil
}
if ( isBanned == true ) {
bannedReviewersList = append ( bannedReviewersList , moderatorIdentityHash )
} else {
notBannedReviewersList = append ( notBannedReviewersList , moderatorIdentityHash )
}
}
err := helpers . SortIdentityHashListToUnicodeOrder ( notBannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
err = helpers . SortIdentityHashListToUnicodeOrder ( bannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
allReviewersListSorted := slices . Concat ( notBannedReviewersList , bannedReviewersList )
//TODO: Add pages and navigation
emptyLabel1 := widget . NewLabel ( "" )
emptyLabel2 := widget . NewLabel ( "" )
emptyLabel3 := widget . NewLabel ( "" )
emptyLabel4 := widget . NewLabel ( "" )
emptyLabel5 := widget . NewLabel ( "" )
approvedLabel := getItalicLabelCentered ( "Approved" )
bannedLabel := getItalicLabelCentered ( "Banned" )
emptyLabel6 := widget . NewLabel ( "" )
authorLabel := getItalicLabelCentered ( "Author" )
isBannedLabel := getItalicLabelCentered ( "Is Banned" )
verdictLabel := getItalicLabelCentered ( "Verdict" )
fullProfileLabel := getItalicLabelCentered ( "Full Profile" )
attributesLabelA := getItalicLabelCentered ( "Attributes" )
attributesLabelB := getItalicLabelCentered ( "Attributes" )
viewModeratorButtonsColumn := container . NewVBox ( emptyLabel1 , emptyLabel6 , widget . NewSeparator ( ) )
moderatorIdentityHashColumn := container . NewVBox ( emptyLabel2 , authorLabel , widget . NewSeparator ( ) )
moderatorIsBannedColumn := container . NewVBox ( emptyLabel3 , isBannedLabel , widget . NewSeparator ( ) )
verdictColumn := container . NewVBox ( emptyLabel4 , verdictLabel , widget . NewSeparator ( ) )
fullProfileReviewColumn := container . NewVBox ( emptyLabel5 , fullProfileLabel , widget . NewSeparator ( ) )
approvedAttributesColumn := container . NewVBox ( approvedLabel , attributesLabelA , widget . NewSeparator ( ) )
bannedAttributesColumn := container . NewVBox ( bannedLabel , attributesLabelB , widget . NewSeparator ( ) )
for _ , moderatorIdentityHash := range allReviewersListSorted {
viewModeratorButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewModeratorDetailsPage ( window , moderatorIdentityHash , currentPage )
} )
moderatorIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( moderatorIdentityHash )
if ( err != nil ) { return false , false , nil , err }
identityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( moderatorIdentityHashString , 10 )
if ( err != nil ) { return false , false , nil , err }
identityHashLabel := getBoldLabelCentered ( identityHashTrimmed )
moderatorIsBannedBool := slices . Contains ( bannedReviewersList , moderatorIdentityHash )
moderatorIsBanned := helpers . ConvertBoolToYesOrNoString ( moderatorIsBannedBool )
moderatorIsBannedTranslated := translate ( moderatorIsBanned )
moderatorIsBannedLabel := getBoldLabelCentered ( moderatorIsBannedTranslated )
profileVerdictExists , profileVerdict , fullProfileReviewExists , fullProfileReviewBytes , _ , attributeApproveReviewsMap , attributeBanReviewsMap , err := reviewStorage . GetModeratorNewestProfileReviews ( moderatorIdentityHash , profileHash , profileNetworkType , profileAttributeHashesList )
if ( err != nil ) { return false , false , nil , err }
if ( profileVerdictExists == false ) {
// Review was deleted or changed after reviewers were retrieved
continue
}
profileVerdictLabel := getBoldLabelCentered ( profileVerdict )
viewModeratorButtonsColumn . Add ( viewModeratorButton )
moderatorIdentityHashColumn . Add ( identityHashLabel )
moderatorIsBannedColumn . Add ( moderatorIsBannedLabel )
verdictColumn . Add ( profileVerdictLabel )
if ( fullProfileReviewExists == false ) {
noneLabel := getLabelCentered ( "None" )
fullProfileReviewColumn . Add ( noneLabel )
} else {
ableToRead , reviewHash , _ , reviewNetworkType , retrievedModeratorIdentityHash , _ , _ , currentReviewedHash , _ , _ , err := readReviews . ReadReviewAndHash ( false , fullProfileReviewBytes )
if ( err != nil ) { return false , false , nil , err }
if ( ableToRead == false ) {
return false , false , nil , errors . New ( "GetModeratorNewestProfileReviews returning invalid full profile review." )
}
if ( reviewNetworkType != profileNetworkType ) {
return false , false , nil , errors . New ( "GetModeratorNewestProfileReviews returning full profile review belonging to different network type." )
}
if ( moderatorIdentityHash != retrievedModeratorIdentityHash ) {
return false , false , nil , errors . New ( "GetModeratorNewestProfileReviews returning full profile review by different moderator." )
}
areEqual := bytes . Equal ( currentReviewedHash , profileHash [ : ] )
if ( areEqual == false ) {
return false , false , nil , errors . New ( "GetModeratorNewestProfileReviews returning full profile review for different reviewedHash." )
}
fullProfileReviewButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewReviewDetailsPage ( window , reviewHash , currentPage )
} )
fullProfileReviewColumn . Add ( fullProfileReviewButton )
}
if ( len ( attributeApproveReviewsMap ) == 0 ) {
noneLabel := getLabelCentered ( "None" )
approvedAttributesColumn . Add ( noneLabel )
} else {
numberOfApprovedAttributes := len ( attributeApproveReviewsMap )
numberOfApprovedAttributesString := helpers . ConvertIntToString ( numberOfApprovedAttributes )
viewApprovedAttributesButton := widget . NewButtonWithIcon ( numberOfApprovedAttributesString , theme . VisibilityIcon ( ) , func ( ) {
//TODO: A page to view the attribute approvals
showUnderConstructionDialog ( window )
} )
approvedAttributesColumn . Add ( viewApprovedAttributesButton )
}
if ( len ( attributeBanReviewsMap ) == 0 ) {
noneLabel := getLabelCentered ( "None" )
bannedAttributesColumn . Add ( noneLabel )
} else {
numberOfBannedAttributes := len ( attributeBanReviewsMap )
numberOfBannedAttributesString := helpers . ConvertIntToString ( numberOfBannedAttributes )
viewBannedAttributesButton := widget . NewButtonWithIcon ( numberOfBannedAttributesString , theme . VisibilityIcon ( ) , func ( ) {
//TODO: A page to view the attribute bans
showUnderConstructionDialog ( window )
} )
bannedAttributesColumn . Add ( viewBannedAttributesButton )
}
viewModeratorButtonsColumn . Add ( widget . NewSeparator ( ) )
moderatorIdentityHashColumn . Add ( widget . NewSeparator ( ) )
moderatorIsBannedColumn . Add ( widget . NewSeparator ( ) )
fullProfileReviewColumn . Add ( widget . NewSeparator ( ) )
approvedAttributesColumn . Add ( widget . NewSeparator ( ) )
bannedAttributesColumn . Add ( widget . NewSeparator ( ) )
}
reviewsGrid := container . NewHBox ( layout . NewSpacer ( ) , viewModeratorButtonsColumn , moderatorIdentityHashColumn , moderatorIsBannedColumn , fullProfileReviewColumn , approvedAttributesColumn , bannedAttributesColumn , layout . NewSpacer ( ) )
return true , true , reviewsGrid , nil
}
moderatorModeEnabled , parametersExist , verdictsGrid , err := getReviewerVerdictsGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( moderatorModeEnabled == false ) {
description1 := getBoldLabelCentered ( "Moderator mode is disabled." )
description2 := getLabelCentered ( "You must enable moderator mode to view the reviewer verdicts." )
enableModeratorModeButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable Moderator Mode" , theme . NavigateNextIcon ( ) , func ( ) {
setManageModeratorModePage ( window , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , enableModeratorModeButton )
setPageContent ( page , window )
return
}
if ( parametersExist == false ) {
description1 := getBoldLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for them to download." )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , currentPage ) )
//TODO: Add button to view progress
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , refreshButton )
setPageContent ( page , window )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , verdictsGrid )
setPageContent ( page , window )
}
// This page will show all moderators who have banned/approved the attribute
func setViewAttributeReviewerVerdictsPage ( window fyne . Window , attributeHash [ 27 ] byte , viewIndex int , previousPage func ( ) ) {
setLoadingScreen ( window , "View Attribute Verdicts" , "Loading verdicts..." )
currentPage := func ( ) { setViewAttributeReviewerVerdictsPage ( window , attributeHash , viewIndex , previousPage ) }
title := getPageTitleCentered ( "View Attribute Verdicts" )
backButton := getBackButtonCentered ( previousPage )
attributeMetadataIsKnown , _ , attributeAuthor , attributeNetworkType , attributeProfileHashesList , err := profileStorage . GetProfileAttributeMetadata ( attributeHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( attributeMetadataIsKnown == false ) {
description1 := getBoldLabelCentered ( "The attribute is not downloaded." )
description2 := getLabelCentered ( "You must download it to view its reviews." )
description3 := getLabelCentered ( "It may not be possible if the attribute has been deleted from the network." )
description4 := getLabelCentered ( "Try to download the attribute?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
//TODO: Create a way to download profiles which contain an attribute
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , downloadButton )
setPageContent ( page , window )
return
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( appNetworkType != attributeNetworkType ) {
setErrorEncounteredPage ( window , errors . New ( "setViewAttributeReviewerVerdictsPage called with attribute belonging to different network type than app." ) , previousPage )
return
}
downloadingRequiredReviews , err := backgroundDownloads . CheckIfAppCanDetermineIdentityVerdicts ( attributeAuthor )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( downloadingRequiredReviews == false ) {
description1 := getBoldLabelCentered ( "This attribute's author is outside of your moderator range." )
description2 := getLabelCentered ( "Download the reviews for this attribute?" )
downloadButton := getWidgetCentered ( widget . NewButton ( "Download" , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , attributeHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , downloadButton )
setPageContent ( page , window )
return
}
attributeApproveAdvocatesMap , attributeBanAdvocatesMap , err := reviewStorage . GetProfileAttributeVerdictMaps ( attributeHash , attributeNetworkType , true , attributeProfileHashesList )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( len ( attributeApproveAdvocatesMap ) == 0 && len ( attributeBanAdvocatesMap ) == 0 ) {
noReviewersDescription := getBoldLabelCentered ( "No moderators have reviewed the attribute." )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , currentPage ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , noReviewersDescription , updateButton )
setPageContent ( page , window )
return
}
description1 := getLabelCentered ( "These are the moderators who have reviewed the attribute." )
description2 := getLabelCentered ( "This includes moderators who have approved a profile that contains this attribute." )
//TODO: Navigation pages and buttons
//Outputs:
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
// -bool: Parameters exist
// -*fyne.Container: Reviewer verdicts grid
// -error
getReviewerVerdictsGrid := func ( ) ( bool , bool , * fyne . Container , error ) {
approveAdvocatesList := helpers . GetListOfMapKeys ( attributeApproveAdvocatesMap )
banAdvocatesList := helpers . GetListOfMapKeys ( attributeApproveAdvocatesMap )
allReviewersList := slices . Concat ( approveAdvocatesList , banAdvocatesList )
notBannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
bannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
for _ , moderatorIdentityHash := range allReviewersList {
requiredDataIsBeingDownloaded , parametersExist , isBanned , err := bannedModeratorConsensus . GetModeratorIsBannedStatus ( false , moderatorIdentityHash , attributeNetworkType )
if ( err != nil ) { return false , false , nil , err }
if ( requiredDataIsBeingDownloaded == false ) {
return false , parametersExist , nil , nil
}
if ( parametersExist == false ) {
return true , false , nil , nil
}
if ( isBanned == true ) {
bannedReviewersList = append ( bannedReviewersList , moderatorIdentityHash )
} else {
notBannedReviewersList = append ( notBannedReviewersList , moderatorIdentityHash )
}
}
err := helpers . SortIdentityHashListToUnicodeOrder ( notBannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
err = helpers . SortIdentityHashListToUnicodeOrder ( bannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
allReviewersListSorted := slices . Concat ( notBannedReviewersList , bannedReviewersList )
//TODO: Add pages and navigation
emptyLabelA := widget . NewLabel ( "" )
authorLabel := getItalicLabelCentered ( "Author" )
isBannedLabel := getItalicLabelCentered ( "Is Banned" )
reviewTypeTitle := getItalicLabelCentered ( "Review Type" )
verdictLabel := getItalicLabelCentered ( "Verdict" )
reasonLabel := getItalicLabelCentered ( "Reason" )
emptyLabelC := widget . NewLabel ( "" )
viewModeratorButtonsColumn := container . NewVBox ( emptyLabelA , widget . NewSeparator ( ) )
moderatorIdentityHashColumn := container . NewVBox ( authorLabel , widget . NewSeparator ( ) )
moderatorIsBannedColumn := container . NewVBox ( isBannedLabel , widget . NewSeparator ( ) )
reviewTypeColumn := container . NewVBox ( reviewTypeTitle , widget . NewSeparator ( ) )
verdictColumn := container . NewVBox ( verdictLabel , widget . NewSeparator ( ) )
reasonColumn := container . NewVBox ( reasonLabel , widget . NewSeparator ( ) )
viewReviewButtonsColumn := container . NewVBox ( emptyLabelC , widget . NewSeparator ( ) )
for _ , moderatorIdentityHash := range allReviewersListSorted {
viewModeratorButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewModeratorDetailsPage ( window , moderatorIdentityHash , currentPage )
} )
moderatorIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( moderatorIdentityHash )
if ( err != nil ) { return false , false , nil , err }
identityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( moderatorIdentityHashString , 10 )
if ( err != nil ) { return false , false , nil , err }
identityHashLabel := getBoldLabelCentered ( identityHashTrimmed )
moderatorIsBannedBool := slices . Contains ( bannedReviewersList , moderatorIdentityHash )
moderatorIsBanned := helpers . ConvertBoolToYesOrNoString ( moderatorIsBannedBool )
moderatorIsBannedTranslated := translate ( moderatorIsBanned )
moderatorIsBannedLabel := getBoldLabelCentered ( moderatorIsBannedTranslated )
reviewFound , reviewType , newestReviewBytes , newestReviewMap , reviewVerdict , _ , err := reviewStorage . GetModeratorNewestProfileAttributeReview ( moderatorIdentityHash , attributeHash , attributeNetworkType , true )
if ( err != nil ) { return false , false , nil , err }
if ( reviewFound == false ) {
// Review was deleted or changed after reviewers were retrieved
continue
}
reviewTypeLabel := getBoldLabelCentered ( reviewType )
ableToRead , reviewHash , _ , reviewNetworkType , retrievedModeratorIdentityHash , _ , _ , _ , _ , _ , err := readReviews . ReadReviewAndHash ( false , newestReviewBytes )
if ( err != nil ) { return false , false , nil , err }
if ( ableToRead == false ) {
return false , false , nil , errors . New ( "GetModeratorNewestProfileAttributeReview returning invalid review." )
}
if ( reviewNetworkType != attributeNetworkType ) {
return false , false , nil , errors . New ( "GetModeratorNewestProfileAttributeReview returning review belonging to different networkType." )
}
if ( moderatorIdentityHash != retrievedModeratorIdentityHash ) {
return false , false , nil , errors . New ( "GetModeratorNewestProfileAttributeReview returning review by different moderator." )
}
reviewVerdictTranslated := translate ( reviewVerdict )
reviewVerdictLabel := getBoldLabelCentered ( reviewVerdictTranslated )
getViewReasonButtonOrText := func ( ) ( * fyne . Container , error ) {
reasonString , exists := newestReviewMap [ "Reason" ]
if ( exists == false ) {
noneLabel := getBoldLabelCentered ( translate ( "None" ) )
return noneLabel , nil
}
viewReasonButton := getWidgetCentered ( widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Verdict Reason" , reasonString , false , currentPage )
} ) )
return viewReasonButton , nil
}
viewReasonButtonOrText , err := getViewReasonButtonOrText ( )
if ( err != nil ) { return false , false , nil , err }
viewReviewButton := widget . NewButtonWithIcon ( "View Review" , theme . VisibilityIcon ( ) , func ( ) {
setViewReviewDetailsPage ( window , reviewHash , currentPage )
} )
viewModeratorButtonsColumn . Add ( viewModeratorButton )
moderatorIdentityHashColumn . Add ( identityHashLabel )
moderatorIsBannedColumn . Add ( moderatorIsBannedLabel )
reviewTypeColumn . Add ( reviewTypeLabel )
verdictColumn . Add ( reviewVerdictLabel )
reasonColumn . Add ( viewReasonButtonOrText )
viewReviewButtonsColumn . Add ( viewReviewButton )
viewModeratorButtonsColumn . Add ( widget . NewSeparator ( ) )
moderatorIdentityHashColumn . Add ( widget . NewSeparator ( ) )
moderatorIsBannedColumn . Add ( widget . NewSeparator ( ) )
reviewTypeColumn . Add ( widget . NewSeparator ( ) )
verdictColumn . Add ( widget . NewSeparator ( ) )
reasonColumn . Add ( widget . NewSeparator ( ) )
viewReviewButtonsColumn . Add ( widget . NewSeparator ( ) )
}
reviewsGrid := container . NewHBox ( layout . NewSpacer ( ) , viewModeratorButtonsColumn , moderatorIdentityHashColumn , moderatorIsBannedColumn , reviewTypeColumn , verdictColumn , reasonColumn , viewReviewButtonsColumn , layout . NewSpacer ( ) )
return true , true , reviewsGrid , nil
}
moderatorModeEnabled , parametersExist , verdictsGrid , err := getReviewerVerdictsGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( moderatorModeEnabled == false ) {
description1 := getBoldLabelCentered ( "Moderator mode is disabled." )
description2 := getLabelCentered ( "You must enable moderator mode to view the reviewer verdicts." )
enableModeratorModeButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable Moderator Mode" , theme . NavigateNextIcon ( ) , func ( ) {
setManageModeratorModePage ( window , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , enableModeratorModeButton )
setPageContent ( page , window )
return
}
if ( parametersExist == false ) {
description1 := getBoldLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for them to download." )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , currentPage ) )
//TODO: Add button to view progress
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , refreshButton )
setPageContent ( page , window )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , verdictsGrid )
setPageContent ( page , window )
}
// This page will show all moderators who have banned/approved the message
func setViewMessageReviewerVerdictsPage ( window fyne . Window , messageHash [ 26 ] byte , viewIndex int , previousPage func ( ) ) {
setLoadingScreen ( window , "View Message Verdicts" , "Loading verdicts..." )
currentPage := func ( ) { setViewMessageReviewerVerdictsPage ( window , messageHash , viewIndex , previousPage ) }
title := getPageTitleCentered ( "View Message Verdicts" )
backButton := getBackButtonCentered ( previousPage )
messageMetadataIsKnown , _ , messageNetworkType , _ , messageInbox , messageCipherKeyHash , err := contentMetadata . GetMessageMetadata ( messageHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( messageMetadataIsKnown == false ) {
description1 := getBoldLabelCentered ( "The message is not downloaded." )
description2 := getLabelCentered ( "You must download the message to view its reviews." )
description3 := getLabelCentered ( "It may not be possible if the message has been deleted from the network." )
description4 := getLabelCentered ( "Try to download the message?" )
downloadButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Download" , theme . DownloadIcon ( ) , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , downloadButton )
setPageContent ( page , window )
return
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( appNetworkType != messageNetworkType ) {
// TODO: Show an explanatory page instead of an error. Users may want to view messages by pasting a hash into a text entry lookup, without knowing which network type the message belongs to.
// Add this explanatory page for all of the relevant pages within the moderatorGui file.
setErrorEncounteredPage ( window , errors . New ( "setViewMessageReviewerVerdictsPage called with message belonging to different network type than app." ) , previousPage )
return
}
downloadingRequiredReviews , err := backgroundDownloads . CheckIfAppCanDetermineMessageVerdict ( messageNetworkType , messageInbox , true , messageHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( downloadingRequiredReviews == false ) {
description1 := getBoldLabelCentered ( "This message's inbox is outside of your moderator range." )
description2 := getLabelCentered ( "Download the reviews for this message?" )
downloadButton := getWidgetCentered ( widget . NewButton ( "Download" , func ( ) {
setDownloadReviewsAndReportsForReviewedHashPage ( window , messageHash [ : ] , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , downloadButton )
setPageContent ( page , window )
return
}
approveAdvocatesMap , banAdvocatesMap , err := reviewStorage . GetMessageVerdictMaps ( messageHash , messageNetworkType , messageCipherKeyHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( len ( approveAdvocatesMap ) == 0 && len ( banAdvocatesMap ) == 0 ) {
noReviewersDescription := getBoldLabelCentered ( "No moderators have reviewed the message." )
updateButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Update" , theme . ViewRefreshIcon ( ) , currentPage ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , noReviewersDescription , updateButton )
setPageContent ( page , window )
return
}
description := getLabelCentered ( "Below are the moderators who have reviewed the message." )
//TODO: Navigation button and pages
//Outputs:
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
// -bool: Parameters exist
// -*fyne.Container: Reviewer verdicts grid
// -error
getReviewerVerdictsGrid := func ( ) ( bool , bool , * fyne . Container , error ) {
approveAdvocatesList := helpers . GetListOfMapKeys ( approveAdvocatesMap )
banAdvocatesList := helpers . GetListOfMapKeys ( banAdvocatesMap )
allReviewersList := slices . Concat ( approveAdvocatesList , banAdvocatesList )
notBannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
bannedReviewersList := make ( [ ] [ 16 ] byte , 0 )
for _ , moderatorIdentityHash := range allReviewersList {
requiredDataIsBeingDownloaded , parametersExist , isBanned , err := bannedModeratorConsensus . GetModeratorIsBannedStatus ( false , moderatorIdentityHash , messageNetworkType )
if ( err != nil ) { return false , false , nil , err }
if ( requiredDataIsBeingDownloaded == false ) {
return false , parametersExist , nil , nil
}
if ( parametersExist == false ) {
return true , false , nil , nil
}
if ( isBanned == true ) {
bannedReviewersList = append ( bannedReviewersList , moderatorIdentityHash )
} else {
notBannedReviewersList = append ( notBannedReviewersList , moderatorIdentityHash )
}
}
err := helpers . SortIdentityHashListToUnicodeOrder ( notBannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
err = helpers . SortIdentityHashListToUnicodeOrder ( bannedReviewersList )
if ( err != nil ) { return false , false , nil , err }
allReviewersListSorted := slices . Concat ( notBannedReviewersList , bannedReviewersList )
//TODO: Add pages and navigation
emptyLabelA := widget . NewLabel ( "" )
authorLabel := getItalicLabelCentered ( "Author" )
isBannedLabel := getItalicLabelCentered ( "Is Banned" )
verdictLabel := getItalicLabelCentered ( "Verdict" )
reasonLabel := getItalicLabelCentered ( "Reason" )
emptyLabelC := widget . NewLabel ( "" )
viewModeratorButtonsColumn := container . NewVBox ( emptyLabelA , widget . NewSeparator ( ) )
moderatorIdentityHashColumn := container . NewVBox ( authorLabel , widget . NewSeparator ( ) )
moderatorIsBannedColumn := container . NewVBox ( isBannedLabel , widget . NewSeparator ( ) )
verdictColumn := container . NewVBox ( verdictLabel , widget . NewSeparator ( ) )
reasonColumn := container . NewVBox ( reasonLabel , widget . NewSeparator ( ) )
viewReviewButtonsColumn := container . NewVBox ( emptyLabelC , widget . NewSeparator ( ) )
for _ , moderatorIdentityHash := range allReviewersListSorted {
viewModeratorButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewModeratorDetailsPage ( window , moderatorIdentityHash , currentPage )
} )
moderatorIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( moderatorIdentityHash )
if ( err != nil ) { return false , false , nil , err }
identityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( moderatorIdentityHashString , 10 )
if ( err != nil ) { return false , false , nil , err }
identityHashLabel := getBoldLabelCentered ( identityHashTrimmed )
moderatorIsBannedBool := slices . Contains ( bannedReviewersList , moderatorIdentityHash )
moderatorIsBanned := helpers . ConvertBoolToYesOrNoString ( moderatorIsBannedBool )
moderatorIsBannedTranslated := translate ( moderatorIsBanned )
moderatorIsBannedLabel := getBoldLabelCentered ( moderatorIsBannedTranslated )
reviewFound , newestReviewBytes , _ , err := reviewStorage . GetModeratorNewestMessageReview ( moderatorIdentityHash , messageHash , messageNetworkType , messageCipherKeyHash )
if ( err != nil ) { return false , false , nil , err }
if ( reviewFound == false ) {
// Review was deleted or changed after reviewers were retrieved
continue
}
ableToRead , reviewHash , _ , reviewNetworkType , retrievedModeratorIdentityHash , _ , _ , currentReviewedHash , reviewVerdict , reviewMap , err := readReviews . ReadReviewAndHash ( false , newestReviewBytes )
if ( err != nil ) { return false , false , nil , err }
if ( ableToRead == false ) {
return false , false , nil , errors . New ( "GetModeratorNewestMessageReview returning invalid review." )
}
if ( reviewNetworkType != messageNetworkType ) {
return false , false , nil , errors . New ( "GetModeratorNewestMessageReview returning review belonging to different networkType." )
}
if ( moderatorIdentityHash != retrievedModeratorIdentityHash ) {
return false , false , nil , errors . New ( "GetModeratorNewestMessageReview returning review by different moderator." )
}
areEqual := bytes . Equal ( currentReviewedHash , messageHash [ : ] )
if ( areEqual == false ) {
return false , false , nil , errors . New ( "GetModeratorNewestMessageReview returning review for different reviewedHash." )
}
reviewVerdictTranslated := translate ( reviewVerdict )
reviewVerdictLabel := getBoldLabelCentered ( reviewVerdictTranslated )
getViewReasonButtonOrText := func ( ) ( * fyne . Container , error ) {
reasonString , exists := reviewMap [ "Reason" ]
if ( exists == false ) {
noneLabel := getBoldLabelCentered ( translate ( "None" ) )
return noneLabel , nil
}
viewReasonButton := getWidgetCentered ( widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Verdict Reason" , reasonString , false , currentPage )
} ) )
return viewReasonButton , nil
}
viewReasonButtonOrText , err := getViewReasonButtonOrText ( )
if ( err != nil ) { return false , false , nil , err }
viewReviewButton := widget . NewButtonWithIcon ( "View Review" , theme . VisibilityIcon ( ) , func ( ) {
setViewReviewDetailsPage ( window , reviewHash , currentPage )
} )
viewModeratorButtonsColumn . Add ( viewModeratorButton )
moderatorIdentityHashColumn . Add ( identityHashLabel )
moderatorIsBannedColumn . Add ( moderatorIsBannedLabel )
verdictColumn . Add ( reviewVerdictLabel )
reasonColumn . Add ( viewReasonButtonOrText )
viewReviewButtonsColumn . Add ( viewReviewButton )
viewModeratorButtonsColumn . Add ( widget . NewSeparator ( ) )
moderatorIdentityHashColumn . Add ( widget . NewSeparator ( ) )
moderatorIsBannedColumn . Add ( widget . NewSeparator ( ) )
verdictColumn . Add ( widget . NewSeparator ( ) )
reasonColumn . Add ( widget . NewSeparator ( ) )
viewReviewButtonsColumn . Add ( widget . NewSeparator ( ) )
}
reviewsGrid := container . NewHBox ( layout . NewSpacer ( ) , viewModeratorButtonsColumn , moderatorIdentityHashColumn , moderatorIsBannedColumn , verdictColumn , reasonColumn , viewReviewButtonsColumn , layout . NewSpacer ( ) )
return true , true , reviewsGrid , nil
}
moderatorModeEnabled , parametersExist , verdictsGrid , err := getReviewerVerdictsGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( moderatorModeEnabled == false ) {
description1 := getBoldLabelCentered ( "Moderator mode is disabled." )
description2 := getLabelCentered ( "You must enable moderator mode to view the reviewer verdicts." )
enableModeratorModeButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable Moderator Mode" , theme . NavigateNextIcon ( ) , func ( ) {
setManageModeratorModePage ( window , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , enableModeratorModeButton )
setPageContent ( page , window )
return
}
if ( parametersExist == false ) {
description1 := getBoldLabelCentered ( "Your app is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for them to download." )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , currentPage ) )
//TODO: Add button to view progress
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , refreshButton )
setPageContent ( page , window )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , verdictsGrid )
setPageContent ( page , window )
}
func setViewModeratorDetailsPage ( window fyne . Window , moderatorIdentityHash [ 16 ] byte , previousPage func ( ) ) {
appMemory . SetMemoryEntry ( "CurrentViewedPage" , "ModeratorDetails" )
currentPage := func ( ) { setViewModeratorDetailsPage ( window , moderatorIdentityHash , previousPage ) }
moderatorIdentityHashString , userIdentityType , err := identity . EncodeIdentityHashBytesToString ( moderatorIdentityHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( userIdentityType != "Moderator" ) {
setErrorEncounteredPage ( window , errors . New ( "ViewModeratorDetailsPage called with non-moderator identity: " + moderatorIdentityHashString ) , previousPage )
return
}
title := getPageTitleCentered ( "Moderator Details" )
backButton := getBackButtonCentered ( previousPage )
identityHashLabel := widget . NewLabel ( "Identity Hash:" )
identityHashText := getBoldLabel ( moderatorIdentityHashString )
identityHashRow := container . NewHBox ( layout . NewSpacer ( ) , identityHashLabel , identityHashText , layout . NewSpacer ( ) )
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
rankingKnown , moderatorRank , totalNumberOfModerators , err := moderatorRanking . GetModeratorRanking ( moderatorIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
getModeratorRankText := func ( ) string {
if ( rankingKnown == false ) {
result := translate ( "Unknown" )
return result
}
moderatorRankString := helpers . ConvertIntToString ( moderatorRank )
totalNumberOfModeratorsString := helpers . ConvertIntToString ( totalNumberOfModerators )
moderatorRankText := moderatorRankString + "/" + totalNumberOfModeratorsString
return moderatorRankText
}
moderatorRankText := getModeratorRankText ( )
moderatorRankTitle := widget . NewLabel ( "Moderator Rank:" )
moderatorRankLabel := getBoldLabel ( moderatorRankText )
moderatorRankRow := container . NewHBox ( layout . NewSpacer ( ) , moderatorRankTitle , moderatorRankLabel , layout . NewSpacer ( ) )
showModeratorModeIsDisabledPage := func ( ) {
description1 := getBoldLabelCentered ( "Moderator mode is disabled." )
description2 := getLabelCentered ( "You must enable moderator mode to view the moderator details." )
enableModeratorModeButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable Moderator Mode" , theme . NavigateNextIcon ( ) , func ( ) {
setManageModeratorModePage ( window , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , enableModeratorModeButton )
setPageContent ( page , window )
}
moderatorModeIsEnabled , parametersExist , isBannedStatus , err := bannedModeratorConsensus . GetModeratorIsBannedStatus ( false , moderatorIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( moderatorModeIsEnabled == false ) {
showModeratorModeIsDisabledPage ( )
return
}
if ( parametersExist == false ) {
description1 := getBoldLabelCentered ( "Your client is missing the moderation parameters." )
description2 := getLabelCentered ( "Please wait for them to download." )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , currentPage ) )
//TODO: Add button to view progress
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , refreshButton )
setPageContent ( page , window )
return
}
getBannedStatusString := func ( ) string {
if ( isBannedStatus == true ) {
return "Banned"
}
return "Not Banned"
}
bannedStatusString := getBannedStatusString ( )
isBannedLabel := widget . NewLabel ( "Moderation Status:" )
bannedStatusLabel := getBoldLabel ( bannedStatusString )
bannedStatusRow := container . NewHBox ( layout . NewSpacer ( ) , isBannedLabel , bannedStatusLabel , layout . NewSpacer ( ) )
downloadingRequiredReviews , numberOfBanAdvocates , err := reviewStorage . GetNumberOfBanAdvocatesForIdentity ( moderatorIdentityHash , appNetworkType )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( downloadingRequiredReviews == false ) {
showModeratorModeIsDisabledPage ( )
return
}
numberOfBanAdvocatesString := helpers . ConvertIntToString ( numberOfBanAdvocates )
numberOfBanAdvocatesLabel := widget . NewLabel ( "Number Of Ban Advocates:" )
numberOfBanAdvocatesText := getBoldLabel ( numberOfBanAdvocatesString )
numberOfBanAdvocatesRow := container . NewHBox ( layout . NewSpacer ( ) , numberOfBanAdvocatesLabel , numberOfBanAdvocatesText , layout . NewSpacer ( ) )
viewProfileButton := widget . NewButtonWithIcon ( "View Profile" , theme . AccountIcon ( ) , func ( ) {
setViewPeerProfilePageFromIdentityHash ( window , moderatorIdentityHash , currentPage )
} )
viewReviewsButton := widget . NewButtonWithIcon ( "View Reviews" , theme . ListIcon ( ) , func ( ) {
setViewAllReviewsCreatedByModeratorPage ( window , moderatorIdentityHash , "Profile" , 0 , currentPage )
} )
viewBanAdvocatesButton := widget . NewButtonWithIcon ( "View Ban Advocates" , theme . ErrorIcon ( ) , func ( ) {
setViewIdentityReviewerVerdictsPage ( window , moderatorIdentityHash , 0 , currentPage )
} )
viewStatisticsButton := widget . NewButtonWithIcon ( "View Statistics" , theme . InfoIcon ( ) , func ( ) {
//TODO: A page to view a user's moderation statistics
// An example is the percentage of profiles/attributes/messages they have banned/approved
showUnderConstructionDialog ( window )
} )
buttonsGrid := getContainerCentered ( container . NewGridWithColumns ( 1 , viewProfileButton , viewReviewsButton , viewBanAdvocatesButton , viewStatisticsButton ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , identityHashRow , widget . NewSeparator ( ) , moderatorRankRow , widget . NewSeparator ( ) , bannedStatusRow , widget . NewSeparator ( ) , numberOfBanAdvocatesRow , widget . NewSeparator ( ) , buttonsGrid )
setPageContent ( page , window )
}
func setViewAllReviewsCreatedByModeratorPage ( window fyne . Window , moderatorIdentityHash [ 16 ] byte , reviewType string , viewIndex int64 , previousPage func ( ) ) {
if ( reviewType != "Identity" && reviewType != "Profile" && reviewType != "Attribute" && reviewType != "Message" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewAllReviewsCreatedByModeratorPage called with invalid reviewType: " + reviewType ) , previousPage )
return
}
userIdentityType , err := identity . GetIdentityTypeFromIdentityHash ( moderatorIdentityHash )
if ( err != nil ) {
moderatorIdentityHashHex := encoding . EncodeBytesToHexString ( moderatorIdentityHash [ : ] )
setErrorEncounteredPage ( window , errors . New ( "setViewAllReviewsCreatedByModeratorPage called with invalid identity hash: " + moderatorIdentityHashHex ) , previousPage )
return
}
if ( userIdentityType != "Moderator" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewAllReviewsCreatedByModeratorPage called with non-moderator identity." ) , previousPage )
return
}
currentPage := func ( ) { setViewAllReviewsCreatedByModeratorPage ( window , moderatorIdentityHash , reviewType , viewIndex , previousPage ) }
title := getPageTitleCentered ( "Viewing Moderator Reviews" )
backButton := getBackButtonCentered ( previousPage )
reviewTypeTitle := getBoldLabelCentered ( "Review Type:" )
reviewTypesList := [ ] string { "Identity" , "Profile" , "Attribute" , "Message" }
handleSelectFunction := func ( newReviewType string ) {
setViewAllReviewsCreatedByModeratorPage ( window , moderatorIdentityHash , newReviewType , 0 , previousPage )
}
reviewTypeSelector := widget . NewSelect ( reviewTypesList , handleSelectFunction )
reviewTypeSelector . Selected = reviewType
reviewTypeSelectorCentered := getWidgetCentered ( reviewTypeSelector )
description := getLabelCentered ( "These are the " + reviewType + " reviews created by the moderator." )
getReviewsGrid := func ( ) ( * fyne . Container , error ) {
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) { return nil , err }
reviewedHashLabel := getItalicLabelCentered ( "Reviewed Hash" )
verdictLabel := getItalicLabelCentered ( "Verdict" )
reasonLabel := getItalicLabelCentered ( "Reason" )
emptyLabelA := widget . NewLabel ( "" )
reviewedHashColumn := container . NewVBox ( reviewedHashLabel , widget . NewSeparator ( ) )
verdictColumn := container . NewVBox ( verdictLabel , widget . NewSeparator ( ) )
reasonColumn := container . NewVBox ( reasonLabel , widget . NewSeparator ( ) )
viewReviewButtonsColumn := container . NewVBox ( emptyLabelA , widget . NewSeparator ( ) )
reviewsList , err := reviewStorage . GetAllNewestReviewsCreatedByModerator ( moderatorIdentityHash , reviewType , appNetworkType )
if ( err != nil ) { return nil , err }
if ( len ( reviewsList ) == 0 ) {
noReviewsExistLabel := getBoldLabelCentered ( "No " + reviewType + " reviews exist." )
return noReviewsExistLabel , nil
}
//TODO: Add sort reviews alphabetically and navigation buttons
for _ , reviewBytes := range reviewsList {
ableToRead , reviewHash , _ , reviewNetworkType , reviewerIdentityHash , _ , currentReviewType , reviewedHash , reviewVerdict , reviewMap , err := readReviews . ReadReviewAndHash ( false , reviewBytes )
if ( err != nil ) { return nil , err }
if ( ableToRead == false ) {
return nil , errors . New ( "GetAllNewestReviewsCreatedByModerator returning invalid review." )
}
if ( reviewNetworkType != appNetworkType ) {
return nil , errors . New ( "GetAllNewestReviewsCreatedByModerator returning review belonging to different networkType." )
}
if ( reviewerIdentityHash != moderatorIdentityHash ) {
return nil , errors . New ( "GetAllNewestReviewsCreatedByModerator returning review by different moderator." )
}
if ( currentReviewType != reviewType ) {
return nil , errors . New ( "GetAllNewestReviewsCreatedByModerator returning review of different reviewType" )
}
reviewedHashString , err := helpers . EncodeReviewedHashBytesToString ( reviewedHash )
if ( err != nil ) { return nil , err }
reviewedHashTrimmed , _ , err := helpers . TrimAndFlattenString ( reviewedHashString , 10 )
if ( err != nil ) { return nil , err }
reviewedHashLabel := getBoldLabelCentered ( reviewedHashTrimmed )
verdictLabel := getBoldLabelCentered ( reviewVerdict )
getViewReasonButtonOrLabel := func ( ) * fyne . Container {
reasonString , exists := reviewMap [ "Reason" ]
if ( exists == false ) {
noneLabel := getBoldLabelCentered ( "None" )
return noneLabel
}
viewReasonButton := getWidgetCentered ( widget . NewButtonWithIcon ( "" , theme . InfoIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Verdict Reason" , reasonString , false , currentPage )
} ) )
return viewReasonButton
}
viewReasonButtonOrLabel := getViewReasonButtonOrLabel ( )
viewReviewButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewReviewDetailsPage ( window , reviewHash , currentPage )
} )
reviewedHashColumn . Add ( reviewedHashLabel )
verdictColumn . Add ( verdictLabel )
reasonColumn . Add ( viewReasonButtonOrLabel )
viewReviewButtonsColumn . Add ( viewReviewButton )
reviewedHashColumn . Add ( widget . NewSeparator ( ) )
verdictColumn . Add ( widget . NewSeparator ( ) )
reasonColumn . Add ( widget . NewSeparator ( ) )
viewReviewButtonsColumn . Add ( widget . NewSeparator ( ) )
}
reviewsGrid := container . NewHBox ( layout . NewSpacer ( ) , reviewedHashColumn , verdictColumn , reasonColumn , viewReviewButtonsColumn , layout . NewSpacer ( ) )
return reviewsGrid , nil
}
reviewsGrid , err := getReviewsGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , reviewTypeTitle , reviewTypeSelectorCentered , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , reviewsGrid )
setPageContent ( page , window )
}
func setViewReviewDetailsPage ( window fyne . Window , reviewHash [ 29 ] byte , previousPage func ( ) ) {
currentPage := func ( ) { setViewReviewDetailsPage ( window , reviewHash , previousPage ) }
title := getPageTitleCentered ( "Viewing Review Details" )
backButton := getBackButtonCentered ( previousPage )
exists , reviewBytes , err := badgerDatabase . GetReview ( reviewHash )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( exists == false ) {
description := getBoldLabelCentered ( "Review not found." )
//TODO: Download review
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description )
setPageContent ( page , window )
return
}
getPageContent := func ( ) ( * fyne . Container , error ) {
2024-06-11 06:59:06 +02:00
ableToRead , currentReviewHash , _ , reviewNetworkType , reviewerIdentityHash , reviewCreationTime , reviewType , reviewedHash , reviewVerdict , reviewMap , err := readReviews . ReadReviewAndHash ( false , reviewBytes )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
if ( ableToRead == false ) {
return nil , errors . New ( "Database corrupt: Contains invalid review." )
}
if ( reviewHash != currentReviewHash ) {
return nil , errors . New ( "Database corrupt: Review entry key does not match review hash" )
}
reviewNetworkTypeLabel := widget . NewLabel ( "Review Network Type:" )
reviewNetworkTypeString := helpers . ConvertByteToString ( reviewNetworkType )
reviewNetworkTypeText := getBoldLabel ( reviewNetworkTypeString )
reviewNetworkTypeRow := container . NewHBox ( layout . NewSpacer ( ) , reviewNetworkTypeLabel , reviewNetworkTypeText , layout . NewSpacer ( ) )
reviewAuthorLabel := widget . NewLabel ( "Review Author:" )
reviewerIdentityHashString , _ , err := identity . EncodeIdentityHashBytesToString ( reviewerIdentityHash )
if ( err != nil ) { return nil , err }
reviewerIdentityHashTrimmed , _ , err := helpers . TrimAndFlattenString ( reviewerIdentityHashString , 15 )
if ( err != nil ) { return nil , err }
viewReviewAuthorButton := widget . NewButtonWithIcon ( reviewerIdentityHashTrimmed , theme . VisibilityIcon ( ) , func ( ) {
setViewModeratorDetailsPage ( window , reviewerIdentityHash , currentPage )
} )
reviewerIdentityRow := container . NewHBox ( layout . NewSpacer ( ) , reviewAuthorLabel , viewReviewAuthorButton , layout . NewSpacer ( ) )
reviewHashTitle := widget . NewLabel ( "Review Hash:" )
reviewHashHex := encoding . EncodeBytesToHexString ( reviewHash [ : ] )
reviewHashTrimmed , _ , err := helpers . TrimAndFlattenString ( reviewHashHex , 10 )
if ( err != nil ) { return nil , err }
reviewHashLabel := getBoldLabel ( reviewHashTrimmed )
viewReviewHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewContentHashPage ( window , "Review" , reviewHash [ : ] , currentPage )
} )
reviewHashRow := container . NewHBox ( layout . NewSpacer ( ) , reviewHashTitle , reviewHashLabel , viewReviewHashButton , layout . NewSpacer ( ) )
reviewTypeTitle := widget . NewLabel ( "Review Type:" )
reviewTypeLabel := getBoldLabel ( reviewType )
reviewTypeRow := container . NewHBox ( layout . NewSpacer ( ) , reviewTypeTitle , reviewTypeLabel , layout . NewSpacer ( ) )
reviewedHashTitle := widget . NewLabel ( "Reviewed Hash:" )
reviewedHashString , err := helpers . EncodeReviewedHashBytesToString ( reviewedHash )
if ( err != nil ) { return nil , err }
reviewedHashTrimmed , _ , err := helpers . TrimAndFlattenString ( reviewedHashString , 10 )
if ( err != nil ) { return nil , err }
reviewedHashLabel := getBoldLabel ( reviewedHashTrimmed )
viewReviewedHashButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
if ( reviewType == "Identity" ) {
if ( len ( reviewedHash ) != 16 ) {
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid reviewedHash length." ) , previousPage )
return
}
reviewedIdentityHash := [ 16 ] byte ( reviewedHash )
setViewIdentityHashPage ( window , reviewedIdentityHash , currentPage )
} else {
setViewContentHashPage ( window , reviewType , reviewedHash , currentPage )
}
} )
reviewedHashRow := container . NewHBox ( layout . NewSpacer ( ) , reviewedHashTitle , reviewedHashLabel , viewReviewedHashButton , layout . NewSpacer ( ) )
2024-06-11 06:59:06 +02:00
creationTimeTranslated , err := helpers . ConvertUnixTimeToTimeFromNowTranslated ( reviewCreationTime , true )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
2024-06-11 06:59:06 +02:00
creationTimeTitle := widget . NewLabel ( "Creation Time:" )
creationTimeLabel := getBoldLabel ( creationTimeTranslated )
creationTimeWarningButton := widget . NewButtonWithIcon ( "" , theme . WarningIcon ( ) , func ( ) {
title := translate ( "Creation Time Warning" )
dialogMessage := "Creation times are not verified. They can be faked by the reviewer."
2024-04-11 15:51:56 +02:00
dialogContent := container . NewVBox ( widget . NewLabel ( dialogMessage ) )
dialog . ShowCustom ( title , translate ( "Close" ) , dialogContent , window )
} )
2024-06-11 06:59:06 +02:00
creationTimeRow := container . NewHBox ( layout . NewSpacer ( ) , creationTimeTitle , creationTimeLabel , creationTimeWarningButton , layout . NewSpacer ( ) )
2024-04-11 15:51:56 +02:00
verdictTitle := widget . NewLabel ( "Verdict:" )
verdictLabel := getBoldLabel ( reviewVerdict )
verdictRow := container . NewHBox ( layout . NewSpacer ( ) , verdictTitle , verdictLabel , layout . NewSpacer ( ) )
getReviewReasonRow := func ( ) ( * fyne . Container , error ) {
reasonTitle := widget . NewLabel ( "Reason:" )
reasonString , exists := reviewMap [ "Reason" ]
if ( exists == false ) {
noneLabel := getBoldItalicLabel ( translate ( "None" ) )
reasonRow := container . NewHBox ( layout . NewSpacer ( ) , reasonTitle , noneLabel , layout . NewSpacer ( ) )
return reasonRow , nil
}
reasonTrimmed , _ , err := helpers . TrimAndFlattenString ( reasonString , 20 )
if ( err != nil ) { return nil , err }
reasonLabel := getBoldLabel ( reasonTrimmed )
viewReasonButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Review Reason" , reasonString , false , currentPage )
} )
reasonRow := container . NewHBox ( layout . NewSpacer ( ) , reasonTitle , reasonLabel , viewReasonButton , layout . NewSpacer ( ) )
return reasonRow , nil
}
reasonRow , err := getReviewReasonRow ( )
if ( err != nil ) { return nil , err }
2024-06-11 06:59:06 +02:00
pageContent := container . NewVBox ( reviewNetworkTypeRow , widget . NewSeparator ( ) , reviewerIdentityRow , widget . NewSeparator ( ) , reviewHashRow , widget . NewSeparator ( ) , reviewTypeRow , widget . NewSeparator ( ) , reviewedHashRow , widget . NewSeparator ( ) , creationTimeRow , widget . NewSeparator ( ) , verdictRow , widget . NewSeparator ( ) , reasonRow , widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
if ( reviewType == "Identity" ) {
_ , exists := reviewMap [ "ErrantMessages" ]
if ( exists == true ) {
errantMessagesTitle := widget . NewLabel ( "Errant Messages:" )
errantMessagesRow := container . NewHBox ( layout . NewSpacer ( ) , errantMessagesTitle , layout . NewSpacer ( ) )
pageContent . Add ( errantMessagesRow )
//TODO: Add errant Profiles and reviews, and add buttons to view each.
}
}
if ( reviewType != "Identity" ) {
viewReviewedContentOrIdentityButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Reviewed " + reviewType , theme . VisibilityIcon ( ) , func ( ) {
if ( reviewType == "Message" ) {
if ( len ( reviewedHash ) != 26 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( reviewedHash )
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex ) , currentPage )
return
}
reviewedMessageHash := [ 26 ] byte ( reviewedHash )
setViewMessageForModerationPage ( window , reviewedMessageHash , currentPage )
} else if ( reviewType == "Profile" ) {
if ( len ( reviewedHash ) != 28 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( reviewedHash )
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex ) , currentPage )
return
}
reviewedProfileHash := [ 28 ] byte ( reviewedHash )
setViewProfileForModerationPage ( window , reviewedProfileHash , currentPage )
} else if ( reviewType == "Attribute" ) {
if ( len ( reviewedHash ) != 27 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( reviewedHash )
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex ) , currentPage )
return
}
reviewedAttributeHash := [ 27 ] byte ( reviewedHash )
setViewProfileAttributeForModerationPage ( window , reviewedAttributeHash , currentPage )
}
} ) )
pageContent . Add ( viewReviewedContentOrIdentityButton )
}
viewReviewedHashModerationDetailsButton := getWidgetCentered ( widget . NewButtonWithIcon ( "View Reviewed " + reviewType + " Details" , theme . VisibilityIcon ( ) , func ( ) {
if ( reviewType == "Identity" ) {
if ( len ( reviewedHash ) != 16 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( reviewedHash )
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid length reviewedHash for Identity review: " + reviewedHashHex ) , currentPage )
return
}
reviewedIdentityHash := [ 16 ] byte ( reviewedHash )
setViewIdentityModerationDetailsPage ( window , reviewedIdentityHash , currentPage )
} else if ( reviewType == "Profile" ) {
if ( len ( reviewedHash ) != 28 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( reviewedHash )
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex ) , currentPage )
return
}
reviewedProfileHash := [ 28 ] byte ( reviewedHash )
setViewProfileModerationDetailsPage ( window , reviewedProfileHash , currentPage )
} else if ( reviewType == "Attribute" ) {
if ( len ( reviewedHash ) != 27 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( reviewedHash )
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex ) , currentPage )
return
}
reviewedAttributeHash := [ 27 ] byte ( reviewedHash )
setViewAttributeModerationDetailsPage ( window , reviewedAttributeHash , currentPage )
} else if ( reviewType == "Message" ) {
if ( len ( reviewedHash ) != 26 ) {
reviewedHashHex := encoding . EncodeBytesToHexString ( reviewedHash )
setErrorEncounteredPage ( window , errors . New ( "ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex ) , currentPage )
return
}
reviewedMessageHash := [ 26 ] byte ( reviewedHash )
setViewMessageModerationDetailsPage ( window , reviewedMessageHash , currentPage )
}
} ) )
pageContent . Add ( viewReviewedHashModerationDetailsButton )
//TODO: Add anything else?
return pageContent , nil
}
pageContent , err := getPageContent ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , pageContent )
setPageContent ( page , window )
}
func setModeratorSettingsPage ( window fyne . Window , previousPage func ( ) ) {
currentPage := func ( ) { setModeratorSettingsPage ( window , previousPage ) }
title := getPageTitleCentered ( "Moderator Settings" )
backButton := getBackButtonCentered ( previousPage )
description := getLabelCentered ( "Manage your moderation settings." )
getSettingsGrid := func ( ) ( * fyne . Container , error ) {
settingTitleColumn := container . NewVBox ( )
settingStatusColumn := container . NewVBox ( )
manageSettingButtonsColumn := container . NewVBox ( )
addSettingRow := func ( addSeparator bool , settingTitle string , settingName string , defaultIsOn bool , manageSettingPage func ( ) ) error {
settingTitleLabel := getBoldLabelCentered ( settingTitle )
getSettingOnOffStatus := func ( ) ( string , error ) {
exists , settingOnOffStatus , err := mySettings . GetSetting ( settingName )
if ( err != nil ) { return "" , err }
if ( exists == false ) {
if ( defaultIsOn == true ) {
return "On" , nil
}
return "Off" , nil
}
return settingOnOffStatus , nil
}
settingStatus , err := getSettingOnOffStatus ( )
if ( err != nil ) { return err }
settingStatusLabel := getBoldLabelCentered ( settingStatus )
manageSettingButton := widget . NewButtonWithIcon ( "Manage" , theme . SettingsIcon ( ) , manageSettingPage )
settingTitleColumn . Add ( settingTitleLabel )
settingStatusColumn . Add ( settingStatusLabel )
manageSettingButtonsColumn . Add ( manageSettingButton )
if ( addSeparator == true ) {
settingTitleColumn . Add ( widget . NewSeparator ( ) )
settingStatusColumn . Add ( widget . NewSeparator ( ) )
manageSettingButtonsColumn . Add ( widget . NewSeparator ( ) )
}
return nil
}
err := addSettingRow ( true , "Moderator Mode" , "ModeratorModeOnOffStatus" , false , func ( ) {
setManageModeratorModePage ( window , currentPage )
} )
if ( err != nil ) { return nil , err }
err = addSettingRow ( true , "Moderate Messages" , "ModerateMessagesOnOffStatus" , false , func ( ) {
setManageModerateMessagesModePage ( window , currentPage )
} )
if ( err != nil ) { return nil , err }
err = addSettingRow ( true , "Moderate Mate Identities" , "ModerateMateContentOnOffStatus" , true , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
if ( err != nil ) { return nil , err }
err = addSettingRow ( true , "Moderate Host Identities" , "ModerateHostContentOnOffStatus" , true , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
if ( err != nil ) { return nil , err }
err = addSettingRow ( true , "Moderate Moderator Identities" , "ModerateModeratorContentOnOffStatus" , true , func ( ) {
//TODO
showUnderConstructionDialog ( window )
} )
if ( err != nil ) { return nil , err }
settingsGrid := container . NewHBox ( layout . NewSpacer ( ) , settingTitleColumn , settingStatusColumn , manageSettingButtonsColumn , layout . NewSpacer ( ) )
return settingsGrid , nil
}
settingsGrid , err := getSettingsGrid ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , settingsGrid )
setPageContent ( page , window )
}
func setManageModeratorModePage ( window fyne . Window , previousPage func ( ) ) {
currentPage := func ( ) { setManageModeratorModePage ( window , previousPage ) }
title := getPageTitleCentered ( "Manage Moderator Mode" )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( "Moderator Mode" )
description1 := getLabelCentered ( "Activate this mode if you want to be a moderator." )
description2 := getLabelCentered ( "Seekia will start downloading content for you to moderate." )
getModeratorModeStatus := func ( ) ( string , error ) {
exists , moderatorModeStatus , err := mySettings . GetSetting ( "ModeratorModeOnOffStatus" )
if ( err != nil ) { return "" , err }
if ( exists == false ) {
return "Off" , nil
}
if ( moderatorModeStatus != "On" && moderatorModeStatus != "Off" ) {
return "" , errors . New ( "MySettings malformed: Invalid moderator mode status: " + moderatorModeStatus )
}
return moderatorModeStatus , nil
}
moderatorModeStatus , err := getModeratorModeStatus ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
moderatorModeStatusLabel := getLabelCentered ( "Moderator Mode Status:" )
moderatorModeStatusText := getBoldLabelCentered ( moderatorModeStatus )
getEnableDisableText := func ( ) string {
if ( moderatorModeStatus == "On" ) {
return "Disable"
}
return "Enable"
}
enableDisableText := getEnableDisableText ( )
enableDisableButton := getWidgetCentered ( widget . NewButton ( enableDisableText , func ( ) {
if ( moderatorModeStatus == "On" ) {
err := mySettings . SetSetting ( "ModeratorModeOnOffStatus" , "Off" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , currentPage )
return
}
currentPage ( )
return
}
setConfirmEnableModeratorModePage ( window , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , moderatorModeStatusLabel , moderatorModeStatusText , enableDisableButton )
setPageContent ( page , window )
}
func setConfirmEnableModeratorModePage ( window fyne . Window , previousPage func ( ) , nextPage func ( ) ) {
title := getPageTitleCentered ( "Enable Moderator Mode" )
backButton := getBackButtonCentered ( previousPage )
description1 := getBoldLabelCentered ( "Enable Moderator Mode?" )
description2 := getLabelCentered ( "This mode will download unapproved content for you to moderate." )
description3 := getLabelCentered ( "This content may contain illegal and unruleful content." )
description4 := getLabelCentered ( "You must accept the legal risks of downloading this content." )
enableButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable" , theme . ConfirmIcon ( ) , func ( ) {
err := mySettings . SetSetting ( "ModeratorModeOnOffStatus" , "On" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
nextPage ( )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , enableButton )
setPageContent ( page , window )
}
func setManageModerateMessagesModePage ( window fyne . Window , previousPage func ( ) ) {
currentPage := func ( ) { setManageModeratorModePage ( window , previousPage ) }
title := getPageTitleCentered ( "Manage Moderate Messages Mode" )
backButton := getBackButtonCentered ( previousPage )
subtitle := getPageSubtitleCentered ( "Moderate Messages Mode" )
description1 := getLabelCentered ( "Activate this mode if you want to moderate messages." )
description2 := getLabelCentered ( "Seekia will start downloading messages for you to moderate." )
description3 := getLabelCentered ( "You will be reviewing messages which have been reported by users." )
description4 := getLabelCentered ( "Be aware that these messages are more likely to contain unruleful content." )
getModerateMessagesModeStatus := func ( ) ( string , error ) {
exists , moderateMessagesModeStatus , err := mySettings . GetSetting ( "ModerateMessagesOnOffStatus" )
if ( err != nil ) { return "" , err }
if ( exists == false ) {
return "Off" , nil
}
if ( moderateMessagesModeStatus != "On" && moderateMessagesModeStatus != "Off" ) {
return "" , errors . New ( "MySettings malformed: Invalid moderate messages mode status: " + moderateMessagesModeStatus )
}
return moderateMessagesModeStatus , nil
}
moderateMessagesModeStatus , err := getModerateMessagesModeStatus ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
moderateMessagesModeStatusLabel := getLabelCentered ( "Moderate Messages Mode Status:" )
moderateMessagesModeStatusText := getBoldLabelCentered ( moderateMessagesModeStatus )
getEnableDisableText := func ( ) string {
if ( moderateMessagesModeStatus == "On" ) {
return "Disable"
}
return "Enable"
}
enableDisableText := getEnableDisableText ( )
enableDisableButton := getWidgetCentered ( widget . NewButton ( enableDisableText , func ( ) {
if ( moderateMessagesModeStatus == "On" ) {
err := mySettings . SetSetting ( "ModerateMessagesOnOffStatus" , "Off" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , currentPage )
return
}
currentPage ( )
return
}
setConfirmEnableModerateMessagesModePage ( window , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , subtitle , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , widget . NewSeparator ( ) , moderateMessagesModeStatusLabel , moderateMessagesModeStatusText , enableDisableButton )
setPageContent ( page , window )
}
func setConfirmEnableModerateMessagesModePage ( window fyne . Window , previousPage func ( ) , nextPage func ( ) ) {
title := getPageTitleCentered ( "Enable Moderate Messages Mode" )
backButton := getBackButtonCentered ( previousPage )
description1 := getBoldLabelCentered ( "Enable Moderate Messages Mode?" )
description2 := getLabelCentered ( "This mode will download reported messages for you to moderate." )
description3 := getLabelCentered ( "These are likely to contain illegal and unruleful content." )
description4 := getLabelCentered ( "You must accept the legal risks of downloading this content." )
enableButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Enable" , theme . ConfirmIcon ( ) , func ( ) {
err := mySettings . SetSetting ( "ModerateMessagesOnOffStatus" , "On" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
nextPage ( )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , enableButton )
setPageContent ( page , window )
}
func setBuildMyModeratorProfilePage ( window fyne . Window , previousPage func ( ) ) {
currentPage := func ( ) { setBuildMyModeratorProfilePage ( window , previousPage ) }
title := getPageTitleCentered ( "Build Moderator Profile" )
backButton := getBackButtonCentered ( previousPage )
description1 := getLabelCentered ( "Build your moderator profile." )
description2 := getLabelCentered ( "All information is optional." )
usernameButton := widget . NewButton ( "Username" , func ( ) {
setBuildProfilePage_Username ( window , "Moderator" , currentPage )
} )
avatarButton := widget . NewButton ( "Avatar" , func ( ) {
setBuildProfilePage_Avatar ( window , "Moderator" , currentPage )
} )
descriptionButton := widget . NewButton ( "Description" , func ( ) {
setBuildProfilePage_Description ( window , "Moderator" , currentPage )
} )
profileLanguageButton := widget . NewButton ( translate ( "Profile Language" ) , func ( ) {
setBuildProfilePage_ProfileLanguage ( window , "Moderator" , currentPage )
} )
languageButton := widget . NewButton ( "Language" , func ( ) {
//TODO
// The format of this attribute will be different than the one for mates
// It will not include a fluency field. It will simply contain a list of understood languages
showUnderConstructionDialog ( window )
} )
buttonsColumn := getContainerCentered ( container . NewGridWithColumns ( 1 , usernameButton , avatarButton , descriptionButton , profileLanguageButton , languageButton ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , widget . NewSeparator ( ) , buttonsColumn )
setPageContent ( page , window )
}
func setViewMyReviewsPage ( window fyne . Window , reviewType string , previousPage func ( ) ) {
if ( reviewType != "Identity" && reviewType != "Profile" && reviewType != "Attribute" && reviewType != "Message" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMyReviewsPage called with invalid reviewType: " + reviewType ) , previousPage )
return
}
setLoadingScreen ( window , "View My Reviews" , "Loading my reviews..." )
currentPage := func ( ) { setViewMyReviewsPage ( window , reviewType , previousPage ) }
title := getPageTitleCentered ( "My Reviews" )
backButton := getBackButtonCentered ( previousPage )
myIdentityExists , myIdentityHash , err := myIdentity . GetMyIdentityHash ( "Moderator" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( myIdentityExists == false ) {
description1 := getBoldLabelCentered ( "Your moderator identity does not exist." )
description2 := getLabelCentered ( "Thus, you have no moderator reviews." )
description3 := getLabelCentered ( "Create your identity?" )
createIdentityButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Create Identity" , theme . NavigateNextIcon ( ) , func ( ) {
setChooseNewIdentityHashPage ( window , "Moderator" , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , createIdentityButton )
setPageContent ( page , window )
return
}
//TODO: Add info about moderator's number of used reviews out of total that have been funded
reviewTypeLabel := getBoldLabelCentered ( "Review Type:" )
allReviewTypesList := [ ] string { "Identity" , "Profile" , "Attribute" , "Message" }
handleSelectFunction := func ( newReviewType string ) {
setViewMyReviewsPage ( window , newReviewType , previousPage )
}
reviewTypeSelector := widget . NewSelect ( allReviewTypesList , handleSelectFunction )
reviewTypeSelector . Selected = reviewType
reviewTypeSelectorCentered := getWidgetCentered ( reviewTypeSelector )
description := getLabelCentered ( "Below are your " + reviewType + " reviews." )
getResultsContainer := func ( ) ( * fyne . Container , error ) {
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) { return nil , err }
myIdentityExists , myReviewsList , err := myReviews . GetMyNewestReviewsListSorted ( reviewType , appNetworkType )
if ( err != nil ) { return nil , err }
if ( myIdentityExists == false ) {
return nil , errors . New ( "My identity not found after being found already." )
}
totalNumberOfReviews := len ( myReviewsList )
if ( totalNumberOfReviews == 0 ) {
reviewTypeLowercase := strings . ToLower ( reviewType )
noReviewsExistText := getBoldLabelCentered ( "No " + reviewTypeLowercase + " reviews exist." )
return noReviewsExistText , nil
}
getFinalPageIndex := func ( ) int {
if ( totalNumberOfReviews <= 5 ) {
return 0
}
maximumIndex := totalNumberOfReviews - 5
return maximumIndex
}
finalPageIndex := getFinalPageIndex ( )
getViewIndex := func ( ) ( int , error ) {
if ( totalNumberOfReviews <= 5 ) {
return 0 , nil
}
exists , currentViewIndex := appMemory . GetMemoryEntry ( "MyReviewsPageViewIndex_" + reviewType )
if ( exists == false ) {
return 0 , nil
}
currentViewIndexInt , err := helpers . ConvertStringToInt ( currentViewIndex )
if ( err != nil ) { return 0 , err }
maximumIndex := totalNumberOfReviews - 1
if ( currentViewIndexInt < 0 ) {
// Index is out of range, restart at 0
appMemory . SetMemoryEntry ( "MyReviewsPageViewIndex_" + reviewType , "0" )
return 0 , nil
}
if ( currentViewIndexInt > maximumIndex ) {
finalPageIndexString := helpers . ConvertIntToString ( finalPageIndex )
appMemory . SetMemoryEntry ( "MyReviewsPageViewIndex_" + reviewType , finalPageIndexString )
return finalPageIndex , nil
}
return currentViewIndexInt , nil
}
viewIndex , err := getViewIndex ( )
if ( err != nil ) { return nil , err }
getNavigateToBeginningButton := func ( ) fyne . Widget {
if ( totalNumberOfReviews <= 5 || viewIndex == 0 ) {
emptyButton := widget . NewButton ( " " , nil )
return emptyButton
}
goToBeginningButton := widget . NewButtonWithIcon ( "" , theme . MediaSkipPreviousIcon ( ) , func ( ) {
appMemory . SetMemoryEntry ( "MyReviewsPageViewIndex_" + reviewType , "0" )
currentPage ( )
} )
return goToBeginningButton
}
getNavigateToEndButton := func ( ) fyne . Widget {
emptyButton := widget . NewButton ( " " , nil )
if ( totalNumberOfReviews <= 5 || viewIndex >= finalPageIndex ) {
return emptyButton
}
goToEndButton := widget . NewButtonWithIcon ( "" , theme . MediaSkipNextIcon ( ) , func ( ) {
finalPageIndexString := helpers . ConvertIntToString ( finalPageIndex )
appMemory . SetMemoryEntry ( "MyReviewsPageViewIndex_" + reviewType , finalPageIndexString )
currentPage ( )
} )
return goToEndButton
}
getNavigateLeftButton := func ( ) fyne . Widget {
if ( totalNumberOfReviews <= 5 || viewIndex == 0 ) {
emptyButton := widget . NewButton ( " " , nil )
return emptyButton
}
button := widget . NewButtonWithIcon ( "" , theme . NavigateBackIcon ( ) , func ( ) {
newIndex := helpers . ConvertIntToString ( viewIndex - 5 )
appMemory . SetMemoryEntry ( "MyReviewsPageViewIndex_" + reviewType , newIndex )
currentPage ( )
} )
return button
}
getNavigateRightButton := func ( ) fyne . Widget {
emptyButton := widget . NewButton ( " " , nil )
if ( totalNumberOfReviews <= 5 || viewIndex >= finalPageIndex ) {
return emptyButton
}
button := widget . NewButtonWithIcon ( "" , theme . NavigateNextIcon ( ) , func ( ) {
newIndex := helpers . ConvertIntToString ( viewIndex + 5 )
appMemory . SetMemoryEntry ( "MyReviewsPageViewIndex_" + reviewType , newIndex )
currentPage ( )
} )
return button
}
getViewingReviewsLabelWithNavRow := func ( ) * fyne . Container {
if ( totalNumberOfReviews == 1 ) {
viewingReviewText := getBoldLabelCentered ( "Viewing 1 Review" )
return viewingReviewText
}
totalNumberOfReviewsString := helpers . ConvertIntToString ( totalNumberOfReviews )
if ( totalNumberOfReviews <= 5 ) {
viewingReviewsText := getBoldLabelCentered ( "Viewing " + totalNumberOfReviewsString + " Reviews" )
return viewingReviewsText
}
// We need to show navigation buttons
viewingReviewsText := getBoldLabel ( "Viewing " + totalNumberOfReviewsString + " Reviews" )
navigateToBeginningButton := getNavigateToBeginningButton ( )
navigateToEndButton := getNavigateToEndButton ( )
navigateLeftButton := getNavigateLeftButton ( )
navigateRightButton := getNavigateRightButton ( )
navigationButtonsWithNumShowingRow := container . NewHBox ( layout . NewSpacer ( ) , navigateToBeginningButton , navigateLeftButton , viewingReviewsText , navigateRightButton , navigateToEndButton , layout . NewSpacer ( ) )
return navigationButtonsWithNumShowingRow
}
viewingReviewsLabelWithNavRow := getViewingReviewsLabelWithNavRow ( )
reviewedHashLabel := getItalicLabelCentered ( "Reviewed Hash" )
2024-06-11 06:59:06 +02:00
creationTimeLabel := getItalicLabelCentered ( "Creation Time" )
2024-04-11 15:51:56 +02:00
verdictLabel := getItalicLabelCentered ( "Verdict" )
reasonLabel := getItalicLabelCentered ( "Reason" )
emptyLabel := widget . NewLabel ( "" )
reviewedHashColumn := container . NewVBox ( reviewedHashLabel , widget . NewSeparator ( ) )
2024-06-11 06:59:06 +02:00
creationTimeColumn := container . NewVBox ( creationTimeLabel , widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
verdictColumn := container . NewVBox ( verdictLabel , widget . NewSeparator ( ) )
reasonColumn := container . NewVBox ( reasonLabel , widget . NewSeparator ( ) )
viewReviewButtonsColumn := container . NewVBox ( emptyLabel , widget . NewSeparator ( ) )
viewIndexOnwardsReviewsList := myReviewsList [ viewIndex : ]
for index , reviewBytes := range viewIndexOnwardsReviewsList {
2024-06-11 06:59:06 +02:00
ableToRead , reviewHash , _ , reviewNetworkType , reviewerIdentityHash , reviewCreationTime , currentReviewType , reviewedHash , reviewVerdict , reviewMap , err := readReviews . ReadReviewAndHash ( false , reviewBytes )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
if ( ableToRead == false ) {
return nil , errors . New ( "GetMyNewestReviewsListSorted returning invalid review" )
}
if ( reviewNetworkType != appNetworkType ) {
return nil , errors . New ( "GetMyNewestReviewsListSorted returning review belonging to different networkType." )
}
if ( reviewerIdentityHash != myIdentityHash ) {
return nil , errors . New ( "GetMyNewestReviewsListSorted returning review for different identity hash." )
}
if ( currentReviewType != reviewType ) {
return nil , errors . New ( "GetMyNewestReviewsListSorted returning review of a different reviewType" )
}
reviewedHashString , err := helpers . EncodeReviewedHashBytesToString ( reviewedHash )
if ( err != nil ) { return nil , err }
reviewedHashTrimmed , _ , err := helpers . TrimAndFlattenString ( reviewedHashString , 10 )
if ( err != nil ) { return nil , err }
reviewedHashLabel := getBoldLabel ( reviewedHashTrimmed )
2024-06-11 06:59:06 +02:00
creationTimeString , err := helpers . ConvertUnixTimeToTimeFromNowTranslated ( reviewCreationTime , false )
2024-04-11 15:51:56 +02:00
if ( err != nil ) { return nil , err }
2024-06-11 06:59:06 +02:00
creationTimeLabel := getBoldLabelCentered ( creationTimeString )
2024-04-11 15:51:56 +02:00
verdictLabel := getBoldLabelCentered ( reviewVerdict )
getReviewReasonCell := func ( ) ( * fyne . Container , error ) {
reasonString , exists := reviewMap [ "Reason" ]
if ( exists == false ) {
noneLabel := getBoldItalicLabelCentered ( translate ( "None" ) )
return noneLabel , nil
}
reasonTrimmed , _ , err := helpers . TrimAndFlattenString ( reasonString , 20 )
if ( err != nil ) { return nil , err }
reasonLabel := getBoldLabel ( reasonTrimmed )
viewReasonButton := widget . NewButtonWithIcon ( "" , theme . VisibilityIcon ( ) , func ( ) {
setViewTextPage ( window , "Viewing Review Reason" , reasonString , false , currentPage )
} )
reasonCell := container . NewHBox ( layout . NewSpacer ( ) , reasonLabel , viewReasonButton , layout . NewSpacer ( ) )
return reasonCell , nil
}
reasonCell , err := getReviewReasonCell ( )
if ( err != nil ) { return nil , err }
viewReviewButton := widget . NewButtonWithIcon ( "View" , theme . VisibilityIcon ( ) , func ( ) {
setViewReviewDetailsPage ( window , reviewHash , currentPage )
} )
reviewedHashColumn . Add ( reviewedHashLabel )
2024-06-11 06:59:06 +02:00
creationTimeColumn . Add ( creationTimeLabel )
2024-04-11 15:51:56 +02:00
verdictColumn . Add ( verdictLabel )
reasonColumn . Add ( reasonCell )
viewReviewButtonsColumn . Add ( viewReviewButton )
reviewedHashColumn . Add ( widget . NewSeparator ( ) )
2024-06-11 06:59:06 +02:00
creationTimeColumn . Add ( widget . NewSeparator ( ) )
2024-04-11 15:51:56 +02:00
verdictColumn . Add ( widget . NewSeparator ( ) )
reasonColumn . Add ( widget . NewSeparator ( ) )
viewReviewButtonsColumn . Add ( widget . NewSeparator ( ) )
if ( index >= 4 ) {
break
}
}
2024-06-11 06:59:06 +02:00
reviewsGrid := container . NewHBox ( layout . NewSpacer ( ) , reviewedHashColumn , creationTimeColumn , verdictColumn , reasonColumn , viewReviewButtonsColumn , layout . NewSpacer ( ) )
2024-04-11 15:51:56 +02:00
resultsContainer := container . NewVBox ( viewingReviewsLabelWithNavRow , widget . NewSeparator ( ) , reviewsGrid )
return resultsContainer , nil
}
resultsContainer , err := getResultsContainer ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , reviewTypeLabel , reviewTypeSelectorCentered , widget . NewSeparator ( ) , description , widget . NewSeparator ( ) , resultsContainer )
setPageContent ( page , window )
}
func setViewMyModeratorScorePage ( window fyne . Window , previousPage func ( ) ) {
currentPage := func ( ) { setViewMyModeratorScorePage ( window , previousPage ) }
title := getPageTitleCentered ( "My Moderator Score" )
backButton := getBackButtonCentered ( previousPage )
description1 := getLabelCentered ( "Moderator scores are used to resolve conflicts when moderators disagree." )
description2 := getLabelCentered ( "You must have a minimum moderator score to be able to ban other moderators." )
description3 := getLabelCentered ( "If you have a higher moderator score than another, you can ban them." )
description4 := getLabelCentered ( "Increase your score by sending cryptocurrency." )
identityExists , myIdentityScore , _ , _ , _ , err := myIdentityScore . GetMyIdentityScore ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
if ( identityExists == false ) {
description5 := getBoldLabelCentered ( "Your Moderator identity does not exist." )
description6 := getLabelCentered ( "You must create it to view your Moderator Identity score." )
createIdentityButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Create Identity" , theme . NavigateNextIcon ( ) , func ( ) {
setChooseNewIdentityHashPage ( window , "Moderator" , currentPage , currentPage )
} ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , widget . NewSeparator ( ) , description5 , description6 , createIdentityButton )
setPageContent ( page , window )
return
}
myModeratorScoreString := helpers . ConvertFloat64ToStringRounded ( myIdentityScore , 3 )
moderatorScoreTitle := getItalicLabelCentered ( "My Moderator Identity Score:" )
moderatorScoreLabel := getBoldLabelCentered ( myModeratorScoreString )
refreshButton := getWidgetCentered ( widget . NewButtonWithIcon ( "Refresh" , theme . ViewRefreshIcon ( ) , func ( ) {
//TODO: Add page to download status and show progress
showUnderConstructionDialog ( window )
} ) )
getMyModeratorRankText := func ( ) ( string , error ) {
myIdentityExists , myIdentityHash , err := myIdentity . GetMyIdentityHash ( "Moderator" )
if ( err != nil ) { return "" , err }
if ( myIdentityExists == false ) {
return "" , errors . New ( "My moderator identity not found after being found already." )
}
appNetworkType , err := getAppNetworkType . GetAppNetworkType ( )
if ( err != nil ) { return "" , err }
rankingKnown , moderatorRank , totalNumberOfModerators , err := moderatorRanking . GetModeratorRanking ( myIdentityHash , appNetworkType )
if ( err != nil ) { return "" , err }
if ( rankingKnown == false ) {
result := translate ( "Unknown" )
return result , nil
}
moderatorRankString := helpers . ConvertIntToString ( moderatorRank )
totalNumberOfModeratorsString := helpers . ConvertIntToString ( totalNumberOfModerators )
moderatorRankText := moderatorRankString + "/" + totalNumberOfModeratorsString
return moderatorRankText , nil
}
myModeratorRankText , err := getMyModeratorRankText ( )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
myModeratorRankTitle := widget . NewLabel ( "My Moderator Rank:" )
myModeratorRankLabel := getBoldLabel ( myModeratorRankText )
myModeratorRankRow := container . NewHBox ( layout . NewSpacer ( ) , myModeratorRankTitle , myModeratorRankLabel , layout . NewSpacer ( ) )
getSendFundsButtonWithIcon := func ( cryptocurrencyName string ) ( * fyne . Container , error ) {
cryptocurrencyIcon , err := getFyneImageIcon ( cryptocurrencyName )
if ( err != nil ) { return nil , err }
iconSize := getCustomFyneSize ( 0 )
cryptocurrencyIcon . SetMinSize ( iconSize )
sendFundsButton := widget . NewButton ( "Send " + cryptocurrencyName , func ( ) {
nextPage := func ( ) { setViewMyAddressToIncreaseIdentityScorePage ( window , cryptocurrencyName , 50 , currentPage ) }
setCryptoIdentityScorePrivacyWarningPage ( window , currentPage , nextPage )
} )
sendFundsButtonWithIcon := container . NewGridWithColumns ( 1 , cryptocurrencyIcon , sendFundsButton )
return sendFundsButtonWithIcon , nil
}
sendFundsButtonWithIcon_Ethereum , err := getSendFundsButtonWithIcon ( "Ethereum" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
sendFundsButtonWithIcon_Cardano , err := getSendFundsButtonWithIcon ( "Cardano" )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
sendFundsButtonsRow := getContainerCentered ( container . NewGridWithColumns ( 2 , sendFundsButtonWithIcon_Ethereum , sendFundsButtonWithIcon_Cardano ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , widget . NewSeparator ( ) , moderatorScoreTitle , moderatorScoreLabel , refreshButton , widget . NewSeparator ( ) , myModeratorRankRow , widget . NewSeparator ( ) , sendFundsButtonsRow )
setPageContent ( page , window )
}
func setCryptoIdentityScorePrivacyWarningPage ( window fyne . Window , previousPage func ( ) , nextPage func ( ) ) {
title := getPageTitleCentered ( "Privacy Warning" )
backButton := getBackButtonCentered ( previousPage )
description1 := getBoldLabelCentered ( "Be aware that your privacy is at risk when using cryptocurrencies." )
description2 := getLabelCentered ( "When you send money from your wallet, all users of Seekia will see your wallet and its balance." )
description3 := getLabelCentered ( "If you have a large amount of cryptocurrency, you should not send your funds from that wallet." )
description4 := getLabelCentered ( "For privacy, you should send funds directly from an exchange." )
description5 := getLabelCentered ( "You can also use a tool such as a zero knowledge accumulator for stronger privacy." )
description6 := getBoldLabelCentered ( "Do you understand the privacy risks?" )
iUnderstandButton := getWidgetCentered ( widget . NewButtonWithIcon ( "I Understand" , theme . ConfirmIcon ( ) , nextPage ) )
page := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , description1 , description2 , description3 , description4 , description5 , description6 , iUnderstandButton )
setPageContent ( page , window )
}
func setViewMyAddressToIncreaseIdentityScorePage ( window fyne . Window , cryptocurrencyName string , reviewsToFund int64 , previousPage func ( ) ) {
if ( cryptocurrencyName != "Ethereum" && cryptocurrencyName != "Cardano" ) {
setErrorEncounteredPage ( window , errors . New ( "setViewMyAddressToIncreaseIdentityScorePage called with invalid cryptocurrencyName: " + cryptocurrencyName ) , previousPage )
return
}
currentPage := func ( ) { setViewMyAddressToIncreaseIdentityScorePage ( window , cryptocurrencyName , reviewsToFund , previousPage ) }
title := getPageTitleCentered ( "Send Moderator Funds" )
backButton := getBackButtonCentered ( previousPage )
//identityExists, identityScoreAddress, err := myIdentityScore.GetMyIdentityScoreReceivingAddress(cryptocurrency)
//if (err != nil) {
// setErrorEncounteredPage(window, err, previousPage)
// return
//}
//if (identityExists == false) {
// This should not occur, this page should not be reached unless identity exists.
// setErrorEncounteredPage(window, errors.New("Identity not found."), previousPage)
// return
//}
warning1 := getBoldLabelCentered ( "Privacy Warning: This address is linked to your moderator identity." )
warning2 := getLabelCentered ( "All users of Seekia will be able to see all address transactions." )
warning3 := getBoldLabelCentered ( "All funds will be destroyed forever." )
cryptoAddressRow , err := getCryptocurrencyAddressLabelWithCopyAndQRButtons ( window , cryptocurrencyName , "SeekiaIsNotCompleteYet" , currentPage )
if ( err != nil ) {
setErrorEncounteredPage ( window , err , previousPage )
return
}
content := container . NewVBox ( title , backButton , widget . NewSeparator ( ) , warning1 , warning2 , warning3 , widget . NewSeparator ( ) , cryptoAddressRow )
setPageContent ( content , window )
}