Commit 87014f12 authored by Wei Han's avatar Wei Han

code update

parent 09b0eb2e
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* 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 */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
44006126336D83DB220E7214 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; }; 44006126336D83DB220E7214 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
705C78A9CBF3D37B370DC92C /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CB77023451E7FACEB5CCC67A /* libPods-example.a */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
...@@ -19,11 +19,11 @@ ...@@ -19,11 +19,11 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = example/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
31E3569C4DACA1583750BB4B /* 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>"; }; 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>"; };
67CF26DD341753F546BD183F /* 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>"; }; 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>"; };
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = example/AppDelegate.swift; sourceTree = "<group>"; }; 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>"; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = "<group>"; };
CB77023451E7FACEB5CCC67A /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */ /* End PBXFileReference section */
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
705C78A9CBF3D37B370DC92C /* libPods-example.a in Frameworks */, 09422FEEE292BF7FDB944B44 /* libPods-example.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
CB77023451E7FACEB5CCC67A /* libPods-example.a */, 7646DEA673059A6FBED034D5 /* libPods-example.a */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -92,8 +92,8 @@ ...@@ -92,8 +92,8 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = { BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
31E3569C4DACA1583750BB4B /* Pods-example.debug.xcconfig */, 5350E2781CCDA8D204AD92D7 /* Pods-example.debug.xcconfig */,
67CF26DD341753F546BD183F /* Pods-example.release.xcconfig */, 66DA0C9F0E73892891015312 /* Pods-example.release.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -105,13 +105,13 @@ ...@@ -105,13 +105,13 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */;
buildPhases = ( buildPhases = (
0C0B6164CF1596DDFC4F19C5 /* [CP] Check Pods Manifest.lock */, 1A63BC39C4970FBC7B74189D /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */, 13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */, 13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
1784E64423995B1E7F285F50 /* [CP] Embed Pods Frameworks */, 4C643B981BE7FEF41566F449 /* [CP] Embed Pods Frameworks */,
6A78F44E33668E0CBF927584 /* [CP] Copy Pods Resources */, 4DB8EF54BF2FC8DAD832C9D8 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
...@@ -183,7 +183,7 @@ ...@@ -183,7 +183,7 @@
shellPath = /bin/sh; 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"; 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";
}; };
0C0B6164CF1596DDFC4F19C5 /* [CP] Check Pods Manifest.lock */ = { 1A63BC39C4970FBC7B74189D /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
...@@ -205,7 +205,7 @@ ...@@ -205,7 +205,7 @@
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 = "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; showEnvVarsInLog = 0;
}; };
1784E64423995B1E7F285F50 /* [CP] Embed Pods Frameworks */ = { 4C643B981BE7FEF41566F449 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
...@@ -222,7 +222,7 @@ ...@@ -222,7 +222,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
6A78F44E33668E0CBF927584 /* [CP] Copy Pods Resources */ = { 4DB8EF54BF2FC8DAD832C9D8 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
...@@ -255,7 +255,7 @@ ...@@ -255,7 +255,7 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = { 13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 31E3569C4DACA1583750BB4B /* Pods-example.debug.xcconfig */; baseConfigurationReference = 5350E2781CCDA8D204AD92D7 /* Pods-example.debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
...@@ -283,7 +283,7 @@ ...@@ -283,7 +283,7 @@
}; };
13B07F951A680F5B00A75B9A /* Release */ = { 13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 67CF26DD341753F546BD183F /* Pods-example.release.xcconfig */; baseConfigurationReference = 66DA0C9F0E73892891015312 /* Pods-example.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
......
...@@ -632,15 +632,15 @@ ...@@ -632,15 +632,15 @@
_currentY = 16.0; _currentY = 16.0;
// === PROJECT UPDATES === // === PROJECT UPDATES ===
NSArray *announcements = self.announcements; // NSArray *announcements = self.announcements;
if (announcements.count > 0) { // if (announcements.count > 0) {
UIView *announcementSection = [self buildAnnouncementSection:announcements]; // UIView *announcementSection = [self buildAnnouncementSection:announcements];
CGRect f = announcementSection.frame; // CGRect f = announcementSection.frame;
f.origin.y = _currentY; // f.origin.y = _currentY;
announcementSection.frame = f; // announcementSection.frame = f;
[_contentContainer addSubview:announcementSection]; // [_contentContainer addSubview:announcementSection];
_currentY += CGRectGetHeight(announcementSection.frame) + 12; // _currentY += CGRectGetHeight(announcementSection.frame) + 12;
} // }
// === APPOINTMENTS === // === APPOINTMENTS ===
NSArray *appointments = mainData[@"appointment"]; NSArray *appointments = mainData[@"appointment"];
...@@ -668,7 +668,8 @@ ...@@ -668,7 +668,8 @@
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, _currentY); _scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, _currentY);
NSLog(@"✅ Dashboard UI refreshed with %lu announcements, %lu appointments, %lu issues", NSLog(@"✅ Dashboard UI refreshed with %lu announcements, %lu appointments, %lu issues",
(unsigned long)announcements.count, (unsigned long)appointments.count, (unsigned long)issues.count); // (unsigned long)announcements.count,
(unsigned long)appointments.count, (unsigned long)issues.count);
} }
- (UIView *)buildAnnouncementSection:(NSArray *)announcements { - (UIView *)buildAnnouncementSection:(NSArray *)announcements {
......
...@@ -84,7 +84,7 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica ...@@ -84,7 +84,7 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica
[self.drawerVC didMoveToParentViewController:self]; [self.drawerVC didMoveToParentViewController:self];
self.drawerLeadingConstraint = self.drawerLeadingConstraint =
[self.drawerVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:-self.drawerWidth]; [self.drawerVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:self.drawerWidth];
[self.drawerVC.view.widthAnchor constraintEqualToConstant:self.drawerWidth].active = YES; [self.drawerVC.view.widthAnchor constraintEqualToConstant:self.drawerWidth].active = YES;
[self.drawerVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; [self.drawerVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
...@@ -123,11 +123,10 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica ...@@ -123,11 +123,10 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica
#pragma mark - Drawer Actions #pragma mark - Drawer Actions
- (void)openDrawer { - (void)openDrawer {
// Make sure overlay and drawer are on top
[self.view bringSubviewToFront:self.overlayView]; [self.view bringSubviewToFront:self.overlayView];
[self.view bringSubviewToFront:self.drawerVC.view]; [self.view bringSubviewToFront:self.drawerVC.view];
self.drawerLeadingConstraint.constant = 0; self.drawerLeadingConstraint.constant = 0; // moves drawer fully into view
[UIView animateWithDuration:0.25 animations:^{ [UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded]; [self.view layoutIfNeeded];
...@@ -138,7 +137,7 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica ...@@ -138,7 +137,7 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica
} }
- (void)closeDrawer { - (void)closeDrawer {
self.drawerLeadingConstraint.constant = -self.drawerWidth; self.drawerLeadingConstraint.constant = self.drawerWidth; // moves drawer offscreen
[UIView animateWithDuration:0.25 animations:^{ [UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded]; [self.view layoutIfNeeded];
...@@ -167,12 +166,13 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica ...@@ -167,12 +166,13 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica
startX = self.mainVC.view.transform.tx; startX = self.mainVC.view.transform.tx;
} else if (pan.state == UIGestureRecognizerStateChanged) { } else if (pan.state == UIGestureRecognizerStateChanged) {
CGFloat newTx = startX + x; CGFloat newTx = startX + x;
newTx = MAX(0, newTx); // Clamp between 0 (open) and -drawerWidth (closed)
newTx = MIN(self.drawerWidth, newTx); newTx = MIN(0, newTx);
newTx = MAX(-self.drawerWidth, newTx);
CGFloat progress = newTx / self.drawerWidth; CGFloat progress = fabs(newTx / self.drawerWidth);
self.mainVC.view.transform = CGAffineTransformMakeTranslation(newTx, 0); self.mainVC.view.transform = CGAffineTransformMakeTranslation(newTx, 0);
self.drawerLeadingConstraint.constant = -self.drawerWidth + newTx; self.drawerLeadingConstraint.constant = newTx; // trailing anchor moves from +drawerWidth → 0
[self.view layoutIfNeeded]; [self.view layoutIfNeeded];
self.overlayView.alpha = progress; self.overlayView.alpha = progress;
} else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) { } else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
...@@ -181,9 +181,9 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica ...@@ -181,9 +181,9 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica
BOOL shouldOpen = NO; BOOL shouldOpen = NO;
if (fabs(velocityX) > 400) { if (fabs(velocityX) > 400) {
shouldOpen = (velocityX > 0); shouldOpen = (velocityX < 0); // left swipe opens drawer
} else { } else {
shouldOpen = currentTx > (self.drawerWidth * 0.45); shouldOpen = fabs(currentTx) > (self.drawerWidth * 0.45);
} }
if (shouldOpen) [self openDrawer]; if (shouldOpen) [self openDrawer];
......
// ProjectViewController.h
#import <UIKit/UIKit.h>
#import "DrawerController.h"
@interface ProjectViewController : UIViewController
@property (nonatomic, weak) DrawerController *drawerController;
@property (nonatomic, copy) NSString *ClientID;
@property (nonatomic, copy) NSString *ClientCode;
@property (nonatomic, copy) NSString *user_token;
@end
// ProjectViewController.mm
#import "ProjectViewController.h"
@interface ProjectViewController ()
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UILabel *titleLabel;
@end
@implementation ProjectViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.systemBackgroundColor;
[self setupHeader];
}
#pragma mark - Header Setup
- (void)setupHeader {
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.5 blue:0.6 alpha:1.0];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
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.headerView addSubview:menuButton];
[NSLayoutConstraint activateConstraints:@[
[self.headerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerView.heightAnchor constraintEqualToConstant:48],
[menuButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-16],
[menuButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[menuButton.widthAnchor constraintEqualToConstant:26],
[menuButton.heightAnchor constraintEqualToConstant:26],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
]];
}
#pragma mark - Helper
- (void)handleMenuButtonTapped {
NSLog(@"🍔 Menu button tapped");
if (self.drawerController) {
[self.drawerController toggleDrawer];
} else {
NSLog(@"⚠️ drawerController not set on DashboardViewController");
}
}
@end
// UnitViewController.h
#import <UIKit/UIKit.h>
#import "DrawerController.h"
@interface UnitViewController : UIViewController
@property (nonatomic, weak) DrawerController *drawerController;
@property (nonatomic, copy) NSString *ClientID;
@property (nonatomic, copy) NSString *ClientCode;
@property (nonatomic, copy) NSString *user_token;
@end
// UnitViewController.mm
#import "UnitViewController.h"
@interface UnitViewController ()
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UILabel *titleLabel;
@end
@implementation UnitViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.systemBackgroundColor;
[self setupHeader];
}
#pragma mark - Header Setup
- (void)setupHeader {
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.5 blue:0.6 alpha:1.0];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.backButton setImage:[UIImage 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];
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Unit";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerView addSubview:self.titleLabel];
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.headerView addSubview:menuButton];
[NSLayoutConstraint activateConstraints:@[
[self.headerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerView.heightAnchor constraintEqualToConstant:48],
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:8],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:32],
[self.backButton.heightAnchor constraintEqualToConstant:32],
[menuButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-16],
[menuButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[menuButton.widthAnchor constraintEqualToConstant:26],
[menuButton.heightAnchor constraintEqualToConstant:26],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
]];
}
#pragma mark - Helper
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)handleMenuButtonTapped {
NSLog(@"🍔 Menu button tapped");
if (self.drawerController) {
[self.drawerController toggleDrawer];
} else {
NSLog(@"⚠️ drawerController not set on DashboardViewController");
}
}
@end
...@@ -4,35 +4,45 @@ ...@@ -4,35 +4,45 @@
#import "DrawerViewController.h" #import "DrawerViewController.h"
#import "DrawerController.h" #import "DrawerController.h"
#import "NetworkManager.h" #import "NetworkManager.h"
#import "UnitViewController.h"
#import "ProjectViewController.h"
@implementation QmsPluginUI @implementation QmsPluginUI
+ (UIViewController *)makeViewController { + (UIViewController *)makeViewController {
// 0. Start network monitoring immediately
[NetworkManager sharedManager]; [NetworkManager sharedManager];
// 1. Create drawer // 1️⃣ Drawer menu
DrawerViewController *drawer = [[DrawerViewController alloc] init]; DrawerViewController *drawer = [[DrawerViewController alloc] init];
drawer.profileName = @"placeholder"; drawer.profileName = @"placeholder";
drawer.profileEmail = @"placeholder"; drawer.profileEmail = @"placeholder";
// 2. Client props // 2️⃣ Screens
ProjectViewController *project = [[ProjectViewController alloc] init]; // Landing page
UnitViewController *unit = [[UnitViewController alloc] init]; // Secondary page
DashboardViewController *dashboard = [[DashboardViewController alloc] init];
// 3️⃣ UINavigationController with landing page
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:project];
// 4️⃣ Create drawer controller wrapping nav
NSString *clientID = @"clientID_loading"; NSString *clientID = @"clientID_loading";
NSString *clientCode = @"clientCode_loading"; NSString *clientCode = @"clientCode_loading";
NSString *userToken = @"userToken_loading"; NSString *userToken = @"userToken_loading";
// 3. Root container DrawerController *drawerController = [[DrawerController alloc]
DrawerController *drawerController = initWithDrawerViewController:drawer
[[DrawerController alloc] initWithDrawerViewController:drawer
clientID:clientID clientID:clientID
clientCode:clientCode clientCode:clientCode
userToken:userToken]; userToken:userToken];
// 4. Back-reference // 5️⃣ Inject drawerController reference into all screens
if ([drawerController.mainViewController isKindOfClass:[DashboardViewController class]]) { project.drawerController = drawerController;
((DashboardViewController *)drawerController.mainViewController).drawerController = unit.drawerController = 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; return drawerController;
} }
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
#pragma mark - Detail Content #pragma mark - Detail Content
- (void)setupDetailContent { - (void)setupDetailContent {
// 1️⃣ Scroll view container
UIScrollView *scroll = [[UIScrollView alloc] init]; UIScrollView *scroll = [[UIScrollView alloc] init];
scroll.translatesAutoresizingMaskIntoConstraints = NO; scroll.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scroll]; [self.view addSubview:scroll];
...@@ -89,6 +90,7 @@ ...@@ -89,6 +90,7 @@
[container.widthAnchor constraintEqualToAnchor:scroll.widthAnchor], [container.widthAnchor constraintEqualToAnchor:scroll.widthAnchor],
]]; ]];
// 2️⃣ Stack view
UIStackView *stack = [[UIStackView alloc] init]; UIStackView *stack = [[UIStackView alloc] init];
stack.axis = UILayoutConstraintAxisVertical; stack.axis = UILayoutConstraintAxisVertical;
stack.spacing = 12; stack.spacing = 12;
...@@ -102,35 +104,48 @@ ...@@ -102,35 +104,48 @@
[stack.bottomAnchor constraintLessThanOrEqualToAnchor:container.bottomAnchor constant:-16], [stack.bottomAnchor constraintLessThanOrEqualToAnchor:container.bottomAnchor constant:-16],
]]; ]];
// 3️⃣ Unit label
UILabel *unitLabel = [[UILabel alloc] init]; UILabel *unitLabel = [[UILabel alloc] init];
unitLabel.text = self.itemData[@"unitName"]; unitLabel.text = self.itemData[@"unitName"] ?: @"-";
unitLabel.font = [UIFont boldSystemFontOfSize:22]; unitLabel.font = [UIFont boldSystemFontOfSize:22];
unitLabel.textColor = UIColor.labelColor; unitLabel.textColor = UIColor.labelColor;
unitLabel.numberOfLines = 0; unitLabel.numberOfLines = 0;
[stack addArrangedSubview:unitLabel]; [stack addArrangedSubview:unitLabel];
// spacing // 4️⃣ Spacer
UIView *spacer = [[UIView alloc] init]; UIView *spacer = [[UIView alloc] init];
[spacer.heightAnchor constraintEqualToConstant:12].active = YES; [spacer.heightAnchor constraintEqualToConstant:12].active = YES;
[stack addArrangedSubview:spacer]; [stack addArrangedSubview:spacer];
// 5️⃣ Status color
NSString *status = self.itemData[@"status"]; NSString *status = self.itemData[@"status"];
UIColor *statusColor = [self colorForStatus:status]; UIColor *statusColor = [self colorForStatus:status];
// Add rows // 6️⃣ Helper block to safely get field values
[stack addArrangedSubview:[self makeRow:@"Created Date" value:self.itemData[@"createdOn"] color:nil]]; NSString *(^safeField)(NSString *) = ^NSString *(NSString *fieldName) {
[stack addArrangedSubview:[self makeRow:@"Created By" value:self.itemData[@"createdBy"] color:nil]]; id fieldNames = self.itemData[@"raw"][@"fieldNames"];
[stack addArrangedSubview:[self makeRow:@"Uploaded On" value:self.itemData[@"raw"][@"syncedAt"] color:statusColor]]; if ([fieldNames isKindOfClass:[NSDictionary class]]) {
[stack addArrangedSubview:[self makeRow:@"Action Made" value:self.itemData[@"type"] color:nil]]; id value = fieldNames[fieldName];
[stack addArrangedSubview:[self makeRow:@"Location" value:self.itemData[@"raw"][@"fieldNames"][@"locationName"] ?: @"-" color:nil]]; if ([value isKindOfClass:[NSString class]]) {
[stack addArrangedSubview:[self makeRow:@"Category" value:self.itemData[@"raw"][@"category"][@"categoryName"] ?: @"-" color:nil]]; return value;
[stack addArrangedSubview:[self makeRow:@"Type" value:self.itemData[@"raw"][@"type"][@"typeName"] color:nil]]; }
[stack addArrangedSubview:[self makeRow:@"Issue" value:self.itemData[@"raw"][@"issueDisplay"][@"issueName"] ?: @"-" color:nil]]; }
[stack addArrangedSubview:[self makeRow:@"Comment" value:self.itemData[@"raw"][@"remarks"] ?: @"-" color:nil]]; return @"-";
};
// 7️⃣ Add rows
[stack addArrangedSubview:[self makeRow:@"Created Date" value:self.itemData[@"createdOn"] ?: @"-" color:nil]];
[stack addArrangedSubview:[self makeRow:@"Created By" value:self.itemData[@"createdBy"] ?: @"-" color:nil]];
[stack addArrangedSubview:[self makeRow:@"Uploaded On" value:self.itemData[@"raw"][@"syncedAt"] ?: @"-" color:statusColor]];
[stack addArrangedSubview:[self makeRow:@"Action Made" value:self.itemData[@"type"] ?: @"-" color:nil]];
[stack addArrangedSubview:[self makeRow:@"Location" value:safeField(@"locationName") color:nil]];
[stack addArrangedSubview:[self makeRow:@"Category" value:safeField(@"categoryName") color:nil]];
[stack addArrangedSubview:[self makeRow:@"Type" value:safeField(@"typeName") color:nil]];
[stack addArrangedSubview:[self makeRow:@"Issue" value:safeField(@"issueName") color:nil]];
[stack addArrangedSubview:[self makeRow:@"Comment" value:self.itemData[@"raw"][@"remarks"] ?: self.itemData[@"raw"][@"payload"][@"comment"] ?: @"-" color:nil]];
} }
- (UIView *)makeRow:(NSString *)title - (UIView *)makeRow:(NSString *)title
value:(NSString *)value value:(NSString *)value
color:(UIColor *)color { color:(UIColor *)color {
......
...@@ -392,12 +392,17 @@ typedef NS_ENUM(NSInteger, HistorySyncStatus) { ...@@ -392,12 +392,17 @@ typedef NS_ENUM(NSInteger, HistorySyncStatus) {
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(@"Tapped section %ld row %ld", (long)indexPath.section, (long)indexPath.row);
HistorySyncItem *selectedItem = self.filteredItems[indexPath.row]; HistorySyncItem *selectedItem = self.filteredItems[indexPath.row];
NSDictionary *safeData = [self normalizedRow:selectedItem.raw];
if (!safeData) {
NSLog(@"❌ Invalid history item tapped: %@", selectedItem.raw);
return;
}
HistoryDetailsViewController *vc = [HistoryDetailsViewController new]; HistoryDetailsViewController *vc = [HistoryDetailsViewController new];
vc.itemData = selectedItem.raw; vc.itemData = safeData;
vc.modalPresentationStyle = UIModalPresentationFullScreen; vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil]; [self presentViewController:vc animated:YES completion:nil];
} }
...@@ -450,7 +455,7 @@ typedef NS_ENUM(NSInteger, HistorySyncStatus) { ...@@ -450,7 +455,7 @@ typedef NS_ENUM(NSInteger, HistorySyncStatus) {
[self.syncAgainButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [self.syncAgainButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.syncAgainButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [self.syncAgainButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.syncAgainButton.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], [self.syncAgainButton.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
[self.syncAgainButton.heightAnchor constraintEqualToConstant:30], [self.syncAgainButton.heightAnchor constraintEqualToConstant:45],
]]; ]];
} }
...@@ -618,4 +623,23 @@ typedef NS_ENUM(NSInteger, HistorySyncStatus) { ...@@ -618,4 +623,23 @@ typedef NS_ENUM(NSInteger, HistorySyncStatus) {
hasFailedItems ? [UIColor systemBlueColor] : [UIColor lightGrayColor]; hasFailedItems ? [UIColor systemBlueColor] : [UIColor lightGrayColor];
} }
- (NSDictionary *)normalizedRow:(id)row {
if ([row isKindOfClass:[NSDictionary class]]) {
return row;
}
if ([row isKindOfClass:[NSString class]]) {
NSData *data = [(NSString *)row dataUsingEncoding:NSUTF8StringEncoding];
if (!data) return nil;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([json isKindOfClass:[NSDictionary class]]) {
return json;
}
}
return nil;
}
@end @end
...@@ -52,6 +52,7 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -52,6 +52,7 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
@property (nonatomic, strong) UIButton *downloadUnitsToggle; @property (nonatomic, strong) UIButton *downloadUnitsToggle;
@property (nonatomic, strong) SyncProgressOverlay *progressOverlay; @property (nonatomic, strong) SyncProgressOverlay *progressOverlay;
@property (nonatomic, strong) UIButton *yesBtn;
@end @end
...@@ -329,8 +330,8 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -329,8 +330,8 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
- (void)showSyncConfirmationModal { - (void)showSyncConfirmationModal {
if (self.syncModalOverlay) return; // already showing if (self.syncModalOverlay) return; // already showing
self.shouldSubmitPending = YES; self.shouldSubmitPending = NO;
self.shouldDownloadUnits = YES; self.shouldDownloadUnits = NO;
[self buildSyncModal]; [self buildSyncModal];
} }
...@@ -377,17 +378,20 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -377,17 +378,20 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
// --- Toggles --- // --- Toggles ---
self.submitPendingToggle = self.submitPendingToggle =
[self createToggleWithTitle:@"Submit all pending" [self createToggleWithTitle:@"Submit all pending"
selected:YES selected:NO
action:@selector(onSubmitPendingToggle)]; action:@selector(onSubmitPendingToggle)];
self.downloadUnitsToggle = self.downloadUnitsToggle =
[self createToggleWithTitle:@"Download all selected units" [self createToggleWithTitle:@"Download all selected units"
selected:YES selected:NO
action:@selector(onDownloadUnitsToggle)]; action:@selector(onDownloadUnitsToggle)];
// --- Buttons --- // --- Buttons ---
UIButton *noBtn = [self modalButton:@"NO" action:@selector(onSyncModalNo)]; UIButton *noBtn = [self modalButton:@"NO" action:@selector(onSyncModalNo)];
UIButton *yesBtn = [self modalButton:@"YES" action:@selector(onSyncModalYes)]; self.yesBtn = [self modalButton:@"YES" action:@selector(onSyncModalYes)];
self.yesBtn.enabled = self.shouldSubmitPending || self.shouldDownloadUnits;
self.yesBtn.alpha = self.yesBtn.enabled ? 1.0 : 0.5;
// --- Layout --- // --- Layout ---
UIStackView *stack = [[UIStackView alloc] initWithArrangedSubviews:@[ UIStackView *stack = [[UIStackView alloc] initWithArrangedSubviews:@[
...@@ -396,7 +400,7 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -396,7 +400,7 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
self.submitPendingToggle, self.submitPendingToggle,
self.downloadUnitsToggle, self.downloadUnitsToggle,
noBtn, noBtn,
yesBtn self.yesBtn
]]; ]];
stack.axis = UILayoutConstraintAxisVertical; stack.axis = UILayoutConstraintAxisVertical;
...@@ -487,12 +491,14 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -487,12 +491,14 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
self.shouldSubmitPending = !self.shouldSubmitPending; self.shouldSubmitPending = !self.shouldSubmitPending;
self.submitPendingToggle.selected = self.shouldSubmitPending; self.submitPendingToggle.selected = self.shouldSubmitPending;
[self updateToggleAppearance:self.submitPendingToggle title:@"Submit all pending"]; [self updateToggleAppearance:self.submitPendingToggle title:@"Submit all pending"];
[self updateYesButtonState];
} }
- (void)onDownloadUnitsToggle { - (void)onDownloadUnitsToggle {
self.shouldDownloadUnits = !self.shouldDownloadUnits; self.shouldDownloadUnits = !self.shouldDownloadUnits;
self.downloadUnitsToggle.selected = self.shouldDownloadUnits; self.downloadUnitsToggle.selected = self.shouldDownloadUnits;
[self updateToggleAppearance:self.downloadUnitsToggle title:@"Download all selected units"]; [self updateToggleAppearance:self.downloadUnitsToggle title:@"Download all selected units"];
[self updateYesButtonState];
} }
- (void)updateToggleAppearance:(UIButton *)btn title:(NSString *)title { - (void)updateToggleAppearance:(UIButton *)btn title:(NSString *)title {
...@@ -530,15 +536,20 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -530,15 +536,20 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
[[OfflineSyncManager shared] [[OfflineSyncManager shared]
processNextItemWithProgress:^(NSInteger step, NSInteger total, NSString *title) { processNextItemWithProgress:^(NSInteger step, NSInteger total, NSString *title) {
NSLog(@"📊 progress %ld/%ld %@", (long)step, (long)total, title);
[self.progressOverlay updateStep:step [self.progressOverlay updateStep:step
total:total total:total
title:title]; title:title];
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
NSLog(@"🎉 Offline sync COMPLETED finished=%d", finished);
self.pendingItemCount = [self loadPendingItemCount]; self.pendingItemCount = [self loadPendingItemCount];
self.historyCount = [self loadHistoryItemCount]; self.historyCount = [self loadHistoryItemCount];
if (!self.shouldDownloadUnits) {
[self finishSyncWithSuccess:finished];
}
[self refreshUI]; [self refreshUI];
}]; }];
} }
...@@ -620,4 +631,11 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -620,4 +631,11 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
return [formatter stringFromDate:date]; return [formatter stringFromDate:date];
} }
- (void)updateYesButtonState {
BOOL enabled = self.shouldSubmitPending || self.shouldDownloadUnits;
self.yesBtn.enabled = enabled;
self.yesBtn.alpha = enabled ? 1.0 : 0.5;
}
@end @end
// APIConfig.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface APIConfig : NSObject
/// Base API URL (no trailing slash)
+ (NSString *)baseURL;
/// Auth token (JWT)
+ (NSString *)authToken;
/// Convenience: baseURL + path + ?token=
+ (NSURL *)urlWithPath:(NSString *)path;
/// Dictionary form (for future flexibility)
+ (NSDictionary<NSString *, NSString *> *)deviceInfo;
/// JSON string form (what your APIs expect)
+ (NSString *)deviceInfoJSONString;
@end
NS_ASSUME_NONNULL_END
// APIConfig.mm
#import "APIConfig.h"
@implementation APIConfig
+ (NSString *)baseURL {
return @"https://kitadev.commudesk.com/api";
}
+ (NSString *)authToken {
return @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
}
+ (NSURL *)urlWithPath:(NSString *)path {
NSString *urlString =
[NSString stringWithFormat:@"%@%@?token=%@",
[self baseURL],
path,
[self authToken]];
return [NSURL URLWithString:urlString];
}
+ (NSDictionary<NSString *, NSString *> *)deviceInfo {
return @{
@"OS": @"AND",
@"IMEI": @"AND:2a2f13ff17b1cbb5",
@"OS_VERSION": @"35",
@"MODEL": @"2306EPN60G",
@"APP_VERSION": @"1.22.26"
};
}
+ (NSString *)deviceInfoJSONString {
NSData *data =
[NSJSONSerialization dataWithJSONObject:[self deviceInfo]
options:0
error:nil];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
@end
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