iOS: clean up import project and make thumbnails for sprites and backgrounds

This commit is contained in:
Yueyu 2021-04-09 07:02:35 +08:00
parent 397ce34148
commit 468bc4e0ab
7 changed files with 176 additions and 152 deletions

View file

@ -65,7 +65,8 @@
- (BOOL) application:(UIApplication *)application openURL:(NSURL *) url sourceApplication:(NSString *) sourceApplication annotation:(id) annotation {
if (url) {
[IO receiveProject:url];
NSLog(@"openg url: %@", url.absoluteURL);
[ScratchJr receiveProject:url];
}
return YES;
}

View file

@ -58,14 +58,20 @@ NSString* dberror() {return [NSString stringWithFormat:@"SQL error: %s", sqlite3
NSData* data = [body dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:data options: 0 error: nil];
// NSLog(@"stmt %@", dict);
sqlite3_stmt *stmt;
NSString *stmtstr = [dict objectForKey: @"stmt"];
NSArray *values = [dict objectForKey: @"values"];
// NSLog(@"stmt %@", stmtstr);
return [Database stmt:stmtstr with:values];
}
+ (NSString*) stmt: (NSString *)stmtstr with:(NSArray *) values {
sqlite3_stmt *stmt;
// NSLog(@"stmt %@", stmtstr);
if (!(sqlite3_prepare_v2(db, [stmtstr UTF8String], -1, &stmt, NULL) == SQLITE_OK)) return dberror();
for(int i=0;i<[values count];i++)
for(int i=0;i<[values count];i++) {
sqlite3_bind_text(stmt, i+1, [[values objectAtIndex: i] UTF8String], -1, SQLITE_TRANSIENT);
// NSLog(@"stmt done %@", stmtstr);
}
// NSLog(@"stmt done %@", stmtstr);
if (!(sqlite3_step(stmt) == SQLITE_DONE)) return dberror();
sqlite3_finalize(stmt);
return [NSString stringWithFormat:@"%lld",sqlite3_last_insert_rowid(db)];
@ -130,22 +136,9 @@ NSString* dberror() {return [NSString stringWithFormat:@"SQL error: %s", sqlite3
for (int i = 0; i < data.count; i++) {
[placeholders addObject:@"?"];
}
sqlite3_stmt *stmt;
NSString *stmtstr = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)", table, keys, [placeholders componentsJoinedByString:@","]];
NSArray *values = [data allValues];
// NSLog(@"stmt %@", stmtstr);
if (sqlite3_prepare_v2(db, [stmtstr UTF8String], -1, &stmt, NULL) != SQLITE_OK) {
return dberror();
}
for(int i=0;i<[values count];i++) {
sqlite3_bind_text(stmt, i+1, [[values objectAtIndex: i] UTF8String], -1, SQLITE_TRANSIENT);
}
// NSLog(@"stmt done %@", stmtstr);
if (sqlite3_step(stmt) != SQLITE_DONE) {
return dberror();
}
sqlite3_finalize(stmt);
return [NSString stringWithFormat:@"%lld", sqlite3_last_insert_rowid(db)];
return [Database stmt:stmtstr with:values];
}
@end

View file

@ -282,118 +282,126 @@ NSMutableDictionary *soundtimers;
}
+ (void) receiveProject: (NSURL *) url {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *tempDir = [[IO getTmpPath:[[NSUUID alloc] init].UUIDString].path stringByAppendingString:@"/"];
// uncompress
[SSZipArchive unzipFileAtPath:url.path toDestination:tempDir];
NSFileManager *fileManager = [NSFileManager defaultManager];
// remove zip
// [fileManager removeItemAtURL:url error:nil];
NSString *projectPath = [tempDir stringByAppendingString:@"/project/data.json"];
if (![fileManager fileExistsAtPath:projectPath]) {
// project data file doesn't exist
return;
NSString *tempDir = [[IO getTmpPath:[[NSUUID alloc] init].UUIDString].path stringByAppendingString:@"/"];
// uncompress
[SSZipArchive unzipFileAtPath:url.path toDestination:tempDir];
NSFileManager *fileManager = [NSFileManager defaultManager];
// remove zip
[fileManager removeItemAtURL:url error:nil];
NSString *projectPath = [tempDir stringByAppendingString:@"/project/data.json"];
if (![fileManager fileExistsAtPath:projectPath]) {
// project data file doesn't exist
return;
}
NSData *data = [[NSData alloc] initWithContentsOfFile:projectPath];
NSError *error = nil;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingFragmentsAllowed error:&error];
if (error != nil) {
// invalid json
return;
}
NSMutableDictionary *project = [[NSMutableDictionary alloc] init];
[project setValue:@"1" forKey:@"isgift"];
[project setValue:@"NO" forKey:@"deleted"];
NSDictionary *json = [dictionary valueForKey:@"json"];
[project setValue:[json jsonString] forKey:@"json"];
NSDictionary *thumbnail = [dictionary valueForKey:@"thumbnail"];
[project setValue:[thumbnail jsonString] forKey:@"thumbnail"];
[project setValue:@"iOSv01" forKey:@"version"];
[project setValue:[dictionary valueForKey:@"name"] forKey:@"name"];
// save project to database
[Database insert:@"projects" with:project];
NSMutableDictionary *sprites = [[NSMutableDictionary alloc] init];
for (NSString *name in [json valueForKey:@"pages"]) {
NSDictionary *page = [json valueForKey:name];
for (NSString *spriteName in [page valueForKey:@"sprites"]) {
NSDictionary *sprite = [page valueForKey:spriteName];
[sprites setValue:sprite forKey:[sprite valueForKey:@"md5"]];
}
NSData *data = [[NSData alloc] initWithContentsOfFile:projectPath];
NSError *error = nil;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingFragmentsAllowed error:&error];
if (error != nil) {
// invalid json
return;
}
// read project data
// create project
NSDirectoryEnumerator<NSString *> * enumerator = [fileManager enumeratorAtPath:tempDir];
NSString *path;
while ((path = [enumerator nextObject]) != nil) {
// only copy image and sounds
if (![path hasSuffix:@".png"] && ![path hasSuffix:@".wav"] && ![path hasSuffix:@".svg"]) {
continue;
}
NSString *fileName = [path lastPathComponent];
NSArray *parts = [path componentsSeparatedByString:@"/"];
if (parts.count < 2) {
continue;
}
NSString *folder = parts[1];
// extract files
NSString *toPath = [[IO getpath] stringByAppendingPathComponent:fileName];
if (![fileManager fileExistsAtPath: toPath]) {
// NSLog(@"copy file to path %@", toPath);
NSString *fromPath = [tempDir stringByAppendingString:path];
[fileManager copyItemAtPath:fromPath toPath:toPath error:&error];
if (error != nil) {
continue;
}
}
if ([folder isEqualToString:@"sounds"] || [folder isEqualToString:@"thumbnails"]) {
// process for sounds and thumbnails is done
continue;
}
// save background or shape to database.
NSString *table = [folder isEqualToString:@"characters"] ? @"usershapes" : @"userbkgs";
NSMutableArray *values = [[NSMutableArray alloc] init];
[values addObject:fileName];
// check database
NSString *stmt = [NSString stringWithFormat:@"SELECT id FROM %@ WHERE md5 = ?", table];
NSArray *res = [Database findDataIn:stmt with:values];
// TODO: if query encounter an error, res.count will also be greater than 0
if (res.count > 0) {
continue;
}
// insert into database
NSLog(@"%@ not exists, creating", fileName);
NSMutableDictionary *asset = [[NSMutableDictionary alloc] init];
NSString *pngName = [fileName stringByReplacingOccurrencesOfString:@".svg" withString:@".png"];
[asset setValue:@"iOSv01" forKey:@"version"];
[asset setValue:pngName forKey:@"altmd5"];
[asset setValue:fileName forKey:@"md5"];
[asset setValue:[fileName pathExtension] forKey:@"ext"];
[asset setValue:@"480" forKey:@"width"];
[asset setValue:@"360" forKey:@"height"];
if ([folder isEqualToString:@"characters"]) {
// create shape
NSDictionary *sprite = [sprites valueForKey:fileName];
if (sprite == nil) {
continue;
}
// we need all values to be NSString
NSString *width = [sprite valueForKey:@"w"];
NSString *height = [sprite valueForKey:@"h"];
NSString *scale = [sprite valueForKey:@"scale"];
[asset setValue:[NSString stringWithFormat:@"%@", width] forKey:@"width"];
[asset setValue:[NSString stringWithFormat:@"%@", height] forKey:@"height"];
[asset setValue:[NSString stringWithFormat:@"%@", scale] forKey:@"scale"];
[asset setValue:[sprite valueForKey:@"id"] forKey:@"name"];
}
NSMutableDictionary *project = [[NSMutableDictionary alloc] init];
[project setValue:@"1" forKey:@"isgift"];
[project setValue:@"NO" forKey:@"deleted"];
NSDictionary *json = [dictionary valueForKey:@"json"];
[project setValue:[json jsonString] forKey:@"json"];
NSDictionary *thumbnail = [dictionary valueForKey:@"thumbnail"];
[project setValue:[thumbnail jsonString] forKey:@"thumbnail"];
[project setValue:@"iOSv01" forKey:@"version"];
[project setValue:[dictionary valueForKey:@"name"] forKey:@"name"];
// save project to database
[Database insert:@"projects" with:project];
NSMutableDictionary *sprites = [[NSMutableDictionary alloc] init];
for (NSString *name in [json valueForKey:@"pages"]) {
NSDictionary *page = [json valueForKey:name];
for (NSString *spriteName in [page valueForKey:@"sprites"]) {
NSDictionary *sprite = [page valueForKey:spriteName];
[sprites setValue:sprite forKey:[sprite valueForKey:@"md5"]];
}
// check thumbnail or create
if (![fileManager fileExistsAtPath:[[IO getpath] stringByAppendingPathComponent:pngName]]) {
NSString *js = [NSString stringWithFormat:@"ScratchJr.makeThumb('%@', %@, %@);", fileName, [asset valueForKey:@"width"], [asset valueForKey:@"height"]];
[ViewController.webview evaluateJavaScript:js completionHandler:nil];
}
// read project data
// create project
NSDirectoryEnumerator<NSString *> * enumerator = [fileManager enumeratorAtPath:tempDir];
NSString *path;
while ((path = [enumerator nextObject]) != nil) {
// only copy image and sounds
if (![path hasSuffix:@".png"] && ![path hasSuffix:@".wav"] && ![path hasSuffix:@".svg"]) {
continue;
}
NSString *fileName = [path lastPathComponent];
// NSLog(@"%@", path);
NSArray *parts = [path componentsSeparatedByString:@"/"];
if (parts.count < 2) {
continue;
}
NSString *folder = parts[1];
// extract files
NSString *toPath = [[IO getpath] stringByAppendingPathComponent:fileName];
if (![fileManager fileExistsAtPath: toPath]) {
NSLog(@"copy file to path %@", toPath);
NSString *fromPath = [tempDir stringByAppendingString:path];
[fileManager copyItemAtPath:fromPath toPath:toPath error:&error];
if (error != nil) {
continue;
}
}
if ([folder isEqualToString:@"sounds"] || [folder isEqualToString:@"thumbnails"]) {
// process for sounds and thumbnails is done
continue;
}
// save background or shape to database.
NSString *table = [folder isEqualToString:@"characters"] ? @"usershapes" : @"userbkgs";
NSMutableArray *values = [[NSMutableArray alloc] init];
[values addObject:fileName];
// check database
NSString *stmt = [NSString stringWithFormat:@"SELECT id FROM %@ WHERE md5 = ?", table];
NSArray *res = [Database findDataIn:stmt with:values];
if (res.count > 0) {
continue;
}
// insert into database
NSLog(@"%@ not exists, creating", fileName);
NSMutableDictionary *asset = [[NSMutableDictionary alloc] init];
[asset setValue:@"iOSv01" forKey:@"version"];
[asset setValue:nil forKey:@"altmd5"];
[asset setValue:fileName forKey:@"md5"];
[asset setValue:[fileName pathExtension] forKey:@"ext"];
[asset setValue:@"480" forKey:@"width"];
[asset setValue:@"360" forKey:@"height"];
if ([folder isEqualToString:@"characters"]) {
// create shape
NSDictionary *sprite = [sprites valueForKey:fileName];
if (sprite == nil) {
continue;
}
NSString *width = [sprite valueForKey:@"w"];
NSString *height = [sprite valueForKey:@"h"];
[asset setValue:[NSString stringWithFormat:@"%@", width] forKey:@"width"];
[asset setValue:[NSString stringWithFormat:@"%@", height] forKey:@"height"];
[asset setValue:[sprite valueForKey:@"scale"] forKey:@"scale"];
[asset setValue:[sprite valueForKey:@"id"] forKey:@"name"];
}
[Database insert:table with:asset];
}
// delete temp folder
[fileManager removeItemAtPath:tempDir error:nil];
// refresh lobby
[ViewController.webview evaluateJavaScript:@"Lobby.refresh();" completionHandler:nil];
});
[Database insert:table with:asset];
}
// delete temp folder
[fileManager removeItemAtPath:tempDir error:nil];
// refresh lobby
[ViewController.webview evaluateJavaScript:@"Lobby.refresh();" completionHandler:nil];
}
////////////////////////////

