mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
Merge pull request #755 from castdrian/ios
fix(ios): support mod index networking and text input dismissal
This commit is contained in:
@@ -30,6 +30,45 @@ public final class GRPickerBridge: NSObject {
|
||||
// (<sandbox>/Library/Application Support/<identity>).
|
||||
private static let loveIdentity = "pokemon-love2d"
|
||||
|
||||
@objc(httpDownloadWithUrl:destination:userAgent:accept:)
|
||||
public static func httpDownload(url: UnsafePointer<CChar>?,
|
||||
destination: UnsafePointer<CChar>?,
|
||||
userAgent: UnsafePointer<CChar>?,
|
||||
accept: UnsafePointer<CChar>?) -> Bool {
|
||||
guard let url, let destination,
|
||||
let requestURL = URL(string: String(cString: url)) else { return false }
|
||||
var request = URLRequest(url: requestURL)
|
||||
request.timeoutInterval = 300
|
||||
if let userAgent, userAgent.pointee != 0 {
|
||||
request.setValue(String(cString: userAgent), forHTTPHeaderField: "User-Agent")
|
||||
}
|
||||
if let accept, accept.pointee != 0 {
|
||||
request.setValue(String(cString: accept), forHTTPHeaderField: "Accept")
|
||||
}
|
||||
let target = URL(fileURLWithPath: String(cString: destination))
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
var succeeded = false
|
||||
let task = URLSession.shared.downloadTask(with: request) { temporary, response, error in
|
||||
defer { semaphore.signal() }
|
||||
guard error == nil, let temporary,
|
||||
let http = response as? HTTPURLResponse,
|
||||
(200..<300).contains(http.statusCode) else { return }
|
||||
try? FileManager.default.removeItem(at: target)
|
||||
do {
|
||||
try FileManager.default.moveItem(at: temporary, to: target)
|
||||
succeeded = true
|
||||
} catch {
|
||||
succeeded = false
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
guard semaphore.wait(timeout: .now() + 305) == .success else {
|
||||
task.cancel()
|
||||
return false
|
||||
}
|
||||
return succeeded
|
||||
}
|
||||
|
||||
// MARK: - Entry points called from liblove (C strings on purpose)
|
||||
|
||||
@objc(presentPickerWithKind:saveDir:)
|
||||
|
||||
@@ -103,6 +103,7 @@ WRAP_REGISTRATION = """#ifdef LOVE_IOS
|
||||
{ "pickFile", w_pickFile },
|
||||
{ "createFile", w_createFile },
|
||||
{ "syncHealthSteps", w_syncHealthSteps },
|
||||
{ "httpDownload", w_httpDownload },
|
||||
#endif
|
||||
"""
|
||||
|
||||
@@ -144,6 +145,32 @@ int w_syncHealthSteps(lua_State *L)
|
||||
|
||||
WRAP_SYNC_REGISTRATION = """#ifdef LOVE_IOS
|
||||
{ "syncHealthSteps", w_syncHealthSteps },
|
||||
{ "httpDownload", w_httpDownload },
|
||||
#endif
|
||||
"""
|
||||
|
||||
BRIDGE_EXTRA_FUNCS = """
|
||||
#ifdef LOVE_IOS
|
||||
int w_httpDownload(lua_State *L)
|
||||
{
|
||||
const char *url = luaL_checkstring(L, 1);
|
||||
const char *destination = luaL_checkstring(L, 2);
|
||||
const char *userAgent = luaL_optstring(L, 3, "gen1recomp");
|
||||
const char *accept = luaL_optstring(L, 4, "");
|
||||
Class cls = objc_getClass("GRPickerBridge");
|
||||
if (cls == nullptr)
|
||||
{
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
typedef signed char (*GRDownload)(Class, SEL, const char *, const char *,
|
||||
const char *, const char *);
|
||||
signed char ok = ((GRDownload)objc_msgSend)(
|
||||
cls, sel_registerName("httpDownloadWithUrl:destination:userAgent:accept:"),
|
||||
url, destination, userAgent, accept);
|
||||
lua_pushboolean(L, ok != 0);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
"""
|
||||
|
||||
@@ -216,7 +243,8 @@ def patch_wrap_system():
|
||||
if anchor not in text:
|
||||
fail(f"anchor not found in {WRAP_SYSTEM}")
|
||||
has_native_picker = re.search(r"\bint w_pickFile\s*\(", text) is not None
|
||||
text = text.replace(anchor, (WRAP_SYNC_FUNCS if has_native_picker else WRAP_FUNCS) + anchor, 1)
|
||||
bridge_funcs = WRAP_SYNC_FUNCS if has_native_picker else WRAP_FUNCS
|
||||
text = text.replace(anchor, bridge_funcs + BRIDGE_EXTRA_FUNCS + anchor, 1)
|
||||
reg_anchor = '\t{ "vibrate", w_vibrate },\n'
|
||||
if reg_anchor not in text:
|
||||
fail(f"registration anchor not found in {WRAP_SYSTEM}")
|
||||
@@ -224,7 +252,7 @@ def patch_wrap_system():
|
||||
text = text.replace(reg_anchor, reg_anchor + registration, 1)
|
||||
WRAP_SYSTEM.write_text(text)
|
||||
print("patch_love_src: wrap_System.cpp patched "
|
||||
"(pickFile/createFile/syncHealthSteps)")
|
||||
"(pickFile/createFile/syncHealthSteps/httpDownload)")
|
||||
|
||||
|
||||
def patch_pbxproj():
|
||||
|
||||
@@ -148,15 +148,14 @@ function HostShell.haveCurl()
|
||||
return readOk and out ~= nil and out:find("curl", 1, true) ~= nil
|
||||
end
|
||||
|
||||
-- The bridge only exists in our Android liblove. An older APK reports nil
|
||||
-- here and falls back to the "no transport" error the callers already show;
|
||||
-- the iOS build compiles the same wrapper but always returns false, so gate
|
||||
-- on the OS as well and keep its error message honest.
|
||||
-- An older mobile build reports nil here and falls back to the "no transport"
|
||||
-- error the callers already show.
|
||||
local function haveBridge()
|
||||
if not (love and love.system and type(love.system.httpDownload) == "function") then
|
||||
return false
|
||||
end
|
||||
return love.system.getOS and love.system.getOS() == "Android"
|
||||
local osName = love.system.getOS and love.system.getOS()
|
||||
return osName == "Android" or osName == "iOS"
|
||||
end
|
||||
|
||||
-- Is any transport available at all? Callers gate on this, never on curl.
|
||||
|
||||
@@ -1214,8 +1214,7 @@ local function buildFindPanel(imp, parent, m)
|
||||
imp.findQuery or "", Strings("Search mods"),
|
||||
imp._findSearchFocus == true,
|
||||
function()
|
||||
imp._findSearchFocus = true
|
||||
imp:_armTextInput()
|
||||
imp:_toggleFindSearchFocus()
|
||||
end)
|
||||
|
||||
local cats = (imp.findIndex and imp.findIndex.categories) or {}
|
||||
|
||||
@@ -1733,6 +1733,15 @@ function RomImporter:_switchTab(id)
|
||||
self:_disarmTextInput()
|
||||
end
|
||||
|
||||
function RomImporter:_toggleFindSearchFocus()
|
||||
self._findSearchFocus = not self._findSearchFocus
|
||||
if self._findSearchFocus then
|
||||
self:_armTextInput()
|
||||
else
|
||||
self:_disarmTextInput()
|
||||
end
|
||||
end
|
||||
|
||||
-- ------- settings gear (options.lua + enabled mods' option schemas)
|
||||
|
||||
function RomImporter:_openSettings()
|
||||
|
||||
@@ -133,6 +133,13 @@ check(ri._findSearchFocus == false, "a tab change drops the caret")
|
||||
eq(lastArm(), false, "and disarms setTextInput")
|
||||
ri.tab = "find"
|
||||
|
||||
ri:_toggleFindSearchFocus()
|
||||
check(ri._findSearchFocus == true, "tapping the search field focuses it")
|
||||
eq(lastArm(), true, "refocusing the search field arms setTextInput")
|
||||
ri:_toggleFindSearchFocus()
|
||||
check(ri._findSearchFocus == false, "tapping the focused search field blurs it")
|
||||
eq(lastArm(), false, "blurring the search field disarms setTextInput")
|
||||
|
||||
-- ---- desktop contract (#529): disarm never lowers off Android -------------
|
||||
|
||||
ri.android = false
|
||||
|
||||
Reference in New Issue
Block a user