From 6ada694dd2cb610602179a449b52b0d2e0f55900 Mon Sep 17 00:00:00 2001
From: Tasos Bitsios <tasosbitsios@algorandfndation>
Date: Wed, 22 Jan 2025 12:56:58 +0100
Subject: [PATCH] split txn modals finished; responsive vertical spacing in QR
 view

---
 ui/modals/transaction/controller.go |   3 +-
 ui/modals/transaction/model.go      |   3 +-
 ui/modals/transaction/view.go       | 121 +++++++++++++++++++---------
 3 files changed, 83 insertions(+), 44 deletions(-)

diff --git a/ui/modals/transaction/controller.go b/ui/modals/transaction/controller.go
index e0e17b72..ade062f5 100644
--- a/ui/modals/transaction/controller.go
+++ b/ui/modals/transaction/controller.go
@@ -66,8 +66,7 @@ func (m *ViewModel) Account() *algod.Account {
 }
 
 func (m *ViewModel) IsIncentiveProtocol() bool {
-	return true // NOCOMMIT
-	// return m.State.Status.LastProtocolVersion == "https://github.com/algorandfoundation/specs/tree/236dcc18c9c507d794813ab768e467ea42d1b4d9"
+	return m.State.Status.LastProtocolVersion == "https://github.com/algorandfoundation/specs/tree/236dcc18c9c507d794813ab768e467ea42d1b4d9"
 }
 
 // Whether the 2A incentive fee should be added
diff --git a/ui/modals/transaction/model.go b/ui/modals/transaction/model.go
index c914b726..dbfe4fbe 100644
--- a/ui/modals/transaction/model.go
+++ b/ui/modals/transaction/model.go
@@ -42,8 +42,7 @@ func (m ViewModel) FormatedAddress() string {
 }
 
 func (m ViewModel) IsQREnabled() bool {
-	return true // TODO
-	// return m.State.Status.Network == "testnet-v1.0" || m.State.Status.Network == "mainnet-v1.0"
+	return m.State.Status.Network == "testnet-v1.0" || m.State.Status.Network == "mainnet-v1.0"
 }
 
 // New creates and instance of the ViewModel with a default controls.Model
diff --git a/ui/modals/transaction/view.go b/ui/modals/transaction/view.go
index f58772ec..837e89f4 100644
--- a/ui/modals/transaction/view.go
+++ b/ui/modals/transaction/view.go
@@ -9,6 +9,66 @@ import (
 	"github.com/charmbracelet/x/ansi"
 )
 
