diff --git a/.gitmodules b/.gitmodules index 43a256942..3e8e7e50e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "NYPLAudiobookToolkit"] path = NYPLAudiobookToolkit url = https://github.com/NYPL-Simplified/NYPLAudiobookToolkit.git +[submodule "availability"] + path = availability + url = https://github.com/go-darwin/availability diff --git a/NYPLAEToolkit b/NYPLAEToolkit index 6fc1c3285..b93f55108 160000 --- a/NYPLAEToolkit +++ b/NYPLAEToolkit @@ -1 +1 @@ -Subproject commit 6fc1c3285c9095f6c36470d69ca25272a817372a +Subproject commit b93f55108b9b6ffd5a99743bcfed5b920c0d51e1 diff --git a/NYPLAudiobookToolkit b/NYPLAudiobookToolkit index 5194fc4b3..e485079f7 160000 --- a/NYPLAudiobookToolkit +++ b/NYPLAudiobookToolkit @@ -1 +1 @@ -Subproject commit 5194fc4b3545cd3efc011ba2f6be27b0307cc920 +Subproject commit e485079f76218d9e73a976b58729e6fc2695ef3b diff --git a/Simplified.xcodeproj/project.pbxproj b/Simplified.xcodeproj/project.pbxproj index 92423b547..61ed85d81 100644 --- a/Simplified.xcodeproj/project.pbxproj +++ b/Simplified.xcodeproj/project.pbxproj @@ -1030,6 +1030,9 @@ 8C835DD5234D0B900050A18D /* NYPLFacetBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C835DD4234D0B900050A18D /* NYPLFacetBarView.swift */; }; 8CC26F832370C1DF0000D8E1 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC26F822370C1DF0000D8E1 /* Account.swift */; }; 8CE9C471237F84820072E964 /* NYPLBookDetailsProblemDocumentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CE9C470237F84820072E964 /* NYPLBookDetailsProblemDocumentViewController.swift */; }; + 95F0AA4B2E091D99007AA753 /* DeprecationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F0AA4A2E091D99007AA753 /* DeprecationView.swift */; }; + 95F0AA4C2E091D99007AA753 /* DeprecationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F0AA4A2E091D99007AA753 /* DeprecationView.swift */; }; + 95F0AA4D2E091D99007AA753 /* DeprecationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F0AA4A2E091D99007AA753 /* DeprecationView.swift */; }; A4276F481B00046300CA7194 /* NYPLMyBooksDownloadInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = A4276F471B00046300CA7194 /* NYPLMyBooksDownloadInfo.m */; }; A42E0DF11B3F5A490095EBAE /* NYPLRemoteViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A42E0DF01B3F5A490095EBAE /* NYPLRemoteViewController.m */; }; A42E0DF41B40F4E00095EBAE /* NYPLCatalogFeedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A42E0DF31B40F4E00095EBAE /* NYPLCatalogFeedViewController.m */; }; @@ -1708,6 +1711,7 @@ 8C835DD4234D0B900050A18D /* NYPLFacetBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NYPLFacetBarView.swift; sourceTree = ""; }; 8CC26F822370C1DF0000D8E1 /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; 8CE9C470237F84820072E964 /* NYPLBookDetailsProblemDocumentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NYPLBookDetailsProblemDocumentViewController.swift; sourceTree = ""; }; + 95F0AA4A2E091D99007AA753 /* DeprecationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeprecationView.swift; sourceTree = ""; }; A4276F461B00046300CA7194 /* NYPLMyBooksDownloadInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NYPLMyBooksDownloadInfo.h; sourceTree = ""; }; A4276F471B00046300CA7194 /* NYPLMyBooksDownloadInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NYPLMyBooksDownloadInfo.m; sourceTree = ""; }; A42E0DEF1B3F5A490095EBAE /* NYPLRemoteViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NYPLRemoteViewController.h; sourceTree = ""; }; @@ -2906,6 +2910,7 @@ 11B20E6C19D9F6DD00877A23 /* NYPLReloadView.h */, 11B20E6D19D9F6DD00877A23 /* NYPLReloadView.m */, 17E81F07261522B3001003C2 /* NYPLRoundedButton.swift */, + 95F0AA4A2E091D99007AA753 /* DeprecationView.swift */, ); path = Views; sourceTree = ""; @@ -3763,6 +3768,7 @@ 2126FE6625C089110095C45C /* ReaderFormatModule.swift in Sources */, 7321485C28651E4B000DF0F0 /* NYPLSignInModalFactory.swift in Sources */, 73EB0A8725821DF4006BC997 /* NYPLCatalogGroupedFeedViewController.m in Sources */, + 95F0AA4B2E091D99007AA753 /* DeprecationView.swift in Sources */, 73EB0A8825821DF4006BC997 /* NYPLBackgroundExecutor.swift in Sources */, 73D8D27F25A68D4300DF5F69 /* NYPLBookmarkR2Location.swift in Sources */, 73EB0A8925821DF4006BC997 /* NYPLProblemDocument.swift in Sources */, @@ -4024,6 +4030,7 @@ 7359DCB527E92462001C4254 /* NYPLSignInBusinessLogic+OAuthClientCredentials.swift in Sources */, 73FCA2C625005BA4001B0C5D /* NYPLReloadView.m in Sources */, 1747335C2853B1190090B1F3 /* NYPLSettingsDeleteServerDataViewController.swift in Sources */, + 95F0AA4C2E091D99007AA753 /* DeprecationView.swift in Sources */, 73FCA2C925005BA4001B0C5D /* NYPLCatalogGroupedFeedViewController.m in Sources */, 73FCA2CA25005BA4001B0C5D /* NYPLBackgroundExecutor.swift in Sources */, 73CB8CC9285012D700603BA1 /* OELoginNavHeader.swift in Sources */, @@ -4327,6 +4334,7 @@ 11E0208D197F05D9009DEA93 /* UIFont+NYPLSystemFontOverride.m in Sources */, 03690E291EB2B44300F75D5F /* NYPLReadiumBookmark.swift in Sources */, E683953B217663B100371072 /* NYPLFacetViewDefaultDataSource.swift in Sources */, + 95F0AA4D2E091D99007AA753 /* DeprecationView.swift in Sources */, 174733662857A6950090B1F3 /* NYPLSettingsDeleteLibraryCardViewController.swift in Sources */, 73B5DFDC26052A1800225C12 /* NYPLBookButtonsState.m in Sources */, E6207B652118973800864143 /* NYPLAppTheme.swift in Sources */, @@ -4721,7 +4729,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.9.5; + MARKETING_VERSION = 3.9.7; PRODUCT_BUNDLE_IDENTIFIER = org.nypl.labs.SimplyE; PRODUCT_MODULE_NAME = SimplyE; PROVISIONING_PROFILE = "2e185b6c-271e-4b02-a05e-860b8c3831f6"; @@ -4768,7 +4776,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.9.5; + MARKETING_VERSION = 3.9.7; PRODUCT_BUNDLE_IDENTIFIER = org.nypl.labs.SimplyE; PRODUCT_MODULE_NAME = SimplyE; PROVISIONING_PROFILE = "b3d9154d-70e1-48d6-a0c5-869431277a5c"; @@ -5020,8 +5028,11 @@ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; CODE_SIGN_ENTITLEMENTS = Simplified/SimplyE.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = 7262U6ST2R; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 7262U6ST2R; + ENABLE_USER_SCRIPT_SANDBOXING = NO; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Simplified/AppInfrastructure/Simplified-Prefix.pch"; @@ -5040,7 +5051,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.9.6; + MARKETING_VERSION = 3.9.7; OTHER_LDFLAGS = ( "$(inherited)", "-ld_classic", @@ -5048,6 +5059,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.nypl.labs.SimplyE; PROVISIONING_PROFILE = "2e185b6c-271e-4b02-a05e-860b8c3831f6"; PROVISIONING_PROFILE_SPECIFIER = "SimplyE Development"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "SimplyE Dev"; RUN_CLANG_STATIC_ANALYZER = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG SIMPLYE FEATURE_DRM_CONNECTOR FEATURE_CRASH_REPORTING FEATURE_OVERDRIVE_AUTH FEATURE_AUDIOBOOKS AXIS"; SWIFT_OBJC_BRIDGING_HEADER = "Simplified/AppInfrastructure/SimplyE-Bridging-Header.h"; @@ -5074,8 +5086,11 @@ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; CODE_SIGN_ENTITLEMENTS = Simplified/SimplyE.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = 7262U6ST2R; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 7262U6ST2R; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Simplified/AppInfrastructure/Simplified-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -5093,7 +5108,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.9.6; + MARKETING_VERSION = 3.9.7; OTHER_LDFLAGS = ( "$(inherited)", "-ld_classic", @@ -5101,6 +5116,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.nypl.labs.SimplyE; PROVISIONING_PROFILE = "b3d9154d-70e1-48d6-a0c5-869431277a5c"; PROVISIONING_PROFILE_SPECIFIER = "SimplyE Distribution"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "SimplyE Dev"; RUN_CLANG_STATIC_ANALYZER = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "SIMPLYE FEATURE_DRM_CONNECTOR FEATURE_CRASH_REPORTING FEATURE_OVERDRIVE_AUTH FEATURE_AUDIOBOOKS AXIS"; SWIFT_OBJC_BRIDGING_HEADER = "Simplified/AppInfrastructure/SimplyE-Bridging-Header.h"; diff --git a/Simplified/Announcements/NYPLAnnouncementBusinessLogic.swift b/Simplified/Announcements/NYPLAnnouncementBusinessLogic.swift index 83ed7940d..899f2e00d 100644 --- a/Simplified/Announcements/NYPLAnnouncementBusinessLogic.swift +++ b/Simplified/Announcements/NYPLAnnouncementBusinessLogic.swift @@ -83,7 +83,7 @@ class NYPLAnnouncementBusinessLogic { - Returns: The alert controller to be presented. */ private func alert(announcements: [Announcement]) -> UIAlertController? { - let title = NSLocalizedString("Announcement", comment: "") + let title = NSLocalizedString("Important Update", comment: "") var currentAlert: UIAlertController? = nil let alerts = announcements.map { diff --git a/Simplified/AppInfrastructure/NYPLConfiguration.swift b/Simplified/AppInfrastructure/NYPLConfiguration.swift index 0a0aa919b..0290ec8dd 100644 --- a/Simplified/AppInfrastructure/NYPLConfiguration.swift +++ b/Simplified/AppInfrastructure/NYPLConfiguration.swift @@ -28,6 +28,10 @@ class NYPLConfiguration: NSObject { @objc static var accentColor: UIColor { return UIColor(red: 0.0/255.0, green: 144/255.0, blue: 196/255.0, alpha:1.0) } + + @objc static var blueBackgroundColor: UIColor { + return UIColor(red: 20/255.0, green: 54/255.0, blue: 97/255.0, alpha:1.0) + } @objc static var readerBackgroundColor: UIColor { return UIColor(white: 250/255.0, alpha:1.0) diff --git a/Simplified/AppInfrastructure/Simplified-Prefix.pch b/Simplified/AppInfrastructure/Simplified-Prefix.pch index 49c286c42..c1f321a8c 100644 --- a/Simplified/AppInfrastructure/Simplified-Prefix.pch +++ b/Simplified/AppInfrastructure/Simplified-Prefix.pch @@ -1,6 +1,6 @@ #ifndef __cplusplus -@import Darwin.Availability; +//@import Darwin.availability; #ifndef __IPHONE_3_0 #warning "This project uses features only available in iOS SDK 3.0 and later." diff --git a/Simplified/Catalog/NYPLCatalogGroupedFeedViewController.m b/Simplified/Catalog/NYPLCatalogGroupedFeedViewController.m index b009445b2..1936dd815 100644 --- a/Simplified/Catalog/NYPLCatalogGroupedFeedViewController.m +++ b/Simplified/Catalog/NYPLCatalogGroupedFeedViewController.m @@ -34,6 +34,7 @@ @interface NYPLCatalogGroupedFeedViewController () @property (nonatomic) UIRefreshControl *refreshControl; @property (nonatomic) NYPLOpenSearchDescription *searchDescription; @property (nonatomic) NYPLFacetBarView *facetBarView; +@property (nonatomic) DeprecationView *deprecationView; @property (nonatomic) UITableView *tableView; @property (nonatomic) NYPLBook *mostRecentBookSelected; @property (nonatomic) int tempBookPosition; @@ -95,14 +96,20 @@ - (void)viewDidLoad [self.tableView addSubview:self.refreshControl]; [self.view addSubview:self.tableView]; - self.facetBarView = [[NYPLFacetBarView alloc] initWithOrigin:CGPointZero width:self.view.bounds.size.width]; + self.deprecationView = [[DeprecationView alloc] initWithOrigin:CGPointZero width:self.view.bounds.size.width]; + [self.view addSubview:self.deprecationView]; + [self.deprecationView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; + [self.deprecationView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + [self.deprecationView autoPinEdgeToSuperviewSafeArea:ALEdgeTop]; + + self.facetBarView = [[NYPLFacetBarView alloc] initWithOrigin:CGPointMake(0, self.deprecationView.frame.size.height) width:self.view.bounds.size.width]; self.facetBarView.entryPointView.delegate = self; self.facetBarView.entryPointView.dataSource = self; [self.view addSubview:self.facetBarView]; [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; - [self.facetBarView autoPinEdgeToSuperviewSafeArea:ALEdgeTop]; + [self.facetBarView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_deprecationView]; if(self.feed.openSearchURL) { self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] @@ -131,7 +138,7 @@ - (void)didMoveToParentViewController:(UIViewController *)parent [super didMoveToParentViewController:parent]; if(parent) { - CGFloat top = self.view.safeAreaInsets.top; + CGFloat top = self.view.safeAreaInsets.top + self.deprecationView.frame.size.height + kTableViewInsetAdjustmentWithEntryPoints; if (self.facetBarView.frame.size.height > 0) { top = CGRectGetMaxY(self.facetBarView.frame) + kTableViewInsetAdjustmentWithEntryPoints; } diff --git a/Simplified/Catalog/NYPLCatalogUngroupedFeedViewController.m b/Simplified/Catalog/NYPLCatalogUngroupedFeedViewController.m index 528565869..33f6f6064 100644 --- a/Simplified/Catalog/NYPLCatalogUngroupedFeedViewController.m +++ b/Simplified/Catalog/NYPLCatalogUngroupedFeedViewController.m @@ -21,8 +21,8 @@ static const CGFloat kCollectionViewCrossfadeDuration = 0.3; @interface NYPLCatalogUngroupedFeedViewController () - + @property (nonatomic) NYPLOpenSearchDescription *searchDescription; @property (nonatomic) NYPLCatalogUngroupedFeed *feed; @@ -30,6 +30,7 @@ @interface NYPLCatalogUngroupedFeedViewController () @property (nonatomic, weak) NYPLRemoteViewController *remoteViewController; @property (nonatomic) UIRefreshControl *collectionViewRefreshControl; @property (nonatomic) UIActivityIndicatorView *collectionViewActivityIndicator; +@property (nonatomic) DeprecationView *deprecationView; @property (nonatomic) NYPLFacetBarView *facetBarView; @property (nonatomic) NYPLFacetViewDefaultDataSource *facetViewDataSource; @@ -40,111 +41,116 @@ @implementation NYPLCatalogUngroupedFeedViewController - (instancetype)initWithUngroupedFeed:(NYPLCatalogUngroupedFeed *const)feed remoteViewController:(NYPLRemoteViewController *const)remoteViewController { - self = [super init]; - if(!self) return nil; - self.feed = feed; - self.feed.delegate = self; - self.remoteViewController = remoteViewController; - - return self; + self = [super init]; + if(!self) return nil; + self.feed = feed; + self.feed.delegate = self; + self.remoteViewController = remoteViewController; + + return self; } - (UIEdgeInsets)scrollIndicatorInsets { - return UIEdgeInsetsMake(CGRectGetMaxY(self.facetBarView.frame), - 0, - self.view.safeAreaInsets.bottom, - 0); + return UIEdgeInsetsMake(CGRectGetMaxY(self.facetBarView.frame), + 0, + self.view.safeAreaInsets.bottom, + 0); } #pragma mark UIViewController - (void)viewDidLoad { - [super viewDidLoad]; - - self.collectionView.dataSource = self; - self.collectionView.delegate = self; - self.collectionView.alpha = 0.0; - - if (@available(iOS 11.0, *)) { - self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; - } - self.collectionView.alwaysBounceVertical = YES; - self.collectionViewRefreshControl = [[UIRefreshControl alloc] init]; - [self.collectionViewRefreshControl addTarget:self action:@selector(userDidRefresh:) forControlEvents:UIControlEventValueChanged]; - [self.collectionView addSubview:self.collectionViewRefreshControl]; - - if(self.feed.openSearchURL) { - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] - initWithImage:[UIImage imageNamed:@"Search"] - style:UIBarButtonItemStylePlain - target:self - action:@selector(didSelectSearch)]; - self.navigationItem.rightBarButtonItem.accessibilityLabel = NSLocalizedString(@"Search", nil); - self.navigationItem.rightBarButtonItem.enabled = NO; - - // prevent possible unusable Search box when going to Search page - self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] - initWithTitle:NSLocalizedString(@"Back", @"Back button text") - style:UIBarButtonItemStylePlain - target:nil action:nil]; + [super viewDidLoad]; + + self.collectionView.dataSource = self; + self.collectionView.delegate = self; + self.collectionView.alpha = 0.0; + + if (@available(iOS 11.0, *)) { + self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + } + self.collectionView.alwaysBounceVertical = YES; + self.collectionViewRefreshControl = [[UIRefreshControl alloc] init]; + [self.collectionViewRefreshControl addTarget:self action:@selector(userDidRefresh:) forControlEvents:UIControlEventValueChanged]; + [self.collectionView addSubview:self.collectionViewRefreshControl]; + + if(self.feed.openSearchURL) { + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] + initWithImage:[UIImage imageNamed:@"Search"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(didSelectSearch)]; + self.navigationItem.rightBarButtonItem.accessibilityLabel = NSLocalizedString(@"Search", nil); + self.navigationItem.rightBarButtonItem.enabled = NO; + + // prevent possible unusable Search box when going to Search page + self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] + initWithTitle:NSLocalizedString(@"Back", @"Back button text") + style:UIBarButtonItemStylePlain + target:nil action:nil]; + + [self fetchOpenSearchDescription]; + } + + [self.collectionView reloadData]; + self.deprecationView = [[DeprecationView alloc] initWithOrigin:CGPointZero width:self.view.bounds.size.width]; + [self.view addSubview:self.deprecationView]; + [self.deprecationView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; + [self.deprecationView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + [self.deprecationView autoPinEdgeToSuperviewSafeArea:ALEdgeTop]; + + self.facetBarView = [[NYPLFacetBarView alloc] initWithOrigin:CGPointMake(0, self.deprecationView.frame.size.height) width:self.view.bounds.size.width]; + self.facetBarView.entryPointView.delegate = self; + self.facetBarView.entryPointView.dataSource = self; + self.facetViewDataSource = [[NYPLFacetViewDefaultDataSource alloc] initWithFacetGroups:self.feed.facetGroups]; + self.facetBarView.facetView.delegate = self; + self.facetBarView.facetView.dataSource = self.facetViewDataSource; - [self fetchOpenSearchDescription]; - } - - [self.collectionView reloadData]; - - self.facetBarView = [[NYPLFacetBarView alloc] initWithOrigin:CGPointZero width:self.view.bounds.size.width]; - self.facetBarView.entryPointView.delegate = self; - self.facetBarView.entryPointView.dataSource = self; - self.facetViewDataSource = [[NYPLFacetViewDefaultDataSource alloc] initWithFacetGroups:self.feed.facetGroups]; - self.facetBarView.facetView.delegate = self; - self.facetBarView.facetView.dataSource = self.facetViewDataSource; - - [self.view addSubview:self.facetBarView]; - [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; - [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; - [self.facetBarView autoPinEdgeToSuperviewSafeArea:ALEdgeTop]; - - self.collectionViewActivityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; - self.collectionViewActivityIndicator.hidden = YES; - [self.collectionViewActivityIndicator startAnimating]; - [self.collectionView addSubview:self.collectionViewActivityIndicator]; - - [self enable3DTouch]; + [self.view addSubview:self.facetBarView]; + [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; + [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + [self.facetBarView autoPinEdgeToSuperviewSafeArea:ALEdgeTop]; + + self.collectionViewActivityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + self.collectionViewActivityIndicator.hidden = YES; + [self.collectionViewActivityIndicator startAnimating]; + [self.collectionView addSubview:self.collectionViewActivityIndicator]; + + [self enable3DTouch]; } - (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [UIView animateWithDuration:kCollectionViewCrossfadeDuration animations:^{ - self.collectionView.alpha = 1.0; - self.facetBarView.alpha = 1.0; - }]; + [super viewDidAppear:animated]; + [UIView animateWithDuration:kCollectionViewCrossfadeDuration animations:^{ + self.collectionView.alpha = 1.0; + self.facetBarView.alpha = 1.0; + }]; } - (void)didMoveToParentViewController:(UIViewController *)parent { - [super didMoveToParentViewController:parent]; - - if(parent) { - [self updateActivityIndicator]; - self.collectionView.scrollIndicatorInsets = [self scrollIndicatorInsets]; - [self.collectionView setContentOffset:CGPointMake(0, -CGRectGetMaxY(self.facetBarView.frame)) - animated:NO]; - } + [super didMoveToParentViewController:parent]; + + if(parent) { + [self updateActivityIndicator]; + self.collectionView.scrollIndicatorInsets = [self scrollIndicatorInsets]; + [self.collectionView setContentOffset:CGPointMake(0, -CGRectGetMaxY(self.facetBarView.frame)) + animated:NO]; + } } - (void)userDidRefresh:(UIRefreshControl *)refreshControl { - if ([[self.navigationController.visibleViewController class] isSubclassOfClass:[NYPLCatalogFeedViewController class]] && - [self.navigationController.visibleViewController respondsToSelector:@selector(load)]) { - [self.remoteViewController load]; - } - - [refreshControl endRefreshing]; - [[NSNotificationCenter defaultCenter] postNotificationName:NSNotification.NYPLSyncEnded object:nil]; + if ([[self.navigationController.visibleViewController class] isSubclassOfClass:[NYPLCatalogFeedViewController class]] && + [self.navigationController.visibleViewController respondsToSelector:@selector(load)]) { + [self.remoteViewController load]; + } + + [refreshControl endRefreshing]; + [[NSNotificationCenter defaultCenter] postNotificationName:NSNotification.NYPLSyncEnded object:nil]; } #pragma mark UICollectionViewDataSource @@ -152,18 +158,18 @@ - (void)userDidRefresh:(UIRefreshControl *)refreshControl - (NSInteger)collectionView:(__attribute__((unused)) UICollectionView *)collectionView numberOfItemsInSection:(__attribute__((unused)) NSInteger)section { - return self.feed.books.count; + return self.feed.books.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - [self.feed prepareForBookIndex:indexPath.row]; - [self updateActivityIndicator]; - - NYPLBook *const book = self.feed.books[indexPath.row]; - - return NYPLBookCellDequeue(collectionView, indexPath, book); + [self.feed prepareForBookIndex:indexPath.row]; + [self updateActivityIndicator]; + + NYPLBook *const book = self.feed.books[indexPath.row]; + + return NYPLBookCellDequeue(collectionView, indexPath, book); } #pragma mark UICollectionViewDelegate @@ -171,9 +177,9 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView - (void)collectionView:(__attribute__((unused)) UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *const)indexPath { - NYPLBook *const book = self.feed.books[indexPath.row]; - - [[[NYPLBookDetailViewController alloc] initWithBook:book] presentFromViewController:self]; + NYPLBook *const book = self.feed.books[indexPath.row]; + + [[[NYPLBookDetailViewController alloc] initWithBook:book] presentFromViewController:self]; } #pragma mark NYPLCatalogUngroupedFeedDelegate @@ -182,7 +188,7 @@ - (void)catalogUngroupedFeed:(__attribute__((unused)) NYPLCatalogUngroupedFeed *)catalogUngroupedFeed didUpdateBooks:(__attribute__((unused)) NSArray *)books { - [self.collectionView reloadData]; + [self.collectionView reloadData]; } - (void)catalogUngroupedFeed:(__attribute__((unused)) @@ -190,16 +196,16 @@ - (void)catalogUngroupedFeed:(__attribute__((unused)) didAddBooks:(__attribute__((unused)) NSArray *)books range:(NSRange const)range { - NSMutableArray *const indexPaths = [NSMutableArray arrayWithCapacity:range.length]; - - for(NSUInteger i = 0; i < range.length; ++i) { - NSUInteger indexes[2] = {0, i + range.location}; - [indexPaths addObject:[NSIndexPath indexPathWithIndexes:indexes length:2]]; - } - - // Just reloadData instead of inserting items, to avoid a weird crash (issue #144). -// [self.collectionView insertItemsAtIndexPaths:indexPaths]; - [self.collectionView reloadData]; + NSMutableArray *const indexPaths = [NSMutableArray arrayWithCapacity:range.length]; + + for(NSUInteger i = 0; i < range.length; ++i) { + NSUInteger indexes[2] = {0, i + range.location}; + [indexPaths addObject:[NSIndexPath indexPathWithIndexes:indexes length:2]]; + } + + // Just reloadData instead of inserting items, to avoid a weird crash (issue #144). + // [self.collectionView insertItemsAtIndexPaths:indexPaths]; + [self.collectionView reloadData]; } #pragma mark NYPLFacetViewDelegate @@ -207,122 +213,122 @@ - (void)catalogUngroupedFeed:(__attribute__((unused)) - (void)facetView:(__attribute__((unused)) NYPLFacetView *)facetView didSelectFacetAtIndexPath:(NSIndexPath *const)indexPath { - NYPLCatalogFacetGroup *const group = self.feed.facetGroups[[indexPath indexAtPosition:0]]; - NYPLCatalogFacet *const facet = group.facets[[indexPath indexAtPosition:1]]; - - NSURL *facetURL = facet.href; - if (facetURL != nil) { - [self.remoteViewController loadWithURL:facetURL]; - } else { - [NYPLErrorLogger logErrorWithCode:NYPLErrorCodeNoURL - summary:@"Facet missing the `href` URL to load" - metadata:@{ - @"methodName": @"facetView:didSelectFacetAtIndexPath:", - @"facet title": facet.title ?: @"N/A", - }]; - [self.remoteViewController showReloadViewWithMessage:NSLocalizedString(@"This URL cannot be found. Please close the app entirely and reload it. If the problem persists, please contact your library's Help Desk.", @"Generic error message indicating that the URL the user was trying to load is missing.")]; - } + NYPLCatalogFacetGroup *const group = self.feed.facetGroups[[indexPath indexAtPosition:0]]; + NYPLCatalogFacet *const facet = group.facets[[indexPath indexAtPosition:1]]; + + NSURL *facetURL = facet.href; + if (facetURL != nil) { + [self.remoteViewController loadWithURL:facetURL]; + } else { + [NYPLErrorLogger logErrorWithCode:NYPLErrorCodeNoURL + summary:@"Facet missing the `href` URL to load" + metadata:@{ + @"methodName": @"facetView:didSelectFacetAtIndexPath:", + @"facet title": facet.title ?: @"N/A", + }]; + [self.remoteViewController showReloadViewWithMessage:NSLocalizedString(@"This URL cannot be found. Please close the app entirely and reload it. If the problem persists, please contact your library's Help Desk.", @"Generic error message indicating that the URL the user was trying to load is missing.")]; + } } #pragma mark NYPLEntryPointViewDelegate - (void)entryPointViewDidSelectWithEntryPointFacet:(NYPLCatalogFacet *)entryPointFacet { - NSURL *const newURL = entryPointFacet.href; - - if (newURL != nil) { - [self.remoteViewController loadWithURL:newURL]; - } else { - [NYPLErrorLogger logErrorWithCode:NYPLErrorCodeNoURL - summary:@"Facet missing the `href` URL to load" - metadata:@{ - @"methodName": @"entryPointViewDidSelectWithEntryPointFacet:", - @"facet title": entryPointFacet.title ?: @"N/A", - }]; - [self.remoteViewController showReloadViewWithMessage:NSLocalizedString(@"This URL cannot be found. Please close the app entirely and reload it. If the problem persists, please contact your library's Help Desk.", @"Generic error message indicating that the URL the user was trying to load is missing.")]; - } + NSURL *const newURL = entryPointFacet.href; + + if (newURL != nil) { + [self.remoteViewController loadWithURL:newURL]; + } else { + [NYPLErrorLogger logErrorWithCode:NYPLErrorCodeNoURL + summary:@"Facet missing the `href` URL to load" + metadata:@{ + @"methodName": @"entryPointViewDidSelectWithEntryPointFacet:", + @"facet title": entryPointFacet.title ?: @"N/A", + }]; + [self.remoteViewController showReloadViewWithMessage:NSLocalizedString(@"This URL cannot be found. Please close the app entirely and reload it. If the problem persists, please contact your library's Help Desk.", @"Generic error message indicating that the URL the user was trying to load is missing.")]; + } } - (NSArray *)facetsForEntryPointView { - return self.feed.entryPoints; + return self.feed.entryPoints; } #pragma mark - 3D Touch -(void)enable3DTouch { - if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] && - (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)) { - [self registerForPreviewingWithDelegate:self sourceView:self.view]; - } + if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] && + (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)) { + [self registerForPreviewingWithDelegate:self sourceView:self.view]; + } } - (UIViewController *)previewingContext:(id)previewingContext viewControllerForLocation:(CGPoint)location { - CGPoint referencePoint = [self.collectionView convertPoint:location fromView:self.view]; - NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:referencePoint]; - UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath]; - if (![cell isKindOfClass:[NYPLBookNormalCell class]]) { - return nil; - } - NYPLBookNormalCell *bookCell = (NYPLBookNormalCell *) cell; - UIViewController *vc = [[UIViewController alloc] init]; - vc.view.tag = indexPath.row; - UIImageView *imView = [[UIImageView alloc] initWithImage:bookCell.cover.image]; - imView.contentMode = UIViewContentModeScaleAspectFill; - [vc.view addSubview:imView]; - [imView autoPinEdgesToSuperviewEdges]; - - vc.preferredContentSize = CGSizeZero; - previewingContext.sourceRect = [self.view convertRect:cell.frame fromView:[cell superview]]; - - return vc; + CGPoint referencePoint = [self.collectionView convertPoint:location fromView:self.view]; + NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:referencePoint]; + UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath]; + if (![cell isKindOfClass:[NYPLBookNormalCell class]]) { + return nil; + } + NYPLBookNormalCell *bookCell = (NYPLBookNormalCell *) cell; + UIViewController *vc = [[UIViewController alloc] init]; + vc.view.tag = indexPath.row; + UIImageView *imView = [[UIImageView alloc] initWithImage:bookCell.cover.image]; + imView.contentMode = UIViewContentModeScaleAspectFill; + [vc.view addSubview:imView]; + [imView autoPinEdgesToSuperviewEdges]; + + vc.preferredContentSize = CGSizeZero; + previewingContext.sourceRect = [self.view convertRect:cell.frame fromView:[cell superview]]; + + return vc; } - (void)previewingContext:(__unused id)previewingContext commitViewController:(UIViewController *)viewControllerToCommit { - NYPLBook *const book = self.feed.books[viewControllerToCommit.view.tag]; - [[[NYPLBookDetailViewController alloc] initWithBook:book] presentFromViewController:self]; + NYPLBook *const book = self.feed.books[viewControllerToCommit.view.tag]; + [[[NYPLBookDetailViewController alloc] initWithBook:book] presentFromViewController:self]; } #pragma mark - - (void)updateActivityIndicator { - UIEdgeInsets insets = [self scrollIndicatorInsets]; - if(self.feed.currentlyFetchingNextURL) { - insets.bottom += kActivityIndicatorPadding + self.collectionViewActivityIndicator.frame.size.height; - CGRect frame = self.collectionViewActivityIndicator.frame; - frame.origin = CGPointMake(CGRectGetMidX(self.collectionView.frame) - frame.size.width/2, - self.collectionView.contentSize.height + kActivityIndicatorPadding/2); - self.collectionViewActivityIndicator.frame = frame; - } - self.collectionViewActivityIndicator.hidden = !self.feed.currentlyFetchingNextURL; - self.collectionView.contentInset = insets; + UIEdgeInsets insets = [self scrollIndicatorInsets]; + if(self.feed.currentlyFetchingNextURL) { + insets.bottom += kActivityIndicatorPadding + self.collectionViewActivityIndicator.frame.size.height; + CGRect frame = self.collectionViewActivityIndicator.frame; + frame.origin = CGPointMake(CGRectGetMidX(self.collectionView.frame) - frame.size.width/2, + self.collectionView.contentSize.height + kActivityIndicatorPadding/2); + self.collectionViewActivityIndicator.frame = frame; + } + self.collectionViewActivityIndicator.hidden = !self.feed.currentlyFetchingNextURL; + self.collectionView.contentInset = insets; } - (void)didSelectSearch { - [self.navigationController - pushViewController:[[NYPLCatalogSearchViewController alloc] - initWithOpenSearchDescription:self.searchDescription] - animated:YES]; + [self.navigationController + pushViewController:[[NYPLCatalogSearchViewController alloc] + initWithOpenSearchDescription:self.searchDescription] + animated:YES]; } - (void)fetchOpenSearchDescription { - [NYPLOpenSearchDescription - withURL:self.feed.openSearchURL - shouldResetCache:NO - completionHandler:^(NYPLOpenSearchDescription *const description) { - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - self.searchDescription = description; - self.navigationItem.rightBarButtonItem.enabled = YES; - }]; - }]; + [NYPLOpenSearchDescription + withURL:self.feed.openSearchURL + shouldResetCache:NO + completionHandler:^(NYPLOpenSearchDescription *const description) { + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + self.searchDescription = description; + self.navigationItem.rightBarButtonItem.enabled = YES; + }]; + }]; } @end diff --git a/Simplified/MyBooks/NYPLMyBooksViewController.m b/Simplified/MyBooks/NYPLMyBooksViewController.m index 50895f12f..4e7b0ccd5 100644 --- a/Simplified/MyBooks/NYPLMyBooksViewController.m +++ b/Simplified/MyBooks/NYPLMyBooksViewController.m @@ -66,6 +66,7 @@ @interface NYPLMyBooksViewController () @property (nonatomic) FacetShow activeFacetShow; @property (nonatomic) FacetSort activeFacetSort; @property (nonatomic) NSArray *books; +@property (nonatomic) DeprecationView *deprecationView; @property (nonatomic) NYPLFacetBarView *facetBarView; @property (nonatomic) UILabel *instructionsLabel; @property (nonatomic) UIRefreshControl *refreshControl; @@ -115,52 +116,58 @@ - (void)dealloc - (void)viewDidLoad { - [super viewDidLoad]; - - self.view.backgroundColor = [NYPLConfiguration primaryBackgroundColor]; - - self.activeFacetShow = FacetShowAll; - self.activeFacetSort = FacetSortAuthor; - - self.collectionView.dataSource = self; - self.collectionView.delegate = self; - - self.collectionView.alwaysBounceVertical = YES; - self.refreshControl = [[UIRefreshControl alloc] init]; - [self.refreshControl addTarget:self action:@selector(didPullToRefresh) forControlEvents:UIControlEventValueChanged]; - [self.collectionView addSubview:self.refreshControl]; - - self.facetBarView = [[NYPLFacetBarView alloc] initWithOrigin:CGPointZero width:0]; - self.facetBarView.facetView.dataSource = self; - self.facetBarView.facetView.delegate = self; - [self.view addSubview:self.facetBarView]; - [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; - [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; - [self.facetBarView autoPinEdgeToSuperviewSafeArea:ALEdgeTop]; - - self.instructionsLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - self.instructionsLabel.hidden = YES; - self.instructionsLabel.text = NSLocalizedString(@"MyBooksGoToCatalog", nil); - self.instructionsLabel.textAlignment = NSTextAlignmentCenter; - self.instructionsLabel.textColor = [NYPLConfiguration primaryTextColor]; - self.instructionsLabel.numberOfLines = 0; - [self.view addSubview:self.instructionsLabel]; - [self.instructionsLabel autoCenterInSuperview]; - [self.instructionsLabel autoSetDimension:ALDimensionWidth toSize:300.0]; - - self.searchButton = [[UIBarButtonItem alloc] - initWithImage:[UIImage imageNamed:@"Search"] - style:UIBarButtonItemStylePlain - target:self - action:@selector(didSelectSearch)]; - self.searchButton.accessibilityLabel = NSLocalizedString(@"Search", nil); - self.navigationItem.rightBarButtonItem = self.searchButton; - - // prevent possible unusable Search box when going to Search page - self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] - initWithTitle:NSLocalizedString(@"Back", @"Back button text") - style:UIBarButtonItemStylePlain - target:nil action:nil]; + [super viewDidLoad]; + + self.view.backgroundColor = [NYPLConfiguration primaryBackgroundColor]; + + self.activeFacetShow = FacetShowAll; + self.activeFacetSort = FacetSortAuthor; + + self.collectionView.dataSource = self; + self.collectionView.delegate = self; + + self.collectionView.alwaysBounceVertical = YES; + self.refreshControl = [[UIRefreshControl alloc] init]; + [self.refreshControl addTarget:self action:@selector(didPullToRefresh) forControlEvents:UIControlEventValueChanged]; + [self.collectionView addSubview:self.refreshControl]; + + self.deprecationView = [[DeprecationView alloc] initWithOrigin:CGPointZero width:self.view.bounds.size.width]; + [self.view addSubview:self.deprecationView]; + [self.deprecationView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; + [self.deprecationView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + [self.deprecationView autoPinEdgeToSuperviewSafeArea:ALEdgeTop]; + + self.facetBarView = [[NYPLFacetBarView alloc] initWithOrigin:CGPointMake(0, self.deprecationView.frame.size.height) width:self.view.bounds.size.width]; + self.facetBarView.facetView.dataSource = self; + self.facetBarView.facetView.delegate = self; + [self.view addSubview:self.facetBarView]; + [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeLeading]; + [self.facetBarView autoPinEdgeToSuperviewEdge:ALEdgeTrailing]; + [self.facetBarView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_deprecationView]; + + self.instructionsLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.instructionsLabel.hidden = YES; + self.instructionsLabel.text = NSLocalizedString(@"MyBooksGoToCatalog", nil); + self.instructionsLabel.textAlignment = NSTextAlignmentCenter; + self.instructionsLabel.textColor = [NYPLConfiguration primaryTextColor]; + self.instructionsLabel.numberOfLines = 0; + [self.view addSubview:self.instructionsLabel]; + [self.instructionsLabel autoCenterInSuperview]; + [self.instructionsLabel autoSetDimension:ALDimensionWidth toSize:300.0]; + + self.searchButton = [[UIBarButtonItem alloc] + initWithImage:[UIImage imageNamed:@"Search"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(didSelectSearch)]; + self.searchButton.accessibilityLabel = NSLocalizedString(@"Search", nil); + self.navigationItem.rightBarButtonItem = self.searchButton; + + // prevent possible unusable Search box when going to Search page + self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] + initWithTitle:NSLocalizedString(@"Back", @"Back button text") + style:UIBarButtonItemStylePlain + target:nil action:nil]; } - (void)viewWillAppear:(BOOL)animated diff --git a/Simplified/Network/NYPLNetworkQueue.swift b/Simplified/Network/NYPLNetworkQueue.swift index 690ee09af..43456ccee 100644 --- a/Simplified/Network/NYPLNetworkQueue.swift +++ b/Simplified/Network/NYPLNetworkQueue.swift @@ -1,5 +1,6 @@ import Foundation import SQLite +typealias Expression = SQLite.Expression /** Recommended pattern by SQLite docs @@ -52,15 +53,15 @@ final class NetworkQueue: NSObject { private let sqlTable = Table(NetworkQueue.TableName) - private let sqlID = Expression(value: "id") - private let sqlLibraryID = Expression(value: "library_identifier") - private let sqlUpdateID = Expression(value: "update_identifier") - private let sqlUrl = Expression(value: "request_url") - private let sqlMethod = Expression(value: "request_method") - private let sqlParameters = Expression(value: "request_parameters") - private let sqlHeader = Expression(value: "request_header") - private let sqlRetries = Expression(value: "retry_count") - private let sqlDateCreated = Expression(value: "date_created") + private let sqlID = Expression("id") + private let sqlLibraryID = Expression("library_identifier") + private let sqlUpdateID = Expression("update_identifier") + private let sqlUrl = Expression("request_url") + private let sqlMethod = Expression("request_method") + private let sqlParameters = Expression("request_parameters") + private let sqlHeader = Expression("request_header") + private let sqlRetries = Expression("retry_count") + private let sqlDateCreated = Expression("date_created") // MARK: - Public Functions diff --git a/Simplified/Reader2/Bookmarks/NYPLReadiumBookmark+Compare.swift b/Simplified/Reader2/Bookmarks/NYPLReadiumBookmark+Compare.swift index 957885f7b..45b6f35cc 100644 --- a/Simplified/Reader2/Bookmarks/NYPLReadiumBookmark+Compare.swift +++ b/Simplified/Reader2/Bookmarks/NYPLReadiumBookmark+Compare.swift @@ -35,7 +35,7 @@ extension NYPLReadiumBookmark { return false } - return self.progressWithinChapter =~= locatorChapterProgress + return self.progressWithinChapter == locatorChapterProgress } override func isEqual(_ object: Any?) -> Bool { @@ -43,7 +43,7 @@ extension NYPLReadiumBookmark { return false } - let progressIsEqual = (self.progressWithinChapter =~= other.progressWithinChapter) + let progressIsEqual = (self.progressWithinChapter == other.progressWithinChapter) switch self.chapterID { case .href(let href): diff --git a/Simplified/Views/DeprecationView.swift b/Simplified/Views/DeprecationView.swift new file mode 100644 index 000000000..97f7179a5 --- /dev/null +++ b/Simplified/Views/DeprecationView.swift @@ -0,0 +1,49 @@ +import UIKit +import WebKit + +@objcMembers class DeprecationView : UIView { + + var linkButton: UIButton = { + let linkButton = UIButton(type: .custom) + linkButton.backgroundColor = NYPLConfiguration.blueBackgroundColor + linkButton.setTitle("Please note: SimplyE will discontinue service in late August 2025. Learn more: nypl.org/ebookhelp", for: .normal) + linkButton.setTitleColor(.white, for: .normal) + linkButton.titleLabel?.font = .systemFont(ofSize: 14, weight: .regular) + linkButton.titleLabel?.textAlignment = .center + linkButton.titleLabel?.numberOfLines = 0 + linkButton.contentEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) + linkButton.translatesAutoresizingMaskIntoConstraints = false + linkButton.isUserInteractionEnabled = true + return linkButton + }() + + @available(*, unavailable) + private override init(frame: CGRect) { + super.init(frame: frame) + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + init(origin: CGPoint, width: CGFloat) { + super.init(frame: CGRect(x: origin.x, y: origin.y, width: width, height: linkButton.frame.size.height)) + + addSubview(linkButton) + linkButton.addTarget(self, action: #selector(myButtonTapped), for: .touchUpInside) + linkButton.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor).isActive = true + linkButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor).isActive = true + linkButton.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor).isActive = true + linkButton.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor).isActive = true + } + + @objc func myButtonTapped() { + if let url = URL(string: "https://www.nypl.org/ebookhelp") { + UIApplication.shared.open(url) + } else { + print("Invalid URL") + } + } + +} diff --git a/Simplified/Views/NYPLRoundedButton.swift b/Simplified/Views/NYPLRoundedButton.swift index 6493e375c..3b09ac7fd 100644 --- a/Simplified/Views/NYPLRoundedButton.swift +++ b/Simplified/Views/NYPLRoundedButton.swift @@ -165,7 +165,7 @@ private let NYPLRoundedButtonPadding: CGFloat = 6.0 } extension NYPLRoundedButton { - @objc (initWithType:isFromDetailView:) + @objc(initWithType:isFromDetailView:) convenience init(type: NYPLRoundedButtonType, isFromDetailView: Bool) { self.init(type: type, endDate: nil, isFromDetailView: isFromDetailView) } diff --git a/Simplified/en.lproj/Localizable.strings b/Simplified/en.lproj/Localizable.strings index 2c7def146..cd0387618 100644 --- a/Simplified/en.lproj/Localizable.strings +++ b/Simplified/en.lproj/Localizable.strings @@ -322,4 +322,5 @@ Deleting your account means that you will no longer have access to ebooks, audio "hour_suffix_short" = "%d h"; // Announcement -"Announcement" = "Announcement"; +"Important Update" = "Important Update"; +"Please note: SimplyE will discontinue service in late August 2025. Learn more: nypl.org/ebookhelp" = "Please note: SimplyE will discontinue service in late August 2025. Learn more: nypl.org/ebookhelp"; diff --git a/availability b/availability new file mode 160000 index 000000000..732370a5f --- /dev/null +++ b/availability @@ -0,0 +1 @@ +Subproject commit 732370a5f13e35df4e316b22bcde442cb9f54bd3