Files
gen1recomp/src/import/online/TradeScreen.lua
T
2026-08-28 10:14:44 -04:00

319 lines
11 KiB
Lua

local Kit = require("src.ui.kit.Kit")
local Theme = require("src.ui.kit.Theme")
local Strings = require("src.core.Strings")
local Ui = require("src.import.online.Ui")
local PAL = Theme.PAL
local TradeScreen = {}
local function LV() return require("src.import.LauncherView") end
local function OP() return require("src.import.OnlinePanel") end
local function Client() return require("src.online.Client") end
local function Sprites() return require("src.online.OnlineSprites") end
local function rowId(side, row, at)
local key = tostring(row.key or row.index or at):gsub("|", "-")
return ("online-trade-%s-%s"):format(side, key)
end
local function column(imp, x, y, w, m, side, rows, onPick)
local _, gap, tiny = Ui.pads(m)
local rowH = math.max(m.rowH, Kit.tapMin())
local cy = y
if #rows == 0 then
Kit.emptyBox(x, cy, w, rowH, Strings("No POKeMON here."))
return rowH + gap
end
local sprites = Sprites()
local iconSize = math.max(16, math.floor(rowH * 0.62))
for at, row in ipairs(rows) do
local pick = row.ref ~= nil and row.ref or row.index
local ink = LV().rowHit(imp, x, cy, w, rowH, row.picked,
rowId(side, row, at), function()
if row.pickable == false then return end
onPick(pick)
end)
local tx = x + math.floor(10 * m.s)
local sprite = sprites.get(row.version, row.mon)
if sprite and sprites.drawIcon(sprite, tx, cy + (rowH - iconSize) / 2,
iconSize) then
tx = tx + iconSize + math.floor(6 * m.s)
end
Kit.text("small", Kit.ellipsize("small", row.label,
w - (tx - x) - math.floor(10 * m.s)), tx,
cy + (rowH - Kit.textHeight("small")) / 2,
(row.pickable == false) and PAL.faint or (ink or PAL.text))
cy = cy + rowH + tiny
end
return (cy - y) + gap
end
local function localTrade(imp, x, y, w, m)
local OnlinePanel = OP()
local tr = OnlinePanel.tradeState(imp)
local c = OnlinePanel.cache(imp)
local _, gap, tiny = Ui.pads(m)
local rowH = math.max(m.btnH, Kit.tapMin())
local cy = y
local colW = math.floor((w - gap) / 2)
if #c.tradeSlots < 2 then
Kit.emptyBox(x, cy, w, rowH * 2,
Strings("Trading needs two saves on this machine."))
return (rowH * 2) + gap
end
cy = cy + Ui.label(Strings("Saves"), x, cy) + tiny
for i, side in ipairs({ "a", "b" }) do
local entry = tr.sides[side]
Ui.chooser(imp, x + (i - 1) * (colW + gap), cy, colW, rowH,
"online-trade-slot-" .. side,
entry and entry.label or Strings("Pick a save"),
function() OnlinePanel.tradeCycleSide(imp, side, -1) end,
function() OnlinePanel.tradeCycleSide(imp, side, 1) end)
end
cy = cy + rowH + gap
local tallest = 0
for i, side in ipairs({ "a", "b" }) do
local sx = x + (i - 1) * (colW + gap)
local view = OnlinePanel.tradeSideView(imp, side)
local h
if view and not view.handle then
Kit.emptyBox(sx, cy, colW, rowH,
tostring(view.reason or "that save can't be read"))
h = rowH + gap
else
h = column(imp, sx, cy, colW, m, side, c.tradeRows[side] or {},
function(ref) OnlinePanel.tradePick(imp, side, ref) end)
if OnlinePanel.tradePcAllowed(imp, side) then
LV().btn(imp, sx, cy + h, colW, rowH, "online-trade-pc-" .. side,
Strings("From PC"),
{ kind = "ghost", font = "small",
action = function()
OnlinePanel.pcOpen(imp, { side = side })
end })
h = h + rowH + tiny
end
end
tallest = math.max(tallest, h)
end
cy = cy + tallest
LV().btn(imp, x, cy, w, rowH, "online-trade-preview", Strings("Preview"),
{ kind = "primary", font = "small",
enabled = tr.picks.a ~= nil and tr.picks.b ~= nil,
action = function() OnlinePanel.tradeModalPreview(imp) end })
cy = cy + rowH + tiny
if tr.status then
cy = cy + Kit.textWrapped("small", tostring(tr.status), x, cy, w,
tr.statusOk and PAL.green or PAL.yellow, 3) + tiny
end
return cy - y
end
local function remoteTrade(imp, x, y, w, m)
local OnlinePanel = OP()
local st = OnlinePanel.state(imp)
local tr = OnlinePanel.tradeState(imp)
local _, gap, tiny = Ui.pads(m)
local rowH = math.max(m.btnH, Kit.tapMin())
local cy = y
local colW = math.floor((w - gap) / 2)
local online = Client().state() == "online"
if tr.remote then
local stage = tr.remote:stage()
cy = cy + Kit.textWrapped("small", OnlinePanel.remoteStageText(stage),
x, cy, w, PAL.heading, 2) + tiny
local mine, theirs = OnlinePanel.remoteRows(tr.remote)
local left = column(imp, x, cy, colW, m, "mine", mine, function(ref)
OnlinePanel.remotePick(imp, ref)
end)
local right = column(imp, x + colW + gap, cy, colW, m, "theirs", theirs,
function() end)
cy = cy + math.max(left, right)
local third = math.floor((w - 2 * gap) / 3)
LV().btn(imp, x, cy, third, rowH, "online-trade-yes", Strings("Confirm"),
{ kind = "primary", font = "small", enabled = stage == "confirming",
action = function() OnlinePanel.remoteConfirm(imp, true) end })
LV().btn(imp, x + third + gap, cy, third, rowH, "online-trade-no",
Strings("Say no"),
{ kind = "ghost", font = "small", enabled = stage == "confirming",
action = function() OnlinePanel.remoteConfirm(imp, false) end })
LV().btn(imp, x + 2 * (third + gap), cy, third, rowH,
"online-trade-cancel", Strings("Cancel"),
{ kind = "danger", font = "small",
action = function() OnlinePanel.endRemoteTrade(imp) end })
return (cy + rowH + gap) - y
end
local refusal = OnlinePanel.remoteTradeRefusal(imp)
if refusal then
cy = cy + Kit.textWrapped("small", refusal, x, cy, w, PAL.yellow, 3) + tiny
end
LV().btn(imp, x, cy, w, rowH, "online-trade-remote-start",
Strings("Set up a trade"),
{ kind = "primary", font = "small", enabled = online,
action = function() OnlinePanel.startWizard(imp, "tradeRemote") end })
cy = cy + rowH + tiny
local note = tr.remoteError or tr.remoteResult or tr.status or st.status
if note then
cy = cy + Kit.textWrapped("small", tostring(note), x, cy, w,
tr.remoteError and PAL.red or PAL.muted, 3) + tiny
end
return cy - y
end
local MODES = {
{ id = "local", title = "On this device",
note = "Trade between two saves on this device." },
{ id = "remote", title = "Over the internet",
note = "Trade with another trainer over the relay." },
}
function TradeScreen.draw(imp, x, y, w, availH, m)
local OnlinePanel = OP()
local tr = OnlinePanel.tradeState(imp)
local _, gap, tiny = Ui.pads(m)
local rowH = math.max(m.btnH, Kit.tapMin())
local cy = y + Ui.header(imp, x, y, w, m, Strings("Trade"))
if tr.remote then tr.chosen = true end
if not tr.chosen then
local cardH = math.max(math.floor(74 * m.s), m.rowH * 2)
if m.twoCol then
local colW = math.floor((w - gap) / 2)
for i, mode in ipairs(MODES) do
local id = mode.id
Ui.entryCard(imp, x + (i - 1) * (colW + gap), cy, colW, cardH,
"online-trade-mode-" .. id, Strings(mode.title), Strings(mode.note),
true, function()
OnlinePanel.tradeMode(imp, id)
tr.chosen = true
end)
end
cy = cy + cardH + gap
else
for _, mode in ipairs(MODES) do
local id = mode.id
Ui.entryCard(imp, x, cy, w, cardH, "online-trade-mode-" .. id,
Strings(mode.title), Strings(mode.note), true, function()
OnlinePanel.tradeMode(imp, id)
tr.chosen = true
end)
cy = cy + cardH + gap
end
end
return cy - y
end
cy = cy + Ui.label(Strings("Trade with"), x, cy) + tiny
local half = math.floor((w - gap) / 2)
for i, mode in ipairs(MODES) do
local id = mode.id
if Kit.chip(x + (i - 1) * (half + gap), cy, half, rowH,
Strings(mode.title), tr.mode == id, PAL.lineStrong,
"online-trade-pick-" .. id) then
LV().queueAction(imp, "online-trade-pick-" .. id, function()
OnlinePanel.tradeMode(imp, id)
end)
end
end
cy = cy + rowH + gap
if tr.mode == "remote" then
cy = cy + remoteTrade(imp, x, cy, w, m)
else
cy = cy + localTrade(imp, x, cy, w, m)
end
return cy - y
end
local function modalMon(m, entry, label, x, w, y, box)
local sprites = Sprites()
local sprite = entry and entry.mon
and sprites.get(entry.version, entry.mon) or nil
if sprite then
sprites.drawFront(sprite, x + math.floor((w - box) / 2), y, box)
end
local cy = y + box + math.floor(4 * m.s)
Kit.textCenter("micro", label, x, cy, w, PAL.faint)
cy = cy + Kit.textHeight("micro") + math.floor(2 * m.s)
Kit.textCenter("small",
Kit.ellipsize("small", (entry and entry.label) or "?", w),
x, cy, w, PAL.heading)
return (cy + Kit.textHeight("small")) - y
end
function TradeScreen.drawModal(imp, m)
local OnlinePanel = OP()
local mo = OnlinePanel.tradeModal(imp)
if not mo then return false end
local pad = math.floor(18 * m.s)
local gap = math.floor(8 * m.s)
local w = math.floor(460 * m.s)
local innerW = w - 2 * pad
local btnH = math.max(m.btnH, Kit.tapMin())
local box = math.floor(56 * m.s)
local monH = box + math.floor(6 * m.s) + Kit.textHeight("micro")
+ Kit.textHeight("small")
local result = mo.view == "result"
local lines = result and (mo.resultLines or {}) or (mo.lines or {})
local heading = result and (mo.message or "")
or ((#lines > 0) and Strings("What changes") or nil)
local linesH = heading and (Kit.textHeight("small") + math.floor(4 * m.s))
or 0
for _, line in ipairs(lines) do
linesH = linesH + Kit.wrapHeight("small", tostring(line), innerW, 2)
+ math.floor(3 * m.s)
end
local h = pad + Kit.textHeight("button") + gap + monH + gap + linesH + gap
+ btnH + pad
local px, py, pw, ph = LV().modalPanel(m, w, h)
innerW = pw - 2 * pad
local cy = py + pad
Kit.textBold("button", Strings("Trade"), px + pad, cy, PAL.heading)
cy = cy + Kit.textHeight("button") + gap
local slotW = math.floor((innerW - gap) / 2)
local left = modalMon(m, mo.give, Strings("Give"), px + pad, slotW, cy, box)
local right = modalMon(m, mo.get, Strings("Get"),
px + pad + slotW + gap, slotW, cy, box)
cy = cy + math.max(left, right) + gap
if heading then
Kit.text("small", Kit.ellipsize("small", heading, innerW), px + pad, cy,
result and (mo.ok and PAL.green or PAL.yellow) or PAL.detail)
cy = cy + Kit.textHeight("small") + math.floor(4 * m.s)
end
for _, line in ipairs(lines) do
cy = cy + Kit.textWrapped("small", tostring(line), px + pad, cy, innerW,
PAL.muted, 2) + math.floor(3 * m.s)
end
cy = math.floor(py + ph - pad - btnH)
if result then
LV().btn(imp, px + pad, cy, innerW, btnH,
OnlinePanel.TRADE_MODAL_DONE, Strings("Done"),
{ kind = "primary", font = "small",
action = function() OnlinePanel.tradeModalClose(imp) end })
return true
end
local half = math.floor((innerW - gap) / 2)
LV().btn(imp, px + pad, cy, half, btnH,
OnlinePanel.TRADE_MODAL_CANCEL, Strings("Cancel"),
{ kind = "ghost", font = "small",
action = function() OnlinePanel.tradeModalClose(imp) end })
LV().btn(imp, px + pad + half + gap, cy, innerW - half - gap, btnH,
OnlinePanel.TRADE_MODAL_CONFIRM, Strings("Confirm"),
{ kind = "primary", font = "small",
action = function() OnlinePanel.tradeModalConfirm(imp) end })
return true
end
return TradeScreen