Commit abcdd3b4 authored by Wei Han's avatar Wei Han

UI update for plan page

parent 3806f808
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
2F8D09092E9605E200C764FF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F8D09082E9605E200C764FF /* CoreGraphics.framework */; }; 2F8D09092E9605E200C764FF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F8D09082E9605E200C764FF /* CoreGraphics.framework */; };
2F99420D2EA9C5F000622199 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F99420C2EA9C5F000622199 /* QuartzCore.framework */; };
2FAEF09A2E8B7BC80086EDA3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */; }; 2FAEF09A2E8B7BC80086EDA3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */; };
2FAEF09C2E8B7BD40086EDA3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */; }; 2FAEF09C2E8B7BD40086EDA3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
2F8D09082E9605E200C764FF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; 2F8D09082E9605E200C764FF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
2F9647652E86307D002CC7CB /* QmsPluginFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = QmsPluginFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2F9647652E86307D002CC7CB /* QmsPluginFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = QmsPluginFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2F99420C2EA9C5F000622199 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.0.sdk/System/iOSSupport/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.0.sdk/System/iOSSupport/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
...@@ -46,6 +48,7 @@ ...@@ -46,6 +48,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
2F99420D2EA9C5F000622199 /* QuartzCore.framework in Frameworks */,
2F8D09092E9605E200C764FF /* CoreGraphics.framework in Frameworks */, 2F8D09092E9605E200C764FF /* CoreGraphics.framework in Frameworks */,
2FAEF09C2E8B7BD40086EDA3 /* Foundation.framework in Frameworks */, 2FAEF09C2E8B7BD40086EDA3 /* Foundation.framework in Frameworks */,
2FAEF09A2E8B7BC80086EDA3 /* UIKit.framework in Frameworks */, 2FAEF09A2E8B7BC80086EDA3 /* UIKit.framework in Frameworks */,
...@@ -75,6 +78,7 @@ ...@@ -75,6 +78,7 @@
2FAEF0982E8B7BC80086EDA3 /* Frameworks */ = { 2FAEF0982E8B7BC80086EDA3 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
2F99420C2EA9C5F000622199 /* QuartzCore.framework */,
2F8D09082E9605E200C764FF /* CoreGraphics.framework */, 2F8D09082E9605E200C764FF /* CoreGraphics.framework */,
2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */, 2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */,
2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */, 2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */,
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
@property (nonatomic, strong) NSDictionary *unitPlanData; @property (nonatomic, strong) NSDictionary *unitPlanData;
@property (nonatomic, strong) NSArray *locations; @property (nonatomic, strong) NSArray *locations;
@property (nonatomic, strong) NSString *planImageURL; @property (nonatomic, strong) NSString *planImageURL;
@property (nonatomic, assign) CGFloat planWidth;
@property (nonatomic, assign) CGFloat planHeight;
@end @end
...@@ -36,6 +38,12 @@ ...@@ -36,6 +38,12 @@
- (void)viewDidLayoutSubviews { - (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews]; [super viewDidLayoutSubviews];
[self.view bringSubviewToFront:self.headerView]; [self.view bringSubviewToFront:self.headerView];
static BOOL hasRenderedLocations = NO;
if (!hasRenderedLocations && self.planImageView.image && self.locations.count > 0) {
hasRenderedLocations = YES;
[self renderAllLocations:self.locations];
}
} }
- (void)fetchInitialData { - (void)fetchInitialData {
...@@ -54,7 +62,7 @@ ...@@ -54,7 +62,7 @@
[jsonData writeToFile:filePath atomically:YES]; [jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 UnitPlan saved to %@", filePath); NSLog(@"📁 UnitPlan saved to %@", filePath);
// 🔍 Parse the JSON // 🔍 Parse JSON
NSDictionary *appData = data[@"AppData"]; NSDictionary *appData = data[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) { if (![appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"⚠️ Server returned non-success status: %@", appData[@"message"]); NSLog(@"⚠️ Server returned non-success status: %@", appData[@"message"]);
...@@ -71,20 +79,36 @@ ...@@ -71,20 +79,36 @@
self.unitPlanData = mainData.firstObject; self.unitPlanData = mainData.firstObject;
self.locations = self.unitPlanData[@"location"]; self.locations = self.unitPlanData[@"location"];
// Extract first issue’s plan image URL if (self.locations.count == 0) {
NSLog(@"⚠️ No locations found in plan");
return;
}
// ✅ Extract plan dimensions and image URL
NSDictionary *firstLocation = self.locations.firstObject; NSDictionary *firstLocation = self.locations.firstObject;
NSDictionary *firstIssue = [firstLocation[@"issue"] firstObject]; NSArray *issues = firstLocation[@"issue"];
if (issues.count == 0) {
NSLog(@"⚠️ No issues found under first location");
return;
}
NSDictionary *firstIssue = issues.firstObject;
NSString *widthStr = [NSString stringWithFormat:@"%@", firstIssue[@"plan_width"]];
NSString *heightStr = [NSString stringWithFormat:@"%@", firstIssue[@"plan_height"]];
self.planWidth = [widthStr floatValue];
self.planHeight = [heightStr floatValue];
self.planImageURL = firstIssue[@"plan_image"]; self.planImageURL = firstIssue[@"plan_image"];
NSLog(@"📐 Plan dimensions: width = %f, height = %f", self.planWidth, self.planHeight);
NSLog(@"🗺 Found %lu locations", (unsigned long)self.locations.count); NSLog(@"🗺 Found %lu locations", (unsigned long)self.locations.count);
NSLog(@"🖼 Plan image URL: %@", self.planImageURL); NSLog(@"🖼 Plan image URL: %@", self.planImageURL);
// Now update the UI on main thread // Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self displayPlanImage]; [self displayPlanImage];
[self debugPrintAllIssues];
}); });
}]; }];
[self debugPrintAllIssues];
} }
- (void)displayPlanImage { - (void)displayPlanImage {
...@@ -116,6 +140,9 @@ ...@@ -116,6 +140,9 @@
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
self.planImageView.image = image; self.planImageView.image = image;
[self.scrollView setZoomScale:1.0 animated:NO]; [self.scrollView setZoomScale:1.0 animated:NO];
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
[self renderAllLocations:self.locations];
NSLog(@"✅ Plan image displayed successfully"); NSLog(@"✅ Plan image displayed successfully");
}); });
}]; }];
...@@ -169,7 +196,7 @@ ...@@ -169,7 +196,7 @@
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.titleLabel.text = self.projectName ?: @"Plan Viewer"; self.titleLabel.text = self.projectName ?: @"Plan Viewer";
self.titleLabel.textColor = UIColor.whiteColor; self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont boldSystemFontOfSize:18]; self.titleLabel.font = [UIFont boldSystemFontOfSize:20];
self.titleLabel.textAlignment = NSTextAlignmentCenter; self.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.headerView addSubview:self.titleLabel]; [self.headerView addSubview:self.titleLabel];
...@@ -178,13 +205,13 @@ ...@@ -178,13 +205,13 @@
subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
subtitleLabel.text = self.projectCode ?: @""; subtitleLabel.text = self.projectCode ?: @"";
subtitleLabel.textColor = [UIColor colorWithWhite:1.0 alpha:0.8]; subtitleLabel.textColor = [UIColor colorWithWhite:1.0 alpha:0.8];
subtitleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular]; subtitleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
subtitleLabel.textAlignment = NSTextAlignmentCenter; subtitleLabel.textAlignment = NSTextAlignmentCenter;
[self.headerView addSubview:subtitleLabel]; [self.headerView addSubview:subtitleLabel];
// ✅ Constraints // ✅ Constraints
UILayoutGuide *safe = self.view.safeAreaLayoutGuide; UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
CGFloat headerHeight = 80.0; // ⬆️ Taller header now CGFloat headerHeight = 110.0; // header height
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
// Status bar background // Status bar background
...@@ -211,17 +238,18 @@ ...@@ -211,17 +238,18 @@
[self.helpButton.widthAnchor constraintEqualToConstant:44], [self.helpButton.widthAnchor constraintEqualToConstant:44],
[self.helpButton.heightAnchor constraintEqualToConstant:44], [self.helpButton.heightAnchor constraintEqualToConstant:44],
// Title label (below buttons) // Title label (below buttons, left-aligned)
[self.titleLabel.topAnchor constraintEqualToAnchor:self.backButton.bottomAnchor constant:4], [self.titleLabel.topAnchor constraintEqualToAnchor:self.backButton.bottomAnchor constant:4],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor], [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:16],
[self.titleLabel.trailingAnchor constraintLessThanOrEqualToAnchor:self.helpButton.leadingAnchor constant:-8],
// Subtitle (below title) // Subtitle (below title, left-aligned)
[subtitleLabel.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:2], [subtitleLabel.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:2],
[subtitleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor], [subtitleLabel.leadingAnchor constraintEqualToAnchor:self.titleLabel.leadingAnchor],
[subtitleLabel.trailingAnchor constraintLessThanOrEqualToAnchor:self.helpButton.leadingAnchor constant:-8],
]]; ]];
} }
- (void)loadPlanImageFromURL:(NSString *)urlString { - (void)loadPlanImageFromURL:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString]; NSURL *url = [NSURL URLWithString:urlString];
if (!url) return; if (!url) return;
...@@ -273,6 +301,19 @@ ...@@ -273,6 +301,19 @@
NSDictionary *unitPlan = mainData.firstObject; NSDictionary *unitPlan = mainData.firstObject;
self.unitPlanData = unitPlan; 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 // Save JSON for debugging
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"unitPlanParsed.json"]; NSString *filePath = [docsPath stringByAppendingPathComponent:@"unitPlanParsed.json"];
...@@ -288,7 +329,7 @@ ...@@ -288,7 +329,7 @@
NSLog(@"⚠️ No plan_image found in response"); NSLog(@"⚠️ No plan_image found in response");
} }
// ✅ (Optional) Update title or debug log // ✅ Update title
NSString *unitName = unitPlan[@"unit_name"] ?: @"No name"; NSString *unitName = unitPlan[@"unit_name"] ?: @"No name";
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
self.titleLabel.text = unitName; self.titleLabel.text = unitName;
...@@ -310,6 +351,11 @@ ...@@ -310,6 +351,11 @@
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.bouncesZoom = YES;
self.scrollView.alwaysBounceVertical = YES;
self.scrollView.alwaysBounceHorizontal = YES;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO; self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.scrollView]; [self.view addSubview:self.scrollView];
...@@ -338,6 +384,91 @@ ...@@ -338,6 +384,91 @@
]]; ]];
} }
- (void)renderLocation:(NSDictionary *)locationData onImageView:(UIImageView *)planImageView {
if (!planImageView.image) return;
CGRect imageRect = [self imageRectInImageView:planImageView];
CGFloat displayedWidth = imageRect.size.width;
CGFloat displayedHeight = imageRect.size.height;
NSArray *issues = locationData[@"issue"];
NSLog(@"Total issues: %lu", (unsigned long)issues.count);
NSLog(@"planWidth: %f, planHeight: %f", self.planWidth, self.planHeight);
CGFloat scaleX = displayedWidth / self.planWidth;
CGFloat scaleY = displayedHeight / self.planHeight;
NSArray *points = locationData[@"points"];
if (!points || points.count == 0) {
NSLog(@"⚠️ No points found for location %@", locationData[@"id"]);
return;
}
UIBezierPath *path = [UIBezierPath bezierPath];
for (int i = 0; i < points.count; i++) {
NSDictionary *point = points[i];
CGFloat x = imageRect.origin.x + [point[@"x"] doubleValue] * scaleX;
CGFloat y = imageRect.origin.y + [point[@"y"] doubleValue] * scaleY;
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 ||
x > imageRect.origin.x + imageRect.size.width ||
y > imageRect.origin.y + imageRect.size.height) {
NSLog(@"⚠️ Point %d is out of bounds!", i);
}
}
[path closePath];
CAShapeLayer *polygonLayer = [CAShapeLayer layer];
polygonLayer.path = path.CGPath;
polygonLayer.fillColor = UIColor.clearColor.CGColor;
polygonLayer.strokeColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.3].CGColor;
polygonLayer.lineWidth = 2.0;
[planImageView.layer addSublayer:polygonLayer];
}
- (CGRect)imageRectInImageView:(UIImageView *)imageView {
CGSize imageSize = imageView.image.size;
CGSize viewSize = imageView.bounds.size;
CGFloat scale = MIN(viewSize.width / imageSize.width, viewSize.height / imageSize.height);
CGFloat width = imageSize.width * scale;
CGFloat height = imageSize.height * scale;
CGFloat x = (viewSize.width - width) / 2.0;
CGFloat y = (viewSize.height - height) / 2.0;
return CGRectMake(x, y, width, height);
}
- (void)renderAllLocations:(NSArray *)locations {
for (NSDictionary *locationData in locations) {
[self renderLocation:locationData onImageView:self.planImageView];
}
}
- (UIColor *)colorFromHex:(NSString *)hexString {
unsigned int rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:[hexString stringByReplacingOccurrencesOfString:@"#" withString:@""]];
[scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue >> 16) & 0xFF) / 255.0
green:((rgbValue >> 8) & 0xFF) / 255.0
blue:(rgbValue & 0xFF) / 255.0
alpha:1.0];
}
- (void)handleNextScreen { - (void)handleNextScreen {
[self showAddIssuePopup]; [self showAddIssuePopup];
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment