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
db23c5fb
Commit
db23c5fb
authored
Oct 10, 2025
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
native UI update
parent
579f896f
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
333 additions
and
185 deletions
+333
-185
Info.plist
...PluginFramework/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
DetailsViewController.mm
...work/QmsPluginFramework/AddIssue/DetailsViewController.mm
+131
-23
PlanViewController.mm
...amework/QmsPluginFramework/AddIssue/PlanViewController.mm
+74
-20
DashboardViewController.mm
...k/QmsPluginFramework/Dashboard/DashboardViewController.mm
+118
-132
Info.plist
ios/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
No files found.
framework/QmsPluginFramework/QmsPluginFramework.xcframework/Info.plist
View file @
db23c5fb
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
db23c5fb
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
db23c5fb
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/DetailsViewController.mm
View file @
db23c5fb
// DetailsViewController.mm
#import "DetailsViewController.h"
@interface AddIssueDetailsViewController ()
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UITextField *locationField;
@property (nonatomic, strong) UITextView *commentField;
@property (nonatomic, strong) UIButton *submitButton;
@property (nonatomic, strong) UIButton *resetButton;
@end
@implementation AddIssueDetailsViewController
...
...
@@ -13,34 +14,125 @@
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
[self setupForm];
// Create all views (don’t position them yet)
[self createHeader];
[self createForm];
}
- (void)setupHeader {
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat topInset = self.view.safeAreaInsets.top;
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, topInset, self.view.bounds.size.width, 48)];
header.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
header.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self.view addSubview:header];
CGFloat headerHeight = 48.0;
// Header layout
self.headerView.frame = CGRectMake(0, topInset, self.view.bounds.size.width, headerHeight);
// Title Label
UILabel *title = [self.headerView viewWithTag:101];
if (title) {
title.frame = CGRectMake(0, 8, self.headerView.bounds.size.width, 32);
}
// Scroll view layout (below header)
CGFloat scrollY = topInset + headerHeight;
self.scrollView.frame = CGRectMake(0, scrollY,
self.view.bounds.size.width,
self.view.bounds.size.height - scrollY);
// Adjust internal subviews (since width may have changed)
self.locationField.frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 40);
self.commentField.frame = CGRectMake(20, 140, self.view.bounds.size.width - 40, 100);
self.submitButton.frame = CGRectMake(20, 260, self.view.bounds.size.width - 40, 48);
}
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0, 8, header.bounds.size.width, 32)];
#pragma mark - Setup
- (void)createHeader {
// Header container
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
// Back button (SF Symbol)
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem];
backButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *backImage = [UIImage systemImageNamed:@"chevron.left"];
backImage = [backImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[backButton setImage:backImage forState:UIControlStateNormal];
backButton.tintColor = [UIColor whiteColor];
backButton.backgroundColor = [UIColor clearColor];
[backButton addTarget:self action:@selector(dismissSelf)
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:backButton];
// Title label
UILabel *title = [[UILabel alloc] init];
title.translatesAutoresizingMaskIntoConstraints = NO;
title.text = @"Add Issue Details";
title.textColor = UIColor.whiteColor;
title.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
title.textAlignment = NSTextAlignmentCenter;
[header addSubview:title];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
backButton.frame = CGRectMake(12, 8, 32, 32);
[backButton setImage:[UIImage imageNamed:@"back24"] forState:UIControlStateNormal];
[backButton addTarget:self action:@selector(dismissSelf) forControlEvents:UIControlEventTouchUpInside];
[header addSubview:backButton];
[self.headerView addSubview:title];
// ✅ Reset button (refresh icon)
self.resetButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.resetButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *refreshImage = [UIImage systemImageNamed:@"arrow.clockwise"];
refreshImage = [refreshImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self.resetButton setImage:refreshImage forState:UIControlStateNormal];
self.resetButton.tintColor = [UIColor whiteColor];
self.resetButton.backgroundColor = [UIColor clearColor];
[self.resetButton addTarget:self
action:@selector(handleReset)
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.resetButton];
// Status bar background (same color as header)
UIView *statusBarBackground = [[UIView alloc] init];
statusBarBackground.backgroundColor = self.headerView.backgroundColor;
statusBarBackground.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:statusBarBackground];
// Auto Layout
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
// 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],
// Back button
[backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:8],
[backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[backButton.widthAnchor constraintEqualToConstant:44],
[backButton.heightAnchor constraintEqualToConstant:44],
// Title centered
[title.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[title.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
// ✅ Reset button (right)
[self.resetButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-8],
[self.resetButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.resetButton.widthAnchor constraintEqualToConstant:44],
[self.resetButton.heightAnchor constraintEqualToConstant:44],
// Status bar color fill
[statusBarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[statusBarBackground.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[statusBarBackground.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[statusBarBackground.bottomAnchor constraintEqualToAnchor:safe.topAnchor],
]];
}
- (void)setupForm {
CGFloat topInset = self.view.safeAreaInsets.top + 48;
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, topInset, self.view.bounds.size.width, self.view.bounds.size.height - topInset)];
- (void)createForm {
self.scrollView = [[UIScrollView alloc] init];
[self.view addSubview:self.scrollView];
UILabel *locationLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 200, 20)];
...
...
@@ -48,7 +140,7 @@
locationLabel.font = [UIFont boldSystemFontOfSize:16];
[self.scrollView addSubview:locationLabel];
self.locationField = [[UITextField alloc] initWithFrame:CGRect
Make(20, 50, self.view.bounds.size.width - 40, 40)
];
self.locationField = [[UITextField alloc] initWithFrame:CGRect
Zero
];
self.locationField.borderStyle = UITextBorderStyleRoundedRect;
[self.scrollView addSubview:self.locationField];
...
...
@@ -57,14 +149,14 @@
commentLabel.font = [UIFont boldSystemFontOfSize:16];
[self.scrollView addSubview:commentLabel];
self.commentField = [[UITextView alloc] initWithFrame:CGRect
Make(20, 140, self.view.bounds.size.width - 40, 100)
];
self.commentField = [[UITextView alloc] initWithFrame:CGRect
Zero
];
self.commentField.layer.borderColor = [UIColor lightGrayColor].CGColor;
self.commentField.layer.borderWidth = 1.0;
self.commentField.layer.cornerRadius = 8;
[self.scrollView addSubview:self.commentField];
self.submitButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.submitButton.frame = CGRect
Make(20, 260, self.view.bounds.size.width - 40, 48)
;
self.submitButton.frame = CGRect
Zero
;
self.submitButton.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
[self.submitButton setTitle:@"Submit" forState:UIControlStateNormal];
[self.submitButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
...
...
@@ -73,6 +165,23 @@
[self.scrollView addSubview:self.submitButton];
}
- (void)handleReset {
NSLog(@"🔄 Reset button tapped");
self.locationField.text = @"";
self.commentField.text = @"";
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Fields Cleared"
message:@"All inputs have been reset."
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark - Actions
- (void)dismissSelf {
[self dismissViewControllerAnimated:YES completion:nil];
}
...
...
@@ -86,4 +195,3 @@
}
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/PlanViewController.mm
View file @
db23c5fb
...
...
@@ -29,55 +29,104 @@
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// Get safe area + bounds
CGFloat topInset = self.view.safeAreaInsets.top;
CGFloat headerHeight = 48.0;
// Layout header
self.headerView.frame = CGRectMake(0, topInset, self.view.bounds.size.width, headerHeight);
// Layout title
self.titleLabel.frame = CGRectMake(0, 8, self.headerView.bounds.size.width, 32);
self.helpButton.frame = CGRectMake(self.headerView.bounds.size.width - 44, 8, 32, 32);
// 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);
// 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.scrollView.frame = CGRectMake(0, scrollY, self.view.bounds.size.width, self.view.bounds.size.height - scrollY);
self.planImageView.frame = self.scrollView.bounds;
// Make absolutely sure header is above scroll view
[self.view bringSubviewToFront:self.headerView];
}
#pragma mark - UI Creation
- (void)createHeader {
// 🟩 Status bar background view
UIView *statusBarBackground = [[UIView alloc] init];
statusBarBackground.backgroundColor = [UIColor colorWithRed:0/255.0
green:109/255.0
blue:141/255.0
alpha:1];
statusBarBackground.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:statusBarBackground];
// 🟦 Header background view
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
self.headerView.backgroundColor = statusBarBackground.backgroundColor;
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
// Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.backButton setImage:[UIImage imageNamed:@"back24"] forState:UIControlStateNormal];
[self.backButton addTarget:self action:@selector(handleBack) forControlEvents:UIControlEventTouchUpInside];
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
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)
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.backButton];
// Title
// 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
self.helpButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.helpButton setImage:[UIImage imageNamed:@"btn_white_help_3x"] forState:UIControlStateNormal];
[self.helpButton addTarget:self action:@selector(showTutorial) forControlEvents:UIControlEventTouchUpInside];
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];
// ✅ Constraints
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
// Status bar background
[statusBarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[statusBarBackground.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[statusBarBackground.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[statusBarBackground.bottomAnchor constraintEqualToAnchor:safe.topAnchor],
// Header pinned below safe area
[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],
// Back button
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:8],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[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.widthAnchor constraintEqualToConstant:44],
[self.helpButton.heightAnchor constraintEqualToConstant:44],
// Title centered
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
]];
}
- (void)createScrollView {
...
...
@@ -94,7 +143,7 @@
UIImage *testImage = [UIImage imageNamed:@"image_placeholder"];
if (!testImage) {
NSLog(@"❌ image_placeholder not found in bundle!");
self.planImageView.backgroundColor = [UIColor
systemTeal
Color];
self.planImageView.backgroundColor = [UIColor
white
Color];
// 👉 Temporary test button
UIButton *testButton = [UIButton buttonWithType:UIButtonTypeSystem];
...
...
@@ -148,4 +197,9 @@
return self.planImageView;
}
#pragma mark - Status Bar Style
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent; // ✅ White text/icons
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.mm
View file @
db23c5fb
...
...
@@ -7,16 +7,34 @@
DashboardHeaderView *_headerView;
UIScrollView *_scrollView;
UIView *_contentContainer;
NSMutableDictionary *_sectionViews;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0]; // #F2F2F2
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];
_sectionViews = [NSMutableDictionary dictionary];
[self setupHeader];
[self setupScrollContent];
[self setupFooter];
[self fetchDashboardData];
}
#pragma mark - Layout
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIView *footerView = self.view.subviews.lastObject;
CGFloat footerHeight = 80.0;
CGFloat bottomInset = self.view.safeAreaInsets.bottom;
footerView.frame = CGRectMake(
0,
self.view.bounds.size.height - footerHeight - bottomInset,
self.view.bounds.size.width,
footerHeight + bottomInset
);
}
#pragma mark - Header
...
...
@@ -29,73 +47,47 @@
backgroundImage:[UIImage imageNamed:@"header_bg"]
overlayImage:[UIImage imageNamed:@"overlay"]];
[self.view addSubview:_headerView];
// Create Back Button
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem];
backButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *backImage = [UIImage systemImageNamed:@"chevron.left"];
backImage = [backImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage *backImage = [[UIImage systemImageNamed:@"chevron.left"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[backButton setImage:backImage forState:UIControlStateNormal];
backButton.tintColor = [UIColor whiteColor];
backButton.layer.cornerRadius = 18;
backButton.backgroundColor = [UIColor clearColor];
backButton.clipsToBounds = YES;
[backButton addTarget:self
action:@selector(handleBackButtonTapped)
forControlEvents:UIControlEventTouchUpInside];
[backButton addTarget:self action:@selector(handleBackButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
// Create Menu Button
UIButton *menuButton = [UIButton buttonWithType:UIButtonTypeSystem];
menuButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *menuImage = [UIImage systemImageNamed:@"line.3.horizontal"];
menuImage = [menuImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage *menuImage = [[UIImage systemImageNamed:@"line.3.horizontal"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[menuButton setImage:menuImage forState:UIControlStateNormal];
menuButton.tintColor = [UIColor whiteColor];
menuButton.backgroundColor = [UIColor clearColor];
menuButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 8, 8);
[menuButton addTarget:self
action:@selector(handleMenuButtonTapped)
forControlEvents:UIControlEventTouchUpInside];
[menuButton addTarget:self action:@selector(handleMenuButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:menuButton];
// ✅ Use Auto Layout constraints to respect safe area
[NSLayoutConstraint activateConstraints:@[
// Back button - top left
[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],
// Menu button - top right
[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],
]];
[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 {
NSLog(@"🔙 Back button tapped
– attempting to close DashboardViewController
");
NSLog(@"🔙 Back button tapped");
if (self.presentingViewController) {
[self dismissViewControllerAnimated:YES completion:nil];
} else if (self.navigationController) {
[self.navigationController popViewControllerAnimated:YES];
} else {
NSLog(@"⚠️ No parent VC found to close!");
}
}
- (void)handleMenuButtonTapped {
NSLog(@"🍔 Menu button tapped
– (TODO: open side menu or modal)
");
NSLog(@"🍔 Menu button tapped");
}
#pragma mark - Footer
...
...
@@ -116,145 +108,139 @@
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;
NSArray *icons = @[ @"calendar", @"plus.circle", @"list.bullet" ];
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,
visibleButton
Height);
button.frame = CGRectMake(i * buttonWidth, 0, buttonWidth,
footer
Height);
[button setTitle:titles[i] forState:UIControlStateNormal];
[button setTitleColor:[UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]
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];
[button setImage:[UIImage systemImageNamed:icons[i]] forState:UIControlStateNormal];
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.titleEdgeInsets = UIEdgeInsetsMake(imageSize.height + spacing, -imageSize.width, 0, 0);
button.imageEdgeInsets = UIEdgeInsetsMake(-titleSize.height - spacing / 2, 0, 0, -titleSize.width);
button.tag = i;
[button addTarget:self action:@selector(footerButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
[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
)];
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
PlanViewController *planVC = [[PlanViewController alloc] init];
planVC.modalPresentationStyle = UIModalPresentationFullScreen;
if (!planVC) {
NSLog(@"❌ PlanViewController class not found!");
return;
}
[self presentViewController:planVC animated:YES completion:nil];
break;
}
case 2:
// View Access Item
NSLog(@"View Access Item tapped");
break;
default:
break;
}
}
#pragma mark - Scroll
able
Content
#pragma mark - Scroll 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;
_scrollView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_scrollView];
_scrollView.clipsToBounds = NO;
_contentContainer.clipsToBounds = NO;
_contentContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.bounds.size.width, 800)];
_contentContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.bounds.size.width, 0)];
_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));
// Add 3 fixed section titles, store them for later population
NSArray *sectionNames = @[ @"Project Update", @"Appointments", @"Issue Updates" ];
for (NSString *name in sectionNames) {
UILabel *header = [[UILabel alloc] initWithFrame:CGRectMake(16, y, self.view.bounds.size.width - 32, 24)];
header.text = name;
header.font = [UIFont boldSystemFontOfSize:18];
[_contentContainer addSubview:header];
y += 30;
UIView *sectionContainer = [[UIView alloc] initWithFrame:CGRectMake(0, y, self.view.bounds.size.width, 0)];
[_contentContainer addSubview:sectionContainer];
_sectionViews[name] = sectionContainer;
y += 20; // spacing before next section
}
_contentContainer.frame = CGRectMake(0, 0, _scrollView.bounds.size.width, y);
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, y);
}
#pragma mark - Networking
- (void)fetchDashboardData {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/posts?_limit=9"];
__weak typeof(self) weakSelf = self;
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) return;
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf populateSectionsWithData:json];
});
}] resume];
}
- (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;
- (void)populateSectionsWithData:(NSArray *)data {
NSArray *sectionKeys = @[ @"Project Update", @"Appointments", @"Issue Updates" ];
int itemsPerSection = (int)ceil(data.count / 3.0);
CGFloat sectionBottomY = 0;
for (int i = 0; i < sectionKeys.count; i++) {
NSString *key = sectionKeys[i];
UIView *sectionContainer = _sectionViews[key];
CGFloat y = 0;
NSArray *subset = [data subarrayWithRange:NSMakeRange(i * itemsPerSection,
MIN(itemsPerSection, data.count - i * itemsPerSection))];
for (NSDictionary *item in subset) {
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);
UILabel *body = [[UILabel alloc] initWithFrame:CGRectMake(12, 12, card.bounds.size.width - 24, 80)];
body.text = item[@"title"];
body.numberOfLines = 2;
body.font = [UIFont systemFontOfSize:15];
[card addSubview:body];
[sectionContainer addSubview:card];
y += 120;
}
sectionContainer.frame = CGRectMake(0, sectionContainer.frame.origin.y, self.view.bounds.size.width, y);
sectionBottomY = CGRectGetMaxY(sectionContainer.frame) + 20;
}
_contentContainer.frame = CGRectMake(0, 0, _scrollView.bounds.size.width, sectionBottomY);
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, sectionBottomY);
}
@end
ios/QmsPluginFramework.xcframework/Info.plist
View file @
db23c5fb
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
db23c5fb
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
db23c5fb
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