Commit 4a7abd98 authored by Wei Han's avatar Wei Han

code update

parent 87014f12
......@@ -7,8 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
09422FEEE292BF7FDB944B44 /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7646DEA673059A6FBED034D5 /* libPods-example.a */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
305DBAC1A0BEA3CAED44A62D /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20C2E11D8F9CB707F74FE9BB /* libPods-example.a */; };
44006126336D83DB220E7214 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
......@@ -19,12 +19,12 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = "<group>"; };
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = example/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
5350E2781CCDA8D204AD92D7 /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = "<group>"; };
66DA0C9F0E73892891015312 /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = "<group>"; };
20C2E11D8F9CB707F74FE9BB /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = example/AppDelegate.swift; sourceTree = "<group>"; };
7646DEA673059A6FBED034D5 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = "<group>"; };
A73ECAAA402D2F3FA2A038B4 /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F58A99A1418BFFCA17EA3A73 /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -32,7 +32,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
09422FEEE292BF7FDB944B44 /* libPods-example.a in Frameworks */,
305DBAC1A0BEA3CAED44A62D /* libPods-example.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -55,7 +55,7 @@
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
7646DEA673059A6FBED034D5 /* libPods-example.a */,
20C2E11D8F9CB707F74FE9BB /* libPods-example.a */,
);
name = Frameworks;
sourceTree = "<group>";
......@@ -92,8 +92,8 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
5350E2781CCDA8D204AD92D7 /* Pods-example.debug.xcconfig */,
66DA0C9F0E73892891015312 /* Pods-example.release.xcconfig */,
F58A99A1418BFFCA17EA3A73 /* Pods-example.debug.xcconfig */,
A73ECAAA402D2F3FA2A038B4 /* Pods-example.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
......@@ -105,13 +105,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */;
buildPhases = (
1A63BC39C4970FBC7B74189D /* [CP] Check Pods Manifest.lock */,
448EFC1B200E72FABB8D5D7E /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
4C643B981BE7FEF41566F449 /* [CP] Embed Pods Frameworks */,
4DB8EF54BF2FC8DAD832C9D8 /* [CP] Copy Pods Resources */,
18D01E9BF38825650F353B4D /* [CP] Embed Pods Frameworks */,
CCF6FD120FD8E8FD6C5FCB1F /* [CP] Copy Pods Resources */,
);
buildRules = (
);
......@@ -183,46 +183,46 @@
shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
};
1A63BC39C4970FBC7B74189D /* [CP] Check Pods Manifest.lock */ = {
18D01E9BF38825650F353B4D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-example-checkManifestLockResult.txt",
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
4C643B981BE7FEF41566F449 /* [CP] Embed Pods Frameworks */ = {
448EFC1B200E72FABB8D5D7E /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-example-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
4DB8EF54BF2FC8DAD832C9D8 /* [CP] Copy Pods Resources */ = {
CCF6FD120FD8E8FD6C5FCB1F /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
......@@ -255,7 +255,7 @@
/* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5350E2781CCDA8D204AD92D7 /* Pods-example.debug.xcconfig */;
baseConfigurationReference = F58A99A1418BFFCA17EA3A73 /* Pods-example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
......@@ -283,7 +283,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 66DA0C9F0E73892891015312 /* Pods-example.release.xcconfig */;
baseConfigurationReference = A73ECAAA402D2F3FA2A038B4 /* Pods-example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
......
......@@ -8,32 +8,32 @@
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
......
......@@ -376,8 +376,7 @@
#pragma mark - Api
- (void)requestAccessItem{
[APIClient requestAccessItem:@"135"
completion:^(BOOL success, NSDictionary *data, NSError *error) {
[APIClient requestAccessItem:^(BOOL success, NSDictionary *data, NSError *error) {
NSLog(@"📦 Received General Info Data: %@", data);
NSDictionary *general = data[@"Data"];
......
......@@ -15,6 +15,11 @@ NS_ASSUME_NONNULL_BEGIN
clientCode:(NSString *)clientCode
userToken:(NSString *)userToken;
@property (nonatomic, copy) NSString *projectCode;
@property (nonatomic, copy) NSString *projectName;
@property (nonatomic, copy) NSString *projectId;
@property (nonatomic, copy) NSString *drawingPlanId;
@end
NS_ASSUME_NONNULL_END
......@@ -13,6 +13,7 @@
#import "AccessItemViewController.h"
#import "OfflineSyncManager.h"
#import "LocalStorage.h"
#import "APIConfig.h"
@interface DashboardViewController ()
......@@ -29,8 +30,6 @@
@property (nonatomic, assign) NSInteger intPendingAccessCount;
@property (nonatomic, assign) BOOL bln_ReminderPA;
@property (nonatomic, assign) BOOL bln_POASignOff;
@property (nonatomic, strong) NSString *projectCode;
@property (nonatomic, strong) NSString *projectName;
@property (nonatomic, strong) UIImage *headerBackgroundImage;
@property (nonatomic, strong) NSArray *announcements;
@property (nonatomic, strong) UIView *loadingOverlay;
......@@ -41,6 +40,7 @@
@property (nonatomic, strong) UILabel *projectNameLabel;
@property (nonatomic, strong) UILabel *unitNameLabel;
@property (nonatomic, strong) UIButton *infoButton;
@property (nonatomic, strong) UIButton *backButton;
@end
......@@ -67,14 +67,14 @@
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];
_sectionViews = [NSMutableDictionary dictionary];
[APIConfig setProjectId:self.projectId];
[APIConfig setDrawingPlanId:self.drawingPlanId];
[self setupHeader];
[self setupScrollContent];
[self setupFooter];
self.projectCode = @"PTD197656";
self.projectName = @"Ara E`Residence Dev";
[self showLoadingOverlay:@"Loading dashboard..."];
[self checkAndRefreshAPIs];
......@@ -90,6 +90,12 @@
NSLog(@"Dashboard loaded, refreshing data");
[self refreshDashboardContent];
NSLog(@"in viewWillAppear ClientID: %@, ClientCode: %@, user_token: %@", self.ClientID, self.ClientCode, self.user_token);
self.navigationController.navigationBarHidden = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.navigationController.navigationBarHidden = YES;
}
- (void)checkAndRefreshAPIs {
......@@ -302,7 +308,24 @@
self.unitNameLabel.text = @"";
});
});
}
self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"]
forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self
action:@selector(onBack)
forControlEvents:UIControlEventTouchUpInside];
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerView 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],
]];
}
- (void)handleBackButtonTapped {
......@@ -1292,4 +1315,8 @@
[self checkAndRefreshAPIs];
}
- (void)onBack {
[self.navigationController popViewControllerAnimated:YES];
}
@end
......@@ -10,4 +10,8 @@
@property (nonatomic, copy) NSString *ClientCode;
@property (nonatomic, copy) NSString *user_token;
@property (nonatomic, copy) NSString *projectId;
@property (nonatomic, copy) NSString *projectName;
@property (nonatomic, copy) NSArray *units;
@end
// UnitViewController.mm
#import "UnitViewController.h"
#import "DashboardViewController.h"
@interface UnitViewController () <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
@interface UnitViewController ()
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UISearchBar *searchBar;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, copy) NSArray *filteredUnits;
@end
@implementation UnitViewController
......@@ -12,8 +20,30 @@
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.systemBackgroundColor;
self.filteredUnits = self.units;
if (self.filteredUnits.count == 1){
NSDictionary *unit = self.filteredUnits.firstObject;
dispatch_async(dispatch_get_main_queue(), ^{
[self openUnit:unit];
});
}
[self setupHeader];
[self setupSearchBar];
[self setupTableView];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.navigationController.navigationBarHidden = YES;
}
#pragma mark - Header Setup
......@@ -34,7 +64,7 @@
[self.headerView addSubview:self.backButton];
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Unit";
self.titleLabel.text = self.projectName ?: @"";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
......@@ -68,9 +98,152 @@
]];
}
#pragma mark - Search Bar
- (void)setupSearchBar {
self.searchBar = [[UISearchBar alloc] init];
self.searchBar.placeholder = @"Search";
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchBar.delegate = self;
self.searchBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.searchBar];
[NSLayoutConstraint activateConstraints:@[
[self.searchBar.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:8],
[self.searchBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:16],
[self.searchBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16],
[self.searchBar.heightAnchor constraintEqualToConstant:44]
]];
}
- (void)searchBar:(UISearchBar *)searchBar
textDidChange:(NSString *)searchText {
if (searchText.length == 0) {
self.filteredUnits = self.units;
} else {
NSPredicate *predicate =
[NSPredicate predicateWithBlock:^BOOL(NSDictionary *unit, NSDictionary *bindings) {
NSString *name = unit[@"unit"] ?: @"";
return [name localizedCaseInsensitiveContainsString:searchText];
}];
self.filteredUnits = [self.units filteredArrayUsingPredicate:predicate];
}
[self.tableView reloadData];
}
#pragma mark - Table View
- (void)setupTableView {
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero
style:UITableViewStylePlain];
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundColor = UIColor.systemBackgroundColor;
[self.tableView registerClass:UITableViewCell.class
forCellReuseIdentifier:@"UnitCell"];
[self.view addSubview:self.tableView];
[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]
]];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.filteredUnits.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:@"UnitCell"
forIndexPath:indexPath];
// ---- Reset reused cell ----
for (UIView *subview in cell.contentView.subviews) {
[subview removeFromSuperview];
}
NSDictionary *unit = self.filteredUnits[indexPath.row];
// ---- Label ----
UILabel *label = [[UILabel alloc] init];
label.text = unit[@"unit"] ?: unit[@"name"] ?: @"";
label.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
label.translatesAutoresizingMaskIntoConstraints = NO;
// ---- Arrow ----
UIImageView *arrow = [[UIImageView alloc] initWithImage:
[UIImage systemImageNamed:@"chevron.right"]];
arrow.tintColor = UIColor.systemGrayColor;
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];
// ---- Constraints ----
[NSLayoutConstraint activateConstraints:@[
// Label
[label.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:16],
[label.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor],
[label.trailingAnchor constraintEqualToAnchor:arrow.leadingAnchor constant:-8],
// Arrow
[arrow.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-12],
[arrow.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor],
[arrow.widthAnchor constraintEqualToConstant:12],
[arrow.heightAnchor constraintEqualToConstant:18],
]];
return cell;
}
- (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.contentView.frame =
CGRectInset(cell.contentView.frame, 16, 8);
}
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 64;
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *unit = self.filteredUnits[indexPath.row];
NSLog(@"🏠 Selected unit: %@", unit[@"unit"]);
[self openUnit:unit];
}
#pragma mark - Helper
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
[self.navigationController popViewControllerAnimated:YES];
}
- (void)handleMenuButtonTapped {
......@@ -78,8 +251,24 @@
if (self.drawerController) {
[self.drawerController toggleDrawer];
} else {
NSLog(@"⚠️ drawerController not set on DashboardViewController");
NSLog(@"⚠️ drawerController not set on UnitViewController");
}
}
- (void)openUnit:(NSDictionary *)unit {
NSLog(@"🏠 Auto-opening unit: %@", unit[@"unit"]);
NSString *projectId = [unit[@"project_id"] description];
NSString *drawingPlanId = [unit[@"id"] description];
DashboardViewController *vc = [[DashboardViewController alloc] init];
vc.projectCode = unit[@"name"] ?: @"";
vc.projectName = self.projectName;
vc.projectId = projectId ?: @"";
vc.drawingPlanId = drawingPlanId ?: @"";
vc.drawerController = self.drawerController;
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController pushViewController:vc animated:YES];
}
@end
......@@ -710,7 +710,6 @@
- (void)handleSettingsByLocation:(NSString *)locationID planID:(NSString *)planID {
[APIClient requestSettingsByLocation:locationID
projectID:@"8"
completion:^(NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ Error requesting settings: %@", error);
......
......@@ -18,8 +18,8 @@
drawer.profileEmail = @"placeholder";
// 2️⃣ Screens
ProjectViewController *project = [[ProjectViewController alloc] init]; // Landing page
UnitViewController *unit = [[UnitViewController alloc] init]; // Secondary page
ProjectViewController *project = [[ProjectViewController alloc] init]; // Landing page
UnitViewController *unit = [[UnitViewController alloc] init]; // Secondary page
DashboardViewController *dashboard = [[DashboardViewController alloc] init];
// 3️⃣ UINavigationController with landing page
......@@ -36,16 +36,15 @@
clientCode:clientCode
userToken:userToken];
// 5️⃣ Inject drawerController reference into all screens
// 5️⃣ Assign main content (nav) to drawerController
[drawerController setValue:nav forKey:@"_mainVC"];
// 6️⃣ Inject drawerController reference into all screens
project.drawerController = drawerController;
unit.drawerController = drawerController;
dashboard.drawerController = drawerController;
// 6️⃣ Replace mainVC in DrawerController with nav
[drawerController setValue:nav forKey:@"_mainVC"]; // or update your property to accept UINavigationController
return drawerController;
}
@end
......@@ -6,14 +6,12 @@ NS_ASSUME_NONNULL_BEGIN
@interface APIClient : NSObject
+ (void)requestAccessItem:(NSString *)unitId
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
+ (void)requestAccessItem:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
+ (void)requestGetUnitPlan:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion;
+ (void)requestSettingsByLocation:(NSString * _Nonnull)locationID
projectID:(NSString * _Nonnull)projectID
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion;
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion;
+ (void)submitAddIssue:(NSDictionary * _Nonnull)params
images:(NSArray<UIImage *> * _Nullable)images
......@@ -79,6 +77,9 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)downloadAndCacheImage:(NSURL *)url
completion:(void (^)(BOOL success))completion;
+ (void)requestCompanyCode:(NSString *)companyCode
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion;
@end
NS_ASSUME_NONNULL_END
......@@ -4,8 +4,7 @@
@implementation APIClient
+ (void)requestAccessItem:(NSString *)unitId
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
+ (void)requestAccessItem:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/owner/plan/getAccessItem"];
......@@ -15,8 +14,8 @@
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"drawing_plan_id": unitId ?: @"",
@"os": [APIConfig os] ,
@"drawing_plan_id": [APIConfig drawingPlanId] ?: @"",
@"information": [APIConfig deviceInfo],
}
};
......@@ -97,8 +96,8 @@
};
// 🧩 Add POST fields
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[drawing_plan_id]",@"135");
appendFormField(@"data[os]", [APIConfig os] );
appendFormField(@"data[drawing_plan_id]",[APIConfig drawingPlanId] );
// You can reuse your existing getDeviceInfo() method to produce this JSON string
NSString *deviceInfo = [APIConfig deviceInfoJSONString];
......@@ -156,7 +155,6 @@
}
+ (void)requestSettingsByLocation:(NSString *)locationID
projectID:(NSString *)projectID
completion:(void (^)(NSDictionary *data, NSError *error))completion {
NSURL *url = [APIConfig urlWithPath:@"/owner/plan/getGeneralSettingByLocation"];
......@@ -183,8 +181,8 @@
};
// 🧩 Add POST fields
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[project_id]", projectID ?: @"0");
appendFormField(@"data[os]", [APIConfig os] );
appendFormField(@"data[project_id]", [APIConfig projectId] ?: @"0");
appendFormField(@"data[location_id]", locationID ?: @"0");
NSString *deviceInfo = [APIConfig deviceInfoJSONString];
......@@ -277,7 +275,7 @@
}
// 🔹 Append OS info
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[os]", [APIConfig os] );
// 🔹 Append images
if (images.count > 0) {
......@@ -371,7 +369,7 @@
}
// 🔹 Always include OS
appendFormField(@"data[plan_id]", @"135");
appendFormField(@"data[plan_id]", [APIConfig drawingPlanId] );
appendFormField(@"data[location_id]", updateData[@"location_id"]);
appendFormField(@"data[issue_id]", updateData[@"issue_id"]);
appendFormField(@"data[issue_setting_id]", updateData[@"issue_setting_id"]);
......@@ -455,9 +453,9 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"project_id": @"8",
@"drawing_plan_id": @"135"
@"os": [APIConfig os] ,
@"project_id": [APIConfig projectId] ,
@"drawing_plan_id": [APIConfig drawingPlanId]
}
};
......@@ -519,8 +517,8 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"drawing_plan_id": @"135"
@"os": [APIConfig os] ,
@"drawing_plan_id": [APIConfig drawingPlanId]
}
};
......@@ -708,7 +706,7 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"project_id": @"8",
@"project_id": [APIConfig projectId] ,
@"appointment_id": appointmentId,
@"reason": reason
}
......@@ -779,8 +777,8 @@
};
// Add form fields
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[drawing_plan_id]", @"135");
appendFormField(@"data[os]", [APIConfig os] );
appendFormField(@"data[drawing_plan_id]", [APIConfig drawingPlanId] );
NSString *infoJson = @"{\"OS\":\"AND\",\"IMEI\":\"AND:2a2f13ff17b1cbb5\",\"OS_VERSION\":\"35\",\"MODEL\":\"2306EPN60G\",\"APP_VERSION\":\"1.22.26\"}";
appendFormField(@"data[information]", infoJson);
......@@ -836,8 +834,8 @@
};
// Add form fields (same as DashboardInfo)
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[project_id]", @"8");
appendFormField(@"data[os]", [APIConfig os] );
appendFormField(@"data[project_id]", [APIConfig projectId] );
appendFormField(@"data[client_id]", @"3");
NSString *infoJson = @"{\"OS\":\"AND\",\"IMEI\":\"AND:2a2f13ff17b1cbb5\",\"OS_VERSION\":\"35\",\"MODEL\":\"2306EPN60G\",\"APP_VERSION\":\"1.22.26\"}";
......@@ -897,7 +895,7 @@
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"os": [APIConfig os] ,
@"issue_id": issueID,
@"information": [APIConfig deviceInfo],
}
......@@ -964,7 +962,7 @@
@"data": @{
@"issue_id": issueID,
@"remarks": remarks,
@"os": @"AND",
@"os": [APIConfig os] ,
@"full_response": @"false",
@"information": [APIConfig deviceInfo],
}
......@@ -1045,7 +1043,7 @@
// 🔹 Append OS info
appendFormField(@"data[issue_id]", issueID ?: @"");
appendFormField(@"data[remarks]", remarks ?: @"");
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[os]", [APIConfig os] );
// 🔹 Append images
if (images.count > 0) {
......@@ -1145,8 +1143,8 @@
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"drawing_plan_id": @"135",
@"os": [APIConfig os] ,
@"drawing_plan_id": [APIConfig drawingPlanId] ,
@"information": [APIConfig deviceInfo],
}
};
......@@ -1218,7 +1216,7 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"os": [APIConfig os] ,
@"issue_id": issueArray,
@"remarks": remarksSafe
}
......@@ -1284,7 +1282,7 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"os": [APIConfig os] ,
@"issue_id": issueID ?: @"",
@"remarks": remarks ?: @""
}
......@@ -1348,8 +1346,8 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"project_id": @"8",
@"os": [APIConfig os] ,
@"project_id": [APIConfig projectId] ,
@"information": [APIConfig deviceInfo],
}
};
......@@ -1412,8 +1410,8 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"project_id": @"8",
@"os": [APIConfig os] ,
@"project_id": [APIConfig projectId] ,
@"information": [APIConfig deviceInfo]
}
};
......@@ -1476,9 +1474,9 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"project_id": @"8",
@"drawing_plan_id": @"135",
@"os": [APIConfig os] ,
@"project_id": [APIConfig projectId] ,
@"drawing_plan_id": [APIConfig drawingPlanId] ,
@"information": [APIConfig deviceInfo]
}
};
......@@ -1541,7 +1539,7 @@
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"os": [APIConfig os] ,
}
};
......@@ -1722,6 +1720,69 @@
// [task resume];
// }
+ (void)requestCompanyCode:(NSString *)companyCode
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; {
NSString *urlString = @"https://kitadev.commudesk.com/api/companycode/get";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSDictionary *jsonBody = @{
@"data": @{
@"os": [APIConfig os],
@"company_code": companyCode.length > 0
? [companyCode lowercaseString]
: @"",
@"information": [APIConfig deviceInfo],
}
};
// ✅ Convert dictionary → NSData
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:jsonBody options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON Serialization Error: %@", jsonError);
if (completion) completion(nil, jsonError);
return;
}
request.HTTPBody = bodyData;
// 🧭 Debug logs
NSLog(@"🌍 URL: %@", urlString);
NSLog(@"📦 Body JSON: %@", jsonBody);
// ✅ Make request
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Network Error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(nil, error);
});
return;
}
NSError *jsonParseError;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonParseError];
if (jsonParseError) {
NSLog(@"⚠️ JSON Parse Error: %@", jsonParseError);
} else {
NSLog(@"✅ Company Code API Response:\n%@", jsonResponse);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(jsonResponse, jsonParseError);
});
}];
[task resume];
}
#pragma mark - Helper Methods
+ (NSString *)multipartFormField:(NSString *)name value:(NSString *)value boundary:(NSString *)boundary {
return [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"data[%@]\"\r\n\r\n%@\r\n", boundary, name, value];
......
......@@ -5,11 +5,24 @@ NS_ASSUME_NONNULL_BEGIN
@interface APIConfig : NSObject
//os
+ (NSString *)os;
/// Base API URL (no trailing slash)
+ (NSString *)baseURL;
+ (void)setBaseURL:(NSString *)baseURL;
//drawingplan
+ (NSString *)drawingPlanId;
+ (void)setDrawingPlanId:(NSString *)drawingPlanId;
//projectid
+ (NSString *)projectId;
+ (void)setProjectId:(NSString *)projectId;
/// Auth token (JWT)
+ (NSString *)authToken;
+ (void)setAuthTokem:(NSString *)authToken;
/// Convenience: baseURL + path + ?token=
+ (NSURL *)urlWithPath:(NSString *)path;
......
// APIConfig.mm
#import "APIConfig.h"
static NSString *kBaseURL = @"https://kitadev.commudesk.com/api";
static NSString *kDrawingPlanId = @"";
static NSString *kProjectId = @"";
static NSString *kAuthToken = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
@implementation APIConfig
#pragma mark - OS
+ (NSString *)os {
return @"AND";
}
#pragma mark - URL
+ (NSString *)baseURL {
return @"https://kitadev.commudesk.com/api";
return kBaseURL;
}
+ (void)setBaseURL:(NSString *)baseURL {
if (baseURL.length > 0) {
kBaseURL = [baseURL copy];
NSLog(@"🌐 API baseURL set to: %@", kBaseURL);
}
}
#pragma mark - Project Id
+ (NSString *)projectId {
return kProjectId;
}
+ (void)setProjectId:(NSString *)projectId {
if (projectId.length > 0) {
kProjectId = [projectId copy];
NSLog(@"🌐 API projectId set to: %@", kProjectId);
}
}
#pragma mark - Drawing Plan Id
+ (NSString *)drawingPlanId {
return kDrawingPlanId;
}
+ (void)setDrawingPlanId:(NSString *)drawingPlanId {
if (drawingPlanId.length > 0) {
kDrawingPlanId = [drawingPlanId copy];
NSLog(@"🌐 API drawing plan id set to: %@", kDrawingPlanId);
}
}
#pragma mark - AuthToken
+ (NSString *)authToken {
return @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
return kAuthToken;
}
+ (void)setAuthTokem:(NSString *)authToken {
if (authToken.length > 0) {
kAuthToken = [authToken copy];
NSLog(@"🌐 API drawing plan id set to: %@", kAuthToken);
}
}
+ (NSURL *)urlWithPath:(NSString *)path {
......@@ -22,7 +71,8 @@
+ (NSDictionary<NSString *, NSString *> *)deviceInfo {
return @{
@"OS": @"AND",
@"OS": [self os],
@"drawing_plan_id": [self drawingPlanId],
@"IMEI": @"AND:2a2f13ff17b1cbb5",
@"OS_VERSION": @"35",
@"MODEL": @"2306EPN60G",
......
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
// ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
QmsRootView()
.ignoresSafeArea() // important for navigation & drawer
}
}
#Preview {
ContentView()
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
// QmRootView.swift
import SwiftUI
import QmsPluginFramework
struct QmsRootView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
return QmsPluginUI.makeViewController()
}
func updateUIViewController(
_ uiViewController: UIViewController,
context: Context
) {
// no-op
}
}
// testAppApp.swift
import SwiftUI
@main
struct testAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
......@@ -8,32 +8,32 @@
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment