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
82cef0dc
Commit
82cef0dc
authored
Jan 09, 2026
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code update
parent
4a7abd98
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
185 additions
and
75 deletions
+185
-75
project.pbxproj
...ginFramework/QmsPluginFramework.xcodeproj/project.pbxproj
+4
-0
AccessAppointmentViewController.mm
...inFramework/AccessItem/AccessAppointmentViewController.mm
+1
-1
AppointmentDetailsViewController.mm
...Framework/Appointment/AppointmentDetailsViewController.mm
+2
-2
AppointmentViewController.mm
...sPluginFramework/Appointment/AppointmentViewController.mm
+33
-19
AppointmentViewMoreViewController.mm
...ramework/Appointment/AppointmentViewMoreViewController.mm
+1
-1
DashboardViewController.h
...rk/QmsPluginFramework/Dashboard/DashboardViewController.h
+1
-0
DashboardViewController.mm
...k/QmsPluginFramework/Dashboard/DashboardViewController.mm
+0
-0
GeneralInfoViewController.mm
...QmsPluginFramework/Dashboard/GeneralInfoViewController.mm
+1
-1
ProjectViewController.mm
...ork/QmsPluginFramework/Dashboard/ProjectViewController.mm
+31
-15
UnitViewController.h
...amework/QmsPluginFramework/Dashboard/UnitViewController.h
+1
-0
UnitViewController.mm
...mework/QmsPluginFramework/Dashboard/UnitViewController.mm
+2
-1
AddInfoViewController.mm
...amework/QmsPluginFramework/Issue/AddInfoViewController.mm
+2
-2
DetailsViewController.mm
...msPluginFramework/Issue/AddIssue/DetailsViewController.mm
+2
-2
PlanViewController.mm
...k/QmsPluginFramework/Issue/AddIssue/PlanViewController.mm
+2
-2
HistoryViewController.mm
...amework/QmsPluginFramework/Issue/HistoryViewController.mm
+1
-1
IssuesViewController.mm
...ramework/QmsPluginFramework/Issue/IssuesViewController.mm
+1
-1
WithdrawIssuesViewController.mm
.../QmsPluginFramework/Issue/WithdrawIssuesViewController.mm
+2
-2
WithdrawSingleIssueViewController.mm
...luginFramework/Issue/WithdrawSingleIssueViewController.mm
+2
-2
SyncProjectViewController.mm
...work/QmsPluginFramework/Sync/SyncProjectViewController.mm
+2
-1
APIClient.h
...ginFramework/QmsPluginFramework/Utilities/API/APIClient.h
+22
-22
APIClient.mm
...inFramework/QmsPluginFramework/Utilities/API/APIClient.mm
+0
-0
APIConfig.h
...ginFramework/QmsPluginFramework/Utilities/API/APIConfig.h
+7
-0
APIConfig.mm
...inFramework/QmsPluginFramework/Utilities/API/APIConfig.mm
+65
-0
OfflineSyncManager.mm
...uginFramework/Utilities/OfflineSync/OfflineSyncManager.mm
+0
-0
No files found.
framework/QmsPluginFramework/QmsPluginFramework.xcodeproj/project.pbxproj
View file @
82cef0dc
...
...
@@ -239,6 +239,7 @@
TargetAttributes
=
{
2F9647642E86307D002CC7CB
=
{
CreatedOnToolsVersion
=
26.0.1
;
LastSwiftMigration
=
2620
;
};
2FC779A82F0E1C310002A1D4
=
{
CreatedOnToolsVersion
=
26.2
;
...
...
@@ -312,6 +313,7 @@
isa
=
XCBuildConfiguration
;
buildSettings
=
{
BUILD_LIBRARY_FOR_DISTRIBUTION
=
YES
;
CLANG_ENABLE_MODULES
=
YES
;
CODE_SIGN_STYLE
=
Automatic
;
CURRENT_PROJECT_VERSION
=
1
;
DEFINES_MODULE
=
YES
;
...
...
@@ -343,6 +345,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD
=
NO
;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD
=
NO
;
SWIFT_EMIT_LOC_STRINGS
=
YES
;
SWIFT_OPTIMIZATION_LEVEL
=
"-Onone"
;
SWIFT_VERSION
=
4.0
;
TARGETED_DEVICE_FAMILY
=
"1,2"
;
};
...
...
@@ -352,6 +355,7 @@
isa
=
XCBuildConfiguration
;
buildSettings
=
{
BUILD_LIBRARY_FOR_DISTRIBUTION
=
YES
;
CLANG_ENABLE_MODULES
=
YES
;
CODE_SIGN_STYLE
=
Automatic
;
CURRENT_PROJECT_VERSION
=
1
;
DEFINES_MODULE
=
YES
;
...
...
framework/QmsPluginFramework/QmsPluginFramework/AccessItem/AccessAppointmentViewController.mm
View file @
82cef0dc
...
...
@@ -514,7 +514,7 @@
[APIClient requestCancelAppointment:self.appointmentData[@"appointment_id"]
reason:remarks
completion:^(NSDictionary *data, NSError *error)
completion:^(
BOOL success,
NSDictionary *data, NSError *error)
{
dispatch_async(dispatch_get_main_queue(), ^{
...
...
framework/QmsPluginFramework/QmsPluginFramework/Appointment/AppointmentDetailsViewController.mm
View file @
82cef0dc
...
...
@@ -933,7 +933,7 @@
[
APIClient
requestCancelAppointment:self
.
appointmentData
[@"
id
"]
reason:remarks
completion:
^(
NSDictionary
*
data
,
NSError
*
error
)
completion:
^(
BOOL
success
,
NSDictionary
*
data
,
NSError
*
error
)
{
dispatch_async
(
dispatch_get_main_queue
(),
^{
...
...
@@ -966,7 +966,7 @@
}
-
(
void
)
requestGeneralInfo
{
[
APIClient
requestGeneralInfo:
^(
NSDictionary
*
data
,
NSError
*
error
)
{
[
APIClient
requestGeneralInfo:
^(
BOOL
success
,
NSDictionary
*
data
,
NSError
*
error
)
{
if
(
error
)
return
;
NSDictionary
*
generalInfo =
data[@"Data"];
self
.
floorPlanImage =
generalInfo[@"image"];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Appointment/AppointmentViewController.mm
View file @
82cef0dc
...
...
@@ -32,6 +32,7 @@
@property (nonatomic, strong) WKWebView *termsWebView;
@property (nonatomic, strong) NSString *termsAndCondition;
@property (nonatomic, strong) NSString *appointmentType;
@property (nonatomic, assign) BOOL hasLoadedTermsHTML;
// Labels
@property (nonatomic, strong) UILabel *unitLabel;
...
...
@@ -61,12 +62,23 @@
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self requestAppointment];
[self requestGeneralInfo];
[self setupHeader];
[self setupFooter];
[self setupUI];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.termsAndCondition
&&
!self.hasLoadedTermsHTML) {
[self.termsWebView loadHTMLString:self.termsAndCondition baseURL:nil];
self.hasLoadedTermsHTML = YES;
}
}
#pragma mark - Setup UI
- (void)setupUI {
// Scroll view
...
...
@@ -173,26 +185,30 @@
#pragma mark = Overlay t
&
c
- (void)setupTermsOverlay {
// Overlay background
self.termsOverlay = [[UIView alloc] init];
self.termsOverlay.backgroundColor = UIColor.whiteColor;
self.termsOverlay.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.termsOverlay];
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
[self.termsOverlay.topAnchor constraintEqualToAnchor:self.headerBar.bottomAnchor],
[self.termsOverlay.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.termsOverlay.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.termsOverlay.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
,
[self.termsOverlay.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]];
// Title
self.termsTitleLabel = [[UILabel alloc] init];
self.termsTitleLabel.text = @"Terms
&
Conditions";
self.termsTitleLabel.font = [UIFont boldSystemFontOfSize:18];
self.termsTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.termsOverlay addSubview:self.termsTitleLabel];
// WebView container
self.termsContainer = [[UIView alloc] init];
self.termsContainer.backgroundColor = [UIColor c
olorWithWhite:0.95 alpha:1.0
];
self.termsContainer.backgroundColor = [UIColor c
learColor
];
self.termsContainer.layer.cornerRadius = 12.0;
self.termsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[self.termsOverlay addSubview:self.termsContainer];
...
...
@@ -202,12 +218,10 @@
self.termsWebView.translatesAutoresizingMaskIntoConstraints = NO;
self.termsWebView.scrollView.delegate = self;
self.termsWebView.navigationDelegate = self;
self.termsWebView.opaque = NO;
self.termsWebView.backgroundColor = [UIColor clearColor];
[self.termsContainer addSubview:self.termsWebView];
self.termsContainer.backgroundColor = [UIColor yellowColor];
self.termsWebView.backgroundColor = [UIColor redColor];
// Agree button
self.agreeButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.agreeButton.translatesAutoresizingMaskIntoConstraints = NO;
...
...
@@ -220,7 +234,7 @@
forControlEvents:UIControlEventTouchUpInside];
[self.termsOverlay addSubview:self.agreeButton];
// Layout
// Layout
constraints
[NSLayoutConstraint activateConstraints:@[
[self.termsTitleLabel.topAnchor constraintEqualToAnchor:self.termsOverlay.topAnchor constant:40],
[self.termsTitleLabel.leadingAnchor constraintEqualToAnchor:self.termsOverlay.leadingAnchor constant:20],
...
...
@@ -243,7 +257,6 @@
]];
}
#pragma mark - Labels
- (void)setupLabels:(UIView *)parent {
self.unitLabel = [[UILabel alloc] init];
...
...
@@ -450,7 +463,7 @@
#pragma mark - api
- (void)requestAppointment {
[APIClient requestAppointment:^(NSDictionary *data, NSError *error) {
[APIClient requestAppointment:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) return;
if (!data[@"Data"]) return;
...
...
@@ -477,14 +490,16 @@
NSArray *slots = selectedTypeDict[@"slots"] ?: @[];
self.allSlots = slots; // store all raw slots
// --- 3️⃣ Load Terms HTML ---
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (!self.termsAndCondition) {
NSString *termsHTML = selectedTypeDict[@"terms"] ?: @"";
NSLog(@"termsHTML: %@", termsHTML);
NSString *styledHTML = [NSString stringWithFormat:
@"
<html>
"
"
<head>
"
"
<meta
name=
\"viewport\"
content=
\"width=device-width,
initial-scale=
1.0,
maximum-scale=
1.0\"
>
"
"
<style>
"
"
body
{
font-size
:
14
px
;
font-family
:
-apple-system
;
line-height
:
1.5
;
padding
:
12px
;
background-color
:
#F9F9F9
;
color
:
#000000
;
}
"
"
body
{
font-size
:
16
px
;
font-family
:
-apple-system
;
line-height
:
1.5
;
padding
:
12px
;
background-color
:
#F9F9F9
;
color
:
#000000
;
}
"
"
p
,
div
,
span
,
li
{
color
:
#000000
!important
;
}
"
"
p
{
margin-bottom
:
12px
;
}
"
"
</style>
"
...
...
@@ -494,17 +509,16 @@
self.termsAndCondition = styledHTML;
dispatch_async(dispatch_get_main_queue(), ^{
[self.termsWebView loadHTMLString:styledHTML baseURL:nil];
[self buildMarkedDatesFromSlots:slots];
[self.calendarView.collectionView reloadData];
}
[self.termsContainer layoutIfNeeded];
[self.termsWebView layoutIfNeeded];
[self.termsWebView loadHTMLString:self.termsAndCondition baseURL:nil];
});
}];
}
-(void) requestGeneralInfo {
[APIClient requestGeneralInfo:^(NSDictionary *data, NSError *error) {
[APIClient requestGeneralInfo:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) return;
NSDictionary *generalInfo = data[@"Data"];
...
...
@@ -705,7 +719,7 @@
dispatch_group_t
group =
dispatch_group_create();
dispatch_group_enter
(
group
);
[
APIClient
requestAppointment:
^(
NSDictionary
*
data
,
NSError
*
error
)
{
[
APIClient
requestAppointment:
^(
BOOL
success
,
NSDictionary
*
data
,
NSError
*
error
)
{
if
(
data
[@"
Data
"])
{
NSDictionary
*
dataDict =
data[@"Data"];
self
.
appointmentData =
dataDict;
...
...
@@ -730,7 +744,7 @@
}];
dispatch_group_enter(group);
[APIClient requestGeneralInfo:^(NSDictionary *data, NSError *error) {
[APIClient requestGeneralInfo:^(
BOOL success,
NSDictionary *data, NSError *error) {
id reps = data[@"Data"][@"representative"];
self.representativeList = [reps isKindOfClass:[NSArray class]] ? reps : @[];
dispatch_group_leave(group);
...
...
framework/QmsPluginFramework/QmsPluginFramework/Appointment/AppointmentViewMoreViewController.mm
View file @
82cef0dc
...
...
@@ -927,7 +927,7 @@
- (void)requestDashboardInfo {
[self.loadingView startAnimating];
[APIClient requestDashboardInfo:^(NSDictionary *data, NSError *error) {
[APIClient requestDashboardInfo:^(
BOOL success,
NSDictionary *data, NSError *error) {
[self.loadingView stopAnimating];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.h
View file @
82cef0dc
...
...
@@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
@property
(
nonatomic
,
copy
)
NSString
*
projectName
;
@property
(
nonatomic
,
copy
)
NSString
*
projectId
;
@property
(
nonatomic
,
copy
)
NSString
*
drawingPlanId
;
@property
(
nonatomic
,
copy
)
NSString
*
projectLogo
;
@end
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.mm
View file @
82cef0dc
This diff is collapsed.
Click to expand it.
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/GeneralInfoViewController.mm
View file @
82cef0dc
...
...
@@ -541,7 +541,7 @@ typedef struct {
#pragma mark - api
- (void)requestGeneralInfo {
[APIClient requestGeneralInfo:^(NSDictionary *data, NSError *error) {
[APIClient requestGeneralInfo:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error || !data) {
NSLog(@"❌ General info error: %@", error.localizedDescription);
return;
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/ProjectViewController.mm
View file @
82cef0dc
...
...
@@ -156,33 +156,48 @@
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ProjectCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ProjectCardCell"
forIndexPath:indexPath];
// Default placeholder
cell.imageView.image = [UIImage systemImageNamed:@"photo"];
NSDictionary *project = self.projects[indexPath.item];
// Project name
cell.nameLabel.text = project[@"project_name"];
id projectName = project[@"project_name"];
cell.nameLabel.text = [projectName isKindOfClass:[NSString class]] ? projectName : @"";
// Get logo URL safely
NSString *logo = project[@"logo"];
NSString *thumb = project[@"logo_thumbnail"];
NSString *logoURLString = (logo.length > 0) ? logo :
(thumb.length > 0) ? thumb : nil;
// Project logo
NSString *logoURLString = project[@"logo"] ?: project[@"logo_thumbnail"];
NSURL *url = [NSURL URLWithString:logoURLString];
// Async load image (simple placeholder approach)
NSIndexPath *currentIndexPath = indexPath;
NSURL *url = [NSURL URLWithString:logoURLString ?: @""];
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:url];
// Async load image safely
if (url) {
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
UIImage *image = data ? [UIImage imageWithData:data] : nil;
if (!image) return; // leave placeholder
dispatch_async(dispatch_get_main_queue(), ^{
NSIndexPath *visibleIndexPath = [collectionView indexPathForCell:cell];
if (visibleIndexPath && visibleIndexPath.item == currentIndexPath.item) {
cell.imageView.image = image ?: [UIImage systemImageNamed:@"photo"];
// Only update if the cell is still visible at this indexPath
ProjectCardCell *updateCell = (ProjectCardCell *)[collectionView cellForItemAtIndexPath:indexPath];
if (updateCell) {
updateCell.imageView.image = image;
}
});
});
}];
[task resume];
}
return cell;
}
...
...
@@ -194,6 +209,7 @@
vc.projectName = project[@"project_name"];
vc.units = project[@"unit"];
vc.drawerController = self.drawerController;
vc.projectLogo = project[@"logo"] ?: project[@"logo_thumbnail"];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController pushViewController:vc animated:YES];
...
...
@@ -212,7 +228,7 @@
#pragma mark - API
- (void)requestProjectList {
[APIClient requestProjectList:^(NSDictionary *data, NSError *error) {
[APIClient requestProjectList:^(
BOOL success,
NSDictionary *data, NSError *error) {
// debug
NSString *plainText = [NSString stringWithFormat:@"%@", data];
...
...
@@ -259,7 +275,7 @@
}
- (void)requestCompanyCode {
[APIClient requestCompanyCode:@"kita" completion:^(NSDictionary *data, NSError *error) {
[APIClient requestCompanyCode:@"kita" completion:^(
BOOL success,
NSDictionary *data, NSError *error) {
// debug
NSString *plainText = [NSString stringWithFormat:@"%@", data];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/UnitViewController.h
View file @
82cef0dc
...
...
@@ -13,5 +13,6 @@
@property
(
nonatomic
,
copy
)
NSString
*
projectId
;
@property
(
nonatomic
,
copy
)
NSString
*
projectName
;
@property
(
nonatomic
,
copy
)
NSArray
*
units
;
@property
(
nonatomic
,
copy
)
NSString
*
projectLogo
;
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/UnitViewController.mm
View file @
82cef0dc
...
...
@@ -260,13 +260,14 @@ didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *projectId = [unit[@"project_id"] description];
NSString *drawingPlanId = [unit[@"id"] description];
NSLog(@"self.projectLogo: %@", self.projectLogo);
DashboardViewController *vc = [[DashboardViewController alloc] init];
vc.projectCode = unit[@"name"] ?: @"";
vc.projectName = self.projectName;
vc.projectId = projectId ?: @"";
vc.drawingPlanId = drawingPlanId ?: @"";
vc.drawerController = self.drawerController;
vc.projectLogo = self.projectLogo;
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController pushViewController:vc animated:YES];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/AddInfoViewController.mm
View file @
82cef0dc
...
...
@@ -597,7 +597,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
// ✅ JSON ONLY
[APIClient submitAddInfo:self.issueID
remarks:self.commentTextView.text
completion:^(NSDictionary *response, NSError *error) {
completion:^(
BOOL success,
NSDictionary *response, NSError *error) {
[self handleSubmitResponse:response error:error];
}];
return;
...
...
@@ -607,7 +607,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
images:images
mediaURL:self.selectedMediaURL
mediaType:mediaType
completion:^(NSDictionary *response, NSError *error) {
completion:^(
BOOL success,
NSDictionary *response, NSError *error) {
[self handleSubmitResponse:response error:error];
}];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/AddIssue/DetailsViewController.mm
View file @
82cef0dc
...
...
@@ -957,7 +957,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
[APIClient submitUpdateIssue:updateData
images:self.addedImages
completion:^(
NSDictionary * _Nullable response, NSError * _Nullable error)
{
completion:^(
BOOL success, NSDictionary *response, NSError *error)
{
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
[self showAlertWithTitle:@"Update Failed" message:error.localizedDescription];
...
...
@@ -1043,7 +1043,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
[APIClient submitAddIssue:issueData
images:self.uploadedImages
completion:^(NSDictionary *response, NSError *error) {
completion:^(
BOOL success,
NSDictionary *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(@"❌ Submission failed: %@", error.localizedDescription);
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/AddIssue/PlanViewController.mm
View file @
82cef0dc
...
...
@@ -69,7 +69,7 @@
- (void)handleGetUnitPlan {
NSLog(@"🌐 requesting Unit Plan data...");
[APIClient requestGetUnitPlan:^(NSDictionary *data, NSError *error) {
[APIClient requestGetUnitPlan:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ Unit Plan request failed: %@", error.localizedDescription);
return;
...
...
@@ -710,7 +710,7 @@
- (void)handleSettingsByLocation:(NSString *)locationID planID:(NSString *)planID {
[APIClient requestSettingsByLocation:locationID
completion:^(NSDictionary *data, NSError *error) {
completion:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ Error requesting settings: %@", error);
return;
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/HistoryViewController.mm
View file @
82cef0dc
...
...
@@ -127,7 +127,7 @@
#pragma mark - API request/response
- (void)handleIssues {
[APIClient requestHistory:self.issueID
completion:^(NSDictionary *data, NSError *error) {
completion:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ Error requesting history: %@", error);
return;
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/IssuesViewController.mm
View file @
82cef0dc
...
...
@@ -300,7 +300,7 @@
- (void)handleGetIssue {
NSLog(@"🌐 requesting Issue data...");
[APIClient requestIssues:^(NSDictionary *data, NSError *error) {
[APIClient requestIssues:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ Issue request failed: %@", error.localizedDescription);
return;
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/WithdrawIssuesViewController.mm
View file @
82cef0dc
...
...
@@ -286,7 +286,7 @@
[searchContainer.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:50],
[searchContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8],
[searchContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8],
[searchContainer.heightAnchor constraintEqualToConstant:1
0
0],
[searchContainer.heightAnchor constraintEqualToConstant:1
2
0],
[self.searchBar.leadingAnchor constraintEqualToAnchor:searchContainer.leadingAnchor],
[self.searchBar.trailingAnchor constraintEqualToAnchor:searchContainer.trailingAnchor],
...
...
@@ -383,7 +383,7 @@
#pragma mark - Data
- (void)requestIssues {
[APIClient requestIssues:^(NSDictionary *data, NSError *error) {
[APIClient requestIssues:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) return;
NSArray *allIssues = data[@"Data"] ?: @[];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/WithdrawSingleIssueViewController.mm
View file @
82cef0dc
...
...
@@ -264,7 +264,7 @@
- (void)requestDeleteIssue:(NSString *)issueID remarks:(NSString *)remarks {
NSLog(@"🚀 Sending DELETE ISSUE for ID=%@, remarks=%@", issueID, remarks);
[APIClient requestDeleteIssue:issueID remarks:remarks completion:^(NSDictionary *data, NSError *error) {
[APIClient requestDeleteIssue:issueID remarks:remarks completion:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"Error %@", error.localizedDescription);
return;
...
...
@@ -303,7 +303,7 @@
[APIClient requestVoidIssue:ids
remarks:remarks
completion:^(NSDictionary *data, NSError *error) {
completion:^(
BOOL success,
NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"Error %@", error.localizedDescription);
return;
...
...
framework/QmsPluginFramework/QmsPluginFramework/Sync/SyncProjectViewController.mm
View file @
82cef0dc
...
...
@@ -105,6 +105,7 @@ UICollectionViewDataSource
@implementation SyncProjectViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];
self.projects = [NSMutableArray array];
self.selectedUnits = [NSMutableArray array];
...
...
@@ -480,7 +481,7 @@ didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self showLoading:YES];
[APIClient requestProjectList:^(NSDictionary *data, NSError *error) {
[APIClient requestProjectList:^(
BOOL success,
NSDictionary *data, NSError *error) {
// debug
NSString *plainText = [NSString stringWithFormat:@"%@", data];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIClient.h
View file @
82cef0dc
...
...
@@ -8,22 +8,22 @@ NS_ASSUME_NONNULL_BEGIN
+
(
void
)
requestAccessItem
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestGetUnitPlan
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestGetUnitPlan
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestSettingsByLocation
:(
NSString
*
_Nonnull
)
locationID
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
submitAddIssue
:(
NSDictionary
*
_Nonnull
)
params
images
:(
NSArray
<
UIImage
*>
*
_Nullable
)
images
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
submitUpdateIssue
:(
NSDictionary
*
_Nonnull
)
updateData
images
:(
NSArray
<
UIImage
*>
*
_Nullable
)
images
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestAppointment
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestAppointment
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestGeneralInfo
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestGeneralInfo
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
submitAppointment
:(
NSDictionary
*
)
appointmentData
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
...
...
@@ -33,52 +33,52 @@ NS_ASSUME_NONNULL_BEGIN
+
(
void
)
requestCancelAppointment
:(
id
)
appointmentId
reason
:(
NSString
*
)
reason
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestDashboardInfo
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
requestDashboardInfo
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestAnnouncement
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
requestAnnouncement
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestHistory
:(
NSString
*
)
issueID
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
submitAddInfo
:(
NSString
*
)
issueID
remarks
:(
NSString
*
)
remarks
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
uploadAddInfo
:(
NSString
*
)
issueID
remarks
:(
NSString
*
)
remarks
images
:(
NSArray
<
UIImage
*>
*
)
images
mediaURL
:(
NSURL
*
)
mediaURL
mediaType
:(
NSString
*
)
mediaType
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestIssues
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
requestIssues
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestVoidIssue
:(
id
)
issueID
remarks
:(
NSString
*
)
remarks
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestDeleteIssue
:(
id
)
issueID
remarks
:(
NSString
*
)
remarks
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestCommonArea
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestCommonArea
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestGeneralSettings
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestGeneralSettings
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestDefectMatrix
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestDefectMatrix
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestProjectList
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestProjectList
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
requestArrayImage
:(
NSArray
*
)
imageArray
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
+
(
void
)
downloadAndCacheImage
:(
NSURL
*
)
url
completion
:(
void
(
^
)(
BOOL
success
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSString
*
filePath
))
completion
;
+
(
void
)
requestCompanyCode
:(
NSString
*
)
companyCode
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
error
))
completion
;
@end
...
...
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIClient.mm
View file @
82cef0dc
This diff is collapsed.
Click to expand it.
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIConfig.h
View file @
82cef0dc
...
...
@@ -33,6 +33,13 @@ NS_ASSUME_NONNULL_BEGIN
/// JSON string form (what your APIs expect)
+
(
NSString
*
)
deviceInfoJSONString
;
//Offline
+
(
BOOL
)
handleOfflineForAPI
:(
NSString
*
)
apiName
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
//Null
+
(
NSDictionary
*
)
dictionaryByReplacingNullsWithBlanks
:(
NSDictionary
*
)
dict
;
@end
NS_ASSUME_NONNULL_END
...
...
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIConfig.mm
View file @
82cef0dc
// APIConfig.mm
#import "APIConfig.h"
#import "LocalStorage.h"
#import "NetworkManager.h"
static NSString *kBaseURL = @"https://kitadev.commudesk.com/api";
static NSString *kDrawingPlanId = @"";
...
...
@@ -89,4 +91,67 @@ static NSString *kAuthToken = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
#pragma mark - Offline Handling
+ (BOOL)handleOfflineForAPI:(NSString *)apiName
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSString *cacheKey =
[NSString stringWithFormat:@"%@_%@", apiName, [self projectId]];
if (![NetworkManager.sharedManager isConnected]) {
NSDictionary *cached = [LocalStorage loadDictionaryForKey:cacheKey];
if (cached) {
NSLog(@"🟡 Loaded from cache: %@", cacheKey);
if (completion) completion(YES, cached, nil);
} else {
NSError *offlineErr =
[NSError errorWithDomain:@"OfflineError"
code:-1
userInfo:@{
NSLocalizedDescriptionKey:
@"No network and no cached data"
}];
if (completion) completion(NO, nil, offlineErr);
}
return YES; // offline handled
}
return NO; // proceed with online request
}
#pragma mark - Null Handling
+ (NSDictionary *)dictionaryByReplacingNullsWithBlanks:(NSDictionary *)dict {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *key in dict) {
id value = dict[key];
if (value == [NSNull null]) {
result[key] = @""; // or NSNull-safe replacement
} else if ([value isKindOfClass:[NSDictionary class]]) {
result[key] = [self dictionaryByReplacingNullsWithBlanks:value];
} else if ([value isKindOfClass:[NSArray class]]) {
result[key] = [self arrayByReplacingNullsWithBlanks:value];
} else {
result[key] = value;
}
}
return result;
}
+ (NSArray *)arrayByReplacingNullsWithBlanks:(NSArray *)array {
NSMutableArray *result = [NSMutableArray array];
for (id obj in array) {
if (obj == [NSNull null]) {
[result addObject:@""]; // or other safe value
} else if ([obj isKindOfClass:[NSDictionary class]]) {
[result addObject:[self dictionaryByReplacingNullsWithBlanks:obj]];
} else if ([obj isKindOfClass:[NSArray class]]) {
[result addObject:[self arrayByReplacingNullsWithBlanks:obj]];
} else {
[result addObject:obj];
}
}
return result;
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Utilities/OfflineSync/OfflineSyncManager.mm
View file @
82cef0dc
This diff is collapsed.
Click to expand it.
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