2
0

Ensure alerts are triggered on main thread.

This commit is contained in:
Maarten Billemont 2020-03-05 11:29:10 -05:00
parent 9c3e272849
commit ee16c4a66d
9 changed files with 148 additions and 135 deletions

View File

@ -161,13 +161,14 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
MPError( error, @"StoreKit request (%@) failed.", request ); MPError( error, @"StoreKit request (%@) failed.", request );
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
PearlMainQueue( ^{
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
strf( @"%@\n\n%@", error.localizedDescription, strf( @"%@\n\n%@", error.localizedDescription,
@"Ensure you are online and try logging out and back into iTunes from your device's Settings." ) @"Ensure you are online and try logging out and back into iTunes from your device's Settings." )
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]]; [controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil]; [self.navigationController presentViewController:controller animated:YES completion:nil];
#else } );
#endif #endif
} }

View File

@ -248,8 +248,7 @@
MPKey *recoverKey = newKey; MPKey *recoverKey = newKey;
#ifdef PEARL_UIKIT #ifdef PEARL_UIKIT
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:PearlString( @"Migrating %ld sites...", PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:strf( @"Migrating %ld sites...", (long)[user.sites count] )];
(long)[user.sites count] )];
#endif #endif
for (MPSiteEntity *site in user.sites) { for (MPSiteEntity *site in user.sites) {
@ -261,8 +260,9 @@
#ifdef PEARL_UIKIT #ifdef PEARL_UIKIT
masterPassword = PearlAwait( ^(void (^setResult)(id)) { masterPassword = PearlAwait( ^(void (^setResult)(id)) {
PearlMainQueue( ^{
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enter Old Master Password" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enter Old Master Password" message:
PearlString( @"Your old master password is required to migrate the stored password for %@", site.name ) strf( @"Your old master password is required to migrate the stored password for %@", site.name )
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[controller addTextFieldWithConfigurationHandler:nil]; [controller addTextFieldWithConfigurationHandler:nil];
[controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler: [controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler:
@ -275,6 +275,7 @@
}]]; }]];
[self.navigationController presentViewController:controller animated:YES completion:nil]; [self.navigationController presentViewController:controller animated:YES completion:nil];
} ); } );
} );
#endif #endif
if (!masterPassword) if (!masterPassword)
// Don't Migrate // Don't Migrate

View File

@ -548,11 +548,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
do { do {
if ([MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) { if ([MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSError *error = [self importSites:importData askImportPassword:importPassword askUserPassword:userPassword resultBlock( [self importSites:importData askImportPassword:importPassword askUserPassword:userPassword
saveInContext:context]; saveInContext:context] );
PearlMainQueue( ^{
resultBlock( error );
} );
}]) }])
break; break;
usleep( (useconds_t)(USEC_PER_SEC * 0.2) ); usleep( (useconds_t)(USEC_PER_SEC * 0.2) );

View File

@ -113,7 +113,7 @@
} }
if (cell == self.checkInconsistencies) if (cell == self.checkInconsistencies)
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *context) {
if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems) { if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems) {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"No Inconsistencies" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"No Inconsistencies" message:
@"No inconsistencies were detected in your sites." @"No inconsistencies were detected in your sites."
@ -215,7 +215,7 @@
- (IBAction)securityButton:(id)sender { - (IBAction)securityButton:(id)sender {
[[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender: [[self dismissPopup].navigationController performSegueWithIdentifier:@"web" sender:
[NSURL URLWithString:@"https://masterpassword.app/security.html"]]; [NSURL URLWithString:@"https://masterpassword.app/masterpassword-algorithm.pdf"]];
} }
- (IBAction)sourceButton:(id)sender { - (IBAction)sourceButton:(id)sender {

View File

@ -40,7 +40,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
NSMutableString *features = [NSMutableString string]; NSMutableString *features = [NSMutableString string];
NSArray *storeVersions = @[ NSArray *storeVersions = @[
@"Generated Usernames\nSecurity Question Answers", @"Generated Usernames\nSecurity Question Answers",
@"TouchID Support" @"Biometrics Support",
]; ];
NSInteger storeVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"storeVersion"]; NSInteger storeVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"storeVersion"];
for (; storeVersion < [storeVersions count]; ++storeVersion) for (; storeVersion < [storeVersions count]; ++storeVersion)

View File

@ -431,22 +431,22 @@ referenceSizeForFooterInSection:(NSInteger)section {
NSManagedObjectID *userID = user.permanentObjectID; NSManagedObjectID *userID = user.permanentObjectID;
UIAlertController *controller = [UIAlertController alertControllerWithTitle:user.name message:nil preferredStyle:UIAlertControllerStyleActionSheet]; UIAlertController *controller = [UIAlertController alertControllerWithTitle:user.name message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { [controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Deleting User" message: UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
@"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert]; @"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { [controller_ addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
[self deleteUser:userID]; [self deleteUser:userID];
}]]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; [controller_ addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:controller animated:YES completion:nil]; [self presentViewController:controller_ animated:YES completion:nil];
}]]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Reset Password" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [controller addAction:[UIAlertAction actionWithTitle:@"Reset Password" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Resetting User" message: UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Resetting User" message:
@"The user's master password will be reset." preferredStyle:UIAlertControllerStyleAlert]; @"The user's master password will be reset." preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Reset User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { [controller_ addAction:[UIAlertAction actionWithTitle:@"Reset User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
[self resetUser:userID avatar:avatarCell]; [self resetUser:userID avatar:avatarCell];
}]]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; [controller_ addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:controller animated:YES completion:nil]; [self presentViewController:controller_ animated:YES completion:nil];
}]]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:controller animated:YES completion:nil]; [self presentViewController:controller animated:YES completion:nil];

