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
d5fc7ec0
Commit
d5fc7ec0
authored
Dec 12, 2025
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code update
parent
01266f51
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
797 additions
and
8 deletions
+797
-8
project.pbxproj
example/ios/example.xcodeproj/project.pbxproj
+0
-0
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
DashboardViewController.h
...rk/QmsPluginFramework/Dashboard/DashboardViewController.h
+6
-0
DashboardViewController.mm
...k/QmsPluginFramework/Dashboard/DashboardViewController.mm
+64
-5
DrawerController.h
...Framework/QmsPluginFramework/Dashboard/DrawerController.h
+32
-0
DrawerController.mm
...ramework/QmsPluginFramework/Dashboard/DrawerController.mm
+230
-0
DrawerViewController.h
...ework/QmsPluginFramework/Dashboard/DrawerViewController.h
+16
-0
DrawerViewController.mm
...work/QmsPluginFramework/Dashboard/DrawerViewController.mm
+229
-0
QmsPlugin.mm
framework/QmsPluginFramework/QmsPluginFramework/QmsPlugin.mm
+29
-3
SyncScreenViewController.h
...mework/QmsPluginFramework/Sync/SyncScreenViewController.h
+7
-0
SyncScreenViewController.m
...mework/QmsPluginFramework/Sync/SyncScreenViewController.m
+183
-0
QmsDashboardViewManager.mm
ios/QmsPlugin/QmsDashboardViewManager.mm
+1
-0
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
No files found.
example/ios/example.xcodeproj/project.pbxproj
View file @
d5fc7ec0
This diff is collapsed.
Click to expand it.
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
d5fc7ec0
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
d5fc7ec0
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.h
View file @
d5fc7ec0
// DashboardViewController.h
#import <UIKit/UIKit.h>
#import "DrawerController.h"
NS_ASSUME_NONNULL_BEGIN
...
...
@@ -8,6 +9,11 @@ NS_ASSUME_NONNULL_BEGIN
@property
(
nonatomic
,
copy
)
NSString
*
ClientID
;
@property
(
nonatomic
,
copy
)
NSString
*
ClientCode
;
@property
(
nonatomic
,
copy
)
NSString
*
user_token
;
@property
(
nonatomic
,
weak
)
DrawerController
*
drawerController
;
-
(
instancetype
)
initWithClientID
:(
NSString
*
)
clientID
clientCode
:(
NSString
*
)
clientCode
userToken
:(
NSString
*
)
userToken
;
@end
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.mm
View file @
d5fc7ec0
...
...
@@ -49,6 +49,18 @@
CGFloat _currentY;
}
- (instancetype)initWithClientID:(NSString *)clientID
clientCode:(NSString *)clientCode
userToken:(NSString *)userToken {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_ClientID = [clientID copy];
_ClientCode = [clientCode copy];
_user_token = [userToken copy];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];
...
...
@@ -61,8 +73,9 @@
self.projectCode = @"PTD197656";
self.projectName = @"Ara E`Residence Dev";
[self
refreshDashboardContent
];
[self
checkAndRefreshAPIs
];
NSLog(@"in viewDidLoad ClientID: %@, ClientCode: %@, user_token: %@", self.ClientID, self.ClientCode, self.user_token);
NSLog(@"dashboard.drawerController = %@", self.drawerController);
}
- (void)viewWillAppear:(BOOL)animated {
...
...
@@ -73,6 +86,16 @@
NSLog(@"in viewWillAppear ClientID: %@, ClientCode: %@, user_token: %@", self.ClientID, self.ClientCode, self.user_token);
}
- (void)checkAndRefreshAPIs {
// Only trigger API calls when all props are set and not the placeholder
if (![_ClientID isEqualToString:@"clientID_loading"] &&
![_ClientCode isEqualToString:@"clientCode_loading"] &&
![_user_token isEqualToString:@"userToken_loading"]) {
NSLog(@"in checkAndRefreshApis ClientID: %@, ClientCode: %@, user_token: %@", self.ClientID, self.ClientCode, self.user_token);
[self refreshDashboardContent]; // Your API call method
}
}
#pragma mark - Refresh Logic
- (void)refreshDashboardContent {
NSLog(@"🔁 Refreshing dashboard content...");
...
...
@@ -204,6 +227,21 @@
[self.projectNameLabel.centerXAnchor constraintEqualToAnchor:headerBar.centerXAnchor],
[self.projectNameLabel.centerYAnchor constraintEqualToAnchor:headerBar.centerYAnchor]
]];
// --- Menu Button (Top Right) ---
UIButton *menuButton = [UIButton buttonWithType:UIButtonTypeCustom];
menuButton.translatesAutoresizingMaskIntoConstraints = NO;
[menuButton setImage:[UIImage systemImageNamed:@"line.horizontal.3"] forState:UIControlStateNormal];
menuButton.tintColor = UIColor.whiteColor;
[menuButton addTarget:self action:@selector(handleMenuButtonTapped) forControlEvents:UIControlEventTouchUpInside];
[headerBar addSubview:menuButton];
[NSLayoutConstraint activateConstraints:@[
[menuButton.trailingAnchor constraintEqualToAnchor:headerBar.trailingAnchor constant:-16],
[menuButton.centerYAnchor constraintEqualToAnchor:headerBar.centerYAnchor],
[menuButton.widthAnchor constraintEqualToConstant:26],
[menuButton.heightAnchor constraintEqualToConstant:26],
]];
// -----------------------
// Unit name bottom-left
...
...
@@ -265,10 +303,6 @@
}
}
- (void)handleMenuButtonTapped {
NSLog(@"🍔 Menu button tapped");
}
#pragma mark - Footer
- (void)setupFooter {
CGFloat footerHeight = 80.0;
...
...
@@ -1206,4 +1240,29 @@
self.spinner = nil;
}
- (void)handleMenuButtonTapped {
NSLog(@"🍔 Menu button tapped");
if (self.drawerController) {
[self.drawerController toggleDrawer];
} else {
NSLog(@"⚠️ drawerController not set on DashboardViewController");
}
}
#pragma mark - prop setter
- (void)setClientID:(NSString *)ClientID {
_ClientID = [ClientID copy];
[self checkAndRefreshAPIs];
}
- (void)setClientCode:(NSString *)ClientCode {
_ClientCode = [ClientCode copy];
[self checkAndRefreshAPIs];
}
- (void)setUser_token:(NSString *)user_token {
_user_token = [user_token copy];
[self checkAndRefreshAPIs];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DrawerController.h
0 → 100644
View file @
d5fc7ec0
// DrawerController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
extern
NSString
*
const
DrawerDidSelectItemNotification
;
// posted when an item is tapped
@interface
DrawerController
:
UIViewController
@property
(
nonatomic
,
strong
,
readonly
)
UIViewController
*
mainViewController
;
@property
(
nonatomic
,
strong
,
readonly
)
UIViewController
*
drawerViewController
;
// ✅ New initializer: pass drawer + client props directly
-
(
instancetype
)
initWithDrawerViewController
:(
UIViewController
*
)
drawer
clientID
:(
NSString
*
)
clientID
clientCode
:(
NSString
*
)
clientCode
userToken
:(
NSString
*
)
user_token
;
// Drawer actions
-
(
void
)
openDrawer
;
-
(
void
)
closeDrawer
;
-
(
void
)
toggleDrawer
;
-
(
BOOL
)
isDrawerOpen
;
// Optional: keep setters if props can change later
@property
(
nonatomic
,
copy
)
NSString
*
ClientID
;
@property
(
nonatomic
,
copy
)
NSString
*
ClientCode
;
@property
(
nonatomic
,
copy
)
NSString
*
user_token
;
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DrawerController.mm
0 → 100644
View file @
d5fc7ec0
// DrawerController.m
#import "DrawerController.h"
#import "DashboardViewController.h"
NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotification";
@interface DrawerController () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) DashboardViewController *mainVC;
@property (nonatomic, strong) UIViewController *drawerVC;
@property (nonatomic, strong) UIView *overlayView;
@property (nonatomic, assign) BOOL drawerOpen;
@property (nonatomic, assign) CGFloat drawerWidth;
@property (nonatomic, strong) UIPanGestureRecognizer *panGR;
@property (nonatomic, strong) NSLayoutConstraint *drawerLeadingConstraint;
@end
@implementation DrawerController
#pragma mark - Initializer
- (instancetype)initWithDrawerViewController:(UIViewController *)drawer
clientID:(NSString *)clientID
clientCode:(NSString *)clientCode
userToken:(NSString *)user_token {
self = [super initWithNibName:nil bundle:nil];
if (!self) return nil;
// 1️⃣ Initialize DashboardViewController with props
_mainVC = [[DashboardViewController alloc] initWithClientID:clientID
clientCode:clientCode
userToken:user_token];
// 2️⃣ Set back-reference to drawerController
_mainVC.drawerController = self;
// 3️⃣ Save props locally
_ClientID = [clientID copy];
_ClientCode = [clientCode copy];
_user_token = [user_token copy];
// 4️⃣ Set drawer VC and drawer width
_drawerVC = drawer;
_drawerWidth = MIN([UIScreen mainScreen].bounds.size.width * 0.78, 360);
return self;
}
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self setupDrawer];
[self setupOverlay];
[self setupMainVC];
[self setupPanGesture];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(menuItemSelected:)
name:DrawerDidSelectItemNotification
object:nil];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Getters
- (UIViewController *)mainViewController {
return _mainVC;
}
- (UIViewController *)drawerViewController {
return _drawerVC;
}
#pragma mark - Setup UI
- (void)setupDrawer {
[self addChildViewController:self.drawerVC];
self.drawerVC.view.translatesAutoresizingMaskIntoConstraints = NO;
self.drawerVC.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.drawerVC.view];
[self.drawerVC didMoveToParentViewController:self];
self.drawerLeadingConstraint =
[self.drawerVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:-self.drawerWidth];
[self.drawerVC.view.widthAnchor constraintEqualToConstant:self.drawerWidth].active = YES;
[self.drawerVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[self.drawerVC.view.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
self.drawerLeadingConstraint.active = YES;
}
- (void)setupOverlay {
// Overlay only covers the mainVC, not the drawer
self.overlayView = [[UIView alloc] initWithFrame:self.mainVC.view.frame];
self.overlayView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
self.overlayView.alpha = 0.0;
self.overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
// Tap gesture to close drawer
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeDrawer)];
[self.overlayView addGestureRecognizer:tap];
// Add overlay **below** the drawer so it doesn't block menu interactions
[self.view insertSubview:self.overlayView belowSubview:self.drawerVC.view];
}
- (void)setupMainVC {
[self addChildViewController:self.mainVC];
self.mainVC.view.frame = self.view.bounds;
self.mainVC.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.mainVC.view];
[self.mainVC didMoveToParentViewController:self];
}
- (void)setupPanGesture {
self.panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
self.panGR.delegate = self;
[self.mainVC.view addGestureRecognizer:self.panGR];
}
#pragma mark - Drawer Actions
- (void)openDrawer {
// Make sure overlay and drawer are on top
[self.view bringSubviewToFront:self.overlayView];
[self.view bringSubviewToFront:self.drawerVC.view];
self.drawerLeadingConstraint.constant = 0;
[UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded];
self.overlayView.alpha = 1.0;
}];
self.drawerOpen = YES;
}
- (void)closeDrawer {
self.drawerLeadingConstraint.constant = -self.drawerWidth;
[UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded];
self.overlayView.alpha = 0.0;
}];
self.drawerOpen = NO;
}
- (void)toggleDrawer {
if (self.drawerOpen) [self closeDrawer];
else [self openDrawer];
}
- (BOOL)isDrawerOpen {
return self.drawerOpen;
}
#pragma mark - Pan Gesture
- (void)handlePan:(UIPanGestureRecognizer *)pan {
CGPoint translation = [pan translationInView:self.view];
CGFloat x = translation.x;
static CGFloat startX;
if (pan.state == UIGestureRecognizerStateBegan) {
startX = self.mainVC.view.transform.tx;
} else if (pan.state == UIGestureRecognizerStateChanged) {
CGFloat newTx = startX + x;
newTx = MAX(0, newTx);
newTx = MIN(self.drawerWidth, newTx);
CGFloat progress = newTx / self.drawerWidth;
self.mainVC.view.transform = CGAffineTransformMakeTranslation(newTx, 0);
self.drawerLeadingConstraint.constant = -self.drawerWidth + newTx;
[self.view layoutIfNeeded];
self.overlayView.alpha = progress;
} else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
CGFloat velocityX = [pan velocityInView:self.view].x;
CGFloat currentTx = self.mainVC.view.transform.tx;
BOOL shouldOpen = NO;
if (fabs(velocityX) > 400) {
shouldOpen = (velocityX > 0);
} else {
shouldOpen = currentTx > (self.drawerWidth * 0.45);
}
if (shouldOpen) [self openDrawer];
else [self closeDrawer];
}
}
#pragma mark - Notification
- (void)menuItemSelected:(NSNotification *)note {
[self closeDrawer];
}
#pragma mark - Gesture Delegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer == self.panGR) {
CGPoint v = [self.panGR velocityInView:self.view];
return fabs(v.x) > fabs(v.y);
}
return YES;
}
#pragma mark - Prop Setters
- (void)setClientID:(NSString *)ClientID {
_ClientID = [ClientID copy];
if ([self.mainVC respondsToSelector:NSSelectorFromString(@"setClientID:")]) {
[self.mainVC setValue:_ClientID forKey:@"ClientID"];
}
}
- (void)setClientCode:(NSString *)ClientCode {
_ClientCode = [ClientCode copy];
if ([self.mainVC respondsToSelector:NSSelectorFromString(@"setClientCode:")]) {
[self.mainVC setValue:_ClientCode forKey:@"ClientCode"];
}
}
- (void)setUser_token:(NSString *)user_token {
_user_token = [user_token copy];
if ([self.mainVC respondsToSelector:NSSelectorFromString(@"setUser_token:")]) {
[self.mainVC setValue:_user_token forKey:@"user_token"];
}
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DrawerViewController.h
0 → 100644
View file @
d5fc7ec0
// DrawerViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
DrawerViewController
:
UIViewController
// Data to populate (you can set these from GLOBALS or app state)
@property
(
nonatomic
,
strong
)
NSString
*
profileName
;
@property
(
nonatomic
,
strong
)
NSString
*
profileEmail
;
@property
(
nonatomic
,
strong
)
NSURL
*
profileImageURL
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSDictionary
*>
*
menuItems
;
// array of { @"title":..., @"action":... }
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DrawerViewController.mm
0 → 100644
View file @
d5fc7ec0
// DrawerViewController.m
#import "DrawerViewController.h"
#import "DrawerController.h"
#import "SyncScreenViewController.h"
@interface DrawerViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UIImageView *avatarView;
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UILabel *emailLabel;
@property (nonatomic, strong) UITableView *table;
@property (nonatomic, strong) UIView *headerContainer;
@end
@implementation DrawerViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithRed:0.02 green:0.36 blue:0.47 alpha:1.0]; // #035E79-ish
[self buildUI];
[self loadDefaultsIfNeeded];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleDrawerAction:)
name:DrawerDidSelectItemNotification
object:nil];
}
- (void)buildUI {
self.view.backgroundColor = [UIColor colorWithRed:0.02 green:0.36 blue:0.47 alpha:1.0];
CGFloat topHeight = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) ? 180 : 120;
// HEADER CONTAINER
self.headerContainer = [[UIView alloc] init];
self.headerContainer.translatesAutoresizingMaskIntoConstraints = NO;
self.headerContainer.backgroundColor = [UIColor colorWithRed:0 green:0.42 blue:0.55 alpha:1.0];
[self.view addSubview:self.headerContainer];
[NSLayoutConstraint activateConstraints:@[
[self.headerContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerContainer.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.headerContainer.heightAnchor constraintEqualToConstant:topHeight],
]];
// TOUCHABLE HEADER
UIButton *profileTap = [UIButton buttonWithType:UIButtonTypeCustom];
profileTap.translatesAutoresizingMaskIntoConstraints = NO;
[profileTap addTarget:self action:@selector(profileTapped) forControlEvents:UIControlEventTouchUpInside];
[self.headerContainer addSubview:profileTap];
[NSLayoutConstraint activateConstraints:@[
[profileTap.leadingAnchor constraintEqualToAnchor:self.headerContainer.leadingAnchor],
[profileTap.trailingAnchor constraintEqualToAnchor:self.headerContainer.trailingAnchor],
[profileTap.topAnchor constraintEqualToAnchor:self.headerContainer.topAnchor],
[profileTap.bottomAnchor constraintEqualToAnchor:self.headerContainer.bottomAnchor],
]];
// AVATAR
CGFloat avatarSize = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) ? 100 : 50;
self.avatarView = [[UIImageView alloc] init];
self.avatarView.translatesAutoresizingMaskIntoConstraints = NO;
self.avatarView.layer.cornerRadius = avatarSize / 2.0;
self.avatarView.clipsToBounds = YES;
self.avatarView.layer.borderColor = [UIColor whiteColor].CGColor;
self.avatarView.layer.borderWidth = 1.0;
self.avatarView.contentMode = UIViewContentModeScaleAspectFill;
[self.headerContainer addSubview:self.avatarView];
[NSLayoutConstraint activateConstraints:@[
[self.avatarView.leadingAnchor constraintEqualToAnchor:self.headerContainer.leadingAnchor constant:18],
[self.avatarView.centerYAnchor constraintEqualToAnchor:self.headerContainer.centerYAnchor],
[self.avatarView.widthAnchor constraintEqualToConstant:avatarSize],
[self.avatarView.heightAnchor constraintEqualToConstant:avatarSize],
]];
// NAME LABEL
self.nameLabel = [[UILabel alloc] init];
self.nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.nameLabel.textColor = UIColor.whiteColor;
self.nameLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular];
self.nameLabel.numberOfLines = 2;
[self.headerContainer addSubview:self.nameLabel];
// EMAIL LABEL
self.emailLabel = [[UILabel alloc] init];
self.emailLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.emailLabel.textColor = UIColor.whiteColor;
self.emailLabel.font = [UIFont systemFontOfSize:14];
[self.headerContainer addSubview:self.emailLabel];
[NSLayoutConstraint activateConstraints:@[
[self.nameLabel.leadingAnchor constraintEqualToAnchor:self.avatarView.trailingAnchor constant:16],
[self.nameLabel.trailingAnchor constraintEqualToAnchor:self.headerContainer.trailingAnchor constant:-18],
[self.nameLabel.bottomAnchor constraintEqualToAnchor:self.headerContainer.centerYAnchor constant:-4],
[self.emailLabel.leadingAnchor constraintEqualToAnchor:self.nameLabel.leadingAnchor],
[self.emailLabel.trailingAnchor constraintEqualToAnchor:self.nameLabel.trailingAnchor],
[self.emailLabel.topAnchor constraintEqualToAnchor:self.nameLabel.bottomAnchor constant:4],
]];
// MENU TABLE
self.table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
self.table.translatesAutoresizingMaskIntoConstraints = NO;
self.table.dataSource = self;
self.table.delegate = self;
self.table.backgroundColor = UIColor.clearColor;
self.table.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:self.table];
[NSLayoutConstraint activateConstraints:@[
[self.table.topAnchor constraintEqualToAnchor:self.headerContainer.bottomAnchor],
[self.table.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.table.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.table.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
]];
}
- (void)loadDefaultsIfNeeded {
if (!self.profileName) self.profileName = @"Guest User";
if (!self.profileEmail) self.profileEmail = @"guest@example.com";
if (!self.profileImageURL) self.profileImageURL = nil;
self.nameLabel.text = self.profileName;
self.emailLabel.text = self.profileEmail;
if (self.profileImageURL) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *d = [NSData dataWithContentsOfURL:self.profileImageURL];
UIImage *img = d ? [UIImage imageWithData:d] : [UIImage imageNamed:@"small_placeholder"];
dispatch_async(dispatch_get_main_queue(), ^{
self.avatarView.image = img;
});
});
} else {
self.avatarView.image = [UIImage imageNamed:@"small_placeholder"];
}
if (!self.menuItems) {
self.menuItems = @[
@{@"title": @"Project List", @"action": @"projectList"},
@{@"title": @"Notification", @"action": @"notification"},
@{@"title": @"Announcement", @"action": @"announcement"},
@{@"title": @"Help", @"action": @"help"},
@{@"title": @"Sync", @"action": @"sync"},
@{@"title": @"Logout", @"action": @"logout"}
];
}
[self.table reloadData];
}
#pragma mark - Profile tap
- (void)profileTapped {
// Post a notification to navigate
[[NSNotificationCenter defaultCenter] postNotificationName:DrawerDidSelectItemNotification object:nil userInfo:@{@"action": @"profile"}];
}
#pragma mark - Table datasource/delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.menuItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellId = @"drawerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont systemFontOfSize:16];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSDictionary *item = self.menuItems[indexPath.row];
cell.textLabel.text = item[@"title"] ?: @"";
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 56; }
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *item = self.menuItems[indexPath.row];
NSString *action = item[@"action"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"DrawerDidSelectItemNotification"
object:action];
}
- (void)handleDrawerAction:(NSNotification *)notification {
NSString *action = notification.object;
if ([action isEqualToString:@"projectList"]) {
// [self openProjectList];
NSLog(@"navigating to Project List");
}
else if ([action isEqualToString:@"notification"]) {
// [self openNotification];
NSLog(@"navigating to Notification");
}
else if ([action isEqualToString:@"announcement"]) {
// [self openAnnouncement];
NSLog(@"navigating to Announcement");
}
else if ([action isEqualToString:@"help"]) {
// [self openHelp];
NSLog(@"navigating to Help");
}
else if ([action isEqualToString:@"sync"]) {
NSLog(@"navigating to Sync");
SyncScreenViewController *nextVC = [[SyncScreenViewController alloc] init];
nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:nextVC animated:YES completion:nil];
}
else if ([action isEqualToString:@"logout"]) {
// [self performLogout];
NSLog(@"navigating to Logout");
}
}
@end
framework/QmsPluginFramework/QmsPluginFramework/QmsPlugin.mm
View file @
d5fc7ec0
//QmsPlugin.mm
//
QmsPlugin.mm
#import "QmsPlugin.h"
#import "DashboardViewController.h"
#import "DrawerViewController.h"
#import "DrawerController.h"
@implementation QmsPluginUI
+ (UIViewController *)makeViewController {
DashboardViewController *vc = [[DashboardViewController alloc] init];
return vc;
// 1. Create main dashboard screen (props will be set via DrawerController)
DrawerViewController *drawer = [[DrawerViewController alloc] init];
drawer.profileName = @"placeholder";
drawer.profileEmail = @"placeholder";
// 2. Set client props (replace with actual values from your globals or RN)
NSString *clientID = @"clientID_loading";
NSString *clientCode = @"clientCode_loading";
NSString *userToken = @"userToken_loading";
// 3. Create DrawerController with drawer + props
DrawerController *drawerController =
[[DrawerController alloc] initWithDrawerViewController:drawer
clientID:clientID
clientCode:clientCode
userToken:userToken];
// 4. Allow dashboard to call openDrawer() via drawerController.mainViewController
if ([drawerController.mainViewController isKindOfClass:[DashboardViewController class]]) {
((DashboardViewController *)drawerController.mainViewController).drawerController = drawerController;
}
NSLog(@"drawerController.mainViewController = %@", drawerController.mainViewController);
return drawerController;
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Sync/SyncScreenViewController.h
0 → 100644
View file @
d5fc7ec0
// SyncViewController.h
#import <UIKit/UIKit.h>
@interface
SyncScreenViewController
:
UIViewController
@end
framework/QmsPluginFramework/QmsPluginFramework/Sync/SyncScreenViewController.m
0 → 100644
View file @
d5fc7ec0
// SyncViewController.m
#import "SyncScreenViewController.h"
@interface
SyncScreenViewController
()
@property
(
nonatomic
,
strong
)
UIView
*
headerView
;
@property
(
nonatomic
,
strong
)
UIButton
*
backButton
;
@property
(
nonatomic
,
strong
)
UILabel
*
titleLabel
;
@property
(
nonatomic
,
strong
)
UILabel
*
lastUpdatedLabel
;
@property
(
nonatomic
,
strong
)
UIStackView
*
cardStack
;
@property
(
nonatomic
,
strong
)
UIView
*
offlineUnitCard
;
@property
(
nonatomic
,
strong
)
UIView
*
pendingItemsCard
;
@property
(
nonatomic
,
strong
)
UIView
*
historyCard
;
@property
(
nonatomic
,
strong
)
UIButton
*
syncButton
;
@end
@implementation
SyncScreenViewController
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
];
self
.
view
.
backgroundColor
=
UIColor
.
whiteColor
;
[
self
setupHeader
];
[
self
setupMainContent
];
[
self
setupSyncButton
];
}
#pragma mark - Header
-
(
void
)
setupHeader
{
self
.
headerView
=
[[
UIView
alloc
]
init
];
self
.
headerView
.
backgroundColor
=
[
UIColor
colorWithRed
:
0
.
0
green
:
0
.
5
blue
:
0
.
6
alpha
:
1
.
0
];
self
.
headerView
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
self
.
view
addSubview
:
self
.
headerView
];
self
.
backButton
=
[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
[
self
.
backButton
setImage
:[
UIImage
imageNamed
:
@"back24"
]
forState
:
UIControlStateNormal
];
self
.
backButton
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
self
.
headerView
addSubview
:
self
.
backButton
];
self
.
titleLabel
=
[[
UILabel
alloc
]
init
];
self
.
titleLabel
.
text
=
@"SYNC"
;
self
.
titleLabel
.
textColor
=
UIColor
.
whiteColor
;
self
.
titleLabel
.
font
=
[
UIFont
boldSystemFontOfSize
:
18
];
self
.
titleLabel
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
self
.
headerView
addSubview
:
self
.
titleLabel
];
// Constraints
[
NSLayoutConstraint
activateConstraints
:@[
[
self
.
headerView
.
topAnchor
constraintEqualToAnchor
:
self
.
view
.
safeAreaLayoutGuide
.
topAnchor
],
[
self
.
headerView
.
leadingAnchor
constraintEqualToAnchor
:
self
.
view
.
leadingAnchor
],
[
self
.
headerView
.
trailingAnchor
constraintEqualToAnchor
:
self
.
view
.
trailingAnchor
],
[
self
.
headerView
.
heightAnchor
constraintEqualToConstant
:
48
],
[
self
.
backButton
.
leadingAnchor
constraintEqualToAnchor
:
self
.
headerView
.
leadingAnchor
constant
:
8
],
[
self
.
backButton
.
centerYAnchor
constraintEqualToAnchor
:
self
.
headerView
.
centerYAnchor
],
[
self
.
backButton
.
widthAnchor
constraintEqualToConstant
:
32
],
[
self
.
backButton
.
heightAnchor
constraintEqualToConstant
:
32
],
[
self
.
titleLabel
.
centerXAnchor
constraintEqualToAnchor
:
self
.
headerView
.
centerXAnchor
],
[
self
.
titleLabel
.
centerYAnchor
constraintEqualToAnchor
:
self
.
headerView
.
centerYAnchor
],
]];
}
#pragma mark - Main Content
-
(
void
)
setupMainContent
{
UIView
*
content
=
[[
UIView
alloc
]
init
];
content
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
self
.
view
addSubview
:
content
];
[
NSLayoutConstraint
activateConstraints
:@[
[
content
.
topAnchor
constraintEqualToAnchor
:
self
.
headerView
.
bottomAnchor
constant
:
16
],
[
content
.
leadingAnchor
constraintEqualToAnchor
:
self
.
view
.
leadingAnchor
constant
:
16
],
[
content
.
trailingAnchor
constraintEqualToAnchor
:
self
.
view
.
trailingAnchor
constant
:
-
16
],
]];
// Last Updated
self
.
lastUpdatedLabel
=
[[
UILabel
alloc
]
init
];
self
.
lastUpdatedLabel
.
numberOfLines
=
2
;
self
.
lastUpdatedLabel
.
text
=
@"Last Updated:
\n
--"
;
self
.
lastUpdatedLabel
.
textColor
=
[
UIColor
grayColor
];
self
.
lastUpdatedLabel
.
font
=
[
UIFont
boldSystemFontOfSize
:
16
];
self
.
lastUpdatedLabel
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
content
addSubview
:
self
.
lastUpdatedLabel
];
[
NSLayoutConstraint
activateConstraints
:@[
[
self
.
lastUpdatedLabel
.
topAnchor
constraintEqualToAnchor
:
content
.
topAnchor
],
[
self
.
lastUpdatedLabel
.
leadingAnchor
constraintEqualToAnchor
:
content
.
leadingAnchor
],
[
self
.
lastUpdatedLabel
.
trailingAnchor
constraintEqualToAnchor
:
content
.
trailingAnchor
],
]];
// Cards Stack
self
.
cardStack
=
[[
UIStackView
alloc
]
init
];
self
.
cardStack
.
axis
=
UILayoutConstraintAxisVertical
;
self
.
cardStack
.
spacing
=
16
;
self
.
cardStack
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
content
addSubview
:
self
.
cardStack
];
[
NSLayoutConstraint
activateConstraints
:@[
[
self
.
cardStack
.
topAnchor
constraintEqualToAnchor
:
self
.
lastUpdatedLabel
.
bottomAnchor
constant
:
16
],
[
self
.
cardStack
.
leadingAnchor
constraintEqualToAnchor
:
content
.
leadingAnchor
],
[
self
.
cardStack
.
trailingAnchor
constraintEqualToAnchor
:
content
.
trailingAnchor
],
]];
// Add 3 cards
[
self
.
cardStack
addArrangedSubview
:[
self
createCardWithTitle
:
@"Offline Units"
count
:
@"0"
]];
[
self
.
cardStack
addArrangedSubview
:[
self
createCardWithTitle
:
@"Pending Items"
count
:
@"0"
]];
[
self
.
cardStack
addArrangedSubview
:[
self
createCardWithTitle
:
@"History"
count
:
@"0"
]];
}
#pragma mark - Card Factory
-
(
UIView
*
)
createCardWithTitle
:
(
NSString
*
)
title
count
:
(
NSString
*
)
countText
{
UIView
*
card
=
[[
UIView
alloc
]
init
];
card
.
backgroundColor
=
UIColor
.
whiteColor
;
card
.
layer
.
borderWidth
=
1
;
card
.
layer
.
borderColor
=
[
UIColor
lightGrayColor
].
CGColor
;
card
.
layer
.
cornerRadius
=
10
;
card
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
NSLayoutConstraint
activateConstraints
:@[
[
card
.
heightAnchor
constraintEqualToConstant
:
120
]
]];
UILabel
*
titleLabel
=
[[
UILabel
alloc
]
init
];
titleLabel
.
text
=
title
;
titleLabel
.
font
=
[
UIFont
boldSystemFontOfSize
:
20
];
titleLabel
.
textColor
=
[
UIColor
colorWithRed
:
0
.
0
green
:
0
.
5
blue
:
0
.
6
alpha
:
1
.
0
];
titleLabel
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
UILabel
*
countLabel
=
[[
UILabel
alloc
]
init
];
countLabel
.
text
=
countText
;
countLabel
.
font
=
[
UIFont
boldSystemFontOfSize
:
28
];
countLabel
.
textColor
=
[
UIColor
colorWithRed
:
0
.
0
green
:
0
.
5
blue
:
0
.
6
alpha
:
1
.
0
];
countLabel
.
textAlignment
=
NSTextAlignmentRight
;
countLabel
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
card
addSubview
:
titleLabel
];
[
card
addSubview
:
countLabel
];
[
NSLayoutConstraint
activateConstraints
:@[
[
titleLabel
.
leadingAnchor
constraintEqualToAnchor
:
card
.
leadingAnchor
constant
:
16
],
[
titleLabel
.
topAnchor
constraintEqualToAnchor
:
card
.
topAnchor
constant
:
16
],
[
countLabel
.
trailingAnchor
constraintEqualToAnchor
:
card
.
trailingAnchor
constant
:
-
16
],
[
countLabel
.
bottomAnchor
constraintEqualToAnchor
:
card
.
bottomAnchor
constant
:
-
16
],
]];
return
card
;
}
#pragma mark - Sync Button
-
(
void
)
setupSyncButton
{
self
.
syncButton
=
[
UIButton
buttonWithType
:
UIButtonTypeSystem
];
self
.
syncButton
.
backgroundColor
=
[
UIColor
colorWithRed
:
0
.
0
green
:
0
.
5
blue
:
0
.
6
alpha
:
1
.
0
];
[
self
.
syncButton
setTitle
:
@"SYNC"
forState
:
UIControlStateNormal
];
[
self
.
syncButton
setTitleColor
:
UIColor
.
whiteColor
forState
:
UIControlStateNormal
];
self
.
syncButton
.
titleLabel
.
font
=
[
UIFont
boldSystemFontOfSize
:
16
];
self
.
syncButton
.
layer
.
cornerRadius
=
8
;
self
.
syncButton
.
translatesAutoresizingMaskIntoConstraints
=
NO
;
[
self
.
view
addSubview
:
self
.
syncButton
];
[
NSLayoutConstraint
activateConstraints
:@[
[
self
.
syncButton
.
topAnchor
constraintEqualToAnchor
:
self
.
cardStack
.
bottomAnchor
constant
:
16
],
[
self
.
syncButton
.
leadingAnchor
constraintEqualToAnchor
:
self
.
view
.
leadingAnchor
constant
:
16
],
[
self
.
syncButton
.
trailingAnchor
constraintEqualToAnchor
:
self
.
view
.
trailingAnchor
constant
:
-
16
],
[
self
.
syncButton
.
heightAnchor
constraintEqualToConstant
:
50
],
[
self
.
syncButton
.
bottomAnchor
constraintEqualToAnchor
:
self
.
view
.
safeAreaLayoutGuide
.
bottomAnchor
constant
:
-
16
],
]];
}
@end
ios/QmsPlugin/QmsDashboardViewManager.mm
View file @
d5fc7ec0
//QmsDashboardViewManager.mm
#import <React/RCTViewManager.h>
#import <QmsPluginFramework/QmsPluginFramework.h>
#import <QmsPluginFramework/QmsPlugin.h>
...
...
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
d5fc7ec0
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
d5fc7ec0
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