Commit 2ac4e245 authored by Wei Han's avatar Wei Han

UI code update

parent db23c5fb
...@@ -4,4 +4,7 @@ ...@@ -4,4 +4,7 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@interface AddIssueDetailsViewController : UIViewController @interface AddIssueDetailsViewController : UIViewController
@property (nonatomic, strong) NSString *selectedLocationName;
@property (nonatomic, strong) NSMutableArray<UIImage *> *uploadedImages;
@end @end
#import "DetailsViewController.h" #import "DetailsViewController.h"
@interface AddIssueDetailsViewController () @interface AddIssueDetailsViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property (nonatomic, strong) UIView *headerView; @property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIScrollView *scrollView; @property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UITextField *locationField; @property (nonatomic, strong) UITextField *locationField;
...@@ -18,6 +18,11 @@ ...@@ -18,6 +18,11 @@
// Create all views (don’t position them yet) // Create all views (don’t position them yet)
[self createHeader]; [self createHeader];
[self createForm]; [self createForm];
// Set location if passed from previous screen
if (self.selectedLocationName && self.selectedLocationName.length > 0) {
self.locationField.text = self.selectedLocationName;
}
self.uploadedImages = [NSMutableArray arrayWithObjects:[NSNull null], [NSNull null], [NSNull null], nil];
} }
- (void)viewDidLayoutSubviews { - (void)viewDidLayoutSubviews {
...@@ -37,14 +42,7 @@ ...@@ -37,14 +42,7 @@
// Scroll view layout (below header) // Scroll view layout (below header)
CGFloat scrollY = topInset + headerHeight; CGFloat scrollY = topInset + headerHeight;
self.scrollView.frame = CGRectMake(0, scrollY, self.scrollView.frame = CGRectMake(0, scrollY, self.view.bounds.size.width, self.view.bounds.size.height - scrollY);
self.view.bounds.size.width,
self.view.bounds.size.height - scrollY);
// Adjust internal subviews (since width may have changed)
self.locationField.frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 40);
self.commentField.frame = CGRectMake(20, 140, self.view.bounds.size.width - 40, 100);
self.submitButton.frame = CGRectMake(20, 260, self.view.bounds.size.width - 40, 48);
} }
#pragma mark - Setup #pragma mark - Setup
...@@ -132,37 +130,397 @@ ...@@ -132,37 +130,397 @@
} }
- (void)createForm { - (void)createForm {
self.scrollView = [[UIScrollView alloc] init]; UIScrollView *scroll = [[UIScrollView alloc] init];
[self.view addSubview:self.scrollView]; scroll.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scroll];
UILabel *locationLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 200, 20)]; self.scrollView = scroll;
locationLabel.text = @"*Location";
locationLabel.font = [UIFont boldSystemFontOfSize:16]; UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[self.scrollView addSubview:locationLabel]; [NSLayoutConstraint activateConstraints:@[
[scroll.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
self.locationField = [[UITextField alloc] initWithFrame:CGRectZero]; [scroll.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
self.locationField.borderStyle = UITextBorderStyleRoundedRect; [scroll.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.scrollView addSubview:self.locationField]; [scroll.bottomAnchor constraintEqualToAnchor:safe.bottomAnchor],
]];
UILabel *commentLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 110, 200, 20)];
commentLabel.text = @"Comment"; UIView *content = [[UIView alloc] init];
commentLabel.font = [UIFont boldSystemFontOfSize:16]; content.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:commentLabel]; [scroll addSubview:content];
[NSLayoutConstraint activateConstraints:@[
self.commentField = [[UITextView alloc] initWithFrame:CGRectZero]; [content.topAnchor constraintEqualToAnchor:scroll.topAnchor],
self.commentField.layer.borderColor = [UIColor lightGrayColor].CGColor; [content.leadingAnchor constraintEqualToAnchor:scroll.leadingAnchor],
self.commentField.layer.borderWidth = 1.0; [content.trailingAnchor constraintEqualToAnchor:scroll.trailingAnchor],
self.commentField.layer.cornerRadius = 8; [content.bottomAnchor constraintEqualToAnchor:scroll.bottomAnchor],
[self.scrollView addSubview:self.commentField]; [content.widthAnchor constraintEqualToAnchor:scroll.widthAnchor],
]];
self.submitButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.submitButton.frame = CGRectZero; CGFloat spacing = 16;
self.submitButton.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1]; UIView *lastView = nil;
[self.submitButton setTitle:@"Submit" forState:UIControlStateNormal];
[self.submitButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; // “For” label
self.submitButton.layer.cornerRadius = 8; UILabel *forLabel = [self makeLabelWithText:@"For" bold:NO size:14];
[self.submitButton addTarget:self action:@selector(handleSubmit) forControlEvents:UIControlEventTouchUpInside]; [content addSubview:forLabel];
[self.scrollView addSubview:self.submitButton]; [forLabel.topAnchor constraintEqualToAnchor:content.topAnchor constant:spacing].active = YES;
[forLabel.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:20].active = YES;
UILabel *unitLabel = [self makeLabelWithText:@"Ara E Residence Dev, C-L(2)" bold:YES size:16];
[content addSubview:unitLabel];
[unitLabel.topAnchor constraintEqualToAnchor:forLabel.bottomAnchor constant:4].active = YES;
[unitLabel.leadingAnchor constraintEqualToAnchor:forLabel.leadingAnchor].active = YES;
lastView = unitLabel;
// Location section
UILabel *locationTitle = [self makeLabelWithText:@"*Location" bold:YES size:15];
[content addSubview:locationTitle];
[locationTitle.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing].active = YES;
[locationTitle.leadingAnchor constraintEqualToAnchor:forLabel.leadingAnchor].active = YES;
UIView *locationContainer = [self makeRoundedBox];
[content addSubview:locationContainer];
[NSLayoutConstraint activateConstraints:@[
[locationContainer.topAnchor constraintEqualToAnchor:locationTitle.bottomAnchor constant:8],
[locationContainer.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:20],
[locationContainer.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-20],
[locationContainer.heightAnchor constraintEqualToConstant:44],
]];
UITextField *locationField = [[UITextField alloc] init];
locationField.translatesAutoresizingMaskIntoConstraints = NO;
locationField.text = self.selectedLocationName ?: @"Select location";
locationField.font = [UIFont systemFontOfSize:15];
locationField.enabled = NO;
[locationContainer addSubview:locationField];
self.locationField = locationField;
UIButton *reselectBtn = [UIButton buttonWithType:UIButtonTypeSystem];
reselectBtn.translatesAutoresizingMaskIntoConstraints = NO;
[reselectBtn setTitle:@"Reselect" forState:UIControlStateNormal];
[reselectBtn setTitleColor:[UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1] forState:UIControlStateNormal];
reselectBtn.titleLabel.font = [UIFont boldSystemFontOfSize:14];
[reselectBtn addTarget:self action:@selector(dismissSelf) forControlEvents:UIControlEventTouchUpInside];
[locationContainer addSubview:reselectBtn];
[NSLayoutConstraint activateConstraints:@[
[locationField.leadingAnchor constraintEqualToAnchor:locationContainer.leadingAnchor constant:8],
[locationField.centerYAnchor constraintEqualToAnchor:locationContainer.centerYAnchor],
[reselectBtn.trailingAnchor constraintEqualToAnchor:locationContainer.trailingAnchor constant:-4],
[reselectBtn.centerYAnchor constraintEqualToAnchor:locationContainer.centerYAnchor],
[locationField.trailingAnchor constraintEqualToAnchor:reselectBtn.leadingAnchor constant:-12],
]];
lastView = locationContainer;
// Category, Type, Issue — dropdown style
NSArray *titles = @[@"*Category", @"*Type", @"*Issue"];
NSMutableArray *dropdowns = [NSMutableArray array];
for (NSString *t in titles) {
UILabel *lbl = [self makeLabelWithText:t bold:YES size:15];
[content addSubview:lbl];
[lbl.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing].active = YES;
[lbl.leadingAnchor constraintEqualToAnchor:forLabel.leadingAnchor].active = YES;
UIButton *dropdown = [self makeDropdownWithPlaceholder:[NSString stringWithFormat:@"- Select %@ -", [t componentsSeparatedByString:@" "].lastObject]];
[content addSubview:dropdown];
[NSLayoutConstraint activateConstraints:@[
[dropdown.topAnchor constraintEqualToAnchor:lbl.bottomAnchor constant:8],
[dropdown.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:20],
[dropdown.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-20],
[dropdown.heightAnchor constraintEqualToConstant:44],
]];
[dropdowns addObject:dropdown];
lastView = dropdown;
}
// Comment box
UILabel *commentLabel = [self makeLabelWithText:@"Comment" bold:YES size:15];
[content addSubview:commentLabel];
[commentLabel.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing].active = YES;
[commentLabel.leadingAnchor constraintEqualToAnchor:forLabel.leadingAnchor].active = YES;
UITextView *comment = [[UITextView alloc] init];
comment.translatesAutoresizingMaskIntoConstraints = NO;
comment.layer.borderWidth = 1.0;
comment.layer.cornerRadius = 8;
comment.layer.borderColor = [UIColor lightGrayColor].CGColor;
comment.font = [UIFont systemFontOfSize:15];
[content addSubview:comment];
[NSLayoutConstraint activateConstraints:@[
[comment.topAnchor constraintEqualToAnchor:commentLabel.bottomAnchor constant:8],
[comment.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:20],
[comment.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-20],
[comment.heightAnchor constraintEqualToConstant:100],
]];
self.commentField = comment;
lastView = comment;
// Image upload section
UILabel *uploadLabel = [self makeLabelWithText:@"*Image Upload" bold:YES size:15];
[content addSubview:uploadLabel];
[uploadLabel.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing].active = YES;
[uploadLabel.leadingAnchor constraintEqualToAnchor:forLabel.leadingAnchor].active = YES;
UIStackView *uploadRow = [[UIStackView alloc] init];
uploadRow.axis = UILayoutConstraintAxisHorizontal;
uploadRow.spacing = 12;
uploadRow.distribution = UIStackViewDistributionFillEqually;
uploadRow.translatesAutoresizingMaskIntoConstraints = NO;
[content addSubview:uploadRow];
[NSLayoutConstraint activateConstraints:@[
[uploadRow.topAnchor constraintEqualToAnchor:uploadLabel.bottomAnchor constant:8],
[uploadRow.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:20],
[uploadRow.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-20],
[uploadRow.heightAnchor constraintEqualToConstant:90],
]];
for (int i = 0; i < 3; i++) {
UIButton *uploadBtn = [self makeUploadBox];
uploadBtn.tag = 1000 + i; // unique ID for each button
[uploadRow addArrangedSubview:uploadBtn];
}
lastView = uploadRow;
// Submit button
UIButton *submit = [UIButton buttonWithType:UIButtonTypeSystem];
submit.translatesAutoresizingMaskIntoConstraints = NO;
submit.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
[submit setTitle:@"Submit" forState:UIControlStateNormal];
[submit setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
submit.titleLabel.font = [UIFont boldSystemFontOfSize:16];
submit.layer.cornerRadius = 8;
[submit addTarget:self action:@selector(handleSubmit) forControlEvents:UIControlEventTouchUpInside];
[content addSubview:submit];
[NSLayoutConstraint activateConstraints:@[
[submit.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing],
[submit.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:20],
[submit.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-20],
[submit.heightAnchor constraintEqualToConstant:48],
]];
lastView = submit;
[content.bottomAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:spacing].active = YES;
}
- (UILabel *)makeLabelWithText:(NSString *)text bold:(BOOL)bold size:(CGFloat)size {
UILabel *lbl = [[UILabel alloc] init];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
lbl.text = text;
lbl.font = bold ? [UIFont boldSystemFontOfSize:size] : [UIFont systemFontOfSize:size];
lbl.textColor = [UIColor darkTextColor];
return lbl;
}
- (UIView *)makeRoundedBox {
UIView *box = [[UIView alloc] init];
box.translatesAutoresizingMaskIntoConstraints = NO;
box.layer.borderWidth = 1.0;
box.layer.borderColor = [UIColor lightGrayColor].CGColor;
box.layer.cornerRadius = 8;
return box;
}
- (UIButton *)makeDropdownWithPlaceholder:(NSString *)placeholder {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.translatesAutoresizingMaskIntoConstraints = NO;
btn.layer.borderWidth = 1.0;
btn.layer.cornerRadius = 8;
btn.layer.borderColor = [UIColor lightGrayColor].CGColor;
btn.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1];
// Title setup
[btn setTitle:placeholder forState:UIControlStateNormal];
[btn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
btn.titleLabel.font = [UIFont systemFontOfSize:15];
// Align text on the left
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
btn.contentEdgeInsets = UIEdgeInsetsMake(0, 12, 0, 0);
// Add a dropdown chevron (SF Symbol)
UIImage *chevron = [UIImage systemImageNamed:@"chevron.down"];
UIImageView *arrow = [[UIImageView alloc] initWithImage:chevron];
arrow.translatesAutoresizingMaskIntoConstraints = NO;
arrow.tintColor = [UIColor grayColor];
[btn addSubview:arrow];
// Position arrow on right side
[NSLayoutConstraint activateConstraints:@[
[arrow.centerYAnchor constraintEqualToAnchor:btn.centerYAnchor],
[arrow.trailingAnchor constraintEqualToAnchor:btn.trailingAnchor constant:-12],
[arrow.widthAnchor constraintEqualToConstant:12],
[arrow.heightAnchor constraintEqualToConstant:8]
]];
// Bring title above arrow
btn.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 20);
// Add tap handler (for menu)
[btn addTarget:self action:@selector(handleDropdownTap:) forControlEvents:UIControlEventTouchUpInside];
return btn;
}
- (void)handleDropdownTap:(UIButton *)sender {
NSString *title = sender.titleLabel.text ?: @"Select";
UIAlertController *menu = [UIAlertController alertControllerWithTitle:title
message:@"Pick an option"
preferredStyle:UIAlertControllerStyleActionSheet];
NSArray *options = @[@"Option 1", @"Option 2", @"Option 3"];
for (NSString *opt in options) {
[menu addAction:[UIAlertAction actionWithTitle:opt
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[sender setTitle:opt forState:UIControlStateNormal];
[sender setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}]];
}
[menu addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:menu animated:YES completion:nil];
}
- (UIButton *)makeUploadBox {
UIButton *upload = [UIButton buttonWithType:UIButtonTypeCustom]; // ✅ not System
upload.translatesAutoresizingMaskIntoConstraints = NO;
upload.layer.borderWidth = 1.0;
upload.layer.cornerRadius = 8;
upload.layer.borderColor = [UIColor lightGrayColor].CGColor;
[upload setTitle:@"Upload" forState:UIControlStateNormal];
[upload setTitleColor:[UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1] forState:UIControlStateNormal];
[upload setImage:[UIImage systemImageNamed:@"camera"] forState:UIControlStateNormal];
upload.tintColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
upload.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 8);
upload.titleLabel.font = [UIFont boldSystemFontOfSize:14];
[upload addTarget:self action:@selector(handleUploadTap:) forControlEvents:UIControlEventTouchUpInside];
return upload;
}
- (void)handleUploadTap:(UIButton *)sender {
NSInteger index = sender.tag - 1000;
UIAlertController *sheet = [UIAlertController alertControllerWithTitle:@"Upload Image"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
[sheet addAction:[UIAlertAction actionWithTitle:@"Camera"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self openImagePickerForIndex:index source:UIImagePickerControllerSourceTypeCamera];
}]];
[sheet addAction:[UIAlertAction actionWithTitle:@"Gallery"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self openImagePickerForIndex:index source:UIImagePickerControllerSourceTypePhotoLibrary];
}]];
[sheet addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:sheet animated:YES completion:nil];
}
- (void)openImagePickerForIndex:(NSInteger)index source:(UIImagePickerControllerSourceType)source {
if (![UIImagePickerController isSourceTypeAvailable:source]) return;
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = source;
picker.view.tag = index; // store which slot this is for
[self presentViewController:picker animated:YES completion:nil];
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
NSInteger index = picker.view.tag; // will be 0–2 after fix
// Store image
if (index < self.uploadedImages.count) {
self.uploadedImages[index] = image;
} else {
[self.uploadedImages addObject:image];
}
// Update UI
UIButton *button = [self.view viewWithTag:1000 + index];
if ([button isKindOfClass:[UIButton class]]) {
[button setTitle:nil forState:UIControlStateNormal];
[button setImage:image forState:UIControlStateNormal];
button.imageView.contentMode = UIViewContentModeScaleAspectFill;
button.imageView.clipsToBounds = YES;
button.layer.masksToBounds = YES;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
button.imageEdgeInsets = UIEdgeInsetsZero;
[self addRemoveButtonToUpload:button atIndex:index];
}
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)addRemoveButtonToUpload:(UIButton *)uploadBtn atIndex:(NSInteger)index {
// Remove existing remove button if any (avoid duplicates)
for (UIView *sub in uploadBtn.subviews) {
if (sub.tag == 9000) {
[sub removeFromSuperview];
}
}
// Create small X button
UIButton *removeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
removeBtn.tag = 9000;
removeBtn.translatesAutoresizingMaskIntoConstraints = NO;
[removeBtn setImage:[UIImage systemImageNamed:@"xmark.circle.fill"] forState:UIControlStateNormal];
removeBtn.tintColor = [UIColor whiteColor];
removeBtn.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4];
removeBtn.layer.cornerRadius = 10;
removeBtn.clipsToBounds = YES;
removeBtn.contentEdgeInsets = UIEdgeInsetsMake(4, 4, 4, 4);
removeBtn.accessibilityIdentifier = [NSString stringWithFormat:@"remove_%ld", (long)index];
[removeBtn addTarget:self action:@selector(handleRemoveImage:) forControlEvents:UIControlEventTouchUpInside];
[uploadBtn addSubview:removeBtn];
// Position in top-right corner
[NSLayoutConstraint activateConstraints:@[
[removeBtn.topAnchor constraintEqualToAnchor:uploadBtn.topAnchor constant:4],
[removeBtn.trailingAnchor constraintEqualToAnchor:uploadBtn.trailingAnchor constant:-4],
[removeBtn.widthAnchor constraintEqualToConstant:20],
[removeBtn.heightAnchor constraintEqualToConstant:20],
]];
}
- (void)handleRemoveImage:(UIButton *)sender {
UIView *uploadBtn = sender.superview;
if (![uploadBtn isKindOfClass:[UIButton class]]) return;
NSInteger index = ((UIButton *)uploadBtn).tag - 1000;
if (index < self.uploadedImages.count) {
[self.uploadedImages removeObjectAtIndex:index];
}
// Reset upload button
UIButton *button = (UIButton *)uploadBtn;
[button setImage:[UIImage systemImageNamed:@"camera"] forState:UIControlStateNormal];
[button setTitle:@"Upload" forState:UIControlStateNormal];
[button setTitleColor:[UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1] forState:UIControlStateNormal];
button.tintColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
button.imageView.contentMode = UIViewContentModeCenter;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 8);
// Remove the small "x" button
[sender removeFromSuperview];
} }
- (void)handleReset { - (void)handleReset {
...@@ -177,6 +535,7 @@ ...@@ -177,6 +535,7 @@
style:UIAlertActionStyleDefault style:UIAlertActionStyleDefault
handler:nil]]; handler:nil]];
[self presentViewController:alert animated:YES completion:nil]; [self presentViewController:alert animated:YES completion:nil];
[self.uploadedImages removeAllObjects];
} }
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
@property (nonatomic, strong) UIScrollView *scrollView; @property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIImageView *planImageView; @property (nonatomic, strong) UIImageView *planImageView;
@property (nonatomic, strong) NSString *selectedLocation;
@end @end
@implementation PlanViewController @implementation PlanViewController
...@@ -170,11 +172,115 @@ ...@@ -170,11 +172,115 @@
} }
- (void)handleNextScreen { - (void)handleNextScreen {
NSLog(@"➡️ Test button tapped — navigating to AddIssueDetailsViewController"); [self showAddIssuePopup];
}
- (void)showAddIssuePopup {
NSLog(@"🟢 Showing Add Issue popup");
// Background dim view
UIView *overlay = [[UIView alloc] initWithFrame:self.view.bounds];
overlay.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
overlay.alpha = 0.0;
overlay.tag = 999; // so we can find and remove it later
[self.view addSubview:overlay];
// Popup container
CGFloat safeBottom = self.view.safeAreaInsets.bottom;
CGFloat popupHeight = 180 + safeBottom;
UIView *popup = [[UIView alloc] initWithFrame:CGRectMake(0,
self.view.bounds.size.height,
self.view.bounds.size.width,
popupHeight)];
popup.backgroundColor = UIColor.whiteColor;
popup.layer.cornerRadius = 16;
popup.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
popup.clipsToBounds = YES;
popup.tag = 1000;
[self.view addSubview:popup];
// Label — “You have selected”
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, popup.bounds.size.width - 40, 20)];
label.text = @"You have selected:";
label.textColor = [UIColor blackColor];
label.font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
[popup addSubview:label];
// Mock location name
UILabel *locationLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 50, popup.bounds.size.width - 40, 24)];
locationLabel.text = @"Building A - 2nd Floor";
self.selectedLocation = locationLabel.text;
locationLabel.textColor = [UIColor blackColor];
locationLabel.font = [UIFont boldSystemFontOfSize:17];
[popup addSubview:locationLabel];
// Buttons row
CGFloat buttonWidth = (self.view.bounds.size.width - 48) / 2;
CGFloat buttonY = popupHeight - 60 - safeBottom; // ✅ push up above safe area
UIButton *reselectButton = [UIButton buttonWithType:UIButtonTypeSystem];
reselectButton.frame = CGRectMake(16, buttonY, buttonWidth, 44);
[reselectButton setTitle:@"Reselect" forState:UIControlStateNormal];
[reselectButton setTitleColor:[UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1]
forState:UIControlStateNormal];
reselectButton.layer.borderWidth = 1.0;
reselectButton.layer.borderColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1].CGColor;
reselectButton.layer.cornerRadius = 8;
[reselectButton addTarget:self action:@selector(dismissAddIssuePopup)
forControlEvents:UIControlEventTouchUpInside];
[popup addSubview:reselectButton];
UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeSystem];
nextButton.frame = CGRectMake(32 + buttonWidth, buttonY, buttonWidth, 44);
[nextButton setTitle:@"Next" forState:UIControlStateNormal];
[nextButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
nextButton.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
nextButton.layer.cornerRadius = 8;
[nextButton addTarget:self action:@selector(handleConfirmAddIssue)
forControlEvents:UIControlEventTouchUpInside];
[popup addSubview:nextButton];
// Animate in
[UIView animateWithDuration:0.3 animations:^{
overlay.alpha = 1.0;
popup.frame = CGRectMake(0,
self.view.bounds.size.height - popupHeight,
self.view.bounds.size.width,
popupHeight);
}];
}
- (void)dismissAddIssuePopup {
NSLog(@"❌ Dismissing Add Issue popup");
UIView *overlay = [self.view viewWithTag:999];
UIView *popup = [self.view viewWithTag:1000];
[UIView animateWithDuration:0.25 animations:^{
overlay.alpha = 0.0;
popup.frame = CGRectMake(0,
self.view.bounds.size.height,
popup.bounds.size.width,
popup.bounds.size.height);
} completion:^(BOOL finished) {
[overlay removeFromSuperview];
[popup removeFromSuperview];
}];
}
- (void)handleConfirmAddIssue {
NSLog(@"✅ Confirm Add Issue pressed");
// Dismiss popup first
[self dismissAddIssuePopup];
AddIssueDetailsViewController *nextVC = [[AddIssueDetailsViewController alloc] init]; // Then open AddIssueDetailsViewController after a short delay
nextVC.modalPresentationStyle = UIModalPresentationFullScreen; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self presentViewController:nextVC animated:YES completion:nil]; AddIssueDetailsViewController *nextVC = [[AddIssueDetailsViewController alloc] init];
nextVC.selectedLocationName = self.selectedLocation; // ✅ Pass it here
nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:nextVC animated:YES completion:nil];
});
} }
#pragma mark - Actions #pragma mark - Actions
......
// DashboardAPIClient.h
#import <Foundation/Foundation.h>
@interface DashboardAPIClient : NSObject
+ (void)fetchDashboardSummary:(void (^)(NSDictionary *data))completion;
+ (void)fetchAnnouncements:(void (^)(NSArray *data))completion;
+ (void)fetchAppointments:(void (^)(NSArray *data))completion;
+ (void)fetchIssues:(void (^)(NSArray *data))completion;
+ (void)fetchHeaderInfo:(void (^)(NSDictionary *data))completion;
@end
// DashbaordAPIClient.mm
#import "DashboardAPIClient.h"
@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];
}
+ (void)fetchAnnouncements:(void (^)(NSArray *))completion {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/posts?_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)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];
}
+ (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];
}
+ (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];
}
@end
//DashboardHeaderView.mm
#import "DashboardHeaderView.h" #import "DashboardHeaderView.h"
@implementation DashboardHeaderView @implementation DashboardHeaderView
......
// DashboardViewController.mm
#import "DashboardViewController.h" #import "DashboardViewController.h"
#import "DashboardHeaderView.h" #import "DashboardHeaderView.h"
#import <CoreGraphics/CoreGraphics.h> #import <CoreGraphics/CoreGraphics.h>
#import "PlanViewController.h" #import "PlanViewController.h"
#import "DashboardAPIClient.h"
@implementation DashboardViewController { @implementation DashboardViewController {
DashboardHeaderView *_headerView; DashboardHeaderView *_headerView;
UIScrollView *_scrollView; UIScrollView *_scrollView;
UIView *_contentContainer; UIView *_contentContainer, *_inspectionBanner;
NSMutableDictionary *_sectionViews; NSMutableDictionary *_sectionViews;
CGFloat _currentY;
} }
- (void)viewDidLoad { - (void)viewDidLoad {
...@@ -25,6 +28,7 @@ ...@@ -25,6 +28,7 @@
#pragma mark - Layout #pragma mark - Layout
- (void)viewDidLayoutSubviews { - (void)viewDidLayoutSubviews {
NSLog(@"Header frame: %@", NSStringFromCGRect(_headerView.frame));
[super viewDidLayoutSubviews]; [super viewDidLayoutSubviews];
UIView *footerView = self.view.subviews.lastObject; UIView *footerView = self.view.subviews.lastObject;
CGFloat footerHeight = 80.0; CGFloat footerHeight = 80.0;
...@@ -159,88 +163,273 @@ ...@@ -159,88 +163,273 @@
- (void)setupScrollContent { - (void)setupScrollContent {
CGFloat topOffset = 220.0; CGFloat topOffset = 220.0;
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, topOffset, self.view.bounds.size.width, self.view.bounds.size.height - topOffset)]; _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(
0,
topOffset,
self.view.bounds.size.width,
self.view.bounds.size.height - topOffset
)];
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_scrollView.backgroundColor = [UIColor clearColor]; _scrollView.backgroundColor = [UIColor clearColor];
// 🩹 Add dynamic bottom padding so last card doesn’t clip under footer
CGFloat footerHeight = 80.0 + self.view.safeAreaInsets.bottom;
_scrollView.contentInset = UIEdgeInsetsMake(0, 0, footerHeight, 0);
_scrollView.scrollIndicatorInsets = _scrollView.contentInset;
[self.view addSubview:_scrollView]; [self.view addSubview:_scrollView];
_contentContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.bounds.size.width, 0)]; _contentContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.bounds.size.width, 0)];
_contentContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth; _contentContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[_scrollView addSubview:_contentContainer]; [_scrollView addSubview:_contentContainer];
_currentY = 16.0;
[self setupInspectionChecklistBanner];
if (_currentY == 0) {
_currentY = 16.0;
}
}
CGFloat y = 20; #pragma mark - Inspection Checklist Banner
// Add 3 fixed section titles, store them for later population - (void)setupInspectionChecklistBanner {
NSArray *sectionNames = @[ @"Project Update", @"Appointments", @"Issue Updates" ]; BOOL blnContactlessHandover = NO; // mock GLOBALS.BLN_CONTACTLESS_HANDOVER == 1
for (NSString *name in sectionNames) { BOOL blnInspChecklist = NO; // mock self.bln_InspChecklist
UILabel *header = [[UILabel alloc] initWithFrame:CGRectMake(16, y, self.view.bounds.size.width - 32, 24)]; NSString *handoverStatus = @"Pending"; // mock self.strContactlessHandoverStatus
header.text = name; NSInteger daysRemaining = 3; // mock self.strDays
header.font = [UIFont boldSystemFontOfSize:18];
[_contentContainer addSubview:header];
y += 30;
UIView *sectionContainer = [[UIView alloc] initWithFrame:CGRectMake(0, y, self.view.bounds.size.width, 0)]; // ✅ Condition check
[_contentContainer addSubview:sectionContainer]; if (!(blnContactlessHandover && blnInspChecklist && [handoverStatus isEqualToString:@"Pending"])) {
_sectionViews[name] = sectionContainer; NSLog(@"ℹ️ No inspection checklist banner required");
return;
}
y += 20; // spacing before next section // Banner container
_inspectionBanner = [[UIView alloc] initWithFrame:CGRectMake(16, 16, self.view.bounds.size.width - 32, 90)];
_inspectionBanner.backgroundColor = [UIColor colorWithRed:1.0 green:0.39 blue:0.39 alpha:1.0]; // #FF6464
_inspectionBanner.layer.cornerRadius = 20;
_inspectionBanner.clipsToBounds = YES;
// Tap gesture (simulate button press)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleInspectionBannerTap)];
[_inspectionBanner addGestureRecognizer:tap];
// Title label
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 16, _inspectionBanner.bounds.size.width - 80, 24)];
titleLabel.text = @"Submit Unit Inspection Checklist";
titleLabel.font = [UIFont boldSystemFontOfSize:16];
titleLabel.textColor = UIColor.whiteColor;
[_inspectionBanner addSubview:titleLabel];
// Right arrow icon
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"chevron.right"]];
arrow.tintColor = UIColor.whiteColor;
arrow.frame = CGRectMake(_inspectionBanner.bounds.size.width - 36, (_inspectionBanner.bounds.size.height - 24)/2, 20, 24);
arrow.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[_inspectionBanner addSubview:arrow];
// Days remaining pill (optional)
if (daysRemaining > 0) {
UIView *pill = [[UIView alloc] initWithFrame:CGRectMake(16, CGRectGetMaxY(titleLabel.frame) + 6, 170, 28)];
pill.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4];
pill.layer.cornerRadius = 14;
pill.clipsToBounds = YES;
UIImageView *calendarIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"calendar"]];
calendarIcon.tintColor = UIColor.whiteColor;
calendarIcon.frame = CGRectMake(8, 4, 20, 20);
[pill addSubview:calendarIcon];
UILabel *daysLabel = [[UILabel alloc] initWithFrame:CGRectMake(34, 4, 130, 20)];
daysLabel.text = [NSString stringWithFormat:@"%ld days remaining", (long)daysRemaining];
daysLabel.textColor = UIColor.whiteColor;
daysLabel.font = [UIFont boldSystemFontOfSize:13];
[pill addSubview:daysLabel];
[_inspectionBanner addSubview:pill];
} }
_contentContainer.frame = CGRectMake(0, 0, _scrollView.bounds.size.width, y); [_contentContainer addSubview:_inspectionBanner];
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, y); _currentY = CGRectGetMaxY(_inspectionBanner.frame) + 16.0;
}
- (void)handleInspectionBannerTap {
NSLog(@"🟥 Inspection checklist banner tapped");
// In future: open WebView screen or perform navigation
[UIView animateWithDuration:0.1 animations:^{
_inspectionBanner.alpha = 0.6;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^{
_inspectionBanner.alpha = 1.0;
}];
}];
} }
#pragma mark - Networking #pragma mark - Networking
- (void)fetchDashboardData { - (void)fetchDashboardData {
NSURL *url = [NSURL URLWithString:@"https://jsonplaceholder.typicode.com/posts?_limit=9"];
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
[[[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { [DashboardAPIClient fetchDashboardSummary:^(NSDictionary *data) {
if (error) return; __strong typeof(weakSelf) strongSelf = weakSelf;
NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"🏗 Dashboard Summary: %@", data);
dispatch_async(dispatch_get_main_queue(), ^{ // In the future: update header info (project/unit name, etc.)
[weakSelf populateSectionsWithData:json]; [strongSelf->_headerView configureWithProjectName:data[@"name"]
}); unitName:data[@"username"]
}] resume]; backgroundImage:[UIImage imageNamed:@"header_bg"]
} overlayImage:[UIImage imageNamed:@"overlay"]];
}];
- (void)populateSectionsWithData:(NSArray *)data {
NSArray *sectionKeys = @[ @"Project Update", @"Appointments", @"Issue Updates" ]; [DashboardAPIClient fetchHeaderInfo:^(NSDictionary *data) {
int itemsPerSection = (int)ceil(data.count / 3.0); __strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
CGFloat sectionBottomY = 0;
for (int i = 0; i < sectionKeys.count; i++) { NSLog(@"🖼 Header info: %@", data);
NSString *key = sectionKeys[i];
UIView *sectionContainer = _sectionViews[key]; NSString *projectName = data[@"title"] ?: @"Project A";
CGFloat y = 0; NSString *unitName = @"Demo Unit 3A";
NSString *imageURL = data[@"url"];
NSArray *subset = [data subarrayWithRange:NSMakeRange(i * itemsPerSection,
MIN(itemsPerSection, data.count - i * itemsPerSection))]; NSURL *url = [NSURL URLWithString:imageURL];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
for (NSDictionary *item in subset) { completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
UIView *card = [[UIView alloc] initWithFrame:CGRectMake(16, y, self.view.bounds.size.width - 32, 100)]; if (error) {
card.backgroundColor = [UIColor whiteColor]; NSLog(@"❌ Failed to download image: %@", error.localizedDescription);
card.layer.cornerRadius = 8; return;
card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor; }
card.layer.shadowOpacity = 0.8; UIImage *image = [UIImage imageWithData:data];
card.layer.shadowOffset = CGSizeMake(0, 1); if (!image) return;
UILabel *body = [[UILabel alloc] initWithFrame:CGRectMake(12, 12, card.bounds.size.width - 24, 80)]; dispatch_async(dispatch_get_main_queue(), ^{
body.text = item[@"title"]; [strongSelf->_headerView configureWithProjectName:projectName
body.numberOfLines = 2; unitName:unitName
body.font = [UIFont systemFontOfSize:15]; backgroundImage:image
[card addSubview:body]; overlayImage:[UIImage imageNamed:@"overlay"]];
[sectionContainer addSubview:card]; });
}];
[task resume];
NSLog(@"🖼 Header image URL: %@", imageURL);
}];
[DashboardAPIClient fetchAnnouncements:^(NSArray *data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"📢 Announcements: %@", data);
[strongSelf populateSection:@"Project Update" withData:data];
}];
[DashboardAPIClient fetchAppointments:^(NSArray *data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"📅 Appointments: %@", data);
[strongSelf populateSection:@"Appointments" withData:data];
}];
[DashboardAPIClient fetchIssues:^(NSArray *data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"🪲 Issues: %@", data);
[strongSelf populateSection:@"Issue Updates" withData:data];
}];
}
- (UIImage *)downloadImageFrom:(NSString *)urlString {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
return data ? [UIImage imageWithData:data] : [UIImage imageNamed:@"header_bg"];
}
- (void)populateSection:(NSString *)title withData:(NSArray *)data {
CGFloat y = _currentY;
// --- Section Header ---
UILabel *header = [[UILabel alloc] initWithFrame:CGRectMake(16, y, self.view.bounds.size.width - 32, 24)];
header.text = title;
header.font = [UIFont boldSystemFontOfSize:18];
[_contentContainer addSubview:header];
y += 34;
// --- Special handling for Project Update ---
if ([title isEqualToString:@"Project Update"]) {
UIScrollView *hScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, y, self.view.bounds.size.width, 140)];
hScroll.showsHorizontalScrollIndicator = NO;
hScroll.autoresizingMask = UIViewAutoresizingFlexibleWidth;
CGFloat x = 16;
for (NSDictionary *item in data) {
UIView *card = [self createCardWithText:item[@"title"] ?: @"No title"
frame:CGRectMake(x, 0, 220, 120)];
[hScroll addSubview:card];
x += 236; // card width + spacing
}
hScroll.contentSize = CGSizeMake(x, 140);
[_contentContainer addSubview:hScroll];
y += 150; // spacing after horizontal list
} else {
// --- Vertical cards for all other sections ---
for (NSDictionary *item in data) {
UIView *card = [self createCardWithText:item[@"title"] ?: @"No title"
frame:CGRectMake(16, y, self.view.bounds.size.width - 32, 100)];
[_contentContainer addSubview:card];
y += 120; y += 120;
} }
sectionContainer.frame = CGRectMake(0, sectionContainer.frame.origin.y, self.view.bounds.size.width, y); y += 20; // extra bottom padding between sections
sectionBottomY = CGRectGetMaxY(sectionContainer.frame) + 20;
} }
_contentContainer.frame = CGRectMake(0, 0, _scrollView.bounds.size.width, sectionBottomY); _currentY = y;
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, sectionBottomY); _contentContainer.frame = CGRectMake(0, 0, _scrollView.bounds.size.width, _currentY);
_scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, _currentY);
}
#pragma mark - Card Factory with Tap Animation
- (UIView *)createCardWithText:(NSString *)text frame:(CGRect)frame {
UIView *card = [[UIView alloc] initWithFrame:frame];
card.backgroundColor = [UIColor whiteColor];
card.layer.cornerRadius = 8;
card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
card.layer.shadowOpacity = 0.8;
card.layer.shadowOffset = CGSizeMake(0, 1);
card.userInteractionEnabled = YES;
UILabel *body = [[UILabel alloc] initWithFrame:CGRectMake(12, 12, frame.size.width - 24, frame.size.height - 24)];
body.text = text;
body.numberOfLines = 2;
body.font = [UIFont systemFontOfSize:15];
[card addSubview:body];
// Add tap gesture with animation
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cardTapped:)];
[card addGestureRecognizer:tap];
return card;
}
#pragma mark - Tap Handlers
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gesture {
UILabel *header = (UILabel *)gesture.view;
[self animateTapForView:header];
NSLog(@"📘 Section tapped: %@", header.text);
}
- (void)cardTapped:(UITapGestureRecognizer *)gesture {
UIView *card = gesture.view;
[self animateTapForView:card];
NSLog(@"🟩 Card tapped: %@", ((UILabel *)card.subviews.firstObject).text);
}
- (void)animateTapForView:(UIView *)view {
[UIView animateWithDuration:0.1 animations:^{
view.transform = CGAffineTransformMakeScale(0.96, 0.96);
view.alpha = 0.8;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^{
view.transform = CGAffineTransformIdentity;
view.alpha = 1.0;
}];
}];
} }
@end @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