View File

@ -182,7 +182,8 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
@try { @try {
inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] ); inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] );
PearlAddNotificationObserver( MPFoundInconsistenciesNotification, nil, nil, ^(id self, NSNotification *note) { PearlAddNotificationObserver(
MPFoundInconsistenciesNotification, nil, [NSOperationQueue mainQueue], ^(id self, NSNotification *note) {
switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) { switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) {
case MPFixableResultNoProblems: case MPFixableResultNoProblems:
@ -244,22 +245,26 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
MPError( error, @"While reading imported sites from %@.", url ); MPError( error, @"While reading imported sites from %@.", url );
if (!importedSitesData) { if (!importedSitesData) {
PearlMainQueue( ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:
strf( @"Master Password couldn't read the import sites.\n\n%@", strf( @"Master Password couldn't read the import sites.\n\n%@",
(id)[error localizedDescription]?: error ) (id)[error localizedDescription]?: error )
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
} );
return; return;
} }
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding]; NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
if (!importedSitesString) { if (!importedSitesString) {
PearlMainQueue( ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:
@"Master Password couldn't understand the import file." @"Master Password couldn't understand the import file."
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
} );
return; return;
} }
@ -281,6 +286,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"]; PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
[self importSites:importData askImportPassword:^NSString *(NSString *userName) { [self importSites:importData askImportPassword:^NSString *(NSString *userName) {
return PearlAwait( ^(void (^setResult)(id)) { return PearlAwait( ^(void (^setResult)(id)) {
PearlMainQueue( ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Importing Sites For\n%@", userName ) message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Importing Sites For\n%@", userName ) message:
@"Enter the master password used to create this export file." @"Enter the master password used to create this export file."
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
@ -295,8 +301,10 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
}]]; }]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
} ); } );
} );
} askUserPassword:^NSString *(NSString *userName) { } askUserPassword:^NSString *(NSString *userName) {
return PearlAwait( (id)^(void (^setResult)(id)) { return PearlAwait( (id)^(void (^setResult)(id)) {
PearlMainQueue( ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message:
@"Enter the current master password for this user." @"Enter the current master password for this user."
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
@ -311,14 +319,17 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
}]]; }]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
} ); } );
} );
} result:^(NSError *error) { } result:^(NSError *error) {
[activityOverlay cancelOverlayAnimated:YES]; [activityOverlay cancelOverlayAnimated:YES];
if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) { if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) {
PearlMainQueue( ^{
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription] UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription]
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]]; [controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil]; [self.navigationController presentViewController:controller animated:YES completion:nil];
} );
} }
}]; }];
} }
@ -341,6 +352,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
NSString *importData = [UIPasteboard generalPasteboard].string; NSString *importData = [UIPasteboard generalPasteboard].string;
MPMarshalledFile *importFile = mpw_marshal_read( NULL, importData.UTF8String ); MPMarshalledFile *importFile = mpw_marshal_read( NULL, importData.UTF8String );
if (importFile && importFile->error.type == MPMarshalSuccess && importFile->info->format != MPMarshalFormatNone) { if (importFile && importFile->error.type == MPMarshalSuccess && importFile->info->format != MPMarshalFormatNone) {
PearlMainQueue( ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Import Sites?" message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Import Sites?" message:
@"We've detected Master Password import sites on your pasteboard, would you like to import them?" @"We've detected Master Password import sites on your pasteboard, would you like to import them?"
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
@ -351,6 +363,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
}]]; }]];
[alert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
} );
} }
mpw_marshal_file_free( &importFile ); mpw_marshal_file_free( &importFile );
} ); } );
@ -422,7 +435,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Feedback" message:
@"Have a question, comment, issue or just saying thanks?\n\n" @"Have a question, comment, issue or just saying thanks?\n\n"
@"We'd love to hear what you think!\n" @"We'd love to hear what you think!\n"
@"masterpassword@lyndir.com" @"help@masterpassword.app"
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
@ -452,7 +465,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
if (logs && ([[MPConfig get].sendInfo boolValue] || [[MPiOSConfig get].traceMode boolValue])) if (logs && ([[MPConfig get].sendInfo boolValue] || [[MPiOSConfig get].traceMode boolValue]))
logLevel = PearlLogLevelDebug; logLevel = PearlLogLevelDebug;
[[[PearlEMail alloc] initForEMailTo:@"Master Password Development <masterpassword@lyndir.com>" [[[PearlEMail alloc] initForEMailTo:@"Master Password Development <help@masterpassword.app"
subject:strf( @"Feedback for Master Password [%@]", subject:strf( @"Feedback for Master Password [%@]",
[[PearlKeyChain deviceIdentifier] stringByDeletingMatchesOf:@"-.*"] ) [[PearlKeyChain deviceIdentifier] stringByDeletingMatchesOf:@"-.*"] )
body:strf( @"\n\n\n" body:strf( @"\n\n\n"
@ -479,12 +492,14 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
static dispatch_once_t once = 0; static dispatch_once_t once = 0;
dispatch_once( &once, ^{ dispatch_once( &once, ^{
PearlMainQueue( ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Failed To Load Sites" message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Failed To Load Sites" message:
@"Master Password was unable to open your sites history.\n" @"Master Password was unable to open your sites history.\n"
@"This may be due to corruption. You can either reset Master Password and " @"This may be due to corruption. You can either reset Master Password and "
@"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now." @"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now."
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [alert addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self openFeedbackWithLogs:YES forVC:nil]; [self openFeedbackWithLogs:YES forVC:nil];
}]]; }]];
[alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
@ -493,6 +508,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
[alert addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
} ); } );
} );
} }
- (void)showExportForVC:(UIViewController *)viewController { - (void)showExportForVC:(UIViewController *)viewController {
@ -620,6 +636,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset { - (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
PearlMainQueue( ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Changing Master Password" message: UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Changing Master Password" message:
@"If you continue, you'll be able to set a new master password.\n\n" @"If you continue, you'll be able to set a new master password.\n\n"
@"Changing your master password will cause all your generated passwords to change!\n" @"Changing your master password will cause all your generated passwords to change!\n"
@ -639,6 +656,7 @@ void mpw_log_sink_pearl(const MPLogEvent *record) {
}]]; }]];
[alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:alert animated:YES completion:nil]; [self.navigationController presentViewController:alert animated:YES completion:nil];
} );
} }
#pragma mark - UIDocumentInteractionControllerDelegate #pragma mark - UIDocumentInteractionControllerDelegate

