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
3dd910fa
Commit
3dd910fa
authored
Oct 27, 2025
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
AddIssueDetails api progress
parent
1c3bdce0
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
275 additions
and
144 deletions
+275
-144
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
+7
-1
AddIssueAPIClient.mm
...ramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
+91
-5
DetailsViewController.h
...ework/QmsPluginFramework/AddIssue/DetailsViewController.h
+7
-0
DetailsViewController.mm
...work/QmsPluginFramework/AddIssue/DetailsViewController.mm
+75
-17
PlanViewController.mm
...amework/QmsPluginFramework/AddIssue/PlanViewController.mm
+85
-111
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 @
3dd910fa
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
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
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
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
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
3dd910fa
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
3dd910fa
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.h
View file @
3dd910fa
// AddIssueAPIClient.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface
AddIssueAPIClient
:
NSObject
+
(
void
)
fetchGetUnitPlan
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchSettingsByLocation
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchSettingsByLocation
:(
NSString
*
)
locationID
projectID
:(
NSString
*
)
projectID
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
submitAddIssue
:(
NSDictionary
*
)
params
images
:(
NSArray
<
UIImage
*>
*
)
images
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
View file @
3dd910fa
...
...
@@ -90,8 +90,9 @@
[task resume];
}
+ (void)fetchSettingsByLocation:(void (^)(NSDictionary *data, NSError *error))completion{
// ✅ Build URL
+ (void)fetchSettingsByLocation:(NSString *)locationID
projectID:(NSString *)projectID
completion:(void (^)(NSDictionary *data, NSError *error))completion {
NSString *urlString = @"https://kitadev.commudesk.com/api/issue/getGeneralSettingByLocation?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
NSURL *url = [NSURL URLWithString:urlString];
...
...
@@ -118,8 +119,8 @@
// 🧩 Add POST fields
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[project_id]",
@"8
");
appendFormField(@"data[location_id]",
@"1458"); //temp number
appendFormField(@"data[project_id]",
projectID ?: @"0
");
appendFormField(@"data[location_id]",
locationID ?: @"0");
NSString *deviceInfo = @"{\"OS\":\"AND\",\"IMEI\":\"AND:2a2f13ff17b1cbb5\",\"OS_VERSION\":\"35\",\"MODEL\":\"2306EPN60G\",\"APP_VERSION\":\"1.22.26\"}";
appendFormField(@"data[information]", deviceInfo);
...
...
@@ -177,6 +178,91 @@
[task resume];
}
+ (void)submitAddIssue:(NSDictionary *)issueData
images:(NSArray<UIImage *> * _Nullable)images
completion:(void (^)(NSDictionary * _Nullable response, NSError * _Nullable error))completion {
@end
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/issue/addIssue?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA"; NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 🧱 Multipart body
NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]
forHTTPHeaderField:@"Content-Type"];
NSMutableData *body = [NSMutableData data];
// Helper 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]];
};
// 🔹 Append form data fields
for (NSString *key in issueData.allKeys) {
id value = issueData[key];
if ([value isKindOfClass:[NSNumber class]]) value = [(NSNumber *)value stringValue];
if ([value isKindOfClass:[NSString class]]) {
appendFormField([NSString stringWithFormat:@"data[%@]", key], value);
}
}
// 🔹 Append OS info
appendFormField(@"data[os]", @"AND");
// 🔹 Append images
if (images.count > 0) {
for (int i = 0; i < images.count; i++) {
UIImage *image = images[i];
NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
if (!imageData) continue;
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:
@"Content-Disposition: form-data; name=\"data[image][%d]\"; filename=\"image%d.jpg\"\r\n", i, i]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
}
}
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
// Debug
NSLog(@"📦 [AddIssue] Uploading %lu image(s)", (unsigned long)images.count);
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ [AddIssue] Network error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{ if (completion) completion(nil, error); });
return;
}
NSError *jsonErr;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
if (jsonErr) {
NSString *raw = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"⚠️ [AddIssue] JSON parse error: %@\nRaw response: %@", jsonErr, raw);
dispatch_async(dispatch_get_main_queue(), ^{ if (completion) completion(nil, jsonErr); });
return;
}
NSLog(@"✅ [AddIssue] Response: %@", json);
dispatch_async(dispatch_get_main_queue(), ^{ if (completion) completion(json, nil); });
}];
[task resume];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/DetailsViewController.h
View file @
3dd910fa
...
...
@@ -15,4 +15,11 @@
@property
(
nonatomic
,
strong
)
NSString
*
projectCode
;
@property
(
nonatomic
,
strong
)
NSString
*
projectName
;
@property
(
nonatomic
,
assign
)
CGFloat
planX
;
@property
(
nonatomic
,
assign
)
CGFloat
planY
;
-
(
void
)
dismissSelf
;
-
(
void
)
handleSubmit
;
-
(
void
)
handleReset
;
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/DetailsViewController.mm
View file @
3dd910fa
#import "DetailsViewController.h"
#import "AddIssueAPIClient.h"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface AddIssueDetailsViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property (nonatomic, strong) UIView *headerView;
...
...
@@ -10,12 +13,10 @@
@property (nonatomic, strong) NSArray *categories;
@property (nonatomic, strong) NSArray *types;
@property (nonatomic, strong) NSArray *issues;
@property (nonatomic, weak) UIButton *typeButton;
@property (nonatomic, weak) UIButton *issueButton;
@property (nonatomic, copy) NSString *selectedTypeName;
@property (nonatomic, copy) NSString * selectedIssueID;
@end
...
...
@@ -25,11 +26,15 @@
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
NSLog(@"📦 Data received in AddIssueDetailsViewController:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@
\n locationData: %@",
NSLog(@"📦 Data being brought over:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@\n projectName: %@\n projectCode: %@\n XCoordinates: %f\n YCoordinates: %f
\n locationData: %@",
self.planID,
self.locationID,
self.selectedLocationName,
self.defectMatrix,
self.projectName,
self.projectCode,
self.planX,
self.planY,
self.locationData);
NSDictionary *locData = self.locationData;
...
...
@@ -251,7 +256,7 @@
[locationField.centerYAnchor constraintEqualToAnchor:locationContainer.centerYAnchor],
]];
// === Reselect Button (
below the container, lef
t-aligned) ===
// === Reselect Button (
inside the container, righ
t-aligned) ===
UIButton *reselectBtn = [UIButton buttonWithType:UIButtonTypeSystem];
reselectBtn.translatesAutoresizingMaskIntoConstraints = NO;
[reselectBtn setTitle:@"Reselect" forState:UIControlStateNormal];
...
...
@@ -259,13 +264,15 @@
forState:UIControlStateNormal];
reselectBtn.titleLabel.font = [UIFont boldSystemFontOfSize:14];
[reselectBtn addTarget:self action:@selector(dismissSelf) forControlEvents:UIControlEventTouchUpInside];
[
content
addSubview:reselectBtn];
[
locationContainer
addSubview:reselectBtn];
[NSLayoutConstraint activateConstraints:@[
[reselectBtn.topAnchor constraintEqualToAnchor:locationContainer.bottomAnchor constant:4],
[reselectBtn.leadingAnchor constraintEqualToAnchor:locationContainer.leadingAnchor constant:4],
[reselectBtn.trailingAnchor constraintEqualToAnchor:locationContainer.trailingAnchor constant:-8],
[reselectBtn.centerYAnchor constraintEqualToAnchor:locationContainer.centerYAnchor],
// shrink locationField width so it doesn’t overlap
[locationField.trailingAnchor constraintEqualToAnchor:reselectBtn.leadingAnchor constant:-8],
]];
lastView = locationContainer;
// Category, Type, Issue — dropdown style
NSArray *titles = @[@"*Category", @"*Type", @"*Issue"];
...
...
@@ -302,12 +309,13 @@
NSArray *categories = self.locationData[@"category"];
if (categories.count > 0) {
NSDictionary *firstCategory = categories.firstObject;
NSString *categoryName =
firstCategory[@"cat_name"]
?: @"";
NSString *categoryName =
locationField.text
?: @"";
[dropdown setTitle:categoryName forState:UIControlStateNormal];
[dropdown setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
} else {
[dropdown setTitle:@"(No Category)" forState:UIControlStateNormal];
[dropdown setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
}
dropdown.enabled = NO; // make it non-clickable
...
...
@@ -444,6 +452,7 @@
return btn;
}
- (void)handleDropdownTap:(UIButton *)sender {
NSInteger tag = sender.tag;
NSString *title = sender.titleLabel.text ?: @"Select";
...
...
@@ -504,11 +513,32 @@
[sender setTitle:opt forState:UIControlStateNormal];
[sender setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
if (tag == 2001) { // Type
if (tag == 2001) {
// === Type dropdown ===
self.selectedTypeName = opt;
// Reset issue button when type changes
self.selectedIssueID = nil; // reset previous issue selection
[self.issueButton setTitle:@"- Select Issue -" forState:UIControlStateNormal];
[self.issueButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
NSLog(@"✅ Selected Type: %@", self.selectedTypeName);
} else if (tag == 2002) {
// === Issue dropdown ===
NSArray *issuesForType = @[];
for (NSDictionary *type in self.types) {
if ([type[@"type_name"] isEqualToString:self.selectedTypeName]) {
issuesForType = type[@"issue"];
break;
}
}
for (NSDictionary *issue in issuesForType) {
NSString *issueName = issue[@"issue_name"];
if ([issueName isEqualToString:opt]) {
self.selectedIssueID = [NSString stringWithFormat:@"%@", issue[@"issue_id"]];
NSLog(@"✅ Selected Issue: %@ (ID: %@)", issueName, self.selectedIssueID);
break;
}
}
}
}]];
}
...
...
@@ -711,11 +741,39 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
}
- (void)handleSubmit {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Submitted"
message:@"Issue has been added (mock)."
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
NSLog(@"Calling addIssue API:\n planID: %@\n locationID: %@\n selectedIssueID: %@\n XCoordinates: %f\n YCoordinates: %f\n commentField: %@",
self.planID,
self.locationID,
self.selectedIssueID,
self.planX,
self.planY,
self.commentField);
NSDictionary *issueData = @{
@"plan_id": self.planID ?: @"0",
@"location_id": self.locationID ?: @"0",
@"issue_setting_id": self.selectedIssueID ?: @"",
@"position_x": [NSString stringWithFormat:@"%f", self.planX ?: 0.0],
@"position_y": [NSString stringWithFormat:@"%f", self.planY ?: 0.0],
@"comment": self.commentField ?: @"",
@"os": @"AND"
};
[AddIssueAPIClient submitAddIssue:issueData
images:self.uploadedImages
completion:^(NSDictionary *response, NSError *error) {
if (error) {
NSLog(@"❌ Submission failed: %@", error.localizedDescription);
return;
}
NSDictionary *appData = response[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"✅ Issue submitted successfully!");
} else {
NSLog(@"⚠️ API Error: %@", appData[@"message"]);
}
}];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/PlanViewController.mm
View file @
3dd910fa
...
...
@@ -30,6 +30,10 @@
@property (nonatomic, strong) NSString *locationID;
@property (nonatomic, strong) NSDictionary *locationData;
@property (nonatomic, strong) NSString *defectMatrix;
@property (nonatomic, strong) NSDictionary *unitPlanResponse;
@property (nonatomic, strong) NSArray *unitPlanLocations;
@property (nonatomic, assign) CGFloat tappedPlanX;
@property (nonatomic, assign) CGFloat tappedPlanY;
@end
...
...
@@ -46,7 +50,7 @@
self.overlayLayers = [NSMutableArray array];
[self
fetchInitialData
];
[self
handleGetUnitPlan
];
[self.view bringSubviewToFront:self.headerView];
}
...
...
@@ -61,7 +65,7 @@
}
}
- (void)
fetchInitialData
{
- (void)
handleGetUnitPlan
{
NSLog(@"🌐 Fetching Unit Plan data...");
[AddIssueAPIClient fetchGetUnitPlan:^(NSDictionary *data, NSError *error) {
...
...
@@ -79,6 +83,9 @@
[jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 UnitPlan saved to %@", filePath);
// 🔹 Save the full API response
self.unitPlanResponse = data;
// 🔍 Parse JSON
NSDictionary *appData = data[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) {
...
...
@@ -91,6 +98,7 @@
NSLog(@"⚠️ No unit plan data found");
return;
}
self.unitPlanLocations = mainData.firstObject[@"location"];
// Store main plan object
self.unitPlanData = mainData.firstObject;
...
...
@@ -113,7 +121,6 @@
NSString *widthStr = [NSString stringWithFormat:@"%@", firstIssue[@"plan_width"]];
NSString *heightStr = [NSString stringWithFormat:@"%@", firstIssue[@"plan_height"]];
self.planID = [NSString stringWithFormat:@"%@", firstIssue[@"plan_id"] ?: @"0"];
self.locationID = [NSString stringWithFormat:@"%@", firstIssue[@"location_id"] ?: @"0"];
self.planWidth = [widthStr floatValue];
self.planHeight = [heightStr floatValue];
...
...
@@ -122,7 +129,7 @@
NSLog(@"📐 Plan dimensions: width = %f, height = %f", self.planWidth, self.planHeight);
NSLog(@"🗺 Found %lu locations", (unsigned long)self.locations.count);
NSLog(@"🖼 Plan image URL: %@", self.planImageURL);
NSLog(@"🧭 plan_id = %@
, location_id = %@", self.planID, self.locatio
nID);
NSLog(@"🧭 plan_id = %@
", self.pla
nID);
// Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^{
...
...
@@ -179,12 +186,25 @@
if (self.selectionLocked) return;
CGPoint tapPoint = [recognizer locationInView:self.planImageView];
NSLog(@"👆 User tapped at: %@", NSStringFromCGPoint(tapPoint));
NSLog(@"👆 User tapped
on screen
at: %@", NSStringFromCGPoint(tapPoint));
// Remove previous marker (if any)
[self.markerView removeFromSuperview];
// Get image display rect and scaling ratios
CGRect imageRect = [self imageRectInImageView:self.planImageView];
CGFloat displayedWidth = imageRect.size.width;
CGFloat displayedHeight = imageRect.size.height;
CGFloat scaleX = displayedWidth / self.planWidth;
CGFloat scaleY = displayedHeight / self.planHeight;
// Add new marker
// 🔹 Convert back to original plan coordinates
CGFloat planX = (tapPoint.x - imageRect.origin.x) / scaleX;
CGFloat planY = (tapPoint.y - imageRect.origin.y) / scaleY;
NSLog(@"🧭 Original plan coordinates: (%.2f, %.2f)", planX, planY);
self.tappedPlanX = planX;
self.tappedPlanY = planY;
// Optional: Visual marker
[self.markerView removeFromSuperview];
UIView *marker = [[UIView alloc] initWithFrame:CGRectMake(tapPoint.x - 6, tapPoint.y - 6, 12, 12)];
marker.backgroundColor = [UIColor redColor];
marker.layer.cornerRadius = 6;
...
...
@@ -193,23 +213,19 @@
[self.planImageView addSubview:marker];
self.markerView = marker;
// C
heck if tap inside any polyg
on
// C
ontinue with polygon detecti
on
for (int i = 0; i < self.locations.count; i++) {
NSDictionary *locationData = self.locations[i];
CAShapeLayer *overlay = self.overlayLayers[i];
if ([self isPoint:tapPoint insideLocation:locationData]) {
NSLog(@"✅ Tap inside location: %@", locationData[@"name"]);
// Selected: Red border
overlay.strokeColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.8].CGColor;
self.selectedOverlay = overlay;
self.selectionLocked = YES;
self.selectedLocation = locationData[@"name"];
[self showAddIssuePopup];
} else {
// Non-selected: Gray border, no fill
overlay.strokeColor = [UIColor colorWithWhite:0.6 alpha:0.5].CGColor;
overlay.fillColor = UIColor.clearColor.CGColor;
}
...
...
@@ -377,69 +393,6 @@
});
}
- (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;
// ✅ Extract and store plan dimensions (ensure they’re numeric)
NSString *widthStr = [NSString stringWithFormat:@"%@", unitPlan[@"plan_width"]];
NSString *heightStr = [NSString stringWithFormat:@"%@", unitPlan[@"plan_height"]];
self.planWidth = [widthStr floatValue];
self.planHeight = [heightStr floatValue];
NSLog(@"📏 planWidth = %f, planHeight = %f", self.planWidth, self.planHeight);
// 🧱 Safety check
if (self.planWidth <= 0 || self.planHeight <= 0) {
NSLog(@"⚠️ Invalid plan dimensions — overlays may not render correctly.");
}
// 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");
}
// ✅ Update title
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 {
self.scrollView = [[UIScrollView alloc] init];
...
...
@@ -510,12 +463,6 @@
if (i == 0) [path moveToPoint:CGPointMake(x, y)];
else [path addLineToPoint:CGPointMake(x, y)];
// 🔵 Visual dot marker
// UIView *dot = [[UIView alloc] initWithFrame:CGRectMake(x - 2, y - 2, 4, 4)];
// dot.backgroundColor = [UIColor blueColor];
// dot.layer.cornerRadius = 2;
// [planImageView addSubview:dot];
NSLog(@"📍 Point %d -> x=%f, y=%f", i, x, y);
if (x < imageRect.origin.x || y < imageRect.origin.y ||
...
...
@@ -670,8 +617,36 @@
self.selectionLocked = NO;
[self dismissAddIssuePopup];
[AddIssueAPIClient fetchSettingsByLocation:^(NSDictionary *data, NSError *error) {
// Hide loader once we have a result
// === 1️⃣ Find the matching location ID ===
NSString *selectedName = self.selectedLocation;
NSLog(@"self.unitPlanLocation: %@, self.selectedLocation: %@", self.unitPlanLocations, self.selectedLocation);
for (NSDictionary *loc in self.unitPlanLocations) {
NSString *locName = loc[@"location_name"] ?: loc[@"name"];
NSString *locID = [NSString stringWithFormat:@"%@", loc[@"location_id"] ?: loc[@"id"]];
if ([locName isEqualToString:self.selectedLocation]) {
self.locationID = locID;
NSLog(@"✅ Matched location: %@ → ID %@", locName, locID);
break;
}
}
if (self.locationID) {
NSLog(@"📡 Fetching settings for location %@ and plan %@", self.locationID, self.planID);
[self handleSettingsByLocation:self.locationID planID:self.planID];
} else {
NSLog(@"⚠️ No match found for %@", self.selectedLocation);
}
}
- (void)handleSettingsByLocation:(NSString *)locationID planID:(NSString *)planID {
[AddIssueAPIClient fetchSettingsByLocation:locationID
projectID:@"8"
completion:^(NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ Error fetching settings: %@", error);
return;
...
...
@@ -696,15 +671,32 @@
if ([appData[@"status"] isEqualToString:@"success"] && mainData) {
NSLog(@"✅ Location settings loaded successfully");
// Determine defectMatrix flag
NSString *defectMatrix = mainData ? @"YES" : @"NO";
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[self navigateToAddIssueDetailsWithLocationData:mainData defectMatrix:defectMatrix];
});
return;
}
// === 3️⃣ Fallback and special message handling ===
NSString *message = appData[@"message"] ?: @"Unknown server response.";
if ([message isEqualToString:@"user_not_found"]) {
NSLog(@"Session Expired, Please log in again");
} else if ([message.lowercaseString containsString:@"defect matrix not found"] ||
[message.lowercaseString containsString:@"location not found"]) {
[self navigateToAddIssueDetailsWithLocationData:nil defectMatrix:@"NO"];
} else {
NSLog(@"Error %@", message);
}
}];
}
- (void)navigateToAddIssueDetailsWithLocationData:(NSDictionary *)mainData defectMatrix:(NSString *)defectMatrix {
AddIssueDetailsViewController *nextVC = [[AddIssueDetailsViewController alloc] init];
nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
NSLog(@"locationID %@ and planID %@", self.locationID, self.planID);
// ✅ Pass data forward
nextVC.planID = self.planID;
nextVC.locationID = self.locationID;
nextVC.selectedLocationName = self.selectedLocation;
...
...
@@ -712,39 +704,21 @@
nextVC.defectMatrix = defectMatrix;
nextVC.projectCode = self.projectCode;
nextVC.projectName = self.projectName;
nextVC.planX = self.tappedPlanX;
nextVC.planY = self.tappedPlanY;
NSLog(@"📦 Data being brought over:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@\n projectName: %@\n projectCode: %@
\n locationData: %@",
NSLog(@"📦 Data being brought over:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@\n projectName: %@\n projectCode: %@\n XCoordinates: %f\n YCoordinates: %f
\n locationData: %@",
nextVC.planID,
nextVC.locationID,
nextVC.selectedLocationName,
nextVC.defectMatrix,
nextVC.projectName,
nextVC.projectCode,
nextVC.planX,
nextVC.planY,
nextVC.locationData);
[self presentViewController:nextVC animated:YES completion:nil];
});
return;
}
// === 3️⃣ Fallback and special message handling ===
NSString *message = appData[@"message"] ?: @"Unknown server response.";
if ([message isEqualToString:@"user_not_found"]) {
NSLog(@"Session Expired, Please log in again");
// Optionally trigger logout flow here
} else if ([message.lowercaseString containsString:@"defect matrix not found"] ||
[message.lowercaseString containsString:@"location not found"]) {
// Proceed anyway but with defectMatrix=NO
AddIssueDetailsViewController *nextVC = [[AddIssueDetailsViewController alloc] init];
nextVC.planID = self.planID;
nextVC.locationID = self.locationID;
nextVC.selectedLocationName = self.selectedLocation;
nextVC.defectMatrix = @"NO";
[self presentViewController:nextVC animated:YES completion:nil];
} else {
NSLog(@"Error %@", message);
}
}];
}
#pragma mark - Actions
...
...
ios/QmsPluginFramework.xcframework/Info.plist
View file @
3dd910fa
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
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
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
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
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
3dd910fa
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
3dd910fa
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