+var textHeader = "Sign this transaction to register your account as %s"
+var textOpenURLInBrowser = "Open this URL in your browser:"
+var textPeraUserPressSForQr = style.Italics("Pera wallet user? Press S to scan a QR instead.")
+var text2AFeeWarning = style.Red.Render(style.Bold(("⚠ Transaction fee set to 2 ALGO (opting in to rewards)")))
+var textScanQrOrPressS = style.Green.Render("Scan the QR code with Pera") + " or " + style.Yellow.Render("press S to show a link instead")
+var textOffline320Note1 = style.Bold("Note: this will take effect after 320 rounds (~15 min.)")
+var textOffline320Note2 = "Please keep your node running during this cooldown period."
+
+func (m ViewModel) isOffline() bool {
+	return m.ATxn.AUrlTxnKeyreg.VotePK == nil
+}
+
+func (m ViewModel) renderQRModal(renderIn string, txn string, spacing int) (render string) {
+	remainingSpaces := spacing
+	render = renderIn
+	if m.ShouldAddIncentivesFee() {
+		if remainingSpaces > 0 {
+			render = lipgloss.JoinVertical(lipgloss.Center, render, "")
+			remainingSpaces -= 1
+		}
+		render = lipgloss.JoinVertical(
+			lipgloss.Center,
+			render,
+			text2AFeeWarning,
+		)
+	}
+	if m.isOffline() {
+		if remainingSpaces > 0 {
+			render = lipgloss.JoinVertical(lipgloss.Center, render, "")
+			remainingSpaces -= 1
+		}
+		render = lipgloss.JoinVertical(
+			lipgloss.Center,
+			render,
+			textOffline320Note1,
+			textOffline320Note2,
+		)
+	}
+	// if we did not emit a space already but we can
+	if remainingSpaces > 0 {
+		render = lipgloss.JoinVertical(lipgloss.Center, render, "")
+		remainingSpaces -= 1
+	}
+	render = lipgloss.JoinVertical(
+		lipgloss.Center,
+		render,
+		textScanQrOrPressS,
+	)
+	if remainingSpaces > 0 {
+		render = lipgloss.JoinVertical(lipgloss.Center, render, "")
+		remainingSpaces -= 1
+	}
+	render = lipgloss.JoinVertical(
+		lipgloss.Center,
+		render,
+		qrStyle.Render(txn),
+	)
+	return
+}
+
 func (m ViewModel) View() string {
 	if m.Participation == nil {
 		return "No key selected"
@@ -20,29 +80,23 @@ func (m ViewModel) View() string {
 	}
 
 	var adj string
-	isOffline := m.ATxn.AUrlTxnKeyreg.VotePK == nil
-	if isOffline {
+	if m.isOffline() {
 		adj = "offline"
 	} else {
 		adj = "online"
 	}
 
-	textHeader := "Sign this transaction to register your account as %s"
-	textOpenURLInBrowser := "Open this URL in your browser:"
-	textPeraUserPressSForQr := style.Italics("Pera wallet user? Press S to scan a QR instead.")
-	text2AFeeWarning := style.Yellow.Render(style.Bold(("⚠ Transaction fee set to 2 ALGO (opting in to rewards)")))
-	textScanQrOrPressS := style.Green.Render("Scan the QR code with Pera") + " or " + style.Yellow.Render("press S to show a link instead")
-	textOffline320Note := style.Bold("Note: this will take effect after 320 rounds (~15 min.)\n") + "Please keep your node running during this cooldown period."
-
 	intro := fmt.Sprintf(textHeader, adj)
-	render := intro
+	render := ""
+	qrSpacing := 3
+	qrText, qrErr := m.ATxn.ProduceQRCode()
 
 	if m.ShowLink {
 		link := participation.ToShortLink(*m.Link, m.ShouldAddIncentivesFee())
 
 		render = lipgloss.JoinVertical(
 			lipgloss.Center,
-			render,
+			intro,
 			"",
 			textOpenURLInBrowser,
 			"",
@@ -56,12 +110,13 @@ func (m ViewModel) View() string {
 				text2AFeeWarning,
 			)
 		}
-		if isOffline {
+		if m.isOffline() {
 			render = lipgloss.JoinVertical(
 				lipgloss.Center,
 				render,
 				"",
-				textOffline320Note,
+				textOffline320Note1,
+				textOffline320Note2,
 			)
 		}
 		if m.IsQREnabled() {
@@ -75,41 +130,27 @@ func (m ViewModel) View() string {
 
 	} else {
 		// TODO: Refactor ATxn to Interface
-		txn, err := m.ATxn.ProduceQRCode()
-
-		// TODO responsive vertical spaces? calculate on modal/screen height diff
-		if m.ShouldAddIncentivesFee() {
-			render = lipgloss.JoinVertical(
+		if qrErr != nil {
+			return lipgloss.JoinVertical(
 				lipgloss.Center,
-				render,
-				text2AFeeWarning,
+				"Something went wrong while generating the QR code",
+				"Press S to display a link",
 			)
 		}
-		if isOffline {
-			render = lipgloss.JoinVertical(
-				lipgloss.Center,
-				render,
-				textOffline320Note,
-			)
-		}
-		render = lipgloss.JoinVertical(
-			lipgloss.Center,
-			render,
-			textScanQrOrPressS,
-		)
-		if err != nil {
-			return "Something went wrong"
-		}
-		render = lipgloss.JoinVertical(
-			lipgloss.Center,
-			render,
-			qrStyle.Render(txn),
-		)
+
+		render = m.renderQRModal(intro, qrText, qrSpacing)
 	}
 
 	width := lipgloss.Width(render)
 	height := lipgloss.Height(render)
 
+	for qrSpacing > 0 && !m.ShowLink && (width > m.Width || height > m.Height) {
+		qrSpacing -= 1
+		render = m.renderQRModal(intro, qrText, qrSpacing)
+		width = lipgloss.Width(render)
+		height = lipgloss.Height(render)
+	}
+
 	if !m.ShowLink && (width > m.Width || height > m.Height) {
 		return lipgloss.JoinVertical(
 			lipgloss.Center,