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
c8fb728f
Commit
c8fb728f
authored
Oct 28, 2025
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code update
parent
3dd910fa
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
289 additions
and
136 deletions
+289
-136
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
AddIssueAPIClient.mm
...ramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
+7
-1
DetailsViewController.mm
...work/QmsPluginFramework/AddIssue/DetailsViewController.mm
+144
-42
PlanViewController.mm
...amework/QmsPluginFramework/AddIssue/PlanViewController.mm
+16
-16
DashboardHeaderView.mm
...ework/QmsPluginFramework/Dashboard/DashboardHeaderView.mm
+9
-9
DashboardViewController.mm
...k/QmsPluginFramework/Dashboard/DashboardViewController.mm
+113
-68
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
No files found.
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
c8fb728f
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
c8fb728f
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
View file @
c8fb728f
...
...
@@ -217,7 +217,13 @@
// 🔹 Append images
if (images.count > 0) {
for (int i = 0; i < images.count; i++) {
UIImage *image = images[i];
id maybeImage = images[i];
if (![maybeImage isKindOfClass:[UIImage class]]) {
NSLog(@"⚠️ Skipping non-UIImage at index %d: %@", i, maybeImage);
continue; // skip invalid entries
}
UIImage *image = (UIImage *)maybeImage;
NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
if (!imageData) continue;
...
...
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/DetailsViewController.mm
View file @
c8fb728f
...
...
@@ -206,7 +206,7 @@
[content addSubview:forLabel];
[forLabel.topAnchor constraintEqualToAnchor:content.topAnchor constant:spacing].active = YES;
[forLabel.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:20].active = YES;
// 🧩 Build dynamic text safely
NSString *unitText = @"";
if (self.projectName && self.projectCode) {
...
...
@@ -240,12 +240,14 @@
[locationContainer.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-20],
[locationContainer.heightAnchor constraintEqualToConstant:44],
]];
lastView = locationContainer;
// === Location Field (read-only) ===
UITextField *locationField = [[UITextField alloc] init];
locationField.translatesAutoresizingMaskIntoConstraints = NO;
locationField.text = self.selectedLocationName ?: @"Select location";
locationField.font = [UIFont systemFontOfSize:15];
locationField.textColor = [UIColor blackColor];
locationField.enabled = NO;
[locationContainer addSubview:locationField];
self.locationField = locationField;
...
...
@@ -257,22 +259,22 @@
]];
// === Reselect Button (inside the container, right-aligned) ===
UIButton *reselectBtn = [UIButton buttonWithType:UIButtonTypeSystem];
reselectBtn.translatesAutoresizingMaskIntoConstraints = NO;
[reselectBtn setTitle:@"Reselect" forState:UIControlStateNormal];
[reselectBtn setTitleColor:[UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1]
forState:UIControlStateNormal];
reselectBtn.titleLabel.font = [UIFont boldSystemFontOfSize:14];
[reselectBtn addTarget:self action:@selector(dismissSelf) forControlEvents:UIControlEventTouchUpInside];
[locationContainer addSubview:reselectBtn];
[NSLayoutConstraint activateConstraints:@[
[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],
]];
//
UIButton *reselectBtn = [UIButton buttonWithType:UIButtonTypeSystem];
//
reselectBtn.translatesAutoresizingMaskIntoConstraints = NO;
//
[reselectBtn setTitle:@"Reselect" forState:UIControlStateNormal];
//
[reselectBtn setTitleColor:[UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1]
//
forState:UIControlStateNormal];
//
reselectBtn.titleLabel.font = [UIFont boldSystemFontOfSize:14];
//
[reselectBtn addTarget:self action:@selector(dismissSelf) forControlEvents:UIControlEventTouchUpInside];
//
[locationContainer addSubview:reselectBtn];
//
//
[NSLayoutConstraint activateConstraints:@[
//
[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],
//
]];
// Category, Type, Issue — dropdown style
NSArray *titles = @[@"*Category", @"*Type", @"*Issue"];
...
...
@@ -336,7 +338,9 @@
comment.layer.borderWidth = 1.0;
comment.layer.cornerRadius = 8;
comment.layer.borderColor = [UIColor lightGrayColor].CGColor;
comment.backgroundColor = [UIColor whiteColor];
comment.font = [UIFont systemFontOfSize:15];
comment.textColor = [UIColor blackColor];
[content addSubview:comment];
[NSLayoutConstraint activateConstraints:@[
[comment.topAnchor constraintEqualToAnchor:commentLabel.bottomAnchor constant:8],
...
...
@@ -381,7 +385,7 @@
[submit setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
submit.titleLabel.font = [UIFont boldSystemFontOfSize:16];
submit.layer.cornerRadius = 8;
[submit addTarget:self action:@selector(handleSubmit) forControlEvents:UIControlEventTouchUpInside];
[submit addTarget:self action:@selector(handleSubmit
Tap
) forControlEvents:UIControlEventTouchUpInside];
[content addSubview:submit];
[NSLayoutConstraint activateConstraints:@[
[submit.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing],
...
...
@@ -391,7 +395,12 @@
]];
lastView = submit;
[content.bottomAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing].active = YES;
// 👇 Add tap gesture to dismiss keyboard
UITapGestureRecognizer *tapToDismiss = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(dismissKeyboard)];
tapToDismiss.cancelsTouchesInView = NO; // ensures buttons still respond
[self.scrollView addGestureRecognizer:tapToDismiss];
}
- (UILabel *)makeLabelWithText:(NSString *)text bold:(BOOL)bold size:(CGFloat)size {
...
...
@@ -740,40 +749,133 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)handleSubmit {
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);
- (void)handleSubmitTap {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Confirm Submission"
message:@"Are you sure you want to submit this issue?"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"Submit"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self performSubmit]; // 👈 call your existing submission logic here
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:nil];
[alert addAction:cancelAction];
[alert addAction:confirmAction];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)performSubmit {
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.text);
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 ?: @"",
@"comment": self.commentField
.text
?: @"",
@"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"]);
}
images:self.uploadedImages
completion:^(NSDictionary *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{ // ensure UI updates happen on main thread
if (error) {
NSLog(@"❌ Submission failed: %@", error.localizedDescription);
[self showAlertWithTitle:@"Submission Failed"
message:error.localizedDescription ?: @"An unknown error occurred."];
return;
}
NSDictionary *appData = response[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"✅ Issue submitted successfully!");
// ✅ Success alert
UIAlertController *successAlert = [UIAlertController alertControllerWithTitle:@"Issue Submitted"
message:@"Your issue has been successfully added."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
// Optionally go back or refresh dashboard
UIViewController *presenter = self.presentingViewController;
if (presenter.presentingViewController) {
[presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil];
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}}];
[successAlert addAction:ok];
[self presentViewController:successAlert animated:YES completion:nil];
} else {
NSString *msg = appData[@"message"] ?: @"Unexpected response from server.";
NSLog(@"⚠️ API Error: %@", msg);
[self showAlertWithTitle:@"Submission Error" message:msg];
}
});
}];
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)dismissKeyboard {
[self.view endEditing:YES];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)keyboardWillShow:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat kbHeight = kbFrame.size.height;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 0, kbHeight + 20, 0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
// 👇 Optional: make sure comment field is visible
[self.scrollView scrollRectToVisible:self.commentField.frame animated:YES];
}
- (void)keyboardWillHide:(NSNotification *)notification {
self.scrollView.contentInset = UIEdgeInsetsZero;
self.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/PlanViewController.mm
View file @
c8fb728f
...
...
@@ -291,16 +291,16 @@
[self.headerView addSubview:self.backButton];
// ❓ 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)
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.helpButton];
//
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)
//
forControlEvents:UIControlEventTouchUpInside];
//
[self.headerView addSubview:self.helpButton];
// 🏷 Title label (project name)
self.titleLabel = [[UILabel alloc] init];
...
...
@@ -344,20 +344,20 @@
[self.backButton.heightAnchor constraintEqualToConstant:44],
// Help button
[self.helpButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-8],
[self.helpButton.centerYAnchor constraintEqualToAnchor:self.backButton.centerYAnchor],
[self.helpButton.widthAnchor constraintEqualToConstant:44],
[self.helpButton.heightAnchor constraintEqualToConstant:44],
//
[self.helpButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-8],
//
[self.helpButton.centerYAnchor constraintEqualToAnchor:self.backButton.centerYAnchor],
//
[self.helpButton.widthAnchor constraintEqualToConstant:44],
//
[self.helpButton.heightAnchor constraintEqualToConstant:44],
// Title label (below buttons, left-aligned)
[self.titleLabel.topAnchor constraintEqualToAnchor:self.backButton.bottomAnchor constant:4],
[self.titleLabel.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:16],
[self.titleLabel.trailingAnchor constraintLessThanOrEqualToAnchor:self.helpButton.leadingAnchor constant:-8],
//
[self.titleLabel.trailingAnchor constraintLessThanOrEqualToAnchor:self.helpButton.leadingAnchor constant:-8],
// Subtitle (below title, left-aligned)
[subtitleLabel.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:2],
[subtitleLabel.leadingAnchor constraintEqualToAnchor:self.titleLabel.leadingAnchor],
[subtitleLabel.trailingAnchor constraintLessThanOrEqualToAnchor:self.helpButton.leadingAnchor constant:-8],
//
[subtitleLabel.trailingAnchor constraintLessThanOrEqualToAnchor:self.helpButton.leadingAnchor constant:-8],
]];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardHeaderView.mm
View file @
c8fb728f
...
...
@@ -52,11 +52,11 @@
[self addSubview:_unitNameLabel];
// Info button (bottom right)
_infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
_infoButton.translatesAutoresizingMaskIntoConstraints = NO;
[_infoButton setImage:[UIImage systemImageNamed:@"info.circle"] forState:UIControlStateNormal];
_infoButton.tintColor = [UIColor whiteColor];
[self addSubview:_infoButton];
//
_infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
//
_infoButton.translatesAutoresizingMaskIntoConstraints = NO;
//
[_infoButton setImage:[UIImage systemImageNamed:@"info.circle"] forState:UIControlStateNormal];
//
_infoButton.tintColor = [UIColor whiteColor];
//
[self addSubview:_infoButton];
// Layout constraints
[NSLayoutConstraint activateConstraints:@[
...
...
@@ -79,10 +79,10 @@
[_unitNameLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-16],
// Info button bottom-right
[_infoButton.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-16],
[_infoButton.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-18],
[_infoButton.widthAnchor constraintEqualToConstant:24],
[_infoButton.heightAnchor constraintEqualToConstant:24],
//
[_infoButton.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-16],
//
[_infoButton.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-18],
//
[_infoButton.widthAnchor constraintEqualToConstant:24],
//
[_infoButton.heightAnchor constraintEqualToConstant:24],
]];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.mm
View file @
c8fb728f
...
...
@@ -24,6 +24,8 @@
@property (nonatomic, strong) NSString *projectName;
@property (nonatomic, strong) UIImage *headerBackgroundImage;
@property (nonatomic, strong) NSArray *announcements;
@property (nonatomic, strong) UIView *loadingOverlay;
@property (nonatomic, strong) UIActivityIndicatorView *spinner;
@end
...
...
@@ -47,49 +49,49 @@
self.projectCode = @"PTD197656";
self.projectName = @"Ara E`Residence Dev";
[DashboardAPIClient fetchDashboardInfo:^(NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ fetchDashboardInfo error: %@", error.localizedDescription);
return;
}
[self refreshDashboardContent];
}
#pragma mark - Refresh Logic
- (void)refreshDashboardContent {
NSLog(@"🔁 Refreshing dashboard content...");
NSLog(@"🧩 Dashboard Info response received");
[self processDashboardResponse:data];
dispatch_group_t group = dispatch_group_create();
__block NSDictionary *dashboardData = nil;
__block NSDictionary *announcementData = nil;
// 💾 Optionally, save full JSON to a file for reference
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"DashboardInfoResponse.txt"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
[jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 Dashboard API response saved to %@", filePath);
dispatch_group_enter(group);
[DashboardAPIClient fetchDashboardInfo:^(NSDictionary *data, NSError *error) {
if (!error) dashboardData = data;
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[DashboardAPIClient fetchAnnouncement:^(NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ fetchAnnouncement error: %@", error.localizedDescription);
return;
}
if (!error) announcementData = data;
dispatch_group_leave(group);
}];
NSLog(@"🗞️ Announcement response received");
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
if (dashboardData) [self processDashboardResponse:dashboardData];
if (announcementData) [self processAnnouncementResponse:announcementData];
NSLog(@"✅ Dashboard refresh complete");
});
}
// 🔍 Optional: Log the whole JSON structure for debugging
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"%@", jsonString);
// 💾 Save to file for offline reference
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"AnnouncementResponse.txt"];
[jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 Announcement response saved to %@", filePath);
- (void)handlePullToRefresh:(UIRefreshControl *)refreshControl {
NSLog(@"🔄 Pull-to-refresh triggered");
// ✅ Process and show popup announcements
[self processAnnouncementResponse:data];
}];
[self refreshDashboardContent];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[refreshControl endRefreshing];
});
}
#pragma mark - Layout
- (void)viewDidLayoutSubviews {
NSLog(@"Header frame: %@", NSStringFromCGRect(_headerView.frame));
[super viewDidLayoutSubviews];
...
...
@@ -105,7 +107,6 @@
}
#pragma mark - Header
- (void)setupHeader {
CGFloat headerHeight = 220.0;
_headerView = [[DashboardHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, headerHeight)];
...
...
@@ -131,33 +132,33 @@
});
[self.view addSubview:_headerView];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem];
backButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *backImage = [[UIImage systemImageNamed:@"chevron.left"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[backButton setImage:backImage forState:UIControlStateNormal];
backButton.tintColor = [UIColor whiteColor];
[backButton addTarget:self action:@selector(handleBackButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
UIButton *menuButton = [UIButton buttonWithType:UIButtonTypeSystem];
menuButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *menuImage = [[UIImage systemImageNamed:@"line.3.horizontal"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[menuButton setImage:menuImage forState:UIControlStateNormal];
menuButton.tintColor = [UIColor whiteColor];
[menuButton addTarget:self action:@selector(handleMenuButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:menuButton];
[NSLayoutConstraint activateConstraints:@[
[backButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8],
[backButton.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:4],
[backButton.widthAnchor constraintEqualToConstant:44],
[backButton.heightAnchor constraintEqualToConstant:44],
[menuButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8],
[menuButton.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:4],
[menuButton.widthAnchor constraintEqualToConstant:44],
[menuButton.heightAnchor constraintEqualToConstant:44],
]];
//
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem];
//
backButton.translatesAutoresizingMaskIntoConstraints = NO;
//
UIImage *backImage = [[UIImage systemImageNamed:@"chevron.left"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
//
[backButton setImage:backImage forState:UIControlStateNormal];
//
backButton.tintColor = [UIColor whiteColor];
//
[backButton addTarget:self action:@selector(handleBackButtonTapped) forControlEvents:UIControlEventTouchUpInside];
//
[self.view addSubview:backButton];
//
UIButton *menuButton = [UIButton buttonWithType:UIButtonTypeSystem];
//
menuButton.translatesAutoresizingMaskIntoConstraints = NO;
//
UIImage *menuImage = [[UIImage systemImageNamed:@"line.3.horizontal"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
//
[menuButton setImage:menuImage forState:UIControlStateNormal];
//
menuButton.tintColor = [UIColor whiteColor];
//
[menuButton addTarget:self action:@selector(handleMenuButtonTapped) forControlEvents:UIControlEventTouchUpInside];
//
[self.view addSubview:menuButton];
//
[NSLayoutConstraint activateConstraints:@[
//
[backButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8],
//
[backButton.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:4],
//
[backButton.widthAnchor constraintEqualToConstant:44],
//
[backButton.heightAnchor constraintEqualToConstant:44],
//
//
[menuButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8],
//
[menuButton.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:4],
//
[menuButton.widthAnchor constraintEqualToConstant:44],
//
[menuButton.heightAnchor constraintEqualToConstant:44],
//
]];
}
- (void)handleBackButtonTapped {
...
...
@@ -174,7 +175,6 @@
}
#pragma mark - Footer
- (void)setupFooter {
CGFloat footerHeight = 80.0;
CGFloat bottomInset = self.view.safeAreaInsets.bottom;
...
...
@@ -241,7 +241,6 @@
}
#pragma mark - Scroll Content
- (void)setupScrollContent {
CGFloat topOffset = 220.0;
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(
...
...
@@ -258,6 +257,17 @@
_scrollView.contentInset = UIEdgeInsetsMake(0, 0, footerHeight, 0);
_scrollView.scrollIndicatorInsets = _scrollView.contentInset;
// === 🌀 Add Pull-to-Refresh ===
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:@selector(handlePullToRefresh:)
forControlEvents:UIControlEventValueChanged];
if (@available(iOS 10.0, *)) {
_scrollView.refreshControl = refreshControl;
} else {
[_scrollView addSubview:refreshControl];
}
[self.view addSubview:_scrollView];
_contentContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.bounds.size.width, 0)];
...
...
@@ -346,7 +356,6 @@
}
#pragma mark - Dashboard Data Processor
- (void)processDashboardResponse:(NSDictionary *)data {
NSDictionary *appData = data[@"AppData"];
NSDictionary *mainData = data[@"Data"];
...
...
@@ -467,8 +476,6 @@
// }
}
- (void)refreshDashboardSectionsWithData:(NSDictionary *)mainData {
NSLog(@"🔄 Refreshing dashboard sections...");
...
...
@@ -525,6 +532,7 @@
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(16, 0, 200, 24)];
title.text = @"Project Update";
title.font = [UIFont boldSystemFontOfSize:18];
title.textColor = [UIColor blackColor];
title.userInteractionEnabled = YES; // 👈 enable taps
UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
...
...
@@ -567,6 +575,7 @@
title.text = @"Appointments";
title.font = [UIFont boldSystemFontOfSize:18];
[section addSubview:title];
title.textColor = [UIColor blackColor];
title.userInteractionEnabled = YES; // 👈 enable taps
UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
...
...
@@ -604,6 +613,7 @@
title.text = @"Issue Updates";
title.font = [UIFont boldSystemFontOfSize:18];
[section addSubview:title];
title.textColor = [UIColor blackColor];
title.userInteractionEnabled = YES; // 👈 enable taps
UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
...
...
@@ -675,6 +685,7 @@
title.text = item[@"title"] ?: @"Untitled announcement";
title.numberOfLines = 3;
title.font = [UIFont boldSystemFontOfSize:16];
title.textColor = [UIColor blackColor];
[card addSubview:title];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleAnnouncementTap:)];
...
...
@@ -730,6 +741,7 @@
timeLabel.textAlignment = NSTextAlignmentRight;
timeLabel.text = startTime;
timeLabel.font = [UIFont boldSystemFontOfSize:15];
timeLabel.textColor = [UIColor grayColor];
[card addSubview:timeLabel];
// === Description text ===
...
...
@@ -945,7 +957,6 @@
}
#pragma mark - Individual Card Taps
- (void)handleAnnouncementTap:(UITapGestureRecognizer *)gesture {
UIView *card = gesture.view;
[self animateTapForView:card];
...
...
@@ -973,7 +984,6 @@
}
#pragma mark - Card Factory with Tap Animation
- (UIView *)createCardWithText:(NSString *)text frame:(CGRect)frame {
UIView *card = [[UIView alloc] initWithFrame:frame];
card.backgroundColor = [UIColor whiteColor];
...
...
@@ -997,7 +1007,6 @@
}
#pragma mark - Tap Handlers
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gesture {
UILabel *header = (UILabel *)gesture.view;
[self animateTapForView:header];
...
...
@@ -1022,4 +1031,40 @@
}];
}
#pragma mark - Loading Overlay
- (void)showLoadingOverlay:(NSString *)message {
if (self.loadingOverlay.superview) return; // already showing
UIView *overlay = [[UIView alloc] initWithFrame:self.view.bounds];
overlay.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge];
spinner.center = overlay.center;
spinner.color = UIColor.whiteColor;
[spinner startAnimating];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(spinner.frame) + 16,
overlay.bounds.size.width, 30)];
label.text = message ?: @"Loading...";
label.textAlignment = NSTextAlignmentCenter;
label.textColor = UIColor.whiteColor;
label.font = [UIFont boldSystemFontOfSize:16];
[overlay addSubview:spinner];
[overlay addSubview:label];
[self.view addSubview:overlay];
self.loadingOverlay = overlay;
self.spinner = spinner;
}
- (void)hideLoadingOverlay {
[self.spinner stopAnimating];
[self.loadingOverlay removeFromSuperview];
self.loadingOverlay = nil;
self.spinner = nil;
}
@end
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
c8fb728f
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
c8fb728f
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