Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
weihan-plugin
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Wei Han
weihan-plugin
Commits
3806f808
Commit
3806f808
authored
Oct 22, 2025
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PlanScreen UI update
parent
1c49cf8f
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
462 additions
and
133 deletions
+462
-133
Info.plist
...PluginFramework/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
AddIssueAPIClient.h
...Framework/QmsPluginFramework/AddIssue/AddIssueAPIClient.h
+9
-0
AddIssueAPIClient.mm
...ramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
+182
-0
PlanViewController.h
...ramework/QmsPluginFramework/AddIssue/PlanViewController.h
+3
-0
PlanViewController.mm
...amework/QmsPluginFramework/AddIssue/PlanViewController.mm
+251
-66
DashboardAPIClient.h
...amework/QmsPluginFramework/Dashboard/DashboardAPIClient.h
+0
-4
DashboardAPIClient.mm
...mework/QmsPluginFramework/Dashboard/DashboardAPIClient.mm
+0
-52
DashboardViewController.mm
...k/QmsPluginFramework/Dashboard/DashboardViewController.mm
+7
-1
Info.plist
ios/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
No files found.
framework/QmsPluginFramework/QmsPluginFramework.xcframework/Info.plist
View file @
3806f808
...
@@ -8,32 +8,32 @@
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
3806f808
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
3806f808
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.h
0 → 100644
View file @
3806f808
// AddIssueAPIClient.h
#import <Foundation/Foundation.h>
@interface
AddIssueAPIClient
:
NSObject
+
(
void
)
fetchGetUnitPlan
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchSettingsByLocation
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
0 → 100644
View file @
3806f808
// AddIssueAPIClient.mm
#import "AddIssueAPIClient.h"
@implementation AddIssueAPIClient
+ (void)fetchGetUnitPlan:(void (^)(NSDictionary *data, NSError *error))completion {
// ✅ Construct URL (with token)
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/plan/getLocationByUnit?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 🧱 multipart/form-data setup (same as fetchAnnouncement)
NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
NSMutableData *body = [NSMutableData data];
// 👇 Helper block to add form fields
void (^appendFormField)(NSString *, NSString *) = ^(NSString *key, NSString *value) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:
@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", value]
dataUsingEncoding:NSUTF8StringEncoding]];
};
// 🧩 Add POST fields
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[drawing_plan_id]",@"135");
// You can reuse your existing getDeviceInfo() method to produce this JSON string
NSString *deviceInfo = @"{\"OS\":\"AND\",\"IMEI\":\"AND:2a2f13ff17b1cbb5\",\"OS_VERSION\":\"35\",\"MODEL\":\"2306EPN60G\",\"APP_VERSION\":\"1.22.26\"}";
appendFormField(@"data[information]", deviceInfo);
// 🔚 End boundary
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
// 🌍 Debug logs
NSLog(@"🌍 [fetchUnitPlan] URL: %@", urlString);
NSLog(@"📦 [fetchUnitPlan] Body:\n%@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
// 🌐 Perform request
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ [fetchUnitPlan] Network error: %@", error);
if (completion) completion(nil, error);
return;
}
NSError *jsonErr;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
if (jsonErr) {
NSLog(@"❌ [fetchUnitPlan] JSON parse error: %@", jsonErr);
if (completion) completion(nil, jsonErr);
return;
}
NSLog(@"✅ [fetchUnitPlan] Response:\n%@", json);
NSDictionary *appData = json[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"📄 Successfully fetched unit plan for ID");
} else if (appData[@"error_code"] && [appData[@"error_code"] integerValue] == 503) {
NSLog(@"⚠️ Server under maintenance (503)");
} else {
NSLog(@"⚠️ API returned failure: %@", appData[@"message"]);
}
// ✅ Call back on main thread
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(json, nil);
});
}
}];
[task resume];
}
+ (void)fetchSettingsByLocation:(void (^)(NSDictionary *data, NSError *error))completion{
// ✅ Build URL
NSString *urlString = @"https://kitadev.commudesk.com/api/issue/getGeneralSettingByLocation?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 🧱 multipart/form-data setup
NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
NSMutableData *body = [NSMutableData data];
// Helper block for adding form fields
void (^appendFormField)(NSString *, NSString *) = ^(NSString *key, NSString *value) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:
@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", value]
dataUsingEncoding:NSUTF8StringEncoding]];
};
// 🧩 Add POST fields
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[project_id]", @"8");
appendFormField(@"data[location_id]", @"1458"); //temp number
NSString *deviceInfo = @"{\"OS\":\"AND\",\"IMEI\":\"AND:2a2f13ff17b1cbb5\",\"OS_VERSION\":\"35\",\"MODEL\":\"2306EPN60G\",\"APP_VERSION\":\"1.22.26\"}";
appendFormField(@"data[information]", deviceInfo);
// End boundary
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
// 🌍 Debug logs
NSLog(@"🌍 [fetchSettingsByLocation] URL: %@", urlString);
NSLog(@"📦 [fetchSettingsByLocation] Body:\n%@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
// 🌐 Send request
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ [fetchSettingsByLocation] Network error: %@", error);
if (completion) completion(nil, error);
return;
}
NSError *jsonErr;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
if (jsonErr) {
NSLog(@"❌ JSON parse error: %@", jsonErr);
if (completion) completion(nil, jsonErr);
return;
}
NSLog(@"✅ [fetchSettingsByLocation] Response:\n%@", json);
NSDictionary *appData = json[@"AppData"];
NSString *status = appData[@"status"];
if ([status isEqualToString:@"success"]) {
NSLog(@"📄 Successfully fetched settings for location");
}
else if ([appData[@"error_code"] integerValue] == 503) {
NSLog(@"⚠️ Maintenance mode (503)");
}
else {
NSLog(@"⚠️ Failed: %@", appData[@"message"]);
}
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(json, nil);
});
}
}];
[task resume];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/PlanViewController.h
View file @
3806f808
...
@@ -5,6 +5,9 @@ NS_ASSUME_NONNULL_BEGIN
...
@@ -5,6 +5,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface
PlanViewController
:
UIViewController
@interface
PlanViewController
:
UIViewController
@property
(
nonatomic
,
strong
)
NSString
*
projectCode
;
@property
(
nonatomic
,
strong
)
NSString
*
projectName
;
@end
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/PlanViewController.mm
View file @
3806f808
// PlanViewController.mm
// PlanViewController.mm
#import "PlanViewController.h"
#import "PlanViewController.h"
#import "DetailsViewController.h"
#import "DetailsViewController.h"
#import "AddIssueAPIClient.h"
@interface PlanViewController ()
@interface PlanViewController ()
...
@@ -8,11 +9,12 @@
...
@@ -8,11 +9,12 @@
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UIButton *helpButton;
@property (nonatomic, strong) UIButton *helpButton;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIImageView *planImageView;
@property (nonatomic, strong) UIImageView *planImageView;
@property (nonatomic, strong) NSString *selectedLocation;
@property (nonatomic, strong) NSString *selectedLocation;
@property (nonatomic, strong) NSDictionary *unitPlanData;
@property (nonatomic, strong) NSArray *locations;
@property (nonatomic, strong) NSString *planImageURL;
@end
@end
...
@@ -26,34 +28,104 @@
...
@@ -26,34 +28,104 @@
// Create UI elements (but don’t assign final frames yet)
// Create UI elements (but don’t assign final frames yet)
[self createHeader];
[self createHeader];
[self createScrollView];
[self createScrollView];
[self fetchInitialData];
[self.view bringSubviewToFront:self.headerView];
}
}
- (void)viewDidLayoutSubviews {
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[super viewDidLayoutSubviews];
[self.view bringSubviewToFront:self.headerView];
}
CGFloat topInset = self.view.safeAreaInsets.top;
- (void)fetchInitialData {
CGFloat headerHeight = 48.0
;
NSLog(@"🌐 Fetching Unit Plan data...")
;
// Layout header
[AddIssueAPIClient fetchGetUnitPlan:^(NSDictionary *data, NSError *error) {
self.headerView.frame = CGRectMake(0, topInset, self.view.bounds.size.width, headerHeight);
if (error) {
NSLog(@"❌ Unit Plan fetch failed: %@", error.localizedDescription);
return;
}
NSLog(@"✅ Raw Unit Plan response received");
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"getUnitPlan.txt"];
[jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 UnitPlan saved to %@", filePath);
// 🔍 Parse the JSON
NSDictionary *appData = data[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"⚠️ Server returned non-success status: %@", appData[@"message"]);
return;
}
// Layout items within header
NSArray *mainData = data[@"Data"];
self.backButton.frame = CGRectMake(12, 8, 32, 32);
if (mainData.count == 0) {
self.helpButton.frame = CGRectMake(self.headerView.bounds.size.width - 44, 8, 32, 32);
NSLog(@"⚠️ No unit plan data found");
self.titleLabel.frame = CGRectMake(0, 8, self.headerView.bounds.size.width, 32);
return;
}
// Layout scroll view
// Store main plan object
CGFloat scrollY = topInset + headerHeight;
self.unitPlanData = mainData.firstObject;
self.scrollView.frame = CGRectMake(0, scrollY, self.view.bounds.size.width, self.view.bounds.size.height - scrollY);
self.locations = self.unitPlanData[@"location"];
self.planImageView.frame = self.scrollView.bounds;
[self.view bringSubviewToFront:self.headerView];
// Extract first issue’s plan image URL
NSDictionary *firstLocation = self.locations.firstObject;
NSDictionary *firstIssue = [firstLocation[@"issue"] firstObject];
self.planImageURL = firstIssue[@"plan_image"];
NSLog(@"🗺 Found %lu locations", (unsigned long)self.locations.count);
NSLog(@"🖼 Plan image URL: %@", self.planImageURL);
// Now update the UI on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[self displayPlanImage];
});
}];
[self debugPrintAllIssues];
}
}
#pragma mark - UI Creation
- (void)displayPlanImage {
if (!self.planImageURL || self.planImageURL.length == 0) {
NSLog(@"⚠️ No plan image URL found");
return;
}
NSURL *url = [NSURL URLWithString:self.planImageURL];
if (!url) {
NSLog(@"⚠️ Invalid plan image URL: %@", self.planImageURL);
return;
}
NSLog(@"⬇️ Downloading plan image from %@", self.planImageURL);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error || !data) {
NSLog(@"❌ Failed to download plan image: %@", error.localizedDescription);
return;
}
UIImage *image = [UIImage imageWithData:data];
if (!image) {
NSLog(@"⚠️ Could not decode image data");
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
self.planImageView.image = image;
[self.scrollView setZoomScale:1.0 animated:NO];
NSLog(@"✅ Plan image displayed successfully");
});
}];
[task resume];
}
#pragma mark - UI Creation
- (void)createHeader {
- (void)createHeader {
// 🟩 Status bar background
view
// 🟩 Status bar background
UIView *statusBarBackground = [[UIView alloc] init];
UIView *statusBarBackground = [[UIView alloc] init];
statusBarBackground.backgroundColor = [UIColor colorWithRed:0/255.0
statusBarBackground.backgroundColor = [UIColor colorWithRed:0/255.0
green:109/255.0
green:109/255.0
...
@@ -62,44 +134,58 @@
...
@@ -62,44 +134,58 @@
statusBarBackground.translatesAutoresizingMaskIntoConstraints = NO;
statusBarBackground.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:statusBarBackground];
[self.view addSubview:statusBarBackground];
// 🟦 Header background
view
// 🟦 Header background
self.headerView = [[UIView alloc] init];
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = statusBarBackground.backgroundColor;
self.headerView.backgroundColor = statusBarBackground.backgroundColor;
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
[self.view addSubview:self.headerView];
// Back button
//
🔙
Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *backImage = [[UIImage systemImageNamed:@"chevron.left"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage *backImage = [[UIImage systemImageNamed:@"chevron.left"]
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self.backButton setImage:backImage forState:UIControlStateNormal];
[self.backButton setImage:backImage forState:UIControlStateNormal];
self.backButton.tintColor = [UIColor whiteColor];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self action:@selector(handleBack)
[self.backButton addTarget:self
action:@selector(handleBack)
forControlEvents:UIControlEventTouchUpInside];
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.backButton];
[self.headerView addSubview:self.backButton];
// Title label
// ❓ Help button
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.titleLabel.text = @"Plan Viewer";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.headerView addSubview:self.titleLabel];
// Help button
self.helpButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.helpButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.helpButton.translatesAutoresizingMaskIntoConstraints = NO;
self.helpButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *helpImage = [[UIImage systemImageNamed:@"questionmark.circle"]
UIImage *helpImage = [[UIImage systemImageNamed:@"questionmark.circle"]
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self.helpButton setImage:helpImage forState:UIControlStateNormal];
[self.helpButton setImage:helpImage forState:UIControlStateNormal];
self.helpButton.tintColor = [UIColor whiteColor];
self.helpButton.tintColor = UIColor.whiteColor;
[self.helpButton addTarget:self action:@selector(showTutorial)
[self.helpButton addTarget:self
action:@selector(showTutorial)
forControlEvents:UIControlEventTouchUpInside];
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.helpButton];
[self.headerView addSubview:self.helpButton];
// 🏷 Title label (project name)
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.titleLabel.text = self.projectName ?: @"Plan Viewer";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.headerView addSubview:self.titleLabel];
// 🧩 Subtitle label (project code)
UILabel *subtitleLabel = [[UILabel alloc] init];
subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
subtitleLabel.text = self.projectCode ?: @"";
subtitleLabel.textColor = [UIColor colorWithWhite:1.0 alpha:0.8];
subtitleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
subtitleLabel.textAlignment = NSTextAlignmentCenter;
[self.headerView addSubview:subtitleLabel];
// ✅ Constraints
// ✅ Constraints
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
CGFloat headerHeight = 80.0; // ⬆️ Taller header now
[NSLayoutConstraint activateConstraints:@[
[NSLayoutConstraint activateConstraints:@[
// Status bar background
// Status bar background
[statusBarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[statusBarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
...
@@ -107,68 +193,149 @@
...
@@ -107,68 +193,149 @@
[statusBarBackground.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[statusBarBackground.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[statusBarBackground.bottomAnchor constraintEqualToAnchor:safe.topAnchor],
[statusBarBackground.bottomAnchor constraintEqualToAnchor:safe.topAnchor],
// Header
pinned below safe area
// Header
[self.headerView.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerView.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerView.heightAnchor constraintEqualToConstant:
48
],
[self.headerView.heightAnchor constraintEqualToConstant:
headerHeight
],
// Back button
// Back button
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:8],
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:8],
[self.backButton.
centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor
],
[self.backButton.
topAnchor constraintEqualToAnchor:self.headerView.topAnchor constant:4
],
[self.backButton.widthAnchor constraintEqualToConstant:44],
[self.backButton.widthAnchor constraintEqualToConstant:44],
[self.backButton.heightAnchor constraintEqualToConstant:44],
[self.backButton.heightAnchor constraintEqualToConstant:44],
// Help button
// Help button
[self.helpButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-8],
[self.helpButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-8],
[self.helpButton.centerYAnchor constraintEqualToAnchor:self.
headerView
.centerYAnchor],
[self.helpButton.centerYAnchor constraintEqualToAnchor:self.
backButton
.centerYAnchor],
[self.helpButton.widthAnchor constraintEqualToConstant:44],
[self.helpButton.widthAnchor constraintEqualToConstant:44],
[self.helpButton.heightAnchor constraintEqualToConstant:44],
[self.helpButton.heightAnchor constraintEqualToConstant:44],
// Title centered
// Title label (below buttons)
[self.titleLabel.topAnchor constraintEqualToAnchor:self.backButton.bottomAnchor constant:4],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
// Subtitle (below title)
[subtitleLabel.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:2],
[subtitleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
]];
]];
}
}
- (void)loadPlanImageFromURL:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
if (!url) return;
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Failed to load image: %@", error);
return;
}
UIImage *image = [UIImage imageWithData:data];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
self.planImageView.image = image;
NSLog(@"🖼 Plan image loaded successfully");
});
}
}];
[task resume];
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
});
}
- (void)handleUnitPlanResponse:(NSDictionary *)data {
NSLog(@"🧩 Handling Unit Plan response...");
NSDictionary *appData = data[@"AppData"];
NSArray *mainData = data[@"Data"];
// 🧱 Step 1 — Check for maintenance
if ([appData[@"error_code"] integerValue] == 503) {
NSLog(@"⚠️ Maintenance mode");
[self showAlertWithTitle:@"Maintenance Mode" message:@"System under maintenance. Please try again later."];
return;
}
// 🧱 Step 2 — If status is success
if ([appData[@"status"] isEqualToString:@"success"]) {
if (mainData.count > 0) {
NSDictionary *unitPlan = mainData.firstObject;
self.unitPlanData = unitPlan;
// Save JSON for debugging
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"unitPlanParsed.json"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:unitPlan options:NSJSONWritingPrettyPrinted error:nil];
[jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 Parsed unit plan saved to %@", filePath);
// 🖼 Step 3 — Load image if available
NSString *planImageURL = unitPlan[@"plan_image"];
if (planImageURL.length > 0) {
[self loadPlanImageFromURL:planImageURL];
} else {
NSLog(@"⚠️ No plan_image found in response");
}
// ✅ (Optional) Update title or debug log
NSString *unitName = unitPlan[@"unit_name"] ?: @"No name";
dispatch_async(dispatch_get_main_queue(), ^{
self.titleLabel.text = unitName;
});
}
} else {
// 🧱 Step 4 — Handle error response
NSString *message = appData[@"message"] ?: @"Unknown error.";
if ([message isEqualToString:@"user_not_found"]) {
[self showAlertWithTitle:@"Session Expired" message:@"Please log in again."];
} else {
[self showAlertWithTitle:@"Error" message:message];
}
}
}
- (void)createScrollView {
- (void)createScrollView {
self.scrollView = [[UIScrollView alloc] init];
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.delegate = (id<UIScrollViewDelegate>)self;
self.scrollView.delegate = (id<UIScrollViewDelegate>)self;
self.scrollView.minimumZoomScale = 1.0;
self.scrollView.minimumZoomScale = 1.0;
self.scrollView.maximumZoomScale = 5.0;
self.scrollView.maximumZoomScale = 5.0;
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.scrollView];
[self.view addSubview:self.scrollView];
self.planImageView = [[UIImageView alloc] init];
self.planImageView = [[UIImageView alloc] init];
self.planImageView.contentMode = UIViewContentModeScaleAspectFit;
self.planImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.scrollView addSubview:self.planImageView];
UIImage *testImage = [UIImage imageNamed:@"image_placeholder"];
if (!testImage) {
NSLog(@"❌ image_placeholder not found in bundle!");
self.planImageView.backgroundColor = [UIColor whiteColor];
self.planImageView.backgroundColor = [UIColor whiteColor];
self.planImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:self.planImageView];
// 👉 Temporary test button
// ✅ Scroll view constraints (below header)
UIButton *testButton = [UIButton buttonWithType:UIButtonTypeSystem];
[NSLayoutConstraint activateConstraints:@[
[testButton setTitle:@"Next Screen →" forState:UIControlStateNormal];
[self.scrollView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
testButton.titleLabel.font = [UIFont boldSystemFontOfSize:18];
[self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[testButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
testButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
testButton.layer.cornerRadius = 8;
]];
testButton.clipsToBounds = YES;
// Add simple frame — will center it later in viewDidLayoutSubviews
testButton.frame = CGRectMake(0, 0, 200, 50);
testButton.center = self.view.center;
[testButton addTarget:self
action:@selector(handleNextScreen)
forControlEvents:UIControlEventTouchUpInside];
// Add directly on top of main view (not inside scrollView)
// ✅ Image view constraints (fills scroll view)
[self.view addSubview:testButton];
[NSLayoutConstraint activateConstraints:@[
} else {
[self.planImageView.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor],
self.planImageView.image = testImage;
[self.planImageView.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor],
}
[self.planImageView.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor],
[self.planImageView.bottomAnchor constraintEqualToAnchor:self.scrollView.bottomAnchor],
[self.planImageView.widthAnchor constraintEqualToAnchor:self.scrollView.widthAnchor],
[self.planImageView.heightAnchor constraintEqualToAnchor:self.scrollView.heightAnchor],
]];
}
}
- (void)handleNextScreen {
- (void)handleNextScreen {
...
@@ -308,4 +475,22 @@
...
@@ -308,4 +475,22 @@
return UIStatusBarStyleLightContent; // ✅ White text/icons
return UIStatusBarStyleLightContent; // ✅ White text/icons
}
}
- (void)debugPrintAllIssues {
for (NSDictionary *loc in self.locations) {
NSString *roomName = loc[@"name"];
NSArray *issues = loc[@"issue"];
NSLog(@"📍 Room: %@ (%lu issues)", roomName, (unsigned long)issues.count);
for (NSDictionary *issue in issues) {
NSString *title = issue[@"issue"];
NSString *status = issue[@"status_internal"];
NSString *x = issue[@"pos_x"];
NSString *y = issue[@"pos_y"];
NSString *color = issue[@"status_in_color"];
NSLog(@" - %@ [%@] (x:%@, y:%@, color:%@)", title, status, x, y, color);
}
}
}
@end
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardAPIClient.h
View file @
3806f808
...
@@ -3,10 +3,6 @@
...
@@ -3,10 +3,6 @@
@interface
DashboardAPIClient
:
NSObject
@interface
DashboardAPIClient
:
NSObject
+
(
void
)
fetchDashboardSummary
:(
void
(
^
)(
NSDictionary
*
data
))
completion
;
+
(
void
)
fetchAppointments
:(
void
(
^
)(
NSArray
*
data
))
completion
;
+
(
void
)
fetchIssues
:(
void
(
^
)(
NSArray
*
data
))
completion
;
+
(
void
)
fetchHeaderInfo
:(
void
(
^
)(
NSDictionary
*
data
))
completion
;
+
(
void
)
fetchDashboardInfo
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchDashboardInfo
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchAnnouncement
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchAnnouncement
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardAPIClient.mm
View file @
3806f808
...
@@ -3,58 +3,6 @@
...
@@ -3,58 +3,6 @@
@implementation DashboardAPIClient
@implementation DashboardAPIClient
+ (void)fetchDashboardSummary:(void (^)(NSDictionary *))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/users/1"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
}
+ (void)fetchAppointments:(void (^)(NSArray *))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/todos?_limit=5"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
}
+ (void)fetchIssues:(void (^)(NSArray *))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/comments?_limit=5"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
}
+ (void)fetchHeaderInfo:(void (^)(NSDictionary *data))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/photos/1"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Header info fetch failed: %@", error);
if (completion) completion(@{});
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (completion) completion(json);
}];
[task resume];
}
+ (void)fetchDashboardInfo:(void (^)(NSDictionary *data, NSError *error))completion {
+ (void)fetchDashboardInfo:(void (^)(NSDictionary *data, NSError *error))completion {
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/plan/getIssueUpdateAppointmentInfo";
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/plan/getIssueUpdateAppointmentInfo";
NSURL *url = [NSURL URLWithString:urlString];
NSURL *url = [NSURL URLWithString:urlString];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.mm
View file @
3806f808
...
@@ -229,6 +229,8 @@
...
@@ -229,6 +229,8 @@
switch (sender.tag) {
switch (sender.tag) {
case 1: {
case 1: {
PlanViewController *planVC = [[PlanViewController alloc] init];
PlanViewController *planVC = [[PlanViewController alloc] init];
planVC.projectCode = self.projectCode;
planVC.projectName = self.projectName;
planVC.modalPresentationStyle = UIModalPresentationFullScreen;
planVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:planVC animated:YES completion:nil];
[self presentViewController:planVC animated:YES completion:nil];
break;
break;
...
@@ -538,7 +540,11 @@
...
@@ -538,7 +540,11 @@
hScroll.showsHorizontalScrollIndicator = NO;
hScroll.showsHorizontalScrollIndicator = NO;
CGFloat x = 16;
CGFloat x = 16;
for (NSDictionary *item in announcements) {
NSArray *limitedAnnouncements = (announcements.count > 5)
? [announcements subarrayWithRange:NSMakeRange(0, 5)]
: announcements;
for (NSDictionary *item in limitedAnnouncements) {
UIView *card = [self makeAnnouncementCard:item];
UIView *card = [self makeAnnouncementCard:item];
CGRect frame = card.frame;
CGRect frame = card.frame;
frame.origin.x = x;
frame.origin.x = x;
...
...
ios/QmsPluginFramework.xcframework/Info.plist
View file @
3806f808
...
@@ -8,32 +8,32 @@
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
3806f808
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
3806f808
No preview for this file type
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment