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
72a404a7
Commit
72a404a7
authored
Jan 26, 2026
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code update
parent
d7d2568a
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
797 additions
and
255 deletions
+797
-255
AnnounceDetailsViewController.h
...ginFramework/Announcement/AnnounceDetailsViewController.h
+18
-0
AnnounceDetailsViewController.mm
...inFramework/Announcement/AnnounceDetailsViewController.mm
+78
-0
AnnounceViewController.h
.../QmsPluginFramework/Announcement/AnnounceViewController.h
+11
-0
AnnounceViewController.mm
...QmsPluginFramework/Announcement/AnnounceViewController.mm
+79
-0
ClientAnnounceViewController.h
...uginFramework/Announcement/ClientAnnounceViewController.h
+17
-0
ClientAnnounceViewController.mm
...ginFramework/Announcement/ClientAnnounceViewController.mm
+78
-0
DrawerViewController.mm
...work/QmsPluginFramework/Dashboard/DrawerViewController.mm
+0
-228
ProjectViewController.mm
...ork/QmsPluginFramework/Dashboard/ProjectViewController.mm
+79
-27
DrawerController.h
...ginFramework/QmsPluginFramework/Drawer/DrawerController.h
+0
-0
DrawerController.mm
...inFramework/QmsPluginFramework/Drawer/DrawerController.mm
+0
-0
DrawerViewController.h
...ramework/QmsPluginFramework/Drawer/DrawerViewController.h
+0
-0
DrawerViewController.mm
...amework/QmsPluginFramework/Drawer/DrawerViewController.mm
+0
-0
HelpViewController.h
...nFramework/QmsPluginFramework/Drawer/HelpViewController.h
+16
-0
HelpViewController.mm
...Framework/QmsPluginFramework/Drawer/HelpViewController.mm
+196
-0
NotificationViewController.h
...rk/QmsPluginFramework/Drawer/NotificationViewController.h
+16
-0
NotificationViewController.mm
...k/QmsPluginFramework/Drawer/NotificationViewController.mm
+0
-0
ProfileViewController.h
...amework/QmsPluginFramework/Drawer/ProfileViewController.h
+11
-0
ProfileViewController.mm
...mework/QmsPluginFramework/Drawer/ProfileViewController.mm
+0
-0
APIClient.h
...ginFramework/QmsPluginFramework/Utilities/API/APIClient.h
+7
-0
APIClient.mm
...inFramework/QmsPluginFramework/Utilities/API/APIClient.mm
+191
-0
No files found.
framework/QmsPluginFramework/QmsPluginFramework/Announcement/AnnounceDetailsViewController.h
0 → 100644
View file @
72a404a7
// AnnounceDetailsViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
AnnouncementDetailsViewController
:
UIViewController
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Announcement/AnnounceDetailsViewController.mm
0 → 100644
View file @
72a404a7
// AnnounceDetailsViewController.mm
#import "AnnounceDetailsViewController.h"
#import "APIClient.h"
@interface AnnouncementDetailsViewController ()
// Header (existing)
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@end
@implementation AnnouncementDetailsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
//Header
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self.view addSubview:self.headerBar];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44],
]];
// Title
//need to make it detect which screen its navigating from then set differently (Project Update Details if from client announce else Announcement Details from announce)
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Announcement";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
// Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self
action:@selector(onBack)
forControlEvents:UIControlEventTouchUpInside];
for (UIView *sub in @[self.titleLabel, self.backButton]) {
sub.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:sub];
}
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
]];
}
#pragma mark - helpers
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Announcement/AnnounceViewController.h
0 → 100644
View file @
72a404a7
// AnnounceViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
AnnouncementViewController
:
UIViewController
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Announcement/AnnounceViewController.mm
0 → 100644
View file @
72a404a7
// AnnounceViewController.mm
#import "AnnounceViewController.h"
#import "APIClient.h"
@interface AnnouncementViewController ()
// Header (existing)
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@end
@implementation AnnouncementViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
//Header
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self.view addSubview:self.headerBar];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44],
]];
// Title
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Announcement";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
// Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self
action:@selector(onBack)
forControlEvents:UIControlEventTouchUpInside];
for (UIView *sub in @[self.titleLabel, self.backButton]) {
sub.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:sub];
}
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
]];
}
#pragma mark - helpers
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Announcement/ClientAnnounceViewController.h
0 → 100644
View file @
72a404a7
// ClientAnnounceViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
ClientAnnouncementViewController
:
UIViewController
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Announcement/ClientAnnounceViewController.mm
0 → 100644
View file @
72a404a7
// ClientAnnounceViewController.mm
#import "ClientAnnounceViewController.h"
#import "APIClient.h"
@interface ClientAnnouncementViewController ()
// Header (existing)
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@end
@implementation ClientAnnouncementViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
//Header
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self.view addSubview:self.headerBar];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44],
]];
// Title
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Project Update";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
// Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self
action:@selector(onBack)
forControlEvents:UIControlEventTouchUpInside];
for (UIView *sub in @[self.titleLabel, self.backButton]) {
sub.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:sub];
}
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
]];
}
#pragma mark - helpers
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DrawerViewController.mm
deleted
100644 → 0
View file @
d7d2568a
This diff is collapsed.
Click to expand it.
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/ProjectViewController.mm
View file @
72a404a7
...
@@ -5,6 +5,8 @@
...
@@ -5,6 +5,8 @@
#import "UnitViewController.h"
#import "UnitViewController.h"
#import "ImageCacheHelper.h"
#import "ImageCacheHelper.h"
static NSString * const ProfileDidUpdateNotification = @"ProfileDidUpdateNotification";
@interface ProjectCardCell : UICollectionViewCell
@interface ProjectCardCell : UICollectionViewCell
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UILabel *nameLabel;
...
@@ -111,29 +113,29 @@
...
@@ -111,29 +113,29 @@
}
}
- (void)checkAndRefreshAPIs {
- (void)checkAndRefreshAPIs {
NSLog(@"🔍 Checking credentials...");
//
NSLog(@"🔍 Checking credentials...");
NSLog(@"ClientID: %@", self.ClientID);
//
NSLog(@"ClientID: %@", self.ClientID);
NSLog(@"ClientCode: %@", self.ClientCode);
//
NSLog(@"ClientCode: %@", self.ClientCode);
NSLog(@"user_token: %@", self.user_token);
//
NSLog(@"user_token: %@", self.user_token);
//
[self showLoadingOverlay:@"Loading..."];
//
[self showLoadingOverlay:@"Loading..."];
//
if (![self isReadyToLoadDashboard]) {
//
if (![self isReadyToLoadDashboard]) {
NSLog(@"⏳ Waiting for all credentials to be ready...");
//
NSLog(@"⏳ Waiting for all credentials to be ready...");
return;
//
return;
}
//
}
//
if (_isLoadingDashboard) return;
//
if (_isLoadingDashboard) return;
//
self.isLoadingDashboard = YES;
//
self.isLoadingDashboard = YES;
//
NSLog(@"✅ All credentials ready. ClientID: %@, ClientCode: %@, user_token: %@",
//
NSLog(@"✅ All credentials ready. ClientID: %@, ClientCode: %@, user_token: %@",
self.ClientID, self.ClientCode, self.user_token);
//
self.ClientID, self.ClientCode, self.user_token);
//
//
[APIConfig setAuthTokem:self.user_token];
//
[APIConfig setAuthTokem:self.user_token];
[APIConfig setClientId:self.ClientID];
//
[APIConfig setClientId:self.ClientID];
//
self.ClientCode = @"spt";
self.ClientCode = @"spt";
[self requestCompanyCode];
[self requestCompanyCode];
}
}
...
@@ -337,12 +339,13 @@
...
@@ -337,12 +339,13 @@
- (void)requestProjectList {
- (void)requestProjectList {
[APIClient requestProjectList:^(BOOL success, NSDictionary *data, NSError *error) {
[APIClient requestProjectList:^(BOOL success, NSDictionary *data, NSError *error) {
//
debug
//
Save debug file
NSString *plainText = [NSString stringWithFormat:@"%@", data];
NSString *plainText = [NSString stringWithFormat:@"%@", data];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"projectList.txt"];
NSString *filePath = [docsPath stringByAppendingPathComponent:@"projectList.txt"];
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"📁 projectList saved as plain text to: %@", filePath);
NSLog(@"📁 projectList saved as plain text to: %@", filePath);
[self hideLoadingOverlay];
[self hideLoadingOverlay];
self.isLoadingDashboard = NO;
self.isLoadingDashboard = NO;
...
@@ -351,7 +354,6 @@
...
@@ -351,7 +354,6 @@
return;
return;
}
}
// RN parity: status_code check
if (data[@"status_code"]) {
if (data[@"status_code"]) {
NSLog(@"❌ API status error: %@", data[@"message"]);
NSLog(@"❌ API status error: %@", data[@"message"]);
return;
return;
...
@@ -369,16 +371,16 @@
...
@@ -369,16 +371,16 @@
return;
return;
}
}
if (!error) {
self.projects = projects;
self.projects = projects;
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
[self.collectionView reloadData];
// Auto-select first project if only 1
if (self.projects.count == 1) {
if (self.projects.count == 1) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
[self collectionView:self.collectionView didSelectItemAtIndexPath:indexPath];
[self collectionView:self.collectionView didSelectItemAtIndexPath:indexPath];
}
}
});
});
}
}];
}];
}
}
...
@@ -427,7 +429,57 @@
...
@@ -427,7 +429,57 @@
NSLog(@"baseURL: %@", baseURL);
NSLog(@"baseURL: %@", baseURL);
[APIConfig setBaseURL:baseURL];
[APIConfig setBaseURL:baseURL];
[self requestProjectList];
[self requestProjectList];
[self requestProfile];
}
}];
}
-(void) requestProfile {
[APIClient requestProfile:^(BOOL success, NSDictionary *data, NSError *error) {
// Save debug file
NSString *plainText = [NSString stringWithFormat:@"%@", data];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"profile.txt"];
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"📁 profile saved as plain text to: %@", filePath);
[self hideLoadingOverlay];
self.isLoadingDashboard = NO;
if (error || !data) {
NSLog(@"❌ Project list API failed: %@", error);
return;
}
if (data[@"status_code"]) {
NSLog(@"❌ API status error: %@", data[@"message"]);
return;
}
}
NSDictionary *appData = data[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"❌ API failure: %@", appData[@"message"]);
return;
}
NSDictionary *profile = data[@"Data"];
if (![profile isKindOfClass:[NSDictionary class]]) {
NSLog(@"❌ Invalid profile list format");
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
NSDictionary *profileInfo = @{
@"name": profile[@"name"] ?: @"",
@"email": profile[@"email"] ?: @"",
@"avatar": profile[@"avatar"] ?: @""
};
NSLog(@"profile info ready to be used");
[[NSNotificationCenter defaultCenter] postNotificationName:ProfileDidUpdateNotification
object:nil
userInfo:profileInfo];
});
}];
}];
}
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/D
ashboard
/DrawerController.h
→
framework/QmsPluginFramework/QmsPluginFramework/D
rawer
/DrawerController.h
View file @
72a404a7
File moved
framework/QmsPluginFramework/QmsPluginFramework/D
ashboard
/DrawerController.mm
→
framework/QmsPluginFramework/QmsPluginFramework/D
rawer
/DrawerController.mm
View file @
72a404a7
File moved
framework/QmsPluginFramework/QmsPluginFramework/D
ashboard
/DrawerViewController.h
→
framework/QmsPluginFramework/QmsPluginFramework/D
rawer
/DrawerViewController.h
View file @
72a404a7
File moved
framework/QmsPluginFramework/QmsPluginFramework/Drawer/DrawerViewController.mm
0 → 100644
View file @
72a404a7
This diff is collapsed.
Click to expand it.
framework/QmsPluginFramework/QmsPluginFramework/Drawer/HelpViewController.h
0 → 100644
View file @
72a404a7
// HelpViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
HelpViewController
:
UIViewController
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Drawer/HelpViewController.mm
0 → 100644
View file @
72a404a7
// HelpViewController.mm
#import "HelpViewController.h"
#import <WebKit/WebKit.h>
@interface HelpViewController () <WKNavigationDelegate>
// Header
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
// WebView & loading
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) UIActivityIndicatorView *spinner;
// Bottom toolbar
@property (nonatomic, strong) UIView *bottomBar;
@property (nonatomic, strong) UIButton *btnBack;
@property (nonatomic, strong) UIButton *btnHome;
@property (nonatomic, strong) UIButton *btnForward;
@end
@implementation HelpViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
[self setupWebView];
[self setupBottomBar];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerBar];
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44]
]];
// Title
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Help";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:self.titleLabel];
// Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[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.headerBar addSubview:self.backButton];
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor]
]];
}
#pragma mark - WebView
- (void)setupWebView {
self.webView = [[WKWebView alloc] initWithFrame:CGRectZero];
self.webView.navigationDelegate = self;
self.webView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.webView];
// Spinner
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge];
self.spinner.color = [UIColor systemBlueColor];
self.spinner.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.spinner];
[self.spinner startAnimating];
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
[self.webView.topAnchor constraintEqualToAnchor:self.headerBar.bottomAnchor],
[self.webView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.webView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.webView.bottomAnchor constraintEqualToAnchor:safe.bottomAnchor constant:-48], // leave space for bottom bar
[self.spinner.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
[self.spinner.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor]
]];
NSURL *url = [NSURL URLWithString:@"https://qms.support.commudesk.com/support/solutions"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
#pragma mark - Bottom Toolbar
- (void)setupBottomBar {
self.bottomBar = [[UIView alloc] init];
self.bottomBar.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0];
self.bottomBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.bottomBar];
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
[self.bottomBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.bottomBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.bottomBar.bottomAnchor constraintEqualToAnchor:safe.bottomAnchor],
[self.bottomBar.heightAnchor constraintEqualToConstant:48]
]];
// Buttons
self.btnBack = [self createBottomButtonWithImage:@"arrow.backward"];
self.btnHome = [self createBottomButtonWithImage:@"house"];
self.btnForward = [self createBottomButtonWithImage:@"arrow.forward"];
[self.btnBack addTarget:self action:@selector(webBack) forControlEvents:UIControlEventTouchUpInside];
[self.btnHome addTarget:self action:@selector(webHome) forControlEvents:UIControlEventTouchUpInside];
[self.btnForward addTarget:self action:@selector(webForward) forControlEvents:UIControlEventTouchUpInside];
NSArray *buttons = @[self.btnBack, self.btnHome, self.btnForward];
UIStackView *stack = [[UIStackView alloc] initWithArrangedSubviews:buttons];
stack.axis = UILayoutConstraintAxisHorizontal;
stack.distribution = UIStackViewDistributionFillEqually;
stack.translatesAutoresizingMaskIntoConstraints = NO;
[self.bottomBar addSubview:stack];
[NSLayoutConstraint activateConstraints:@[
[stack.topAnchor constraintEqualToAnchor:self.bottomBar.topAnchor],
[stack.leadingAnchor constraintEqualToAnchor:self.bottomBar.leadingAnchor],
[stack.trailingAnchor constraintEqualToAnchor:self.bottomBar.trailingAnchor],
[stack.bottomAnchor constraintEqualToAnchor:self.bottomBar.bottomAnchor]
]];
}
- (UIButton *)createBottomButtonWithImage:(NSString *)systemName {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
[btn setImage:[UIImage systemImageNamed:systemName] forState:UIControlStateNormal];
btn.tintColor = [UIColor blackColor];
return btn;
}
#pragma mark - WebView Navigation Actions
- (void)webBack {
if ([self.webView canGoBack]) {
[self.webView goBack];
}
}
- (void)webForward {
if ([self.webView canGoForward]) {
[self.webView goForward];
}
}
- (void)webHome {
NSURL *url = [NSURL URLWithString:@"https://qms.support.commudesk.com/support/solutions"];
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
[self.spinner startAnimating];
}
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[self.spinner stopAnimating];
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
[self.spinner stopAnimating];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert"
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark - Back
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/Drawer/NotificationViewController.h
0 → 100644
View file @
72a404a7
// NotificationViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
NotificationViewController
:
UIViewController
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Drawer/NotificationViewController.mm
0 → 100644
View file @
72a404a7
This diff is collapsed.
Click to expand it.
framework/QmsPluginFramework/QmsPluginFramework/Drawer/ProfileViewController.h
0 → 100644
View file @
72a404a7
// ProfileViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
ProfileViewController
:
UIViewController
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Drawer/ProfileViewController.mm
0 → 100644
View file @
72a404a7
This diff is collapsed.
Click to expand it.
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIClient.h
View file @
72a404a7
...
@@ -89,6 +89,13 @@ NS_ASSUME_NONNULL_BEGIN
...
@@ -89,6 +89,13 @@ NS_ASSUME_NONNULL_BEGIN
+
(
void
)
updateThirdPartyLink
:(
NSDictionary
*
)
payload
+
(
void
)
updateThirdPartyLink
:(
NSDictionary
*
)
payload
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
requestProfile
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
deleteProfile
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
editProfile
:(
NSString
*
)
name
completion
:(
void
(
^
)(
BOOL
success
,
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
@end
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/Utilities/API/APIClient.mm
View file @
72a404a7
...
@@ -2128,6 +2128,197 @@
...
@@ -2128,6 +2128,197 @@
[task resume];
[task resume];
}
}
+ (void)requestProfile:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
if ([APIConfig handleOfflineForAPI:@"Profile" completion:completion]) {
return;
}
NSURL *url = [APIConfig urlWithPath:@"/framework/owner/auth/user"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSDictionary *jsonBody = @{
@"data": @{
@"os": [APIConfig os] ,
@"information": [APIConfig deviceInfo],
}
};
NSLog(@"🌍 request profile: %@", url.absoluteString);
NSLog(@"📦 request body json: %@", jsonBody);
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:jsonBody options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON Serialization Error: %@", jsonError);
if (completion) completion(NO, nil, jsonError);
return;
}
request.HTTPBody = bodyData;
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(), ^{
completion(NO, nil, error);
});
return;
}
NSError *parseError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
NSLog(@"⚠️ JSON Parse Error: %@", parseError);
dispatch_async(dispatch_get_main_queue(), ^{
completion(NO, nil, parseError);
});
return;
}
NSString *cacheKey = [NSString stringWithFormat:@"Profile_%@", [APIConfig projectId]];
NSDictionary *safeJson = [APIConfig dictionaryByReplacingNullsWithBlanks:json];
[LocalStorage saveDictionary:safeJson forKey:cacheKey];
NSLog(@"💾 Saved to cache: %@", cacheKey);
dispatch_async(dispatch_get_main_queue(), ^{
completion(YES, json, nil);
});
}];
[task resume];
}
+ (void)deleteProfile:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/framework/owner/auth/accDeleteRequest"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSDictionary *jsonBody = @{
@"data": @{
@"os": [APIConfig os] ,
@"information": [APIConfig deviceInfo],
}
};
NSLog(@"🌍 delete profile: %@", url.absoluteString);
NSLog(@"📦 delete body json: %@", jsonBody);
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:jsonBody options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON Serialization Error: %@", jsonError);
if (completion) completion(NO, nil, jsonError);
return;
}
request.HTTPBody = bodyData;
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(), ^{
completion(NO, nil, error);
});
return;
}
NSError *parseError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
NSLog(@"⚠️ JSON Parse Error: %@", parseError);
dispatch_async(dispatch_get_main_queue(), ^{
completion(NO, nil, parseError);
});
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
completion(YES, json, nil);
});
}];
[task resume];
}
+ (void)editProfile:(NSString *)name
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/framework/owner/auth/editUser"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
NSDictionary *jsonBody = @{
@"data": @{
@"name": name ?: @"",
@"language": @"2",
@"os": [APIConfig os] ,
@"information": [APIConfig deviceInfo],
}
};
NSLog(@"🌍 edit profile: %@", url.absoluteString);
NSLog(@"📦 edit profile json: %@", jsonBody);
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:jsonBody options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON Serialization Error: %@", jsonError);
if (completion) completion(NO, nil, jsonError);
return;
}
request.HTTPBody = bodyData;
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(), ^{
completion(NO, nil, error);
});
return;
}
NSError *parseError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
NSLog(@"⚠️ JSON Parse Error: %@", parseError);
dispatch_async(dispatch_get_main_queue(), ^{
completion(NO, nil, parseError);
});
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
completion(YES, json, nil);
});
}];
[task resume];
}
#pragma mark - Helper Methods
#pragma mark - Helper Methods
+ (NSString *)multipartFormField:(NSString *)name value:(NSString *)value boundary:(NSString *)boundary {
+ (NSString *)multipartFormField:(NSString *)name value:(NSString *)value boundary:(NSString *)boundary {
...
...
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