package gui // accountCreditGui.go implements pages to view and increase a user's account credit, and to spend credit to increase their identity balance import "fyne.io/fyne/v2" import "fyne.io/fyne/v2/widget" import "fyne.io/fyne/v2/container" import "fyne.io/fyne/v2/layout" import "fyne.io/fyne/v2/theme" import "fyne.io/fyne/v2/dialog" import "seekia/resources/currencies" import "seekia/internal/appMemory" import "seekia/internal/convertCurrencies" import "seekia/internal/globalSettings" import "seekia/internal/helpers" import "seekia/internal/network/appNetworkType/getAppNetworkType" import "seekia/internal/network/myAccountCredit" import "seekia/internal/parameters/getParameters" import "errors" import "time" func setViewMyAccountCreditPage(window fyne.Window, myIdentityType string, previousPage func()){ currentPage := func(){setViewMyAccountCreditPage(window, myIdentityType, previousPage)} appMemory.SetMemoryEntry("CurrentViewedPage", "AccountCredit") title := getPageTitleCentered("My " + myIdentityType + " Account Credit") backButton := getBackButtonCentered(previousPage) description1 := getLabelCentered("Broadcasting to the Seekia network requires credit.") description2 := getLabelCentered("You can be gifted credit to your account by sharing an account identifier.") description3 := getLabelCentered("You can also send Ethereum or Cardano to add to your account credit.") getMyCreditBalanceSection := func()(*fyne.Container, error){ appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { return nil, err } myCreditBalanceLabel := getItalicLabelCentered("My Credit Balance:") getCurrentAppCurrency := func()(string, error){ exists, currentAppCurrency, err := globalSettings.GetSetting("Currency") if (err != nil) { return "", err } if (exists == false){ return "USD", nil } return currentAppCurrency, nil } currentAppCurrencyCode, err := getCurrentAppCurrency() if (err != nil){ return nil, err } _, appCurrencySymbol, err := currencies.GetCurrencyInfoFromCurrencyCode(currentAppCurrencyCode) if (err != nil) { return nil, err } appCurrencySymbolButton := widget.NewButton(appCurrencySymbol, func(){ setChangeAppCurrencyPage(window, currentPage) }) parametersExist, appCurrencyAccountCreditBalance, err := myAccountCredit.GetMyCreditAccountBalanceInAnyCurrency(myIdentityType, appNetworkType, currentAppCurrencyCode) if (err != nil) { return nil, err } getAccountBalanceText := func()(string, error){ if (parametersExist == false){ return "Unknown", nil } appCurrencyAccountCreditBalanceString := helpers.ConvertFloat64ToStringRounded(appCurrencyAccountCreditBalance, 3) return appCurrencyAccountCreditBalanceString, nil } accountBalanceText, err := getAccountBalanceText() if (err != nil) { return nil, err } appCurrencyAccountCreditBalanceLabel := getBoldLabel(accountBalanceText + " " + currentAppCurrencyCode) myCreditBalanceRow := container.NewHBox(layout.NewSpacer(), appCurrencySymbolButton, appCurrencyAccountCreditBalanceLabel, layout.NewSpacer()) currentBalanceRefreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), func(){ if (parametersExist == false){ dialogTitle := translate("Parameters Missing.") dialogMessageA := getLabelCentered(translate("The network parameters are not downloaded.")) dialogMessageB := getLabelCentered(translate("You must wait for them to download to view your balance.")) //TODO: View progress button dialogContent := container.NewVBox(dialogMessageA, dialogMessageB) dialog.ShowCustom(dialogTitle, translate("Close"), dialogContent, window) return } //TODO showUnderConstructionDialog(window) })) myCreditBalanceSection := container.NewVBox(myCreditBalanceLabel, myCreditBalanceRow, currentBalanceRefreshButton) return myCreditBalanceSection, nil } myCreditBalanceSection, err := getMyCreditBalanceSection() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } viewAccountIdentifierButton := getWidgetCentered(widget.NewButtonWithIcon("View Account Identifier", theme.VisibilityIcon(), func(){ setAddAccountCreditWithAccountIdentifierPage(window, myIdentityType, currentPage) })) ethereumIcon, err := getFyneImageIcon("Ethereum") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } iconSize := getCustomFyneSize(0) ethereumIcon.SetMinSize(iconSize) addFundsButton_Ethereum := widget.NewButton("Send Ethereum", func(){ nextPage := func(){setAddAccountCreditWithCryptocurrencyPage(window, myIdentityType, "Ethereum", currentPage)} setBuyAccountCreditCryptoPrivacyWarningPage(window, currentPage, nextPage) }) addFundsButtonWithIcon_Ethereum := container.NewGridWithColumns(1, ethereumIcon, addFundsButton_Ethereum) cardanoIcon, err := getFyneImageIcon("Cardano") if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } cardanoIcon.SetMinSize(iconSize) addFundsButton_Cardano := widget.NewButton("Send Cardano", func(){ nextPage := func(){setAddAccountCreditWithCryptocurrencyPage(window, myIdentityType, "Cardano", currentPage)} setBuyAccountCreditCryptoPrivacyWarningPage(window, currentPage, nextPage) }) addFundsButtonWithIcon_Cardano := container.NewGridWithColumns(1, cardanoIcon, addFundsButton_Cardano) viewPricingButton := getWidgetCentered(widget.NewButtonWithIcon("View Pricing", theme.VisibilityIcon(), func(){ setViewSeekiaPricingPage(window, currentPage) })) addFundsButtonsGrid := getContainerCentered(container.NewGridWithColumns(2, addFundsButtonWithIcon_Ethereum, addFundsButtonWithIcon_Cardano)) page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), myCreditBalanceSection, widget.NewSeparator(), viewAccountIdentifierButton, widget.NewSeparator(), addFundsButtonsGrid, widget.NewSeparator(), viewPricingButton) setPageContent(page, window) } func setAddAccountCreditWithAccountIdentifierPage(window fyne.Window, myIdentityType string, previousPage func()){ title := getPageTitleCentered("Add Account Credit") backButton := getBackButtonCentered(previousPage) description1 := getLabelCentered("Use this identifier to receive account credit.") appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } viewUsedIdentifiersButton := getWidgetCentered(widget.NewButtonWithIcon("View Used Identifiers", theme.HistoryIcon(), func(){ //TODO showUnderConstructionDialog(window) })) identityExists, unusedAccountIdentifier, err := myAccountCredit.GetAnUnusedCreditAccountIdentifier(myIdentityType, appNetworkType) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } if (identityExists == false){ setErrorEncounteredPage(window, errors.New("setAddAccountCreditWithAccountIdentifierPage called when identity is missing"), previousPage) return } myIdentifierLabel := getBoldLabelCentered("My Account Identifier:") identifierEntry := widget.NewEntry() identifierEntry.SetText(unusedAccountIdentifier) identifierEntry.OnChanged = func(_ string){ identifierEntry.SetText(unusedAccountIdentifier) } identifierEntryBoxed := getWidgetBoxed(identifierEntry) entryWidener := widget.NewLabel(" ") entryWidened := getContainerCentered(container.NewGridWithColumns(1, identifierEntryBoxed, entryWidener)) page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, widget.NewSeparator(), viewUsedIdentifiersButton, widget.NewSeparator(), myIdentifierLabel, entryWidened) setPageContent(page, window) } func setBuyAccountCreditCryptoPrivacyWarningPage(window fyne.Window, previousPage func(), nextPage func()){ title := getPageTitleCentered("Privacy Warning") backButton := getBackButtonCentered(previousPage) description1 := getLabelCentered("Be aware that your privacy is at risk when using cryptocurrencies.") description2 := getLabelCentered("When you send money from your wallet, it is possible to guess that you are a user of Seekia.") description3 := getLabelCentered("There is also a risk of someone linking your wallet to your Seekia identity.") description4 := getBoldLabelCentered("To protect yourself, wait before funding your Seekia identity.") description5 := getLabelCentered("For example, after funding your account, wait a few days before funding your identity.") description6 := getLabelCentered("This will break the link between your transaction and your Seekia profile/identity.") description7 := getLabelCentered("If you have a large amount of cryptocurrency, you should be wary of sending your funds from that wallet.") description8 := getLabelCentered("For privacy, you should send funds directly from an exchange.") description9 := getLabelCentered("You can also use a privacy tool such as a zero knowledge accumulator for stronger protection.") description10 := 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, widget.NewSeparator(), description4, description5, description6, widget.NewSeparator(), description7, description8, description9, widget.NewSeparator(), description10, iUnderstandButton) setPageContent(page, window) } func setAddAccountCreditWithCryptocurrencyPage(window fyne.Window, myIdentityType string, cryptocurrency string, previousPage func()){ setLoadingScreen(window, "Add " + myIdentityType + " Account Credit", "Loading Add Account Credit page...") if (cryptocurrency != "Ethereum" && cryptocurrency != "Cardano"){ setErrorEncounteredPage(window, errors.New("Invalid cryptocurrency: " + cryptocurrency), previousPage) return } currentPage := func(){setAddAccountCreditWithCryptocurrencyPage(window, myIdentityType, cryptocurrency, previousPage)} title := getPageTitleCentered("Add " + myIdentityType + " Account Credit") backButton := getBackButtonCentered(previousPage) viewUsedAddressesButton := getWidgetCentered(widget.NewButtonWithIcon("View Used Addresses", theme.HistoryIcon(), func(){ //TODO showUnderConstructionDialog(window) })) appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } myIdentityExists, myFundsAddress, err := myAccountCredit.GetAnUnusedCreditAccountCryptoAddress(myIdentityType, appNetworkType, cryptocurrency) if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } if (myIdentityExists == false){ description1 := getBoldLabelCentered("Your " + myIdentityType + " identity does not exist.") descriptionB := getLabelCentered("Create your identity?.") createIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Create Identity", theme.NavigateNextIcon(), func(){ setChooseNewIdentityHashPage(window, myIdentityType, currentPage, currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, descriptionB, createIdentityButton) setPageContent(page, window) return } description1 := getLabelCentered("Send " + cryptocurrency + " to increase your account credit.") descriptionB := getBoldLabelCentered("All funds sent will be destroyed forever.") cryptoAddressLabelRow, err := getCryptocurrencyAddressLabelWithCopyAndQRButtons(window, cryptocurrency, myFundsAddress, currentPage) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } estimateCostsDescription := getLabelCentered("Use the page below to determine how much you should send.") viewPricingButton := getWidgetCentered(widget.NewButtonWithIcon("View Pricing", theme.VisibilityIcon(), func(){ setViewSeekiaPricingPage(window, currentPage) })) page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, descriptionB, widget.NewSeparator(), viewUsedAddressesButton, widget.NewSeparator(), cryptoAddressLabelRow, widget.NewSeparator(), estimateCostsDescription, viewPricingButton) setPageContent(page, window) return } // This page is used to show how much it costs to fund broadcasts on the Seekia network func setViewSeekiaPricingPage(window fyne.Window, previousPage func()){ currentPage := func(){setViewSeekiaPricingPage(window, previousPage)} title := getPageTitleCentered("Seekia Pricing (Under Construction)") backButton := getBackButtonCentered(previousPage) description := getLabelCentered("Below are the estimated prices to broadcast content on the Seekia network.") getAppCurrency := func()(string, error){ exists, appCurrencyCode, err := globalSettings.GetSetting("Currency") if (err != nil) { return "", err } if (exists == false){ return "USD", nil } return appCurrencyCode, nil } appCurrencyCode, err := getAppCurrency() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } currentCurrencyLabel := getBoldLabelCentered("Current Currency:") _, appCurrencySymbol, err := currencies.GetCurrencyInfoFromCurrencyCode(appCurrencyCode) if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } chooseCurrencyButton := widget.NewButton(appCurrencySymbol + appCurrencyCode, func(){ setChangeAppCurrencyPage(window, currentPage) }) currentCurrencyRow := container.NewHBox(layout.NewSpacer(), currentCurrencyLabel, chooseCurrencyButton, layout.NewSpacer()) actionNameLabel := getItalicLabelCentered("Action Name") costLabel := getItalicLabelCentered("Cost") actionNameColumn := container.NewVBox(actionNameLabel, widget.NewSeparator()) costColumn := container.NewVBox(costLabel, widget.NewSeparator()) appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } //Outputs: // -bool: Parameters exist // -error addActionRows := func()(bool, error){ exchangeRatesAreDownloaded, err := convertCurrencies.CheckIfExchangeRatesAreDownloaded(appNetworkType) if (err != nil){ return false, err } if (exchangeRatesAreDownloaded == false){ return false, nil } //Outputs: // -bool: Exchange rates exist // -error addActionRow := func(actionName string, costInGramsOfGold float64)(bool, error){ costInKilogramsOfGold := costInGramsOfGold/1000 exchangeRateExists, appCurrencyCostFloat64, err := convertCurrencies.ConvertKilogramsOfGoldToAnyCurrency(appNetworkType, costInKilogramsOfGold, appCurrencyCode) if (err != nil) { return false, err } if (exchangeRateExists == false) { return false, nil } appCurrencyCostString := helpers.ConvertFloat64ToStringRounded(appCurrencyCostFloat64, 3) appCurrencyCostFormatted := appCurrencySymbol + " " + appCurrencyCostString + " " + appCurrencyCode actionNameText := getBoldLabelCentered(actionName) currencyCostLabel := getBoldLabelCentered(appCurrencyCostFormatted) actionNameColumn.Add(actionNameText) costColumn.Add(currencyCostLabel) actionNameColumn.Add(widget.NewSeparator()) costColumn.Add(widget.NewSeparator()) return true, nil } currentTime := time.Now().Unix() parametersExist, messageKilobyteGoldCostPerDay, err := getParameters.GetMessageKilobyteGoldCostPerDay(appNetworkType, currentTime) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } //TODO: Fix below numbers textMessageSizeKilobytes := float64(2) imageMessageSizeKilobytes := float64(22) textMessageGramsOfGoldCost := messageKilobyteGoldCostPerDay * textMessageSizeKilobytes * 14 imageMessageGramsOfGoldCost := messageKilobyteGoldCostPerDay * imageMessageSizeKilobytes * 14 parametersExist, err = addActionRow("Send 100 Text Messages", textMessageGramsOfGoldCost * 100) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, err = addActionRow("Send 100 Image Messages", imageMessageGramsOfGoldCost * 100) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, mateIdentityGoldCostPerDay, err := getParameters.GetIdentityBalanceGoldCostPerDay(appNetworkType, "Mate", currentTime) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, err = addActionRow("Fund Mate Identity for 3 Months", mateIdentityGoldCostPerDay * 90) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, hostIdentityGoldCostPerDay, err := getParameters.GetIdentityBalanceGoldCostPerDay(appNetworkType, "Host", currentTime) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, err = addActionRow("Fund Host Identity for 3 Months", hostIdentityGoldCostPerDay * 90) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, fundMateProfileCost, err := getParameters.GetFundMateProfileCostInGold(appNetworkType, currentTime) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, err = addActionRow("Broadcast Mate Profile 30 Times", fundMateProfileCost * 30) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, fundReportCost, err := getParameters.GetFundReportCostInGold(appNetworkType, currentTime) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } parametersExist, err = addActionRow("Make 10 Reports", fundReportCost * 10) if (err != nil) { return false, err } if (parametersExist == false){ return false, nil } return true, nil } parametersExist, err := addActionRows() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } if (parametersExist == false){ description1 := getBoldLabelCentered("Currency exchange rates are not downloaded.") descriptionB := getLabelCentered("Please wait for them to download to view pricing.") //TODO: Add monitor button refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage)) page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, descriptionB, refreshButton) setPageContent(page, window) return } pricingGrid := container.NewHBox(layout.NewSpacer(), actionNameColumn, costColumn, layout.NewSpacer()) calculateDescription := getLabelCentered("Use the pages below to calculate costs.") identityIcon, err := getFyneImageIcon("Profile") if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } chatIcon, err := getFyneImageIcon("Chat") if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } identityCostsButton := widget.NewButton("Identity Costs", func(){ setViewIdentityBalancePriceCalculatorPage(window, "Mate", 30, currentPage) }) chatCostsButton := widget.NewButton("Chat Costs", func(){ setViewMessagePricingCalculatorPage(window, "Image", 14, 100, currentPage) }) identityCostsButtonWithIcon := container.NewGridWithColumns(1, identityIcon, identityCostsButton) chatCostsButtonWithIcon := container.NewGridWithColumns(1, chatIcon, chatCostsButton) buttonsGrid := getContainerCentered(container.NewGridWithRows(1, identityCostsButtonWithIcon, chatCostsButtonWithIcon)) page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), currentCurrencyRow, widget.NewSeparator(), pricingGrid, widget.NewSeparator(), calculateDescription, buttonsGrid) setPageContent(page, window) } // This page is used to show how much it costs to fund a user on the Seekia network // Users use this to determine how much money to send to their account func setViewIdentityBalancePriceCalculatorPage(window fyne.Window, identityType string, daysToFund int, previousPage func()){ currentPage := func(){setViewIdentityBalancePriceCalculatorPage(window, identityType, daysToFund, previousPage)} if (identityType != "Mate" && identityType != "Host"){ setErrorEncounteredPage(window, errors.New("setViewIdentityBalancePriceCalculatorPage called with invalid identityType: " + identityType), previousPage) return } title := getPageTitleCentered("Identity Balance Pricing") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Calculate Identity Balance Pricing") appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } //Outputs: // -bool: Parameters exist // -*fyne.Container: Calculator section // -error getCalculatorContainer := func()(bool, *fyne.Container, error){ currentTime := time.Now().Unix() exchangeRatesAreDownloaded, err := convertCurrencies.CheckIfExchangeRatesAreDownloaded(appNetworkType) if (err != nil){ return false, nil, err } if (exchangeRatesAreDownloaded == false){ return false, nil, nil } identityTypeLabel := getBoldLabelCentered("Identity Type:") identityTypesList := []string{"Mate", "Host"} identityTypeSelector := widget.NewSelect(identityTypesList, func(newIdentityType string){ if (newIdentityType == identityType){ return } setViewIdentityBalancePriceCalculatorPage(window, newIdentityType, daysToFund, previousPage) }) identityTypeSelector.Selected = identityType identityTypeSelectorCentered := getWidgetCentered(identityTypeSelector) daysToFundSelectorFunction := func(entry string){ if (entry == "1 month"){ if (daysToFund == 30){ return } setViewIdentityBalancePriceCalculatorPage(window, identityType, 30, previousPage) } if (entry == "3 months"){ if (daysToFund == 90){ return } setViewIdentityBalancePriceCalculatorPage(window, identityType, 90, previousPage) } if (entry == "6 months"){ if (daysToFund == 180){ return } setViewIdentityBalancePriceCalculatorPage(window, identityType, 180, previousPage) } } desiredDurationLabel := getBoldLabelCentered("Desired Duration:") daysToFundSelectorOptions := []string{"1 month", "3 months", "6 months"} daysToFundSelector := widget.NewSelect(daysToFundSelectorOptions, daysToFundSelectorFunction) if (daysToFund == 30){ daysToFundSelector.Selected = "1 month" } else if (daysToFund == 90){ daysToFundSelector.Selected = "3 months" } else if (daysToFund == 180){ daysToFundSelector.Selected = "6 months" } daysToFundSelectorCentered := getWidgetCentered(daysToFundSelector) costLabel := getBoldLabelCentered("Cost:") parametersExist, gramsOfGoldCostPerDay, err := getParameters.GetIdentityBalanceGoldCostPerDay(appNetworkType, identityType, currentTime) if (err != nil) { return false, nil, err } if (parametersExist == false){ return false, nil, nil } gramsOfGoldCost := gramsOfGoldCostPerDay * float64(daysToFund) kilogramsOfGoldCost := gramsOfGoldCost/1000 getAppCurrency := func()(string, error){ exists, appCurrencyCode, err := globalSettings.GetSetting("Currency") if (err != nil) { return "", err } if (exists == false){ return "USD", nil } return appCurrencyCode, nil } appCurrencyCode, err := getAppCurrency() if (err != nil) { return false, nil, err } exchangeRateExists, appCurrencyCost, err := convertCurrencies.ConvertKilogramsOfGoldToAnyCurrency(appNetworkType, kilogramsOfGoldCost, appCurrencyCode) if (err != nil) { return false, nil, err } if (exchangeRateExists == false) { return false, nil, nil } appCurrencyCostString := helpers.ConvertFloat64ToStringRounded(appCurrencyCost, 2) _, appCurrencySymbol, err := currencies.GetCurrencyInfoFromCurrencyCode(appCurrencyCode) if (err != nil) { return false, nil, err } appCurrencyIconButton := widget.NewButton(appCurrencySymbol, func(){ setChangeAppCurrencyPage(window, currentPage) }) appCurrencyCostLabel := getBoldLabel(appCurrencyCostString + " " + appCurrencyCode) appCurrencyRow := container.NewHBox(layout.NewSpacer(), appCurrencyIconButton, appCurrencyCostLabel, layout.NewSpacer()) calculatorContainer := container.NewVBox(identityTypeLabel, identityTypeSelectorCentered, widget.NewSeparator(), desiredDurationLabel, daysToFundSelectorCentered, widget.NewSeparator(), costLabel, appCurrencyRow) return true, calculatorContainer, nil } parametersExist, calculatorContainer, err := getCalculatorContainer() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } if (parametersExist == false){ description1 := getBoldLabelCentered("Network parameters are not downloaded.") description2 := getLabelCentered("Please wait for them to download.") //TODO: Add page to monitor download progress. refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage)) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, refreshButton) setPageContent(page, window) return } description1 := getLabelCentered("Calculate identity balance pricing below.") description2 := getLabelCentered("All mate and host identities must be funded before broadcasting profiles.") description3 := getLabelCentered("You can always increase your identity balance later.") page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), calculatorContainer) setPageContent(page, window) } // This page is used to show how much it costs to fund messages // Users can use this to determine how much credit to send to their account func setViewMessagePricingCalculatorPage(window fyne.Window, messageType string, messageDuration int64, numberOfMessages int, previousPage func()){ if (messageType != "Image" && messageType != "Text"){ setErrorEncounteredPage(window, errors.New("setViewMessagePricingCalculatorPage called with invalid messageType: " + messageType), previousPage) return } if (messageDuration != 2 && messageDuration != 14){ setErrorEncounteredPage(window, errors.New("setViewMessagePricingCalculatorPage called with invalid messageDuration."), previousPage) return } if (numberOfMessages != 10 && numberOfMessages != 100 && numberOfMessages != 1000){ setErrorEncounteredPage(window, errors.New("setViewMessagePricingCalculatorPage called with invalid numberOfMessages."), previousPage) return } currentPage := func(){setViewMessagePricingCalculatorPage(window, messageType, messageDuration, numberOfMessages, previousPage)} title := getPageTitleCentered("Message Pricing Calculator") backButton := getBackButtonCentered(previousPage) subtitle := getPageSubtitleCentered("Calculate Message Costs") appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } //Outputs: // -bool: Parameters exist // -*fyne.Container: Calculator section // -error getPricingCalculatorSection := func()(bool, *fyne.Container, error){ messageTypeLabel := getBoldLabelCentered("Message Type:") messageTypesList := []string{"Image", "Text"} messageTypeSelector := widget.NewSelect(messageTypesList, func(newMessageType string){ if (newMessageType == messageType){ return } setViewMessagePricingCalculatorPage(window, newMessageType, messageDuration, numberOfMessages, previousPage) }) messageTypeSelector.Selected = messageType messageTypeSelectorCentered := getWidgetCentered(messageTypeSelector) messageDurationLabel := getBoldLabelCentered("Message Duration:") durationOptionsList := []string{"2 days", "2 weeks"} durationSelectFunction := func(newDuration string){ if (newDuration == "2 days"){ if (messageDuration == 2){ return } setViewMessagePricingCalculatorPage(window, messageType, 2, numberOfMessages, previousPage) return } if (newDuration == "2 weeks"){ if (messageDuration == 14){ return } setViewMessagePricingCalculatorPage(window, messageType, 14, numberOfMessages, previousPage) return } } durationSelector := widget.NewSelect(durationOptionsList, durationSelectFunction) if (messageDuration == 2){ durationSelector.Selected = "2 days" } else if (messageDuration == 14){ durationSelector.Selected = "2 weeks" } durationSelectorCentered := getWidgetCentered(durationSelector) numberOfMessagesLabel := getBoldLabelCentered("Number Of Messages:") numberOfMessagesOptionsList := []string{"10 Messages", "100 Messages", "1000 Messages"} numberOfMessagesSelector := widget.NewSelect(numberOfMessagesOptionsList, func(newNumberOfMessages string){ if (newNumberOfMessages == "10 Messages"){ if (numberOfMessages == 10){ return } setViewMessagePricingCalculatorPage(window, messageType, messageDuration, 10, previousPage) return } if (newNumberOfMessages == "100 Messages"){ if (numberOfMessages == 100){ return } setViewMessagePricingCalculatorPage(window, messageType, messageDuration, 100, previousPage) return } if (newNumberOfMessages == "1000 Messages"){ if (numberOfMessages == 1000){ return } setViewMessagePricingCalculatorPage(window, messageType, messageDuration, 1000, previousPage) return } }) if (numberOfMessages == 10){ numberOfMessagesSelector.Selected = "10 Messages" } else if (numberOfMessages == 100){ numberOfMessagesSelector.Selected = "100 Messages" } else if (numberOfMessages == 1000){ numberOfMessagesSelector.Selected = "1000 Messages" } numberOfMessagesSelectorCentered := getWidgetCentered(numberOfMessagesSelector) costLabel := getBoldLabelCentered("Cost:") currentTime := time.Now().Unix() parametersExist, messageKilobyteGoldCostPerDay, err := getParameters.GetMessageKilobyteGoldCostPerDay(appNetworkType, currentTime) if (err != nil) { return false, nil, err } if (parametersExist == false){ return false, nil, nil } getMessageSizeKilobytes := func()int{ //TODO: Fix below numbers if (messageType == "Text"){ return 2 } // messageType == "Image" return 22 } messageSizeKilobytes := getMessageSizeKilobytes() gramsOfGoldCost := messageKilobyteGoldCostPerDay * float64(messageSizeKilobytes) * float64(messageDuration) * float64(numberOfMessages) kilogramsOfGoldCost := gramsOfGoldCost/1000 exchangeRatesExist, err := convertCurrencies.CheckIfExchangeRatesAreDownloaded(appNetworkType) if (err != nil) { return false, nil, err } if (exchangeRatesExist == false){ return false, nil, nil } getAppCurrencyCode := func()(string, error){ exists, appCurrencyCode, err := globalSettings.GetSetting("Currency") if (err != nil) { return "", err } if (exists == false){ return "USD", nil } return appCurrencyCode, nil } appCurrencyCode, err := getAppCurrencyCode() if (err != nil) { return false, nil, err } parametersExist, appCurrencyCost, err := convertCurrencies.ConvertKilogramsOfGoldToAnyCurrency(appNetworkType, kilogramsOfGoldCost, appCurrencyCode) if (err != nil) { return false, nil, err } if (parametersExist == false){ return false, nil, nil } _, appCurrencyUnitsSymbol, err := currencies.GetCurrencyInfoFromCurrencyCode(appCurrencyCode) if (err != nil) { return false, nil, err } appCurrencyCostString := helpers.ConvertFloat64ToStringRounded(appCurrencyCost, 2) appCurrencySymbolButton := widget.NewButton(appCurrencyUnitsSymbol, func(){ setChangeAppCurrencyPage(window, currentPage) }) appCurrencyLabel := getBoldLabel(appCurrencyCostString + " " + appCurrencyCode) appCurrencyRow := container.NewHBox(layout.NewSpacer(), appCurrencySymbolButton, appCurrencyLabel, layout.NewSpacer()) pricingCalculatorSection := container.NewVBox(messageTypeLabel, messageTypeSelectorCentered, widget.NewSeparator(), messageDurationLabel, durationSelectorCentered, widget.NewSeparator(), numberOfMessagesLabel, numberOfMessagesSelectorCentered, widget.NewSeparator(), costLabel, appCurrencyRow) return true, pricingCalculatorSection, nil } parametersExist, pricingCalculatorSection, err := getPricingCalculatorSection() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } if (parametersExist == false){ description1 := getBoldLabelCentered("Network parameters are not downloaded.") description2 := getLabelCentered("Please wait for them to download.") //TODO: Add page to monitor download progress. refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage)) page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, refreshButton) setPageContent(page, window) return } description := getLabelCentered("Use this calculator to estimate message costs.") page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description, widget.NewSeparator(), pricingCalculatorSection) setPageContent(page, window) } func setIncreaseMyIdentityBalancePage(window fyne.Window, myIdentityType string, daysToFund int, previousPage func()){ if (myIdentityType != "Mate" && myIdentityType != "Host"){ setErrorEncounteredPage(window, errors.New("setIncreaseMyIdentityBalancePage called with invalid myIdentityType: " + myIdentityType), previousPage) } currentPage := func(){setIncreaseMyIdentityBalancePage(window, myIdentityType, daysToFund, previousPage)} title := getPageTitleCentered("Increase Identity Balance") backButton := getBackButtonCentered(previousPage) appNetworkType, err := getAppNetworkType.GetAppNetworkType() if (err != nil) { setErrorEncounteredPage(window, err, previousPage) return } //Outputs: // -bool: Parameters exist // -*fyne.Container // -error getPageContent := func()(bool, *fyne.Container, error){ description := getLabelCentered("Choose the amount of time to add to your identity balance.") myCreditBalanceLabel := getItalicLabelCentered("My Credit Balance:") getCurrentAppCurrency := func()(string, error){ exists, currentAppCurrency, err := globalSettings.GetSetting("Currency") if (err != nil) { return "", err } if (exists == false){ return "USD", nil } return currentAppCurrency, nil } currentAppCurrencyCode, err := getCurrentAppCurrency() if (err != nil){ return false, nil, err } _, appCurrencySymbol, err := currencies.GetCurrencyInfoFromCurrencyCode(currentAppCurrencyCode) if (err != nil){ return false, nil, err } appCurrencySymbolButton1 := widget.NewButton(appCurrencySymbol, func(){ setChangeAppCurrencyPage(window, currentPage) }) parametersExist, appCurrencyAccountCreditBalance, err := myAccountCredit.GetMyCreditAccountBalanceInAnyCurrency(myIdentityType, appNetworkType, currentAppCurrencyCode) if (err != nil){ return false, nil, err } if (parametersExist == false){ return false, nil, nil } getAccountBalanceText := func()(string, error){ if (parametersExist == false){ return "Unknown", nil } appCurrencyAccountCreditBalanceString := helpers.ConvertFloat64ToStringRounded(appCurrencyAccountCreditBalance, 3) return appCurrencyAccountCreditBalanceString, nil } accountBalanceText, err := getAccountBalanceText() if (err != nil){ return false, nil, err } appCurrencyAccountCreditBalanceLabel := getBoldLabel(accountBalanceText + " " + currentAppCurrencyCode) myCreditBalanceRow := container.NewHBox(layout.NewSpacer(), appCurrencySymbolButton1, appCurrencyAccountCreditBalanceLabel, layout.NewSpacer()) manageMyBalanceButton := getWidgetCentered(widget.NewButtonWithIcon("Manage", theme.VisibilityIcon(), func(){ setViewMyAccountCreditPage(window, myIdentityType, currentPage) })) currentTime := time.Now().Unix() selectTimeDescription := getLabelCentered("Select the amount of time to fund.") //TODO: Make clear that there is a minimum amount that must be initially sent and show that value in the GUI timeOptionsList := []string{"1 Day", "1 Week", "1 Month", "3 Months", "6 Months"} timeToFundSelector := widget.NewSelect(timeOptionsList, func(response string){ getNewDaysToFund := func()int{ if (response == "1 Day"){ return 1 } if (response == "1 Week"){ return 7 } if (response == "1 Month"){ return 30 } if (response == "3 Months"){ return 90 } // response == "6 Months" return 180 } newDaysToFund := getNewDaysToFund() if (newDaysToFund == daysToFund){ return } setIncreaseMyIdentityBalancePage(window, myIdentityType, newDaysToFund, previousPage) }) if (daysToFund == 1){ timeToFundSelector.Selected = "1 Day" } else if (daysToFund == 7){ timeToFundSelector.Selected = "1 Week" } else if (daysToFund == 30){ timeToFundSelector.Selected = "1 Month" } else if (daysToFund == 90){ timeToFundSelector.Selected = "3 Months" } else if (daysToFund == 180){ timeToFundSelector.Selected = "6 Months" } timeToFundSelectorCentered := getWidgetCentered(timeToFundSelector) costLabel := getLabelCentered("Cost:") parametersExist, gramsOfGoldCostPerDay, err := getParameters.GetIdentityBalanceGoldCostPerDay(appNetworkType, myIdentityType, currentTime) if (err != nil){ return false, nil, err } if (parametersExist == false){ return false, nil, nil } appCurrencySymbolButton2 := widget.NewButton(appCurrencySymbol, func(){ setChangeAppCurrencyPage(window, currentPage) }) costInKilogramsOfGold := (gramsOfGoldCostPerDay/1000) * float64(daysToFund) parametersExist, appCurrencyCost, err := convertCurrencies.ConvertKilogramsOfGoldToAnyCurrency(appNetworkType, costInKilogramsOfGold, currentAppCurrencyCode) if (err != nil){ return false, nil, err } appCurrencyCostString := helpers.ConvertFloat64ToStringRounded(appCurrencyCost, 3) appCurrencyLabel := getBoldLabel(appCurrencyCostString + " " + currentAppCurrencyCode) costRow := container.NewHBox(layout.NewSpacer(), appCurrencySymbolButton2, appCurrencyLabel, layout.NewSpacer()) confirmButton := getWidgetCentered(widget.NewButtonWithIcon("Confirm Payment", theme.ConfirmIcon(), func(){ //TODO showUnderConstructionDialog(window) })) pageContent := container.NewVBox(description, widget.NewSeparator(), myCreditBalanceLabel, myCreditBalanceRow, manageMyBalanceButton, widget.NewSeparator(), selectTimeDescription, timeToFundSelectorCentered, widget.NewSeparator(), costLabel, costRow, widget.NewSeparator(), confirmButton) return true, pageContent, nil } parametersExist, pageContent, err := getPageContent() if (err != nil){ setErrorEncounteredPage(window, err, previousPage) return } if (parametersExist == false){ description1 := getBoldLabelCentered("Seekia is missing the network parameters.") description2 := getLabelCentered("You must wait for them to download.") //TODO: View progress page refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage)) page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, refreshButton) setPageContent(page, window) return } page := container.NewVBox(title, backButton, widget.NewSeparator(), pageContent) setPageContent(page, window) }