diff --git a/.gitmodules b/.gitmodules index ffb2d269..56825eb7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "jFlash/Classes/External/FMDB"] path = jFlash/Classes/External/FMDB - url = http://github.com/ccgus/fmdb.git + url = https://github.com/ccgus/fmdb.git [submodule "jFlash/Server/lweflash/lib/gaesessions"] path = jFlash/Server/lweflash/lib/gaesessions url = https://github.com/dound/gae-sessions.git @@ -9,22 +9,22 @@ url = git@github.com:LongWeekend/Long-Weekend-Dev-Tools.git [submodule "jFlash/Classes/External/asi-http-request"] path = jFlash/Classes/External/asi-http-request - url = git://github.com/pokeb/asi-http-request.git + url = https://github.com/pokeb/asi-http-request.git [submodule "jFlash/Classes/External/janrain"] path = jFlash/Classes/External/janrain url = git@github.com:LongWeekend/engage.iphone.git [submodule "jFlash/Classes/External/DSActivityView"] path = jFlash/Classes/External/DSActivityView - url = git@github.com:rsharrott/DSActivityView.git + url = https://github.com/dominik-hadl/DSActivityView.git [submodule "jFlash/Classes/External/TTTAttributedLabel"] path = jFlash/Classes/External/TTTAttributedLabel - url = git@github.com:LongWeekend/TTTAttributedLabel.git + url = https://github.com/TTTAttributedLabel/TTTAttributedLabel.git [submodule "jFlash/Classes/External/LWEGradientButton"] path = jFlash/Classes/External/LWEGradientButton url = git@github.com:LongWeekend/LWEGradientButton.git [submodule "jFlash/Classes/External/MBProgressHUD"] path = jFlash/Classes/External/MBProgressHUD - url = git://github.com/matej/MBProgressHUD.git + url = https://github.com/jdg/MBProgressHUD.git [submodule "jFlash/Classes/External/jump.ios"] path = jFlash/Classes/External/jump.ios - url = git@github.com:janrain/jump.ios.git + url = https://github.com/janrain/jump.ios.git diff --git a/jFlash/Assets/CFlash/help/algorithm@2x.html b/jFlash/Assets/CFlash/help/algorithm@2x.html index c5847e61..f8e382e7 100644 --- a/jFlash/Assets/CFlash/help/algorithm@2x.html +++ b/jFlash/Assets/CFlash/help/algorithm@2x.html @@ -25,7 +25,6 @@ You can also choose to exclude learned words from study using the "Hide Learned Cards" switch.

-

If this sounds confusing, don't worry! There are presets for easy, medium & hard so you don't have to worry about the math (worry about Chinese *grin*). diff --git a/jFlash/Assets/CFlash/help/browse@2x.html b/jFlash/Assets/CFlash/help/browse@2x.html index 54adda77..da440120 100644 --- a/jFlash/Assets/CFlash/help/browse@2x.html +++ b/jFlash/Assets/CFlash/help/browse@2x.html @@ -13,9 +13,8 @@ Tap the Settings icon, and then tap Study Mode to switch between the two.

-

Once in Browse Mode, you can move backwards & forwards through the set by tapping the Last & Next buttons. - Using the Actions button, you can add the card to other sets (including your starred words), tweet the word, or report a correction. + Using the Actions button, you can add the card to other sets (including your starred words), share the card, or report a correction.

diff --git a/jFlash/Assets/CFlash/help/corrections@2x.html b/jFlash/Assets/CFlash/help/corrections@2x.html index d2c9c81b..18b7916b 100644 --- a/jFlash/Assets/CFlash/help/corrections@2x.html +++ b/jFlash/Assets/CFlash/help/corrections@2x.html @@ -7,7 +7,7 @@
-

If you find things you believe are incorrect, please us know. It's quick & easy!

+

If you find things you believe are incorrect, please let us know. It's quick & easy!

Tap the Actions button on the Practice screen. Tap Fix Card.

diff --git a/jFlash/Assets/CFlash/help/integration@2x.html b/jFlash/Assets/CFlash/help/integration@2x.html index dbc0ff41..f682ed3f 100644 --- a/jFlash/Assets/CFlash/help/integration@2x.html +++ b/jFlash/Assets/CFlash/help/integration@2x.html @@ -9,7 +9,7 @@

How does it work? Simply follow a link:

cflash://CHINESE_WORD
to open cFlash from another app and launch - a search. ie:
cflash://中国語
will launch jflash and search for 中国語. Ask your other favorite apps to include this functionality as + a search. ie:
cflash://中国語
will launch cflash and search for 中国語. Ask your other favorite apps to include this functionality as well and let's build the perfect environment for learning, reviewing and retaining Chinese!

diff --git a/jFlash/Assets/CFlash/help/practice@2x.html b/jFlash/Assets/CFlash/help/practice@2x.html index 9f651dc7..3755b04c 100644 --- a/jFlash/Assets/CFlash/help/practice@2x.html +++ b/jFlash/Assets/CFlash/help/practice@2x.html @@ -11,9 +11,8 @@ Once the meaning is revealed, you can indicate whether you got it right or wrong. If you know the word already, or simply don't like it, you can press bury it - the card will immediately become Learned.

-

Using the Actions button, you can add the card to other sets (including your starred words), tweet the word, or report a correction.

+

Using the Actions button, you can add the card to other sets (including your starred words), share the card, or report a correction.

-

The first time you get a card right, it moves from Studying to Right 1x. Each time you get it right, it will be promoted to a higher level. diff --git a/jFlash/Assets/CFlash/help/welcome@2x.html b/jFlash/Assets/CFlash/help/welcome@2x.html index 1be3797b..96ba3e2f 100644 --- a/jFlash/Assets/CFlash/help/welcome@2x.html +++ b/jFlash/Assets/CFlash/help/welcome@2x.html @@ -24,9 +24,6 @@ -

- Follow us on Twitter! -
diff --git a/jFlash/Assets/JFlash/help/algorithm@2x.html b/jFlash/Assets/JFlash/help/algorithm@2x.html index 39f03dcb..7d886513 100644 --- a/jFlash/Assets/JFlash/help/algorithm@2x.html +++ b/jFlash/Assets/JFlash/help/algorithm@2x.html @@ -25,7 +25,6 @@ You can also choose to exclude learned words from study using the "Hide Learned Cards" switch.

-

If this sounds confusing, don't worry! There are presets for easy, medium & hard so you don't have to worry about the math (worry about Japanese *grin*). diff --git a/jFlash/Assets/JFlash/help/browse@2x.html b/jFlash/Assets/JFlash/help/browse@2x.html index 54adda77..da440120 100644 --- a/jFlash/Assets/JFlash/help/browse@2x.html +++ b/jFlash/Assets/JFlash/help/browse@2x.html @@ -13,9 +13,8 @@ Tap the Settings icon, and then tap Study Mode to switch between the two.

-

Once in Browse Mode, you can move backwards & forwards through the set by tapping the Last & Next buttons. - Using the Actions button, you can add the card to other sets (including your starred words), tweet the word, or report a correction. + Using the Actions button, you can add the card to other sets (including your starred words), share the card, or report a correction.

diff --git a/jFlash/Assets/JFlash/help/corrections@2x.html b/jFlash/Assets/JFlash/help/corrections@2x.html index d2c9c81b..18b7916b 100644 --- a/jFlash/Assets/JFlash/help/corrections@2x.html +++ b/jFlash/Assets/JFlash/help/corrections@2x.html @@ -7,7 +7,7 @@
-

If you find things you believe are incorrect, please us know. It's quick & easy!

+

If you find things you believe are incorrect, please let us know. It's quick & easy!

Tap the Actions button on the Practice screen. Tap Fix Card.

diff --git a/jFlash/Assets/JFlash/help/practice@2x.html b/jFlash/Assets/JFlash/help/practice@2x.html index 0542ecb7..d8756c62 100644 --- a/jFlash/Assets/JFlash/help/practice@2x.html +++ b/jFlash/Assets/JFlash/help/practice@2x.html @@ -11,9 +11,8 @@ Once the meaning is revealed, you can indicate whether you got it right or wrong. If you know the word already, or simply don't like it, you can press bury it - the card will immediately become Learned.

-

Using the Actions button, you can add the card to other sets (including your starred words), tweet the word, or report a correction.

+

Using the Actions button, you can add the card to other sets (including your starred words), share the card, or report a correction.

-

The first time you get a card right, it moves from Studying to Right 1x. Each time you get it right, it will be promoted to a higher level. diff --git a/jFlash/Assets/JFlash/help/welcome@2x.html b/jFlash/Assets/JFlash/help/welcome@2x.html index f4b59848..5e440651 100644 --- a/jFlash/Assets/JFlash/help/welcome@2x.html +++ b/jFlash/Assets/JFlash/help/welcome@2x.html @@ -19,17 +19,13 @@

We have a new and improved dictionary, 50,000+ example sentences and a feedback mechanism for reporting data corrections. You can even set the difficulty level for large sets.

-

We have cross-referenced example sentences with readings, so you can discover new words, and Twitter integration, so you can share cool new words with your friends.

+

We have cross-referenced example sentences with readings so you can discover new words and share them with friends.

We hope you enjoy Japanese Flash!

