Use loading screen whenever launch is slow.

Previously we had to manually account for each version that had a DB
change.

// FREEBIE
This commit is contained in:
Michael Kirk 2018-04-23 09:30:37 -04:00
parent f2cc8cf9d2
commit f782ea97df
4 changed files with 119 additions and 79 deletions

View File

@ -307,6 +307,7 @@
45360B911F952AA900FA666C /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; };
4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4539B5851F79348F007141FF /* PushRegistrationManager.swift */; };
4542DF52208B82E9007B4E76 /* ThreadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadModel.swift */; };
4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */; };
45464DBC1DFA041F001D3FD6 /* DataChannelMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45464DBB1DFA041F001D3FD6 /* DataChannelMessage.swift */; };
454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 454A84032059C787008B8C75 /* MediaTileViewController.swift */; };
454A965A1FD6017E008D2A0E /* SignalAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D913491F62D4A500722898 /* SignalAttachment.swift */; };
@ -931,6 +932,7 @@
4539B5851F79348F007141FF /* PushRegistrationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushRegistrationManager.swift; sourceTree = "<group>"; };
453CC0361D08E1A60040EBA3 /* sn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sn; path = translations/sn.lproj/Localizable.strings; sourceTree = "<group>"; };
4542DF51208B82E9007B4E76 /* ThreadModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadModel.swift; sourceTree = "<group>"; };
4542DF53208D40AC007B4E76 /* LoadingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewController.swift; sourceTree = "<group>"; };
45464DBB1DFA041F001D3FD6 /* DataChannelMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataChannelMessage.swift; sourceTree = "<group>"; };
454A84032059C787008B8C75 /* MediaTileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaTileViewController.swift; sourceTree = "<group>"; };
454A965E1FD60EA2008D2A0E /* OWSFlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSFlatButton.swift; path = SignalMessaging/Views/OWSFlatButton.swift; sourceTree = SOURCE_ROOT; };
@ -1655,6 +1657,7 @@
34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */,
340FC897204DAC8D007AEB0F /* ThreadSettings */,
34D1F0BE1F8EC1760066283D /* Utils */,
4542DF53208D40AC007B4E76 /* LoadingViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
@ -3200,6 +3203,7 @@
452314A01F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift in Sources */,
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
45D2AC02204885170033C692 /* OWS2FAReminderViewController.swift in Sources */,
4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */,
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */,
34D1F0B71F87F8850066283D /* OWSGenericAttachmentView.m in Sources */,
34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */,

View File