View File

@ -37,10 +37,6 @@
<string>[auto]</string> <string>[auto]</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>[auto]</string> <string>[auto]</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>volto</string>
</array>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>

View File

@ -69,7 +69,7 @@
</collectionViewFlowLayout> </collectionViewFlowLayout>
<cells> <cells>
<collectionViewCell opaque="NO" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarCell" id="Zab-uQ-uk9" customClass="MPAvatarCell"> <collectionViewCell opaque="NO" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MPAvatarCell" id="Zab-uQ-uk9" customClass="MPAvatarCell">
<rect key="frame" x="80" y="114.5" width="215" height="667"/> <rect key="frame" x="80" y="115" width="215" height="667"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="215" height="667"/> <rect key="frame" x="0.0" y="0.0" width="215" height="667"/>
@ -898,15 +898,15 @@
<action selector="valueChanged:" destination="JFc-sj-awD" eventType="valueChanged" id="KmT-CO-GZh"/> <action selector="valueChanged:" destination="JFc-sj-awD" eventType="valueChanged" id="KmT-CO-GZh"/>
</connections> </connections>
</switch> </switch>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="TouchID" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xf-vt-aXd"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Biometrics" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xf-vt-aXd">
<rect key="frame" x="20" y="20" width="374" height="20"/> <rect key="frame" x="20" y="20" width="374" height="21"/>
<fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/> <fontDescription key="fontDescription" name="Exo2.0-Bold" family="Exo 2.0" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URR-yZ-QuC"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="URR-yZ-QuC">
<rect key="frame" x="20" y="48" width="374" height="143"/> <rect key="frame" x="20" y="49" width="374" height="142"/>
<string key="text">When enabled on a TouchID-enabled device, your fingerprint will be required to load your saved password. Note that this feature requires that the Save Password option is enabled and TouchID support has been purchased from the in-app store.</string> <string key="text">When enabled on a biometrics-enabled device, your fingerprint or face scan will be required to load your saved password. Note that this feature requires that the Save Password option is enabled and Biometrics support has been purchased from the in-app store.</string>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/> <fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="12"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@ -1030,7 +1030,7 @@
<rect key="frame" x="0.0" y="0.0" width="414" height="250"/> <rect key="frame" x="0.0" y="0.0" width="414" height="250"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="999" verticalCompressionResistancePriority="1000" text="© 2011-2017, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sPw-mV-mFF"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="999" verticalCompressionResistancePriority="1000" text="© 2011-2020, Maarten Billemont (lhunath)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sPw-mV-mFF">
<rect key="frame" x="20" y="4" width="374" height="106"/> <rect key="frame" x="20" y="4" width="374" height="106"/>
<fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/> <fontDescription key="fontDescription" name="Exo2.0-Regular" family="Exo 2.0" pointSize="11"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>