Commit 3806f808 authored by Wei Han's avatar Wei Han

PlanScreen UI update

parent 1c49cf8f
......@@ -8,32 +8,32 @@
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
......
// 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
// 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
......@@ -5,6 +5,9 @@ NS_ASSUME_NONNULL_BEGIN
@interface PlanViewController : UIViewController
@property (nonatomic, strong) NSString *projectCode;
@property (nonatomic, strong) NSString *projectName;
@end
NS_ASSUME_NONNULL_END
// PlanViewController.mm
#import "PlanViewController.h"
#import "DetailsViewController.h"
#import "AddIssueAPIClient.h"
@interface PlanViewController ()
......@@ -8,11 +9,12 @@
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UIButton *helpButton;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIImageView *planImageView;
@property (nonatomic, strong) NSString *selectedLocation;
@property (nonatomic, strong) NSDictionary *unitPlanData;
@property (nonatomic, strong) NSArray *locations;
@property (nonatomic, strong) NSString *planImageURL;
@end
......@@ -26,34 +28,104 @@
// Create UI elements (but don’t assign final frames yet)
[self createHeader];
[self createScrollView];
[self fetchInitialData];
[self.view bringSubviewToFront:self.headerView];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.view bringSubviewToFront:self.headerView];
}
CGFloat topInset = self.view.safeAreaInsets.top;
CGFloat headerHeight = 48.0;
- (void)fetchInitialData {
NSLog(@"🌐 Fetching Unit Plan data...");
// Layout header
self.headerView.frame = CGRectMake(0, topInset, self.view.bounds.size.width, headerHeight);
[AddIssueAPIClient fetchGetUnitPlan:^(NSDictionary *data, NSError *error) {
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
self.backButton.frame = CGRectMake(12, 8, 32, 32);
self.helpButton.frame = CGRectMake(self.headerView.bounds.size.width - 44, 8, 32, 32);
self.titleLabel.frame = CGRectMake(0, 8, self.headerView.bounds.size.width, 32);
NSArray *mainData = data[@"Data"];
if (mainData.count == 0) {
NSLog(@"⚠️ No unit plan data found");
return;
}
// Layout scroll view
CGFloat scrollY = topInset + headerHeight;
self.scrollView.frame = CGRectMake(0, scrollY, self.view.bounds.size.width, self.view.bounds.size.height - scrollY);
self.planImageView.frame = self.scrollView.bounds;
// Store main plan object
self.unitPlanData = mainData.firstObject;
self.locations = self.unitPlanData[@"location"];
[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 {
// 🟩 Status bar background view
// 🟩 Status bar background
UIView *statusBarBackground = [[UIView alloc] init];
statusBarBackground.backgroundColor = [UIColor colorWithRed:0/255.0
green:109/255.0
......@@ -62,44 +134,58 @@
statusBarBackground.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:statusBarBackground];
// 🟦 Header background view
// 🟦 Header background
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = statusBarBackground.backgroundColor;
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
// Back button
// 🔙 Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
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.tintColor = [UIColor whiteColor];
[self.backButton addTarget:self action:@selector(handleBack)
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self
action:@selector(handleBack)
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.backButton];
// Title label
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
// ❓ Help button
self.helpButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.helpButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *helpImage = [[UIImage systemImageNamed:@"questionmark.circle"]
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self.helpButton setImage:helpImage forState:UIControlStateNormal];
self.helpButton.tintColor = [UIColor whiteColor];
[self.helpButton addTarget:self action:@selector(showTutorial)
self.helpButton.tintColor = UIColor.whiteColor;
[self.helpButton addTarget:self
action:@selector(showTutorial)
forControlEvents:UIControlEventTouchUpInside];
[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
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
CGFloat headerHeight = 80.0; // ⬆️ Taller header now
[NSLayoutConstraint activateConstraints:@[
// Status bar background
[statusBarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
......@@ -107,68 +193,149 @@
[statusBarBackground.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[statusBarBackground.bottomAnchor constraintEqualToAnchor:safe.topAnchor],
// Header pinned below safe area
// Header
[self.headerView.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerView.heightAnchor constraintEqualToConstant:48],
[self.headerView.heightAnchor constraintEqualToConstant:headerHeight],
// Back button
[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.heightAnchor constraintEqualToConstant:44],
// Help button
[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.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.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 {
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.delegate = (id<UIScrollViewDelegate>)self;
self.scrollView.minimumZoomScale = 1.0;
self.scrollView.maximumZoomScale = 5.0;
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.scrollView];
self.planImageView = [[UIImageView alloc] init];
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.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:self.planImageView];
// 👉 Temporary test button
UIButton *testButton = [UIButton buttonWithType:UIButtonTypeSystem];
[testButton setTitle:@"Next Screen →" forState:UIControlStateNormal];
testButton.titleLabel.font = [UIFont boldSystemFontOfSize:18];
[testButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
testButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
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];
// ✅ Scroll view constraints (below header)
[NSLayoutConstraint activateConstraints:@[
[self.scrollView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
[self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
]];
// Add directly on top of main view (not inside scrollView)
[self.view addSubview:testButton];
} else {
self.planImageView.image = testImage;
}
// ✅ Image view constraints (fills scroll view)
[NSLayoutConstraint activateConstraints:@[
[self.planImageView.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor],
[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 {
......@@ -308,4 +475,22 @@
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
......@@ -3,10 +3,6 @@
@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)fetchAnnouncement:(void (^)(NSDictionary *data, NSError *error))completion;
......
......@@ -3,58 +3,6 @@
@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 {
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/plan/getIssueUpdateAppointmentInfo";
NSURL *url = [NSURL URLWithString:urlString];
......
......@@ -229,6 +229,8 @@
switch (sender.tag) {
case 1: {
PlanViewController *planVC = [[PlanViewController alloc] init];
planVC.projectCode = self.projectCode;
planVC.projectName = self.projectName;
planVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:planVC animated:YES completion:nil];
break;
......@@ -538,7 +540,11 @@
hScroll.showsHorizontalScrollIndicator = NO;
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];
CGRect frame = card.frame;
frame.origin.x = x;
......
......@@ -8,32 +8,32 @@
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
......
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