Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07e55140ac | ||
|
|
fbbd08790d | ||
|
|
fcaa5d1d8c | ||
|
|
ea5be8efcb | ||
|
|
c8b4933c3d | ||
|
|
981ee171ae | ||
|
|
3ed6b93736 | ||
|
|
56a515c5ea | ||
|
|
15ac7a2dbf | ||
|
|
c5c7999753 | ||
|
|
bb58ed0169 | ||
|
|
4545a5c745 | ||
|
|
da8c7064fe | ||
|
|
d9bd604436 |
2
platform-darwin/External/InAppSettingsKit
vendored
2
platform-darwin/External/InAppSettingsKit
vendored
Submodule platform-darwin/External/InAppSettingsKit updated: b58b72563a...2dcb598d18
2
platform-darwin/External/Pearl
vendored
2
platform-darwin/External/Pearl
vendored
Submodule platform-darwin/External/Pearl updated: 8853d299b2...284cd041f8
@@ -19,7 +19,9 @@
|
||||
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */; };
|
||||
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; };
|
||||
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3957D76F71A652716EECC /* MPStoreViewController.m */; };
|
||||
93D393AA69A1193401160418 /* UIView+AlphaScale.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39488AB33616661725929 /* UIView+AlphaScale.m */; };
|
||||
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */; };
|
||||
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */; };
|
||||
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */; };
|
||||
93D394B5036C882B33C71872 /* MPPasswordsSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E7A12CC352B2825AA66 /* MPPasswordsSegue.m */; };
|
||||
93D39508A6814612A5B3C226 /* MPMessageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399B36CDB2004D7C51391 /* MPMessageViewController.m */; };
|
||||
@@ -28,6 +30,7 @@
|
||||
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; };
|
||||
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.m */; };
|
||||
93D39577FD8BB0945DB2F0A3 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */; };
|
||||
93D3959696396A91961C6148 /* UIView+AlphaScale.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */; };
|
||||
93D395B715D15F2B56F2A2EE /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D392C5A6572DB0EB5B82C8 /* mpw-types.c */; };
|
||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
||||
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */; };
|
||||
@@ -44,7 +47,7 @@
|
||||
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D395105935859D71679931 /* MPOverlayViewController.m */; };
|
||||
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */; };
|
||||
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399A8E3181B442D347CD7 /* MPAlgorithmV2.m */; };
|
||||
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadFromArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */; };
|
||||
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadItems.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadItems.h */; };
|
||||
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; };
|
||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; };
|
||||
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */; };
|
||||
@@ -53,8 +56,9 @@
|
||||
93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */; };
|
||||
93D39B8F90F58A5D158DDBA3 /* MPPasswordsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */; };
|
||||
93D39BA1EA3CAAC8A220B4A6 /* MPAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */; };
|
||||
93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B7B765546B1F1900CB7 /* UIView+Visible.h */; };
|
||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
||||
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadFromArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadFromArray.m */; };
|
||||
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadItems.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadItems.m */; };
|
||||
93D39D596A2E376D6F6F5DA1 /* MPCombinedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D393310223DDB35218467A /* MPCombinedViewController.m */; };
|
||||
93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39CC01630D0421205C4C4 /* MPNavigationController.m */; };
|
||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
||||
@@ -67,6 +71,22 @@
|
||||
DA071BF4190187FE00179766 /* empty.png in Resources */ = {isa = PBXBuildFile; fileRef = DA071BF2190187FE00179766 /* empty.png */; };
|
||||
DA095E75172F4CD8001C948B /* MPLogsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */; };
|
||||
DA0979171E9A81EE00F0BFE8 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979161E9A81EE00F0BFE8 /* libsodium.a */; };
|
||||
DA0CC5291EAB99BA009A8ED9 /* IASKAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5071EAB99BA009A8ED9 /* IASKAppSettingsViewController.m */; };
|
||||
DA0CC52A1EAB99BA009A8ED9 /* IASKAppSettingsWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5091EAB99BA009A8ED9 /* IASKAppSettingsWebViewController.m */; };
|
||||
DA0CC52B1EAB99BA009A8ED9 /* IASKMultipleValueSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC50B1EAB99BA009A8ED9 /* IASKMultipleValueSelection.m */; };
|
||||
DA0CC52C1EAB99BA009A8ED9 /* IASKSpecifierValuesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC50D1EAB99BA009A8ED9 /* IASKSpecifierValuesViewController.m */; };
|
||||
DA0CC52D1EAB99BA009A8ED9 /* IASKSettingsReader.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5111EAB99BA009A8ED9 /* IASKSettingsReader.m */; };
|
||||
DA0CC52E1EAB99BA009A8ED9 /* IASKSettingsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5131EAB99BA009A8ED9 /* IASKSettingsStore.m */; };
|
||||
DA0CC52F1EAB99BA009A8ED9 /* IASKSettingsStoreFile.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5151EAB99BA009A8ED9 /* IASKSettingsStoreFile.m */; };
|
||||
DA0CC5301EAB99BA009A8ED9 /* IASKSettingsStoreUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5171EAB99BA009A8ED9 /* IASKSettingsStoreUserDefaults.m */; };
|
||||
DA0CC5311EAB99BA009A8ED9 /* IASKSpecifier.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5191EAB99BA009A8ED9 /* IASKSpecifier.m */; };
|
||||
DA0CC5321EAB99BA009A8ED9 /* IASKPSSliderSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC51C1EAB99BA009A8ED9 /* IASKPSSliderSpecifierViewCell.m */; };
|
||||
DA0CC5331EAB99BA009A8ED9 /* IASKPSTextFieldSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC51E1EAB99BA009A8ED9 /* IASKPSTextFieldSpecifierViewCell.m */; };
|
||||
DA0CC5341EAB99BA009A8ED9 /* IASKSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5201EAB99BA009A8ED9 /* IASKSlider.m */; };
|
||||
DA0CC5351EAB99BA009A8ED9 /* IASKSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5221EAB99BA009A8ED9 /* IASKSwitch.m */; };
|
||||
DA0CC5361EAB99BA009A8ED9 /* IASKTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5241EAB99BA009A8ED9 /* IASKTextField.m */; };
|
||||
DA0CC5371EAB99BA009A8ED9 /* IASKTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5261EAB99BA009A8ED9 /* IASKTextView.m */; };
|
||||
DA0CC5381EAB99BA009A8ED9 /* IASKTextViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC5281EAB99BA009A8ED9 /* IASKTextViewCell.m */; };
|
||||
DA24EBAE19DAD08900FF010B /* tip_basic_black_top.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38941711E29700CF925C /* tip_basic_black_top.png */; };
|
||||
DA24EBAF19DAD08C00FF010B /* tip_basic_black_top@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38951711E29700CF925C /* tip_basic_black_top@2x.png */; };
|
||||
DA24EBE819DAD6DE00FF010B /* Icon-320.png in Resources */ = {isa = PBXBuildFile; fileRef = DA24EBE619DAD6DE00FF010B /* Icon-320.png */; };
|
||||
@@ -344,20 +364,6 @@
|
||||
DAF4EF50190A81E400023C90 /* NSManagedObject+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */; };
|
||||
DAF4EF51190A81E400023C90 /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */; };
|
||||
DAFC5656172C573B00CB5CC5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
DAFC5683172C57EC00CB5CC5 /* IASKAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5665172C57EC00CB5CC5 /* IASKAppSettingsViewController.m */; };
|
||||
DAFC5684172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5667172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.m */; };
|
||||
DAFC5685172C57EC00CB5CC5 /* IASKSpecifierValuesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5669172C57EC00CB5CC5 /* IASKSpecifierValuesViewController.m */; };
|
||||
DAFC5686172C57EC00CB5CC5 /* IASKSettingsReader.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC566D172C57EC00CB5CC5 /* IASKSettingsReader.m */; };
|
||||
DAFC5687172C57EC00CB5CC5 /* IASKSettingsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC566F172C57EC00CB5CC5 /* IASKSettingsStore.m */; };
|
||||
DAFC5688172C57EC00CB5CC5 /* IASKSettingsStoreFile.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5671172C57EC00CB5CC5 /* IASKSettingsStoreFile.m */; };
|
||||
DAFC5689172C57EC00CB5CC5 /* IASKSettingsStoreUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5673172C57EC00CB5CC5 /* IASKSettingsStoreUserDefaults.m */; };
|
||||
DAFC568A172C57EC00CB5CC5 /* IASKSpecifier.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5675172C57EC00CB5CC5 /* IASKSpecifier.m */; };
|
||||
DAFC568B172C57EC00CB5CC5 /* IASKPSSliderSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5678172C57EC00CB5CC5 /* IASKPSSliderSpecifierViewCell.m */; };
|
||||
DAFC568C172C57EC00CB5CC5 /* IASKPSTextFieldSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC567A172C57EC00CB5CC5 /* IASKPSTextFieldSpecifierViewCell.m */; };
|
||||
DAFC568D172C57EC00CB5CC5 /* IASKPSTitleValueSpecifierViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC567C172C57EC00CB5CC5 /* IASKPSTitleValueSpecifierViewCell.m */; };
|
||||
DAFC568E172C57EC00CB5CC5 /* IASKSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC567E172C57EC00CB5CC5 /* IASKSlider.m */; };
|
||||
DAFC568F172C57EC00CB5CC5 /* IASKSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5680172C57EC00CB5CC5 /* IASKSwitch.m */; };
|
||||
DAFC5690172C57EC00CB5CC5 /* IASKTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFC5682172C57EC00CB5CC5 /* IASKTextField.m */; };
|
||||
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */; };
|
||||
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */; };
|
||||
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */; };
|
||||
@@ -460,7 +466,7 @@
|
||||
/* Begin PBXFileReference section */
|
||||
93D390519405B76CC6A57C4F /* MPCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPCell.h; sourceTree = "<group>"; };
|
||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
|
||||
93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadFromArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionView+PearlReloadFromArray.m"; sourceTree = "<group>"; };
|
||||
93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionView+PearlReloadItems.m"; sourceTree = "<group>"; };
|
||||
93D390A3B351FEF1B9EDAB56 /* mpw-algorithm_v2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v2.c"; sourceTree = "<group>"; };
|
||||
93D390A99850139D0FF0211E /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = "<group>"; };
|
||||
93D390FADEB325D8D54A957D /* PearlOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlOverlay.m; sourceTree = "<group>"; };
|
||||
@@ -471,11 +477,12 @@
|
||||
93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppSettingsViewController.m; sourceTree = "<group>"; };
|
||||
93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.h; sourceTree = "<group>"; };
|
||||
93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
|
||||
93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionView+PearlReloadFromArray.h"; sourceTree = "<group>"; };
|
||||
93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadItems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionView+PearlReloadItems.h"; sourceTree = "<group>"; };
|
||||
93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootSegue.h; sourceTree = "<group>"; };
|
||||
93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsViewController.m; sourceTree = "<group>"; };
|
||||
93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = "<group>"; };
|
||||
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; };
|
||||
93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+AlphaScale.h"; sourceTree = "<group>"; };
|
||||
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
|
||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
||||
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
|
||||
@@ -483,8 +490,10 @@
|
||||
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
|
||||
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
|
||||
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = "<group>"; };
|
||||
93D39488AB33616661725929 /* UIView+AlphaScale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+AlphaScale.m"; sourceTree = "<group>"; };
|
||||
93D394D73F5BC92297CE8D7B /* MPAlgorithmV3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV3.h; sourceTree = "<group>"; };
|
||||
93D395105935859D71679931 /* MPOverlayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOverlayViewController.m; sourceTree = "<group>"; };
|
||||
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Visible.m"; sourceTree = "<group>"; };
|
||||
93D3956915634581E737B38C /* PearlNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlNavigationController.m; sourceTree = "<group>"; };
|
||||
93D3957D76F71A652716EECC /* MPStoreViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPStoreViewController.m; sourceTree = "<group>"; };
|
||||
93D3969393A3A46BD27D7078 /* mpw-algorithm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm.c"; sourceTree = "<group>"; };
|
||||
@@ -524,6 +533,7 @@
|
||||
93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUICollectionView.h; sourceTree = "<group>"; };
|
||||
93D39B381350802A194BF332 /* MPAvatarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAvatarCell.m; sourceTree = "<group>"; };
|
||||
93D39B455A71EC98C749E623 /* MPOverlayViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOverlayViewController.h; sourceTree = "<group>"; };
|
||||
93D39B7B765546B1F1900CB7 /* UIView+Visible.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Visible.h"; sourceTree = "<group>"; };
|
||||
93D39BAA71DE51B4D8A1286C /* MPCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCell.m; sourceTree = "<group>"; };
|
||||
93D39C41A27AA42D044D68AE /* NSString+MPMarkDown.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+MPMarkDown.m"; path = "iOS/NSString+MPMarkDown.m"; sourceTree = "<group>"; };
|
||||
93D39C426E03358384018E85 /* MPAnswersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAnswersViewController.m; sourceTree = "<group>"; };
|
||||
@@ -609,6 +619,54 @@
|
||||
DA0979131E9A81EE00F0BFE8 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
|
||||
DA0979141E9A81EE00F0BFE8 /* sodium.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sodium.h; sourceTree = "<group>"; };
|
||||
DA0979161E9A81EE00F0BFE8 /* libsodium.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsodium.a; sourceTree = "<group>"; };
|
||||
DA0CC4F61EAB99BA009A8ED9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4F71EAB99BA009A8ED9 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4F81EAB99BA009A8ED9 /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4F91EAB99BA009A8ED9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4FA1EAB99BA009A8ED9 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4FB1EAB99BA009A8ED9 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4FC1EAB99BA009A8ED9 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4FD1EAB99BA009A8ED9 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4FE1EAB99BA009A8ED9 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC4FF1EAB99BA009A8ED9 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/IASKLocalizable.strings"; sourceTree = "<group>"; };
|
||||
DA0CC5001EAB99BA009A8ED9 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC5011EAB99BA009A8ED9 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC5021EAB99BA009A8ED9 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC5031EAB99BA009A8ED9 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC5041EAB99BA009A8ED9 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/IASKLocalizable.strings; sourceTree = "<group>"; };
|
||||
DA0CC5061EAB99BA009A8ED9 /* IASKAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKAppSettingsViewController.h; sourceTree = "<group>"; };
|
||||
DA0CC5071EAB99BA009A8ED9 /* IASKAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKAppSettingsViewController.m; sourceTree = "<group>"; };
|
||||
DA0CC5081EAB99BA009A8ED9 /* IASKAppSettingsWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKAppSettingsWebViewController.h; sourceTree = "<group>"; };
|
||||
DA0CC5091EAB99BA009A8ED9 /* IASKAppSettingsWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKAppSettingsWebViewController.m; sourceTree = "<group>"; };
|
||||
DA0CC50A1EAB99BA009A8ED9 /* IASKMultipleValueSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKMultipleValueSelection.h; sourceTree = "<group>"; };
|
||||
DA0CC50B1EAB99BA009A8ED9 /* IASKMultipleValueSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKMultipleValueSelection.m; sourceTree = "<group>"; };
|
||||
DA0CC50C1EAB99BA009A8ED9 /* IASKSpecifierValuesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSpecifierValuesViewController.h; sourceTree = "<group>"; };
|
||||
DA0CC50D1EAB99BA009A8ED9 /* IASKSpecifierValuesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSpecifierValuesViewController.m; sourceTree = "<group>"; };
|
||||
DA0CC50E1EAB99BA009A8ED9 /* IASKViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKViewController.h; sourceTree = "<group>"; };
|
||||
DA0CC5101EAB99BA009A8ED9 /* IASKSettingsReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsReader.h; sourceTree = "<group>"; };
|
||||
DA0CC5111EAB99BA009A8ED9 /* IASKSettingsReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsReader.m; sourceTree = "<group>"; };
|
||||
DA0CC5121EAB99BA009A8ED9 /* IASKSettingsStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsStore.h; sourceTree = "<group>"; };
|
||||
DA0CC5131EAB99BA009A8ED9 /* IASKSettingsStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsStore.m; sourceTree = "<group>"; };
|
||||
DA0CC5141EAB99BA009A8ED9 /* IASKSettingsStoreFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsStoreFile.h; sourceTree = "<group>"; };
|
||||
DA0CC5151EAB99BA009A8ED9 /* IASKSettingsStoreFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsStoreFile.m; sourceTree = "<group>"; };
|
||||
DA0CC5161EAB99BA009A8ED9 /* IASKSettingsStoreUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsStoreUserDefaults.h; sourceTree = "<group>"; };
|
||||
DA0CC5171EAB99BA009A8ED9 /* IASKSettingsStoreUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsStoreUserDefaults.m; sourceTree = "<group>"; };
|
||||
DA0CC5181EAB99BA009A8ED9 /* IASKSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSpecifier.h; sourceTree = "<group>"; };
|
||||
DA0CC5191EAB99BA009A8ED9 /* IASKSpecifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSpecifier.m; sourceTree = "<group>"; };
|
||||
DA0CC51B1EAB99BA009A8ED9 /* IASKPSSliderSpecifierViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKPSSliderSpecifierViewCell.h; sourceTree = "<group>"; };
|
||||
DA0CC51C1EAB99BA009A8ED9 /* IASKPSSliderSpecifierViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKPSSliderSpecifierViewCell.m; sourceTree = "<group>"; };
|
||||
DA0CC51D1EAB99BA009A8ED9 /* IASKPSTextFieldSpecifierViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKPSTextFieldSpecifierViewCell.h; sourceTree = "<group>"; };
|
||||
DA0CC51E1EAB99BA009A8ED9 /* IASKPSTextFieldSpecifierViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKPSTextFieldSpecifierViewCell.m; sourceTree = "<group>"; };
|
||||
DA0CC51F1EAB99BA009A8ED9 /* IASKSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSlider.h; sourceTree = "<group>"; };
|
||||
DA0CC5201EAB99BA009A8ED9 /* IASKSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSlider.m; sourceTree = "<group>"; };
|
||||
DA0CC5211EAB99BA009A8ED9 /* IASKSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSwitch.h; sourceTree = "<group>"; };
|
||||
DA0CC5221EAB99BA009A8ED9 /* IASKSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSwitch.m; sourceTree = "<group>"; };
|
||||
DA0CC5231EAB99BA009A8ED9 /* IASKTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKTextField.h; sourceTree = "<group>"; };
|
||||
DA0CC5241EAB99BA009A8ED9 /* IASKTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextField.m; sourceTree = "<group>"; };
|
||||
DA0CC5251EAB99BA009A8ED9 /* IASKTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKTextView.h; sourceTree = "<group>"; };
|
||||
DA0CC5261EAB99BA009A8ED9 /* IASKTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextView.m; sourceTree = "<group>"; };
|
||||
DA0CC5271EAB99BA009A8ED9 /* IASKTextViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKTextViewCell.h; sourceTree = "<group>"; };
|
||||
DA0CC5281EAB99BA009A8ED9 /* IASKTextViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextViewCell.m; sourceTree = "<group>"; };
|
||||
DA24EBB219DAD4D000FF010B /* Icon-60.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60.png"; sourceTree = "<group>"; };
|
||||
DA24EBB319DAD4D000FF010B /* Icon-60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@2x.png"; sourceTree = "<group>"; };
|
||||
DA24EBB419DAD4D000FF010B /* Icon-60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-60@3x.png"; sourceTree = "<group>"; };
|
||||
@@ -1468,35 +1526,6 @@
|
||||
DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObject+Pearl.m"; sourceTree = "<group>"; };
|
||||
DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSManagedObject+Pearl.h"; sourceTree = "<group>"; };
|
||||
DAFC5655172C573B00CB5CC5 /* libInAppSettingsKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInAppSettingsKit.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DAFC5664172C57EC00CB5CC5 /* IASKAppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKAppSettingsViewController.h; sourceTree = "<group>"; };
|
||||
DAFC5665172C57EC00CB5CC5 /* IASKAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKAppSettingsViewController.m; sourceTree = "<group>"; };
|
||||
DAFC5666172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKAppSettingsWebViewController.h; sourceTree = "<group>"; };
|
||||
DAFC5667172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKAppSettingsWebViewController.m; sourceTree = "<group>"; };
|
||||
DAFC5668172C57EC00CB5CC5 /* IASKSpecifierValuesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSpecifierValuesViewController.h; sourceTree = "<group>"; };
|
||||
DAFC5669172C57EC00CB5CC5 /* IASKSpecifierValuesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSpecifierValuesViewController.m; sourceTree = "<group>"; };
|
||||
DAFC566A172C57EC00CB5CC5 /* IASKViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKViewController.h; sourceTree = "<group>"; };
|
||||
DAFC566C172C57EC00CB5CC5 /* IASKSettingsReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsReader.h; sourceTree = "<group>"; };
|
||||
DAFC566D172C57EC00CB5CC5 /* IASKSettingsReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsReader.m; sourceTree = "<group>"; };
|
||||
DAFC566E172C57EC00CB5CC5 /* IASKSettingsStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsStore.h; sourceTree = "<group>"; };
|
||||
DAFC566F172C57EC00CB5CC5 /* IASKSettingsStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsStore.m; sourceTree = "<group>"; };
|
||||
DAFC5670172C57EC00CB5CC5 /* IASKSettingsStoreFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsStoreFile.h; sourceTree = "<group>"; };
|
||||
DAFC5671172C57EC00CB5CC5 /* IASKSettingsStoreFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsStoreFile.m; sourceTree = "<group>"; };
|
||||
DAFC5672172C57EC00CB5CC5 /* IASKSettingsStoreUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSettingsStoreUserDefaults.h; sourceTree = "<group>"; };
|
||||
DAFC5673172C57EC00CB5CC5 /* IASKSettingsStoreUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSettingsStoreUserDefaults.m; sourceTree = "<group>"; };
|
||||
DAFC5674172C57EC00CB5CC5 /* IASKSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSpecifier.h; sourceTree = "<group>"; };
|
||||
DAFC5675172C57EC00CB5CC5 /* IASKSpecifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSpecifier.m; sourceTree = "<group>"; };
|
||||
DAFC5677172C57EC00CB5CC5 /* IASKPSSliderSpecifierViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKPSSliderSpecifierViewCell.h; sourceTree = "<group>"; };
|
||||
DAFC5678172C57EC00CB5CC5 /* IASKPSSliderSpecifierViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKPSSliderSpecifierViewCell.m; sourceTree = "<group>"; };
|
||||
DAFC5679172C57EC00CB5CC5 /* IASKPSTextFieldSpecifierViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKPSTextFieldSpecifierViewCell.h; sourceTree = "<group>"; };
|
||||
DAFC567A172C57EC00CB5CC5 /* IASKPSTextFieldSpecifierViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKPSTextFieldSpecifierViewCell.m; sourceTree = "<group>"; };
|
||||
DAFC567B172C57EC00CB5CC5 /* IASKPSTitleValueSpecifierViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKPSTitleValueSpecifierViewCell.h; sourceTree = "<group>"; };
|
||||
DAFC567C172C57EC00CB5CC5 /* IASKPSTitleValueSpecifierViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKPSTitleValueSpecifierViewCell.m; sourceTree = "<group>"; };
|
||||
DAFC567D172C57EC00CB5CC5 /* IASKSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSlider.h; sourceTree = "<group>"; };
|
||||
DAFC567E172C57EC00CB5CC5 /* IASKSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSlider.m; sourceTree = "<group>"; };
|
||||
DAFC567F172C57EC00CB5CC5 /* IASKSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKSwitch.h; sourceTree = "<group>"; };
|
||||
DAFC5680172C57EC00CB5CC5 /* IASKSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKSwitch.m; sourceTree = "<group>"; };
|
||||
DAFC5681172C57EC00CB5CC5 /* IASKTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IASKTextField.h; sourceTree = "<group>"; };
|
||||
DAFC5682172C57EC00CB5CC5 /* IASKTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IASKTextField.m; sourceTree = "<group>"; };
|
||||
DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+PearlExport.h"; sourceTree = "<group>"; };
|
||||
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+PearlExport.m"; sourceTree = "<group>"; };
|
||||
DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+PearlNSArrayFormat.h"; sourceTree = "<group>"; };
|
||||
@@ -1770,6 +1799,68 @@
|
||||
path = lib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA0CC4F41EAB99BA009A8ED9 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA0CC4F51EAB99BA009A8ED9 /* IASKLocalizable.strings */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA0CC5051EAB99BA009A8ED9 /* Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA0CC5061EAB99BA009A8ED9 /* IASKAppSettingsViewController.h */,
|
||||
DA0CC5071EAB99BA009A8ED9 /* IASKAppSettingsViewController.m */,
|
||||
DA0CC5081EAB99BA009A8ED9 /* IASKAppSettingsWebViewController.h */,
|
||||
DA0CC5091EAB99BA009A8ED9 /* IASKAppSettingsWebViewController.m */,
|
||||
DA0CC50A1EAB99BA009A8ED9 /* IASKMultipleValueSelection.h */,
|
||||
DA0CC50B1EAB99BA009A8ED9 /* IASKMultipleValueSelection.m */,
|
||||
DA0CC50C1EAB99BA009A8ED9 /* IASKSpecifierValuesViewController.h */,
|
||||
DA0CC50D1EAB99BA009A8ED9 /* IASKSpecifierValuesViewController.m */,
|
||||
DA0CC50E1EAB99BA009A8ED9 /* IASKViewController.h */,
|
||||
);
|
||||
path = Controllers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA0CC50F1EAB99BA009A8ED9 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA0CC5101EAB99BA009A8ED9 /* IASKSettingsReader.h */,
|
||||
DA0CC5111EAB99BA009A8ED9 /* IASKSettingsReader.m */,
|
||||
DA0CC5121EAB99BA009A8ED9 /* IASKSettingsStore.h */,
|
||||
DA0CC5131EAB99BA009A8ED9 /* IASKSettingsStore.m */,
|
||||
DA0CC5141EAB99BA009A8ED9 /* IASKSettingsStoreFile.h */,
|
||||
DA0CC5151EAB99BA009A8ED9 /* IASKSettingsStoreFile.m */,
|
||||
DA0CC5161EAB99BA009A8ED9 /* IASKSettingsStoreUserDefaults.h */,
|
||||
DA0CC5171EAB99BA009A8ED9 /* IASKSettingsStoreUserDefaults.m */,
|
||||
DA0CC5181EAB99BA009A8ED9 /* IASKSpecifier.h */,
|
||||
DA0CC5191EAB99BA009A8ED9 /* IASKSpecifier.m */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA0CC51A1EAB99BA009A8ED9 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA0CC51B1EAB99BA009A8ED9 /* IASKPSSliderSpecifierViewCell.h */,
|
||||
DA0CC51C1EAB99BA009A8ED9 /* IASKPSSliderSpecifierViewCell.m */,
|
||||
DA0CC51D1EAB99BA009A8ED9 /* IASKPSTextFieldSpecifierViewCell.h */,
|
||||
DA0CC51E1EAB99BA009A8ED9 /* IASKPSTextFieldSpecifierViewCell.m */,
|
||||
DA0CC51F1EAB99BA009A8ED9 /* IASKSlider.h */,
|
||||
DA0CC5201EAB99BA009A8ED9 /* IASKSlider.m */,
|
||||
DA0CC5211EAB99BA009A8ED9 /* IASKSwitch.h */,
|
||||
DA0CC5221EAB99BA009A8ED9 /* IASKSwitch.m */,
|
||||
DA0CC5231EAB99BA009A8ED9 /* IASKTextField.h */,
|
||||
DA0CC5241EAB99BA009A8ED9 /* IASKTextField.m */,
|
||||
DA0CC5251EAB99BA009A8ED9 /* IASKTextView.h */,
|
||||
DA0CC5261EAB99BA009A8ED9 /* IASKTextView.m */,
|
||||
DA0CC5271EAB99BA009A8ED9 /* IASKTextViewCell.h */,
|
||||
DA0CC5281EAB99BA009A8ED9 /* IASKTextViewCell.m */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA24EBB019DAD4D000FF010B /* ios */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2865,64 +2956,15 @@
|
||||
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAFC5663172C57EC00CB5CC5 /* Controllers */,
|
||||
DAFC566B172C57EC00CB5CC5 /* Models */,
|
||||
DAFC5676172C57EC00CB5CC5 /* Views */,
|
||||
DA0CC4F41EAB99BA009A8ED9 /* Resources */,
|
||||
DA0CC5051EAB99BA009A8ED9 /* Controllers */,
|
||||
DA0CC50F1EAB99BA009A8ED9 /* Models */,
|
||||
DA0CC51A1EAB99BA009A8ED9 /* Views */,
|
||||
);
|
||||
name = InAppSettingsKit;
|
||||
path = InAppSettingsKit/InAppSettingsKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DAFC5663172C57EC00CB5CC5 /* Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAFC5664172C57EC00CB5CC5 /* IASKAppSettingsViewController.h */,
|
||||
DAFC5665172C57EC00CB5CC5 /* IASKAppSettingsViewController.m */,
|
||||
DAFC5666172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.h */,
|
||||
DAFC5667172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.m */,
|
||||
DAFC5668172C57EC00CB5CC5 /* IASKSpecifierValuesViewController.h */,
|
||||
DAFC5669172C57EC00CB5CC5 /* IASKSpecifierValuesViewController.m */,
|
||||
DAFC566A172C57EC00CB5CC5 /* IASKViewController.h */,
|
||||
);
|
||||
path = Controllers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DAFC566B172C57EC00CB5CC5 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAFC566C172C57EC00CB5CC5 /* IASKSettingsReader.h */,
|
||||
DAFC566D172C57EC00CB5CC5 /* IASKSettingsReader.m */,
|
||||
DAFC566E172C57EC00CB5CC5 /* IASKSettingsStore.h */,
|
||||
DAFC566F172C57EC00CB5CC5 /* IASKSettingsStore.m */,
|
||||
DAFC5670172C57EC00CB5CC5 /* IASKSettingsStoreFile.h */,
|
||||
DAFC5671172C57EC00CB5CC5 /* IASKSettingsStoreFile.m */,
|
||||
DAFC5672172C57EC00CB5CC5 /* IASKSettingsStoreUserDefaults.h */,
|
||||
DAFC5673172C57EC00CB5CC5 /* IASKSettingsStoreUserDefaults.m */,
|
||||
DAFC5674172C57EC00CB5CC5 /* IASKSpecifier.h */,
|
||||
DAFC5675172C57EC00CB5CC5 /* IASKSpecifier.m */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DAFC5676172C57EC00CB5CC5 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAFC5677172C57EC00CB5CC5 /* IASKPSSliderSpecifierViewCell.h */,
|
||||
DAFC5678172C57EC00CB5CC5 /* IASKPSSliderSpecifierViewCell.m */,
|
||||
DAFC5679172C57EC00CB5CC5 /* IASKPSTextFieldSpecifierViewCell.h */,
|
||||
DAFC567A172C57EC00CB5CC5 /* IASKPSTextFieldSpecifierViewCell.m */,
|
||||
DAFC567B172C57EC00CB5CC5 /* IASKPSTitleValueSpecifierViewCell.h */,
|
||||
DAFC567C172C57EC00CB5CC5 /* IASKPSTitleValueSpecifierViewCell.m */,
|
||||
DAFC567D172C57EC00CB5CC5 /* IASKSlider.h */,
|
||||
DAFC567E172C57EC00CB5CC5 /* IASKSlider.m */,
|
||||
DAFC567F172C57EC00CB5CC5 /* IASKSwitch.h */,
|
||||
DAFC5680172C57EC00CB5CC5 /* IASKSwitch.m */,
|
||||
DAFC5681172C57EC00CB5CC5 /* IASKTextField.h */,
|
||||
DAFC5682172C57EC00CB5CC5 /* IASKTextField.m */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DAFE45D715039823003ABA7C /* Pearl */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -3072,8 +3114,8 @@
|
||||
DAFE462515039823003ABA7C /* Resources */,
|
||||
DA250A16195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h */,
|
||||
DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */,
|
||||
93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */,
|
||||
93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadFromArray.m */,
|
||||
93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadItems.h */,
|
||||
93D3908DF8EABBD952065DC0 /* UICollectionView+PearlReloadItems.m */,
|
||||
DAFE4A63150399FF003ABA83 /* UIControl+PearlBlocks.h */,
|
||||
DAFE4A63150399FF003ABA81 /* UIControl+PearlBlocks.m */,
|
||||
DAFE4A63150399FF003ABA8B /* UIControl+PearlSelect.h */,
|
||||
@@ -3098,6 +3140,10 @@
|
||||
DAEFB01C19BCBD9E00525079 /* UIView+LayoutGone.m */,
|
||||
DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */,
|
||||
DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */,
|
||||
93D39488AB33616661725929 /* UIView+AlphaScale.m */,
|
||||
93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */,
|
||||
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */,
|
||||
93D39B7B765546B1F1900CB7 /* UIView+Visible.h */,
|
||||
);
|
||||
path = "Pearl-UIKit";
|
||||
sourceTree = "<group>";
|
||||
@@ -3203,9 +3249,11 @@
|
||||
93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */,
|
||||
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */,
|
||||
93D392A8777DC30C11361647 /* UITextView+PearlAttributes.h in Headers */,
|
||||
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadFromArray.h in Headers */,
|
||||
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadItems.h in Headers */,
|
||||
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */,
|
||||
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */,
|
||||
93D3959696396A91961C6148 /* UIView+AlphaScale.h in Headers */,
|
||||
93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -3475,6 +3523,8 @@
|
||||
zh_HK,
|
||||
zh_TW,
|
||||
zu,
|
||||
Base,
|
||||
"pt-PT",
|
||||
);
|
||||
mainGroup = DA5BFA39147E415C00F98B1E;
|
||||
productRefGroup = DA5BFA45147E415C00F98B1E /* Products */;
|
||||
@@ -3909,9 +3959,11 @@
|
||||
DAA141201922FF020032B392 /* PearlTween.m in Sources */,
|
||||
93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */,
|
||||
93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */,
|
||||
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadFromArray.m in Sources */,
|
||||
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadItems.m in Sources */,
|
||||
93D3928D629EA563F9EC4909 /* NSPersistentStore+PearlMigration.m in Sources */,
|
||||
93D392A33CCE85431E910C7B /* NSOrderedSetOrArray.m in Sources */,
|
||||
93D393AA69A1193401160418 /* UIView+AlphaScale.m in Sources */,
|
||||
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -3919,26 +3971,50 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DAFC5683172C57EC00CB5CC5 /* IASKAppSettingsViewController.m in Sources */,
|
||||
DAFC5684172C57EC00CB5CC5 /* IASKAppSettingsWebViewController.m in Sources */,
|
||||
DAFC5685172C57EC00CB5CC5 /* IASKSpecifierValuesViewController.m in Sources */,
|
||||
DAFC5686172C57EC00CB5CC5 /* IASKSettingsReader.m in Sources */,
|
||||
DAFC5687172C57EC00CB5CC5 /* IASKSettingsStore.m in Sources */,
|
||||
DAFC5688172C57EC00CB5CC5 /* IASKSettingsStoreFile.m in Sources */,
|
||||
DAFC5689172C57EC00CB5CC5 /* IASKSettingsStoreUserDefaults.m in Sources */,
|
||||
DAFC568A172C57EC00CB5CC5 /* IASKSpecifier.m in Sources */,
|
||||
DAFC568B172C57EC00CB5CC5 /* IASKPSSliderSpecifierViewCell.m in Sources */,
|
||||
DAFC568C172C57EC00CB5CC5 /* IASKPSTextFieldSpecifierViewCell.m in Sources */,
|
||||
DAFC568D172C57EC00CB5CC5 /* IASKPSTitleValueSpecifierViewCell.m in Sources */,
|
||||
DAFC568E172C57EC00CB5CC5 /* IASKSlider.m in Sources */,
|
||||
DAFC568F172C57EC00CB5CC5 /* IASKSwitch.m in Sources */,
|
||||
DAFC5690172C57EC00CB5CC5 /* IASKTextField.m in Sources */,
|
||||
DA0CC52B1EAB99BA009A8ED9 /* IASKMultipleValueSelection.m in Sources */,
|
||||
DA0CC5321EAB99BA009A8ED9 /* IASKPSSliderSpecifierViewCell.m in Sources */,
|
||||
DA0CC52D1EAB99BA009A8ED9 /* IASKSettingsReader.m in Sources */,
|
||||
DA0CC52A1EAB99BA009A8ED9 /* IASKAppSettingsWebViewController.m in Sources */,
|
||||
DA0CC5291EAB99BA009A8ED9 /* IASKAppSettingsViewController.m in Sources */,
|
||||
DA0CC5381EAB99BA009A8ED9 /* IASKTextViewCell.m in Sources */,
|
||||
DA0CC5311EAB99BA009A8ED9 /* IASKSpecifier.m in Sources */,
|
||||
DA0CC5341EAB99BA009A8ED9 /* IASKSlider.m in Sources */,
|
||||
DA0CC5351EAB99BA009A8ED9 /* IASKSwitch.m in Sources */,
|
||||
DA0CC5331EAB99BA009A8ED9 /* IASKPSTextFieldSpecifierViewCell.m in Sources */,
|
||||
DA0CC52E1EAB99BA009A8ED9 /* IASKSettingsStore.m in Sources */,
|
||||
DA0CC52C1EAB99BA009A8ED9 /* IASKSpecifierValuesViewController.m in Sources */,
|
||||
DA0CC5361EAB99BA009A8ED9 /* IASKTextField.m in Sources */,
|
||||
DA0CC5371EAB99BA009A8ED9 /* IASKTextView.m in Sources */,
|
||||
DA0CC52F1EAB99BA009A8ED9 /* IASKSettingsStoreFile.m in Sources */,
|
||||
DA0CC5301EAB99BA009A8ED9 /* IASKSettingsStoreUserDefaults.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
DA0CC4F51EAB99BA009A8ED9 /* IASKLocalizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
DA0CC4F61EAB99BA009A8ED9 /* Base */,
|
||||
DA0CC4F71EAB99BA009A8ED9 /* de */,
|
||||
DA0CC4F81EAB99BA009A8ED9 /* el */,
|
||||
DA0CC4F91EAB99BA009A8ED9 /* en */,
|
||||
DA0CC4FA1EAB99BA009A8ED9 /* es */,
|
||||
DA0CC4FB1EAB99BA009A8ED9 /* fr */,
|
||||
DA0CC4FC1EAB99BA009A8ED9 /* it */,
|
||||
DA0CC4FD1EAB99BA009A8ED9 /* ja */,
|
||||
DA0CC4FE1EAB99BA009A8ED9 /* nl */,
|
||||
DA0CC4FF1EAB99BA009A8ED9 /* pt-PT */,
|
||||
DA0CC5001EAB99BA009A8ED9 /* pt */,
|
||||
DA0CC5011EAB99BA009A8ED9 /* ru */,
|
||||
DA0CC5021EAB99BA009A8ED9 /* sv */,
|
||||
DA0CC5031EAB99BA009A8ED9 /* th */,
|
||||
DA0CC5041EAB99BA009A8ED9 /* tr */,
|
||||
);
|
||||
name = IASKLocalizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
|
||||
@@ -58,6 +58,7 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
|
||||
- (Class)classOfType:(MPSiteType)type;
|
||||
- (NSArray *)allTypes;
|
||||
- (NSArray *)allTypesStartingWith:(MPSiteType)startingType;
|
||||
- (MPSiteType)defaultType;
|
||||
- (MPSiteType)nextType:(MPSiteType)type;
|
||||
- (MPSiteType)previousType:(MPSiteType)type;
|
||||
|
||||
|
||||
@@ -286,6 +286,11 @@ NSOperationQueue *_mpwQueue = nil;
|
||||
return allTypes;
|
||||
}
|
||||
|
||||
- (MPSiteType)defaultType {
|
||||
|
||||
return MPSiteTypeGeneratedLong;
|
||||
}
|
||||
|
||||
- (MPSiteType)nextType:(MPSiteType)type {
|
||||
|
||||
switch (type) {
|
||||
@@ -309,9 +314,9 @@ NSOperationQueue *_mpwQueue = nil;
|
||||
return MPSiteTypeStoredDevicePrivate;
|
||||
case MPSiteTypeStoredDevicePrivate:
|
||||
return MPSiteTypeGeneratedPhrase;
|
||||
default:
|
||||
return MPSiteTypeGeneratedLong;
|
||||
}
|
||||
|
||||
return [self defaultType];
|
||||
}
|
||||
|
||||
- (MPSiteType)previousType:(MPSiteType)type {
|
||||
|
||||
@@ -35,6 +35,7 @@ typedef NS_ENUM( NSUInteger, MPImportResult ) {
|
||||
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *mainContext))mocBlock;
|
||||
+ (BOOL)managedObjectContextPerformBlock:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
||||
+ (BOOL)managedObjectContextPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
|
||||
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
|
||||
|
||||
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
|
||||
- (void)deleteAndResetStore;
|
||||
|
||||
@@ -131,6 +131,25 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock {
|
||||
|
||||
NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady];
|
||||
if (!privateManagedObjectContextIfReady)
|
||||
return nil;
|
||||
|
||||
return PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, privateManagedObjectContextIfReady, nil,
|
||||
^(id host, NSNotification *note) {
|
||||
NSMutableDictionary *affectedObjects = [NSMutableDictionary new];
|
||||
for (NSManagedObject *object in note.userInfo[NSInsertedObjectsKey])
|
||||
affectedObjects[object.objectID] = NSInsertedObjectsKey;
|
||||
for (NSManagedObject *object in note.userInfo[NSUpdatedObjectsKey])
|
||||
affectedObjects[object.objectID] = NSUpdatedObjectsKey;
|
||||
for (NSManagedObject *object in note.userInfo[NSDeletedObjectsKey])
|
||||
affectedObjects[object.objectID] = NSDeletedObjectsKey;
|
||||
changedBlock( affectedObjects );
|
||||
} );
|
||||
}
|
||||
|
||||
- (NSManagedObjectContext *)mainManagedObjectContextIfReady {
|
||||
|
||||
[self loadStore];
|
||||
@@ -196,19 +215,21 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
|
||||
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||
self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
|
||||
|
||||
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
|
||||
PearlAddNotificationObserverTo( self.mainManagedObjectContext, NSManagedObjectContextDidSaveNotification,
|
||||
self.privateManagedObjectContext, nil, ^(NSManagedObjectContext *mainManagedObjectContext, NSNotification *note) {
|
||||
[mainManagedObjectContext performBlock:^{
|
||||
@try {
|
||||
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:note];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
err( @"While merging changes:\n%@", [exception fullDescription] );
|
||||
}
|
||||
}];
|
||||
} );
|
||||
if ([self.mainManagedObjectContext respondsToSelector:@selector( automaticallyMergesChangesFromParent )]) // iOS 10+
|
||||
self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES;
|
||||
else
|
||||
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
|
||||
PearlAddNotificationObserverTo( self.mainManagedObjectContext, NSManagedObjectContextDidSaveNotification,
|
||||
self.privateManagedObjectContext, nil, ^(NSManagedObjectContext *mainContext, NSNotification *note) {
|
||||
[mainContext performBlock:^{
|
||||
@try {
|
||||
[mainContext mergeChangesFromContextDidSaveNotification:note];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
err( @"While merging changes:\n%@", [exception fullDescription] );
|
||||
}
|
||||
}];
|
||||
} );
|
||||
|
||||
|
||||
// Create a new store coordinator.
|
||||
@@ -537,12 +558,13 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
|
||||
// Parse import data.
|
||||
inf( @"Importing sites." );
|
||||
__block MPUserEntity *user = nil;
|
||||
id<MPAlgorithm> importAlgorithm = nil;
|
||||
NSUInteger importFormat = 0;
|
||||
__block MPUserEntity *user = nil;
|
||||
NSUInteger importAvatar = NSNotFound;
|
||||
NSString *importBundleVersion = nil, *importUserName = nil;
|
||||
NSData *importKeyID = nil;
|
||||
NSString *importBundleVersion = nil, *importUserName = nil;
|
||||
id<MPAlgorithm> importAlgorithm = nil;
|
||||
MPSiteType importDefaultType = (MPSiteType)0;
|
||||
BOOL headerStarted = NO, headerEnded = NO, clearText = NO;
|
||||
NSArray *importedSiteLines = [importedSitesString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
||||
NSMutableSet *sitesToDelete = [NSMutableSet set];
|
||||
@@ -573,7 +595,15 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
range:NSMakeRange( 0, [importedSiteLine length] )] lastObject];
|
||||
NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]];
|
||||
NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]];
|
||||
if ([headerName isEqualToString:@"User Name"]) {
|
||||
|
||||
if ([headerName isEqualToString:@"Format"]) {
|
||||
importFormat = (NSUInteger)[headerValue integerValue];
|
||||
if (importFormat >= [sitePatterns count]) {
|
||||
err( @"Unsupported import format: %lu", (unsigned long)importFormat );
|
||||
return MPImportResultInternalError;
|
||||
}
|
||||
}
|
||||
if (([headerName isEqualToString:@"User Name"] || [headerName isEqualToString:@"Full Name"]) && !importUserName) {
|
||||
importUserName = headerValue;
|
||||
|
||||
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||
@@ -591,21 +621,18 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
user = [users lastObject];
|
||||
dbg( @"Existing user? %@", [user debugDescription] );
|
||||
}
|
||||
if ([headerName isEqualToString:@"Avatar"])
|
||||
importAvatar = (NSUInteger)[headerValue integerValue];
|
||||
if ([headerName isEqualToString:@"Key ID"])
|
||||
importKeyID = [headerValue decodeHex];
|
||||
if ([headerName isEqualToString:@"Version"]) {
|
||||
importBundleVersion = headerValue;
|
||||
importAlgorithm = MPAlgorithmDefaultForBundleVersion( importBundleVersion );
|
||||
}
|
||||
if ([headerName isEqualToString:@"Format"]) {
|
||||
importFormat = (NSUInteger)[headerValue integerValue];
|
||||
if (importFormat >= [sitePatterns count]) {
|
||||
err( @"Unsupported import format: %lu", (unsigned long)importFormat );
|
||||
return MPImportResultInternalError;
|
||||
}
|
||||
}
|
||||
if ([headerName isEqualToString:@"Avatar"])
|
||||
importAvatar = (NSUInteger)[headerValue integerValue];
|
||||
if ([headerName isEqualToString:@"Algorithm"])
|
||||
importAlgorithm = MPAlgorithmForVersion( (MPAlgorithmVersion)[headerValue integerValue] );
|
||||
if ([headerName isEqualToString:@"Default Type"])
|
||||
importDefaultType = (MPSiteType)[headerValue integerValue];
|
||||
if ([headerName isEqualToString:@"Passwords"]) {
|
||||
if ([headerValue isEqualToString:@"VISIBLE"])
|
||||
clearText = YES;
|
||||
@@ -709,6 +736,8 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
if (user) {
|
||||
if (importAvatar != NSNotFound)
|
||||
user.avatar = importAvatar;
|
||||
if (importDefaultType)
|
||||
user.defaultType = importDefaultType;
|
||||
dbg( @"Updating User: %@", [user debugDescription] );
|
||||
}
|
||||
else {
|
||||
@@ -716,6 +745,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
user.name = importUserName;
|
||||
user.algorithm = MPAlgorithmDefault;
|
||||
user.keyID = [userKey keyIDForAlgorithm:user.algorithm];
|
||||
user.defaultType = importDefaultType?: user.algorithm.defaultType;
|
||||
if (importAvatar != NSNotFound)
|
||||
user.avatar = importAvatar;
|
||||
dbg( @"Created User: %@", [user debugDescription] );
|
||||
@@ -785,16 +815,16 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
[export appendFormat:@"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n"];
|
||||
[export appendFormat:@"# \n"];
|
||||
[export appendFormat:@"##\n"];
|
||||
[export appendFormat:@"# Format: 1\n"];
|
||||
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
|
||||
[export appendFormat:@"# User Name: %@\n", activeUser.name];
|
||||
[export appendFormat:@"# Full Name: %@\n", activeUser.name];
|
||||
[export appendFormat:@"# Avatar: %lu\n", (unsigned long)activeUser.avatar];
|
||||
[export appendFormat:@"# Key ID: %@\n", [activeUser.keyID encodeHex]];
|
||||
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
|
||||
[export appendFormat:@"# Version: %@\n", [PearlInfoPlist get].CFBundleVersion];
|
||||
[export appendFormat:@"# Format: 1\n"];
|
||||
if (revealPasswords)
|
||||
[export appendFormat:@"# Passwords: VISIBLE\n"];
|
||||
else
|
||||
[export appendFormat:@"# Passwords: PROTECTED\n"];
|
||||
[export appendFormat:@"# Algorithm: %d\n", activeUser.algorithm.version];
|
||||
[export appendFormat:@"# Default Type: %d\n", activeUser.defaultType];
|
||||
[export appendFormat:@"# Passwords: %@\n", revealPasswords? @"VISIBLE": @"PROTECTED"];
|
||||
[export appendFormat:@"##\n"];
|
||||
[export appendFormat:@"#\n"];
|
||||
[export appendFormat:@"# Last Times Password Login\t Site\tSite\n"];
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
- (BOOL)saveToStore {
|
||||
|
||||
__block BOOL success = YES;
|
||||
if ([self hasChanges]) {
|
||||
if ([self hasChanges])
|
||||
[self performBlockAndWait:^{
|
||||
@try {
|
||||
NSError *error = nil;
|
||||
@@ -28,7 +28,6 @@
|
||||
err( @"While saving: %@", [exception fullDescription] );
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
return success && (!self.parentContext || [self.parentContext saveToStore]);
|
||||
}
|
||||
@@ -237,8 +236,8 @@
|
||||
// Invalid self.user.defaultType
|
||||
result = MPApplyFix( result, ^MPFixableResult {
|
||||
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
|
||||
self.name, self.user.name, (long)self.type, (long)MPSiteTypeGeneratedLong );
|
||||
self.type = MPSiteTypeGeneratedLong;
|
||||
self.name, self.user.name, (long)self.type, (long)[self.algorithm defaultType] );
|
||||
self.type = [self.algorithm defaultType];
|
||||
return MPFixableResultProblemsFixed;
|
||||
} );
|
||||
if (![self isKindOfClass:[self.algorithm classOfType:self.type]])
|
||||
@@ -330,7 +329,7 @@
|
||||
|
||||
- (MPSiteType)defaultType {
|
||||
|
||||
return (MPSiteType)[self.defaultType_ unsignedIntegerValue]?: MPSiteTypeGeneratedLong;
|
||||
return (MPSiteType)[self.defaultType_ unsignedIntegerValue]?: self.algorithm.defaultType;
|
||||
}
|
||||
|
||||
- (void)setDefaultType:(MPSiteType)aDefaultType {
|
||||
|
||||
@@ -547,8 +547,8 @@
|
||||
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
|
||||
fetchRequest.sortDescriptors = @[ [[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO] ];
|
||||
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name LIKE[cd] %@) AND user == %@",
|
||||
queryPattern, queryPattern, [MPMacAppDelegate get].activeUserOID];
|
||||
fetchRequest.predicate =
|
||||
[NSPredicate predicateWithFormat:@"name LIKE[cd] %@ AND user == %@", queryPattern, [MPMacAppDelegate get].activeUserOID];
|
||||
prof_rewind( @"fetchRequest" );
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
@@ -161,10 +161,9 @@
|
||||
MPSiteEntity *site = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
|
||||
if ([cell isKindOfClass:[MPGlobalAnswersCell class]]) {
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Answer Copied" ) dismissAfter:2];
|
||||
[UIPasteboard generalPasteboard].string = ((MPGlobalAnswersCell *)cell).answerField.text;
|
||||
}
|
||||
if ([cell isKindOfClass:[MPGlobalAnswersCell class]])
|
||||
[self copyAnswer:((MPGlobalAnswersCell *)cell).answerField.text];
|
||||
|
||||
else if ([cell isKindOfClass:[MPMultipleAnswersCell class]]) {
|
||||
if (!_multiple)
|
||||
[self setMultiple:YES animated:YES];
|
||||
@@ -192,6 +191,7 @@
|
||||
} cancelTitle:@"Cancel" otherTitles:@"Remove Questions", nil];
|
||||
}
|
||||
}
|
||||
|
||||
else if ([cell isKindOfClass:[MPSendAnswersCell class]]) {
|
||||
NSString *body;
|
||||
if (!_multiple) {
|
||||
@@ -215,14 +215,30 @@
|
||||
|
||||
[PearlEMail sendEMailTo:nil fromVC:self subject:strf( @"Master Password security answers for %@", site.name ) body:body];
|
||||
}
|
||||
else if ([cell isKindOfClass:[MPAnswersQuestionCell class]]) {
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Answer Copied" ) dismissAfter:2];
|
||||
[UIPasteboard generalPasteboard].string = ((MPAnswersQuestionCell *)cell).answerField.text;
|
||||
}
|
||||
|
||||
else if ([cell isKindOfClass:[MPAnswersQuestionCell class]])
|
||||
[self copyAnswer:((MPAnswersQuestionCell *)cell).answerField.text];
|
||||
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
- (void)copyAnswer:(NSString *)answer {
|
||||
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
if ([pasteboard respondsToSelector:@selector( setItems:options: )]) {
|
||||
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
|
||||
options:@{
|
||||
UIPasteboardOptionLocalOnly : @NO,
|
||||
UIPasteboardOptionExpirationDate: [NSDate dateWithTimeIntervalSinceNow:3 * 60]
|
||||
}];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Answer Copied (3 min)" ) dismissAfter:2];
|
||||
}
|
||||
else {
|
||||
pasteboard.string = answer;
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Answer Copied" ) dismissAfter:2];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)updateAnimated:(BOOL)animated {
|
||||
|
||||
@@ -49,11 +49,10 @@ const long MPAvatarAdd = 10000;
|
||||
|
||||
[super awakeFromNib];
|
||||
|
||||
self.alpha = 0;
|
||||
self.visible = NO;
|
||||
|
||||
self.nameContainer.layer.cornerRadius = 5;
|
||||
|
||||
self.avatarImageView.hidden = NO;
|
||||
self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.size.height / 2;
|
||||
self.avatarImageView.layer.masksToBounds = NO;
|
||||
self.avatarImageView.backgroundColor = [UIColor clearColor];
|
||||
@@ -211,7 +210,7 @@ const long MPAvatarAdd = 10000;
|
||||
[UIView animateWithDuration:animated? 0.5f: 0 delay:0
|
||||
options:UIViewAnimationOptionOverrideInheritedDuration | UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{
|
||||
self.alpha = 1;
|
||||
self.visible = YES;
|
||||
|
||||
if (self.newUser) {
|
||||
if (self.mode == MPAvatarModeLowered)
|
||||
@@ -220,6 +219,10 @@ const long MPAvatarAdd = 10000;
|
||||
self.avatar = arc4random() % MPAvatarCount;
|
||||
}
|
||||
|
||||
self.nameContainer.alpha = self.visibility;
|
||||
self.avatarImageView.alpha = self.visibility * 0.7f + 0.3f;
|
||||
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||
|
||||
switch (self.mode) {
|
||||
case MPAvatarModeLowered: {
|
||||
[self.avatarSizeConstraint updateConstant:
|
||||
@@ -227,10 +230,9 @@ const long MPAvatarAdd = 10000;
|
||||
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
self.nameContainer.alpha = self.visibility;
|
||||
self.nameContainer.visible = YES;
|
||||
self.nameContainer.backgroundColor = [UIColor clearColor];
|
||||
self.avatarImageView.alpha = self.visibility * 0.7f + 0.3f;
|
||||
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||
self.avatarImageView.visible = YES;
|
||||
break;
|
||||
}
|
||||
case MPAvatarModeRaisedButInactive: {
|
||||
@@ -239,10 +241,9 @@ const long MPAvatarAdd = 10000;
|
||||
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
self.nameContainer.alpha = self.visibility;
|
||||
self.nameContainer.visible = YES;
|
||||
self.nameContainer.backgroundColor = [UIColor clearColor];
|
||||
self.avatarImageView.alpha = 0;
|
||||
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||
self.avatarImageView.visible = NO;
|
||||
break;
|
||||
}
|
||||
case MPAvatarModeRaisedAndActive: {
|
||||
@@ -251,10 +252,9 @@ const long MPAvatarAdd = 10000;
|
||||
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
self.nameContainer.alpha = self.visibility;
|
||||
self.nameContainer.visible = YES;
|
||||
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||
self.avatarImageView.alpha = 1;
|
||||
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||
self.avatarImageView.visible = YES;
|
||||
break;
|
||||
}
|
||||
case MPAvatarModeRaisedAndHidden: {
|
||||
@@ -263,10 +263,9 @@ const long MPAvatarAdd = 10000;
|
||||
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
self.nameContainer.alpha = 0;
|
||||
self.nameContainer.visible = NO;
|
||||
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||
self.avatarImageView.alpha = 0;
|
||||
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||
self.avatarImageView.visible = NO;
|
||||
break;
|
||||
}
|
||||
case MPAvatarModeRaisedAndMinimized: {
|
||||
@@ -274,9 +273,9 @@ const long MPAvatarAdd = 10000;
|
||||
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh + 2];
|
||||
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
self.nameContainer.alpha = 0;
|
||||
self.nameContainer.visible = NO;
|
||||
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||
self.avatarImageView.alpha = 1;
|
||||
self.avatarImageView.visible = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -293,7 +292,7 @@ const long MPAvatarAdd = 10000;
|
||||
else
|
||||
self.avatarImageView.backgroundColor = [UIColor clearColor];
|
||||
self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.size.height / 2;
|
||||
self.spinner.alpha = self.spinnerActive? 1: 0;
|
||||
self.spinner.visible = self.spinnerActive;
|
||||
|
||||
[self.contentView layoutIfNeeded];
|
||||
} completion:nil];
|
||||
|
||||
@@ -28,17 +28,16 @@
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
_views = [NSArray arrayWithObjects:
|
||||
self.view0, self.view1, self.view2, self.view3, self.view4, self.view5, self.view6, self.view7, self.view8, self.view9, nil];
|
||||
_views = @[ self.view0, self.view1, self.view2, self.view3, self.view4, self.view5, self.view6, self.view7, self.view8, self.view9 ];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
self.viewProgress.hidden = NO;
|
||||
self.viewProgress.visible = YES;
|
||||
self.viewProgress.progress = 0;
|
||||
[_views makeObjectsPerformSelector:@selector( setAlpha: ) withObject:@0];
|
||||
[_views makeObjectsPerformSelector:@selector( setVisible: ) withObject:@NO];
|
||||
_nextView = 0;
|
||||
}
|
||||
|
||||
@@ -47,7 +46,7 @@
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
[_views[_nextView++] setAlpha:1];
|
||||
[_views[_nextView++] setVisible:YES];
|
||||
}];
|
||||
|
||||
_viewTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 block:^(NSTimer *timer) {
|
||||
@@ -56,11 +55,11 @@
|
||||
if (self.viewProgress.progress == 1)
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.viewProgress.progress = 0;
|
||||
[_views[_nextView++] setAlpha:1];
|
||||
[_views[_nextView++] setVisible:YES];
|
||||
|
||||
if (_nextView >= [_views count]) {
|
||||
[_viewTimer invalidate];
|
||||
self.viewProgress.hidden = YES;
|
||||
self.viewProgress.visible = NO;
|
||||
}
|
||||
}];
|
||||
} repeats:YES];
|
||||
|
||||
@@ -84,17 +84,28 @@
|
||||
- (IBAction)copyPassword:(id)sender {
|
||||
|
||||
NSString *sitePassword = [self.passwordButton titleForState:UIControlStateNormal];
|
||||
if ([sitePassword length]) {
|
||||
[UIPasteboard generalPasteboard].string = sitePassword;
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.tipContainer.alpha = 1;
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished)
|
||||
PearlMainQueueAfter( 3, ^{
|
||||
self.tipContainer.alpha = 0;
|
||||
} );
|
||||
}];
|
||||
}
|
||||
if (![sitePassword length])
|
||||
return;
|
||||
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
if ([pasteboard respondsToSelector:@selector( setItems:options: )])
|
||||
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: sitePassword } ]
|
||||
options:@{
|
||||
UIPasteboardOptionLocalOnly : @NO,
|
||||
UIPasteboardOptionExpirationDate: [NSDate dateWithTimeIntervalSinceNow:3 * 60]
|
||||
}];
|
||||
else
|
||||
pasteboard.string = sitePassword;
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.tipContainer.visible = YES;
|
||||
} completion:^(BOOL finished) {
|
||||
PearlMainQueueAfter( 3, ^{
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.tipContainer.visible = NO;
|
||||
}];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[dismissButton addTarget:self action:@selector( dismissOverlay: ) forControlEvents:UIControlEventTouchUpInside];
|
||||
dismissButton.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5f];
|
||||
dismissButton.alpha = 0;
|
||||
dismissButton.visible = NO;
|
||||
dismissButton.frame = self.view.bounds;
|
||||
dismissButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
_dismissSegueByButton[[NSValue valueWithNonretainedObject:dismissButton]] =
|
||||
@@ -89,7 +89,7 @@
|
||||
[_dismissSegueByButton removeObjectForKey:dismissSegueKey];
|
||||
|
||||
[UIView animateWithDuration:0.1f animations:^{
|
||||
dismissButton.alpha = 0;
|
||||
dismissButton.visible = NO;
|
||||
} completion:^(BOOL finished) {
|
||||
[dismissButton removeFromSuperview];
|
||||
}];
|
||||
@@ -127,14 +127,14 @@
|
||||
|
||||
CGRectSetY( destinationViewController.view.frame, 100 );
|
||||
destinationViewController.view.transform = CGAffineTransformMakeScale( 1.2f, 1.2f );
|
||||
destinationViewController.view.alpha = 0;
|
||||
destinationViewController.view.visible = NO;
|
||||
|
||||
[UIView transitionWithView:containerViewController.view duration:0.3f
|
||||
options:UIViewAnimationOptionAllowAnimatedContent animations:^{
|
||||
destinationViewController.view.transform = CGAffineTransformIdentity;
|
||||
CGRectSetY( destinationViewController.view.frame, 0 );
|
||||
destinationViewController.view.alpha = 1;
|
||||
dismissButton.alpha = 1;
|
||||
destinationViewController.view.visible = YES;
|
||||
dismissButton.visible = YES;
|
||||
} completion:^(BOOL finished) {
|
||||
[destinationViewController didMoveToParentViewController:containerViewController];
|
||||
[containerViewController setNeedsStatusBarAppearanceUpdate];
|
||||
@@ -147,7 +147,7 @@
|
||||
options:UIViewAnimationOptionAllowAnimatedContent animations:^{
|
||||
CGRectSetY( sourceViewController.view.frame, 100 );
|
||||
sourceViewController.view.transform = CGAffineTransformMakeScale( 0.8f, 0.8f );
|
||||
sourceViewController.view.alpha = 0;
|
||||
sourceViewController.view.visible = NO;
|
||||
[containerViewController removeDismissButtonForViewController:sourceViewController];
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished) {
|
||||
|
||||
@@ -281,12 +281,12 @@
|
||||
|
||||
[self setMode:MPPasswordCellModePassword animated:YES];
|
||||
|
||||
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
[PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic
|
||||
initSheet:^(UIActionSheet *sheet) {
|
||||
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||
for (NSNumber *typeNumber in [MPAlgorithmDefault allTypes]) {
|
||||
for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
|
||||
MPSiteType type = (MPSiteType)[typeNumber unsignedIntegerValue];
|
||||
NSString *typeName = [MPAlgorithmDefault nameOfType:type];
|
||||
NSString *typeName = [mainSite.algorithm nameOfType:type];
|
||||
if (type == mainSite.type)
|
||||
[sheet addButtonWithTitle:strf( @"● %@", typeName )];
|
||||
else
|
||||
@@ -296,7 +296,8 @@
|
||||
if (buttonIndex == [sheet cancelButtonIndex])
|
||||
return;
|
||||
|
||||
MPSiteType type = (MPSiteType)[[MPAlgorithmDefault allTypes][buttonIndex] unsignedIntegerValue]?: MPSiteTypeGeneratedLong;
|
||||
MPSiteType type = (MPSiteType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?:
|
||||
mainSite.user.defaultType?: mainSite.algorithm.defaultType;
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
@@ -492,10 +493,12 @@
|
||||
|
||||
- (void)updateAnimated:(BOOL)animated {
|
||||
|
||||
Weakify( self );
|
||||
if (![NSThread isMainThread]) {
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
PearlMainQueueOperation( ^{
|
||||
Strongify( self );
|
||||
[self updateAnimated:animated];
|
||||
}];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -506,9 +509,10 @@
|
||||
self.upgradeButton.gone = !mainSite.requiresExplicitMigration && ![[MPiOSConfig get].allowDowngrade boolValue];
|
||||
self.answersButton.gone = ![[MPiOSAppDelegate get] isFeatureUnlocked:MPProductGenerateAnswers];
|
||||
BOOL settingsMode = self.mode == MPPasswordCellModeSettings;
|
||||
self.loginNameContainer.alpha = settingsMode || mainSite.loginGenerated || [mainSite.loginName length]? 0.7f: 0;
|
||||
self.modeButton.alpha = self.transientSite? 0: settingsMode? 0.5f: 0.1f;
|
||||
self.counterLabel.alpha = self.counterButton.alpha = mainSite.type & MPSiteTypeClassGenerated? 0.5f: 0;
|
||||
self.loginNameContainer.visible = settingsMode || mainSite.loginGenerated || [mainSite.loginName length];
|
||||
self.modeButton.visible = !self.transientSite;
|
||||
self.modeButton.alpha = settingsMode? 0.5f: 0.1f;
|
||||
self.counterLabel.visible = self.counterButton.visible = mainSite.type & MPSiteTypeClassGenerated;
|
||||
self.modeButton.selected = settingsMode;
|
||||
self.strengthLabel.gone = !settingsMode;
|
||||
self.modeScrollView.scrollEnabled = !self.transientSite;
|
||||
@@ -542,15 +546,21 @@
|
||||
} );
|
||||
|
||||
// Calculate Fields
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
if (![MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPSiteEntity *site = [self siteInContext:context];
|
||||
MPKey *key = [MPiOSAppDelegate get].key;
|
||||
if (!key)
|
||||
if (!key) {
|
||||
wrn( @"Could not load cell content: key unavailable." );
|
||||
PearlMainQueueOperation( ^{
|
||||
Strongify( self );
|
||||
[self updateAnimated:YES];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL loginGenerated = site.loginGenerated;
|
||||
NSString *password = nil, *loginName = [site resolveLoginUsingKey:key];
|
||||
MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPSiteTypeGeneratedLong;
|
||||
MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPAlgorithmDefault.defaultType;
|
||||
if (self.transientSite && transientType & MPSiteTypeClassGenerated)
|
||||
password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:transientType
|
||||
withCounter:1 usingKey:key];
|
||||
@@ -598,7 +608,13 @@
|
||||
else
|
||||
self.indicatorView.hidden = YES;
|
||||
} );
|
||||
}];
|
||||
}]) {
|
||||
wrn( @"Could not load cell content: store unavailable." );
|
||||
PearlMainQueueOperation( ^{
|
||||
Strongify( self );
|
||||
[self updateAnimated:YES];
|
||||
} );
|
||||
}
|
||||
|
||||
[self.contentView layoutIfNeeded];
|
||||
}];
|
||||
@@ -633,8 +649,21 @@
|
||||
return NO;
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied" ) dismissAfter:2];
|
||||
[UIPasteboard generalPasteboard].string = password;
|
||||
[self.window endEditing:YES];
|
||||
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
if ([pasteboard respondsToSelector:@selector(setItems:options:)]) {
|
||||
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: password } ]
|
||||
options:@{
|
||||
UIPasteboardOptionLocalOnly : @NO,
|
||||
UIPasteboardOptionExpirationDate: [NSDate dateWithTimeIntervalSinceNow:3 * 60]
|
||||
}];
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied (3 min)" ) dismissAfter:2];
|
||||
}
|
||||
else {
|
||||
pasteboard.string = password;
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Password Copied" ) dismissAfter:2];
|
||||
}
|
||||
} );
|
||||
|
||||
[site use];
|
||||
@@ -650,8 +679,10 @@
|
||||
return NO;
|
||||
|
||||
PearlMainQueue( ^{
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Login Name Copied" ) dismissAfter:2];
|
||||
[self.window endEditing:YES];
|
||||
|
||||
[UIPasteboard generalPasteboard].string = loginName;
|
||||
[PearlOverlay showTemporaryOverlayWithTitle:strl( @"Login Name Copied" ) dismissAfter:2];
|
||||
} );
|
||||
|
||||
[site use];
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
@property(assign, nonatomic) BOOL active;
|
||||
|
||||
- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void ( ^ )(BOOL finished))completion;
|
||||
- (void)updatePasswords;
|
||||
- (void)reloadPasswords;
|
||||
|
||||
- (IBAction)dismissPopdown:(id)sender;
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#import "MPAnswersViewController.h"
|
||||
#import "MPMessageViewController.h"
|
||||
|
||||
static const NSString *MPTransientPasswordItem = @"MPTransientPasswordItem";
|
||||
|
||||
typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
MPPasswordsBadNameTip = 1 << 0,
|
||||
};
|
||||
@@ -32,7 +34,6 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
@interface MPPasswordsViewController()<NSFetchedResultsControllerDelegate>
|
||||
|
||||
@property(nonatomic, strong) IBOutlet UINavigationBar *navigationBar;
|
||||
@property(nonatomic, readonly) NSString *query;
|
||||
|
||||
@end
|
||||
|
||||
@@ -42,11 +43,9 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
UIColor *_backgroundColor;
|
||||
UIColor *_darkenedBackgroundColor;
|
||||
__weak UIViewController *_popdownVC;
|
||||
BOOL _showTransientItem;
|
||||
NSUInteger _transientItem;
|
||||
NSCharacterSet *_siteNameAcceptableCharactersSet;
|
||||
NSArray *_fuzzyGroups;
|
||||
NSMutableArray *_passwordCollectionViewUpdatesBatch;
|
||||
NSMutableArray<NSMutableArray *> *_passwordCollectionSections;
|
||||
}
|
||||
|
||||
#pragma mark - Life
|
||||
@@ -62,8 +61,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
|
||||
_backgroundColor = self.passwordCollectionView.backgroundColor;
|
||||
_darkenedBackgroundColor = [_backgroundColor colorWithAlphaComponent:0.6f];
|
||||
_transientItem = NSNotFound;
|
||||
_passwordCollectionViewUpdatesBatch = [NSMutableArray arrayWithCapacity:4];
|
||||
_passwordCollectionSections = [NSMutableArray new];
|
||||
|
||||
self.view.backgroundColor = [UIColor clearColor];
|
||||
[self.passwordCollectionView automaticallyAdjustInsetsForKeyboard];
|
||||
@@ -83,7 +81,6 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
|
||||
[self registerObservers];
|
||||
[self updateConfigKey:nil];
|
||||
[self updatePasswords];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
@@ -140,30 +137,42 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
return CGSizeMake( itemWidth, 100 );
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
|
||||
insetForSectionAtIndex:(NSInteger)section {
|
||||
|
||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout;
|
||||
UIEdgeInsets occludedInsets = [self.passwordCollectionView occludedInsets];
|
||||
UIEdgeInsets insets = layout.sectionInset;
|
||||
|
||||
if (section == 0)
|
||||
insets.top += occludedInsets.top;
|
||||
|
||||
if (section == collectionView.numberOfSections - 1)
|
||||
insets.bottom += occludedInsets.bottom;
|
||||
|
||||
return insets;
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
|
||||
return [self.fetchedResultsController.sections count];
|
||||
return [_passwordCollectionSections count];
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
|
||||
if (![MPiOSAppDelegate get].activeUserOID || !_fetchedResultsController)
|
||||
return 0;
|
||||
|
||||
NSUInteger objects = ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects;
|
||||
_transientItem = _showTransientItem? objects: NSNotFound;
|
||||
return objects + (_showTransientItem? 1: 0);
|
||||
return [_passwordCollectionSections[(NSUInteger)section] count];
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
MPPasswordCell *cell = [MPPasswordCell dequeueCellFromCollectionView:collectionView indexPath:indexPath];
|
||||
[cell setFuzzyGroups:_fuzzyGroups];
|
||||
if (indexPath.item < ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects)
|
||||
[cell setSite:[self.fetchedResultsController objectAtIndexPath:indexPath] animated:NO];
|
||||
else
|
||||
id item = _passwordCollectionSections[(NSUInteger)indexPath.section][(NSUInteger)indexPath.item];
|
||||
if ([item isKindOfClass:[MPSiteEntity class]])
|
||||
[cell setSite:item animated:NO];
|
||||
else // item == MPTransientPasswordItem
|
||||
[cell setTransientSite:self.query animated:NO];
|
||||
|
||||
return cell;
|
||||
@@ -180,61 +189,14 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
|
||||
#pragma mark - NSFetchedResultsControllerDelegate
|
||||
|
||||
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
|
||||
forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
|
||||
|
||||
Weakify( self );
|
||||
|
||||
if (controller == _fetchedResultsController) {
|
||||
@synchronized (_passwordCollectionViewUpdatesBatch) {
|
||||
[_passwordCollectionViewUpdatesBatch addObject:[^{
|
||||
Strongify( self );
|
||||
|
||||
switch (type) {
|
||||
case NSFetchedResultsChangeInsert:
|
||||
[self.passwordCollectionView insertItemsAtIndexPaths:@[ newIndexPath ]];
|
||||
break;
|
||||
case NSFetchedResultsChangeDelete:
|
||||
[self.passwordCollectionView deleteItemsAtIndexPaths:@[ indexPath ]];
|
||||
break;
|
||||
case NSFetchedResultsChangeMove:
|
||||
if (![indexPath isEqual:newIndexPath])
|
||||
[self.passwordCollectionView moveItemAtIndexPath:indexPath toIndexPath:newIndexPath];
|
||||
break;
|
||||
case NSFetchedResultsChangeUpdate:
|
||||
[self.passwordCollectionView reloadItemsAtIndexPaths:@[ indexPath ]];
|
||||
break;
|
||||
}
|
||||
} copy]];
|
||||
}
|
||||
|
||||
[controller.managedObjectContext performBlock:^{
|
||||
PearlMainQueueOperation( ^{
|
||||
@try {
|
||||
[self.passwordCollectionView performBatchUpdates:^{
|
||||
[self updateTransientItem];
|
||||
|
||||
@synchronized (_passwordCollectionViewUpdatesBatch) {
|
||||
for (VoidBlock block in _passwordCollectionViewUpdatesBatch)
|
||||
block();
|
||||
[_passwordCollectionViewUpdatesBatch removeAllObjects];
|
||||
}
|
||||
} completion:nil];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
wrn( @"While updating password cells: %@", [exception fullDescription] );
|
||||
[self.passwordCollectionView reloadData];
|
||||
}
|
||||
} );
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
|
||||
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
||||
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
||||
|
||||
if (controller == _fetchedResultsController)
|
||||
[self.passwordCollectionView reloadData];
|
||||
PearlMainQueue( ^{
|
||||
[self.passwordCollectionView updateDataSource:_passwordCollectionSections
|
||||
toSections:[self createPasswordCollectionSections]
|
||||
reloadItems:nil completion:nil];
|
||||
} );
|
||||
}
|
||||
|
||||
#pragma mark - UISearchBarDelegate
|
||||
@@ -266,7 +228,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
if (_passwordsDismissRecognizer)
|
||||
[self.view removeGestureRecognizer:_passwordsDismissRecognizer];
|
||||
|
||||
[self updatePasswords];
|
||||
[self reloadPasswords];
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.passwordCollectionView.backgroundColor = _backgroundColor;
|
||||
}];
|
||||
@@ -290,7 +252,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
if ([[self.query stringByTrimmingCharactersInSet:_siteNameAcceptableCharactersSet] length])
|
||||
[self showTips:MPPasswordsBadNameTip];
|
||||
|
||||
[self updatePasswords];
|
||||
[self reloadPasswords];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,61 +262,78 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
if (showTips & MPPasswordsBadNameTip)
|
||||
self.badNameTipContainer.alpha = 1;
|
||||
self.badNameTipContainer.visible = YES;
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished)
|
||||
PearlMainQueueAfter( 5, ^{
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
if (showTips & MPPasswordsBadNameTip)
|
||||
self.badNameTipContainer.alpha = 0;
|
||||
}];
|
||||
} );
|
||||
PearlMainQueueAfter( 5, ^{
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
if (showTips & MPPasswordsBadNameTip)
|
||||
self.badNameTipContainer.visible = NO;
|
||||
}];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateTransientItem {
|
||||
- (NSMutableArray<NSMutableArray *> *)createPasswordCollectionSections {
|
||||
|
||||
NSString *query = self.query;
|
||||
_showTransientItem = [query length] > 0 && ![[[self.fetchedResultsController.sections[0] objects] filteredArrayUsingPredicate:
|
||||
[NSPredicate predicateWithBlock:^BOOL(MPSiteEntity *site, NSDictionary<NSString *, id> *bindings) {
|
||||
return [site.name isEqualToString:query];
|
||||
}]] count];
|
||||
if (!_showTransientItem && _transientItem != NSNotFound)
|
||||
[self.passwordCollectionView deleteItemsAtIndexPaths:
|
||||
@[ [NSIndexPath indexPathForItem:_transientItem inSection:0] ]];
|
||||
else if (_showTransientItem && _transientItem == NSNotFound) {
|
||||
NSUInteger objects = [self.fetchedResultsController.sections[0] numberOfObjects];
|
||||
[self.passwordCollectionView insertItemsAtIndexPaths:
|
||||
@[ [NSIndexPath indexPathForItem:objects inSection:0] ]];
|
||||
BOOL needTransientItem = [query length] > 0;
|
||||
|
||||
NSArray<id<NSFetchedResultsSectionInfo>> *sectionInfos = [self.fetchedResultsController sections];
|
||||
NSMutableArray *sections = [[NSMutableArray alloc] initWithCapacity:[sectionInfos count]];
|
||||
for (id<NSFetchedResultsSectionInfo> sectionInfo in sectionInfos) {
|
||||
NSArray<MPSiteEntity *> *sites = [sectionInfo.objects copy];
|
||||
[sections addObject:sites];
|
||||
|
||||
if (needTransientItem)
|
||||
for (MPSiteEntity *site in sites)
|
||||
if ([site.name isEqualToString:query]) {
|
||||
needTransientItem = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (_transientItem != NSNotFound)
|
||||
[self.passwordCollectionView reloadItemsAtIndexPaths:
|
||||
@[ [NSIndexPath indexPathForItem:_transientItem inSection:0] ]];
|
||||
|
||||
if (needTransientItem)
|
||||
[sections addObject:@[ MPTransientPasswordItem ]];
|
||||
|
||||
return sections;
|
||||
}
|
||||
|
||||
- (void)registerObservers {
|
||||
|
||||
static NSRegularExpression *bareHostRE = nil;
|
||||
static dispatch_once_t once = 0;
|
||||
dispatch_once( &once, ^{
|
||||
bareHostRE = [NSRegularExpression regularExpressionWithPattern:@"([^\\.]+\\.[^\\.]+)$" options:0 error:nil];
|
||||
} );
|
||||
|
||||
PearlRemoveNotificationObservers();
|
||||
PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, nil, [NSOperationQueue mainQueue],
|
||||
PearlAddNotificationObserver( UIApplicationWillResignActiveNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPPasswordsViewController *self, NSNotification *note) {
|
||||
self.passwordSelectionContainer.alpha = 0;
|
||||
} );
|
||||
PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPPasswordsViewController *self, NSNotification *note) {
|
||||
[self updatePasswords];
|
||||
self.passwordSelectionContainer.visible = NO;
|
||||
} );
|
||||
PearlAddNotificationObserver( UIApplicationDidBecomeActiveNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPPasswordsViewController *self, NSNotification *note) {
|
||||
NSURL *pasteboardURL = nil;
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
if ([pasteboard respondsToSelector:@selector( hasURLs )])
|
||||
pasteboardURL = pasteboard.hasURLs? pasteboard.URL: nil;
|
||||
else
|
||||
pasteboardURL = [NSURL URLWithString:pasteboard.string];
|
||||
|
||||
if (pasteboardURL.host)
|
||||
self.query = NSNullToNil( [pasteboardURL.host firstMatchGroupsOfExpression:bareHostRE][0] );
|
||||
else
|
||||
[self reloadPasswords];
|
||||
|
||||
[UIView animateWithDuration:0.7f animations:^{
|
||||
self.passwordSelectionContainer.alpha = 1;
|
||||
self.passwordSelectionContainer.visible = YES;
|
||||
}];
|
||||
} );
|
||||
PearlAddNotificationObserver( MPSignedOutNotification, nil, nil,
|
||||
^(MPPasswordsViewController *self, NSNotification *note) {
|
||||
PearlMainQueue( ^{
|
||||
_fetchedResultsController = nil;
|
||||
self.passwordsSearchBar.text = nil;
|
||||
[self.passwordCollectionView reloadData];
|
||||
self->_fetchedResultsController = nil;
|
||||
self.query = nil;
|
||||
} );
|
||||
} );
|
||||
PearlAddNotificationObserver( MPCheckConfigNotification, nil, nil,
|
||||
@@ -366,26 +345,23 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, nil, nil,
|
||||
^(MPPasswordsViewController *self, NSNotification *note) {
|
||||
self->_fetchedResultsController = nil;
|
||||
PearlMainQueue( ^{
|
||||
[self.passwordCollectionView reloadData];
|
||||
} );
|
||||
[self reloadPasswords];
|
||||
} );
|
||||
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresDidChangeNotification, nil, nil,
|
||||
^(MPPasswordsViewController *self, NSNotification *note) {
|
||||
PearlMainQueue( ^{
|
||||
[self updatePasswords];
|
||||
[self reloadPasswords];
|
||||
[self registerObservers];
|
||||
} );
|
||||
} );
|
||||
|
||||
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
|
||||
if (mainContext)
|
||||
PearlAddNotificationObserver( NSManagedObjectContextDidSaveNotification, mainContext, nil,
|
||||
^(MPPasswordsViewController *self, NSNotification *note) {
|
||||
// TODO: either move this into the app delegate or remove the duplicate signOutAnimated: call from the app delegate.
|
||||
if (![[MPiOSAppDelegate get] activeUserInContext:note.object])
|
||||
[[MPiOSAppDelegate get] signOutAnimated:YES];
|
||||
} );
|
||||
[MPiOSAppDelegate managedObjectContextChanged:^(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects) {
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) {
|
||||
// TODO: either move this into the app delegate or remove the duplicate signOutAnimated: call from the app delegate.
|
||||
if (![[MPiOSAppDelegate get] activeUserInContext:mainContext])
|
||||
[[MPiOSAppDelegate get] signOutAnimated:YES];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateConfigKey:(NSString *)key {
|
||||
@@ -396,81 +372,38 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
[self.passwordCollectionView reloadData];
|
||||
}
|
||||
|
||||
- (void)updatePasswords {
|
||||
- (void)reloadPasswords {
|
||||
|
||||
NSManagedObjectID *activeUserOID = [MPiOSAppDelegate get].activeUserOID;
|
||||
if (!activeUserOID) {
|
||||
PearlMainQueue( ^{
|
||||
self.passwordsSearchBar.text = nil;
|
||||
[self.passwordCollectionView reloadData];
|
||||
[self.passwordCollectionView setContentOffset:CGPointMake( 0, -self.passwordCollectionView.contentInset.top ) animated:YES];
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
static NSRegularExpression *fuzzyRE;
|
||||
static dispatch_once_t once = 0;
|
||||
dispatch_once( &once, ^{
|
||||
fuzzyRE = [NSRegularExpression regularExpressionWithPattern:@"(.)" options:0 error:nil];
|
||||
} );
|
||||
|
||||
NSString *queryString = self.query;
|
||||
NSString *queryPattern;
|
||||
if ([queryString length] < 13)
|
||||
queryPattern = [queryString stringByReplacingMatchesOfExpression:fuzzyRE withTemplate:@"*$1*"];
|
||||
else
|
||||
// If query is too long, a wildcard per character makes the CoreData fetch take excessively long.
|
||||
queryPattern = strf( @"*%@*", queryString );
|
||||
NSMutableArray *fuzzyGroups = [NSMutableArray arrayWithCapacity:[queryString length]];
|
||||
[fuzzyRE enumerateMatchesInString:queryString options:0 range:NSMakeRange( 0, queryString.length )
|
||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
[fuzzyGroups addObject:[queryString substringWithRange:result.range]];
|
||||
}];
|
||||
_fuzzyGroups = fuzzyGroups;
|
||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||
NSArray *oldSectionInfos = [self.fetchedResultsController sections];
|
||||
NSMutableArray *oldSections = [[NSMutableArray alloc] initWithCapacity:[oldSectionInfos count]];
|
||||
for (id<NSFetchedResultsSectionInfo> sectionInfo in oldSectionInfos)
|
||||
[oldSections addObject:[sectionInfo.objects copy]];
|
||||
static NSRegularExpression *fuzzyRE;
|
||||
static dispatch_once_t once = 0;
|
||||
dispatch_once( &once, ^{
|
||||
fuzzyRE = [NSRegularExpression regularExpressionWithPattern:@"(.)" options:0 error:nil];
|
||||
} );
|
||||
|
||||
NSString *queryString = self.query;
|
||||
NSString *queryPattern = [[queryString stringByReplacingMatchesOfExpression:fuzzyRE withTemplate:@"*$1"]
|
||||
stringByAppendingString:@"*"];
|
||||
NSMutableArray *fuzzyGroups = [NSMutableArray new];
|
||||
[fuzzyRE enumerateMatchesInString:queryString options:0 range:NSMakeRange( 0, queryString.length )
|
||||
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||
[fuzzyGroups addObject:[queryString substringWithRange:result.range]];
|
||||
}];
|
||||
_fuzzyGroups = fuzzyGroups;
|
||||
|
||||
NSError *error = nil;
|
||||
self.fetchedResultsController.fetchRequest.predicate =
|
||||
[NSPredicate predicateWithFormat:@"(%@ == '' OR name LIKE[cd] %@) AND user == %@",
|
||||
queryPattern, queryPattern, activeUserOID];
|
||||
[NSPredicate predicateWithFormat:@"name LIKE[cd] %@ AND user == %@", queryPattern, [MPiOSAppDelegate get].activeUserOID];
|
||||
if (![self.fetchedResultsController performFetch:&error])
|
||||
err( @"Couldn't fetch sites: %@", [error fullDescription] );
|
||||
|
||||
PearlMainQueue( ^{
|
||||
@try {
|
||||
[self.passwordCollectionView performBatchUpdates:^{
|
||||
[self updateTransientItem];
|
||||
|
||||
NSInteger fromSections = self.passwordCollectionView.numberOfSections;
|
||||
NSInteger toSections = [self numberOfSectionsInCollectionView:self.passwordCollectionView];
|
||||
for (NSInteger section = 0; section < MAX( toSections, fromSections ); ++section) {
|
||||
if (section >= fromSections)
|
||||
[self.passwordCollectionView insertSections:[NSIndexSet indexSetWithIndex:section]];
|
||||
else if (section >= toSections)
|
||||
[self.passwordCollectionView deleteSections:[NSIndexSet indexSetWithIndex:section]];
|
||||
else if (section < [oldSections count])
|
||||
[self.passwordCollectionView reloadItemsFromArray:oldSections[section]
|
||||
toArray:[[self.fetchedResultsController sections][section] objects]
|
||||
inSection:section];
|
||||
else
|
||||
[self.passwordCollectionView reloadSections:[NSIndexSet indexSetWithIndex:section]];
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished)
|
||||
[self.passwordCollectionView setContentOffset:CGPointMake( 0, -self.passwordCollectionView.contentInset.top )
|
||||
animated:YES];
|
||||
for (MPPasswordCell *cell in self.passwordCollectionView.visibleCells)
|
||||
[cell setFuzzyGroups:_fuzzyGroups];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
wrn( @"While updating password cells: %@", [exception fullDescription] );
|
||||
[self.passwordCollectionView reloadData];
|
||||
}
|
||||
[self.passwordCollectionView updateDataSource:_passwordCollectionSections
|
||||
toSections:[self createPasswordCollectionSections]
|
||||
reloadItems:@[ MPTransientPasswordItem ] completion:^(BOOL finished) {
|
||||
for (MPPasswordCell *cell in self.passwordCollectionView.visibleCells)
|
||||
[cell setFuzzyGroups:_fuzzyGroups];
|
||||
}];
|
||||
} );
|
||||
}];
|
||||
}
|
||||
@@ -482,18 +415,24 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
|
||||
return [self.passwordsSearchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
}
|
||||
|
||||
- (void)setQuery:(NSString *)query {
|
||||
|
||||
self.passwordsSearchBar.text = [query stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
[self reloadPasswords];
|
||||
}
|
||||
|
||||
- (NSFetchedResultsController *)fetchedResultsController {
|
||||
|
||||
if (!_fetchedResultsController) {
|
||||
_showTransientItem = NO;
|
||||
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
|
||||
fetchRequest.sortDescriptors = @[
|
||||
[[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
|
||||
];
|
||||
fetchRequest.fetchBatchSize = 10;
|
||||
_fetchedResultsController = [[NSFetchedResultsController alloc]
|
||||
initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
|
||||
_fetchedResultsController =
|
||||
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext
|
||||
sectionNameKeyPath:nil cacheName:nil];
|
||||
_fetchedResultsController.delegate = self;
|
||||
}];
|
||||
[self registerObservers];
|
||||
|
||||
@@ -73,10 +73,10 @@ PearlEnum( MPDevelopmentFuelConsumption,
|
||||
|
||||
self.tableView.contentInset = UIEdgeInsetsMake( 64, 0, 49, 0 );
|
||||
|
||||
[self reloadCellsHiding:self.allCellsBySection[0] showing:@[ self.loadingCell ]];
|
||||
[self updateCellsHiding:self.allCellsBySection[0] showing:@[ self.loadingCell ]];
|
||||
[self.allCellsBySection[0] enumerateObjectsUsingBlock:^(MPStoreProductCell *cell, NSUInteger idx, BOOL *stop) {
|
||||
if ([cell isKindOfClass:[MPStoreProductCell class]]) {
|
||||
cell.purchasedIndicator.alpha = 0;
|
||||
cell.purchasedIndicator.visible = NO;
|
||||
[cell.activityIndicator stopAnimating];
|
||||
}
|
||||
}];
|
||||
@@ -257,7 +257,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
|
||||
}
|
||||
|
||||
[hideCells removeObjectsInArray:showCells];
|
||||
[self reloadCellsHiding:hideCells showing:showCells];
|
||||
[self updateCellsHiding:hideCells showing:showCells];
|
||||
}
|
||||
|
||||
- (void)updateFuel {
|
||||
@@ -313,7 +313,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
|
||||
BOOL purchased = [[MPiOSAppDelegate get] isFeatureUnlocked:productIdentifier];
|
||||
NSInteger quantity = [self quantityForProductIdentifier:productIdentifier];
|
||||
cell.priceLabel.text = purchased? @"": [self.currencyFormatter stringFromNumber:@([product.price floatValue] * quantity)];
|
||||
cell.purchasedIndicator.alpha = purchased? 1: 0;
|
||||
cell.purchasedIndicator.visible = purchased;
|
||||
}
|
||||
|
||||
- (NSInteger)quantityForProductIdentifier:(NSString *)productIdentifier {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
|
||||
inf( @"Type selection will appear" );
|
||||
self.recommendedTipContainer.alpha = 0;
|
||||
self.recommendedTipContainer.visible = NO;
|
||||
|
||||
[super viewWillAppear:animated];
|
||||
}
|
||||
@@ -42,15 +42,13 @@
|
||||
|
||||
if ([[MPiOSConfig get].firstRun boolValue])
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
self.recommendedTipContainer.alpha = 1;
|
||||
self.recommendedTipContainer.visible = YES;
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished) {
|
||||
dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
|
||||
[UIView animateWithDuration:0.2f animations:^{
|
||||
self.recommendedTipContainer.alpha = 0;
|
||||
}];
|
||||
} );
|
||||
}
|
||||
PearlMainQueueAfter( 5, ^{
|
||||
[UIView animateWithDuration:0.2f animations:^{
|
||||
self.recommendedTipContainer.visible = NO;
|
||||
}];
|
||||
} );
|
||||
}];
|
||||
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
@implementation MPUsersViewController {
|
||||
NSString *_masterPasswordChoice;
|
||||
NSOperationQueue *_afterUpdates;
|
||||
__weak id _contextChangedObserver;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
@@ -76,7 +77,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
self.avatarCollectionView.allowsMultipleSelection = YES;
|
||||
[self.entryField addTarget:self action:@selector( textFieldEditingChanged: ) forControlEvents:UIControlEventEditingChanged];
|
||||
|
||||
self.preferencesTipContainer.alpha = 0;
|
||||
self.preferencesTipContainer.visible = NO;
|
||||
|
||||
[self setActive:YES animated:NO];
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"tipped.thanks"])
|
||||
@@ -87,16 +88,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
self.userSelectionContainer.alpha = 0;
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
PearlRemoveNotificationObservers();
|
||||
|
||||
[self.marqueeTipTimer invalidate];
|
||||
self.userSelectionContainer.visible = NO;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
@@ -130,6 +122,15 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
((MPWebViewController *)segue.destinationViewController).initialURL = [NSURL URLWithString:@"http://thanks.lhunath.com"];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
[self removeObservers];
|
||||
|
||||
[self.marqueeTipTimer invalidate];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||
@@ -220,6 +221,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
|
||||
if (isNew) {
|
||||
user = [MPUserEntity insertNewObjectInContext:context];
|
||||
user.algorithm = MPAlgorithmDefault;
|
||||
user.defaultType = user.algorithm.defaultType;
|
||||
user.avatar = newUserAvatar;
|
||||
user.name = newUserName;
|
||||
}
|
||||
@@ -464,25 +466,23 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
- (void)deleteUser:(NSManagedObjectID *)userID {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPUserEntity
|
||||
*user_ = [MPUserEntity existingObjectWithID:userID inContext:context];
|
||||
if (!user_)
|
||||
MPUserEntity *user = [MPUserEntity existingObjectWithID:userID inContext:context];
|
||||
if (!user)
|
||||
return;
|
||||
|
||||
[context deleteObject:user_];
|
||||
[context deleteObject:user];
|
||||
[context saveToStore];
|
||||
[self reloadUsers]; // I do NOT understand why our ObjectsDidChangeNotification isn't firing on saveToStore.
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)resetUser:(NSManagedObjectID *)userID avatar:(MPAvatarCell *)avatarCell {
|
||||
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
MPUserEntity *user_ = [MPUserEntity existingObjectWithID:userID inContext:context];
|
||||
if (!user_)
|
||||
MPUserEntity *user = [MPUserEntity existingObjectWithID:userID inContext:context];
|
||||
if (!user)
|
||||
return;
|
||||
|
||||
[[MPiOSAppDelegate get] changeMasterPasswordFor:user_ saveInContext:context didResetBlock:^{
|
||||
[[MPiOSAppDelegate get] changeMasterPasswordFor:user saveInContext:context didResetBlock:^{
|
||||
PearlMainQueue( ^{
|
||||
NSIndexPath *avatarIndexPath = [self.avatarCollectionView indexPathForCell:avatarCell];
|
||||
[self.avatarCollectionView selectItemAtIndexPath:avatarIndexPath animated:NO
|
||||
@@ -497,25 +497,25 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
if (showTips & MPUsersThanksTip)
|
||||
self.thanksTipContainer.alpha = 1;
|
||||
self.thanksTipContainer.visible = YES;
|
||||
if (showTips & MPUsersAvatarTip)
|
||||
self.avatarTipContainer.alpha = 1;
|
||||
self.avatarTipContainer.visible = YES;
|
||||
if (showTips & MPUsersMasterPasswordTip)
|
||||
self.entryTipContainer.alpha = 1;
|
||||
self.entryTipContainer.visible = YES;
|
||||
if (showTips & MPUsersPreferencesTip)
|
||||
self.preferencesTipContainer.alpha = 1;
|
||||
self.preferencesTipContainer.visible = YES;
|
||||
} completion:^(BOOL finished) {
|
||||
if (finished)
|
||||
PearlMainQueueAfter( 5, ^{
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
if (showTips & MPUsersThanksTip)
|
||||
self.thanksTipContainer.alpha = 0;
|
||||
self.thanksTipContainer.visible = NO;
|
||||
if (showTips & MPUsersAvatarTip)
|
||||
self.avatarTipContainer.alpha = 0;
|
||||
self.avatarTipContainer.visible = NO;
|
||||
if (showTips & MPUsersMasterPasswordTip)
|
||||
self.entryTipContainer.alpha = 0;
|
||||
self.entryTipContainer.visible = NO;
|
||||
if (showTips & MPUsersPreferencesTip)
|
||||
self.preferencesTipContainer.alpha = 0;
|
||||
self.preferencesTipContainer.visible = NO;
|
||||
}];
|
||||
} );
|
||||
}];
|
||||
@@ -538,14 +538,14 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
return;
|
||||
|
||||
[UIView animateWithDuration:timer? 0.5f: 0 animations:^{
|
||||
self.marqueeButton.alpha = 0;
|
||||
self.marqueeButton.visible = NO;
|
||||
} completion:^(BOOL finished) {
|
||||
if (!finished)
|
||||
return;
|
||||
|
||||
[self.marqueeButton setTitle:nextMarqueeString forState:UIControlStateNormal];
|
||||
[UIView animateWithDuration:timer? 0.5f: 0 animations:^{
|
||||
self.marqueeButton.alpha = 0.5f;
|
||||
self.marqueeButton.visible = YES;
|
||||
}];
|
||||
}];
|
||||
}
|
||||
@@ -588,8 +588,6 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
|
||||
- (void)updateAvatarVisibility {
|
||||
|
||||
self.previousAvatarButton.alpha = 0;
|
||||
self.nextAvatarButton.alpha = 0;
|
||||
for (NSIndexPath *indexPath in self.avatarCollectionView.indexPathsForVisibleItems) {
|
||||
MPAvatarCell *cell = (MPAvatarCell *)[self.avatarCollectionView cellForItemAtIndexPath:indexPath];
|
||||
[self updateVisibilityForAvatar:cell atIndexPath:indexPath animated:NO];
|
||||
@@ -633,10 +631,10 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
CGFloat visibility = MAX( 0, MIN( 1, 1 - ABS( current / (max / 2) - 1 ) ) );
|
||||
[cell setVisibility:visibility animated:animated];
|
||||
|
||||
if (cell.newUser) {
|
||||
self.previousAvatarButton.alpha = cell.mode == MPAvatarModeRaisedAndActive? visibility * 0.7f: 0;
|
||||
self.nextAvatarButton.alpha = cell.mode == MPAvatarModeRaisedAndActive? visibility * 0.7f: 0;
|
||||
}
|
||||
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||
self.nextAvatarButton.visible = self.previousAvatarButton.visible = cell.newUser && cell.mode == MPAvatarModeRaisedAndActive;
|
||||
self.nextAvatarButton.alpha = self.previousAvatarButton.alpha = visibility * 0.7f;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)afterUpdatesMainQueue:(void ( ^ )(void))block {
|
||||
@@ -646,18 +644,24 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)registerObservers {
|
||||
- (void)removeObservers {
|
||||
|
||||
[self removeKeyPathObservers];
|
||||
PearlRemoveNotificationObservers();
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:_contextChangedObserver];
|
||||
}
|
||||
|
||||
- (void)registerObservers {
|
||||
|
||||
[self removeObservers];
|
||||
[self observeKeyPath:@"avatarCollectionView.contentOffset" withBlock:
|
||||
^(id from, id to, NSKeyValueChange cause, MPUsersViewController *_self) {
|
||||
[_self updateAvatarVisibility];
|
||||
}];
|
||||
|
||||
PearlRemoveNotificationObservers();
|
||||
PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
self.userSelectionContainer.alpha = 0;
|
||||
self.userSelectionContainer.visible = NO;
|
||||
} );
|
||||
PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
@@ -666,7 +670,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
PearlAddNotificationObserver( UIApplicationDidBecomeActiveNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
[UIView animateWithDuration:0.5f animations:^{
|
||||
self.userSelectionContainer.alpha = 1;
|
||||
self.userSelectionContainer.visible = YES;
|
||||
}];
|
||||
} );
|
||||
PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
|
||||
@@ -676,36 +680,31 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
|
||||
} );
|
||||
|
||||
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.avatarCollectionView.alpha = mainContext? 1: 0;
|
||||
}];
|
||||
if (mainContext && self.storeLoadingActivity.isAnimating)
|
||||
[self.storeLoadingActivity stopAnimating];
|
||||
if (!mainContext && !self.storeLoadingActivity.isAnimating)
|
||||
[self.storeLoadingActivity startAnimating];
|
||||
if ((_contextChangedObserver = [MPiOSAppDelegate managedObjectContextChanged:^(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects) {
|
||||
if ([[[affectedObjects allKeys] filteredArrayUsingPredicate:
|
||||
[NSPredicate predicateWithBlock:^BOOL(NSManagedObjectID *objectID, NSDictionary *bindings) {
|
||||
return [objectID.entity.name isEqualToString:NSStringFromClass( [MPUserEntity class] )];
|
||||
}]] count])
|
||||
[self reloadUsers];
|
||||
}]))
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.avatarCollectionView.visible = YES;
|
||||
[self.storeLoadingActivity stopAnimating];
|
||||
}];
|
||||
else
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.avatarCollectionView.visible = NO;
|
||||
[self.storeLoadingActivity startAnimating];
|
||||
}];
|
||||
|
||||
if (mainContext)
|
||||
PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, mainContext, nil,
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey];
|
||||
NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey];
|
||||
if ([[NSSetUnion( insertedObjects, deletedObjects )
|
||||
filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
|
||||
return [evaluatedObject isKindOfClass:[MPUserEntity class]];
|
||||
}]] count])
|
||||
[self reloadUsers];
|
||||
} );
|
||||
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, [MPiOSAppDelegate get].storeCoordinator, nil,
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
self.userIDs = nil;
|
||||
} );
|
||||
PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresDidChangeNotification, [MPiOSAppDelegate get].storeCoordinator, nil,
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
PearlMainQueue( ^{
|
||||
[self registerObservers];
|
||||
[self reloadUsers];
|
||||
} );
|
||||
[self registerObservers];
|
||||
[self reloadUsers];
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -763,7 +762,7 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.userSelectionContainer.alpha = 1;
|
||||
self.userSelectionContainer.visible = YES;
|
||||
}];
|
||||
} );
|
||||
}
|
||||
@@ -828,8 +827,8 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
switch (activeUserState) {
|
||||
case MPActiveUserStateNone: {
|
||||
self.avatarCollectionView.scrollEnabled = YES;
|
||||
self.entryContainer.alpha = 0;
|
||||
self.footerContainer.alpha = 1;
|
||||
self.entryContainer.visible = NO;
|
||||
self.footerContainer.visible = YES;
|
||||
break;
|
||||
}
|
||||
case MPActiveUserStateLogin:
|
||||
@@ -837,15 +836,15 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
case MPActiveUserStateMasterPasswordChoice:
|
||||
case MPActiveUserStateMasterPasswordConfirmation: {
|
||||
self.avatarCollectionView.scrollEnabled = NO;
|
||||
self.entryContainer.alpha = 1;
|
||||
self.footerContainer.alpha = 1;
|
||||
self.entryContainer.visible = YES;
|
||||
self.footerContainer.visible = YES;
|
||||
requestFirstResponder = YES;
|
||||
break;
|
||||
}
|
||||
case MPActiveUserStateMinimized: {
|
||||
self.avatarCollectionView.scrollEnabled = NO;
|
||||
self.entryContainer.alpha = 0;
|
||||
self.footerContainer.alpha = 0;
|
||||
self.entryContainer.visible = NO;
|
||||
self.footerContainer.visible = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
self.webNavigationItem.title = self.initialURL.host;
|
||||
|
||||
self.webView.alpha = 0;
|
||||
self.webView.visible = NO;
|
||||
[self.webView loadRequest:[[NSURLRequest alloc] initWithURL:self.initialURL]];
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
- (void)webViewDidFinishLoad:(UIWebView *)webView {
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.webView.alpha = 1;
|
||||
self.webView.visible = YES;
|
||||
}];
|
||||
|
||||
[self.webNavigationItem setLeftBarButtonItem:[webView canGoBack]? [[UIBarButtonItem alloc]
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
@property(nonatomic, strong) UIDocumentInteractionController *interactionController;
|
||||
|
||||
@property(nonatomic) UIBackgroundTaskIdentifier task;
|
||||
@end
|
||||
|
||||
@implementation MPiOSAppDelegate
|
||||
@@ -244,6 +245,44 @@
|
||||
if (![[MPiOSConfig get].rememberLogin boolValue])
|
||||
[self signOutAnimated:NO];
|
||||
|
||||
// self.task = [application beginBackgroundTaskWithExpirationHandler:^{
|
||||
// [application endBackgroundTask:self.task];
|
||||
// dbg( @"background expiring" );
|
||||
// }];
|
||||
// PearlNotMainQueueOperation( ^{
|
||||
// NSString *pbstring = [UIPasteboard generalPasteboard].string;
|
||||
// while (YES) {
|
||||
// NSString *newString = [UIPasteboard generalPasteboard].string;
|
||||
// if (![newString isEqualToString:pbstring]) {
|
||||
// dbg( @"pasteboard changed to: %@", newString );
|
||||
// pbstring = newString;
|
||||
// NSURL *url = [NSURL URLWithString:pbstring];
|
||||
// if (url) {
|
||||
// NSString *siteName = [url host];
|
||||
// }
|
||||
// MPKey *key = [MPiOSAppDelegate get].key;
|
||||
// if (key)
|
||||
// [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
// NSFetchRequest<MPSiteEntity *>
|
||||
// *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
|
||||
// fetchRequest.sortDescriptors = @[
|
||||
// [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
|
||||
// ];
|
||||
// fetchRequest.fetchBatchSize = 2;
|
||||
// fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(name LIKE[cd] %@) AND user == %@", siteName,
|
||||
// [[MPiOSAppDelegate get] activeUserOID]];
|
||||
// NSError *error = nil;
|
||||
// NSArray<MPSiteEntity *> *results = [fetchRequest execute:&error];
|
||||
// dbg( @"site search, error: %@, results:\n%@", error, results );
|
||||
// if ([results count]) {
|
||||
// [UIPasteboard generalPasteboard].string = [[results firstObject] resolvePasswordUsingKey:key];
|
||||
// }
|
||||
// }];
|
||||
// }
|
||||
// [NSThread sleepForTimeInterval:5];
|
||||
// }
|
||||
// } );
|
||||
|
||||
[super applicationDidEnterBackground:application];
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,4 +5,4 @@ set -e
|
||||
cd "${BASH_SOURCE%/*}"
|
||||
|
||||
rm -vfr lib/*/{.unpacked,.patched,src} lib/include
|
||||
rm -vfr {core,cli}{*.o,*.dSYM} mpw mpw-bench mpw-tests
|
||||
rm -vfr {core,cli,.}/{*.o,*.dSYM} mpw mpw-bench mpw-tests
|
||||
|
||||
@@ -11,19 +11,24 @@ mpwArchive=mpw-$commit.tar.gz
|
||||
[[ -e $mpwArchive ]] && echo >&2 "WARNING: $mpwArchive already exists. Will overwrite."
|
||||
read -n1 -p "Will prepare and release $mpwArchive. Press a key to continue or ^C to abort."
|
||||
|
||||
echo "Cleaning .."
|
||||
( git clean -ffdx . && cd core && git clean -ffdx . )
|
||||
|
||||
echo "Creating archive $mpwArchive .."
|
||||
git ls-files -z . | xargs -0 tar -Lcvzf "$mpwArchive"
|
||||
|
||||
echo "Creating archive signature $mpwArchive.sig .."
|
||||
gpg --detach-sign "$mpwArchive"
|
||||
|
||||
echo "Installing archive and signature in current site .."
|
||||
cd ../../public/site/current
|
||||
ln -sf "../../../platform-independent/cli-c/$mpwArchive"; [[ -e $_ ]]
|
||||
ln -sf "../../../platform-independent/cli-c/$mpwArchive.sig"; [[ -e $_ ]]
|
||||
mv "../../../platform-independent/cli-c/$mpwArchive" .; [[ -e $_ ]]
|
||||
mv "../../../platform-independent/cli-c/$mpwArchive.sig" .; [[ -e $_ ]]
|
||||
ln -sf "$mpwArchive" "masterpassword-cli.tar.gz"; [[ -e $_ ]]
|
||||
ln -sf "$mpwArchive.sig" "masterpassword-cli.tar.gz.sig"; [[ -e $_ ]]
|
||||
|
||||
echo
|
||||
echo "Done. Don't forget to publish the site."
|
||||
echo "package: $mpwArchive"
|
||||
echo "signature: $mpwArchive.sig"
|
||||
echo "Done. Ready to publish the site."
|
||||
echo " package: $mpwArchive"
|
||||
echo " signature: $mpwArchive.sig"
|
||||
echo " url: https://ssl.masterpasswordapp.com/$mpwArchive"
|
||||
|
||||
@@ -1 +1 @@
|
||||
mpw-2.5-cli-1-0-gb01e370f.tar.gz
|
||||
mpw-2.5-cli-2-0-g3ed6b937.tar.gz
|
||||
@@ -1 +1 @@
|
||||
mpw-2.5-cli-1-0-gb01e370f.tar.gz.sig
|
||||
mpw-2.5-cli-2-0-g3ed6b937.tar.gz.sig
|
||||
@@ -1 +0,0 @@
|
||||
../../../platform-independent/cli-c/mpw-2.1-cli1-0-g10f1001.tar.gz
|
||||
BIN
public/site/2013-05/mpw-2.1-cli1-0-g10f1001.tar.gz
Normal file
BIN
public/site/2013-05/mpw-2.1-cli1-0-g10f1001.tar.gz
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../../../platform-independent/cli-c/mpw-2.1-cli2-2-g82c96dd.tar.gz
|
||||
BIN
public/site/2013-05/mpw-2.1-cli2-2-g82c96dd.tar.gz
Normal file
BIN
public/site/2013-05/mpw-2.1-cli2-2-g82c96dd.tar.gz
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../../../platform-independent/cli-c/mpw-2.1-cli3-0-g438daf2.tar.gz
|
||||
BIN
public/site/2013-05/mpw-2.1-cli3-0-g438daf2.tar.gz
Normal file
BIN
public/site/2013-05/mpw-2.1-cli3-0-g438daf2.tar.gz
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../../../platform-independent/cli-c/mpw-2.1-cli4-0-gf6b2287.tar.gz
|
||||
BIN
public/site/2013-05/mpw-2.1-cli4-0-gf6b2287.tar.gz
Normal file
BIN
public/site/2013-05/mpw-2.1-cli4-0-gf6b2287.tar.gz
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../../../platform-independent/cli-c/mpw-2.5-cli-1-0-gb01e370f.tar.gz
|
||||
BIN
public/site/2013-05/mpw-2.5-cli-1-0-gb01e370f.tar.gz
Normal file
BIN
public/site/2013-05/mpw-2.5-cli-1-0-gb01e370f.tar.gz
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
../../../platform-independent/cli-c/mpw-2.5-cli-1-0-gb01e370f.tar.gz.sig
|
||||
BIN
public/site/2013-05/mpw-2.5-cli-1-0-gb01e370f.tar.gz.sig
Normal file
BIN
public/site/2013-05/mpw-2.5-cli-1-0-gb01e370f.tar.gz.sig
Normal file
Binary file not shown.
BIN
public/site/2013-05/mpw-2.5-cli-2-0-g3ed6b937.tar.gz
Normal file
BIN
public/site/2013-05/mpw-2.5-cli-2-0-g3ed6b937.tar.gz
Normal file
Binary file not shown.
BIN
public/site/2013-05/mpw-2.5-cli-2-0-g3ed6b937.tar.gz.sig
Normal file
BIN
public/site/2013-05/mpw-2.5-cli-2-0-g3ed6b937.tar.gz.sig
Normal file
Binary file not shown.
Reference in New Issue
Block a user