- -
- Follow us on Twitter! -
diff --git a/jFlash/Classes/AppSpecific/ActionBarViewController.h b/jFlash/Classes/AppSpecific/ActionBarViewController.h index 0c69240a..8bbac575 100644 --- a/jFlash/Classes/AppSpecific/ActionBarViewController.h +++ b/jFlash/Classes/AppSpecific/ActionBarViewController.h @@ -13,11 +13,6 @@ #import #import "StudyViewProtocols.h" -#define SVC_ACTION_ADDTOSET_BUTTON 1 -#define SVC_ACTION_ADDTOFAV_BUTTON 0 -#define SVC_ACTION_REPORT_BUTTON 2 -#define SVC_ACTION_SHARE_BUTTON 3 - @class ActionBarViewController; @protocol ActionBarViewControllerDelegate @@ -34,16 +29,14 @@ - (BOOL)actionBarShouldReveal:(ActionBarViewController*)avc; @end -@interface ActionBarViewController : UIViewController -- (NSString *)getTweetWord; - // action sheet - (IBAction)showCardActionSheet; +- (void)distributeButtonsEvenly; + @property (assign) IBOutlet id delegate; @property (nonatomic, retain) Card *currentCard; diff --git a/jFlash/Classes/AppSpecific/ActionBarViewController.m b/jFlash/Classes/AppSpecific/ActionBarViewController.m index a45d9ea5..ee06a602 100644 --- a/jFlash/Classes/AppSpecific/ActionBarViewController.m +++ b/jFlash/Classes/AppSpecific/ActionBarViewController.m @@ -7,10 +7,10 @@ // #import "ActionBarViewController.h" -#import @interface ActionBarViewController () - (void) _reportBadData; +- (void) _applyModernStyle:(UIButton *)btn symbolName:(NSString *)name label:(NSString *)labelText color:(UIColor *)color; @end @implementation ActionBarViewController @@ -18,6 +18,54 @@ @implementation ActionBarViewController @synthesize nextCardBtn, prevCardBtn, addBtn, rightBtn, wrongBtn, buryCardBtn; @synthesize cardMeaningBtnHint; +#pragma mark - View lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + if (@available(iOS 13.0, *)) { + self.view.backgroundColor = [UIColor systemBackgroundColor]; + [self _applyModernStyle:self.addBtn symbolName:@"plus.circle.fill" label:@"actions" color:[UIColor systemBlueColor]]; + [self _applyModernStyle:self.rightBtn symbolName:@"checkmark.circle.fill" label:@"right" color:[UIColor systemGreenColor]]; + [self _applyModernStyle:self.wrongBtn symbolName:@"xmark.circle.fill" label:@"wrong" color:[UIColor systemRedColor]]; + [self _applyModernStyle:self.buryCardBtn symbolName:@"archivebox.circle.fill" label:@"bury it" color:[UIColor systemOrangeColor]]; + [self _applyModernStyle:self.prevCardBtn symbolName:@"chevron.left.circle.fill" label:@"prev" color:[UIColor systemGrayColor]]; + [self _applyModernStyle:self.nextCardBtn symbolName:@"chevron.right.circle.fill" label:@"next" color:[UIColor systemGrayColor]]; + } +} + +- (void)_applyModernStyle:(UIButton *)btn symbolName:(NSString *)name label:(NSString *)labelText color:(UIColor *)color +{ + if (!btn) return; + if (@available(iOS 13.0, *)) { + UIImage *icon = [UIImage systemImageNamed:name]; + if (icon) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:44 weight:UIImageSymbolWeightMedium]; + icon = [icon imageByApplyingSymbolConfiguration:config]; + } + [btn setImage:icon forState:UIControlStateNormal]; + [btn setImage:nil forState:UIControlStateHighlighted]; + [btn setBackgroundImage:nil forState:UIControlStateNormal]; + [btn setBackgroundImage:nil forState:UIControlStateHighlighted]; + [btn setTitle:@"" forState:UIControlStateNormal]; + btn.tintColor = color; + btn.backgroundColor = [UIColor clearColor]; + btn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 20, 0); + + UILabel *lbl = (UILabel *)[btn viewWithTag:9002]; + if (!lbl) { + lbl = [[UILabel alloc] init]; + lbl.tag = 9002; + lbl.textAlignment = NSTextAlignmentCenter; + lbl.font = [UIFont systemFontOfSize:11 weight:UIFontWeightMedium]; + lbl.textColor = [UIColor secondaryLabelColor]; + [btn addSubview:lbl]; + [lbl release]; + } + lbl.text = labelText; + } +} + // MMA: 11/14/2011 -- this method appears to be unused... //Give the delegate a chance to not reveal the card - (BOOL)_actionBarShouldReveal:(BOOL)reveal @@ -41,34 +89,63 @@ - (void) studyViewModeDidChange:(StudyViewController*)svc #pragma mark - IBActions -//! IBAction method - loads card action sheet so user can choose "add to set" or "report bad data" +//! IBAction method - shows card action sheet for starred, add to set, fix, and share - (IBAction) showCardActionSheet { - // Show them "remove" if they happen to be studying the favorites instead of "add to favorites". - NSString *favoriteString = @""; Tag *starredTag = [[CurrentState sharedCurrentState] starredTag]; - if ([TagPeer card:self.currentCard isMemberOfTag:starredTag]) - { - favoriteString = NSLocalizedString(@"Remove from Starred",@"ActionBarViewController.ActionSheetRemoveFromFavorites"); - } - else - { - favoriteString = NSLocalizedString(@"Add to Starred",@"ActionBarViewController.ActionSheetAddToFavorites"); - } - - UIActionSheet *as = [[UIActionSheet alloc] initWithTitle:NSLocalizedString(@"Card Actions",@"ActionBarViewController.ActionSheetTitle") delegate:self - cancelButtonTitle:NSLocalizedString(@"Cancel",@"ActionBarViewController.ActionSheetCancel") - destructiveButtonTitle:nil - otherButtonTitles:favoriteString, - NSLocalizedString(@"Add to Study Set",@"ActionBarViewController.ActionSheetAddToSet"), - NSLocalizedString(@"Fix Card",@"ActionBarViewController.ActionSheetReportBadData"), - NSLocalizedString(@"Share This Card",@"Action Sheet Button to post on FB"),nil]; - - // Yes, there is a showInTabBar: which seems like it might be good, but it makes the BG of the action sheet - // REALLY black. You don't want it, trust me - MMA - jFlashAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; - [as showInView:appDelegate.tabBarController.view]; - [as release]; + NSString *favoriteTitle = [TagPeer card:self.currentCard isMemberOfTag:starredTag] + ? NSLocalizedString(@"Remove from Starred", @"ActionBarViewController.ActionSheetRemoveFromFavorites") + : NSLocalizedString(@"Add to Starred", @"ActionBarViewController.ActionSheetAddToFavorites"); + + UIAlertController *sheet = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"Card Actions", @"ActionBarViewController.ActionSheetTitle") + message:nil + preferredStyle:UIAlertControllerStyleActionSheet]; + + Card *card = self.currentCard; + Tag *favTag = starredTag; + + [sheet addAction:[UIAlertAction actionWithTitle:favoriteTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *a) { + if ([TagPeer card:card isMemberOfTag:favTag]) { + NSError *err = nil; + BOOL removed = [TagPeer cancelMembership:card fromTag:favTag error:&err]; + if (!removed && err.code == kRemoveLastCardOnATagError) { + [LWEUIAlertView notificationAlertWithTitle:NSLocalizedString(@"Last Card in Set", @"AddTagViewController.AlertViewLastCardTitle") + message:[err localizedDescription]]; + } + } else { + [TagPeer subscribeCard:card toTag:favTag]; + } + }]]; + + [sheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Add to Study Set", @"ActionBarViewController.ActionSheetAddToSet") style:UIAlertActionStyleDefault handler:^(UIAlertAction *a) { + AddTagViewController *tmpVC = [[AddTagViewController alloc] initWithCard:card]; + tmpVC.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] + initWithTitle:NSLocalizedString(@"Done", @"AddTagViewController.NavDoneButtonTitle") + style:UIBarButtonItemStyleBordered + target:tmpVC + action:@selector(dismissModalViewControllerAnimated:)] autorelease]; + NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:tmpVC, @"controller", + [NSNumber numberWithBool:YES], @"useNavController", nil]; + [tmpVC release]; + [[NSNotificationCenter defaultCenter] postNotificationName:LWEShouldShowModal object:self userInfo:info]; + }]]; + + [sheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Fix Card", @"ActionBarViewController.ActionSheetReportBadData") style:UIAlertActionStyleDefault handler:^(UIAlertAction *a) { + [self _reportBadData]; + }]]; + + [sheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Share This Card", @"Action Sheet Button to post on FB") style:UIAlertActionStyleDefault handler:^(UIAlertAction *a) { + [self shareWord]; + }]]; + + [sheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"ActionBarViewController.ActionSheetCancel") style:UIAlertActionStyleCancel handler:nil]]; + + // iPad needs a source for the popover anchor + sheet.popoverPresentationController.sourceView = self.addBtn; + sheet.popoverPresentationController.sourceRect = self.addBtn.bounds; + + [self presentViewController:sheet animated:YES completion:nil]; } #pragma mark - SVC Subcontroller Delegate Implementation @@ -86,61 +163,6 @@ - (void) reveal LWE_DELEGATE_CALL(@selector(actionBarDidReveal:), self); } -#pragma mark - UIActionSheetDelegate methods - -//! UIActionSheet delegate method - which modal do we load when the user taps "add to set" or "report bad data" -- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex -{ - Tag *favoritesTag = [[CurrentState sharedCurrentState] starredTag]; - if (buttonIndex == SVC_ACTION_REPORT_BUTTON) - { - [self _reportBadData]; - } - else if (buttonIndex == SVC_ACTION_ADDTOSET_BUTTON) - { - AddTagViewController *tmpVC = [[AddTagViewController alloc] initWithCard:self.currentCard]; - tmpVC.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] - initWithTitle:NSLocalizedString(@"Done", @"AddTagViewController.NavDoneButtonTitle") - style:UIBarButtonItemStyleBordered - target:tmpVC - action:@selector(dismissModalViewControllerAnimated:)] autorelease]; - - NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:tmpVC,@"controller", - [NSNumber numberWithBool:YES],@"useNavController",nil]; - [tmpVC release]; - [[NSNotificationCenter defaultCenter] postNotificationName:LWEShouldShowModal object:self userInfo:userInfo]; - } - else if (buttonIndex == SVC_ACTION_ADDTOFAV_BUTTON) - { - // Do something here - subscribe or cancel, depending. - if ([TagPeer card:self.currentCard isMemberOfTag:favoritesTag]) - { - // First of all, do it - NSError *error = nil; - BOOL removed = [TagPeer cancelMembership:self.currentCard fromTag:favoritesTag error:&error]; - if (removed == NO) - { - if (error.code == kRemoveLastCardOnATagError) - { - NSString *errorMessage = [error localizedDescription]; - [LWEUIAlertView notificationAlertWithTitle:NSLocalizedString(@"Last Card in Set", @"AddTagViewController.AlertViewLastCardTitle") - message:errorMessage]; - } - return; - } - } - else - { - [TagPeer subscribeCard:self.currentCard toTag:favoritesTag]; - } - - } - else if (buttonIndex == SVC_ACTION_SHARE_BUTTON) - { - [self shareWord]; - } -} - #pragma mark - MailCompose helper & delegate method - (void) _reportBadData @@ -179,89 +201,77 @@ - (void)mailComposeController:(MFMailComposeViewController*)controller didFinish - (void) shareWord { - NSMutableArray *sharingItems = [NSMutableArray new]; - [sharingItems addObject:[self getTweetWord]]; + // Format: "Headword [reading] meaning" + NSMutableString *shareText = [NSMutableString stringWithString:self.currentCard.headword]; + NSString *reading = self.currentCard.reading; + if ([reading length] > 0) + { + [shareText appendFormat:@" [%@]", reading]; + } + NSString *meaning = [self.currentCard meaningWithoutMarkup]; + if ([meaning length] > 0) + { + [shareText appendFormat:@" %@", meaning]; + } + + NSMutableArray *sharingItems = [NSMutableArray array]; + [sharingItems addObject:shareText]; [sharingItems addObject:@"https://itunes.apple.com/us/app/japanese-flash-vocabulary/id367216357?mt=8"]; - - UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil]; + + UIActivityViewController *activityController = [[[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil] autorelease]; [self presentViewController:activityController animated:YES completion:nil]; } -#pragma mark - TweetWordMethod +#pragma mark - Layout -//! get the tweet word and try to cut the maning of the tweet word so that it gives the result of NSString which is going to fit within the allocation of twitter status update -- (NSString *)getTweetWord +- (void)distributeButtonsEvenly { - NSMutableString *str = nil; - - //Set up the tweet word, so that the str will have the following format - //Head Word [reading] meaning - - // Get the lengths of everyone involved - NSInteger headwordLength = [self.currentCard.headword length]; - NSInteger readingLength = [self.currentCard.reading length]; - NSInteger meaningLength = [[self.currentCard meaningWithoutMarkup] length]; - - // Now go from most conservative (headword exceeds LWE_TWITTER_MAX_CHARS) - // to most liberal (the whole thing fits in LWE_TWITTER_MAX_CHARS) - if (headwordLength > LWE_TWITTER_MAX_CHARS) - { - // Headword alone is longer than kMaxChars - str = [[NSMutableString alloc] initWithFormat:@"%@", [self.currentCard.headword substringToIndex:LWE_TWITTER_MAX_CHARS]]; - } - else - { - // Add four because we add brackets and spaces - if ((headwordLength + readingLength + 4) > LWE_TWITTER_MAX_CHARS) - { - // Headword + reading is too long, so just use headword. - str = [[NSMutableString alloc] initWithFormat:@"%@",self.currentCard.headword]; - } - else - { - str = [[NSMutableString alloc] initWithFormat:@"%@ [%@] ",self.currentCard.headword,self.currentCard.reading]; - } + CGFloat width = self.view.bounds.size.width; + CGFloat height = self.view.bounds.size.height; + if (width <= 0 || height <= 0) return; + + NSMutableArray *buttons = [NSMutableArray array]; + if (self.prevCardBtn) [buttons addObject:self.prevCardBtn]; + if (self.addBtn) [buttons addObject:self.addBtn]; + if (self.rightBtn) [buttons addObject:self.rightBtn]; + if (self.wrongBtn) [buttons addObject:self.wrongBtn]; + if (self.buryCardBtn) [buttons addObject:self.buryCardBtn]; + if (self.nextCardBtn) [buttons addObject:self.nextCardBtn]; + + if (buttons.count == 0) return; + + CGFloat btnWidth = floorf(width / (CGFloat)buttons.count); + for (NSUInteger i = 0; i < buttons.count; i++) { + UIButton *btn = buttons[i]; + CGFloat x = i * btnWidth; + CGFloat w = (i == buttons.count - 1) ? (width - x) : btnWidth; + btn.frame = CGRectMake(x, 0, w, height); } +} - // Now determine if we have any space left for a meaning. - NSInteger charLeftBeforeMeaning = LWE_TWITTER_MAX_CHARS - [str length]; - - // If there are less than 5, just ignore - not worth it - if (charLeftBeforeMeaning > 5) - { - NSString *meaning = [self.currentCard meaningWithoutMarkup]; - NSInteger charLeftAfterMeaning = charLeftBeforeMeaning - meaningLength; - //but in some cases, the "meaning" length, can exceed the maximum length - //of the twitter update status lenght, so it looks for "/" and cut the meaning - //to fit in. - if (charLeftAfterMeaning < 0) - { - NSRange range = [meaning rangeOfString:@"/" options:NSBackwardsSearch]; - if (range.location != NSNotFound && (range.location < charLeftBeforeMeaning)) - { - // We got one, and it fits - // This is still a naive implementation, it should recursively chop off slashes until it fits... - // AT present it only does it once - [str appendString:[meaning substringToIndex:range.location]]; - } - else - { - // Simple truncate - [str appendString:[meaning substringToIndex:charLeftBeforeMeaning]]; +- (void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + [self distributeButtonsEvenly]; + + if (@available(iOS 13.0, *)) { + NSMutableArray *btns = [NSMutableArray array]; + if (self.addBtn) [btns addObject:self.addBtn]; + if (self.rightBtn) [btns addObject:self.rightBtn]; + if (self.wrongBtn) [btns addObject:self.wrongBtn]; + if (self.buryCardBtn) [btns addObject:self.buryCardBtn]; + if (self.prevCardBtn) [btns addObject:self.prevCardBtn]; + if (self.nextCardBtn) [btns addObject:self.nextCardBtn]; + for (UIButton *btn in btns) { + UILabel *lbl = (UILabel *)[btn viewWithTag:9002]; + if (lbl) { + [lbl sizeToFit]; + CGFloat bW = btn.bounds.size.width; + CGFloat bH = btn.bounds.size.height; + lbl.frame = CGRectMake(0, bH - lbl.bounds.size.height - 5, bW, lbl.bounds.size.height); } } - else - { - // Enough room for the whole meaning - [str appendString:meaning]; - } - } - - // Debug output - LWE_LOG(@"Tweet string: %@",str); - LWE_LOG(@"Tweet length: %d",[str length]); - - return (NSString*)[str autorelease]; + } } #pragma mark - Class Plumbing diff --git a/jFlash/Classes/AppSpecific/AlgorithmSettingsViewController.m b/jFlash/Classes/AppSpecific/AlgorithmSettingsViewController.m index 25ccb790..b02f3a8d 100644 --- a/jFlash/Classes/AppSpecific/AlgorithmSettingsViewController.m +++ b/jFlash/Classes/AppSpecific/AlgorithmSettingsViewController.m @@ -29,23 +29,46 @@ @implementation AlgorithmSettingsViewController #pragma mark - UIViewController Methods -- (void)viewDidLoad +- (void)viewDidLoad { - [super viewDidLoad]; - self.navigationItem.title = NSLocalizedString(@"Change Difficulty",@"AlgorithmSettingsViewController.NavBarTitle"); + [super viewDidLoad]; + self.navigationItem.title = NSLocalizedString(@"Change Difficulty",@"AlgorithmSettingsViewController.NavBarTitle"); NSUserDefaults *settings = [NSUserDefaults standardUserDefaults]; self.maxCardsSlider.minimumValue = MIN_MAX_STUDYING; self.maxCardsSlider.maximumValue = MAX_MAX_STUDYING; self.maxCardsSlider.tag = MAX_CARDS_SLIDER_TAG; self.maxCardsSlider.value = (CGFloat)[settings integerForKey:APP_MAX_STUDYING]; - + self.frequencySlider.minimumValue = MIN_FREQUENCY_MULTIPLIER; self.frequencySlider.maximumValue = MAX_FREQUENCY_MULTIPLIER; self.frequencySlider.tag = FREQUENCY_SLIDER_TAG; self.frequencySlider.value = (CGFloat)[settings integerForKey:APP_FREQUENCY_MULTIPLIER]; - + self.difficultySegmentControl.selectedSegmentIndex = [settings integerForKey:APP_DIFFICULTY]; + + // Build a table header view so the segment control sits inside the scroll area + // and is never obscured by the navigation bar. + CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; + UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, 74)]; + headerView.backgroundColor = [UIColor clearColor]; + headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + + UILabel *diffLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 14, screenWidth - 32, 26)]; + diffLabel.text = NSLocalizedString(@"Difficulty", @"AlgorithmVC.Difficulty"); + diffLabel.font = [UIFont boldSystemFontOfSize:17]; + diffLabel.textColor = [UIColor colorWithRed:0.233f green:0.265f blue:0.348f alpha:0.89f]; + diffLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [headerView addSubview:diffLabel]; + [diffLabel release]; + + self.difficultySegmentControl.frame = CGRectMake(16, 44, screenWidth - 32, 32); + self.difficultySegmentControl.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [headerView addSubview:self.difficultySegmentControl]; + + self.tableView.tableHeaderView = headerView; + [headerView release]; + [self setDifficulty:self.difficultySegmentControl]; } diff --git a/jFlash/Classes/AppSpecific/BrowseModeCardViewDelegate.m b/jFlash/Classes/AppSpecific/BrowseModeCardViewDelegate.m index 4546eb09..369685c7 100644 --- a/jFlash/Classes/AppSpecific/BrowseModeCardViewDelegate.m +++ b/jFlash/Classes/AppSpecific/BrowseModeCardViewDelegate.m @@ -131,8 +131,6 @@ - (Card *)getNextCard:(Tag*)cardSet afterCard:(Card*)currentCard direction:(NSSt - (void) actionBarDidChangeMode:(ActionBarViewController *)avc { - // Change action bar view to browse XIB - [[NSBundle mainBundle] loadNibNamed:@"ActionBarViewController-Browse" owner:avc options:nil]; } @end \ No newline at end of file diff --git a/jFlash/Classes/AppSpecific/CFlashUpdateManager.m b/jFlash/Classes/AppSpecific/CFlashUpdateManager.m index ad714280..d5285f25 100644 --- a/jFlash/Classes/AppSpecific/CFlashUpdateManager.m +++ b/jFlash/Classes/AppSpecific/CFlashUpdateManager.m @@ -47,9 +47,6 @@ + (BOOL) _needs11to12SettingsUpdate:(NSUserDefaults *)settings + (void) _updateSettingsFrom11to12:(NSUserDefaults *)settings { - // Set the new key for text size - [settings setObject:SET_TEXT_NORMAL forKey:APP_TEXT_SIZE]; - //New key for the user settings preference in version 1.6.2 [settings setObject:LWE_CF_VERSION_1_2 forKey:APP_SETTINGS_VERSION]; diff --git a/jFlash/Classes/AppSpecific/CardViewController.h b/jFlash/Classes/AppSpecific/CardViewController.h index bc85a9d2..b9aa4f95 100644 --- a/jFlash/Classes/AppSpecific/CardViewController.h +++ b/jFlash/Classes/AppSpecific/CardViewController.h @@ -7,8 +7,8 @@ // #import +#import #import "Card.h" -#import "UIWebView+LWENoBounces.h" #import "MoodIcon.h" #import "StudyViewProtocols.h" @@ -29,10 +29,12 @@ extern NSString * const LWECardHTMLTemplate_EtoJ; - (BOOL)shouldRevealCardView:(CardViewController*)cvc; @end -@interface CardViewController : UIViewController +@interface CardViewController : UIViewController { //! Holds a reference to the current meaning's string-replacement javascript NSString *_tmpJavascript; + //! WKWebView created programmatically inside meaningWebViewContainer. + WKWebView *_meaningWebView; } //! Designated initializer. Passing "NO" to displayMainHeadword shows alt headword (e.g. English) @@ -40,6 +42,11 @@ extern NSString * const LWECardHTMLTemplate_EtoJ; - (IBAction) doToggleReadingBtn; +#if defined(LWE_JFLASH) +//! Speaks the current headword using AVSpeechSynthesizer. +- (IBAction) doSpeakHeadword; +#endif + //! Use when you want to show the reading (w/o persisting that state) - (void) turnReadingOn; @@ -49,6 +56,10 @@ extern NSString * const LWECardHTMLTemplate_EtoJ; //! Whatever the value of readingVisible is, this will reset it to that state. - (void) resetReadingVisibility; +//! Lays out reading, headword, and webview based on current bounds. +//! Call from StudyViewController.viewDidLayoutSubviews (child VC containment is informal). +- (void) layoutCardSubviews; + //! Implement this delegate to control how the card is displayed in a mode. @property (assign) IBOutlet id delegate; @@ -79,8 +90,13 @@ extern NSString * const LWECardHTMLTemplate_EtoJ; //! If the headword is scrollable, the "more icon" will show to help the user understand @property (nonatomic, retain) IBOutlet UIImageView *headwordMoreIcon; -//! Web view that renders the meaning HTML -@property (nonatomic, retain) IBOutlet UIWebView *meaningWebView; +#if defined(LWE_JFLASH) +//! Speaker button that triggers TTS for the current headword. +@property (nonatomic, retain) UIButton *speakBtn; +#endif + +//! Container view (XIB-instantiated UIView) into which the WKWebView is added in viewDidLoad. +@property (nonatomic, retain) IBOutlet UIView *meaningWebViewContainer; @property (nonatomic, retain) NSString *baseHtml; @end diff --git a/jFlash/Classes/AppSpecific/CardViewController.m b/jFlash/Classes/AppSpecific/CardViewController.m index f156344b..8d34908a 100644 --- a/jFlash/Classes/AppSpecific/CardViewController.m +++ b/jFlash/Classes/AppSpecific/CardViewController.m @@ -8,6 +8,56 @@ #import "CardViewController.h" #import "UIScrollView+LWEUtilities.h" +#import + +// Maps iOS system text size category to a CSS font-size string for WKWebView/UIWebView HTML. +static NSString *LWEDynamicTypeCSSFontSize(void) +{ + static NSDictionary *map = nil; + if (!map) { + map = [@{ + UIContentSizeCategoryExtraSmall: @"13px", + UIContentSizeCategorySmall: @"14px", + UIContentSizeCategoryMedium: @"15px", + UIContentSizeCategoryLarge: @"16px", + UIContentSizeCategoryExtraLarge: @"18px", + UIContentSizeCategoryExtraExtraLarge: @"20px", + UIContentSizeCategoryExtraExtraExtraLarge: @"22px", + UIContentSizeCategoryAccessibilityMedium: @"26px", + UIContentSizeCategoryAccessibilityLarge: @"30px", + UIContentSizeCategoryAccessibilityExtraLarge: @"34px", + UIContentSizeCategoryAccessibilityExtraExtraLarge: @"38px", + UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @"44px", + } retain]; + } + NSString *category = [UIApplication sharedApplication].preferredContentSizeCategory; + return map[category] ?: @"16px"; +} + +// Scale factor relative to the default (Large) category, used to scale native label font sizes. +static CGFloat LWEDynamicTypeSizeMultiplier(void) +{ + static NSDictionary *map = nil; + if (!map) { + map = [@{ + UIContentSizeCategoryExtraSmall: @(0.82f), + UIContentSizeCategorySmall: @(0.88f), + UIContentSizeCategoryMedium: @(0.94f), + UIContentSizeCategoryLarge: @(1.00f), + UIContentSizeCategoryExtraLarge: @(1.06f), + UIContentSizeCategoryExtraExtraLarge: @(1.12f), + UIContentSizeCategoryExtraExtraExtraLarge: @(1.19f), + UIContentSizeCategoryAccessibilityMedium: @(1.35f), + UIContentSizeCategoryAccessibilityLarge: @(1.53f), + UIContentSizeCategoryAccessibilityExtraLarge: @(1.76f), + UIContentSizeCategoryAccessibilityExtraExtraLarge: @(1.94f), + UIContentSizeCategoryAccessibilityExtraExtraExtraLarge: @(2.35f), + } retain]; + } + NSString *category = [UIApplication sharedApplication].preferredContentSizeCategory; + NSNumber *multiplier = map[category]; + return multiplier ? multiplier.floatValue : 1.0f; +} #if defined (LWE_CFLASH) #import "ChineseCard.h" @@ -22,17 +72,24 @@ - (void) _updateReadingContainer; //! Returns YES if the contents of theLabel fit in scrollViewContainer w/o scrolling - (BOOL) _shouldHideMoreIconForLabel:(UIView *)theLabel forScrollView:(UIScrollView *)scrollViewContainer; + +#if defined(LWE_JFLASH) +- (AVSpeechSynthesisVoice *) _bestJapaneseVoice; +- (void) _updateSpeakBtnPosition; +@property (nonatomic, retain) AVSpeechSynthesizer *speechSynthesizer; +#endif @end @implementation CardViewController @synthesize delegate; -@synthesize meaningWebView, headwordMoreIcon, headwordLabel, readingMoreIcon, readingLabel, toggleReadingBtn; +@synthesize meaningWebViewContainer, headwordMoreIcon, headwordLabel, readingMoreIcon, readingLabel, toggleReadingBtn; @synthesize readingScrollContainer, headwordScrollContainer, readingVisible = _readingVisible; - @synthesize baseHtml; - @synthesize moodIcon; +#if defined(LWE_JFLASH) +@synthesize speakBtn, speechSynthesizer; +#endif #pragma mark - Flow Methods @@ -96,35 +153,144 @@ - (id) initDisplayMainHeadword:(BOOL)displayMainHeadword NSString *cssHeader = [[ThemeManager sharedThemeManager] currentThemeCSS]; html = [html stringByReplacingOccurrencesOfString:@"##THEMECSS##" withString:cssHeader]; - // Replace the font tag with the current setting - NSString *textSize = [[NSUserDefaults standardUserDefaults] objectForKey:APP_TEXT_SIZE]; - html = [html stringByReplacingOccurrencesOfString:@"##TEXTSIZE##" withString:textSize]; + html = [html stringByReplacingOccurrencesOfString:@"##TEXTSIZE##" withString:LWEDynamicTypeCSSFontSize()]; self.baseHtml = html; } return self; } -- (void)viewDidLoad +- (void)viewDidLoad { [super viewDidLoad]; - [self.meaningWebView loadHTMLString:self.baseHtml baseURL:nil]; - [self.meaningWebView shutOffBouncing]; - self.meaningWebView.backgroundColor = [UIColor clearColor]; - + + // Create the WKWebView programmatically inside the XIB-instantiated container. + // (UIWebView is removed in modern iOS so we no longer instantiate it from the XIB.) + WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; + _meaningWebView = [[WKWebView alloc] initWithFrame:self.meaningWebViewContainer.bounds + configuration:config]; + [config release]; + _meaningWebView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _meaningWebView.navigationDelegate = self; + _meaningWebView.opaque = NO; + _meaningWebView.backgroundColor = [UIColor clearColor]; + _meaningWebView.scrollView.backgroundColor = [UIColor clearColor]; + _meaningWebView.scrollView.bounces = NO; + [self.meaningWebViewContainer addSubview:_meaningWebView]; + [_meaningWebView loadHTMLString:self.baseHtml baseURL:nil]; + // Add mood icon subview - TODO: MMA this is 90% complete, but I want to find a way to do this in the NIB CGRect moodIconRect = CGRectMake(235, 197, 80, 73); self.moodIcon.view.frame = moodIconRect; - self.moodIcon.view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; + self.moodIcon.view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin; [self.view addSubview:self.moodIcon.view]; [self.moodIcon updateMoodIcon:100.0f]; - + // For languages such as Chinese, we may need to configure the font self.headwordLabel.font = [Card configureFontForLabel:self.headwordLabel]; + +#if defined(LWE_JFLASH) + self.speechSynthesizer = [[[AVSpeechSynthesizer alloc] init] autorelease]; + + UIButton *speak = [UIButton buttonWithType:UIButtonTypeSystem]; + UIImage *speakerImg = [UIImage systemImageNamed:@"speaker.wave.2"]; + [speak setImage:speakerImg forState:UIControlStateNormal]; + speak.tintColor = [UIColor whiteColor]; + speak.accessibilityLabel = NSLocalizedString(@"Speak word", @"CardViewController.SpeakWordAccessibility"); + [speak addTarget:self action:@selector(doSpeakHeadword) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:speak]; + self.speakBtn = speak; +#endif +} + +#pragma mark - Layout + +- (void)layoutCardSubviews +{ + CGFloat w = self.view.bounds.size.width; + CGFloat h = self.view.bounds.size.height; + if (w <= 0 || h <= 0) return; + + CGFloat hPad = 10.0; + CGFloat contentW = w - 2.0 * hPad; + + // Reading row at ~25% from top of card area so it lands near 30% of screen height. + CGFloat readingY = MAX(20.0, roundf(h * 0.25)); + CGFloat readingH = 42.0; + self.readingScrollContainer.frame = CGRectMake(hPad, readingY, contentW, readingH); + self.readingMoreIcon.frame = CGRectMake(2.0, readingY + readingH - 17.0, 26.0, 17.0); + // Toggle overlays the full reading row; positioned above the reveal-button zone + // so it intercepts taps without triggering the definition reveal. + self.toggleReadingBtn.frame = CGRectMake(hPad, readingY, contentW, readingH); + + // Headword immediately below reading. + CGFloat headwordY = readingY + readingH + 4.0; + CGFloat headwordH = 55.0; + self.headwordScrollContainer.frame = CGRectMake(hPad, headwordY, contentW, headwordH); + self.headwordMoreIcon.frame = CGRectMake(2.0, headwordY + headwordH - 17.0, 26.0, 17.0); +#if defined(LWE_JFLASH) + [self _updateSpeakBtnPosition]; +#endif + + // Meaning webview fills everything below the headword, giving it full space to the bottom. + CGFloat webY = headwordY + headwordH + 8.0; + CGFloat webH = MAX(60.0, h - webY - 8.0); + self.meaningWebViewContainer.frame = CGRectMake(hPad, webY, contentW, webH); } #pragma mark - IBAction Methods +#if defined(LWE_JFLASH) + +- (void)_updateSpeakBtnPosition +{ + CGRect container = self.headwordScrollContainer.frame; + if (container.size.width <= 0 || self.headwordLabel.text.length == 0) return; + + // Text is center-aligned in the label; compute the visual right edge from intrinsic text width. + CGSize textSize = [self.headwordLabel.text sizeWithAttributes: + @{NSFontAttributeName: self.headwordLabel.font}]; + CGFloat textWidth = MIN(textSize.width, container.size.width); + CGFloat containerCenterX = container.origin.x + container.size.width / 2.0; + CGFloat textRightEdge = containerCenterX + textWidth / 2.0; + + CGFloat btnSize = 36.0; + CGFloat maxX = self.view.bounds.size.width - 2.0; + CGFloat speakX = MIN(textRightEdge + 6.0, maxX - btnSize); + CGFloat speakY = container.origin.y + roundf((container.size.height - btnSize) / 2.0); + self.speakBtn.frame = CGRectMake(speakX, speakY, btnSize, btnSize); +} + +- (AVSpeechSynthesisVoice *)_bestJapaneseVoice +{ + AVSpeechSynthesisVoice *enhanced = nil; + for (AVSpeechSynthesisVoice *v in [AVSpeechSynthesisVoice speechVoices]) { + if (![v.language isEqualToString:@"ja-JP"]) continue; + if (@available(iOS 16.0, *)) { + if (v.quality == AVSpeechSynthesisVoiceQualityPremium) return v; + } + if (v.quality == AVSpeechSynthesisVoiceQualityEnhanced) enhanced = v; + } + return enhanced ?: [AVSpeechSynthesisVoice voiceWithLanguage:@"ja-JP"]; +} + +- (IBAction)doSpeakHeadword +{ + // Reading label text is "kana - romaji"; speak only the kana part. + NSString *reading = self.readingLabel.text; + NSString *text = [[reading componentsSeparatedByString:@" - "] firstObject]; + if (text.length == 0) return; + + [self.speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate]; + + AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:text]; + utterance.voice = [self _bestJapaneseVoice]; + utterance.rate = 0.4f; + [self.speechSynthesizer speakUtterance:utterance]; +} + +#endif + /** * If the reading scroll container is hidden, this shows it. * If it's showing, it hides it. @@ -191,11 +357,8 @@ - (BOOL) _shouldHideMoreIconForLabel:(UILabel *)theLabel forScrollView:(UIScroll // Prepare the view for the current card - (void) _prepareView:(Card*)card { - // Reset the meaning's scroll view location -- this is not available earlier than iOS5, so wrap it. - if ([self.meaningWebView respondsToSelector:@selector(scrollView)]) - { - self.meaningWebView.scrollView.contentOffset = CGPointZero; - } + // Reset the meaning's scroll view location. + _meaningWebView.scrollView.contentOffset = CGPointZero; // Fix up the headword & the meaning; those are a bit easier. [self _injectMeaningHTML:card.meaning]; @@ -209,8 +372,9 @@ - (void) _prepareView:(Card*)card #endif // These calls re-size the reading & headword labels. They used to take the scrollContainer as well, // but we infer it (superview) of the labels inside this call. - [self.readingLabel resizeWithMinFontSize:READING_MIN_FONTSIZE maxFontSize:READING_MAX_FONTSIZE]; - [self.headwordLabel resizeWithMinFontSize:HEADWORD_MIN_FONTSIZE maxFontSize:HEADWORD_MAX_FONTSIZE]; + CGFloat dtScale = LWEDynamicTypeSizeMultiplier(); + [self.readingLabel resizeWithMinFontSize:(NSInteger)(READING_MIN_FONTSIZE * dtScale) maxFontSize:(NSInteger)(READING_MAX_FONTSIZE * dtScale)]; + [self.headwordLabel resizeWithMinFontSize:(NSInteger)(HEADWORD_MIN_FONTSIZE * dtScale) maxFontSize:(NSInteger)(HEADWORD_MAX_FONTSIZE * dtScale)]; // Now resize the scroll views as necessary based on the resized views above, if necessary. // This call also centers the label inside the scroll view. @@ -220,6 +384,9 @@ - (void) _prepareView:(Card*)card //[self _updateReadingContainer]; self.headwordMoreIcon.hidden = [self _shouldHideMoreIconForLabel:self.headwordLabel forScrollView:self.headwordScrollContainer]; +#if defined(LWE_JFLASH) + [self _updateSpeakBtnPosition]; +#endif } - (void) _updateReadingContainer @@ -232,32 +399,35 @@ - (void) _updateReadingContainer - (void) _injectMeaningHTML:(NSString*)html { - // The HTML will be encapsulated in Javascript, make sure to escape that noise - NSString *escapedHtml = [html stringByReplacingOccurrencesOfString:@"'" withString:@"\\\'"]; + // The HTML will be encapsulated in Javascript, escape backslash, quote, and + // newline so the resulting JS string literal stays well-formed for any + // characters that might appear in card meanings. + NSString *escapedHtml = [html stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; + escapedHtml = [escapedHtml stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; + escapedHtml = [escapedHtml stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; + escapedHtml = [escapedHtml stringByReplacingOccurrencesOfString:@"\r" withString:@""]; NSString *js = [NSString stringWithFormat:@"var textElement = document.getElementById('container'); if (textElement) { textElement.innerHTML = '%@'; }",escapedHtml]; - - // Save of copy of this in case the webview hasn't finished loading yet (see WebView delegate below) + + // Save a copy of this in case the webview hasn't finished loading yet + // (see WKNavigationDelegate callback below). + [_tmpJavascript release]; _tmpJavascript = [js retain]; - - // Not loading, do it as normal - [self.meaningWebView stringByEvaluatingJavaScriptFromString:js]; + + [_meaningWebView evaluateJavaScript:js completionHandler:nil]; } -#pragma mark - UIWebViewDelegate Support +#pragma mark - WKNavigationDelegate /** - * This callback should only be called once at the beginning of a study session - * When the webview doesn't load as fast as the view controllers (so far, always) - * the javascript call in "setupWebMeaning" or whatever will do nothing - so - * it caches the result in _tmpJavascript and waits for the delegate callback + * The HTML template loads from a string and a JS-injection request can race the + * load. If the JS was queued before the WebView finished loading, replay it now. */ -- (void)webViewDidFinishLoad:(UIWebView *)webView +- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { - // Aha, we have some HTML on first load, so load that shit up if (_tmpJavascript) { - [self.meaningWebView stringByEvaluatingJavaScriptFromString:_tmpJavascript]; + [_meaningWebView evaluateJavaScript:_tmpJavascript completionHandler:nil]; [_tmpJavascript release]; _tmpJavascript = nil; } @@ -265,42 +435,50 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView #pragma mark - Plumbing -- (void)viewDidUnload +- (void)viewDidUnload { - [super viewDidUnload]; - self.readingScrollContainer = nil; - self.headwordScrollContainer = nil; - self.headwordMoreIcon = nil; - self.readingMoreIcon = nil; - self.headwordLabel = nil; - self.readingLabel = nil; - self.toggleReadingBtn = nil; - self.meaningWebView = nil; - self.moodIcon = nil; + [super viewDidUnload]; + self.readingScrollContainer = nil; + self.headwordScrollContainer = nil; + self.headwordMoreIcon = nil; + self.readingMoreIcon = nil; + self.headwordLabel = nil; + self.readingLabel = nil; + self.toggleReadingBtn = nil; + self.meaningWebViewContainer = nil; + self.moodIcon = nil; +#if defined(LWE_JFLASH) + self.speakBtn = nil; + self.speechSynthesizer = nil; +#endif } -- (void)dealloc +- (void)dealloc { [moodIcon release]; [baseHtml release]; [_tmpJavascript release]; - - [headwordScrollContainer release]; - [headwordMoreIcon release]; + + [headwordScrollContainer release]; + [headwordMoreIcon release]; [headwordLabel release]; - - [readingScrollContainer release]; - [readingMoreIcon release]; + + [readingScrollContainer release]; + [readingMoreIcon release]; [readingLabel release]; [toggleReadingBtn release]; - - // Apparently we're supposed to set this to nil, according to the docs - // I guess it's in case some other guy is holding a reference to this dude - self.meaningWebView.delegate = nil; - [meaningWebView release]; - + +#if defined(LWE_JFLASH) + [speakBtn release]; + [speechSynthesizer release]; +#endif + + _meaningWebView.navigationDelegate = nil; + [_meaningWebView release]; + [meaningWebViewContainer release]; + [super dealloc]; } @@ -310,9 +488,9 @@ - (void)dealloc NSString * const LWECardHTMLTemplate = @"" "" "" -"
" +"
" "##EXAMPLES##" -"
"; \ No newline at end of file +"
"; diff --git a/jFlash/Classes/AppSpecific/HelpViewController.m b/jFlash/Classes/AppSpecific/HelpViewController.m index afbf2b8d..8ed555da 100644 --- a/jFlash/Classes/AppSpecific/HelpViewController.m +++ b/jFlash/Classes/AppSpecific/HelpViewController.m @@ -40,11 +40,12 @@ - (void) viewDidLoad // The tag glossary is only in JFlash NSLocalizedString(@"Tag Glossary",@"HelpViewController.Table_TagGlossary"), #endif - NSLocalizedString(@"Backup Custom Sets",@"HelpViewController.Table_BackupCustomSets"), - NSLocalizedString(@"Feedback",@"HelpViewController.Table_Feedback"), nil]; self.sectionTitles = names; + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.tableView.estimatedRowHeight = 52; + UIBarButtonItem *supportBtn = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Ask Us", @"HelpViewController.GetSatsifactionLink") style:UIBarButtonItemStyleBordered target:self action:@selector(_supportBtnPressed:)] autorelease]; @@ -65,8 +66,7 @@ - (void) viewDidLoad // We only use this in JFlash @"tags@2x", #endif - @"backup@2x", - @"feedback@2x",nil]; + nil]; currentIndex = 0; } @@ -107,21 +107,17 @@ - (void) navigateToNextHelpPage - (void) _supportBtnPressed:(id)sender { - UIAlertView *supportAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"GetSatisfaction.com",@"HelpViewController.SupportAlertMsgTitle") - message:NSLocalizedString(@"Do you have a question?\nA feature request?\n\nIt's best to make your voice heard on our support site, but we respond to e-mail too!",@"HelpViewController.SupportAlertMsgMsg") - delegate:self - cancelButtonTitle:NSLocalizedString(@"No Thanks",@"Cancel") - otherButtonTitles:NSLocalizedString(@"Visit Site",@"Visit Site"),NSLocalizedString(@"Send an Email",@"Mail Us"), nil]; - [supportAlert show]; - [supportAlert release]; -} + UIAlertController *alert = [UIAlertController + alertControllerWithTitle:NSLocalizedString(@"GetSatisfaction.com", @"HelpViewController.SupportAlertMsgTitle") + message:NSLocalizedString(@"Do you have a question?\nA feature request?\n\nIt's best to make your voice heard on our support site, but we respond to e-mail too!", @"HelpViewController.SupportAlertMsgMsg") + preferredStyle:UIAlertControllerStyleAlert]; -#pragma mark - UIAlertViewDelegate Methods + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"No Thanks", @"Cancel") + style:UIAlertActionStyleCancel handler:nil]]; -- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex -{ - if (buttonIndex == SUPPORT_ALERT_SITE_IDX) - { + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Visit Site", @"Visit Site") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *a) { #if defined (LWE_JFLASH) NSURL *url = [NSURL URLWithString:@"http://getsatisfaction.com/longweekend/products/longweekend_japanese_flash"]; #elif defined (LWE_CFLASH) @@ -130,25 +126,25 @@ - (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)butt NSURL *url = [NSURL URLWithString:@"http://getsatisfaction.com/longweekend/"]; #endif [[UIApplication sharedApplication] openURL:url]; - } - else if (buttonIndex == SUPPORT_ALERT_EMAIL_IDX) - { - if ([MFMailComposeViewController canSendMail]) - { + }]]; + + [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Send an Email", @"Mail Us") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *a) { + if ([MFMailComposeViewController canSendMail]) { MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init]; picker.mailComposeDelegate = self; [picker setSubject:@"Please Make This Awesome."]; [picker setToRecipients:[NSArray arrayWithObjects:LWE_SUPPORT_EMAIL, nil]]; - [self presentModalViewController:picker animated:YES]; + [self presentViewController:picker animated:YES completion:nil]; [picker release]; - } - else - { + } else { [LWEUIAlertView notificationAlertWithTitle:NSLocalizedString(@"Email Not Available", @"emailVM.notAvailable.title") message:NSLocalizedString(@"Oh no! It looks like your device isn't set up for Mail yet!", @"emailVM.notAvailable.body")]; - } - } + }]]; + + [self presentViewController:alert animated:YES completion:nil]; } #pragma mark - MFMailComposeViewControllerDelegate Methods @@ -181,6 +177,7 @@ - (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: cell = [LWEUITableUtils reuseCellForIdentifier:@"help" onTable:tableView usingStyle:UITableViewCellStyleDefault]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; cell.selectionStyle = UITableViewCellSelectionStyleGray; + cell.textLabel.numberOfLines = 0; cell.textLabel.text = [self.sectionTitles objectAtIndex:indexPath.row]; return cell; } diff --git a/jFlash/Classes/AppSpecific/HelpWebViewController.h b/jFlash/Classes/AppSpecific/HelpWebViewController.h index ee1db769..5542f93b 100644 --- a/jFlash/Classes/AppSpecific/HelpWebViewController.h +++ b/jFlash/Classes/AppSpecific/HelpWebViewController.h @@ -7,14 +7,18 @@ // #import -#import "UIWebView+LWENoBounces.h" +#import -@interface HelpWebViewController : UIViewController +@interface HelpWebViewController : UIViewController +{ + WKWebView *_webView; +} - (id) initWithFilename:(NSString *)filename usingTitle:(NSString*) title; - (void) loadPageWithBundleFilename:(NSString*)fn usingTitle:(NSString*) title; -@property (nonatomic, retain) IBOutlet UIWebView *webView; +//! Container view (XIB-instantiated UIView) that hosts the WKWebView added in viewDidLoad. +@property (nonatomic, retain) IBOutlet UIView *webViewContainer; @property (nonatomic, retain) NSString *filename; diff --git a/jFlash/Classes/AppSpecific/HelpWebViewController.m b/jFlash/Classes/AppSpecific/HelpWebViewController.m index aa5f104d..5be3bdd3 100644 --- a/jFlash/Classes/AppSpecific/HelpWebViewController.m +++ b/jFlash/Classes/AppSpecific/HelpWebViewController.m @@ -10,7 +10,7 @@ @implementation HelpWebViewController -@synthesize filename, webView; +@synthesize filename, webViewContainer; /** * Initializes the class and sets HTML filename to use and the title of the nav bar. @@ -35,14 +35,22 @@ - (void) loadPageWithBundleFilename:(NSString*)fn usingTitle:(NSString*) title self.title = title; [self _loadPageWithBundleFilename:fn]; } - -/** Creates the UIWebView programmatically */ + +/** Creates the WKWebView programmatically inside the XIB-instantiated container. */ - (void) viewDidLoad { [super viewDidLoad]; - [self.webView shutOffBouncing]; + WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; + _webView = [[WKWebView alloc] initWithFrame:self.webViewContainer.bounds + configuration:config]; + [config release]; + _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _webView.navigationDelegate = self; + _webView.scrollView.bounces = NO; + [self.webViewContainer addSubview:_webView]; + [self _loadPageWithBundleFilename:self.filename]; } @@ -55,22 +63,25 @@ - (void)viewWillAppear: (BOOL)animated } -/** Loads the filename into the _webView UIWebView - there should be no extension on the filename (but the actual file should be .html) */ +/** Loads the filename into the WKWebView - there should be no extension on the filename (but the actual file should be .html) */ - (void) _loadPageWithBundleFilename:(NSString*)fname { - // Prepare the URL NSString *urlAddress = [[NSBundle mainBundle] pathForResource:fname ofType:@"html" inDirectory:@"help"]; + if (urlAddress == nil) return; + NSURL *url = [NSURL fileURLWithPath:urlAddress]; - NSURLRequest *requestObj = [NSURLRequest requestWithURL:url]; - [self.webView loadRequest:requestObj]; + // WKWebView requires a readAccessURL for file:// loads to grant directory access. + [_webView loadFileURL:url allowingReadAccessToURL:[url URLByDeletingLastPathComponent]]; } - - + + //! Standard dealloc - (void)dealloc { + _webView.navigationDelegate = nil; + [_webView release]; [filename release]; - [webView release]; + [webViewContainer release]; [super dealloc]; } diff --git a/jFlash/Classes/AppSpecific/JFlashUpdateManager.m b/jFlash/Classes/AppSpecific/JFlashUpdateManager.m index 2c6c51b0..793593e3 100644 --- a/jFlash/Classes/AppSpecific/JFlashUpdateManager.m +++ b/jFlash/Classes/AppSpecific/JFlashUpdateManager.m @@ -43,6 +43,7 @@ + (void) _updateSettingsFrom162to17:(NSUserDefaults *)settings; + (BOOL) _needs17to18SettingsUpdate:(NSUserDefaults *) settings; + (void) _updateSettingsFrom17to18:(NSUserDefaults *)settings; + @end @@ -303,15 +304,13 @@ + (BOOL) _needs17to18SettingsUpdate:(NSUserDefaults *) settings + (void) _updateSettingsFrom17to18:(NSUserDefaults *)settings { - // Create a default setting that wasn't there before - [settings setObject:SET_TEXT_NORMAL forKey:APP_TEXT_SIZE]; [settings setObject:SET_KANA_ONLY_ON forKey:APP_KANA_ONLY]; [settings setObject:LWE_JF_VERSION_1_8 forKey:APP_DATA_VERSION]; [settings setObject:LWE_JF_VERSION_1_8 forKey:APP_SETTINGS_VERSION]; } -#pragma mark - +#pragma mark - + (BOOL) performMigrations:(NSUserDefaults*)settings { @@ -387,6 +386,7 @@ + (BOOL) performMigrations:(NSUserDefaults*)settings [JFlashUpdateManager _updateSettingsFrom17to18:settings]; migrated = YES; } + return migrated; } diff --git a/jFlash/Classes/AppSpecific/JapaneseSettingsDataSource.m b/jFlash/Classes/AppSpecific/JapaneseSettingsDataSource.m index 85ba7164..766bf503 100644 --- a/jFlash/Classes/AppSpecific/JapaneseSettingsDataSource.m +++ b/jFlash/Classes/AppSpecific/JapaneseSettingsDataSource.m @@ -24,11 +24,6 @@ - (void) dealloc #pragma mark - Settings Data Source -- (CGFloat) sizeForAcknowledgementsRow -{ - return 435.0f; -} - /** Returns all the arrays to configure the settings table */ - (NSArray*) settingsArrayWithPluginManager:(PluginManager *)pluginManager { @@ -64,16 +59,9 @@ - (NSArray*) settingsArrayWithPluginManager:(PluginManager *)pluginManager NSArray *kanaKeys = [NSArray arrayWithObjects:SET_KANA_ONLY_ON,SET_KANA_ONLY_OFF,nil]; NSDictionary *kanaDict = [NSDictionary dictionaryWithObjects:kanaObjects forKeys:kanaKeys]; - // This is for controlling the size of the text in the Web Views - NSArray *textSizeObjects = [NSArray arrayWithObjects:NSLocalizedString(@"Normal",@"SettingsViewController.TextSizeNormal"), - NSLocalizedString(@"Large",@"SettingsViewController.TextSizeLarge"), - NSLocalizedString(@"Huge",@"SettingsViewController.TextSizeHuge"),nil]; - NSArray *textSizeKeys = [NSArray arrayWithObjects:SET_TEXT_NORMAL,SET_TEXT_LARGE,SET_TEXT_HUGE,nil]; - NSDictionary *textSizeDict = [NSDictionary dictionaryWithObjects:textSizeObjects forKeys:textSizeKeys]; - // Create a complete dictionary of all settings display names & their setting constants - NSArray *dictObjects = [NSArray arrayWithObjects:headwordDict,themeDict,readingDict,kanaDict,modeDict,textSizeDict,nil]; - NSArray *dictKeys = [NSArray arrayWithObjects:APP_HEADWORD,APP_THEME,APP_READING,APP_KANA_ONLY,APP_MODE,APP_TEXT_SIZE,nil]; + NSArray *dictObjects = [NSArray arrayWithObjects:headwordDict,themeDict,readingDict,kanaDict,modeDict,nil]; + NSArray *dictKeys = [NSArray arrayWithObjects:APP_HEADWORD,APP_THEME,APP_READING,APP_KANA_ONLY,APP_MODE,nil]; self.settingsHash = [NSDictionary dictionaryWithObjects:dictObjects forKeys:dictKeys]; //====================================== @@ -85,9 +73,8 @@ - (NSArray*) settingsArrayWithPluginManager:(PluginManager *)pluginManager NSLocalizedString(@"Study Language",@"SettingsViewController.SettingNames_StudyLanguage"), NSLocalizedString(@"Furigana / Reading",@"SettingsViewController.SettingNames_DisplayFuriganaReading"), NSLocalizedString(@"Common Kana Words",@"SettingsViewController.SettingNames_KanaOnlyWords"), - NSLocalizedString(@"Text Size",@"SettingsViewController.SettingNames_TextSize"), NSLocalizedString(@"Difficulty",@"SettingsViewController.SettingNames_ChangeDifficulty"),nil]; - NSArray *cardSettingKeys = [NSArray arrayWithObjects:APP_MODE,APP_HEADWORD,APP_READING,APP_KANA_ONLY,APP_TEXT_SIZE,APP_ALGORITHM,nil]; + NSArray *cardSettingKeys = [NSArray arrayWithObjects:APP_MODE,APP_HEADWORD,APP_READING,APP_KANA_ONLY,APP_ALGORITHM,nil]; NSArray *cardSettingArray = [NSArray arrayWithObjects:cardSettingNames,cardSettingKeys,NSLocalizedString(@"Studying",@"SettingsViewController.TableHeader_Studying"),nil]; // Puts single section together, 3rd index is header name NSMutableArray *userSettingNames = [NSMutableArray arrayWithObjects:NSLocalizedString(@"Theme",@"SettingsViewController.SettingNames_Theme"), @@ -97,11 +84,6 @@ - (NSArray*) settingsArrayWithPluginManager:(PluginManager *)pluginManager NSMutableArray *userSettingKeys = [NSMutableArray arrayWithObjects:APP_THEME,APP_REMINDER,APP_USER,APP_PLUGIN,nil]; NSMutableArray *userSettingArray = [NSMutableArray arrayWithObjects:userSettingNames,userSettingKeys,NSLocalizedString(@"Application",@"SettingsViewController.TableHeader_Application"),nil]; - NSArray *socialNames = [NSArray arrayWithObjects:NSLocalizedString(@"Follow us on Twitter",@"SettingsViewController.SettingNames_Twitter"), - NSLocalizedString(@"See us on Facebook",@"SettingsViewController.SettingNames_Facebook"),nil]; - NSArray *socialKeys = [NSArray arrayWithObjects:APP_TWITTER,APP_FACEBOOK,nil]; - NSArray *socialArray = [NSArray arrayWithObjects:socialNames,socialKeys,NSLocalizedString(@"Follow Us",@"SettingsViewController.TableHeader_FollowUs"),nil]; - NSArray *aboutNames = [NSArray arrayWithObjects:NSLocalizedString(@"Japanese Flash was created on a Long Weekend over a few steaks and a few more Coronas. Special thanks goes to Teja for helping us write and simulate the frequency algorithm. This application also uses data from the EDICT dictionary and Tanaka Corpus. The EDICT files are property of the Electronic Dictionary Research and Development Group, and are used in conformance with the Group's license. Some icons by Joseph Wain / glyphish.com. The Japanese Flash Logo & Product Name are original creations and any perceived similarities to other trademarks is unintended and purely coincidental.",@"SettingsViewController.Acknowledgements"),nil]; NSArray *aboutKeys = [NSArray arrayWithObjects:APP_ABOUT,nil]; NSArray *aboutArray = [NSArray arrayWithObjects:aboutNames,aboutKeys,NSLocalizedString(@"Acknowledgements",@"SettingsViewController.TableHeader_Acknowledgements"),nil]; @@ -110,11 +92,11 @@ - (NSArray*) settingsArrayWithPluginManager:(PluginManager *)pluginManager // If there is a new available update plugin, it will show in the first section, however, if it does not have anything, it will show nothing. if (newAvailableUpdate > 0) { - return [NSArray arrayWithObjects:newUpdateArray,cardSettingArray,userSettingArray,socialArray,aboutArray,nil]; + return [NSArray arrayWithObjects:newUpdateArray,cardSettingArray,userSettingArray,aboutArray,nil]; } - else + else { - return [NSArray arrayWithObjects:cardSettingArray,userSettingArray,socialArray,aboutArray,nil]; + return [NSArray arrayWithObjects:cardSettingArray,userSettingArray,aboutArray,nil]; } } diff --git a/jFlash/Classes/AppSpecific/LWEChineseSearchBarInput.xib b/jFlash/Classes/AppSpecific/LWEChineseSearchBarInput.xib index 21ea58c6..775dc7b1 100644 --- a/jFlash/Classes/AppSpecific/LWEChineseSearchBarInput.xib +++ b/jFlash/Classes/AppSpecific/LWEChineseSearchBarInput.xib @@ -1,7 +1,7 @@ - 1280 + 1792 11C74 1938 1138.23 diff --git a/jFlash/Classes/AppSpecific/ModalTaskViewController.h b/jFlash/Classes/AppSpecific/ModalTaskViewController.h index 0f6b7a6e..1d58f528 100644 --- a/jFlash/Classes/AppSpecific/ModalTaskViewController.h +++ b/jFlash/Classes/AppSpecific/ModalTaskViewController.h @@ -7,8 +7,8 @@ // #import +#import #import "LWELongRunningTaskProtocol.h" -#import "UIWebView+LWENoBounces.h" #import "LWEPackageDownloader.h" extern NSString * const LWEModalTaskDidCancel; @@ -17,6 +17,7 @@ extern NSString * const LWEModalTaskDidCancel; { NSString *webViewContentDirectory; //! Sets the sub directory of the content to load into the details web view NSString *webViewContentFileName; //! Sets the filename of the content to load into the details web view + WKWebView *_webView; } // IBActions @@ -35,7 +36,8 @@ extern NSString * const LWEModalTaskDidCancel; @property (nonatomic, retain) IBOutlet UILabel *taskMsgLabel; @property (nonatomic, retain) IBOutlet UIButton *startButton; @property (nonatomic, retain) UIProgressView *progressIndicator; -@property (retain, nonatomic) IBOutlet UIWebView *webView; +//! Container view (XIB-instantiated UIView) that hosts the WKWebView added in viewDidLoad. +@property (retain, nonatomic) IBOutlet UIView *webViewContainer; // User-set properties diff --git a/jFlash/Classes/AppSpecific/ModalTaskViewController.m b/jFlash/Classes/AppSpecific/ModalTaskViewController.m index d90c18c2..c098f865 100644 --- a/jFlash/Classes/AppSpecific/ModalTaskViewController.m +++ b/jFlash/Classes/AppSpecific/ModalTaskViewController.m @@ -15,7 +15,7 @@ */ @implementation ModalTaskViewController -@synthesize taskMsgLabel, progressIndicator, startButton, taskHandler, webView; +@synthesize taskMsgLabel, progressIndicator, startButton, taskHandler, webViewContainer; // For content/webview @synthesize webViewContent; @@ -26,7 +26,16 @@ @implementation ModalTaskViewController - (void)viewDidLoad { [super viewDidLoad]; - + + // Create the WKWebView programmatically inside the XIB-instantiated container. + WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; + _webView = [[WKWebView alloc] initWithFrame:self.webViewContainer.bounds + configuration:config]; + [config release]; + _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _webView.scrollView.bounces = NO; + [self.webViewContainer addSubview:_webView]; + // Make sure the buttons are set to the right states [self updateButtons]; [self showDetailedView]; @@ -185,19 +194,17 @@ - (IBAction) dismiss */ - (IBAction) showDetailedView { - [self.webView shutOffBouncing]; - // Only show content if we have set this variable if (self.webViewContent) { NSURL *url = [NSURL fileURLWithPath:[LWEFile createBundlePathWithFilename:@"plugin-resources/index.html"]]; - [self.webView loadHTMLString:self.webViewContent baseURL:url]; + [_webView loadHTMLString:self.webViewContent baseURL:url]; } } - (void) viewDidUnload { - [self setWebView:nil]; + self.webViewContainer = nil; [super viewDidUnload]; self.taskMsgLabel = nil; self.progressIndicator = nil; @@ -206,11 +213,12 @@ - (void) viewDidUnload //! standard dealloc - (void)dealloc { + [_webView release]; [taskMsgLabel release]; [progressIndicator release]; [webViewContent release]; [taskHandler release]; - self.webView = nil; + [webViewContainer release]; [super dealloc]; } diff --git a/jFlash/Classes/AppSpecific/PluginManager.h b/jFlash/Classes/AppSpecific/PluginManager.h index dbe5e7c5..830dea60 100644 --- a/jFlash/Classes/AppSpecific/PluginManager.h +++ b/jFlash/Classes/AppSpecific/PluginManager.h @@ -10,7 +10,6 @@ #import "FMResultSet.h" #import "Plugin.h" #import "NSDate+LWEUtilities.h" -#import "ASIHTTPRequest.h" extern NSString * const LWEPluginDidInstall; @@ -40,7 +39,12 @@ extern NSString * const LWEPluginDidInstall; //========= THESE GIVE STATE ======== - (BOOL) isTimeForCheckingUpdate; -- (BOOL)checkNewPluginsAsynchronous:(BOOL)asynch; + +//! Fetches the latest available-plugins plist from the server using NSURLSession. +//! The completion block is invoked on the main queue with success=YES if the +//! plist was downloaded and applied, NO otherwise. The completion block may be +//! nil for fire-and-forget callers. +- (void) checkNewPluginsWithCompletion:(void (^)(BOOL success))completion; //! Returns YES if the plugin is loaded. Directory plugins always return YES. diff --git a/jFlash/Classes/AppSpecific/PluginManager.m b/jFlash/Classes/AppSpecific/PluginManager.m index a3629b90..2de084b0 100644 --- a/jFlash/Classes/AppSpecific/PluginManager.m +++ b/jFlash/Classes/AppSpecific/PluginManager.m @@ -15,7 +15,6 @@ @interface PluginManager () - (void)_initDownloadablePluginsDict; - (void) _registerPlugin:(Plugin *)plugin; - (BOOL) _loadDatabasePlugin:(Plugin *)plugin error:(NSError **)error; -- (BOOL) _retrievePlistFromServer; @end @implementation PluginManager @@ -346,22 +345,46 @@ - (BOOL) isTimeForCheckingUpdate } /** - * Check the new plugin over the website, and looks whether it has a new stuff - * \param asynch If YES, the URL retrieve will happen on a background thread (the processing afterward will remain on the main thread) - * \param notifyOnNetworkFail If YES, and network is not available, will prompt a LWEUIAlertView noNetwork alert + * Check the server for an updated available-plugins plist. The completion + * handler runs on the main queue. */ -- (BOOL)checkNewPluginsAsynchronous:(BOOL)asynch -{ - // Check if they have network first, if so, start the background thread - if (asynch) - { - [self performSelectorInBackground:@selector(_retrievePlistFromServer) withObject:nil]; - return YES; - } - else +- (void)checkNewPluginsWithCompletion:(void (^)(BOOL))completion +{ + NSString *urlStr = [LWE_PLUGIN_SERVER stringByAppendingString:LWE_PLUGIN_LIST_REL_URL]; + NSURL *url = [NSURL URLWithString:urlStr]; + if (url == nil) { - return [self _retrievePlistFromServer]; + if (completion) dispatch_async(dispatch_get_main_queue(), ^{ completion(NO); }); + return; } + + NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + NSDictionary *plist = nil; + if (data != nil && error == nil) + { + id parsed = [NSPropertyListSerialization propertyListWithData:data + options:NSPropertyListImmutable + format:NULL + error:NULL]; + if ([parsed isKindOfClass:[NSDictionary class]]) + { + plist = parsed; + } + } + + // processPlistHash: touches NSUserDefaults and self.downloadablePlugins, + // so jump back to the main queue for the apply step and the completion. + dispatch_async(dispatch_get_main_queue(), ^{ + if (plist != nil) + { + [self processPlistHash:plist]; + [[NSUserDefaults standardUserDefaults] setValue:[NSDate date] forKey:PLUGIN_LAST_UPDATE]; + } + if (completion) completion(plist != nil); + }); + }]; + [task resume]; } @@ -389,34 +412,6 @@ - (void) _registerPlugin:(Plugin *)plugin } -/** - * Intended to be run in the background so we don't lock the main thread, but can be run - * synchronously. - */ -- (BOOL)_retrievePlistFromServer -{ - BOOL success = NO; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSString *urlStr = [LWE_PLUGIN_SERVER stringByAppendingString:LWE_PLUGIN_LIST_REL_URL]; - NSDictionary *plist = [[NSDictionary alloc] initWithContentsOfURL:[NSURL URLWithString:urlStr]]; - if (plist) - { - // Ask the plugin manager to deal with it. Wait until done because it needs the plist var to stay around - [self performSelectorOnMainThread:@selector(processPlistHash:) withObject:plist waitUntilDone:YES]; - - // Yep, we got a PLIST - success = YES; - - // Now update the settings so we record that we checked - NSUserDefaults *settings = [NSUserDefaults standardUserDefaults]; - [settings setValue:[NSDate date] forKey:PLUGIN_LAST_UPDATE]; - } - [plist release]; - [pool release]; - return success; -} - #pragma mark - Memory Management - (void)dealloc diff --git a/jFlash/Classes/AppSpecific/PluginSettingsViewController.m b/jFlash/Classes/AppSpecific/PluginSettingsViewController.m index eb0ba864..fbc400d4 100644 --- a/jFlash/Classes/AppSpecific/PluginSettingsViewController.m +++ b/jFlash/Classes/AppSpecific/PluginSettingsViewController.m @@ -49,22 +49,21 @@ - (IBAction) checkUpdatePlugin:(id)sender } /** - * This method will perform the real check update method on the + * This method will perform the real check update method on the * plugin manager. */ - (void)performCheckUpdateWithLoadingView { - - [self _changeLastUpdateLabel]; - BOOL success = [self.pluginManager checkNewPluginsAsynchronous:NO]; - if (success == NO) - { - // If we failed to check for plugins, we probably have no network connectivity. - [LWEUIAlertView noNetworkAlert]; - } - [self _reloadTableData]; - - [DSBezelActivityView removeViewAnimated:YES]; + [self _changeLastUpdateLabel]; + [self.pluginManager checkNewPluginsWithCompletion:^(BOOL success) { + if (success == NO) + { + // If we failed to check for plugins, we probably have no network connectivity. + [LWEUIAlertView noNetworkAlert]; + } + [self _reloadTableData]; + [DSBezelActivityView removeViewAnimated:YES]; + }]; } #pragma mark - @@ -91,7 +90,26 @@ - (void)viewDidLoad [self _reloadTableData]; [self _changeLastUpdateLabel]; - + + CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; + UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, 96)]; + headerView.backgroundColor = [UIColor clearColor]; + headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + + self.btnCheckUpdate.frame = CGRectMake(16, 12, screenWidth - 32, 44); + self.btnCheckUpdate.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [headerView addSubview:self.btnCheckUpdate]; + + self.lblLastUpdate.frame = CGRectMake(16, 64, screenWidth - 32, 21); + self.lblLastUpdate.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [headerView addSubview:self.lblLastUpdate]; + + self.tableView.tableHeaderView = headerView; + [headerView release]; + + self.tableView.rowHeight = UITableViewAutomaticDimension; + self.tableView.estimatedRowHeight = 52; + // Set YELLOW, not RED NSMutableArray *colors = [NSMutableArray arrayWithCapacity:4]; UIColor *color = nil; @@ -196,12 +214,14 @@ - (UITableViewCell *)tableView:(UITableView *)lclTableView cellForRowAtIndexPath cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.accessoryType = UITableViewCellAccessoryCheckmark; Plugin *thePlugin = [self.installedPlugins objectAtIndex:indexPath.row]; + cell.textLabel.numberOfLines = 0; cell.textLabel.text = thePlugin.name; } else { cell = [LWEUITableUtils reuseCellForIdentifier:@"available" onTable:lclTableView usingStyle:UITableViewCellStyleSubtitle]; Plugin *thePlugin = [self.availablePlugins objectAtIndex:indexPath.row]; + cell.textLabel.numberOfLines = 0; cell.textLabel.text = thePlugin.name; cell.detailTextLabel.font = [UIFont boldSystemFontOfSize:12]; cell.detailTextLabel.text = thePlugin.details; diff --git a/jFlash/Classes/AppSpecific/PracticeModeCardViewDelegate.m b/jFlash/Classes/AppSpecific/PracticeModeCardViewDelegate.m index a45adac5..c18dd428 100644 --- a/jFlash/Classes/AppSpecific/PracticeModeCardViewDelegate.m +++ b/jFlash/Classes/AppSpecific/PracticeModeCardViewDelegate.m @@ -182,8 +182,6 @@ - (void) updateStudyViewLabels:(StudyViewController*)svc - (void)actionBarDidChangeMode:(ActionBarViewController *)avc { - // Change action bar view to original XIB - [[NSBundle mainBundle] loadNibNamed:@"ActionBarViewController" owner:avc options:nil]; } -(void) actionBarWillSetup:(ActionBarViewController*)avc diff --git a/jFlash/Classes/AppSpecific/ProgressBarViewController.m b/jFlash/Classes/AppSpecific/ProgressBarViewController.m index 3f7f4794..ac91d419 100644 --- a/jFlash/Classes/AppSpecific/ProgressBarViewController.m +++ b/jFlash/Classes/AppSpecific/ProgressBarViewController.m @@ -34,14 +34,16 @@ - (UIProgressView *)_progressBarForLevel:(NSInteger)i // draws the progress bar - (void) drawProgressBar { - // TODO: iPad customization - NSInteger pbOrigin = 7; + CGFloat totalWidth = self.view.bounds.size.width; + if (totalWidth <= 0) totalWidth = 320.0; + CGFloat colW = totalWidth / 5.0; + CGFloat hPad = 4.0; + NSInteger thisLevelCount = self.tag.seenCardCount; - + // For levels 1-5 for (NSInteger i = 1; i < 6; i++) { - // This call handles the creation and/or getting of the progress bar UIProgressView *progressView = [self _progressBarForLevel:i]; if (i > 1) @@ -54,29 +56,41 @@ - (void) drawProgressBar progress = ((CGFloat)thisLevelCount / (CGFloat)tag.seenCardCount); } progressView.progress = progress; - - // TODO: iPad customization! - //move the origin of the next progress bar over - progressView.frame = CGRectMake(pbOrigin, 19, 57, 14); - pbOrigin += progressView.frame.size.width + 5; + + CGFloat colX = (i - 1) * colW; + progressView.frame = CGRectMake(colX + hPad, 19, colW - 2 * hPad, 14); } - - // Finally bring all the labels to the front + + // Update count labels (tags 201-205) and header labels (tags 301-305) for (NSInteger i = 1; i < 6; i++) { - // Update the label - UILabel *progressLabel = (UILabel*)[self.view viewWithTag:(i+PROGRESS_LABEL_TAG)]; - if (progressLabel) + CGFloat colX = (i - 1) * colW; + CGFloat labelX = colX + hPad; + CGFloat labelW = colW - 2 * hPad; + + UILabel *countLabel = (UILabel*)[self.view viewWithTag:(i + PROGRESS_LABEL_TAG)]; + if (countLabel) { - progressLabel.text = [NSString stringWithFormat:@"%d",[[self.tag.cardLevelCounts objectAtIndex:i] integerValue]]; - [self.view bringSubviewToFront:progressLabel]; + countLabel.text = [NSString stringWithFormat:@"%d", [[self.tag.cardLevelCounts objectAtIndex:i] integerValue]]; + countLabel.frame = CGRectMake(labelX, 20, labelW, 21); + [self.view bringSubviewToFront:countLabel]; + } + + UILabel *headerLabel = (UILabel*)[self.view viewWithTag:(i + 300)]; + if (headerLabel) + { + headerLabel.frame = CGRectMake(labelX, -1, labelW, 21); } } - - [self.view setNeedsLayout]; } -- (void)dealloc +- (void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + if (self.tag) [self drawProgressBar]; +} + +- (void)dealloc { [tag release]; [super dealloc]; diff --git a/jFlash/Classes/AppSpecific/ProgressBarViewController.xib b/jFlash/Classes/AppSpecific/ProgressBarViewController.xib index 9ece6381..38c29ea8 100644 --- a/jFlash/Classes/AppSpecific/ProgressBarViewController.xib +++ b/jFlash/Classes/AppSpecific/ProgressBarViewController.xib @@ -1,7 +1,7 @@ - + @@ -13,11 +13,11 @@ - + - + @@ -90,10 +90,6 @@ - - - - \ No newline at end of file diff --git a/jFlash/XIBs/AddStudySetView.xib b/jFlash/XIBs/AddStudySetView.xib index 2118953b..feb3506b 100644 --- a/jFlash/XIBs/AddStudySetView.xib +++ b/jFlash/XIBs/AddStudySetView.xib @@ -1,7 +1,7 @@ - + @@ -14,7 +14,7 @@ - + diff --git a/jFlash/XIBs/AddTagView.xib b/jFlash/XIBs/AddTagView.xib index 0ea6a35a..de719f4d 100644 --- a/jFlash/XIBs/AddTagView.xib +++ b/jFlash/XIBs/AddTagView.xib @@ -1,7 +1,7 @@ - + diff --git a/jFlash/XIBs/AlgorithmSettingsView.xib b/jFlash/XIBs/AlgorithmSettingsView.xib index 5f97b4fe..efb6f702 100644 --- a/jFlash/XIBs/AlgorithmSettingsView.xib +++ b/jFlash/XIBs/AlgorithmSettingsView.xib @@ -1,491 +1,67 @@ - - - 784 - 11G56 - 2840 - 1138.51 - 569.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1926 - - - YES - IBProxyObject - IBUILabel - IBUISegmentedControl - IBUISlider - IBUITableView - IBUIView - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - {230, 23} - - - _NS:623 - NO - IBCocoaTouchFramework - 0 - 0 - 30 - 5 - 50 - NO - - - - 292 - {230, 23} - - - _NS:623 - NO - IBCocoaTouchFramework - 0 - 0 - 30 - 5 - 50 - NO - - - - 292 - - YES - - - 274 - {{0, 92}, {320, 324}} - - - - 3 - MCAwAA - - NO - YES - NO - IBCocoaTouchFramework - NO - NO - NO - NO - NO - 1 - 1 - 0 - YES - 44 - 10 - 10 - - - - 292 - {{11, 55}, {296, 30}} - - - - NO - NO - IBCocoaTouchFramework - 2 - 4 - 0 - - YES - Easy - Medium - Hard - Custom - - - YES - - - - - - - YES - - - - - - - YES - {0, 0} - {0, 0} - {0, 0} - {0, 0} - - - YES - - - - - - - - - 292 - {{18, 19}, {279, 26}} - - - - NO - YES - NO - IBCocoaTouchFramework - Difficulty - - 2 - MC4yOTgwMzkyMjc3IDAuMzM3MjU0OTExNyAwLjQyMzUyOTQ0NjEgMC44ODk5OTk5ODU3AA - - - - 1 - MSAxIDEAA - - {0, 1} - 1 - 10 - - Helvetica-Bold - Helvetica - 2 - 17 - - - Helvetica-Bold - 17 - 16 - - - - {{0, 64}, {320, 416}} - - - - - 3 - MQA - - 2 - - - - - NO - - IBCocoaTouchFramework - - - - - YES - - - difficultySegmentControl - - - - 9 - - - - view - - - - 24 - - - - tableView - - - - 26 - - - - maxCardsSlider - - - - 33 - - - - frequencySlider - - - - 34 - - - - dataSource - - - - 5 - - - - delegate - - - - 6 - - - - setDifficulty: - - - 13 - - 10 - - - - sliderValueChanged: - - - 13 - - 35 - - - - sliderValueChanged: - - - 13 - - 36 - - - - - YES - - 0 - - YES - - - - - - 1 - - - YES - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - 7 - - - - - 8 - - - - - 27 - - - Max Cards Slider - - - 30 - - - Unseen Slider - - - - - YES - - YES - -1.CustomClassName - -1.IBPluginDependency - -2.CustomClassName - -2.IBPluginDependency - 1.IBPluginDependency - 27.IBPluginDependency - 30.IBPluginDependency - 4.IBPluginDependency - 7.IBPluginDependency - 8.IBPluginDependency - - - YES - AlgorithmSettingsViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - - - - YES - - - - - 36 - - - - YES - - AlgorithmSettingsViewController - UIViewController - - YES - - YES - setDifficulty: - sliderValueChanged: - - - YES - UISegmentedControl - UISlider - - - - YES - - YES - setDifficulty: - sliderValueChanged: - - - YES - - setDifficulty: - UISegmentedControl - - - sliderValueChanged: - UISlider - - - - - YES - - YES - frequencySlider - maxCardsSlider - - - YES - UISlider - UISlider - - - - YES - - YES - frequencySlider - maxCardsSlider - - - YES - - frequencySlider - UISlider - - - maxCardsSlider - UISlider - - - - - IBProjectSource - ./Classes/AlgorithmSettingsViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 1926 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jFlash/XIBs/ExampleSentencesView.xib b/jFlash/XIBs/ExampleSentencesView.xib index f1b4d6e8..e7616955 100644 --- a/jFlash/XIBs/ExampleSentencesView.xib +++ b/jFlash/XIBs/ExampleSentencesView.xib @@ -1,31 +1,20 @@ - + - - + - - - - - - - - - - diff --git a/jFlash/XIBs/ExamplesUnavailable.xib b/jFlash/XIBs/ExamplesUnavailable.xib index 8936f884..538cb86a 100644 --- a/jFlash/XIBs/ExamplesUnavailable.xib +++ b/jFlash/XIBs/ExamplesUnavailable.xib @@ -1,7 +1,7 @@ - + diff --git a/jFlash/XIBs/GroupDescriptionView.xib b/jFlash/XIBs/GroupDescriptionView.xib index 96a15436..90852768 100644 --- a/jFlash/XIBs/GroupDescriptionView.xib +++ b/jFlash/XIBs/GroupDescriptionView.xib @@ -1,188 +1,45 @@ - - - 1280 - 11C74 - 1938 - 1138.23 - 567.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 933 - - - IBProxyObject - IBUIView - IBUILabel - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 292 - - - - 292 - {{7, 7}, {290, 32}} - - - - _NS:328 - NO - YES - 7 - NO - IBCocoaTouchFramework - Label - - 1 - MCAwIDAAA - - - 1 - 10 - - 1 - 17 - - - Helvetica - 17 - 16 - - - - {{8, 12}, {304, 46}} - - - - _NS:196 - - 1 - MC45NzYwMDQ0NjQzIDAuOTc2MDA0NDY0MyAwLjk3NjAwNDQ2NDMAA - - IBCocoaTouchFramework - - - {320, 70} - - - - - 3 - MQA - - 2 - - - IBCocoaTouchFramework - - - - - - - - 0 - - - - - - 1 - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - - - - 3 - - - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - IBUserDefinedRuntimeAttributesPlaceholderName - - IBUserDefinedRuntimeAttributesPlaceholderName - - - - com.apple.InterfaceBuilder.userDefinedRuntimeAttributeType.number - layer.cornerRadius - - - - com.apple.InterfaceBuilder.userDefinedRuntimeAttributeType.number - borderWidth - - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 4 - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 933 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jFlash/XIBs/HelpScrollView.xib b/jFlash/XIBs/HelpScrollView.xib index afbe43cc..02625d72 100644 --- a/jFlash/XIBs/HelpScrollView.xib +++ b/jFlash/XIBs/HelpScrollView.xib @@ -1,7 +1,7 @@ - 784 + 1792 9L31a 680 949.54 diff --git a/jFlash/XIBs/HelpView.xib b/jFlash/XIBs/HelpView.xib index 7cada1df..de02b9c0 100644 --- a/jFlash/XIBs/HelpView.xib +++ b/jFlash/XIBs/HelpView.xib @@ -1,7 +1,7 @@ - + diff --git a/jFlash/XIBs/HelpWebViewController.xib b/jFlash/XIBs/HelpWebViewController.xib index 5b94116e..b775d5c3 100644 --- a/jFlash/XIBs/HelpWebViewController.xib +++ b/jFlash/XIBs/HelpWebViewController.xib @@ -1,187 +1,33 @@ - - - 1072 - 11E53 - 2844 - 1138.47 - 569.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1930 - - - IBProxyObject - IBUIView - IBUIWebView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 319 - {320, 416} - - - - _NS:9 - - 3 - MCAwAA - - NO - IBCocoaTouchFramework - 1 - YES - - - {{0, 64}, {320, 416}} - - - - - 3 - MQA - - 2 - - - - - NO - - IBCocoaTouchFramework - - - - - - - view - - - - 3 - - - - webView - - - - 14 - - - - delegate - - - - 13 - - - - - - 0 - - - - - - 1 - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - - - - HelpWebViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 15 - - - - - HelpWebViewController - UIViewController - - webView - UIWebView - - - webView - - webView - UIWebView - - - - IBProjectSource - ./Classes/HelpWebViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - 1930 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jFlash/XIBs/MainWindow-iPad.xib b/jFlash/XIBs/MainWindow-iPad.xib index 708be348..7e1d7824 100644 --- a/jFlash/XIBs/MainWindow-iPad.xib +++ b/jFlash/XIBs/MainWindow-iPad.xib @@ -1,7 +1,7 @@ - 1536 + 1792 11E53 2840 1138.47 diff --git a/jFlash/XIBs/MainWindow.xib b/jFlash/XIBs/MainWindow.xib index a0bce619..c450ffb9 100644 --- a/jFlash/XIBs/MainWindow.xib +++ b/jFlash/XIBs/MainWindow.xib @@ -1,16 +1,13 @@ - - + + + - + + + - - - - - - - + @@ -19,7 +16,8 @@ - + + @@ -36,35 +34,24 @@ - - + + - - + - - - - - - + - - - - - @@ -72,12 +59,8 @@ - - - - - + @@ -85,34 +68,20 @@ - - - - - - - - - - + - - - - - @@ -123,23 +92,14 @@ - - - - - + - - - - - @@ -149,29 +109,20 @@ - - - - - + - - - - - - + @@ -181,4 +132,4 @@ - \ No newline at end of file + diff --git a/jFlash/XIBs/ModalTaskView.xib b/jFlash/XIBs/ModalTaskView.xib index 0f299eb4..c754eadd 100644 --- a/jFlash/XIBs/ModalTaskView.xib +++ b/jFlash/XIBs/ModalTaskView.xib @@ -11,7 +11,7 @@ - + @@ -41,12 +41,12 @@ - + - + diff --git a/jFlash/XIBs/MoodIcon.xib b/jFlash/XIBs/MoodIcon.xib index cb7eb421..2bb4c65a 100644 --- a/jFlash/XIBs/MoodIcon.xib +++ b/jFlash/XIBs/MoodIcon.xib @@ -1,306 +1,62 @@ - - - 1536 - 11E53 - 2844 - 1138.47 - 569.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1930 - - - IBProxyObject - IBUIButton - IBUIImageView - IBUILabel - IBUIView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 310 - - - - 292 - {{0, 1}, {49, 39}} - - - - NO - NO - 4 - NO - IBCocoaTouchFramework - - NSImage - talkbubble-ft.png - - - - - 292 - {{37, 8}, {43, 65}} - - - - NO - NO - IBCocoaTouchFramework - NO - 0 - 0 - NO - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - Helvetica-Bold - Helvetica - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{6, 8}, {38, 27}} - - - - NO - YES - NO - IBCocoaTouchFramework - 100% - - 1 - MCAwIDAAA - darkTextColor - - - 1 - 10 - 1 - - HelveticaNeue-Bold - Helvetica Neue - 2 - 13 - - - HelveticaNeue-Bold - 13 - 16 - - - - {80, 73} - - - - - 3 - MCAwAA - - IBCocoaTouchFramework - - - - - - - moodIconBtn - - - - 15 - - - - percentCorrectLabel - - - - 16 - - - - talkBubble - - - - 18 - - - - view - - - - 20 - - - - doTogglePercentCorrectBtn - - - 7 - - 19 - - - - - - 0 - - - - - - 1 - - - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 11 - - - percentCorrectTalkBubble - - - 12 - - - moodIconBtn - - - 14 - - - percentCorrectLabel - - - - - MoodIcon - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 20 - - - - - MoodIcon - NSObject - - doTogglePercentCorrectBtn - id - - - doTogglePercentCorrectBtn - - doTogglePercentCorrectBtn - id - - - - UIButton - UILabel - UIImageView - UIView - - - - moodIconBtn - UIButton - - - percentCorrectLabel - UILabel - - - talkBubble - UIImageView - - - view - UIView - - - - IBProjectSource - ./Classes/MoodIcon.h - - - - - 0 - IBCocoaTouchFramework - YES - 3 - - talkbubble-ft.png - {49, 39} - - 1930 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jFlash/XIBs/PluginSettingsView.xib b/jFlash/XIBs/PluginSettingsView.xib index 3a6ea43b..ae62422a 100644 --- a/jFlash/XIBs/PluginSettingsView.xib +++ b/jFlash/XIBs/PluginSettingsView.xib @@ -13,44 +13,41 @@ + + - + - - - - \ No newline at end of file + diff --git a/jFlash/XIBs/ProgressView.xib b/jFlash/XIBs/ProgressView.xib index c63cf990..f2646d19 100644 --- a/jFlash/XIBs/ProgressView.xib +++ b/jFlash/XIBs/ProgressView.xib @@ -1,7 +1,7 @@ - + @@ -34,15 +34,15 @@ - + - + - + diff --git a/jFlash/XIBs/SearchView.xib b/jFlash/XIBs/SearchView.xib index 3481f925..9b55dde1 100644 --- a/jFlash/XIBs/SearchView.xib +++ b/jFlash/XIBs/SearchView.xib @@ -1,8 +1,10 @@ - - + + + - - + + + @@ -17,8 +19,10 @@ - - + + + + @@ -31,24 +35,27 @@ + - + - - + + + - \ No newline at end of file + diff --git a/jFlash/XIBs/SearchingTableCell.xib b/jFlash/XIBs/SearchingTableCell.xib index ef9f77bf..065d69ef 100644 --- a/jFlash/XIBs/SearchingTableCell.xib +++ b/jFlash/XIBs/SearchingTableCell.xib @@ -1,7 +1,7 @@ - 1280 + 1792 11C74 1938 1138.23 diff --git a/jFlash/XIBs/SentenceView.xib b/jFlash/XIBs/SentenceView.xib index 3b2e441c..ce034fdb 100644 --- a/jFlash/XIBs/SentenceView.xib +++ b/jFlash/XIBs/SentenceView.xib @@ -1,431 +1,36 @@ - - - 784 - 10D578 - 759 - 1038.29 - 460.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 79 - - - YES - - - - YES - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - YES - - YES - - - YES - - - - YES - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 292 - - YES - - - 274 - {320, 460} - - NO - YES - NO - IBCocoaTouchFramework - NO - 1 - 1 - 0 - YES - 44 - 10 - 10 - - - {320, 460} - - - 3 - MQA - - 2 - - - IBCocoaTouchFramework - - - - - YES - - - delegate - - - - 13 - - - - dataSource - - - - 14 - - - - view - - - - 15 - - - - - YES - - 0 - - - - - - 1 - - - YES - - - - - - -1 - - - File's Owner - - - -2 - - - - - 7 - - - - - - - YES - - YES - -1.CustomClassName - -2.CustomClassName - 1.IBEditorWindowLastContentRect - 1.IBPluginDependency - 7.IBPluginDependency - - - YES - DisplaySearchedSentenceViewController - UIResponder - {{528, 426}, {320, 460}} - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - YES - - - YES - - - - - YES - - - YES - - - - 15 - - - - YES - - DisplaySearchedSentenceViewController - UITableViewController - - IBProjectSource - Classes/AppSpecific/DisplaySearchedSentenceViewController.h - - - - - YES - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSError.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSFileManager.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueCoding.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyValueObserving.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSKeyedArchiver.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSNetServices.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSObject.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSPort.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSRunLoop.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSStream.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSThread.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURL.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSURLConnection.h - - - - NSObject - - IBFrameworkSource - Foundation.framework/Headers/NSXMLParser.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CAAnimation.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CALayer.h - - - - NSObject - - IBFrameworkSource - QuartzCore.framework/Headers/CIImageProvider.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIAccessibility.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UINibLoading.h - - - - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UIResponder.h - - - - UIResponder - NSObject - - - - UIScrollView - UIView - - IBFrameworkSource - UIKit.framework/Headers/UIScrollView.h - - - - UISearchBar - UIView - - IBFrameworkSource - UIKit.framework/Headers/UISearchBar.h - - - - UISearchDisplayController - NSObject - - IBFrameworkSource - UIKit.framework/Headers/UISearchDisplayController.h - - - - UITableView - UIScrollView - - IBFrameworkSource - UIKit.framework/Headers/UITableView.h - - - - UITableViewController - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITableViewController.h - - - - UIView - - IBFrameworkSource - UIKit.framework/Headers/UITextField.h - - - - UIView - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIView.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UINavigationController.h - - - - UIViewController - - IBFrameworkSource - UIKit.framework/Headers/UITabBarController.h - - - - UIViewController - UIResponder - - IBFrameworkSource - UIKit.framework/Headers/UIViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - ../jFlash.xcodeproj - 3 - 79 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jFlash/XIBs/SettingsView.xib b/jFlash/XIBs/SettingsView.xib index 909d9e33..a3f50677 100644 --- a/jFlash/XIBs/SettingsView.xib +++ b/jFlash/XIBs/SettingsView.xib @@ -1,7 +1,7 @@ - + diff --git a/jFlash/XIBs/StudySetView.xib b/jFlash/XIBs/StudySetView.xib index 7dadbf7b..e906c68f 100644 --- a/jFlash/XIBs/StudySetView.xib +++ b/jFlash/XIBs/StudySetView.xib @@ -1,7 +1,7 @@ - + diff --git a/jFlash/XIBs/StudyView.xib b/jFlash/XIBs/StudyView.xib index d720cece..6265d9bb 100644 --- a/jFlash/XIBs/StudyView.xib +++ b/jFlash/XIBs/StudyView.xib @@ -1,7 +1,7 @@ - + @@ -29,17 +29,17 @@ - + - + - + - @@ -84,7 +84,7 @@ - + - + - +