View file

@ -167,4 +167,7 @@
+ (NSString *)stopfeed;
+ (NSString *)choosecamera:(NSString *)body;
+ (NSString *)captureimage:(NSString *)onCameraCaptureComplete;
// Imports
+ (void) receiveProject:(NSURL *) url;
@end

View file

@ -6,6 +6,10 @@ CameraView* cameraView;
CameraMask* cameraMask;
NSString *cameraAvailable;
// prepare for opening multiple files
NSMutableArray *zipUrls;
bool appReady = false;
AVCaptureVideoPreviewLayer* captureVideoPreviewLayer;
@implementation ScratchJr : NSObject
@ -16,15 +20,41 @@ NSString *oncomplete;
// Init functions
/////////////////////////
+ (NSString *) hideSplash :(NSString *)body{
UIImageView* splashScreen = [ViewController splashScreen];
appReady = true;
dispatch_async(dispatch_get_main_queue(), ^{
[splashScreen removeFromSuperview];
});
// import projects
if (zipUrls != nil && zipUrls.count > 0) {
for (int i = 0; i < zipUrls.count; i++) {
NSURL *url = zipUrls[i];
[zipUrls removeObjectAtIndex:i];
[ScratchJr importProject:url];
}
}
return @"1";
}
+ (void) receiveProject:(NSURL *)url {
if (zipUrls == nil) {
zipUrls = [[NSMutableArray alloc] init];
}
if (appReady) {
[ScratchJr importProject:url];
} else {
[zipUrls addObject:url];
}
}
+ (void) importProject:(NSURL *) url {
NSLog(@"importing project at %@", url.absoluteString);
dispatch_async(dispatch_get_main_queue(), ^{
[IO receiveProject:url];
});
}
//////////////////////////
// camera open and close
/////////////////////////

