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
1c49cf8f
Commit
1c49cf8f
authored
Oct 22, 2025
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
UI update
parent
98fa8e66
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
208 additions
and
132 deletions
+208
-132
README.md
README.md
+1
-1
Info.plist
...PluginFramework/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
DashboardAPIClient.h
...amework/QmsPluginFramework/Dashboard/DashboardAPIClient.h
+1
-1
DashboardAPIClient.mm
...mework/QmsPluginFramework/Dashboard/DashboardAPIClient.mm
+123
-113
DashboardViewController.mm
...k/QmsPluginFramework/Dashboard/DashboardViewController.mm
+73
-7
Info.plist
ios/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
No files found.
README.md
View file @
1c49cf8f
...
...
@@ -21,7 +21,7 @@ xcodebuild -create-xcframework \
## To use in test app
1.
add this line under dependencies in testApp's package.json
"QmsPlugin": "git+http://convep.ddns.me:20000/WeiHan/weihan-plugin.git",
-
"QmsPlugin": "git+http://convep.ddns.me:20000/WeiHan/weihan-plugin.git",
2.
then run yarn install
...
...
framework/QmsPluginFramework/QmsPluginFramework.xcframework/Info.plist
View file @
1c49cf8f
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
1c49cf8f
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
1c49cf8f
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardAPIClient.h
View file @
1c49cf8f
...
...
@@ -4,10 +4,10 @@
@interface
DashboardAPIClient
:
NSObject
+
(
void
)
fetchDashboardSummary
:(
void
(
^
)(
NSDictionary
*
data
))
completion
;
+
(
void
)
fetchAnnouncement
:(
void
(
^
)(
NSArray
*
data
))
completion
;
+
(
void
)
fetchAppointments
:(
void
(
^
)(
NSArray
*
data
))
completion
;
+
(
void
)
fetchIssues
:(
void
(
^
)(
NSArray
*
data
))
completion
;
+
(
void
)
fetchHeaderInfo
:(
void
(
^
)(
NSDictionary
*
data
))
completion
;
+
(
void
)
fetchDashboardInfo
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchAnnouncement
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
@end
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardAPIClient.mm
View file @
1c49cf8f
...
...
@@ -4,176 +4,186 @@
@implementation DashboardAPIClient
+ (void)fetchDashboardSummary:(void (^)(NSDictionary *))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/users/1"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/users/1"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
}
+ (void)fetchAppointments:(void (^)(NSArray *))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/todos?_limit=5"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/todos?_limit=5"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
}
+ (void)fetchIssues:(void (^)(NSArray *))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/comments?_limit=5"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/comments?_limit=5"];
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) { completion(nil); return; }
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
completion(json);
});
}] resume];
}
+ (void)fetchHeaderInfo:(void (^)(NSDictionary *data))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/photos/1"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Header info fetch failed: %@", error);
if (completion) completion(@{});
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (completion) completion(json);
}];
[task resume];
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/photos/1"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Header info fetch failed: %@", error);
if (completion) completion(@{});
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (completion) completion(json);
}];
[task resume];
}
+ (void)fetchDashboardInfo:(void (^)(NSDictionary *data, NSError *error))completion {
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/plan/getIssueUpdateAppointmentInfo";
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/plan/getIssueUpdateAppointmentInfo";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 🪪 Authorization header
NSString *token = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
[request setValue:[NSString stringWithFormat:@"Bearer %@", token] forHTTPHeaderField:@"Authorization"];
// 🧱 Create multipart form-data body
NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
NSMutableData *body = [NSMutableData data];
// Helper block to append fields
void (^appendFormField)(NSString *, NSString *) = ^(NSString *key, NSString *value) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", value] dataUsingEncoding:NSUTF8StringEncoding]];
};
// Add form fields
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[drawing_plan_id]", @"135");
NSString *infoJson = @"{\"OS\":\"AND\",\"IMEI\":\"AND:2a2f13ff17b1cbb5\",\"OS_VERSION\":\"35\",\"MODEL\":\"2306EPN60G\",\"APP_VERSION\":\"1.22.26\"}";
appendFormField(@"data[information]", infoJson);
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
// 🌍 Debug logs
NSLog(@"🌍 URL: %@", urlString);
NSLog(@"🪪 Authorization: Bearer %@", token);
NSLog(@"📦 Body:\n%@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Network error: %@", error);
if (completion) completion(nil, error);
return;
}
NSError *jsonErr;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
NSLog(@"🧩 Dashboard Info response: %@", json);
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(json, jsonErr);
});
}
}];
[task resume];
}
+ (void)fetchAnnouncement:(void (^)(NSDictionary *data, NSError *error))completion {
// ✅ Keep token in URL
NSString *urlString = @"https://kitadev.commudesk.com/api/clientAnnouncement?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 🪪 Authorization header
NSString *token = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
[request setValue:[NSString stringWithFormat:@"Bearer %@", token] forHTTPHeaderField:@"Authorization"];
// 🧱 Create multipart form-data body
// 🧱 multipart/form-data setup
NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
NSMutableData *body = [NSMutableData data];
// Helper block to append fields
void (^appendFormField)(NSString *, NSString *) = ^(NSString *key, NSString *value) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", value] dataUsingEncoding:NSUTF8StringEncoding]];
};
// Add form fields
// Add form fields
(same as DashboardInfo)
appendFormField(@"data[os]", @"AND");
appendFormField(@"data[drawing_plan_id]", @"135");
appendFormField(@"data[project_id]", @"8");
appendFormField(@"data[client_id]", @"3");
NSString *infoJson = @"{\"OS\":\"AND\",\"IMEI\":\"AND:2a2f13ff17b1cbb5\",\"OS_VERSION\":\"35\",\"MODEL\":\"2306EPN60G\",\"APP_VERSION\":\"1.22.26\"}";
appendFormField(@"data[information]", infoJson);
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
// 🌍 Debug logs
NSLog(@"🌍 URL: %@", urlString);
NSLog(@"🪪 Authorization: Bearer %@", token);
NSLog(@"📦 Body:\n%@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Network error: %@", error);
if (completion) completion(nil, error);
return;
}
NSError *jsonErr;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
NSLog(@"🧩 Dashboard Info response: %@", json);
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(json, jsonErr);
});
}
}];
[task resume];
}
+ (void)fetchAnnouncement:(void (^)(NSArray *data))completion {
NSURL *url = [NSURL URLWithString:
@"https://kitadev.commudesk.com/api/announcement?token=YOUR_TOKEN_HERE"];
NSDictionary *body = @{
@"data": @{
@"os": @"iOS",
@"information": @{
@"OS": @"iOS",
@"IMEI": @"iOS:1234567890",
@"OS_VERSION": [[UIDevice currentDevice] systemVersion],
@"MODEL": [[UIDevice currentDevice] model],
@"APP_VERSION": [[[NSBundle mainBundle] infoDictionary]
objectForKey:@"CFBundleShortVersionString"]
}
}
};
NSError *jsonError;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:body options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON serialization failed: %@", jsonError);
if (completion) completion(@[]);
return;
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
request.HTTPBody = jsonData;
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Request failed: %@", error.localizedDescription
);
if (completion) completion(@[]
);
return;
NSLog(@"❌ Network error: %@", error
);
if (completion) completion(nil, error
);
return;
}
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSError *jsonErr;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
NSLog(@"✅ Announcement API response:\n%@", json);
NSDictionary *appData = json[@"AppData"];
NSArray *announcements = @[];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSArray *
announcements = json[@"Data"];
announcements = json[@"Data"];
NSLog(@"📣 Got %lu announcements", (unsigned long)announcements.count);
if (completion) completion(announcements);
} else {
NSLog(@"⚠️ Announcement fetch failed: %@", appData[@"message"]);
if (completion) completion(@[]);
}
}];
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(json, jsonErr);
});
}
}];
[task resume];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Dashboard/DashboardViewController.mm
View file @
1c49cf8f
...
...
@@ -23,6 +23,7 @@
@property (nonatomic, strong) NSString *projectCode;
@property (nonatomic, strong) NSString *projectName;
@property (nonatomic, strong) UIImage *headerBackgroundImage;
@property (nonatomic, strong) NSArray *announcements;
@end
...
...
@@ -69,14 +70,21 @@
return;
}
NSLog(@"🗞️ Announcement response
: %@", data
);
NSLog(@"🗞️ Announcement response
received"
);
// Optional: save to file for reference
// 🔍 Optional: Log the whole JSON structure for debugging
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"%@", jsonString);
// 💾 Save to file for offline reference
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"AnnouncementResponse.txt"];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
[jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 Announcement response saved to %@", filePath);
// ✅ Process and show popup announcements
[self processAnnouncementResponse:data];
}];
}
...
...
@@ -414,6 +422,51 @@
});
}
// DashboardViewController.m
- (void)processAnnouncementResponse:(NSDictionary *)data {
NSLog(@"Handling announcement: %@", data);
NSDictionary *appData = data[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"Announcement fetch failed: %@", appData[@"message"]);
return;
}
// === Combine ===
NSDictionary *innerData = data[@"Data"] ?: data[@"data"];
NSArray *client = innerData[@"client_announcement"] ?: @[];
NSArray *project = innerData[@"project_announcement"] ?: @[];
NSMutableArray *merged = [NSMutableArray arrayWithArray:client];
[merged addObjectsFromArray:project];
// === Sort by date descending ===
NSArray *sorted = [merged sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *a, NSDictionary *b) {
NSString *dateA = a[@"date"] ?: @"";
NSString *dateB = b[@"date"] ?: @"";
return [dateB compare:dateA];
}];
// === Save to property ===
self.announcements = sorted;
// === Save to UserDefaults if needed ===
[[NSUserDefaults standardUserDefaults] setObject:sorted forKey:@"CLIENT_ANNOUNCEMENTS"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(@"✅ Stored %lu announcements", (unsigned long)sorted.count);
// === Check for popup announcements ===
// for (NSDictionary *ann in sorted) {
// if ([ann[@"popup"] integerValue] == 1) {
// [self showPopupForAnnouncement:ann];
// break;
// }
// }
}
- (void)refreshDashboardSectionsWithData:(NSDictionary *)mainData {
NSLog(@"🔄 Refreshing dashboard sections...");
...
...
@@ -424,7 +477,7 @@
_currentY = 16.0;
// === PROJECT UPDATES ===
NSArray *announcements =
mainData[@"announcement"]
;
NSArray *announcements =
self.announcements
;
if (announcements.count > 0) {
UIView *announcementSection = [self buildAnnouncementSection:announcements];
CGRect f = announcementSection.frame;
...
...
@@ -590,16 +643,28 @@
card.layer.shadowOpacity = 0.3;
card.layer.shadowOffset = CGSizeMake(0, 1);
UILabel *date = [[UILabel alloc] initWithFrame:CGRectMake(12, 8, 200, 16)];
// === 1. Resolve the date field (support both created_at and date) ===
NSString *dateString = item[@"created_at"] ?: item[@"date"];
NSString *dateOnly = dateString;
// === take only the date portion (before space) ===
if ([dateString containsString:@" "]) {
dateOnly = [[dateString componentsSeparatedByString:@" "] firstObject];
}
// === format it ===
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd
HH:mm:ss
";
NSDate *dateObj = [fmt dateFromString:
item[@"created_at"]
];
fmt.dateFormat = @"yyyy-MM-dd";
NSDate *dateObj = [fmt dateFromString:
dateOnly
];
fmt.dateFormat = @"dd/MM/yyyy";
UILabel *date = [[UILabel alloc] initWithFrame:CGRectMake(12, 8, 200, 16)];
date.text = dateObj ? [fmt stringFromDate:dateObj] : @"--/--/----";
date.textColor = [UIColor grayColor];
date.font = [UIFont systemFontOfSize:13];
[card addSubview:date];
// === 2. Title ===
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(12, 28, 256, 60)];
title.text = item[@"title"] ?: @"Untitled announcement";
title.numberOfLines = 3;
...
...
@@ -612,6 +677,7 @@
return card;
}
- (UIView *)makeAppointmentCard:(NSDictionary *)item width:(CGFloat)width {
UIView *card = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 90)];
card.backgroundColor = UIColor.whiteColor;
...
...
ios/QmsPluginFramework.xcframework/Info.plist
View file @
1c49cf8f
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
1c49cf8f
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
1c49cf8f
No preview for this file type
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment