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
3995f152
Commit
3995f152
authored
Jan 14, 2026
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code update
parent
91919501
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
353 additions
and
252 deletions
+353
-252
Info.plist
...PluginFramework/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
DashboardViewController.mm
...k/QmsPluginFramework/Dashboard/DashboardViewController.mm
+186
-134
GeneralInfoViewController.mm
...QmsPluginFramework/Dashboard/GeneralInfoViewController.mm
+15
-10
ProjectViewController.mm
...ork/QmsPluginFramework/Dashboard/ProjectViewController.mm
+28
-31
UnitViewController.mm
...mework/QmsPluginFramework/Dashboard/UnitViewController.mm
+34
-20
HistoryViewController.mm
...amework/QmsPluginFramework/Issue/HistoryViewController.mm
+1
-2
IssuesViewController.mm
...ramework/QmsPluginFramework/Issue/IssuesViewController.mm
+13
-12
SyncProjectViewController.mm
...work/QmsPluginFramework/Sync/SyncProjectViewController.mm
+0
-2
SyncScreenViewController.mm
...ework/QmsPluginFramework/Sync/SyncScreenViewController.mm
+1
-2
APIClient.mm
...inFramework/QmsPluginFramework/Utilities/API/APIClient.mm
+23
-23
APIConfig.mm
...inFramework/QmsPluginFramework/Utilities/API/APIConfig.mm
+2
-2
QmsDashboardViewManager.mm
ios/QmsPlugin/QmsDashboardViewManager.mm
+40
-4
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 @
3995f152
...
...
@@ -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
_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
>
<
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
<
/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
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
3995f152
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
3995f152
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.mm
View file @
3995f152
...
...
@@ -16,7 +16,7 @@
#import "APIConfig.h"
#import "ImageCacheHelper.h"
@interface DashboardViewController ()
@interface DashboardViewController ()
<UIScrollViewDelegate>
@property (nonatomic, strong) NSArray *appointments;
@property (nonatomic, strong) NSArray *issues;
...
...
@@ -44,11 +44,14 @@
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UIStackView *contentContainer;
@property (nonatomic, strong) UIView *inspectionBanner;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIView *stickyBar;
@end
@implementation DashboardViewController {
UIScrollView *_scrollView;
NSMutableDictionary *_sectionViews;
CGFloat _currentY;
}
...
...
@@ -57,7 +60,8 @@
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];
_sectionViews = [NSMutableDictionary dictionary];
[self setupScrollView];
[self setupStickyBar];
[self setupHeader];
[self setupScrollContent];
[self setupFooter];
...
...
@@ -66,7 +70,7 @@
NSLog(@"dashboard.drawerController = %@", self.drawerController);
//
[[OfflineSyncManager shared] clearOfflineQueue];
//
[[OfflineSyncManager shared] clearOfflineQueue];
}
- (void)viewWillAppear:(BOOL)animated {
...
...
@@ -125,35 +129,95 @@
}
#pragma mark - Layout
- (void)viewDidLayoutSubviews {
NSLog(@"Header frame: %@", NSStringFromCGRect(_headerView.frame));
[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
);
}
//
- (void)viewDidLayoutSubviews {
//
NSLog(@"Header frame: %@", NSStringFromCGRect(_headerView.frame));
//
[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
- (void)setupStickyBar {
self.stickyBar = [[UIView alloc] init];
self.stickyBar.translatesAutoresizingMaskIntoConstraints = NO;
self.stickyBar.backgroundColor = [UIColor colorWithRed:0 green:0.43 blue:0.55 alpha:0]; // start fully transparent
[self.view addSubview:self.stickyBar];
[NSLayoutConstraint activateConstraints:@[
[self.stickyBar.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.stickyBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.stickyBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.stickyBar.heightAnchor constraintEqualToConstant:44]
]];
// Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"]
forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self action:@selector(onBack)
forControlEvents:UIControlEventTouchUpInside];
[self.stickyBar addSubview:self.backButton];
// Menu button
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];
[self.stickyBar addSubview:menuButton];
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.stickyBar.leadingAnchor constant:8],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.stickyBar.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[menuButton.trailingAnchor constraintEqualToAnchor:self.stickyBar.trailingAnchor constant:-16],
[menuButton.centerYAnchor constraintEqualToAnchor:self.stickyBar.centerYAnchor],
[menuButton.widthAnchor constraintEqualToConstant:26],
[menuButton.heightAnchor constraintEqualToConstant:26],
]];
UIView *statusBarBackground = [[UIView alloc] init];
statusBarBackground.translatesAutoresizingMaskIntoConstraints = NO;
statusBarBackground.backgroundColor =
[UIColor colorWithRed:0 green:0.43 blue:0.55 alpha:1.0];
[self.view insertSubview:statusBarBackground aboveSubview:self.scrollView];
[NSLayoutConstraint activateConstraints:@[
[statusBarBackground.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[statusBarBackground.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[statusBarBackground.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[statusBarBackground.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
]];
}
- (void)setupHeader {
CGFloat headerHeight = 2
20
.0;
CGFloat maxImageHeight = 2
20
.0;
CGFloat headerHeight = 2
55
.0;
CGFloat maxImageHeight = 2
55
.0;
// ---------- Header Container ----------
self.headerView = [[UIView alloc] init];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.backgroundColor = [UIColor colorWithRed:0 green:0.43 blue:0.55 alpha:1.0];
[self.
v
iew addSubview:self.headerView];
[self.
contentV
iew addSubview:self.headerView];
[NSLayoutConstraint activateConstraints:@[
[self.headerView.topAnchor constraintEqualToAnchor:self.
v
iew.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.
v
iew.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.
v
iew.trailingAnchor],
[self.headerView.topAnchor constraintEqualToAnchor:self.
contentV
iew.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.
contentV
iew.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.
contentV
iew.trailingAnchor],
[self.headerView.heightAnchor constraintEqualToConstant:headerHeight]
]];
...
...
@@ -188,7 +252,7 @@
self.overlayImageView.translatesAutoresizingMaskIntoConstraints = NO;
self.overlayImageView.contentMode = UIViewContentModeScaleToFill;
self.overlayImageView.userInteractionEnabled = NO;
self.overlayImageView.alpha = 0.5;
//
self.overlayImageView.alpha = 0.5;
[imageContainer addSubview:self.overlayImageView];
...
...
@@ -199,59 +263,17 @@
[self.overlayImageView.bottomAnchor constraintEqualToAnchor:imageContainer.bottomAnchor]
]];
// ---------- Header Bar (Top) ----------
UIView *headerBar = [[UIView alloc] init];
headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerView addSubview:headerBar];
[NSLayoutConstraint activateConstraints:@[
[headerBar.topAnchor constraintEqualToAnchor:self.headerView.safeAreaLayoutGuide.topAnchor],
[headerBar.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor],
[headerBar.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor],
[headerBar.heightAnchor constraintEqualToConstant:44]
]];
// ---------- Project Name ----------
self.projectNameLabel = [[UILabel alloc] init];
self.projectNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.projectNameLabel.font = [UIFont boldSystemFontOfSize:18];
self.projectNameLabel.textColor = UIColor.whiteColor;
self.projectNameLabel.textAlignment = NSTextAlignmentCenter;
[
headerBa
r addSubview:self.projectNameLabel];
[
imageContaine
r addSubview:self.projectNameLabel];
[NSLayoutConstraint activateConstraints:@[
[self.projectNameLabel.centerXAnchor constraintEqualToAnchor:headerBar.centerXAnchor],
[self.projectNameLabel.centerYAnchor constraintEqualToAnchor:headerBar.centerYAnchor]
]];
// ---------- Menu Button ----------
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]
]];
// ---------- Back Button ----------
self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
[headerBar addSubview:self.backButton];
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:headerBar.leadingAnchor constant:8],
[self.backButton.centerYAnchor constraintEqualToAnchor:headerBar.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.backButton.heightAnchor constraintEqualToConstant:24]
[self.projectNameLabel.centerXAnchor constraintEqualToAnchor:self.stickyBar.centerXAnchor],
[self.projectNameLabel.centerYAnchor constraintEqualToAnchor:self.stickyBar.centerYAnchor]
]];
// ---------- Unit Name ----------
...
...
@@ -281,6 +303,21 @@
[self.infoButton.heightAnchor constraintEqualToConstant:24]
]];
// ---------- Dark Overlay ----------
UIView *darkOverlay = [[UIView alloc] init];
darkOverlay.translatesAutoresizingMaskIntoConstraints = NO;
darkOverlay.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.35];
darkOverlay.userInteractionEnabled = NO;
[imageContainer addSubview:darkOverlay];
[NSLayoutConstraint activateConstraints:@[
[darkOverlay.topAnchor constraintEqualToAnchor:imageContainer.topAnchor],
[darkOverlay.leadingAnchor constraintEqualToAnchor:imageContainer.leadingAnchor],
[darkOverlay.trailingAnchor constraintEqualToAnchor:imageContainer.trailingAnchor],
[darkOverlay.bottomAnchor constraintEqualToAnchor:imageContainer.bottomAnchor]
]];
// ---------- Load Remote Image & Overlay ----------
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
UIImage *overlayImage =
...
...
@@ -297,7 +334,10 @@
NSURL *url = [NSURL URLWithString:remoteHeaderURL];
[ImageCacheHelper loadImageWithURL:url completion:^(UIImage *image) {
self.backgroundImageView.image = image ?: [UIImage imageNamed:@"header_bg"];
[imageContainer bringSubviewToFront:self.backgroundImageView];
[imageContainer bringSubviewToFront:darkOverlay];
[imageContainer bringSubviewToFront:self.overlayImageView];
[imageContainer bringSubviewToFront:self.projectNameLabel];
}];
} else {
self.backgroundImageView.image = [UIImage imageNamed:@"header_bg"];
...
...
@@ -307,7 +347,7 @@
#pragma mark - Footer
- (void)setupFooter {
CGFloat footerHeight =
80
.0;
CGFloat footerHeight =
72
.0;
CGFloat bottomInset = self.view.safeAreaInsets.bottom;
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(
0,
...
...
@@ -320,9 +360,13 @@
footerView.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
footerView.layer.shadowOpacity = 0.8;
footerView.layer.shadowOffset = CGSizeMake(0, -1);
footerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
footerView.layer.cornerRadius = 16.0;
footerView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner; // top-left & top-right
footerView.clipsToBounds = YES;
[self.view addSubview:footerView];
NSArray *titles = @[ @"Make App
ointment", @"Add Issue", @"View
Access Item" ];
NSArray *titles = @[ @"Make App
t.", @"Add Issue", @"
Access Item" ];
NSArray *icons = @[ @"calendar", @"plus.circle", @"list.bullet" ];
CGFloat buttonWidth = self.view.bounds.size.width / titles.count;
...
...
@@ -330,9 +374,9 @@
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(i * buttonWidth, 0, buttonWidth, footerHeight);
[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
whiteColor
] forState:UIControlStateNormal];
button.titleLabel.font = [UIFont boldSystemFontOfSize:13];
button.tintColor = [UIColor
colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0
];
button.tintColor = [UIColor
whiteColor
];
[button setImage:[UIImage systemImageNamed:icons[i]] forState:UIControlStateNormal];
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
...
...
@@ -391,73 +435,64 @@
}
#pragma mark - Scroll Content
- (void)setupScroll
Content
{
// ScrollView
_scrollView = [[UIScrollView alloc] init]
;
_scrollView.translatesAutoresizingMaskIntoConstraints = NO
;
_scrollView.alwaysBounceVertical = YES
;
[self.view addSubview:
_
scrollView];
- (void)setupScroll
View
{
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO
;
self.scrollView.alwaysBounceVertical = YES
;
self.scrollView.delegate = self
;
[self.view addSubview:
self.
scrollView];
CGFloat footerHeight = 80.0;
self.contentView = [[UIView alloc] init];
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:self.contentView];
[NSLayoutConstraint activateConstraints:@[
[_scrollView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
[_scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[_scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[_scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-footerHeight]
[self.scrollView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[self.contentView.topAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.topAnchor],
[self.contentView.leadingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.leadingAnchor],
[self.contentView.trailingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.trailingAnchor],
[self.contentView.bottomAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.bottomAnchor],
[self.contentView.widthAnchor constraintEqualToAnchor:self.scrollView.frameLayoutGuide.widthAnchor],
]];
}
- (void)setupScrollContent {
UIView *banner = [self buildInspectionChecklistBanner];
UIView *stackContainer = [[UIView alloc] init];
stackContainer.translatesAutoresizingMaskIntoConstraints = NO;
[_scrollView addSubview:stackContainer];
CGFloat topOffset = 16;
if (banner) {
banner.translatesAutoresizingMaskIntoConstraints = NO;
[_scroll
View addSubview:banner];
[self.content
View addSubview:banner];
[NSLayoutConstraint activateConstraints:@[
[banner.topAnchor constraintEqualToAnchor:_scrollView.contentLayoutGuide.top
Anchor constant:topOffset],
[banner.leadingAnchor constraintEqualToAnchor:_scroll
View.leadingAnchor constant:16],
[banner.trailingAnchor constraintEqualToAnchor:_scroll
View.trailingAnchor constant:-16],
[banner.topAnchor constraintEqualToAnchor:self.headerView.bottom
Anchor constant:topOffset],
[banner.leadingAnchor constraintEqualToAnchor:self.content
View.leadingAnchor constant:16],
[banner.trailingAnchor constraintEqualToAnchor:self.content
View.trailingAnchor constant:-16],
[banner.heightAnchor constraintEqualToConstant:90]
]];
topOffset += 90 + 16; // stack starts after banner + spacing
topOffset += 90 + 16;
}
// Content container (STACK VIEW)
UIStackView *stack = [[UIStackView alloc] init];
stack.axis = UILayoutConstraintAxisVertical;
stack.spacing =
16
;
stack.spacing =
22
;
stack.translatesAutoresizingMaskIntoConstraints = NO;
stack.layoutMargins = UIEdgeInsetsMake(0, 16, 16, 16);
stack.layoutMarginsRelativeArrangement = YES;
[s
tackContainer
addSubview:stack];
[s
elf.contentView
addSubview:stack];
self.contentContainer = stack;
[NSLayoutConstraint activateConstraints:@[
[stack.topAnchor constraintEqualToAnchor:stackContainer.topAnchor],
[stack.leadingAnchor constraintEqualToAnchor:stackContainer.leadingAnchor],
[stack.trailingAnchor constraintEqualToAnchor:stackContainer.trailingAnchor],
[stack.bottomAnchor constraintEqualToAnchor:stackContainer.bottomAnchor],
[stack.widthAnchor constraintEqualToAnchor:stackContainer.widthAnchor]
]];
[NSLayoutConstraint activateConstraints:@[
// Top/bottom for vertical scrolling
[stackContainer.topAnchor constraintEqualToAnchor:_scrollView.contentLayoutGuide.topAnchor constant:topOffset],
[stackContainer.bottomAnchor constraintEqualToAnchor:_scrollView.contentLayoutGuide.bottomAnchor],
// ⚡ Width locked to frame to prevent horizontal scroll
[stackContainer.widthAnchor constraintEqualToAnchor:_scrollView.frameLayoutGuide.widthAnchor],
// Leading/trailing optional, can just pin to zero if width is fixed
[stackContainer.leadingAnchor constraintEqualToAnchor:_scrollView.leadingAnchor],
[stackContainer.trailingAnchor constraintEqualToAnchor:_scrollView.trailingAnchor]
[stack.topAnchor constraintEqualToAnchor:(banner ? banner.bottomAnchor : self.headerView.bottomAnchor)
constant:16],
[stack.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor],
[stack.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor],
[stack.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor]
]];
}
...
...
@@ -556,7 +591,7 @@
if (pill) {
[constraints addObjectsFromArray:@[
[pill.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:
8
],
[pill.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:
14
],
[pill.leadingAnchor constraintEqualToAnchor:banner.leadingAnchor constant:16],
[pill.heightAnchor constraintEqualToConstant:28],
[pill.bottomAnchor constraintEqualToAnchor:banner.bottomAnchor constant:-16]
...
...
@@ -793,7 +828,7 @@
[hScroll.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:12],
[hScroll.leadingAnchor constraintEqualToAnchor:section.leadingAnchor],
[hScroll.trailingAnchor constraintEqualToAnchor:section.trailingAnchor],
[hScroll.heightAnchor constraintEqualToConstant:
9
0],
[hScroll.heightAnchor constraintEqualToConstant:
8
0],
[hScroll.bottomAnchor constraintEqualToAnchor:section.bottomAnchor] // important
]];
...
...
@@ -942,7 +977,7 @@
[section addSubview:list];
[NSLayoutConstraint activateConstraints:@[
[list.topAnchor constraintEqualToAnchor:title.bottomAnchor],
[list.topAnchor constraintEqualToAnchor:title.bottomAnchor
constant:12
],
[list.leadingAnchor constraintEqualToAnchor:section.leadingAnchor],
[list.trailingAnchor constraintEqualToAnchor:section.trailingAnchor],
[list.bottomAnchor constraintEqualToAnchor:section.bottomAnchor]
...
...
@@ -967,7 +1002,7 @@
card.layer.shadowOpacity = 0.3;
card.layer.shadowOffset = CGSizeMake(0, 1);
[card.heightAnchor constraintEqualToConstant:9
0
].active = YES;
[card.heightAnchor constraintEqualToConstant:9
2
].active = YES;
NSString *appointmentType = item[@"appointment_type"] ?: @"-";
NSString *status = item[@"status"] ?: @"-";
...
...
@@ -1015,8 +1050,8 @@
[card addSubview:desc];
[NSLayoutConstraint activateConstraints:@[
[iconCircle.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:1
2
],
[iconCircle.topAnchor constraintEqualToAnchor:card.topAnchor constant:1
4
],
[iconCircle.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:1
6
],
[iconCircle.topAnchor constraintEqualToAnchor:card.topAnchor constant:1
2
],
[iconCircle.widthAnchor constraintEqualToConstant:24],
[iconCircle.heightAnchor constraintEqualToConstant:24],
...
...
@@ -1026,15 +1061,15 @@
[bell.heightAnchor constraintEqualToConstant:16],
[statusLabel.leadingAnchor constraintEqualToAnchor:iconCircle.trailingAnchor constant:8],
[statusLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:1
2
],
[statusLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:1
4
],
[timeLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[timeLabel.centerYAnchor constraintEqualToAnchor:statusLabel.centerYAnchor],
[desc.topAnchor constraintEqualToAnchor:
statusLabel.bottomAnchor constant:6
],
[desc.leadingAnchor constraintEqualToAnchor:
card.leadingAnchor constant:16
],
[desc.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-
16
],
[desc.bottomAnchor constraintLessThanOrEqualToAnchor:card.bottomAnchor constant:-
8
]
[desc.topAnchor constraintEqualToAnchor:
card.topAnchor constant:41
],
[desc.leadingAnchor constraintEqualToAnchor:
statusLabel.leadingAnchor
],
[desc.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-
20
],
[desc.bottomAnchor constraintLessThanOrEqualToAnchor:card.bottomAnchor constant:-
15
]
]];
objc_setAssociatedObject(card, "appointmentData", item, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
...
...
@@ -1107,7 +1142,7 @@
[section addSubview:list];
[NSLayoutConstraint activateConstraints:@[
[list.topAnchor constraintEqualToAnchor:title.bottomAnchor],
[list.topAnchor constraintEqualToAnchor:title.bottomAnchor
constant:12
],
[list.leadingAnchor constraintEqualToAnchor:section.leadingAnchor],
[list.trailingAnchor constraintEqualToAnchor:section.trailingAnchor],
[list.bottomAnchor constraintEqualToAnchor:section.bottomAnchor]
...
...
@@ -1130,7 +1165,7 @@
card.layer.shadowOpacity = 0.3;
card.layer.shadowOffset = CGSizeMake(0, 1);
[card.heightAnchor constraintGreaterThanOrEqualToConstant:
110
].active = YES;
[card.heightAnchor constraintGreaterThanOrEqualToConstant:
92
].active = YES;
NSString *status = item[@"status_external"] ?: @"Unknown";
NSString *formattedDate = [self formatDate:item[@"created_at"]];
...
...
@@ -1157,7 +1192,7 @@
dateLabel.textAlignment = NSTextAlignmentRight;
[card addSubview:dateLabel];
CGFloat imageSize =
44
;
CGFloat imageSize =
30
;
UIImageView *thumb = [[UIImageView alloc] init];
thumb.translatesAutoresizingMaskIntoConstraints = NO;
thumb.layer.cornerRadius = 6;
...
...
@@ -1195,12 +1230,12 @@
[card addSubview:info];
[NSLayoutConstraint activateConstraints:@[
[dot.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:1
2
],
[dot.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:1
6
],
[dot.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[dot.widthAnchor constraintEqualToConstant:16],
[dot.heightAnchor constraintEqualToConstant:16],
[statusLabel.leadingAnchor constraintEqualToAnchor:dot.trailingAnchor constant:
6
],
[statusLabel.leadingAnchor constraintEqualToAnchor:dot.trailingAnchor constant:
14
],
[statusLabel.centerYAnchor constraintEqualToAnchor:dot.centerYAnchor],
[dateLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
...
...
@@ -1211,9 +1246,9 @@
[thumb.widthAnchor constraintEqualToConstant:imageSize],
[thumb.heightAnchor constraintEqualToConstant:imageSize],
[info.leadingAnchor constraintEqualToAnchor:thumb.trailingAnchor constant:1
0
],
[info.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-1
2
],
[info.
centerYAnchor constraintEqualToAnchor:thumb.centerYAnchor
],
[info.leadingAnchor constraintEqualToAnchor:thumb.trailingAnchor constant:1
4
],
[info.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-1
4
],
[info.
topAnchor constraintEqualToAnchor:card.topAnchor constant:41
],
[info.bottomAnchor constraintLessThanOrEqualToAnchor:card.bottomAnchor constant:-10]
]];
...
...
@@ -1493,4 +1528,21 @@
[self.navigationController popViewControllerAnimated:YES];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetY = scrollView.contentOffset.y;
// Parallax effect for the header image
if (offsetY < 0) {
self.backgroundImageView.transform = CGAffineTransformMakeTranslation(0, offsetY / 2);
} else {
self.backgroundImageView.transform = CGAffineTransformIdentity;
}
// Gradually fade in sticky bar
CGFloat fadeStart = 0;
CGFloat fadeEnd = 100; // how far scroll before fully opaque
CGFloat alpha = MIN(MAX((offsetY - fadeStart) / (fadeEnd - fadeStart), 0), 1);
self.stickyBar.backgroundColor = [UIColor colorWithRed:0 green:0.43 blue:0.55 alpha:alpha];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/GeneralInfoViewController.mm
View file @
3995f152
...
...
@@ -23,6 +23,7 @@
@property (nonatomic) NSLayoutConstraint *infoBottom;
@property (nonatomic) NSLayoutConstraint *documentsBottom;
@property (nonatomic) NSLayoutConstraint *formsBottom;
@property (nonatomic, strong) UILabel *jointTitleLabel;
// Sections for tabs
@property (nonatomic, strong) UIView *infoContainer;
...
...
@@ -238,12 +239,12 @@ typedef struct {
[self.infoContainer addSubview:self.ownerStack];
// --- Joint Owners Title ---
UILabel *jointTitle
= [[UILabel alloc] init];
jointTitle
.text = @"Joint Owner Details";
jointTitle
.font = [UIFont boldSystemFontOfSize:16];
jointTitle
.textColor = UIColor.darkGrayColor;
jointTitle
.translatesAutoresizingMaskIntoConstraints = NO;
[self.infoContainer addSubview:
jointTitle
];
self.jointTitleLabel
= [[UILabel alloc] init];
self.jointTitleLabel
.text = @"Joint Owner Details";
self.jointTitleLabel
.font = [UIFont boldSystemFontOfSize:16];
self.jointTitleLabel
.textColor = UIColor.darkGrayColor;
self.jointTitleLabel
.translatesAutoresizingMaskIntoConstraints = NO;
[self.infoContainer addSubview:
self.jointTitleLabel
];
// --- Joint Owners Stack ---
self.jointOwnersStack = [[UIStackView alloc] init];
...
...
@@ -276,10 +277,10 @@ typedef struct {
[self.ownerStack.leadingAnchor constraintEqualToAnchor:self.infoContainer.leadingAnchor constant:16],
[self.ownerStack.trailingAnchor constraintEqualToAnchor:self.infoContainer.trailingAnchor constant:-16],
[
jointTitle
.topAnchor constraintEqualToAnchor:self.ownerStack.bottomAnchor constant:20],
[
jointTitle
.leadingAnchor constraintEqualToAnchor:self.infoContainer.leadingAnchor constant:16],
[
self.jointTitleLabel
.topAnchor constraintEqualToAnchor:self.ownerStack.bottomAnchor constant:20],
[
self.jointTitleLabel
.leadingAnchor constraintEqualToAnchor:self.infoContainer.leadingAnchor constant:16],
[self.jointOwnersStack.topAnchor constraintEqualToAnchor:
jointTitle
.bottomAnchor constant:12],
[self.jointOwnersStack.topAnchor constraintEqualToAnchor:
self.jointTitleLabel
.bottomAnchor constant:12],
[self.jointOwnersStack.leadingAnchor constraintEqualToAnchor:self.infoContainer.leadingAnchor constant:16],
[self.jointOwnersStack.trailingAnchor constraintEqualToAnchor:self.infoContainer.trailingAnchor constant:-16],
...
...
@@ -643,7 +644,6 @@ typedef struct {
}
maxTitleWidth += 6;
UIStackView* (^OwnerCard)(NSDictionary *) = ^UIStackView* (NSDictionary *owner) {
UIStackView *card = [[UIStackView alloc] init];
...
...
@@ -699,6 +699,11 @@ typedef struct {
[self.jointOwnersStack addArrangedSubview:OwnerCard(owner)];
}
BOOL hasJointOwners = self.jointOwnersStack.arrangedSubviews.count > 0;
self.jointOwnersStack.hidden = !hasJointOwners;
self.jointTitleLabel.hidden = !hasJointOwners;
// ------------------------
// 2️⃣ UNIT INFO SECTION
// ------------------------
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/ProjectViewController.mm
View file @
3995f152
...
...
@@ -34,10 +34,10 @@
// label
self.nameLabel = [[UILabel alloc] init];
self.nameLabel.font = [UIFont boldSystemFontOfSize:
20
];
self.nameLabel.font = [UIFont boldSystemFontOfSize:
18
];
self.nameLabel.textColor = UIColor.whiteColor;
self.nameLabel.backgroundColor =
[[UIColor blackColor] colorWithAlphaComponent:0.35];
//
self.nameLabel.backgroundColor =
//
[[UIColor blackColor] colorWithAlphaComponent:0.35];
self.nameLabel.numberOfLines = 2;
self.nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.nameLabel];
...
...
@@ -116,24 +116,24 @@
NSLog(@"ClientCode: %@", self.ClientCode);
NSLog(@"user_token: %@", self.user_token);
[self showLoadingOverlay:@"Loading..."];
if (![self isReadyToLoadDashboard]) {
NSLog(@"⏳ Waiting for all credentials to be ready...");
return;
}
if (_isLoadingDashboard) return;
self.isLoadingDashboard = YES;
NSLog(@"✅ All credentials ready. ClientID: %@, ClientCode: %@, user_token: %@",
self.ClientID, self.ClientCode, self.user_token);
[APIConfig setAuthTokem:self.user_token];
[APIConfig setClientId:self.ClientID];
[self requestProjectList]
;
//
[self showLoadingOverlay:@"Loading..."];
//
//
if (![self isReadyToLoadDashboard]) {
//
NSLog(@"⏳ Waiting for all credentials to be ready...");
//
return;
//
}
//
//
if (_isLoadingDashboard) return;
//
//
self.isLoadingDashboard = YES;
//
//
NSLog(@"✅ All credentials ready. ClientID: %@, ClientCode: %@, user_token: %@",
//
self.ClientID, self.ClientCode, self.user_token);
//
//
//
[APIConfig setAuthTokem:self.user_token];
//
[APIConfig setClientId:self.ClientID];
self.ClientCode = @"spt"
;
[self requestCompanyCode];
}
...
...
@@ -185,7 +185,7 @@
- (void)setupCollectionView {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
layout.minimumLineSpacing = 1
6
;
layout.minimumLineSpacing = 1
2
;
layout.minimumInteritemSpacing = 16;
layout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
...
...
@@ -202,7 +202,7 @@
// constraints
[NSLayoutConstraint activateConstraints:@[
[self.collectionView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:
8
],
[self.collectionView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:
20
],
[self.collectionView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.collectionView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.collectionView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
...
...
@@ -273,7 +273,7 @@
CGFloat horizontalInset = 16 * 2; // section inset left + right
CGFloat width = collectionView.bounds.size.width - horizontalInset;
CGFloat height =
20
0; // OG-style banner height
CGFloat height =
14
0; // OG-style banner height
return CGSizeMake(width, height);
}
...
...
@@ -400,16 +400,12 @@
return;
}
NSArray *project = data[@"Data"];
if (![project isKindOfClass:[NSArray class]]) {
NSLog(@"❌ Invalid project list format");
return;
}
if (!error) {
NSString *rawURL = data[@"Data"][@"url_path"];
NSString *baseURL = rawURL;
NSLog(@"base url: %@", baseURL);
// remove trailing slash if exists
if ([baseURL hasSuffix:@"/"]) {
baseURL = [baseURL substringToIndex:baseURL.length - 1];
...
...
@@ -418,7 +414,8 @@
// append /api
baseURL = [baseURL stringByAppendingString:@"/api"];
NSLog(@"baseURL: %@", baseURL);
// [APIConfig setBaseURL:baseURL];
[APIConfig setBaseURL:baseURL];
[self requestProjectList];
}
}];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/UnitViewController.mm
View file @
3995f152
...
...
@@ -110,10 +110,10 @@
[self.view addSubview:self.searchBar];
[NSLayoutConstraint activateConstraints:@[
[self.searchBar.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:
8
],
[self.searchBar.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:
0
],
[self.searchBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:16],
[self.searchBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16],
[self.searchBar.heightAnchor constraintEqualToConstant:
44
]
[self.searchBar.heightAnchor constraintEqualToConstant:
72
]
]];
}
...
...
@@ -151,11 +151,19 @@
[self.view addSubview:self.tableView];
UILabel *footerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 50)];
footerLabel.text = @"All items displayed";
footerLabel.textColor = UIColor.systemGrayColor;
footerLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
footerLabel.textAlignment = NSTextAlignmentCenter;
self.tableView.tableFooterView = footerLabel;
[NSLayoutConstraint activateConstraints:@[
[self.tableView.topAnchor constraintEqualToAnchor:self.searchBar.bottomAnchor constant:
8
],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
[self.tableView.topAnchor constraintEqualToAnchor:self.searchBar.bottomAnchor constant:
12
],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor
constant:16
],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor
constant:-16
],
[self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor
constant:self.view.safeAreaInsets.bottom
]
]];
}
...
...
@@ -169,6 +177,7 @@
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:@"UnitCell"
forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// ---- Reset reused cell ----
for (UIView *subview in cell.contentView.subviews) {
...
...
@@ -186,25 +195,30 @@
// ---- Arrow ----
UIImageView *arrow = [[UIImageView alloc] initWithImage:
[UIImage systemImageNamed:@"chevron.right"]];
arrow.tintColor =
UIColor.systemGrayColor
;
arrow.tintColor =
[UIColor colorWithRed:0.0 green:0.5 blue:0.6 alpha:1.0]
;
arrow.translatesAutoresizingMaskIntoConstraints = NO;
// ---- Card styling ----
cell.backgroundColor = UIColor.clearColor;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.backgroundColor = UIColor.whiteColor;
cell.contentView.layer.cornerRadius = 12;
cell.contentView.layer.borderWidth = 1;
cell.contentView.layer.borderColor = UIColor.systemGray4Color.CGColor;
cell.contentView.clipsToBounds = YES;
// ---- Add views ----
[cell.contentView addSubview:label];
[cell.contentView addSubview:arrow];
UIView *cardView = [[UIView alloc] init];
cardView.backgroundColor = UIColor.whiteColor;
cardView.layer.cornerRadius = 12;
cardView.layer.borderWidth = 1;
cardView.layer.borderColor = UIColor.systemGray4Color.CGColor;
cardView.translatesAutoresizingMaskIntoConstraints = NO;
[cell.contentView addSubview:cardView];
// Put label & arrow inside cardView
[cardView addSubview:label];
[cardView addSubview:arrow];
// ---- Constraints ----
[NSLayoutConstraint activateConstraints:@[
// Cardview
[cardView.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor constant:8], // vertical spacing top
[cardView.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor constant:-8], // vertical spacing bottom
[cardView.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:0], // horizontal spacing
[cardView.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:0],
// Label
[label.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:16],
[label.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor],
...
...
@@ -230,7 +244,7 @@ forRowAtIndexPath:(NSIndexPath *)indexPath {
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 6
4
;
return 6
6
;
}
- (void)tableView:(UITableView *)tableView
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/HistoryViewController.mm
View file @
3995f152
...
...
@@ -60,8 +60,7 @@
#pragma mark - Header
- (void)setupHeader {
CGFloat statusBarHeight = UIApplication.sharedApplication.statusBarFrame.size.height;
self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, statusBarHeight + 60)];
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/IssuesViewController.mm
View file @
3995f152
...
...
@@ -82,30 +82,31 @@
[card.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:6],
[card.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:10],
[card.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-10],
[card.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-6],
[self.thumbView.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[self.thumbView.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[self.thumbView.widthAnchor constraintEqualToConstant:44],
[self.thumbView.heightAnchor constraintEqualToConstant:44],
[card.heightAnchor constraintEqualToConstant:141],
[self.statusLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[self.statusLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[self.statusLabel.widthAnchor constraintEqualToConstant:70],
[self.statusLabel.heightAnchor constraintEqualToConstant:24],
[self.referenceLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:16],
[self.referenceLabel.trailingAnchor constraintEqualToAnchor:self.statusLabel.leadingAnchor constant:16],
[self.referenceLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:16],
[self.thumbView.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:16],
[self.thumbView.topAnchor constraintEqualToAnchor:self.referenceLabel.bottomAnchor constant:12],
[self.thumbView.widthAnchor constraintEqualToConstant:44],
[self.thumbView.heightAnchor constraintEqualToConstant:44],
[self.locationLabel.leadingAnchor constraintEqualToAnchor:self.thumbView.trailingAnchor constant:12],
[self.locationLabel.
topAnchor constraintEqualToAnchor:card.topAnchor constant:12
],
[self.locationLabel.
bottomAnchor constraintEqualToAnchor:self.thumbView.centerYAnchor constant:-1
],
[self.createdLabel.leadingAnchor constraintEqualToAnchor:self.thumbView.trailingAnchor constant:12],
[self.createdLabel.topAnchor constraintEqualToAnchor:self.locationLabel.bottomAnchor constant:4],
[self.referenceLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[self.referenceLabel.topAnchor constraintEqualToAnchor:self.thumbView.bottomAnchor constant:8],
[self.createdLabel.topAnchor constraintEqualToAnchor:self.thumbView.centerYAnchor constant:1],
[self.detailsLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[self.detailsLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[self.detailsLabel.topAnchor constraintEqualToAnchor:self.
referenceLabel.bottomAnchor constant:4
],
[self.detailsLabel.topAnchor constraintEqualToAnchor:self.
thumbView.bottomAnchor constant:12
],
[self.detailsLabel.bottomAnchor constraintEqualToAnchor:card.bottomAnchor constant:-12],
]];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Sync/SyncProjectViewController.mm
View file @
3995f152
...
...
@@ -715,8 +715,6 @@ didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
for (SyncUnit *unit in self.selectedUnits) {
[dictArray addObject:[self dictionaryFromUnit:unit]];
}
[LocalStorage saveArray:dictArray forKey:@"SELECTED_OFFLINE_UNITS"];
[self showOfflineUnit];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Sync/SyncScreenViewController.mm
View file @
3995f152
...
...
@@ -670,7 +670,7 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
}
- (NSInteger)loadOfflineUnitCount {
NSArray *units = [LocalStorage loadArrayForKey:
@"SELECTED_OFFLINE_UNITS"
];
NSArray *units = [LocalStorage loadArrayForKey:
kSyncSelectedUnitsKey
];
return units.count;
}
...
...
@@ -714,5 +714,4 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
self.yesBtn.alpha = enabled ? 1.0 : 0.5;
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIClient.mm
View file @
3995f152
...
...
@@ -12,7 +12,7 @@
return;
}
NSURL *url = [APIConfig urlWithPath:@"/owner/plan/getAccessItem"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/plan/getAccessItem"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -84,7 +84,7 @@
}
// ✅ Construct URL (with token)
NSURL *url = [APIConfig urlWithPath:@"/owner/plan/getLocationByUnit"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/plan/getLocationByUnit"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -177,7 +177,7 @@
return;
}
NSURL *url = [APIConfig urlWithPath:@"/issue/getGeneralSettingByLocation"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
issue/getGeneralSettingByLocation"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -269,7 +269,7 @@
images:(NSArray<UIImage *> * _Nullable)images
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/addIssue"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/addIssue"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -361,7 +361,7 @@
images:(NSArray<UIImage *> * _Nullable)images
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion{
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/updateIssue"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/updateIssue"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -470,7 +470,7 @@
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/appointment/getSlot"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/appointment/getSlot"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -544,7 +544,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/plan/getUnitInfo"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/plan/getUnitInfo"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -614,7 +614,7 @@
+ (void)submitAppointment:(NSDictionary *)appointmentData
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/owner/appointment/makeAppointment"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/appointment/makeAppointment"];
NSLog(@"🌍 SUBMIT (NO REP) URL: %@", url.absoluteString);
NSLog(@"📦 SUBMIT (NO REP) Body JSON: %@", appointmentData);
...
...
@@ -673,7 +673,7 @@
+ (void)submitRepresentativeAppointment:(NSDictionary *)repData
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/owner/appointment/makeAppointment"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/appointment/makeAppointment"];
NSLog(@"🌍 SUBMIT URL: %@", url.absoluteString);
// Create request
...
...
@@ -743,7 +743,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/appointment/cancelAppointment"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/appointment/cancelAppointment"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -817,7 +817,7 @@
return;
}
NSURL *url = [APIConfig urlWithPath:@"/owner/plan/getIssueUpdateAppointmentInfo"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/plan/getIssueUpdateAppointmentInfo"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -883,7 +883,7 @@
return;
}
// ✅ Keep token in URL
NSURL *url = [APIConfig urlWithPath:@"/clientAnnouncement"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
clientAnnouncement"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -960,7 +960,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/getIssueHistory"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/getIssueHistory"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1033,7 +1033,7 @@
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/addInfo"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/addInfo"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1103,7 +1103,7 @@
mediaType:(NSString *)mediaType
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/addInfo"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/addInfo"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1218,7 +1218,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/getIssue"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/getIssue"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1294,7 +1294,7 @@
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/voidIssue"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/voidIssue"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1377,7 +1377,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/deleteIssue"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/deleteIssue"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1451,7 +1451,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/plan/getCommonArea"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/plan/getCommonArea"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1525,7 +1525,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/issue/getGeneralSetting"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/issue/getGeneralSetting"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1599,7 +1599,7 @@
// return;
// }
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/issue/getGeneralSettingByUnit"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
issue/getGeneralSettingByUnit"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1669,7 +1669,7 @@
return;
}
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/project/listProject"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/project/listProject"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
@@ -1739,7 +1739,7 @@
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
// ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/owner/offline/syncImageArray"];
NSURL *url = [APIConfig urlWithPath:@"/
framework/
owner/offline/syncImageArray"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
...
...
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIConfig.mm
View file @
3995f152
...
...
@@ -3,10 +3,10 @@
#import "LocalStorage.h"
#import "NetworkManager.h"
static NSString *kBaseURL = @"https://
kitadev
.commudesk.com/api";
static NSString *kBaseURL = @"https://
sptest
.commudesk.com/api";
static NSString *kDrawingPlanId = @"";
static NSString *kProjectId = @"";
static NSString *kAuthToken = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ
lbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA
";
static NSString *kAuthToken = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ
zY29wZSI6InNlcnZlci10by1zZXJ2ZXIiLCJmcmFtZXdvcmstYXBpIjp0cnVlLCJjb21wYW55X2NvZGUiOiJTUFQiLCJzdWIiOjE1NTcsImlzcyI6Imh0dHBzOi8vc3B0ZXN0LmNvbW11ZGVzay5jb20vYXBpL2ZyYW1ld29yay9vd25lci9hdXRoL2NsaWVudF9hdXRoZW50aWNhdGlvbiIsImlhdCI6MTc2Nzc1MjU5OSwiZXhwIjoyMDgzMzIyMTE5LCJuYmYiOjE3Njc3NTI1OTksImp0aSI6IktEcmhmSXgzeWU0WmxaUEYifQ.Bv4ZSjGRm9YYOjGItLSV_3wS7grKuPTabL60BFnp88o
";
static NSString *kClientId = @"3";
@implementation APIConfig
...
...
ios/QmsPlugin/QmsDashboardViewManager.mm
View file @
3995f152
...
...
@@ -6,10 +6,12 @@
@interface QmsDashboardView : UIView
@property (nonatomic, strong) UIViewController *dashboardVC;
@property (nonatomic, assign) BOOL didSetupVC;
// New props
@property (nonatomic, copy) NSString *ClientID;
@property (nonatomic, copy) NSString *ClientCode;
@property (nonatomic, copy) NSString *user_token;
@property (nonatomic, copy) RCTDirectEventBlock onClose;
@end
@implementation QmsDashboardView
...
...
@@ -19,6 +21,12 @@
_dashboardVC = [QmsPluginUI makeViewController];
_didSetupVC = NO;
_dashboardVC.view.backgroundColor = [UIColor whiteColor];
// Listen for native dashboard close notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleDashboardClose:)
name:@"QmsDashboardDidCloseNotification"
object:nil];
}
return self;
}
...
...
@@ -28,6 +36,10 @@
if (self.window && !_didSetupVC) {
UIViewController *parentVC = [UIApplication sharedApplication].keyWindow.rootViewController;
if (parentVC) {
// 1️⃣ create VC with props
_dashboardVC = [QmsPluginUI makeViewController];
[parentVC addChildViewController:_dashboardVC];
_dashboardVC.view.frame = parentVC.view.bounds;
_dashboardVC.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
...
...
@@ -35,14 +47,34 @@
[_dashboardVC didMoveToParentViewController:parentVC];
_didSetupVC = YES;
// Forward props once the VC is ad
ded
// 2️⃣ forward props again if nee
ded
[self forwardPropsToVC];
}
}
}
#pragma mark - Prop Setters
- (void)handleDashboardClose:(NSNotification *)note {
// 1️⃣ Notify JS
if (self.onClose) {
self.onClose(@{});
}
// 2️⃣ Clean up the native view controller
[self cleanupDashboard];
}
- (void)cleanupDashboard {
if (!_dashboardVC) return;
[_dashboardVC willMoveToParentViewController:nil];
[_dashboardVC.view removeFromSuperview];
[_dashboardVC removeFromParentViewController];
_dashboardVC = nil;
_didSetupVC = NO;
}
#pragma mark - Prop Setters
- (void)setClientID:(NSString *)ClientID {
_ClientID = [ClientID copy];
[self forwardProp:@"ClientID" value:_ClientID];
...
...
@@ -59,7 +91,6 @@
}
#pragma mark - Forward Props via KVC
- (void)forwardProp:(NSString *)key value:(NSString *)value {
if (_dashboardVC && [_dashboardVC respondsToSelector:NSSelectorFromString(key)]) {
@try {
...
...
@@ -76,6 +107,11 @@
[self forwardProp:@"user_token" value:_user_token];
}
- (void)removeFromSuperview {
[self cleanupDashboard];
[super removeFromSuperview];
}
@end
@interface QmsDashboardViewManager : RCTViewManager
...
...
ios/QmsPluginFramework.xcframework/Info.plist
View file @
3995f152
...
...
@@ -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
_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
>
<
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
<
/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
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
3995f152
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
3995f152
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