View file

@ -161,30 +161,6 @@ NSDate *startDate;
startDate = [NSDate date];
}
- (void) receiveProject:(NSString *)project{
NSString *callback = [NSString stringWithFormat:@"OS.loadProjectFromSjr('%@');", project];
WKWebView *webview = [ViewController webview];
dispatch_async(dispatch_get_main_queue(), ^{
[webview evaluateJavaScript:callback completionHandler:^(id result, NSError * _Nullable error) {
if (error != nil) {
return;
}
NSString *res = [NSString stringWithFormat:@"%@", result];
if ([res isEqualToString:@"1"]) {
// Success
return;
} else if ([res isEqualToString:@"0"]) {
// Processing error
return;
} else {
// Loading the project failed - reschedule for a time when the WebView has hopefully loaded
// A little bit roundabout, but simpler than queueing projects to be loaded
[self performSelector:@selector(receiveProject:) withObject:project afterDelay:2.0];
}
}];
});
}
- (BOOL)prefersStatusBarHidden{
return YES;
}

View file

@ -902,6 +902,19 @@ export default class ScratchJr {
return str;
}
static makeThumb(svgName, width, height) {
IO.getAsset(svgName, function (svgDataUrl) {
var svgBase64 = svgDataUrl.split(',')[1];
var dataurl = IO.getThumbnail(atob(svgBase64), width, height, 120, 90);
var pngBase64 = dataurl.split(',')[1];
var name = svgName.split('.')[0];
OS.setmedianame(pngBase64, name, 'png', function () {
// we don't need result here.
console.log(`thumbnail for ${svgName} generated.`)
});
});
}
/////////////////
//Application on the background