@ -62,6 +62,8 @@ static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewContr
static NSString *const kURLSchemeSGNLKey = @"sgnl";
static NSString *const kURLHostVerifyPrefix = @"verify";
static NSTimeInterval launchStartedAt;
@interface AppDelegate ()
@property (nonatomic) BOOL hasInitialRootViewController;
@ -105,6 +107,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
// This should be the first thing we do.
SetCurrentAppContext([MainAppContext new]);
launchStartedAt = CACurrentMediaTime();
BOOL isLoggingEnabled;
#ifdef DEBUG
// Specified at Product -> Scheme -> Edit Scheme -> Test -> Arguments -> Environment to avoid things like
@ -177,8 +181,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
UIWindow *mainWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = mainWindow;
CurrentAppContext().mainWindow = mainWindow;
// Show the launch screen until the async database view registrations are complete.
mainWindow.rootViewController = [self loadingRootViewController];
// Show LoadingViewController until the async database view registrations are complete.
mainWindow.rootViewController = [LoadingViewController new];
[mainWindow makeKeyAndVisible];
// Accept push notification when app is not open
@ -311,11 +315,9 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Show the launch screen until the async database view registrations are complete.
//
// Note: we void using loadingRootViewController, since it will indirectly try to
// instantiate primary storage, which will fail.
self.window.rootViewController = [self loadingRootViewControllerWithShowUpgradeWarning:NO];
// Show the launch screen
self.window.rootViewController =
[[UIStoryboard storyboardWithName:@"Launch Screen" bundle:nil] instantiateInitialViewController];
[self.window makeKeyAndVisible];
@ -412,75 +414,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
DDLogInfo(@"iPhone Version: %@", platform);
}
- (UIViewController *)loadingRootViewController
{
NSString *lastLaunchedAppVersion = AppVersion.instance.lastAppVersion;
NSString *lastCompletedLaunchAppVersion = AppVersion.instance.lastCompletedLaunchAppVersion;
// Every time we change or add a database view to a large collection or
// add a database migration to a large collection, this can delay launch
// so we need to bump this constant.
//
// We added a database migration around all outgoing messages in v2.25.0.
NSString *kLastVersionWithDatabaseViewChange = @"2.25.0";
BOOL mayNeedUpgrade = ([TSAccountManager isRegistered] && lastLaunchedAppVersion
&& (!lastCompletedLaunchAppVersion ||
[VersionMigrations isVersion:lastCompletedLaunchAppVersion
lessThan:kLastVersionWithDatabaseViewChange]));
DDLogInfo(@"%@ mayNeedUpgrade: %d", self.logTag, mayNeedUpgrade);
return [self loadingRootViewControllerWithShowUpgradeWarning:mayNeedUpgrade];
}
- (UIViewController *)loadingRootViewControllerWithShowUpgradeWarning:(BOOL)showUpgradeWarning
{
UIViewController *viewController =
[[UIStoryboard storyboardWithName:@"Launch Screen" bundle:nil] instantiateInitialViewController];
if (!showUpgradeWarning) {
return viewController;
}
UIView *rootView = viewController.view;
UIImageView *iconView = nil;
for (UIView *subview in viewController.view.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
iconView = (UIImageView *)subview;
break;
}
}
if (!iconView) {
OWSFail(@"Database view registration overlay has unexpected contents.");
return viewController;
}
UILabel *bottomLabel = [UILabel new];
bottomLabel.text = NSLocalizedString(
@"DATABASE_VIEW_OVERLAY_SUBTITLE", @"Subtitle shown while the app is updating its database.");
bottomLabel.font = [UIFont ows_mediumFontWithSize:16.f];
bottomLabel.textColor = [UIColor whiteColor];
bottomLabel.numberOfLines = 0;
bottomLabel.lineBreakMode = NSLineBreakByWordWrapping;
bottomLabel.textAlignment = NSTextAlignmentCenter;
[rootView addSubview:bottomLabel];
UILabel *topLabel = [UILabel new];
topLabel.text
= NSLocalizedString(@"DATABASE_VIEW_OVERLAY_TITLE", @"Title shown while the app is updating its database.");
topLabel.font = [UIFont ows_mediumFontWithSize:20.f];
topLabel.textColor = [UIColor whiteColor];
topLabel.numberOfLines = 0;
topLabel.lineBreakMode = NSLineBreakByWordWrapping;
topLabel.textAlignment = NSTextAlignmentCenter;
[rootView addSubview:topLabel];
[bottomLabel autoPinWidthToSuperviewWithMargin:20.f];
[topLabel autoPinWidthToSuperviewWithMargin:20.f];
[bottomLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:topLabel withOffset:10.f];
[iconView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:bottomLabel withOffset:40.f];
return viewController;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
OWSAssertIsOnMainThread();
@ -1145,7 +1078,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[self enableBackgroundRefreshIfNecessary];
if ([TSAccountManager isRegistered]) {
DDLogInfo(@"localNumber: %@", [TSAccountManager localNumber]);
DDLogInfo(@"%@ localNumber: %@", [TSAccountManager localNumber], self.logTag);
[[OWSPrimaryStorage sharedManager].newDatabaseConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
@ -1177,7 +1110,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
}
self.hasInitialRootViewController = YES;
DDLogInfo(@"%@ Presenting initial root view controller", self.logTag);
NSTimeInterval startupDuration = CACurrentMediaTime() - launchStartedAt;
DDLogInfo(@"%@ Presenting app %.2f seconds after launch started.", self.logTag, startupDuration);
if ([TSAccountManager isRegistered]) {
HomeViewController *homeView = [HomeViewController new];

View File

@ -0,0 +1,102 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
import PromiseKit
// The initial presentation is intended to be indistinguishable from the Launch Screen.
// After a delay we present some "loading" UI so the user doesn't think the app is frozen.
@objc
public class LoadingViewController: UIViewController {
var logoView: UIImageView!
var topLabel: UILabel!
var bottomLabel: UILabel!
override public func loadView() {
self.view = UIView()
view.backgroundColor = UIColor.ows_materialBlue
self.logoView = UIImageView(image: #imageLiteral(resourceName: "logoSignal"))
view.addSubview(logoView)
logoView.autoCenterInSuperview()
logoView.autoPinToSquareAspectRatio()
logoView.autoMatch(.width, to: .width, of: view, withMultiplier: 1/3)
self.topLabel = buildLabel()
topLabel.alpha = 0
topLabel.font = UIFont.ows_dynamicTypeTitle2
topLabel.text = NSLocalizedString("DATABASE_VIEW_OVERLAY_TITLE", comment: "Title shown while the app is updating its database.")
self.bottomLabel = buildLabel()
bottomLabel.alpha = 0
bottomLabel.font = UIFont.ows_dynamicTypeBody
bottomLabel.text = NSLocalizedString("DATABASE_VIEW_OVERLAY_SUBTITLE", comment: "Subtitle shown while the app is updating its database.")
let labelStack = UIStackView(arrangedSubviews: [topLabel, bottomLabel])
labelStack.axis = .vertical
labelStack.alignment = .center
labelStack.spacing = 8
view.addSubview(labelStack)
labelStack.autoPinEdge(.top, to: .bottom, of: logoView, withOffset: 20)
labelStack.autoPinLeadingToSuperviewMargin()
labelStack.autoPinTrailingToSuperviewMargin()
labelStack.setCompressionResistanceHigh()
labelStack.setContentHuggingHigh()
}
var isShowingTopLabel = false
var isShowingBottomLabel = false
override public func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// We only show the "loading" UI if it's a slow launch. Otherwise this ViewController
// should be indistinguishable from the launch screen.
let kTopLabelThreshold: TimeInterval = 5
DispatchQueue.main.asyncAfter(deadline: .now() + kTopLabelThreshold) { [weak self] in
guard let strongSelf = self else {
return
}
guard !strongSelf.isShowingTopLabel else {
return
}
strongSelf.isShowingTopLabel = true
UIView.animate(withDuration: 0.1) {
strongSelf.topLabel.alpha = 1
}
UIView.animate(withDuration: 0.9, delay: 2, options: [.autoreverse, .repeat, .curveEaseInOut], animations: {
strongSelf.topLabel.alpha = 0.2
}, completion: nil)
}
let kBottomLabelThreshold: TimeInterval = 15
DispatchQueue.main.asyncAfter(deadline: .now() + kBottomLabelThreshold) { [weak self] in
guard let strongSelf = self else {
return
}
guard !strongSelf.isShowingBottomLabel else {
return
}
strongSelf.isShowingBottomLabel = true
UIView.animate(withDuration: 0.1) {
strongSelf.bottomLabel.alpha = 1
}
}
}
private func buildLabel() -> UILabel {
let label = UILabel()
label.textColor = .white
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}
}

View File

@ -506,7 +506,7 @@
"DATABASE_VIEW_OVERLAY_SUBTITLE" = "This can take a few minutes.";
/* Title shown while the app is updating its database. */
"DATABASE_VIEW_OVERLAY_TITLE" = "Updating Database";
"DATABASE_VIEW_OVERLAY_TITLE" = "Optimizing Database";
/* The current day. */
"DATE_TODAY" = "Today";