Extract common code from SearchVC and AllVC.
[ADDED] A more generic element listing controller, now used by the search controller and all elements listing controller. [IMPROVED] Improved change detection and UI handling in the element listing controllers. [FIXED] Bug with previewing generated password types for non-generated elements.
This commit is contained in:
parent
d7d91d13c6
commit
31d4d5b6c6
2
External/iCloudStoreManager
vendored
2
External/iCloudStoreManager
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 39ac68e0fb34f0c6e2f455f132b56fd158630ee7
|
Subproject commit 261344e1faffa59b570343ca11be5dda412242e2
|
@ -12,12 +12,14 @@
|
|||||||
93D392B30CE6C58A9A905E0A /* MPAlgorithmV0.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3938863322199C3E7E2E3 /* MPAlgorithmV0.m */; };
|
93D392B30CE6C58A9A905E0A /* MPAlgorithmV0.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3938863322199C3E7E2E3 /* MPAlgorithmV0.m */; };
|
||||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
|
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */; };
|
||||||
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */; };
|
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */; };
|
||||||
|
93D3944DE5E21C69AA8CC6D4 /* MPElementListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39C56514D6DE72F5FB83E /* MPElementListController.m */; };
|
||||||
93D394744B5485303B326ECB /* MPAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B0DF5E3C56355186738 /* MPAlgorithm.m */; };
|
93D394744B5485303B326ECB /* MPAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B0DF5E3C56355186738 /* MPAlgorithm.m */; };
|
||||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
|
||||||
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
|
93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; };
|
||||||
|
93D3995C0452184780AECD0C /* MPElementListSearchController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D394FF2CF2935332260C50 /* MPElementListSearchController.m */; };
|
||||||
93D399B873AF89808151D2F5 /* MPAppsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390DABAE4368E90E37340 /* MPAppsViewController.m */; };
|
93D399B873AF89808151D2F5 /* MPAppsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D390DABAE4368E90E37340 /* MPAppsViewController.m */; };
|
||||||
93D39BCE5F69D8EBE7E9F6EC /* MPAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E070BD3F45B3045A1DA /* MPAppViewController.m */; };
|
93D39BCE5F69D8EBE7E9F6EC /* MPAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E070BD3F45B3045A1DA /* MPAppViewController.m */; };
|
||||||
93D39BD0F5C7C76678712500 /* MPAllSitesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F16ADA770D8C13B4555 /* MPAllSitesViewController.m */; };
|
93D39BD0F5C7C76678712500 /* MPElementListAllViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F16ADA770D8C13B4555 /* MPElementListAllViewController.m */; };
|
||||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; };
|
||||||
93D39DC7A7282137B08C8D82 /* MPAlgorithmV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */; };
|
93D39DC7A7282137B08C8D82 /* MPAlgorithmV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */; };
|
||||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; };
|
||||||
@ -184,7 +186,6 @@
|
|||||||
DAB8D46415036BCF00CED3BC /* MPiOSConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44915036BCF00CED3BC /* MPiOSConfig.m */; };
|
DAB8D46415036BCF00CED3BC /* MPiOSConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44915036BCF00CED3BC /* MPiOSConfig.m */; };
|
||||||
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */; };
|
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */; };
|
||||||
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */; };
|
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */; };
|
||||||
DAB8D46715036BCF00CED3BC /* MPSearchDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44F15036BCF00CED3BC /* MPSearchDelegate.m */; };
|
|
||||||
DAB8D46815036BCF00CED3BC /* MPTypeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D45115036BCF00CED3BC /* MPTypeViewController.m */; };
|
DAB8D46815036BCF00CED3BC /* MPTypeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D45115036BCF00CED3BC /* MPTypeViewController.m */; };
|
||||||
DAB8D46915036BCF00CED3BC /* MPUnlockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D45315036BCF00CED3BC /* MPUnlockViewController.m */; };
|
DAB8D46915036BCF00CED3BC /* MPUnlockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D45315036BCF00CED3BC /* MPUnlockViewController.m */; };
|
||||||
DAB8D46A15036BCF00CED3BC /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D45415036BCF00CED3BC /* Settings.bundle */; };
|
DAB8D46A15036BCF00CED3BC /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D45415036BCF00CED3BC /* Settings.bundle */; };
|
||||||
@ -821,6 +822,7 @@
|
|||||||
DAE4C98D157E63BE00EFE047 /* avatar-18.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE4C967157E63BE00EFE047 /* avatar-18.png */; };
|
DAE4C98D157E63BE00EFE047 /* avatar-18.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE4C967157E63BE00EFE047 /* avatar-18.png */; };
|
||||||
DAE4C98E157E63BE00EFE047 /* avatar-18@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE4C968157E63BE00EFE047 /* avatar-18@2x.png */; };
|
DAE4C98E157E63BE00EFE047 /* avatar-18@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE4C968157E63BE00EFE047 /* avatar-18@2x.png */; };
|
||||||
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
|
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
|
||||||
|
DAF02C5716C695F100489F65 /* MPElementListCellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DAF02C5616C695F100489F65 /* MPElementListCellView.xib */; };
|
||||||
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */; };
|
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 */; };
|
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 */; };
|
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */; };
|
||||||
@ -969,26 +971,30 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
|
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Indexing.m"; sourceTree = "<group>"; };
|
||||||
93D390B3209212B3049BEC2D /* MPAllSitesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAllSitesViewController.h; sourceTree = "<group>"; };
|
93D390B3209212B3049BEC2D /* MPElementListAllViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListAllViewController.h; sourceTree = "<group>"; };
|
||||||
93D390DABAE4368E90E37340 /* MPAppsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppsViewController.m; sourceTree = "<group>"; };
|
93D390DABAE4368E90E37340 /* MPAppsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppsViewController.m; sourceTree = "<group>"; };
|
||||||
93D3938863322199C3E7E2E3 /* MPAlgorithmV0.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV0.m; sourceTree = "<group>"; };
|
93D3938863322199C3E7E2E3 /* MPAlgorithmV0.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV0.m; sourceTree = "<group>"; };
|
||||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
|
||||||
|
93D393BB5C57D7FCC57A1999 /* MPElementListSearchController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListSearchController.h; sourceTree = "<group>"; };
|
||||||
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
|
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
|
||||||
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
|
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
|
||||||
|
93D394FF2CF2935332260C50 /* MPElementListSearchController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListSearchController.m; sourceTree = "<group>"; };
|
||||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
|
93D396D04E57792A54D437AC /* NSArray+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Indexing.h"; sourceTree = "<group>"; };
|
||||||
93D396E57F8AB8BCF00ADFF6 /* MPAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppViewController.h; sourceTree = "<group>"; };
|
93D396E57F8AB8BCF00ADFF6 /* MPAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppViewController.h; sourceTree = "<group>"; };
|
||||||
93D397CC23446E7E66640D82 /* MPAppsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppsViewController.h; sourceTree = "<group>"; };
|
93D397CC23446E7E66640D82 /* MPAppsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppsViewController.h; sourceTree = "<group>"; };
|
||||||
|
93D398BB1AD9781521B5AB56 /* MPElementListController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListController.h; sourceTree = "<group>"; };
|
||||||
93D398E394E311C545E0A057 /* MPAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithm.h; sourceTree = "<group>"; };
|
93D398E394E311C545E0A057 /* MPAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithm.h; sourceTree = "<group>"; };
|
||||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
|
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = "<group>"; };
|
||||||
93D39AAB616A652A4847E4CF /* MPAlgorithmV0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV0.h; sourceTree = "<group>"; };
|
93D39AAB616A652A4847E4CF /* MPAlgorithmV0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV0.h; sourceTree = "<group>"; };
|
||||||
93D39B0DF5E3C56355186738 /* MPAlgorithm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithm.m; sourceTree = "<group>"; };
|
93D39B0DF5E3C56355186738 /* MPAlgorithm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithm.m; sourceTree = "<group>"; };
|
||||||
|
93D39C56514D6DE72F5FB83E /* MPElementListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListController.m; sourceTree = "<group>"; };
|
||||||
93D39C68AFA48A13015E4FAC /* MPKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPKey.h; sourceTree = "<group>"; };
|
93D39C68AFA48A13015E4FAC /* MPKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPKey.h; sourceTree = "<group>"; };
|
||||||
93D39D0EF77FEC36EA0FB334 /* MPAlgorithmV1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV1.h; sourceTree = "<group>"; };
|
93D39D0EF77FEC36EA0FB334 /* MPAlgorithmV1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV1.h; sourceTree = "<group>"; };
|
||||||
93D39E070BD3F45B3045A1DA /* MPAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppViewController.m; sourceTree = "<group>"; };
|
93D39E070BD3F45B3045A1DA /* MPAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppViewController.m; sourceTree = "<group>"; };
|
||||||
93D39E81EFABC6085AC8AE69 /* MPKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPKey.m; sourceTree = "<group>"; };
|
93D39E81EFABC6085AC8AE69 /* MPKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPKey.m; sourceTree = "<group>"; };
|
||||||
93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV1.m; sourceTree = "<group>"; };
|
93D39E9D7B9005211E7D5262 /* MPAlgorithmV1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV1.m; sourceTree = "<group>"; };
|
||||||
93D39F16ADA770D8C13B4555 /* MPAllSitesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAllSitesViewController.m; sourceTree = "<group>"; };
|
93D39F16ADA770D8C13B4555 /* MPElementListAllViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementListAllViewController.m; sourceTree = "<group>"; };
|
||||||
93D39F37240730C6311B8FBD /* MPElementPickerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementPickerDelegate.h; sourceTree = "<group>"; };
|
93D39F37240730C6311B8FBD /* MPElementListDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementListDelegate.h; sourceTree = "<group>"; };
|
||||||
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; };
|
93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = "<group>"; };
|
||||||
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||||
DA0A1D0315690A9A0092735D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = Resources/Default.png; sourceTree = SOURCE_ROOT; };
|
DA0A1D0315690A9A0092735D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Default.png; path = Resources/Default.png; sourceTree = SOURCE_ROOT; };
|
||||||
@ -1218,8 +1224,6 @@
|
|||||||
DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGuideViewController.m; sourceTree = "<group>"; };
|
DAB8D44B15036BCF00CED3BC /* MPGuideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPGuideViewController.m; sourceTree = "<group>"; };
|
||||||
DAB8D44C15036BCF00CED3BC /* MPMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMainViewController.h; sourceTree = "<group>"; };
|
DAB8D44C15036BCF00CED3BC /* MPMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMainViewController.h; sourceTree = "<group>"; };
|
||||||
DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMainViewController.m; sourceTree = "<group>"; };
|
DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMainViewController.m; sourceTree = "<group>"; };
|
||||||
DAB8D44E15036BCF00CED3BC /* MPSearchDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSearchDelegate.h; sourceTree = "<group>"; };
|
|
||||||
DAB8D44F15036BCF00CED3BC /* MPSearchDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSearchDelegate.m; sourceTree = "<group>"; };
|
|
||||||
DAB8D45015036BCF00CED3BC /* MPTypeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTypeViewController.h; sourceTree = "<group>"; };
|
DAB8D45015036BCF00CED3BC /* MPTypeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTypeViewController.h; sourceTree = "<group>"; };
|
||||||
DAB8D45115036BCF00CED3BC /* MPTypeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTypeViewController.m; sourceTree = "<group>"; };
|
DAB8D45115036BCF00CED3BC /* MPTypeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTypeViewController.m; sourceTree = "<group>"; };
|
||||||
DAB8D45215036BCF00CED3BC /* MPUnlockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUnlockViewController.h; sourceTree = "<group>"; };
|
DAB8D45215036BCF00CED3BC /* MPUnlockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUnlockViewController.h; sourceTree = "<group>"; };
|
||||||
@ -1925,6 +1929,7 @@
|
|||||||
DAE4C967157E63BE00EFE047 /* avatar-18.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18.png"; sourceTree = "<group>"; };
|
DAE4C967157E63BE00EFE047 /* avatar-18.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18.png"; sourceTree = "<group>"; };
|
||||||
DAE4C968157E63BE00EFE047 /* avatar-18@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18@2x.png"; sourceTree = "<group>"; };
|
DAE4C968157E63BE00EFE047 /* avatar-18@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18@2x.png"; sourceTree = "<group>"; };
|
||||||
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||||
|
DAF02C5616C695F100489F65 /* MPElementListCellView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPElementListCellView.xib; sourceTree = "<group>"; };
|
||||||
DAF83D6B15E02E04009C8D49 /* MasterPassword 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 3.xcdatamodel"; sourceTree = "<group>"; };
|
DAF83D6B15E02E04009C8D49 /* MasterPassword 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 3.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+PearlExport.h"; 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>"; };
|
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+PearlExport.m"; sourceTree = "<group>"; };
|
||||||
@ -2517,6 +2522,7 @@
|
|||||||
children = (
|
children = (
|
||||||
DAB8D9B11503757D00CED3BC /* Supporting Files */,
|
DAB8D9B11503757D00CED3BC /* Supporting Files */,
|
||||||
DAB8D44215036BCF00CED3BC /* MainStoryboard_iPhone.storyboard */,
|
DAB8D44215036BCF00CED3BC /* MainStoryboard_iPhone.storyboard */,
|
||||||
|
DAF02C5616C695F100489F65 /* MPElementListCellView.xib */,
|
||||||
93D397CC23446E7E66640D82 /* MPAppsViewController.h */,
|
93D397CC23446E7E66640D82 /* MPAppsViewController.h */,
|
||||||
93D390DABAE4368E90E37340 /* MPAppsViewController.m */,
|
93D390DABAE4368E90E37340 /* MPAppsViewController.m */,
|
||||||
93D396E57F8AB8BCF00ADFF6 /* MPAppViewController.h */,
|
93D396E57F8AB8BCF00ADFF6 /* MPAppViewController.h */,
|
||||||
@ -2531,16 +2537,18 @@
|
|||||||
DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */,
|
DAB8D44D15036BCF00CED3BC /* MPMainViewController.m */,
|
||||||
DAC728C8157C247B00889EF2 /* MPPreferencesViewController.h */,
|
DAC728C8157C247B00889EF2 /* MPPreferencesViewController.h */,
|
||||||
DAC728C9157C247B00889EF2 /* MPPreferencesViewController.m */,
|
DAC728C9157C247B00889EF2 /* MPPreferencesViewController.m */,
|
||||||
DAB8D44E15036BCF00CED3BC /* MPSearchDelegate.h */,
|
|
||||||
DAB8D44F15036BCF00CED3BC /* MPSearchDelegate.m */,
|
|
||||||
DAB8D45015036BCF00CED3BC /* MPTypeViewController.h */,
|
DAB8D45015036BCF00CED3BC /* MPTypeViewController.h */,
|
||||||
DAB8D45115036BCF00CED3BC /* MPTypeViewController.m */,
|
DAB8D45115036BCF00CED3BC /* MPTypeViewController.m */,
|
||||||
DAB8D45215036BCF00CED3BC /* MPUnlockViewController.h */,
|
DAB8D45215036BCF00CED3BC /* MPUnlockViewController.h */,
|
||||||
DAB8D45315036BCF00CED3BC /* MPUnlockViewController.m */,
|
DAB8D45315036BCF00CED3BC /* MPUnlockViewController.m */,
|
||||||
DAB8D45415036BCF00CED3BC /* Settings.bundle */,
|
DAB8D45415036BCF00CED3BC /* Settings.bundle */,
|
||||||
93D39F16ADA770D8C13B4555 /* MPAllSitesViewController.m */,
|
93D39F16ADA770D8C13B4555 /* MPElementListAllViewController.m */,
|
||||||
93D390B3209212B3049BEC2D /* MPAllSitesViewController.h */,
|
93D390B3209212B3049BEC2D /* MPElementListAllViewController.h */,
|
||||||
93D39F37240730C6311B8FBD /* MPElementPickerDelegate.h */,
|
93D39F37240730C6311B8FBD /* MPElementListDelegate.h */,
|
||||||
|
93D39C56514D6DE72F5FB83E /* MPElementListController.m */,
|
||||||
|
93D398BB1AD9781521B5AB56 /* MPElementListController.h */,
|
||||||
|
93D393BB5C57D7FCC57A1999 /* MPElementListSearchController.h */,
|
||||||
|
93D394FF2CF2935332260C50 /* MPElementListSearchController.m */,
|
||||||
);
|
);
|
||||||
path = iOS;
|
path = iOS;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -4574,6 +4582,7 @@
|
|||||||
DAB90E9916BD951200D06F4A /* SourceCodePro-Black.otf in Resources */,
|
DAB90E9916BD951200D06F4A /* SourceCodePro-Black.otf in Resources */,
|
||||||
DAB90E9B16BD951200D06F4A /* SourceCodePro-ExtraLight.otf in Resources */,
|
DAB90E9B16BD951200D06F4A /* SourceCodePro-ExtraLight.otf in Resources */,
|
||||||
DAB90EA016BE1B4200D06F4A /* Exo-Bold.otf in Resources */,
|
DAB90EA016BE1B4200D06F4A /* Exo-Bold.otf in Resources */,
|
||||||
|
DAF02C5716C695F100489F65 /* MPElementListCellView.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -4689,7 +4698,6 @@
|
|||||||
DAB8D46415036BCF00CED3BC /* MPiOSConfig.m in Sources */,
|
DAB8D46415036BCF00CED3BC /* MPiOSConfig.m in Sources */,
|
||||||
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */,
|
DAB8D46515036BCF00CED3BC /* MPGuideViewController.m in Sources */,
|
||||||
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */,
|
DAB8D46615036BCF00CED3BC /* MPMainViewController.m in Sources */,
|
||||||
DAB8D46715036BCF00CED3BC /* MPSearchDelegate.m in Sources */,
|
|
||||||
DAB8D46815036BCF00CED3BC /* MPTypeViewController.m in Sources */,
|
DAB8D46815036BCF00CED3BC /* MPTypeViewController.m in Sources */,
|
||||||
DAB8D46915036BCF00CED3BC /* MPUnlockViewController.m in Sources */,
|
DAB8D46915036BCF00CED3BC /* MPUnlockViewController.m in Sources */,
|
||||||
DA600C2515054F3A008E9AB6 /* MPAppDelegate_Key.m in Sources */,
|
DA600C2515054F3A008E9AB6 /* MPAppDelegate_Key.m in Sources */,
|
||||||
@ -4708,7 +4716,9 @@
|
|||||||
DA81253816B8546B00F4732F /* MPElementStoredEntity.m in Sources */,
|
DA81253816B8546B00F4732F /* MPElementStoredEntity.m in Sources */,
|
||||||
DA81253B16B8546B00F4732F /* MPUserEntity.m in Sources */,
|
DA81253B16B8546B00F4732F /* MPUserEntity.m in Sources */,
|
||||||
DA81253E16B8546C00F4732F /* MPElementGeneratedEntity.m in Sources */,
|
DA81253E16B8546C00F4732F /* MPElementGeneratedEntity.m in Sources */,
|
||||||
93D39BD0F5C7C76678712500 /* MPAllSitesViewController.m in Sources */,
|
93D39BD0F5C7C76678712500 /* MPElementListAllViewController.m in Sources */,
|
||||||
|
93D3944DE5E21C69AA8CC6D4 /* MPElementListController.m in Sources */,
|
||||||
|
93D3995C0452184780AECD0C /* MPElementListSearchController.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -50,8 +50,8 @@
|
|||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
@ -553,8 +553,7 @@ static char privateManagedObjectContextKey, mainManagedObjectContextKey;
|
|||||||
NSString *exportContent = [siteElements objectAtIndex:5];
|
NSString *exportContent = [siteElements objectAtIndex:5];
|
||||||
|
|
||||||
// Create new site.
|
// Create new site.
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmForVersion(
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmForVersion(version) classNameOfType:type]
|
||||||
version) classNameOfType:type]
|
|
||||||
inManagedObjectContext:moc];
|
inManagedObjectContext:moc];
|
||||||
element.name = name;
|
element.name = name;
|
||||||
element.user = user;
|
element.user = user;
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
err(@"While saving %@: %@", NSStringFromClass([self class]), error);
|
err(@"While saving %@: %@", NSStringFromClass([self class]), error);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
if (![moc.parentContext save:&error]) {
|
||||||
|
err(@"While saving parent %@: %@", NSStringFromClass([self class]), error);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@ -29,11 +33,24 @@
|
|||||||
|
|
||||||
- (MPElementType)type {
|
- (MPElementType)type {
|
||||||
|
|
||||||
return (MPElementType)[self.type_ unsignedIntegerValue];
|
// Some people got elements with type == 0.
|
||||||
|
MPElementType type = (MPElementType)[self.type_ unsignedIntegerValue];
|
||||||
|
if (!type || type == NSNotFound)
|
||||||
|
type = [self.user defaultType];
|
||||||
|
if (!type || type == NSNotFound)
|
||||||
|
type = MPElementTypeGeneratedLong;
|
||||||
|
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setType:(MPElementType)aType {
|
- (void)setType:(MPElementType)aType {
|
||||||
|
|
||||||
|
// Make sure we don't poison our model data with invalid values.
|
||||||
|
if (!aType || aType == NSNotFound)
|
||||||
|
aType = [self.user defaultType];
|
||||||
|
if (!aType || aType == NSNotFound)
|
||||||
|
aType = MPElementTypeGeneratedLong;
|
||||||
|
|
||||||
self.type_ = @(aType);
|
self.type_ = @(aType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,283 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
|
|
||||||
*
|
|
||||||
* See the enclosed file LICENSE for license information (LGPLv3). If you did
|
|
||||||
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
|
|
||||||
*
|
|
||||||
* @author Maarten Billemont <lhunath@lyndir.com>
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
//
|
|
||||||
// MPAllSitesViewController
|
|
||||||
//
|
|
||||||
// Created by Maarten Billemont on 2013-01-31.
|
|
||||||
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MPAllSitesViewController.h"
|
|
||||||
|
|
||||||
#import "MPAppDelegate.h"
|
|
||||||
#import "MPAppDelegate_Store.h"
|
|
||||||
|
|
||||||
|
|
||||||
@interface MPAllSitesViewController() <NSFetchedResultsControllerDelegate>
|
|
||||||
|
|
||||||
@property (nonatomic,strong)NSDateFormatter *dateFormatter;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MPAllSitesViewController {
|
|
||||||
|
|
||||||
NSFetchedResultsController *_fetchedResultsController;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
|
||||||
|
|
||||||
[super viewDidLoad];
|
|
||||||
|
|
||||||
self.dateFormatter = [NSDateFormatter new];
|
|
||||||
self.dateFormatter.dateStyle = NSDateFormatterShortStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)close:(id)sender {
|
|
||||||
|
|
||||||
[self dismissViewControllerAnimated:YES completion:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (IBAction)add:(id)sender {
|
|
||||||
|
|
||||||
[PearlAlert showAlertWithTitle:@"Add Site" message:nil viewStyle:UIAlertViewStylePlainTextInput initAlert:nil
|
|
||||||
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
||||||
if (alert.cancelButtonIndex == buttonIndex)
|
|
||||||
return;
|
|
||||||
|
|
||||||
NSString *siteName = [alert textFieldAtIndex:0].text;
|
|
||||||
if (![siteName length])
|
|
||||||
return;
|
|
||||||
|
|
||||||
[MPAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
|
||||||
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserInContext:moc];
|
|
||||||
assert(activeUser);
|
|
||||||
|
|
||||||
MPElementType type = activeUser.defaultType;
|
|
||||||
if (!type)
|
|
||||||
type = activeUser.defaultType = MPElementTypeGeneratedLong;
|
|
||||||
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
|
|
||||||
|
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
|
|
||||||
inManagedObjectContext:moc];
|
|
||||||
|
|
||||||
element.name = siteName;
|
|
||||||
element.user = activeUser;
|
|
||||||
element.type = type;
|
|
||||||
element.lastUsed = [NSDate date];
|
|
||||||
element.version = MPAlgorithmDefaultVersion;
|
|
||||||
[element saveContext];
|
|
||||||
|
|
||||||
NSManagedObjectID *elementOID = [element objectID];
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
MPElementEntity *element_ = (MPElementEntity *)[[MPAppDelegate managedObjectContextForThreadIfReady]
|
|
||||||
objectRegisteredForID:elementOID];
|
|
||||||
[self.delegate didSelectElement:element_];
|
|
||||||
[self close:nil];
|
|
||||||
});
|
|
||||||
}];
|
|
||||||
|
|
||||||
}
|
|
||||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSFetchedResultsController *)fetchedResultsController {
|
|
||||||
|
|
||||||
if (!_fetchedResultsController) {
|
|
||||||
NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must run on the main thread.");
|
|
||||||
NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady];
|
|
||||||
if (!moc)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
|
||||||
fetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]];
|
|
||||||
fetchRequest.fetchBatchSize = 20;
|
|
||||||
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc
|
|
||||||
sectionNameKeyPath:nil cacheName:nil];
|
|
||||||
_fetchedResultsController.delegate = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _fetchedResultsController;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)fetchData {
|
|
||||||
|
|
||||||
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
|
|
||||||
if (!activeUser)
|
|
||||||
return;
|
|
||||||
|
|
||||||
self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
|
|
||||||
|
|
||||||
NSError *error;
|
|
||||||
if (![self.fetchedResultsController performFetch:&error])
|
|
||||||
err(@"Couldn't fetch elements: %@", error);
|
|
||||||
|
|
||||||
[self.tableView reloadData];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated {
|
|
||||||
|
|
||||||
[super viewWillAppear:animated];
|
|
||||||
|
|
||||||
[self fetchData];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// See MP-14, also crashes easily on internal assertions etc..
|
|
||||||
//- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
|
|
||||||
//
|
|
||||||
// [self.searchDisplayController.searchResultsTableView beginUpdates];
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
|
|
||||||
// atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
|
|
||||||
//
|
|
||||||
// UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
|
||||||
// switch(type) {
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeInsert:
|
|
||||||
// [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeDelete:
|
|
||||||
// [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeUpdate:
|
|
||||||
// [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
|
|
||||||
// inTableView:tableView atIndexPath:indexPath];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeMove:
|
|
||||||
// [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
|
|
||||||
// atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
|
||||||
//
|
|
||||||
// UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
|
||||||
// switch(type) {
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeInsert:
|
|
||||||
// [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeDelete:
|
|
||||||
// [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
|
||||||
|
|
||||||
dbg(@"controllerDidChangeContent on thread: %@", [NSThread currentThread].name);
|
|
||||||
[self.tableView reloadData];
|
|
||||||
//[self.tableView endUpdates];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
|
||||||
|
|
||||||
return (NSInteger)[[self.fetchedResultsController sections] count];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
||||||
|
|
||||||
return (NSInteger)[[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] numberOfObjects];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MPElementSearch"];
|
|
||||||
if (!cell.backgroundView) {
|
|
||||||
// cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MPElementSearch"];
|
|
||||||
|
|
||||||
UIImage *backgroundImage = [[UIImage imageNamed:@"ui_list_middle"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)
|
|
||||||
resizingMode:UIImageResizingModeStretch];
|
|
||||||
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
|
|
||||||
backgroundImageView.frame = CGRectMake(-5, 0, 330, 34);
|
|
||||||
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 34)];
|
|
||||||
[backgroundView addSubview:backgroundImageView];
|
|
||||||
backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
|
|
||||||
cell.backgroundView = backgroundView;
|
|
||||||
// cell.textLabel.backgroundColor = [UIColor clearColor];
|
|
||||||
// cell.textLabel.textColor = [UIColor whiteColor];
|
|
||||||
// cell.detailTextLabel.backgroundColor = [UIColor clearColor];
|
|
||||||
// cell.detailTextLabel.textColor = [UIColor lightGrayColor];
|
|
||||||
// cell.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
// cell.clipsToBounds = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self configureCell:cell inTableView:tableView atIndexPath:indexPath];
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
|
||||||
|
|
||||||
cell.textLabel.text = element.name;
|
|
||||||
cell.detailTextLabel.text = PearlString(@"%d views, last on %@: %@",
|
|
||||||
element.uses, [self.dateFormatter stringFromDate:element.lastUsed], [element.algorithm shortNameOfType:element.type]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
[self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]];
|
|
||||||
[self close:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
|
||||||
|
|
||||||
return [[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] name];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
|
|
||||||
|
|
||||||
return [self.fetchedResultsController sectionIndexTitles];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
|
|
||||||
|
|
||||||
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
|
|
||||||
forRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
|
||||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
|
||||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
|
||||||
|
|
||||||
inf(@"Deleting element: %@", element.name);
|
|
||||||
[self.fetchedResultsController.managedObjectContext deleteObject:element];
|
|
||||||
|
|
||||||
#ifdef TESTFLIGHT_SDK_VERSION
|
|
||||||
[TestFlight passCheckpoint:MPCheckpointDeleteElement];
|
|
||||||
#endif
|
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointDeleteElement attributes:@{
|
|
||||||
@"type" : element.typeName,
|
|
||||||
@"version" : @(element.version)}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
|
@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
// MPAllSitesViewController
|
// MPElementListAllViewController
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 2013-01-31.
|
// Created by Maarten Billemont on 2013-01-31.
|
||||||
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
|
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
|
||||||
@ -17,11 +17,9 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import "MPElementPickerDelegate.h"
|
#import "MPElementListController.h"
|
||||||
|
|
||||||
@interface MPAllSitesViewController : UITableViewController
|
@interface MPElementListAllViewController : MPElementListController
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet id<MPElementPickerDelegate> delegate;
|
|
||||||
|
|
||||||
- (IBAction)close:(id)sender;
|
- (IBAction)close:(id)sender;
|
||||||
- (IBAction)add:(id)sender;
|
- (IBAction)add:(id)sender;
|
56
MasterPassword/iOS/MPElementListAllViewController.m
Normal file
56
MasterPassword/iOS/MPElementListAllViewController.m
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
|
||||||
|
*
|
||||||
|
* See the enclosed file LICENSE for license information (LGPLv3). If you did
|
||||||
|
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
*
|
||||||
|
* @author Maarten Billemont <lhunath@lyndir.com>
|
||||||
|
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPElementListAllViewController
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 2013-01-31.
|
||||||
|
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPElementListAllViewController.h"
|
||||||
|
|
||||||
|
@implementation MPElementListAllViewController
|
||||||
|
|
||||||
|
- (IBAction)close:(id)sender {
|
||||||
|
|
||||||
|
[self dismissViewControllerAnimated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)add:(id)sender {
|
||||||
|
|
||||||
|
[PearlAlert showAlertWithTitle:@"Add Site" message:nil viewStyle:UIAlertViewStylePlainTextInput initAlert:nil
|
||||||
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
||||||
|
if (alert.cancelButtonIndex == buttonIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
__weak MPElementListAllViewController *wSelf = self;
|
||||||
|
[self addElementNamed:[alert textFieldAtIndex:0].text completion:^(BOOL success) {
|
||||||
|
if (success)
|
||||||
|
[wSelf close:nil];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
|
||||||
|
[self updateData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
|
||||||
|
[self close:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
259
MasterPassword/iOS/MPElementListCellView.xib
Normal file
259
MasterPassword/iOS/MPElementListCellView.xib
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
|
||||||
|
<data>
|
||||||
|
<int key="IBDocument.SystemTarget">1552</int>
|
||||||
|
<string key="IBDocument.SystemVersion">12C60</string>
|
||||||
|
<string key="IBDocument.InterfaceBuilderVersion">3084</string>
|
||||||
|
<string key="IBDocument.AppKitVersion">1187.34</string>
|
||||||
|
<string key="IBDocument.HIToolboxVersion">625.00</string>
|
||||||
|
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||||
|
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
<string key="NS.object.0">2083</string>
|
||||||
|
</object>
|
||||||
|
<array key="IBDocument.IntegratedClassDependencies">
|
||||||
|
<string>IBProxyObject</string>
|
||||||
|
<string>IBUIImageView</string>
|
||||||
|
<string>IBUILabel</string>
|
||||||
|
<string>IBUITableViewCell</string>
|
||||||
|
</array>
|
||||||
|
<array key="IBDocument.PluginDependencies">
|
||||||
|
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
</array>
|
||||||
|
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||||
|
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||||
|
<integer value="1" key="NS.object.0"/>
|
||||||
|
</object>
|
||||||
|
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||||
|
<object class="IBProxyObject" id="372490531">
|
||||||
|
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||||
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
</object>
|
||||||
|
<object class="IBProxyObject" id="975951072">
|
||||||
|
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||||
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
</object>
|
||||||
|
<object class="IBUITableViewCell" id="1072502652">
|
||||||
|
<reference key="NSNextResponder"/>
|
||||||
|
<int key="NSvFlags">1280</int>
|
||||||
|
<array class="NSMutableArray" key="NSSubviews">
|
||||||
|
<object class="IBUIView" id="70825627">
|
||||||
|
<reference key="NSNextResponder" ref="1072502652"/>
|
||||||
|
<int key="NSvFlags">1280</int>
|
||||||
|
<array class="NSMutableArray" key="NSSubviews">
|
||||||
|
<object class="IBUILabel" id="169671678">
|
||||||
|
<reference key="NSNextResponder" ref="70825627"/>
|
||||||
|
<int key="NSvFlags">1280</int>
|
||||||
|
<object class="NSPSMatrix" key="NSFrameMatrix"/>
|
||||||
|
<string key="NSFrame">{{10, 4}, {38, 22}}</string>
|
||||||
|
<reference key="NSSuperview" ref="70825627"/>
|
||||||
|
<reference key="NSWindow"/>
|
||||||
|
<reference key="NSNextKeyView" ref="35578451"/>
|
||||||
|
<object class="NSColor" key="IBUIBackgroundColor" id="801193159">
|
||||||
|
<int key="NSColorSpace">3</int>
|
||||||
|
<bytes key="NSWhite">MCAwAA</bytes>
|
||||||
|
</object>
|
||||||
|
<bool key="IBUIOpaque">NO</bool>
|
||||||
|
<bool key="IBUIClipsSubviews">YES</bool>
|
||||||
|
<int key="IBUIContentMode">7</int>
|
||||||
|
<bool key="IBUIMultipleTouchEnabled">YES</bool>
|
||||||
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
<string key="IBUIText">Title</string>
|
||||||
|
<object class="NSColor" key="IBUITextColor">
|
||||||
|
<int key="NSColorSpace">3</int>
|
||||||
|
<bytes key="NSWhite">MQA</bytes>
|
||||||
|
</object>
|
||||||
|
<object class="NSColor" key="IBUIHighlightedColor" id="748798155">
|
||||||
|
<int key="NSColorSpace">1</int>
|
||||||
|
<bytes key="NSRGB">MSAxIDEAA</bytes>
|
||||||
|
</object>
|
||||||
|
<int key="IBUIBaselineAdjustment">0</int>
|
||||||
|
<object class="IBUIFontDescription" key="IBUIFontDescription">
|
||||||
|
<int key="type">2</int>
|
||||||
|
<double key="pointSize">18</double>
|
||||||
|
</object>
|
||||||
|
<object class="NSFont" key="IBUIFont">
|
||||||
|
<string key="NSName">Helvetica-Bold</string>
|
||||||
|
<double key="NSSize">18</double>
|
||||||
|
<int key="NSfFlags">16</int>
|
||||||
|
</object>
|
||||||
|
<bool key="IBUIAdjustsFontSizeToFit">NO</bool>
|
||||||
|
</object>
|
||||||
|
<object class="IBUILabel" id="35578451">
|
||||||
|
<reference key="NSNextResponder" ref="70825627"/>
|
||||||
|
<int key="NSvFlags">1280</int>
|
||||||
|
<object class="NSPSMatrix" key="NSFrameMatrix"/>
|
||||||
|
<string key="NSFrame">{{10, 26}, {47, 18}}</string>
|
||||||
|
<reference key="NSSuperview" ref="70825627"/>
|
||||||
|
<reference key="NSWindow"/>
|
||||||
|
<reference key="IBUIBackgroundColor" ref="801193159"/>
|
||||||
|
<bool key="IBUIOpaque">NO</bool>
|
||||||
|
<bool key="IBUIClipsSubviews">YES</bool>
|
||||||
|
<int key="IBUIContentMode">7</int>
|
||||||
|
<bool key="IBUIMultipleTouchEnabled">YES</bool>
|
||||||
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
<string key="IBUIText">Subtitle</string>
|
||||||
|
<object class="NSColor" key="IBUITextColor">
|
||||||
|
<int key="NSColorSpace">3</int>
|
||||||
|
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
|
||||||
|
</object>
|
||||||
|
<reference key="IBUIHighlightedColor" ref="748798155"/>
|
||||||
|
<int key="IBUIBaselineAdjustment">0</int>
|
||||||
|
<object class="IBUIFontDescription" key="IBUIFontDescription">
|
||||||
|
<int key="type">1</int>
|
||||||
|
<double key="pointSize">14</double>
|
||||||
|
</object>
|
||||||
|
<object class="NSFont" key="IBUIFont">
|
||||||
|
<string key="NSName">Helvetica</string>
|
||||||
|
<double key="NSSize">14</double>
|
||||||
|
<int key="NSfFlags">16</int>
|
||||||
|
</object>
|
||||||
|
<bool key="IBUIAdjustsFontSizeToFit">NO</bool>
|
||||||
|
</object>
|
||||||
|
</array>
|
||||||
|
<object class="NSPSMatrix" key="NSFrameMatrix"/>
|
||||||
|
<string key="NSFrameSize">{320, 47}</string>
|
||||||
|
<reference key="NSSuperview" ref="1072502652"/>
|
||||||
|
<reference key="NSWindow"/>
|
||||||
|
<reference key="NSNextKeyView" ref="169671678"/>
|
||||||
|
<reference key="IBUIBackgroundColor" ref="801193159"/>
|
||||||
|
<bool key="IBUIOpaque">NO</bool>
|
||||||
|
<bool key="IBUIClipsSubviews">YES</bool>
|
||||||
|
<int key="IBUIContentMode">4</int>
|
||||||
|
<bool key="IBUIMultipleTouchEnabled">YES</bool>
|
||||||
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
</object>
|
||||||
|
</array>
|
||||||
|
<object class="NSPSMatrix" key="NSFrameMatrix"/>
|
||||||
|
<string key="NSFrameSize">{320, 48}</string>
|
||||||
|
<reference key="NSSuperview"/>
|
||||||
|
<reference key="NSWindow"/>
|
||||||
|
<reference key="NSNextKeyView" ref="70825627"/>
|
||||||
|
<object class="NSColor" key="IBUIBackgroundColor">
|
||||||
|
<int key="NSColorSpace">3</int>
|
||||||
|
<bytes key="NSWhite">MAA</bytes>
|
||||||
|
</object>
|
||||||
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
<bool key="IBUIHidesAccessoryWhenEditing">NO</bool>
|
||||||
|
<int key="IBUIIndentationLevel">1</int>
|
||||||
|
<float key="IBUIIndentationWidth">0.0</float>
|
||||||
|
<reference key="IBUIContentView" ref="70825627"/>
|
||||||
|
<string key="IBUIReuseIdentifier">MPElementListCell</string>
|
||||||
|
<integer value="3" key="IBUIStyle"/>
|
||||||
|
<reference key="IBUITextLabel" ref="169671678"/>
|
||||||
|
<reference key="IBUIDetailTextLabel" ref="35578451"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBUIImageView" id="410525493">
|
||||||
|
<reference key="NSNextResponder"/>
|
||||||
|
<int key="NSvFlags">274</int>
|
||||||
|
<string key="NSFrameSize">{320, 48}</string>
|
||||||
|
<reference key="NSSuperview"/>
|
||||||
|
<reference key="NSWindow"/>
|
||||||
|
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||||
|
<reference key="IBUIBackgroundColor" ref="801193159"/>
|
||||||
|
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
||||||
|
<string key="IBUIContentStretch">{{0.10000000000000001, 0.10000000000000001}, {0.79999999999999982, 0.79999999999999982}}</string>
|
||||||
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
<object class="NSCustomResource" key="IBUIImage">
|
||||||
|
<string key="NSClassName">NSImage</string>
|
||||||
|
<string key="NSResourceName">ui_list_middle.png</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</array>
|
||||||
|
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||||
|
<array class="NSMutableArray" key="connectionRecords">
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||||
|
<string key="label">view</string>
|
||||||
|
<reference key="source" ref="372490531"/>
|
||||||
|
<reference key="destination" ref="1072502652"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">11</int>
|
||||||
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||||
|
<string key="label">backgroundView</string>
|
||||||
|
<reference key="source" ref="1072502652"/>
|
||||||
|
<reference key="destination" ref="410525493"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">10</int>
|
||||||
|
</object>
|
||||||
|
</array>
|
||||||
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
|
<array key="orderedObjects">
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">0</int>
|
||||||
|
<array key="object" id="0"/>
|
||||||
|
<reference key="children" ref="1000"/>
|
||||||
|
<nil key="parent"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">-1</int>
|
||||||
|
<reference key="object" ref="372490531"/>
|
||||||
|
<reference key="parent" ref="0"/>
|
||||||
|
<string key="objectName">File's Owner</string>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">-2</int>
|
||||||
|
<reference key="object" ref="975951072"/>
|
||||||
|
<reference key="parent" ref="0"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">4</int>
|
||||||
|
<reference key="object" ref="1072502652"/>
|
||||||
|
<array class="NSMutableArray" key="children">
|
||||||
|
<reference ref="35578451"/>
|
||||||
|
<reference ref="169671678"/>
|
||||||
|
</array>
|
||||||
|
<reference key="parent" ref="0"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">5</int>
|
||||||
|
<reference key="object" ref="35578451"/>
|
||||||
|
<reference key="parent" ref="1072502652"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">6</int>
|
||||||
|
<reference key="object" ref="169671678"/>
|
||||||
|
<reference key="parent" ref="1072502652"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">8</int>
|
||||||
|
<reference key="object" ref="410525493"/>
|
||||||
|
<reference key="parent" ref="0"/>
|
||||||
|
</object>
|
||||||
|
</array>
|
||||||
|
</object>
|
||||||
|
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
||||||
|
<string key="-1.CustomClassName">UIViewController</string>
|
||||||
|
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
<string key="-2.CustomClassName">UIResponder</string>
|
||||||
|
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
<string key="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
<reference key="4.IBUserGuides" ref="0"/>
|
||||||
|
<boolean value="NO" key="4.showNotes"/>
|
||||||
|
<string key="5.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
<reference key="5.IBUserGuides" ref="0"/>
|
||||||
|
<boolean value="NO" key="5.showNotes"/>
|
||||||
|
<string key="6.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
<reference key="6.IBUserGuides" ref="0"/>
|
||||||
|
<boolean value="NO" key="6.showNotes"/>
|
||||||
|
<string key="8.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||||
|
</dictionary>
|
||||||
|
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
|
||||||
|
<nil key="activeLocalization"/>
|
||||||
|
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||||
|
<nil key="sourceID"/>
|
||||||
|
<int key="maxID">11</int>
|
||||||
|
</object>
|
||||||
|
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||||
|
<int key="IBDocument.localizationMode">0</int>
|
||||||
|
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
|
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||||
|
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||||
|
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
||||||
|
<string key="NS.key.0">ui_list_middle.png</string>
|
||||||
|
<string key="NS.object.0">{300, 34}</string>
|
||||||
|
</object>
|
||||||
|
<string key="IBCocoaTouchPluginVersion">2083</string>
|
||||||
|
</data>
|
||||||
|
</archive>
|
28
MasterPassword/iOS/MPElementListController.h
Normal file
28
MasterPassword/iOS/MPElementListController.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by lhunath on 2013-02-09.
|
||||||
|
//
|
||||||
|
// To change the template use AppCode | Preferences | File Templates.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "MPElementListDelegate.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MPSearchScopeAll,
|
||||||
|
MPSearchScopeOutdated,
|
||||||
|
} MPSearchScope;
|
||||||
|
|
||||||
|
@interface MPElementListController : UITableViewController <NSFetchedResultsControllerDelegate>
|
||||||
|
|
||||||
|
@property (weak, nonatomic) IBOutlet id<MPElementListDelegate> delegate;
|
||||||
|
@property (readonly) NSFetchedResultsController *fetchedResultsController;
|
||||||
|
@property (readonly) NSDateFormatter *dateFormatter;
|
||||||
|
|
||||||
|
- (void)updateData;
|
||||||
|
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(BOOL success))completion;
|
||||||
|
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
- (void)customTableViewUpdates;
|
||||||
|
|
||||||
|
@end
|
269
MasterPassword/iOS/MPElementListController.m
Normal file
269
MasterPassword/iOS/MPElementListController.m
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
//
|
||||||
|
// Created by lhunath on 2013-02-09.
|
||||||
|
//
|
||||||
|
// To change the template use AppCode | Preferences | File Templates.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#import "MPElementListController.h"
|
||||||
|
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "MPAppDelegate.h"
|
||||||
|
|
||||||
|
@interface MPElementListController ()
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPElementListController {
|
||||||
|
|
||||||
|
NSFetchedResultsController *_fetchedResultsController;
|
||||||
|
NSDateFormatter *_dateFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addElementNamed:(NSString *)siteName completion:(void(^)(BOOL success))completion {
|
||||||
|
|
||||||
|
if (![siteName length]) {
|
||||||
|
if (completion)
|
||||||
|
completion(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MPAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
|
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserInContext:moc];
|
||||||
|
assert(activeUser);
|
||||||
|
|
||||||
|
MPElementType type = activeUser.defaultType;
|
||||||
|
if (!type)
|
||||||
|
type = activeUser.defaultType = MPElementTypeGeneratedLong;
|
||||||
|
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
|
||||||
|
|
||||||
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
|
||||||
|
inManagedObjectContext:moc];
|
||||||
|
|
||||||
|
element.name = siteName;
|
||||||
|
element.user = activeUser;
|
||||||
|
element.type = type;
|
||||||
|
element.lastUsed = [NSDate date];
|
||||||
|
element.version = MPAlgorithmDefaultVersion;
|
||||||
|
[element saveContext];
|
||||||
|
|
||||||
|
NSManagedObjectID *elementOID = [element objectID];
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
MPElementEntity *element_ = (MPElementEntity *) [[MPAppDelegate managedObjectContextForThreadIfReady]
|
||||||
|
objectRegisteredForID:elementOID];
|
||||||
|
[self.delegate didSelectElement:element_];
|
||||||
|
if (completion)
|
||||||
|
completion(true);
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSFetchedResultsController *)fetchedResultsController {
|
||||||
|
|
||||||
|
if (!_fetchedResultsController) {
|
||||||
|
NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must run on the main thread.");
|
||||||
|
NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady];
|
||||||
|
if (!moc)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
||||||
|
fetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]];
|
||||||
|
fetchRequest.fetchBatchSize = 20;
|
||||||
|
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc
|
||||||
|
sectionNameKeyPath:nil cacheName:nil];
|
||||||
|
_fetchedResultsController.delegate = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _fetchedResultsController;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDateFormatter *)dateFormatter {
|
||||||
|
|
||||||
|
if (!_dateFormatter)
|
||||||
|
(_dateFormatter = [NSDateFormatter new]).dateStyle = NSDateFormatterShortStyle;
|
||||||
|
|
||||||
|
return _dateFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateData {
|
||||||
|
|
||||||
|
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
|
||||||
|
if (!activeUser)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Build predicate.
|
||||||
|
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@", activeUser];
|
||||||
|
UISearchBar *searchBar = self.searchDisplayController.searchBar;
|
||||||
|
if (searchBar) {
|
||||||
|
NSString *query = [searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
if (!query)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Add query predicate.
|
||||||
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
|
||||||
|
@[predicate, [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", query]]];
|
||||||
|
|
||||||
|
// Add scope predicate.
|
||||||
|
switch ((MPSearchScope) searchBar.selectedScopeButtonIndex) {
|
||||||
|
|
||||||
|
case MPSearchScopeAll:
|
||||||
|
break;
|
||||||
|
case MPSearchScopeOutdated:
|
||||||
|
predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
|
||||||
|
@[[NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], predicate]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.fetchedResultsController.fetchRequest.predicate = predicate;
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
if (![self.fetchedResultsController performFetch:&error])
|
||||||
|
err(@"Couldn't fetch elements: %@", error);
|
||||||
|
else
|
||||||
|
[self.tableView reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)customTableViewUpdates {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// See MP-14, also crashes easily on internal assertions etc..
|
||||||
|
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
|
||||||
|
|
||||||
|
dbg(@"%@", NSStringFromSelector(_cmd));
|
||||||
|
[self.tableView beginUpdates];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
|
||||||
|
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case NSFetchedResultsChangeInsert:
|
||||||
|
dbg(@"%@ -- NSFetchedResultsChangeInsert:%@", NSStringFromSelector(_cmd), anObject);
|
||||||
|
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSFetchedResultsChangeDelete:
|
||||||
|
dbg(@"%@ -- NSFetchedResultsChangeDelete:%@", NSStringFromSelector(_cmd), anObject);
|
||||||
|
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSFetchedResultsChangeUpdate:
|
||||||
|
dbg(@"%@ -- NSFetchedResultsChangeUpdate:%@", NSStringFromSelector(_cmd), anObject);
|
||||||
|
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSFetchedResultsChangeMove:
|
||||||
|
dbg(@"%@ -- NSFetchedResultsChangeMove:%@", NSStringFromSelector(_cmd), anObject);
|
||||||
|
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
|
||||||
|
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
|
||||||
|
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
|
||||||
|
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case NSFetchedResultsChangeInsert:
|
||||||
|
dbg(@"%@ -- NSFetchedResultsChangeInsert:%d", NSStringFromSelector(_cmd), sectionIndex);
|
||||||
|
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
||||||
|
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSFetchedResultsChangeDelete:
|
||||||
|
dbg(@"%@ -- NSFetchedResultsChangeDelete:%d", NSStringFromSelector(_cmd), sectionIndex);
|
||||||
|
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
||||||
|
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSFetchedResultsChangeMove:
|
||||||
|
case NSFetchedResultsChangeUpdate:
|
||||||
|
Throw(@"Invalid change type for section changes: %d", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
||||||
|
|
||||||
|
dbg(@"%@ on %@", NSStringFromSelector(_cmd), [NSThread currentThread].name);
|
||||||
|
[self customTableViewUpdates];
|
||||||
|
[self.tableView endUpdates];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||||
|
|
||||||
|
NSInteger integer = (NSInteger)[[self.fetchedResultsController sections] count];
|
||||||
|
dbg(@"%@ = %d", NSStringFromSelector(_cmd), integer);
|
||||||
|
return integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
NSInteger integer = (NSInteger)[[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] numberOfObjects];
|
||||||
|
dbg(@"%@%d = %d", NSStringFromSelector(_cmd), section, integer);
|
||||||
|
return integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MPElementListCell"];
|
||||||
|
if (!cell)
|
||||||
|
cell = (UITableViewCell *) [[UIViewController alloc] initWithNibName:@"MPElementListCellView" bundle:nil].view;
|
||||||
|
|
||||||
|
[self configureCell:cell inTableView:tableView atIndexPath:indexPath];
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||||
|
|
||||||
|
cell.textLabel.text = element.name;
|
||||||
|
cell.detailTextLabel.text = PearlString(@"%d views, last on %@: %@",
|
||||||
|
element.uses, [self.dateFormatter stringFromDate:element.lastUsed], [element.algorithm shortNameOfType:element.type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
[self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
return [[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] name];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
|
||||||
|
|
||||||
|
return [self.fetchedResultsController sectionIndexTitles];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
|
||||||
|
|
||||||
|
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
|
||||||
|
forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||||
|
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||||
|
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||||
|
|
||||||
|
inf(@"Deleting element: %@", element.name);
|
||||||
|
[self.fetchedResultsController.managedObjectContext deleteObject:element];
|
||||||
|
|
||||||
|
#ifdef TESTFLIGHT_SDK_VERSION
|
||||||
|
[TestFlight passCheckpoint:MPCheckpointDeleteElement];
|
||||||
|
#endif
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointDeleteElement attributes:@{
|
||||||
|
@"type" : element.typeName,
|
||||||
|
@"version" : @(element.version)}];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
// MPElementPickerDelegate
|
// MPElementListDelegate
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 2013-01-31.
|
// Created by Maarten Billemont on 2013-01-31.
|
||||||
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
|
// Copyright 2013 lhunath (Maarten Billemont). All rights reserved.
|
||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#import "MPElementEntity.h"
|
#import "MPElementEntity.h"
|
||||||
|
|
||||||
@protocol MPElementPickerDelegate<NSObject>
|
@protocol MPElementListDelegate <NSObject>
|
||||||
|
|
||||||
- (void)didSelectElement:(MPElementEntity *)element;
|
- (void)didSelectElement:(MPElementEntity *)element;
|
||||||
|
|
19
MasterPassword/iOS/MPElementListSearchController.h
Normal file
19
MasterPassword/iOS/MPElementListSearchController.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// MPSearchDelegate.h
|
||||||
|
// MasterPassword
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 04/01/12.
|
||||||
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPElementListController.h"
|
||||||
|
|
||||||
|
@interface MPElementListSearchController : MPElementListController<UISearchBarDelegate, UISearchDisplayDelegate>
|
||||||
|
|
||||||
|
@property (strong, nonatomic) UILabel *tipView;
|
||||||
|
|
||||||
|
@property (strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
|
||||||
|
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
|
||||||
|
|
||||||
|
@end
|
259
MasterPassword/iOS/MPElementListSearchController.m
Normal file
259
MasterPassword/iOS/MPElementListSearchController.m
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
//
|
||||||
|
// MPSearchDelegate.m
|
||||||
|
// MasterPassword
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 04/01/12.
|
||||||
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPElementListSearchController.h"
|
||||||
|
#import "MPMainViewController.h"
|
||||||
|
#import "MPAppDelegate.h"
|
||||||
|
|
||||||
|
|
||||||
|
@interface MPElementListSearchController ()
|
||||||
|
|
||||||
|
@property (nonatomic) BOOL newSiteSectionWasNeeded;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPElementListSearchController
|
||||||
|
@synthesize searchDisplayController;
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
|
||||||
|
if (!(self = [super init]))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
self.tipView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 170)];
|
||||||
|
self.tipView.textAlignment = NSTextAlignmentCenter;
|
||||||
|
self.tipView.backgroundColor = [UIColor clearColor];
|
||||||
|
self.tipView.textColor = [UIColor lightTextColor];
|
||||||
|
self.tipView.shadowColor = [UIColor blackColor];
|
||||||
|
self.tipView.shadowOffset = CGSizeMake(0, -1);
|
||||||
|
self.tipView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
|
||||||
|
| UIViewAutoresizingFlexibleBottomMargin;
|
||||||
|
self.tipView.numberOfLines = 0;
|
||||||
|
self.tipView.font = [UIFont systemFontOfSize:14];
|
||||||
|
self.tipView.text =
|
||||||
|
@"Tip:\n"
|
||||||
|
@"Name your sites by their domain name:\n"
|
||||||
|
@"apple.com, twitter.com\n\n"
|
||||||
|
@"For email accounts, use the address:\n"
|
||||||
|
@"john@apple.com, john@gmail.com";
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
[((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
// Simulate a tap on the first visible row.
|
||||||
|
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
||||||
|
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:tableView]; ++section) {
|
||||||
|
|
||||||
|
if (![self tableView:tableView numberOfRowsInSection:section])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
[self tableView:tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
[self.delegate didSelectElement:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
|
||||||
|
|
||||||
|
controller.searchBar.showsScopeBar = controller.searchBar.selectedScopeButtonIndex != MPSearchScopeAll;
|
||||||
|
controller.searchBar.text = @"";
|
||||||
|
if (controller.searchBar.showsScopeBar)
|
||||||
|
controller.searchBar.scopeButtonTitles = @[@"All", @"Outdated"];
|
||||||
|
else
|
||||||
|
controller.searchBar.scopeButtonTitles = nil;
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.2f animations:^{
|
||||||
|
self.searchTipContainer.alpha = 0;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
|
||||||
|
|
||||||
|
[self updateData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
|
||||||
|
|
||||||
|
controller.searchBar.prompt = nil;
|
||||||
|
controller.searchBar.searchResultsButtonSelected = NO;
|
||||||
|
controller.searchBar.selectedScopeButtonIndex = MPSearchScopeAll;
|
||||||
|
controller.searchBar.showsScopeBar = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
|
||||||
|
|
||||||
|
tableView.backgroundColor = [UIColor blackColor];
|
||||||
|
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||||
|
tableView.rowHeight = 48.0f;
|
||||||
|
|
||||||
|
self.tableView = tableView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
|
||||||
|
|
||||||
|
[self updateData];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
|
||||||
|
|
||||||
|
[self updateData];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)updateData {
|
||||||
|
|
||||||
|
[super updateData];
|
||||||
|
|
||||||
|
UISearchBar *searchBar = self.searchDisplayController.searchBar;
|
||||||
|
CGRect searchBarFrame = searchBar.frame;
|
||||||
|
[searchBar.superview enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
||||||
|
|
||||||
|
if ([subview isKindOfClass:[UIControl class]] &&
|
||||||
|
CGPointEqualToPoint(
|
||||||
|
CGPointDistanceBetweenCGPoints(searchBarFrame.origin, subview.frame.origin),
|
||||||
|
CGPointMake(0, searchBarFrame.size.height))) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self.tipView removeFromSuperview];
|
||||||
|
[subview addSubview:self.tipView];
|
||||||
|
});
|
||||||
|
|
||||||
|
*stop = YES;
|
||||||
|
}
|
||||||
|
} recurse:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)newSiteSectionNeeded {
|
||||||
|
|
||||||
|
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
if (![query length])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
__block BOOL hasExactQueryMatch = NO;
|
||||||
|
[[self.fetchedResultsController sections] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
||||||
|
id <NSFetchedResultsSectionInfo> sectionInfo = obj;
|
||||||
|
[[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) {
|
||||||
|
if ([[obj_ name] isEqualToString:query]) {
|
||||||
|
hasExactQueryMatch = YES;
|
||||||
|
*stop_ = YES;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
if (hasExactQueryMatch)
|
||||||
|
*stop = YES;
|
||||||
|
}];
|
||||||
|
|
||||||
|
return !hasExactQueryMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)customTableViewUpdates {
|
||||||
|
|
||||||
|
BOOL newSiteSectionIsNeeded = [self newSiteSectionNeeded];
|
||||||
|
dbg(@"isNeeded:%d, wasNeeded:%d", newSiteSectionIsNeeded, self.newSiteSectionWasNeeded);
|
||||||
|
if (newSiteSectionIsNeeded && !self.newSiteSectionWasNeeded) {
|
||||||
|
dbg(@"%@ -- insertSection:%d", NSStringFromSelector(_cmd), [[self.fetchedResultsController sections] count]);
|
||||||
|
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:[[self.fetchedResultsController sections] count]]
|
||||||
|
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
}
|
||||||
|
else if (!newSiteSectionIsNeeded && self.newSiteSectionWasNeeded) {
|
||||||
|
dbg(@"%@ -- deleteSection:%d", NSStringFromSelector(_cmd), [[self.fetchedResultsController sections] count]);
|
||||||
|
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:[[self.fetchedResultsController sections] count]]
|
||||||
|
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||||
|
}
|
||||||
|
self.newSiteSectionWasNeeded = newSiteSectionIsNeeded;
|
||||||
|
dbg(@"wasNeeded->%d", self.newSiteSectionWasNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||||
|
|
||||||
|
NSInteger sectionCount = [super numberOfSectionsInTableView:tableView];
|
||||||
|
if ([self newSiteSectionNeeded])
|
||||||
|
++sectionCount;
|
||||||
|
|
||||||
|
dbg(@"%@ (actually) = %d", NSStringFromSelector(_cmd), sectionCount);
|
||||||
|
return sectionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||||
|
if (section < (NSInteger)fetchSections)
|
||||||
|
return [super tableView:tableView numberOfRowsInSection:section];
|
||||||
|
|
||||||
|
dbg(@"%@%d = %d", NSStringFromSelector(_cmd), section, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||||
|
if (indexPath.section < (NSInteger)fetchSections)
|
||||||
|
[super configureCell:cell inTableView:tableView atIndexPath:indexPath];
|
||||||
|
|
||||||
|
else {
|
||||||
|
// "New" section
|
||||||
|
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
cell.textLabel.text = query;
|
||||||
|
cell.detailTextLabel.text = PearlString(@"Add new site: %@",
|
||||||
|
[MPAlgorithmDefault shortNameOfType:[[MPAppDelegate get].activeUser defaultType]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||||
|
if (indexPath.section < (NSInteger)fetchSections) {
|
||||||
|
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "New" section.
|
||||||
|
NSString *siteName = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
|
||||||
|
[PearlAlert showAlertWithTitle:@"New Site"
|
||||||
|
message:PearlString(@"Do you want to create a new site named:\n%@", siteName)
|
||||||
|
viewStyle:UIAlertViewStyleDefault
|
||||||
|
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
||||||
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||||
|
|
||||||
|
if (buttonIndex == [alert cancelButtonIndex])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self addElementNamed:siteName completion:nil];
|
||||||
|
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||||
|
if (section < (NSInteger)fetchSections)
|
||||||
|
return [super tableView:tableView titleForHeaderInSection:section];
|
||||||
|
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
|
||||||
|
forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
NSUInteger fetchSections = [[self.fetchedResultsController sections] count];
|
||||||
|
if (indexPath.section < (NSInteger)fetchSections)
|
||||||
|
[super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
#import <MessageUI/MessageUI.h>
|
#import <MessageUI/MessageUI.h>
|
||||||
#import "MPTypeViewController.h"
|
#import "MPTypeViewController.h"
|
||||||
#import "MPSearchDelegate.h"
|
#import "MPElementListSearchController.h"
|
||||||
|
|
||||||
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPElementPickerDelegate, UIWebViewDelegate, UIGestureRecognizerDelegate>
|
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPElementListDelegate, UIWebViewDelegate, UIGestureRecognizerDelegate>
|
||||||
|
|
||||||
@property (assign, nonatomic) BOOL siteInfoHidden;
|
@property (assign, nonatomic) BOOL siteInfoHidden;
|
||||||
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate;
|
@property (strong, nonatomic) IBOutlet MPElementListSearchController *searchDelegate;
|
||||||
@property (strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullDownGesture;
|
@property (strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullDownGesture;
|
||||||
@property (strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullUpGesture;
|
@property (strong, nonatomic) IBOutlet UIPanGestureRecognizer *pullUpGesture;
|
||||||
@property (weak, nonatomic) IBOutlet UITextField *contentField;
|
@property (weak, nonatomic) IBOutlet UITextField *contentField;
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
#import "MPAppDelegate.h"
|
#import "MPAppDelegate.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
#import "MPAllSitesViewController.h"
|
#import "MPElementListAllViewController.h"
|
||||||
|
#import "MPElementListSearchController.h"
|
||||||
|
|
||||||
|
|
||||||
@interface MPMainViewController()
|
@interface MPMainViewController()
|
||||||
@ -50,12 +51,12 @@
|
|||||||
if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
|
if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
|
||||||
((MPTypeViewController *)[segue destinationViewController]).delegate = self;
|
((MPTypeViewController *)[segue destinationViewController]).delegate = self;
|
||||||
if ([[segue identifier] isEqualToString:@"MP_AllSites"])
|
if ([[segue identifier] isEqualToString:@"MP_AllSites"])
|
||||||
((MPAllSitesViewController *)[((UINavigationController *)[segue destinationViewController]) topViewController]).delegate = self;
|
((MPElementListAllViewController *)[((UINavigationController *)[segue destinationViewController]) topViewController]).delegate = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
self.searchDelegate = [MPSearchDelegate new];
|
self.searchDelegate = [MPElementListSearchController new];
|
||||||
self.searchDelegate.delegate = self;
|
self.searchDelegate.delegate = self;
|
||||||
self.searchDelegate.searchDisplayController = self.searchDisplayController;
|
self.searchDelegate.searchDisplayController = self.searchDisplayController;
|
||||||
self.searchDelegate.searchTipContainer = self.searchTipContainer;
|
self.searchDelegate.searchTipContainer = self.searchTipContainer;
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
//
|
|
||||||
// MPSearchDelegate.h
|
|
||||||
// MasterPassword
|
|
||||||
//
|
|
||||||
// Created by Maarten Billemont on 04/01/12.
|
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#import "MPElementEntity.h"
|
|
||||||
#import "MPElementPickerDelegate.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
MPSearchScopeAll,
|
|
||||||
MPSearchScopeOutdated,
|
|
||||||
} MPSearchScope;
|
|
||||||
|
|
||||||
@interface MPSearchDelegate : NSObject<UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchDisplayDelegate, NSFetchedResultsControllerDelegate>
|
|
||||||
|
|
||||||
@property (strong, nonatomic) NSDateFormatter *dateFormatter;
|
|
||||||
@property (strong, readonly) NSFetchedResultsController *fetchedResultsController;
|
|
||||||
@property (strong, nonatomic) UILabel *tipView;
|
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet id<MPElementPickerDelegate> delegate;
|
|
||||||
@property (strong, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
|
|
||||||
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
|
|
||||||
|
|
||||||
@end
|
|
@ -1,416 +0,0 @@
|
|||||||
//
|
|
||||||
// MPSearchDelegate.m
|
|
||||||
// MasterPassword
|
|
||||||
//
|
|
||||||
// Created by Maarten Billemont on 04/01/12.
|
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "MPSearchDelegate.h"
|
|
||||||
#import "MPAppDelegate.h"
|
|
||||||
#import "MPAppDelegate_Store.h"
|
|
||||||
#import "MPMainViewController.h"
|
|
||||||
|
|
||||||
@implementation MPSearchDelegate {
|
|
||||||
|
|
||||||
NSFetchedResultsController *_fetchedResultsController;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)init {
|
|
||||||
|
|
||||||
if (!(self = [super init]))
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
self.dateFormatter = [NSDateFormatter new];
|
|
||||||
self.dateFormatter.dateStyle = NSDateFormatterShortStyle;
|
|
||||||
|
|
||||||
self.tipView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 170)];
|
|
||||||
self.tipView.textAlignment = NSTextAlignmentCenter;
|
|
||||||
self.tipView.backgroundColor = [UIColor clearColor];
|
|
||||||
self.tipView.textColor = [UIColor lightTextColor];
|
|
||||||
self.tipView.shadowColor = [UIColor blackColor];
|
|
||||||
self.tipView.shadowOffset = CGSizeMake(0, -1);
|
|
||||||
self.tipView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
|
|
||||||
| UIViewAutoresizingFlexibleBottomMargin;
|
|
||||||
self.tipView.numberOfLines = 0;
|
|
||||||
self.tipView.font = [UIFont systemFontOfSize:14];
|
|
||||||
self.tipView.text =
|
|
||||||
@"Tip:\n"
|
|
||||||
@"Name your sites by their domain name:\n"
|
|
||||||
@"apple.com, twitter.com\n\n"
|
|
||||||
@"For email accounts, use the address:\n"
|
|
||||||
@"john@apple.com, john@gmail.com";
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSFetchedResultsController *)fetchedResultsController {
|
|
||||||
|
|
||||||
if (!_fetchedResultsController) {
|
|
||||||
NSAssert([[NSThread currentThread] isMainThread], @"The fetchedResultsController must run on the main thread.");
|
|
||||||
NSManagedObjectContext *moc = [MPAppDelegate managedObjectContextForThreadIfReady];
|
|
||||||
if (!moc)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
|
||||||
fetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]];
|
|
||||||
fetchRequest.fetchBatchSize = 20;
|
|
||||||
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc
|
|
||||||
sectionNameKeyPath:nil cacheName:nil];
|
|
||||||
_fetchedResultsController.delegate = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _fetchedResultsController;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchBarBookmarkButtonClicked:(UISearchBar *)searchBar {
|
|
||||||
|
|
||||||
[((MPMainViewController *)self.delegate) performSegueWithIdentifier:@"MP_AllSites" sender:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
|
|
||||||
|
|
||||||
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
|
||||||
for (NSInteger section = 0; section < [self numberOfSectionsInTableView:tableView]; ++section) {
|
|
||||||
NSInteger rowCount = [self tableView:tableView numberOfRowsInSection:section];
|
|
||||||
if (!rowCount)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (rowCount == 1)
|
|
||||||
[self tableView:tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
|
||||||
|
|
||||||
[self.delegate didSelectElement:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
|
|
||||||
|
|
||||||
controller.searchBar.prompt = @"Enter the site's name:";
|
|
||||||
controller.searchBar.showsScopeBar = controller.searchBar.selectedScopeButtonIndex != MPSearchScopeAll;
|
|
||||||
controller.searchBar.text = @"";
|
|
||||||
if (controller.searchBar.showsScopeBar)
|
|
||||||
controller.searchBar.scopeButtonTitles = @[@"All", @"Outdated"];
|
|
||||||
else
|
|
||||||
controller.searchBar.scopeButtonTitles = nil;
|
|
||||||
|
|
||||||
[UIView animateWithDuration:0.2f animations:^{
|
|
||||||
self.searchTipContainer.alpha = 0;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
|
|
||||||
|
|
||||||
controller.searchBar.prompt = nil;
|
|
||||||
controller.searchBar.searchResultsButtonSelected = NO;
|
|
||||||
controller.searchBar.selectedScopeButtonIndex = MPSearchScopeAll;
|
|
||||||
controller.searchBar.showsScopeBar = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
|
|
||||||
|
|
||||||
tableView.backgroundColor = [UIColor blackColor];
|
|
||||||
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
||||||
tableView.rowHeight = 48.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
|
|
||||||
|
|
||||||
if (!controller.active)
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
[self fetchData];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
|
|
||||||
|
|
||||||
if (!controller.active)
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
[self fetchData];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)fetchData {
|
|
||||||
|
|
||||||
|
|
||||||
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
||||||
if (!query)
|
|
||||||
return;
|
|
||||||
|
|
||||||
MPUserEntity *activeUser = [MPAppDelegate get].activeUser;
|
|
||||||
if (!activeUser)
|
|
||||||
return;
|
|
||||||
|
|
||||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@ AND name BEGINSWITH[cd] %@", activeUser, query];
|
|
||||||
switch ((MPSearchScope)self.searchDisplayController.searchBar.selectedScopeButtonIndex) {
|
|
||||||
|
|
||||||
case MPSearchScopeAll:
|
|
||||||
break;
|
|
||||||
case MPSearchScopeOutdated:
|
|
||||||
predicate = [NSCompoundPredicate
|
|
||||||
andPredicateWithSubpredicates:@[[NSPredicate predicateWithFormat:@"requiresExplicitMigration_ == YES"], predicate]];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
self.fetchedResultsController.fetchRequest.predicate = predicate;
|
|
||||||
|
|
||||||
NSError *error;
|
|
||||||
if (![self.fetchedResultsController performFetch:&error])
|
|
||||||
err(@"Couldn't fetch elements: %@", error);
|
|
||||||
|
|
||||||
[self.searchDisplayController.searchBar.superview enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
|
||||||
CGRect searchBarFrame = self.searchDisplayController.searchBar.frame;
|
|
||||||
if ([subview isKindOfClass:[UIControl class]] &&
|
|
||||||
CGPointEqualToPoint(
|
|
||||||
CGPointDistanceBetweenCGPoints(searchBarFrame.origin, subview.frame.origin),
|
|
||||||
CGPointMake(0, searchBarFrame.size.height))) {
|
|
||||||
[self.tipView removeFromSuperview];
|
|
||||||
[subview addSubview:self.tipView];
|
|
||||||
*stop = YES;
|
|
||||||
}
|
|
||||||
} recurse:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
// See MP-14, also crashes easily on internal assertions etc..
|
|
||||||
//- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
|
|
||||||
//
|
|
||||||
// [self.searchDisplayController.searchResultsTableView beginUpdates];
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
|
|
||||||
// atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
|
|
||||||
//
|
|
||||||
// UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
|
||||||
// switch(type) {
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeInsert:
|
|
||||||
// [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeDelete:
|
|
||||||
// [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeUpdate:
|
|
||||||
// [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
|
|
||||||
// inTableView:tableView atIndexPath:indexPath];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeMove:
|
|
||||||
// [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
|
|
||||||
// atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
|
||||||
//
|
|
||||||
// UITableView *tableView = self.searchDisplayController.searchResultsTableView;
|
|
||||||
// switch(type) {
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeInsert:
|
|
||||||
// [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// case NSFetchedResultsChangeDelete:
|
|
||||||
// [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
|
||||||
// withRowAnimation:UITableViewRowAnimationFade];
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
|
||||||
|
|
||||||
dbg(@"controllerDidChangeContent on thread: %@", [NSThread currentThread].name);
|
|
||||||
[self.searchDisplayController.searchResultsTableView reloadData];
|
|
||||||
// [self.searchDisplayController.searchResultsTableView endUpdates];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
|
||||||
|
|
||||||
NSArray *sections = [self.fetchedResultsController sections];
|
|
||||||
NSUInteger sectionCount = [sections count];
|
|
||||||
|
|
||||||
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
||||||
if ([query length]) {
|
|
||||||
__block BOOL hasExactQueryMatch = NO;
|
|
||||||
[sections enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
|
||||||
id<NSFetchedResultsSectionInfo> sectionInfo = obj;
|
|
||||||
[[sectionInfo objects] enumerateObjectsUsingBlock:^(id obj_, NSUInteger idx_, BOOL *stop_) {
|
|
||||||
if ([[obj_ name] isEqualToString:query]) {
|
|
||||||
hasExactQueryMatch = YES;
|
|
||||||
*stop_ = YES;
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
if (hasExactQueryMatch)
|
|
||||||
*stop = YES;
|
|
||||||
}];
|
|
||||||
if (!hasExactQueryMatch)
|
|
||||||
// Add a section for "new site".
|
|
||||||
++sectionCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (NSInteger)sectionCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
||||||
|
|
||||||
NSArray *sections = [self.fetchedResultsController sections];
|
|
||||||
if (section < (NSInteger)[sections count])
|
|
||||||
return (NSInteger)[[sections objectAtIndex:(unsigned)section] numberOfObjects];
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MPElementSearch"];
|
|
||||||
if (!cell) {
|
|
||||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MPElementSearch"];
|
|
||||||
|
|
||||||
UIImage *backgroundImage = [[UIImage imageNamed:@"ui_list_middle"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)
|
|
||||||
resizingMode:UIImageResizingModeStretch];
|
|
||||||
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:backgroundImage];
|
|
||||||
backgroundImageView.frame = CGRectMake(-5, 0, 330, 34);
|
|
||||||
backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 34)];
|
|
||||||
[backgroundView addSubview:backgroundImageView];
|
|
||||||
backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
|
|
||||||
cell.backgroundView = backgroundView;
|
|
||||||
cell.textLabel.backgroundColor = [UIColor clearColor];
|
|
||||||
cell.textLabel.textColor = [UIColor whiteColor];
|
|
||||||
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
|
|
||||||
cell.detailTextLabel.textColor = [UIColor lightGrayColor];
|
|
||||||
cell.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
cell.clipsToBounds = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self configureCell:cell inTableView:tableView atIndexPath:indexPath];
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
if (indexPath.section < (NSInteger)[[self.fetchedResultsController sections] count]) {
|
|
||||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
|
||||||
|
|
||||||
cell.textLabel.text = element.name;
|
|
||||||
cell.detailTextLabel.text = PearlString(@"%d views, last on %@: %@",
|
|
||||||
element.uses, [self.dateFormatter stringFromDate:element.lastUsed], [element.algorithm shortNameOfType:element.type]);
|
|
||||||
} else {
|
|
||||||
// "New" section
|
|
||||||
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
||||||
cell.textLabel.text = query;
|
|
||||||
cell.detailTextLabel.text = PearlString(@"Add new site: %@", [MPAlgorithmDefault shortNameOfType:[[MPAppDelegate get].activeUser defaultType]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
if (indexPath.section < (NSInteger)[[self.fetchedResultsController sections] count])
|
|
||||||
[self.delegate didSelectElement:[self.fetchedResultsController objectAtIndexPath:indexPath]];
|
|
||||||
|
|
||||||
else {
|
|
||||||
// "New" section.
|
|
||||||
NSString *siteName = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
||||||
[PearlAlert showAlertWithTitle:@"New Site"
|
|
||||||
message:PearlString(@"Do you want to create a new site named:\n%@", siteName)
|
|
||||||
viewStyle:UIAlertViewStyleDefault
|
|
||||||
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
||||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
||||||
|
|
||||||
if (buttonIndex == [alert cancelButtonIndex])
|
|
||||||
return;
|
|
||||||
|
|
||||||
[MPAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
|
||||||
MPUserEntity *activeUser = [[MPAppDelegate get] activeUserInContext:moc];
|
|
||||||
assert(activeUser);
|
|
||||||
|
|
||||||
MPElementType type = activeUser.defaultType;
|
|
||||||
if (!type)
|
|
||||||
type = activeUser.defaultType = MPElementTypeGeneratedLong;
|
|
||||||
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
|
|
||||||
|
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
|
|
||||||
inManagedObjectContext:moc];
|
|
||||||
|
|
||||||
element.name = siteName;
|
|
||||||
element.user = activeUser;
|
|
||||||
element.type = type;
|
|
||||||
element.lastUsed = [NSDate date];
|
|
||||||
element.version = MPAlgorithmDefaultVersion;
|
|
||||||
[element saveContext];
|
|
||||||
|
|
||||||
NSManagedObjectID *elementOID = [element objectID];
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
MPElementEntity *element_ = (MPElementEntity *)[[MPAppDelegate managedObjectContextForThreadIfReady]
|
|
||||||
objectRegisteredForID:elementOID];
|
|
||||||
[self.delegate didSelectElement:element_];
|
|
||||||
});
|
|
||||||
}];
|
|
||||||
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
|
||||||
|
|
||||||
if (section < (NSInteger)[[self.fetchedResultsController sections] count])
|
|
||||||
return [[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] name];
|
|
||||||
|
|
||||||
return @"";
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
|
|
||||||
|
|
||||||
return [self.fetchedResultsController sectionIndexTitles];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
|
|
||||||
|
|
||||||
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
|
|
||||||
forRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
||||||
|
|
||||||
if (indexPath.section < (NSInteger)[[self.fetchedResultsController sections] count]) {
|
|
||||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
|
||||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
|
||||||
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
|
||||||
|
|
||||||
inf(@"Deleting element: %@", element.name);
|
|
||||||
[self.fetchedResultsController.managedObjectContext deleteObject:element];
|
|
||||||
|
|
||||||
#ifdef TESTFLIGHT_SDK_VERSION
|
|
||||||
[TestFlight passCheckpoint:MPCheckpointDeleteElement];
|
|
||||||
#endif
|
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointDeleteElement attributes:@{
|
|
||||||
@"type" : element.typeName,
|
|
||||||
@"version" : @(element.version)}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
|
@ -87,8 +87,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedElement_.type = cellType;
|
MPElementGeneratedEntity *cellElement = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmDefault classNameOfType:cellType]
|
||||||
NSString *typeContent = [selectedElement.algorithm generateContentForElement:selectedElement_ usingKey:[MPAppDelegate get].key];
|
inManagedObjectContext:moc];
|
||||||
|
cellElement.type = cellType;
|
||||||
|
cellElement.name = selectedElement_.name;
|
||||||
|
cellElement.user = selectedElement_.user;
|
||||||
|
cellElement.loginName = selectedElement_.loginName;
|
||||||
|
cellElement.version = MPAlgorithmDefaultVersion;
|
||||||
|
NSString *typeContent = [cellElement.algorithm generateContentForElement:cellElement usingKey:[MPAppDelegate get].key];
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[(UITextField *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent];
|
[(UITextField *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent];
|
||||||
|
@ -319,37 +319,39 @@
|
|||||||
|
|
||||||
- (void)showNewUserNameAlertFor:(MPUserEntity *)newUser completion:(void (^)(BOOL finished))completion {
|
- (void)showNewUserNameAlertFor:(MPUserEntity *)newUser completion:(void (^)(BOOL finished))completion {
|
||||||
|
|
||||||
[PearlAlert showAlertWithTitle:@"Enter Your Name"
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
message:nil viewStyle:UIAlertViewStylePlainTextInput
|
[PearlAlert showAlertWithTitle:@"Enter Your Name"
|
||||||
initAlert:^(UIAlertView *alert, UITextField *firstField) {
|
message:nil viewStyle:UIAlertViewStylePlainTextInput
|
||||||
firstField.autocapitalizationType = UITextAutocapitalizationTypeWords;
|
initAlert:^(UIAlertView *alert, UITextField *firstField) {
|
||||||
firstField.keyboardType = UIKeyboardTypeAlphabet;
|
firstField.autocapitalizationType = UITextAutocapitalizationTypeWords;
|
||||||
firstField.text = newUser.name;
|
firstField.keyboardType = UIKeyboardTypeAlphabet;
|
||||||
firstField.placeholder = @"eg. Robert Lee Mitchell";
|
firstField.text = newUser.name;
|
||||||
firstField.enablesReturnKeyAutomatically = YES;
|
firstField.placeholder = @"eg. Robert Lee Mitchell";
|
||||||
|
firstField.enablesReturnKeyAutomatically = YES;
|
||||||
|
}
|
||||||
|
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
||||||
|
if (buttonIndex == [alert cancelButtonIndex]) {
|
||||||
|
completion(NO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (![alert textFieldAtIndex:0].text.length) {
|
||||||
|
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
|
||||||
|
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||||
|
[newUser.managedObjectContext performBlock:^{
|
||||||
|
[self showNewUserNameAlertFor:newUser completion:completion];
|
||||||
|
}];
|
||||||
|
} cancelTitle:@"Try Again" otherTitles:nil];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
|
||||||
if (buttonIndex == [alert cancelButtonIndex]) {
|
|
||||||
completion(NO);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (![alert textFieldAtIndex:0].text.length) {
|
|
||||||
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
|
|
||||||
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
|
||||||
[newUser.managedObjectContext performBlock:^{
|
|
||||||
[self showNewUserNameAlertFor:newUser completion:completion];
|
|
||||||
}];
|
|
||||||
} cancelTitle:@"Try Again" otherTitles:nil];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
[newUser.managedObjectContext performBlock:^{
|
[newUser.managedObjectContext performBlock:^{
|
||||||
newUser.name = [alert textFieldAtIndex:0].text;
|
newUser.name = [alert textFieldAtIndex:0].text;
|
||||||
[self showNewUserAvatarAlertFor:newUser completion:completion];
|
[self showNewUserAvatarAlertFor:newUser completion:completion];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonSave, nil];
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonSave, nil];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showNewUserAvatarAlertFor:(MPUserEntity *)newUser completion:(void (^)(BOOL finished))completion {
|
- (void)showNewUserAvatarAlertFor:(MPUserEntity *)newUser completion:(void (^)(BOOL finished))completion {
|
||||||
|
@ -1713,43 +1713,13 @@ You could use the word wall for inspiration in finding a memorable master passw
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="996" y="1425"/>
|
<point key="canvasLocation" x="996" y="1425"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--All Sites View Controller - All Sites-->
|
<!--Element List All View Controller - All Sites-->
|
||||||
<scene sceneID="I7c-vt-d2s">
|
<scene sceneID="I7c-vt-d2s">
|
||||||
<objects>
|
<objects>
|
||||||
<tableViewController id="idA-Pj-1U9" customClass="MPAllSitesViewController" sceneMemberID="viewController">
|
<tableViewController id="idA-Pj-1U9" customClass="MPElementListAllViewController" sceneMemberID="viewController">
|
||||||
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="48" sectionHeaderHeight="22" sectionFooterHeight="22" id="N83-sj-4tl">
|
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="48" sectionHeaderHeight="22" sectionFooterHeight="22" id="N83-sj-4tl">
|
||||||
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
|
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
|
||||||
<prototypes>
|
|
||||||
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="MPElementSearch" textLabel="UGt-vQ-i5K" detailTextLabel="Xv8-kG-Tap" style="IBUITableViewCellStyleSubtitle" id="3eb-mJ-xFj">
|
|
||||||
<rect key="frame" x="0.0" y="22" width="320" height="48"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="320" height="47"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<subviews>
|
|
||||||
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UGt-vQ-i5K">
|
|
||||||
<rect key="frame" x="10" y="4" width="38" height="22"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
|
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
|
||||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
|
||||||
</label>
|
|
||||||
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Xv8-kG-Tap">
|
|
||||||
<rect key="frame" x="10" y="26" width="47" height="18"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
|
||||||
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
|
||||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
|
||||||
</label>
|
|
||||||
</subviews>
|
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
|
||||||
</view>
|
|
||||||
</tableViewCell>
|
|
||||||
</prototypes>
|
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="idA-Pj-1U9" id="yPh-6k-Ba9"/>
|
<outlet property="dataSource" destination="idA-Pj-1U9" id="yPh-6k-Ba9"/>
|
||||||
<outlet property="delegate" destination="idA-Pj-1U9" id="bdk-Iu-Hpv"/>
|
<outlet property="delegate" destination="idA-Pj-1U9" id="bdk-Iu-Hpv"/>
|
||||||
@ -2265,147 +2235,6 @@ You could use the word wall for inspiration in finding a memorable master passw
|
|||||||
<image name="ui_spinner.png" width="75" height="75"/>
|
<image name="ui_spinner.png" width="75" height="75"/>
|
||||||
<image name="ui_textfield.png" width="158" height="34"/>
|
<image name="ui_textfield.png" width="158" height="34"/>
|
||||||
</resources>
|
</resources>
|
||||||
<classes>
|
|
||||||
<class className="MPAllSitesViewController" superclassName="UITableViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAllSitesViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="action" name="add:"/>
|
|
||||||
<relationship kind="action" name="close:"/>
|
|
||||||
<relationship kind="outlet" name="delegate"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPAppViewController" superclassName="UIViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAppViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="action" name="deblock:" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="action" name="gorillas:" candidateClass="UIButton"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPAppsViewController" superclassName="UIViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPAppsViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="action" name="exit"/>
|
|
||||||
<relationship kind="outlet" name="pagePositionView" candidateClass="UIImageView"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPGuideViewController" superclassName="UIViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPGuideViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="action" name="close"/>
|
|
||||||
<relationship kind="outlet" name="pageControl" candidateClass="UIPageControl"/>
|
|
||||||
<relationship kind="outlet" name="scrollView" candidateClass="UIScrollView"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPMainViewController" superclassName="UIViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPMainViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="action" name="action:" candidateClass="UIBarButtonItem"/>
|
|
||||||
<relationship kind="action" name="closeAlert"/>
|
|
||||||
<relationship kind="action" name="closeOutdatedAlert"/>
|
|
||||||
<relationship kind="action" name="copyContent"/>
|
|
||||||
<relationship kind="action" name="editLoginName:" candidateClass="UILongPressGestureRecognizer"/>
|
|
||||||
<relationship kind="action" name="editPassword"/>
|
|
||||||
<relationship kind="action" name="incrementPasswordCounter"/>
|
|
||||||
<relationship kind="action" name="infoOutdatedAlert"/>
|
|
||||||
<relationship kind="action" name="panHelpDown:" candidateClass="UIPanGestureRecognizer"/>
|
|
||||||
<relationship kind="action" name="panHelpUp:" candidateClass="UIPanGestureRecognizer"/>
|
|
||||||
<relationship kind="action" name="resetPasswordCounter:" candidateClass="UILongPressGestureRecognizer"/>
|
|
||||||
<relationship kind="action" name="searchOutdatedElements"/>
|
|
||||||
<relationship kind="action" name="toggleUser"/>
|
|
||||||
<relationship kind="action" name="upgradePassword"/>
|
|
||||||
<relationship kind="outlet" name="actionsTipContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="alertBody" candidateClass="UITextView"/>
|
|
||||||
<relationship kind="outlet" name="alertContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="alertTitle" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="contentContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="contentField" candidateClass="UITextField"/>
|
|
||||||
<relationship kind="outlet" name="contentTipBody" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="contentTipContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="displayContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="helpContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="helpView" candidateClass="UIWebView"/>
|
|
||||||
<relationship kind="outlet" name="loginNameContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="loginNameField" candidateClass="UITextField"/>
|
|
||||||
<relationship kind="outlet" name="loginNameTipBody" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="loginNameTipContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="outdatedAlertBack" candidateClass="UIImageView"/>
|
|
||||||
<relationship kind="outlet" name="outdatedAlertCloseButton" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="outdatedAlertContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="passwordCounter" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="passwordEdit" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="passwordIncrementer" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="passwordUpgrade" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="passwordUser" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="pullDownGesture" candidateClass="UIPanGestureRecognizer"/>
|
|
||||||
<relationship kind="outlet" name="pullDownView" candidateClass="UIImageView"/>
|
|
||||||
<relationship kind="outlet" name="pullUpGesture" candidateClass="UIPanGestureRecognizer"/>
|
|
||||||
<relationship kind="outlet" name="pullUpView" candidateClass="UIImageView"/>
|
|
||||||
<relationship kind="outlet" name="searchDelegate" candidateClass="MPSearchDelegate"/>
|
|
||||||
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="siteName" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="toolTipBody" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="toolTipContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="toolTipEditIcon" candidateClass="UIImageView"/>
|
|
||||||
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="typeTipContainer" candidateClass="UIView"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPPreferencesViewController" superclassName="UITableViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPPreferencesViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="action" name="didToggleSwitch:" candidateClass="UISwitch"/>
|
|
||||||
<relationship kind="action" name="settings:"/>
|
|
||||||
<relationship kind="outlet" name="avatarTemplate" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="avatarsView" candidateClass="UIScrollView"/>
|
|
||||||
<relationship kind="outlet" name="changeMPCell" candidateClass="UITableViewCell"/>
|
|
||||||
<relationship kind="outlet" name="defaultTypeLabel" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="exportCell" candidateClass="UITableViewCell"/>
|
|
||||||
<relationship kind="outlet" name="savePasswordSwitch" candidateClass="UISwitch"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPSearchDelegate" superclassName="NSObject">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPSearchDelegate.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="outlet" name="delegate"/>
|
|
||||||
<relationship kind="outlet" name="searchDisplayController" candidateClass="UISearchDisplayController"/>
|
|
||||||
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPTypeViewController" superclassName="UITableViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPTypeViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="outlet" name="recommendedTipContainer" candidateClass="UIView"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
<class className="MPUnlockViewController" superclassName="UIViewController">
|
|
||||||
<source key="sourceIdentifier" type="project" relativePath="./Classes/MPUnlockViewController.h"/>
|
|
||||||
<relationships>
|
|
||||||
<relationship kind="action" name="add:" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="action" name="facebook:" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="action" name="google:" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="action" name="mail:" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="action" name="targetedUserAction:" candidateClass="UILongPressGestureRecognizer"/>
|
|
||||||
<relationship kind="action" name="twitter:" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="avatarTemplate" candidateClass="UIButton"/>
|
|
||||||
<relationship kind="outlet" name="avatarsView" candidateClass="UIScrollView"/>
|
|
||||||
<relationship kind="outlet" name="createPasswordTipView" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="loadingUsersIndicator" candidateClass="UIActivityIndicatorView"/>
|
|
||||||
<relationship kind="outlet" name="nameLabel" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="newsView" candidateClass="UIWebView"/>
|
|
||||||
<relationship kind="outlet" name="oldNameLabel" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="passwordField" candidateClass="UITextField"/>
|
|
||||||
<relationship kind="outlet" name="passwordFieldLabel" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="passwordTipLabel" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="passwordTipView" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="passwordView" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="spinner" candidateClass="UIImageView"/>
|
|
||||||
<relationship kind="outlet" name="targetedUserActionGesture" candidateClass="UILongPressGestureRecognizer"/>
|
|
||||||
<relationship kind="outlet" name="tip" candidateClass="UILabel"/>
|
|
||||||
<relationship kind="outlet" name="uiContainer" candidateClass="UIView"/>
|
|
||||||
<relationship kind="outlet" name="wordWall" candidateClass="UIView"/>
|
|
||||||
</relationships>
|
|
||||||
</class>
|
|
||||||
</classes>
|
|
||||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||||
<nil key="statusBar"/>
|
<nil key="statusBar"/>
|
||||||
<simulatedOrientationMetrics key="orientation"/>
|
<simulatedOrientationMetrics key="orientation"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user