Commit 57f82def authored by Wei Han's avatar Wei Han

ui update for dashboard

parent 46ab6081
...@@ -7,11 +7,13 @@ ...@@ -7,11 +7,13 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
2F8D09092E9605E200C764FF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F8D09082E9605E200C764FF /* CoreGraphics.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 */
/* 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; };
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; };
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; };
...@@ -44,6 +46,7 @@ ...@@ -44,6 +46,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
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 */,
); );
...@@ -72,6 +75,7 @@ ...@@ -72,6 +75,7 @@
2FAEF0982E8B7BC80086EDA3 /* Frameworks */ = { 2FAEF0982E8B7BC80086EDA3 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
2F8D09082E9605E200C764FF /* CoreGraphics.framework */,
2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */, 2FAEF09B2E8B7BD40086EDA3 /* Foundation.framework */,
2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */, 2FAEF0992E8B7BC80086EDA3 /* UIKit.framework */,
); );
......
// AddIssueViewController.h
#import <UIKit/UIKit.h>
@interface AddIssueViewController : UIViewController
@end
// AddIssueViewController.mm
#import "AddIssueViewController.h"
@implementation AddIssueViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, self.view.bounds.size.width - 40, 40)];
title.text = @"Add Issue Page";
title.textAlignment = NSTextAlignmentCenter;
title.font = [UIFont boldSystemFontOfSize:22];
[self.view addSubview:title];
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
closeButton.frame = CGRectMake(20, 40, 80, 40);
[closeButton setTitle:@"Close" forState:UIControlStateNormal];
[closeButton addTarget:self action:@selector(closeTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:closeButton];
}
- (void)closeTapped {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
// DashboardHeaderView.h
#import <UIKit/UIKit.h>
@interface DashboardHeaderView : UIView
@property (nonatomic, strong) UIImageView *backgroundImageView;
@property (nonatomic, strong) UIImageView *overlayImageView;
@property (nonatomic, strong) UILabel *projectNameLabel;
@property (nonatomic, strong) UILabel *unitNameLabel;
@property (nonatomic, strong) UIButton *infoButton;
- (void)configureWithProjectName:(NSString *)projectName
unitName:(NSString *)unitName
backgroundImage:(UIImage *)backgroundImage
overlayImage:(UIImage *)overlayImage;
@end
#import "DashboardHeaderView.h"
@implementation DashboardHeaderView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupUI];
}
return self;
}
- (void)setupUI {
self.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; // #006D8D
// Background image
_backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
_backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
_backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:_backgroundImageView];
// Overlay image
_overlayImageView = [[UIImageView alloc] initWithFrame:self.bounds];
_overlayImageView.contentMode = UIViewContentModeScaleAspectFill;
_overlayImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_overlayImageView.alpha = 0.4;
[self addSubview:_overlayImageView];
// Header container (for back, title, menu)
UIView *headerBar = [[UIView alloc] init];
headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:headerBar];
// Back button part of header now
// Project name (center title)
_projectNameLabel = [[UILabel alloc] init];
_projectNameLabel.textColor = [UIColor whiteColor];
_projectNameLabel.font = [UIFont boldSystemFontOfSize:18];
_projectNameLabel.textAlignment = NSTextAlignmentCenter;
_projectNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[headerBar addSubview:_projectNameLabel];
// Menu button
UIButton *menuButton = [UIButton buttonWithType:UIButtonTypeSystem];
[menuButton setTitle:@"Menu" forState:UIControlStateNormal];
[menuButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
menuButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
menuButton.translatesAutoresizingMaskIntoConstraints = NO;
[headerBar addSubview:menuButton];
// Unit name (bottom left)
_unitNameLabel = [[UILabel alloc] init];
_unitNameLabel.textColor = [UIColor whiteColor];
_unitNameLabel.font = [UIFont boldSystemFontOfSize:20];
_unitNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[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];
// Layout constraints
[NSLayoutConstraint activateConstraints:@[
// Header bar top
[headerBar.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor constant:0],
[headerBar.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0],
[headerBar.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0],
[headerBar.heightAnchor constraintEqualToConstant:44],
// Back button
// Menu button
[menuButton.trailingAnchor constraintEqualToAnchor:headerBar.trailingAnchor constant:-16],
[menuButton.centerYAnchor constraintEqualToAnchor:headerBar.centerYAnchor],
// Title centered
[_projectNameLabel.centerXAnchor constraintEqualToAnchor:headerBar.centerXAnchor],
[_projectNameLabel.centerYAnchor constraintEqualToAnchor:headerBar.centerYAnchor],
// Unit name bottom-left
[_unitNameLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:16],
[_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],
]];
}
- (void)configureWithProjectName:(NSString *)projectName
unitName:(NSString *)unitName
backgroundImage:(UIImage *)backgroundImage
overlayImage:(UIImage *)overlayImage {
self.projectNameLabel.text = projectName ?: @"Project Name";
self.unitNameLabel.text = unitName ?: @"Unit Name";
self.backgroundImageView.image = backgroundImage ?: [UIImage imageNamed:@"placeholder_header"];
self.overlayImageView.image = overlayImage ?: [UIImage imageNamed:@"placeholder_overlay"];
}
@end
// DashboardViewController
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface DashboardViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "DashboardViewController.h"
#import "DashboardHeaderView.h"
#import <CoreGraphics/CoreGraphics.h>
#import "AddIssueViewController.h"
@implementation DashboardViewController {
DashboardHeaderView *_headerView;
UIScrollView *_scrollView;
UIView *_contentContainer;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0]; // #F2F2F2
[self setupHeader];
[self setupScrollContent];
[self setupFooter];
}
#pragma mark - Header
- (void)setupHeader {
CGFloat headerHeight = 220.0;
_headerView = [[DashboardHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, headerHeight)];
[_headerView configureWithProjectName:@"Project A"
unitName:@"Unit 3A"
backgroundImage:[UIImage imageNamed:@"header_bg"]
overlayImage:[UIImage imageNamed:@"overlay"]];
[self.view addSubview:_headerView];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem];
backButton.frame = CGRectMake(16, 44, 60, 40); // adjust Y for safe area
[backButton setImage:[UIImage systemImageNamed:@"chevron.left"] forState:UIControlStateNormal];
[backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
backButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
[backButton addTarget:self action:@selector(handleBackButtonTapped)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
}
- (void)handleBackButtonTapped {
NSLog(@"🔙 Back button tapped – attempting to close DashboardViewController");
if (self.presentingViewController) {
[self dismissViewControllerAnimated:YES completion:nil];
} else if (self.navigationController) {
[self.navigationController popViewControllerAnimated:YES];
} else {
NSLog(@"⚠️ No parent VC found to close!");
}
}
#pragma mark - Footer
- (void)setupFooter {
CGFloat footerHeight = 80.0;
CGFloat bottomInset = self.view.safeAreaInsets.bottom;
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(
0,
self.view.bounds.size.height - footerHeight,
self.view.bounds.size.width,
footerHeight + bottomInset
)];
footerView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
footerView.backgroundColor = [UIColor whiteColor];
footerView.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
footerView.layer.shadowOpacity = 0.8;
footerView.layer.shadowOffset = CGSizeMake(0, -1);
[self.view addSubview:footerView];
// Button info
NSArray *titles = @[ @"Make Appointment", @"Add Issue", @"View Access Item" ];
NSArray *icons = @[ @"calendar", @"plus.circle", @"list.bullet" ];
CGFloat visibleButtonHeight = footerHeight;
CGFloat buttonWidth = self.view.bounds.size.width / titles.count;
for (NSInteger i = 0; i < titles.count; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(i * buttonWidth, 0, buttonWidth, visibleButtonHeight);
[button setTitle:titles[i] forState:UIControlStateNormal];
[button setTitleColor:[UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]
forState:UIControlStateNormal];
button.titleLabel.font = [UIFont boldSystemFontOfSize:13];
button.tintColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
UIImage *icon = [UIImage systemImageNamed:icons[i]];
[button setImage:icon forState:UIControlStateNormal];
// Center icon above title
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
// Adjust spacing between image and text
CGFloat spacing = 6.0;
CGSize imageSize = button.imageView.frame.size;
CGSize titleSize = button.titleLabel.frame.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
imageSize.height + spacing, // move text below image
-imageSize.width, // center horizontally
0,
0
);
button.imageEdgeInsets = UIEdgeInsetsMake(
-titleSize.height - spacing / 2, // move image up
0,
0,
-titleSize.width
);
button.tag = i;
[button addTarget:self action:@selector(footerButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
[footerView addSubview:button];
// Divider line between buttons (except after last one)
if (i < titles.count - 1) {
UIView *divider = [[UIView alloc] initWithFrame:CGRectMake(
(i + 1) * buttonWidth - 0.5,
10,
1,
footerHeight - 20
)];
divider.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
divider.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[footerView addSubview:divider];
}
}
}
- (void)footerButtonTapped:(UIButton *)sender {
NSLog(@"🟢 Footer button tapped with tag: %ld", (long)sender.tag);
NSString *title = sender.titleLabel.text;
NSLog(@"Footer button tapped: %@", title);
switch (sender.tag) {
case 0:
// Make Appointment
NSLog(@"Make Appointment tapped");
break;
case 1: {
// Add Issue
AddIssueViewController *addIssueVC = [[AddIssueViewController alloc] init];
addIssueVC.modalPresentationStyle = UIModalPresentationFullScreen;
if (!addIssueVC) {
NSLog(@"❌ AddIssueViewController class not found!");
return;
}
[self presentViewController:addIssueVC animated:YES completion:nil];
break;
}
case 2:
// View Access Item
NSLog(@"View Access Item tapped");
break;
default:
break;
}
}
#pragma mark - Scrollable Content
- (void)setupScrollContent {
CGFloat topOffset = 220.0;
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, topOffset, self.view.bounds.size.width, self.view.bounds.size.height - topOffset)];
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:_scrollView];
_scrollView.clipsToBounds = NO;
_contentContainer.clipsToBounds = NO;
_contentContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.bounds.size.width, 800)];
_contentContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[_scrollView addSubview:_contentContainer];
CGFloat y = 20;
y = [self addSectionWithTitle:@"Project Update" text:@"12/10/2025\nAnnouncement Title" y:y];
y = [self addSectionWithTitle:@"Appointments" text:@"You have a joint inspection on 25 Oct 2025" y:y];
y = [self addSectionWithTitle:@"Issue Updates" text:@"Issue REF123 has been lodged." y:y];
_contentContainer.frame = CGRectMake(0, 0, _scrollView.bounds.size.width, y + 20);
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, CGRectGetMaxY(_contentContainer.frame));
}
- (CGFloat)addSectionWithTitle:(NSString *)title text:(NSString *)text y:(CGFloat)y {
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, y, self.view.bounds.size.width - 32, 22)];
titleLabel.text = title;
titleLabel.font = [UIFont boldSystemFontOfSize:18];
[_contentContainer addSubview:titleLabel];
y += 30;
UIView *card = [[UIView alloc] initWithFrame:CGRectMake(16, y, self.view.bounds.size.width - 32, 100)];
card.backgroundColor = [UIColor whiteColor];
card.layer.cornerRadius = 8;
card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
card.layer.shadowOpacity = 0.8;
card.layer.shadowOffset = CGSizeMake(0, 1);
[_contentContainer addSubview:card];
UILabel *body = [[UILabel alloc] initWithFrame:CGRectMake(12, 12, card.bounds.size.width - 24, 80)];
body.text = text;
body.numberOfLines = 0;
body.font = [UIFont systemFontOfSize:15];
[card addSubview:body];
return y + 120;
}
@end
//QmsPlugin.mm //QmsPlugin.mm
#import "QmsPlugin.h" #import "QmsPlugin.h"
#import "DashboardViewController.h"
@implementation QmsPluginFunc @implementation QmsPluginFunc
...@@ -16,14 +17,7 @@ ...@@ -16,14 +17,7 @@
@implementation QmsPluginUI @implementation QmsPluginUI
+ (UIViewController *)makeViewController { + (UIViewController *)makeViewController {
UIViewController *vc = [UIViewController new]; DashboardViewController *vc = [[DashboardViewController alloc] init];
vc.view.backgroundColor = [UIColor whiteColor];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(40, 100, 300, 40)];
label.text = @"UI from xcframework (no subclass)";
label.font = [UIFont boldSystemFontOfSize:22];
[vc.view addSubview:label];
return vc; return vc;
} }
......
...@@ -44,39 +44,42 @@ RCT_EXPORT_MODULE() ...@@ -44,39 +44,42 @@ RCT_EXPORT_MODULE()
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *vc = [QmsPluginUI makeViewController]; UIViewController *vc = [QmsPluginUI makeViewController];
NSLog(@"[QmsPlugin] created QmsPluginViewController: %@", vc); NSLog(@"[QmsPlugin] created Dashboard VC: %@", vc);
// Find topmost view controller UIWindow *keyWindow = UIApplication.sharedApplication.keyWindow;
UIWindow *keyWindow = nil; if (!keyWindow) {
for (UIWindowScene *scene in UIApplication.sharedApplication.connectedScenes) { for (UIWindowScene *scene in UIApplication.sharedApplication.connectedScenes) {
if (scene.activationState == UISceneActivationStateForegroundActive) { if (scene.activationState == UISceneActivationStateForegroundActive) {
keyWindow = scene.windows.firstObject; for (UIWindow *window in scene.windows) {
if (window.isKeyWindow) {
keyWindow = window;
break;
}
}
}
if (keyWindow) break; if (keyWindow) break;
} }
} }
if (keyWindow == nil) { if (!keyWindow) {
NSLog(@"[QmsPlugin] ERROR: keyWindow is nil"); NSLog(@"[QmsPlugin] ❌ ERROR: Could not find key window");
return; return;
} else {
NSLog(@"[QmsPlugin] Found keyWindow: %@", keyWindow);
} }
UIViewController *presentingVC = keyWindow.rootViewController; UIViewController *presentingVC = keyWindow.rootViewController;
NSLog(@"[QmsPlugin] rootViewController = %@", presentingVC);
while (presentingVC.presentedViewController) { while (presentingVC.presentedViewController) {
presentingVC = presentingVC.presentedViewController; presentingVC = presentingVC.presentedViewController;
} }
if (presentingVC) { if (!presentingVC) {
NSLog(@"[QmsPlugin] Presenting VC = %@", presentingVC); NSLog(@"[QmsPlugin] ❌ ERROR: No presenting VC found");
[presentingVC presentViewController:vc animated:YES completion:^{ return;
NSLog(@"[QmsPlugin] UI presented successfully");
}];
} else {
NSLog(@"[QmsPlugin] ERROR: No presenting view controller");
} }
NSLog(@"[QmsPlugin] Presenting Dashboard from %@", presentingVC);
[presentingVC presentViewController:vc animated:YES completion:^{
NSLog(@"[QmsPlugin] ✅ Dashboard UI presented successfully");
}];
}); });
} }
......
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