@g9tm/lynxcontrols-native 0.0.0-stage → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -2
- package/android/build.gradle.kts +45 -0
- package/android/consumer-rules.pro +3 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/com/g9lynx/g9native/G9Bridge.kt +67 -0
- package/android/src/main/java/com/g9lynx/g9native/G9HostModule.kt +159 -0
- package/android/src/main/java/com/g9lynx/g9native/G9SqliteModule.kt +49 -0
- package/android/src/main/java/com/g9lynx/g9native/generated/G9HostModuleSpec.java +48 -0
- package/android/src/main/java/com/g9lynx/g9native/generated/G9SqliteModuleSpec.java +41 -0
- package/android/src/main/java/com/g9lynx/g9native/host/core/G9PreferencesCore.kt +100 -0
- package/android/src/main/java/com/g9lynx/g9native/sqlite/androidx/AndroidxSqlEngine.kt +88 -0
- package/android/src/main/java/com/g9lynx/g9native/sqlite/core/G9SqlEngine.kt +61 -0
- package/android/src/main/java/com/g9lynx/g9native/sqlite/core/G9SqliteCore.kt +260 -0
- package/android/src/main/java/com/g9lynx/g9native/sqlite/core/G9SqliteService.kt +131 -0
- package/android/src/main/java/com/g9lynx/g9native/sqlite/core/G9SqliteTransport.kt +125 -0
- package/android/src/main/java/com/g9lynx/g9native/sqlite/core/G9SqliteValues.kt +71 -0
- package/android/src/main/java/com/g9lynx/g9native/video/G9VideoUI.kt +214 -0
- package/android/src/main/java/com/g9lynx/g9native/video/core/G9VideoCore.kt +67 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/driver.d.ts +20 -0
- package/dist/driver.d.ts.map +1 -0
- package/dist/driver.js +159 -0
- package/dist/driver.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/media.d.ts +60 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.jsx +119 -0
- package/dist/media.jsx.map +1 -0
- package/dist/protocol.d.ts +115 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +1 -0
- package/dist/services.d.ts +36 -0
- package/dist/services.d.ts.map +1 -0
- package/dist/services.js +111 -0
- package/dist/services.js.map +1 -0
- package/dist/transport.d.ts +10 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +77 -0
- package/dist/transport.js.map +1 -0
- package/generated/G9HostModule.ts +71 -0
- package/generated/G9SqliteModule.ts +68 -0
- package/ios/Tests/G9NativeTestSuite.h +25 -0
- package/ios/Tests/G9NativeTestSuite.m +560 -0
- package/ios/Tests/G9NativeTests.m +52 -0
- package/ios/g9lynx-native.podspec +29 -0
- package/ios/src/G9HostModule.h +14 -0
- package/ios/src/G9HostModule.m +121 -0
- package/ios/src/G9SqliteModule.h +14 -0
- package/ios/src/G9SqliteModule.m +167 -0
- package/ios/src/G9VideoUI.h +21 -0
- package/ios/src/G9VideoUI.m +250 -0
- package/ios/src/core/G9HostPaths.h +20 -0
- package/ios/src/core/G9HostPaths.m +23 -0
- package/ios/src/core/G9PreferencesCore.h +43 -0
- package/ios/src/core/G9PreferencesCore.m +114 -0
- package/ios/src/core/G9SqliteCore.h +62 -0
- package/ios/src/core/G9SqliteCore.m +497 -0
- package/ios/src/core/G9SqliteTransport.h +16 -0
- package/ios/src/core/G9SqliteTransport.m +85 -0
- package/ios/src/core/G9VideoCore.h +26 -0
- package/ios/src/core/G9VideoCore.m +37 -0
- package/ios/src/generated/G9HostModuleSpec.h +23 -0
- package/ios/src/generated/G9HostModuleSpec.m +2 -0
- package/ios/src/generated/G9SqliteModuleSpec.h +20 -0
- package/ios/src/generated/G9SqliteModuleSpec.m +2 -0
- package/lynx.lib.json +12 -0
- package/package.json +49 -4
- package/types/platform-native-module.d.ts +46 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#import "G9SqliteTransport.h"
|
|
2
|
+
#import "G9SqliteCore.h"
|
|
3
|
+
|
|
4
|
+
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
|
5
|
+
#error "The columnar transport writes host-order float64; every supported iOS/macOS/Linux target is little-endian."
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
static BOOL G9IsIntegerNumber(NSNumber *n) {
|
|
9
|
+
const char t = [n objCType][0];
|
|
10
|
+
return t == 'q' || t == 'l' || t == 'i' || t == 's' || t == 'c' || t == 'Q' || t == 'L' || t == 'I' || t == 'S' || t == 'C';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@implementation G9SqliteTransport
|
|
14
|
+
|
|
15
|
+
+ (id)wireNumber:(long long)value {
|
|
16
|
+
if (value >= -G9MaxSafeInteger && value <= G9MaxSafeInteger) return [NSNumber numberWithDouble:(double)value];
|
|
17
|
+
return [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%lld", value] forKey:@"int64"];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
+ (id)wireCell:(id)cell {
|
|
21
|
+
if ([cell isKindOfClass:[NSNumber class]] && G9IsIntegerNumber(cell)) return [self wireNumber:[cell longLongValue]];
|
|
22
|
+
return cell;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
+ (NSDictionary *)encode:(NSArray *)results transport:(NSString *)transport {
|
|
26
|
+
BOOL rows = [transport isEqual:@"rows"];
|
|
27
|
+
NSMutableArray *encoded = [NSMutableArray arrayWithCapacity:[results count]];
|
|
28
|
+
for (NSDictionary *result in results) [encoded addObject:rows ? [self rows:result] : [self columnar:result]];
|
|
29
|
+
return [NSDictionary dictionaryWithObjectsAndKeys:rows ? @"rows" : @"columnar", @"transport", encoded, @"results", nil];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
+ (NSDictionary *)rows:(NSDictionary *)result {
|
|
33
|
+
NSMutableArray *rows = [NSMutableArray array];
|
|
34
|
+
for (NSArray *row in [result objectForKey:@"rows"]) {
|
|
35
|
+
NSMutableArray *out = [NSMutableArray arrayWithCapacity:[row count]];
|
|
36
|
+
for (id cell in row) [out addObject:[self wireCell:cell]];
|
|
37
|
+
[rows addObject:out];
|
|
38
|
+
}
|
|
39
|
+
return [NSDictionary dictionaryWithObjectsAndKeys:[result objectForKey:@"columns"], @"columns", rows, @"rows",
|
|
40
|
+
[NSNumber numberWithDouble:[[result objectForKey:@"changes"] doubleValue]], @"changes",
|
|
41
|
+
[self wireNumber:[[result objectForKey:@"lastInsertRowId"] longLongValue]], @"lastInsertRowId", nil];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
+ (NSDictionary *)columnar:(NSDictionary *)result {
|
|
45
|
+
NSArray *rows = [result objectForKey:@"rows"];
|
|
46
|
+
NSMutableData *types = [NSMutableData data];
|
|
47
|
+
NSMutableData *numbers = [NSMutableData data];
|
|
48
|
+
NSMutableData *blobs = [NSMutableData data];
|
|
49
|
+
NSMutableArray *strings = [NSMutableArray array];
|
|
50
|
+
for (NSArray *row in rows) {
|
|
51
|
+
for (id cell in row) {
|
|
52
|
+
uint8_t tag;
|
|
53
|
+
if (cell == (id)[NSNull null]) {
|
|
54
|
+
tag = 0;
|
|
55
|
+
} else if ([cell isKindOfClass:[NSNumber class]]) {
|
|
56
|
+
id wire = G9IsIntegerNumber(cell) ? [self wireNumber:[cell longLongValue]] : cell;
|
|
57
|
+
if ([wire isKindOfClass:[NSDictionary class]]) {
|
|
58
|
+
tag = 2;
|
|
59
|
+
[strings addObject:[wire objectForKey:@"int64"]];
|
|
60
|
+
} else {
|
|
61
|
+
tag = 1;
|
|
62
|
+
double d = [wire doubleValue];
|
|
63
|
+
[numbers appendBytes:&d length:sizeof d];
|
|
64
|
+
}
|
|
65
|
+
} else if ([cell isKindOfClass:[NSString class]]) {
|
|
66
|
+
tag = 3;
|
|
67
|
+
[strings addObject:cell];
|
|
68
|
+
} else {
|
|
69
|
+
tag = 4;
|
|
70
|
+
NSData *data = cell;
|
|
71
|
+
double length = (double)[data length];
|
|
72
|
+
[numbers appendBytes:&length length:sizeof length];
|
|
73
|
+
[blobs appendData:data];
|
|
74
|
+
}
|
|
75
|
+
[types appendBytes:&tag length:1];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return [NSDictionary dictionaryWithObjectsAndKeys:[result objectForKey:@"columns"], @"columns",
|
|
79
|
+
[NSNumber numberWithDouble:(double)[rows count]], @"rowCount",
|
|
80
|
+
[NSNumber numberWithDouble:[[result objectForKey:@"changes"] doubleValue]], @"changes",
|
|
81
|
+
[self wireNumber:[[result objectForKey:@"lastInsertRowId"] longLongValue]], @"lastInsertRowId",
|
|
82
|
+
types, @"types", numbers, @"numbers", strings, @"strings", blobs, @"blobs", nil];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// The platform-free decisions of `<g9-video>` on iOS, the same rules as the Android core
|
|
2
|
+
// (`android/.../video/core/G9VideoCore.kt`): `nearend` once per loop, the best-effort start seek. Foundation only, so
|
|
3
|
+
// the Linux harness runs it; AVFoundation feeds it positions.
|
|
4
|
+
#import <Foundation/Foundation.h>
|
|
5
|
+
|
|
6
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
7
|
+
|
|
8
|
+
@interface G9VideoLoopTracker : NSObject {
|
|
9
|
+
@private
|
|
10
|
+
double _nearEndSeconds;
|
|
11
|
+
BOOL _nearEndSent;
|
|
12
|
+
}
|
|
13
|
+
/** How early `nearend` fires before each loop's end; non-finite or `<= 0` turns it off. */
|
|
14
|
+
@property(nonatomic, assign) double nearEndSeconds;
|
|
15
|
+
/** Seconds left when `nearend` should fire now (once per loop), else nil. Unknown durations (`<= 0`) never fire. */
|
|
16
|
+
- (nullable NSNumber *)progressPositionMs:(double)positionMs durationMs:(double)durationMs;
|
|
17
|
+
/** The video restarted: the next loop may report `nearend` again. */
|
|
18
|
+
- (void)looped;
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@interface G9VideoMath : NSObject
|
|
22
|
+
/** The one-time start seek in ms, or nil when there is nothing to seek or it would land at or past a known end. */
|
|
23
|
+
+ (nullable NSNumber *)startPositionMsForSeconds:(double)startSeconds durationMs:(double)durationMs;
|
|
24
|
+
@end
|
|
25
|
+
|
|
26
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#import "G9VideoCore.h"
|
|
2
|
+
#include <math.h>
|
|
3
|
+
|
|
4
|
+
@implementation G9VideoLoopTracker
|
|
5
|
+
|
|
6
|
+
- (double)nearEndSeconds {
|
|
7
|
+
return _nearEndSeconds;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
- (void)setNearEndSeconds:(double)value {
|
|
11
|
+
_nearEndSeconds = (isfinite(value) && value > 0) ? value : 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
- (nullable NSNumber *)progressPositionMs:(double)positionMs durationMs:(double)durationMs {
|
|
15
|
+
if (_nearEndSent || _nearEndSeconds <= 0 || !(durationMs > 0) || positionMs < 0) return nil;
|
|
16
|
+
double left = (durationMs - positionMs) / 1000.0;
|
|
17
|
+
if (left < 0 || left > _nearEndSeconds) return nil;
|
|
18
|
+
_nearEndSent = YES;
|
|
19
|
+
return [NSNumber numberWithDouble:left];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
- (void)looped {
|
|
23
|
+
_nearEndSent = NO;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@end
|
|
27
|
+
|
|
28
|
+
@implementation G9VideoMath
|
|
29
|
+
|
|
30
|
+
+ (nullable NSNumber *)startPositionMsForSeconds:(double)startSeconds durationMs:(double)durationMs {
|
|
31
|
+
if (!isfinite(startSeconds) || startSeconds <= 0) return nil;
|
|
32
|
+
double target = startSeconds * 1000.0;
|
|
33
|
+
if (durationMs > 0 && target >= durationMs) return nil;
|
|
34
|
+
return [NSNumber numberWithDouble:target];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Generated by @lynx-js/autolink-codegen. Do not edit.
|
|
2
|
+
#import <Foundation/Foundation.h>
|
|
3
|
+
#import <Lynx/LynxModule.h>
|
|
4
|
+
|
|
5
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
6
|
+
|
|
7
|
+
@protocol G9HostModuleSpec <LynxModule>
|
|
8
|
+
|
|
9
|
+
- (void)capabilities:(id)callback;
|
|
10
|
+
- (void)getPreference:(NSString *)key callback:(id)callback;
|
|
11
|
+
- (void)setPreference:(NSString *)key kind:(NSString *)kind value:(nullable NSString *)value callback:(id)callback;
|
|
12
|
+
- (void)preferenceEntries:(NSString *)prefix callback:(id)callback;
|
|
13
|
+
- (void)safeInsets:(id)callback;
|
|
14
|
+
- (void)moveToBack;
|
|
15
|
+
- (void)hideKeyboard;
|
|
16
|
+
- (void)setSoftInputMode:(NSString *)mode;
|
|
17
|
+
- (void)hapticTick;
|
|
18
|
+
- (void)appDataDirectory:(id)callback;
|
|
19
|
+
- (void)assetUri:(NSString *)path callback:(id)callback;
|
|
20
|
+
|
|
21
|
+
@end
|
|
22
|
+
|
|
23
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated by @lynx-js/autolink-codegen. Do not edit.
|
|
2
|
+
#import <Foundation/Foundation.h>
|
|
3
|
+
#import <Lynx/LynxModule.h>
|
|
4
|
+
|
|
5
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
6
|
+
|
|
7
|
+
@protocol G9SqliteModuleSpec <LynxModule>
|
|
8
|
+
|
|
9
|
+
- (void)capabilities:(id)callback;
|
|
10
|
+
- (void)open:(id)options callback:(id)callback;
|
|
11
|
+
- (void)run:(NSString *)session statements:(id)statements options:(id)options callback:(id)callback;
|
|
12
|
+
- (void)begin:(NSString *)session mode:(NSString *)mode callback:(id)callback;
|
|
13
|
+
- (void)commit:(NSString *)tx callback:(id)callback;
|
|
14
|
+
- (void)rollback:(NSString *)tx callback:(id)callback;
|
|
15
|
+
- (void)close:(NSString *)session callback:(id)callback;
|
|
16
|
+
- (void)interrupt:(NSString *)session;
|
|
17
|
+
|
|
18
|
+
@end
|
|
19
|
+
|
|
20
|
+
NS_ASSUME_NONNULL_END
|
package/lynx.lib.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@g9tm/lynxcontrols-native",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "Android and iOS platform layer: the G9SqliteModule and G9HostModule native modules (Autolink) and their JS adapters.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"source": "./src/index.ts",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./media": {
|
|
15
|
+
"source": "./src/media.tsx",
|
|
16
|
+
"types": "./dist/media.d.ts",
|
|
17
|
+
"default": "./dist/media.jsx"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"android/build.gradle.kts",
|
|
23
|
+
"android/consumer-rules.pro",
|
|
24
|
+
"android/src/main",
|
|
25
|
+
"ios/g9lynx-native.podspec",
|
|
26
|
+
"ios/src",
|
|
27
|
+
"ios/Tests/G9NativeTestSuite.h",
|
|
28
|
+
"ios/Tests/G9NativeTestSuite.m",
|
|
29
|
+
"ios/Tests/G9NativeTests.m",
|
|
30
|
+
"generated",
|
|
31
|
+
"types",
|
|
32
|
+
"lynx.lib.json",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "rslib build",
|
|
37
|
+
"codegen": "lynx-autolink-codegen && node scripts/android-bridge-types.mjs --fix",
|
|
38
|
+
"check:android-types": "node scripts/android-bridge-types.mjs"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@g9tm/lynxcontrols-foundation": "1.4.0",
|
|
42
|
+
"@g9tm/lynxcontrols-sqlite": "1.4.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@lynx-js/react": ">=0.126.2 <0.127.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@g9tm/lynxcontrols-lynxtron": "1.4.0",
|
|
49
|
+
"@lynx-js/autolink-codegen": "0.6.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// The two native modules of @g9tm/lynxcontrols-native (plan/specs/06 §4, §5, §7). `npm run codegen` turns these declarations into
|
|
2
|
+
// the Android/iOS specs under android/…/generated and ios/src/generated, and the JS accessors under generated/.
|
|
3
|
+
// Every reply is an envelope `{ ok: true, value } | { ok: false, error }` so error fields survive the bridge.
|
|
4
|
+
|
|
5
|
+
/** @lynxmodule */
|
|
6
|
+
export declare class G9SqliteModule {
|
|
7
|
+
capabilities(callback: (reply: Record<string, unknown>) => void): void;
|
|
8
|
+
open(options: Record<string, unknown>, callback: (reply: Record<string, unknown>) => void): void;
|
|
9
|
+
run(
|
|
10
|
+
session: string,
|
|
11
|
+
statements: unknown[],
|
|
12
|
+
options: Record<string, unknown>,
|
|
13
|
+
callback: (reply: Record<string, unknown>) => void,
|
|
14
|
+
): void;
|
|
15
|
+
begin(session: string, mode: string, callback: (reply: Record<string, unknown>) => void): void;
|
|
16
|
+
commit(tx: string, callback: (reply: Record<string, unknown>) => void): void;
|
|
17
|
+
rollback(tx: string, callback: (reply: Record<string, unknown>) => void): void;
|
|
18
|
+
close(session: string, callback: (reply: Record<string, unknown>) => void): void;
|
|
19
|
+
/** Interrupts the statement running on the session (iOS `sqlite3_interrupt`); a no-op where unsupported. */
|
|
20
|
+
interrupt(session: string): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** @lynxmodule */
|
|
24
|
+
export declare class G9HostModule {
|
|
25
|
+
capabilities(callback: (reply: Record<string, unknown>) => void): void;
|
|
26
|
+
getPreference(key: string, callback: (reply: Record<string, unknown>) => void): void;
|
|
27
|
+
setPreference(
|
|
28
|
+
key: string,
|
|
29
|
+
kind: string,
|
|
30
|
+
value: string | null,
|
|
31
|
+
callback: (reply: Record<string, unknown>) => void,
|
|
32
|
+
): void;
|
|
33
|
+
preferenceEntries(prefix: string, callback: (reply: Record<string, unknown>) => void): void;
|
|
34
|
+
safeInsets(callback: (reply: Record<string, unknown>) => void): void;
|
|
35
|
+
moveToBack(): void;
|
|
36
|
+
hideKeyboard(): void;
|
|
37
|
+
setSoftInputMode(mode: string): void;
|
|
38
|
+
hapticTick(): void;
|
|
39
|
+
/** The app's private data directory, absolute (MAUI `FileSystem.AppDataDirectory`): where the database lives. */
|
|
40
|
+
appDataDirectory(callback: (reply: Record<string, unknown>) => void): void;
|
|
41
|
+
/**
|
|
42
|
+
* The URI the platform image/video loaders open for a file bundled with the app (Android `assets/`, iOS the main
|
|
43
|
+
* bundle's resources): `asset:///…` on Android, `file://…` on iOS; `not-found` when the app does not ship it.
|
|
44
|
+
*/
|
|
45
|
+
assetUri(path: string, callback: (reply: Record<string, unknown>) => void): void;
|
|
46
|
+
}
|