Commit cb977eab authored by Wei Han's avatar Wei Han

code update

parent 5e94fc51
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
0DB59E54C0AC880864FE2DED /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C76E4DA09BCDA64E6AB1EC44 /* libPods-example.a */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
2BE2AF4C6D3B8606D943CAF3 /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8352A4F24DF4210A8AFCA7C2 /* libPods-example.a */; };
44006126336D83DB220E7214 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; }; 44006126336D83DB220E7214 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = example/PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = example/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = example/AppDelegate.swift; sourceTree = "<group>"; }; 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = example/AppDelegate.swift; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = "<group>"; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = "<group>"; };
8352A4F24DF4210A8AFCA7C2 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 8A486A6AB07608F834FB5B89 /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = "<group>"; };
9174F6EB895EEB012209BA4C /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = "<group>"; }; 917B7F7F64B2B22022FAD12E /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = "<group>"; };
A060F5E8935E48625B4E63FC /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = "<group>"; }; C76E4DA09BCDA64E6AB1EC44 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */ /* End PBXFileReference section */
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
2BE2AF4C6D3B8606D943CAF3 /* libPods-example.a in Frameworks */, 0DB59E54C0AC880864FE2DED /* libPods-example.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
8352A4F24DF4210A8AFCA7C2 /* libPods-example.a */, C76E4DA09BCDA64E6AB1EC44 /* libPods-example.a */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -92,8 +92,8 @@ ...@@ -92,8 +92,8 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = { BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
9174F6EB895EEB012209BA4C /* Pods-example.debug.xcconfig */, 8A486A6AB07608F834FB5B89 /* Pods-example.debug.xcconfig */,
A060F5E8935E48625B4E63FC /* Pods-example.release.xcconfig */, 917B7F7F64B2B22022FAD12E /* Pods-example.release.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -105,13 +105,13 @@ ...@@ -105,13 +105,13 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */;
buildPhases = ( buildPhases = (
E427C8CAE7DBF9D62EAF2898 /* [CP] Check Pods Manifest.lock */, D1A8819C404F13A442A1FDE8 /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */, 13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */, 13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
29C7524E232168406C951301 /* [CP] Embed Pods Frameworks */, 4B89C01D6158CC79657F83B1 /* [CP] Embed Pods Frameworks */,
6333DBD2A89CA3E6CDB09BB7 /* [CP] Copy Pods Resources */, 91AD97B7843DEC6888B2EDE6 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
...@@ -183,7 +183,7 @@ ...@@ -183,7 +183,7 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
}; };
29C7524E232168406C951301 /* [CP] Embed Pods Frameworks */ = { 4B89C01D6158CC79657F83B1 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
...@@ -200,7 +200,7 @@ ...@@ -200,7 +200,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
6333DBD2A89CA3E6CDB09BB7 /* [CP] Copy Pods Resources */ = { 91AD97B7843DEC6888B2EDE6 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
...@@ -217,7 +217,7 @@ ...@@ -217,7 +217,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
E427C8CAE7DBF9D62EAF2898 /* [CP] Check Pods Manifest.lock */ = { D1A8819C404F13A442A1FDE8 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
...@@ -255,7 +255,7 @@ ...@@ -255,7 +255,7 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = { 13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 9174F6EB895EEB012209BA4C /* Pods-example.debug.xcconfig */; baseConfigurationReference = 8A486A6AB07608F834FB5B89 /* Pods-example.debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
...@@ -283,7 +283,7 @@ ...@@ -283,7 +283,7 @@
}; };
13B07F951A680F5B00A75B9A /* Release */ = { 13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = A060F5E8935E48625B4E63FC /* Pods-example.release.xcconfig */; baseConfigurationReference = 917B7F7F64B2B22022FAD12E /* Pods-example.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
......
...@@ -8,32 +8,32 @@ ...@@ -8,32 +8,32 @@
<key>BinaryPath</key> <key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string> <string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key> <key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string> <string>ios-arm64</string>
<key>LibraryPath</key> <key>LibraryPath</key>
<string>QmsPluginFramework.framework</string> <string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key> <key>SupportedArchitectures</key>
<array> <array>
<string>arm64</string> <string>arm64</string>
<string>x86_64</string>
</array> </array>
<key>SupportedPlatform</key> <key>SupportedPlatform</key>
<string>ios</string> <string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict> </dict>
<dict> <dict>
<key>BinaryPath</key> <key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string> <string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key> <key>LibraryIdentifier</key>
<string>ios-arm64</string> <string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key> <key>LibraryPath</key>
<string>QmsPluginFramework.framework</string> <string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key> <key>SupportedArchitectures</key>
<array> <array>
<string>arm64</string> <string>arm64</string>
<string>x86_64</string>
</array> </array>
<key>SupportedPlatform</key> <key>SupportedPlatform</key>
<string>ios</string> <string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict> </dict>
</array> </array>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
......
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "AppointmentAPIClient.h" #import "AppointmentAPIClient.h"
#import <WebKit/WebKit.h> #import <WebKit/WebKit.h>
#import "CalendarView.h"
@interface AppointmentViewController () <WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate> @interface AppointmentViewController () <WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate, CalendarViewDelegate>
@property (nonatomic, strong) UIView *headerBar; @property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *titleLabel;
...@@ -25,9 +26,10 @@ ...@@ -25,9 +26,10 @@
@property (nonatomic, strong) NSDictionary *appointmentData; @property (nonatomic, strong) NSDictionary *appointmentData;
@property (nonatomic, strong) WKWebView *termsWebView; @property (nonatomic, strong) WKWebView *termsWebView;
// Calendar placeholder // Calendar
@property (nonatomic, strong) UIView *calendarContainer; @property (nonatomic, strong) UIView *calendarContainer;
@property (nonatomic, strong) UIStackView *legendStack; @property (nonatomic, strong) UIStackView *legendStack;
@property (nonatomic, strong) CalendarView *calendarView;
// Footer buttons // Footer buttons
@property (nonatomic, strong) UIView *footerView; @property (nonatomic, strong) UIView *footerView;
...@@ -209,6 +211,11 @@ ...@@ -209,6 +211,11 @@
self.calendarContainer.translatesAutoresizingMaskIntoConstraints = NO; self.calendarContainer.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.calendarContainer]; [self.contentView addSubview:self.calendarContainer];
self.calendarView = [[CalendarView alloc] initWithFrame:CGRectZero];
self.calendarView.translatesAutoresizingMaskIntoConstraints = NO;
self.calendarView.delegate = self;
[self.calendarContainer addSubview:self.calendarView];
// Legend stack // Legend stack
self.legendStack = [[UIStackView alloc] init]; self.legendStack = [[UIStackView alloc] init];
self.legendStack.axis = UILayoutConstraintAxisHorizontal; self.legendStack.axis = UILayoutConstraintAxisHorizontal;
...@@ -247,11 +254,22 @@ ...@@ -247,11 +254,22 @@
[self.calendarContainer.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:20], [self.calendarContainer.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:20],
[self.calendarContainer.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16], [self.calendarContainer.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.calendarContainer.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16], [self.calendarContainer.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[self.calendarContainer.heightAnchor constraintEqualToConstant:320],
[self.calendarView.topAnchor constraintEqualToAnchor:self.calendarContainer.topAnchor constant:12],
[self.calendarView.leadingAnchor constraintEqualToAnchor:self.calendarContainer.leadingAnchor constant:12],
[self.calendarView.trailingAnchor constraintEqualToAnchor:self.calendarContainer.trailingAnchor constant:-12],
[self.calendarView.bottomAnchor constraintEqualToAnchor:self.calendarContainer.bottomAnchor constant:-12],
[self.legendStack.topAnchor constraintEqualToAnchor:self.calendarContainer.bottomAnchor constant:16], [self.legendStack.topAnchor constraintEqualToAnchor:self.calendarContainer.bottomAnchor constant:16],
[self.legendStack.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor] [self.legendStack.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor]
]]; ]];
CGFloat w = UIScreen.mainScreen.bounds.size.width - 16 - 16 - 12 - 12; // container + inner padding
CGFloat cell = floor(w / 7.0);
CGFloat rows = 6; // max rows calendar ever needs
CGFloat calendarHeight = 40 + 28 + (cell * 0.9 + 12) * rows + 12 + 15;
[self.calendarView.heightAnchor constraintEqualToConstant:calendarHeight].active = YES;
} }
#pragma mark - Footer Buttons #pragma mark - Footer Buttons
...@@ -452,4 +470,12 @@ ...@@ -452,4 +470,12 @@
} }
} }
- (void)calendarView:(CalendarView *)calendar didSelectDate:(NSDate *)date {
NSLog(@"Selected date = %@", date);
}
- (void)calendarViewMonthChanged:(NSDate *)monthFirstDay {
NSLog(@"Month changed = %@", monthFirstDay);
}
@end @end
// CalendarDayCell.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CalendarDayCell : UICollectionViewCell
@property (nonatomic, strong) UILabel *dayLabel;
@property (nonatomic, strong) UIView *statusDot;
@property (nonatomic, strong) UIView *selectionRing;
// Configure cell:
- (void)configureWithDay:(nullable NSNumber *)day
inMonth:(BOOL)inMonth
enabled:(BOOL)enabled
status:(nullable NSString *)status // @"available"/@"limited"/@"unavailable" or nil
selected:(BOOL)selected;
@end
NS_ASSUME_NONNULL_END
// CalendarDayCell.mm
#import "CalendarDayCell.h"
@implementation CalendarDayCell
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.selectionRing = [[UIView alloc] init];
self.selectionRing.translatesAutoresizingMaskIntoConstraints = NO;
self.selectionRing.layer.cornerRadius = 20;
self.selectionRing.layer.masksToBounds = YES;
self.selectionRing.backgroundColor = [UIColor clearColor];
[self.contentView addSubview:self.selectionRing];
self.dayLabel = [[UILabel alloc] init];
self.dayLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.dayLabel.textAlignment = NSTextAlignmentCenter;
self.dayLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular];
[self.selectionRing addSubview:self.dayLabel];
self.statusDot = [[UIView alloc] init];
self.statusDot.translatesAutoresizingMaskIntoConstraints = NO;
self.statusDot.layer.cornerRadius = 5;
self.statusDot.hidden = YES;
[self.contentView addSubview:self.statusDot];
[NSLayoutConstraint activateConstraints:@[
[self.selectionRing.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor],
[self.selectionRing.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor constant:-6],
[self.selectionRing.widthAnchor constraintEqualToConstant:40],
[self.selectionRing.heightAnchor constraintEqualToConstant:40],
[self.dayLabel.centerXAnchor constraintEqualToAnchor:self.selectionRing.centerXAnchor],
[self.dayLabel.centerYAnchor constraintEqualToAnchor:self.selectionRing.centerYAnchor],
[self.statusDot.topAnchor constraintEqualToAnchor:self.selectionRing.bottomAnchor constant:6],
[self.statusDot.centerXAnchor constraintEqualToAnchor:self.selectionRing.centerXAnchor],
[self.statusDot.widthAnchor constraintEqualToConstant:10],
[self.statusDot.heightAnchor constraintEqualToConstant:10],
]];
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
self.dayLabel.text = @"";
self.statusDot.hidden = YES;
self.selectionRing.backgroundColor = [UIColor clearColor];
self.dayLabel.textColor = [UIColor blackColor];
}
- (void)configureWithDay:(nullable NSNumber *)day
inMonth:(BOOL)inMonth
enabled:(BOOL)enabled
status:(nullable NSString *)status
selected:(BOOL)selected
{
if (day == nil || !inMonth) {
// empty cell (padding)
self.dayLabel.text = @"";
self.userInteractionEnabled = NO;
self.dayLabel.alpha = 0.0;
self.statusDot.hidden = YES;
return;
}
self.dayLabel.alpha = 1.0;
self.dayLabel.text = [NSString stringWithFormat:@"%@", day];
self.userInteractionEnabled = enabled;
// style for enabled/disabled
if (!enabled) {
self.dayLabel.textColor = [UIColor colorWithWhite:0.8 alpha:1.0];
} else {
self.dayLabel.textColor = [UIColor colorWithWhite:0.12 alpha:1.0];
}
// status dot
if (status != nil && status.length > 0) {
self.statusDot.hidden = NO;
if ([status isEqualToString:@"available"]) {
self.statusDot.backgroundColor = [UIColor colorWithRed:0.27 green:0.85 blue:0.36 alpha:1.0]; // green
} else if ([status isEqualToString:@"limited"]) {
self.statusDot.backgroundColor = [UIColor colorWithRed:1.0 green:0.59 blue:0.0 alpha:1.0]; // orange
} else if ([status isEqualToString:@"unavailable"]) {
self.statusDot.backgroundColor = [UIColor colorWithRed:1.0 green:0.23 blue:0.19 alpha:1.0]; // red
} else {
self.statusDot.hidden = YES;
}
} else {
self.statusDot.hidden = YES;
}
// selected ring
if (selected) {
self.selectionRing.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.dayLabel.textColor = [UIColor whiteColor];
} else {
self.selectionRing.backgroundColor = [UIColor clearColor];
// small subtle background for current day could be added here
}
}
@end
// CalendarView.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class CalendarView;
@protocol CalendarViewDelegate <NSObject>
- (void)calendarView:(CalendarView *)calendar didSelectDate:(NSDate *)date;
- (void)calendarViewMonthChanged:(NSDate *)monthFirstDay;
@end
@interface CalendarView : UIView
@property (nonatomic, weak) id<CalendarViewDelegate> delegate;
// minDate disables earlier days
@property (nonatomic, strong) NSDate *minDate;
// markedDates: NSDictionary keyed by "yyyy-MM-dd" -> @{ @"status": @"available"/@"limited"/@"unavailable" }
@property (nonatomic, copy) NSDictionary<NSString*, NSDictionary*> *markedDates;
// currently selected date
@property (nonatomic, strong, nullable) NSDate *selectedDate;
// set starting month (default = today)
- (void)setDisplayedMonth:(NSDate *)monthAnimated:(BOOL)animated;
@end
NS_ASSUME_NONNULL_END
// NSDate+CalendarHelpers.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSDate (CalendarHelpers)
- (NSDate *)startOfMonth;
- (NSDate *)endOfMonth;
- (NSInteger)numberOfDaysInMonth;
- (NSInteger)weekdayOfFirstDay; // 1 = Sunday, 2 = Monday ...
- (NSDate *)dateByAddingMonths:(NSInteger)months;
- (BOOL)isSameDayAsDate:(NSDate *)otherDate;
- (NSString *)yyyyMMddString;
@end
NS_ASSUME_NONNULL_END
// NSDate+CalendarHelpers.mm
#import "NSDate+CalendarHelpers.h"
@implementation NSDate (CalendarHelpers)
- (NSCalendar *)_calendar {
static NSCalendar *cal;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cal = [NSCalendar currentCalendar];
cal.timeZone = [NSTimeZone systemTimeZone];
});
return cal;
}
- (NSDate *)startOfMonth {
NSCalendar *cal = [self _calendar];
NSDateComponents *comps = [cal components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:self];
comps.day = 1;
return [cal dateFromComponents:comps];
}
- (NSDate *)endOfMonth {
NSCalendar *cal = [self _calendar];
NSDateComponents *comps = [cal components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:self];
comps.month += 1;
comps.day = 0;
return [cal dateFromComponents:comps];
}
- (NSInteger)numberOfDaysInMonth {
NSCalendar *cal = [self _calendar];
NSRange r = [cal rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:self];
return r.length;
}
- (NSInteger)weekdayOfFirstDay {
NSCalendar *cal = [self _calendar];
NSDate *start = [self startOfMonth];
NSDateComponents *c = [cal components:NSCalendarUnitWeekday fromDate:start];
return c.weekday;
}
- (NSDate *)dateByAddingMonths:(NSInteger)months {
NSCalendar *cal = [self _calendar];
NSDateComponents *c = [[NSDateComponents alloc] init];
c.month = months;
return [cal dateByAddingComponents:c toDate:self options:0];
}
- (BOOL)isSameDayAsDate:(NSDate *)otherDate {
NSCalendar *cal = [self _calendar];
NSDateComponents *a = [cal components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:self];
NSDateComponents *b = [cal components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:otherDate];
return (a.year == b.year && a.month == b.month && a.day == b.day);
}
- (NSString *)yyyyMMddString {
static NSDateFormatter *fmt;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd";
fmt.timeZone = [NSTimeZone systemTimeZone];
});
return [fmt stringFromDate:self];
}
@end
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#import "HistoryViewController.h" #import "HistoryViewController.h"
#import "HistoryAPIClient.h" #import "HistoryAPIClient.h"
#import "CalendarView.h"
#import "NSDate+CalendarHelpers.h"
@interface HistoryViewController () <UITableViewDelegate, UITableViewDataSource> @interface HistoryViewController () <UITableViewDelegate, UITableViewDataSource>
......
...@@ -8,32 +8,32 @@ ...@@ -8,32 +8,32 @@
<key>BinaryPath</key> <key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string> <string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key> <key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string> <string>ios-arm64</string>
<key>LibraryPath</key> <key>LibraryPath</key>
<string>QmsPluginFramework.framework</string> <string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key> <key>SupportedArchitectures</key>
<array> <array>
<string>arm64</string> <string>arm64</string>
<string>x86_64</string>
</array> </array>
<key>SupportedPlatform</key> <key>SupportedPlatform</key>
<string>ios</string> <string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict> </dict>
<dict> <dict>
<key>BinaryPath</key> <key>BinaryPath</key>
<string>QmsPluginFramework.framework/QmsPluginFramework</string> <string>QmsPluginFramework.framework/QmsPluginFramework</string>
<key>LibraryIdentifier</key> <key>LibraryIdentifier</key>
<string>ios-arm64</string> <string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key> <key>LibraryPath</key>
<string>QmsPluginFramework.framework</string> <string>QmsPluginFramework.framework</string>
<key>SupportedArchitectures</key> <key>SupportedArchitectures</key>
<array> <array>
<string>arm64</string> <string>arm64</string>
<string>x86_64</string>
</array> </array>
<key>SupportedPlatform</key> <key>SupportedPlatform</key>
<string>ios</string> <string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict> </dict>
</array> </array>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment