Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa461b73c8 | ||
|
|
e070082f4a | ||
|
|
079434d62b | ||
|
|
f57de77545 | ||
|
|
18657271ba | ||
|
|
11d1dc711d | ||
|
|
965d5efe7f | ||
|
|
87b01fcaaf | ||
|
|
b2624c7572 | ||
|
|
bd37f1d6a7 | ||
|
|
f475c15360 | ||
|
|
d3d4aeea41 | ||
|
|
5913ce80e5 | ||
|
|
4c8bed2826 | ||
|
|
d036b43d6f | ||
|
|
318aca4d8f | ||
|
|
060c9f91f3 | ||
|
|
4184f609d6 | ||
|
|
658d710847 | ||
|
|
3fa9843855 | ||
|
|
de3f51b447 | ||
|
|
43c32e0f4c | ||
|
|
775a6fd4ea | ||
|
|
4f594c8c1d | ||
|
|
ebadac8cd8 | ||
|
|
c48bed5ebd | ||
|
|
4f3efde6f0 | ||
|
|
5b4e86a90a | ||
|
|
2be83752db | ||
|
|
bd1a0f4e25 | ||
|
|
70cd397591 | ||
|
|
1120529e34 | ||
|
|
f57415a08b | ||
|
|
f9da568bfd | ||
|
|
39c9f8c5a0 | ||
|
|
a645e22973 | ||
|
|
eaf86d3348 | ||
|
|
2565321a4a | ||
|
|
ec828a82fd | ||
|
|
411aa41226 | ||
|
|
00b164058d | ||
|
|
9808613c75 | ||
|
|
1d20d81652 | ||
|
|
f5c66ff35a | ||
|
|
4c3d3234f5 | ||
|
|
d543173b18 | ||
|
|
d8578e0162 | ||
|
|
d665833eba | ||
|
|
33e25a5fed | ||
|
|
c0737de939 | ||
|
|
a18679eba8 | ||
|
|
ce321aeceb | ||
|
|
6074547f64 | ||
|
|
8432932cb7 | ||
|
|
f8dccc04d7 | ||
|
|
b38ef59c93 |
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -13,9 +13,9 @@
|
|||||||
[submodule "External/RHStatusItemView"]
|
[submodule "External/RHStatusItemView"]
|
||||||
path = External/RHStatusItemView
|
path = External/RHStatusItemView
|
||||||
url = git://github.com/lhunath/RHStatusItemView.git
|
url = git://github.com/lhunath/RHStatusItemView.git
|
||||||
|
[submodule "External/LoveLyndir"]
|
||||||
|
path = External/LoveLyndir
|
||||||
|
url = git://github.com/Lyndir/love-lyndir.client.git
|
||||||
[submodule "External/DCIntrospect"]
|
[submodule "External/DCIntrospect"]
|
||||||
path = External/DCIntrospect
|
path = External/DCIntrospect
|
||||||
url = https://github.com/lhunath/DCIntrospect.git
|
url = https://github.com/lhunath/DCIntrospect.git
|
||||||
[submodule "External/LoveLyndir"]
|
|
||||||
path = External/DCIntrospect
|
|
||||||
url = git://github.com/Lyndir/love-lyndir.client.git
|
|
||||||
|
|||||||
1
.idea/inspectionProfiles/Project_Default.xml
generated
1
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -9,6 +9,7 @@
|
|||||||
<inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="OCUnusedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="OCUnusedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="SignednessMismatch" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="UnavailableInDeploymentTarget" enabled="true" level="INFO" enabled_by_default="true" />
|
<inspection_tool class="UnavailableInDeploymentTarget" enabled="true" level="INFO" enabled_by_default="true" />
|
||||||
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="UnusedParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="UnusedParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
|||||||
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
language: objective-c
|
||||||
|
xcode_workspace: MasterPassword.xcworkspace
|
||||||
|
xcode_scheme: MasterPassword iOS (Development)
|
||||||
|
xcode_sdk: iphonesimulator
|
||||||
|
git:
|
||||||
|
submodules: false
|
||||||
|
before_install: ./Scripts/updateDependencies
|
||||||
Binary file not shown.
@@ -15,13 +15,13 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2.1.3</string>
|
<string>2.1.7</string>
|
||||||
<key>CFBundleSupportedPlatforms</key>
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
<array>
|
<array>
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>13</string>
|
<string>26</string>
|
||||||
<key>DTPlatformName</key>
|
<key>DTPlatformName</key>
|
||||||
<string>iphoneos</string>
|
<string>iphoneos</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
|
|||||||
BIN
External/Crashlytics.framework/run
vendored
BIN
External/Crashlytics.framework/run
vendored
Binary file not shown.
1
External/FontReplacer
vendored
1
External/FontReplacer
vendored
Submodule External/FontReplacer deleted from 4e3dea0870
2
External/LoveLyndir
vendored
2
External/LoveLyndir
vendored
Submodule External/LoveLyndir updated: c2c0d1e45a...ceed9e2000
2
External/Pearl
vendored
2
External/Pearl
vendored
Submodule External/Pearl updated: 04d8ca58b5...2e328ecff0
@@ -7,7 +7,7 @@ CF_EXTERN_C_BEGIN
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief The Reveal Log level bit flags.
|
\brief The Reveal Log level bit flags.
|
||||||
\discussion These flags are addative. Ie, you should bitwise OR them together.
|
\discussion These flags are additive. i.e. you should bitwise OR them together.
|
||||||
|
|
||||||
\seealso IBARevealLoggerSetLevelMask
|
\seealso IBARevealLoggerSetLevelMask
|
||||||
\seealso IBARevealLoggerGetLevelMask
|
\seealso IBARevealLoggerGetLevelMask
|
||||||
|
|||||||
BIN
External/Reveal.framework/Versions/A/Reveal
vendored
BIN
External/Reveal.framework/Versions/A/Reveal
vendored
Binary file not shown.
15
External/TestFlight/README.md
vendored
15
External/TestFlight/README.md
vendored
@@ -6,12 +6,11 @@ The SDK can track more information if you pass it to TestFlight. The Checkpoint
|
|||||||
|
|
||||||
The SDK also offers a remote logging solution. Find out more about our logging system in the "Remote Logging" section.
|
The SDK also offers a remote logging solution. Find out more about our logging system in the "Remote Logging" section.
|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
The TestFlight SDK requires iOS 4.3 or above, the Apple LLVM compiler, and the libz library to run.
|
The TestFlight SDK requires iOS 4.3 or above, the Apple LLVM compiler, and the libz library to run.
|
||||||
|
|
||||||
The AdSupport.framework is required for iOS 6.0+ in order to uniquely identify users so we can estimate the number of users your app has (using `ASIdentifierManager`). You may weak link the framework in you app. If your app does not link with the AdSupport.framework, the TestFlight SDK will automatically load it for apps running on iOS 6.0+.
|
|
||||||
|
|
||||||
|
|
||||||
## Integration
|
## Integration
|
||||||
|
|
||||||
@@ -40,9 +39,9 @@ The AdSupport.framework is required for iOS 6.0+ in order to uniquely identify u
|
|||||||
|
|
||||||
4. Get your App Token
|
4. Get your App Token
|
||||||
|
|
||||||
1. If this is a new application, and you have not uploaded it to TestFlight before, first register it here: [https://testflightapp.com/dashboard/applications/create/]().
|
1. If this is a new application, and you have not uploaded it to TestFlight before, first register it here: [https://testflightapp.com/dashboard/applications/create/](https://testflightapp.com/dashboard/applications/create/).
|
||||||
|
|
||||||
Otherwise, if you have previously uploaded your app to TestFlight, go to your list of applications ([http://testflightapp.com/dashboard/applications/]()) and click on the application you are using from the list.
|
Otherwise, if you have previously uploaded your app to TestFlight, go to your list of applications ([http://testflightapp.com/dashboard/applications/](http://testflightapp.com/dashboard/applications/)) and click on the application you are using from the list.
|
||||||
|
|
||||||
2. Click on the "App Token" tab on the left. The App Token for that application will be there.
|
2. Click on the "App Token" tab on the left. The App Token for that application will be there.
|
||||||
|
|
||||||
@@ -92,7 +91,9 @@ After you have integrated the SDK into your application you need to upload your
|
|||||||
|
|
||||||
View anonymous information about how often users use your app, how long they use it for, and when they use it. You can see what type of device the user is using, which OS, which language, etc.
|
View anonymous information about how often users use your app, how long they use it for, and when they use it. You can see what type of device the user is using, which OS, which language, etc.
|
||||||
|
|
||||||
Sessions automatically start at app launch, app did become active, and app will enter foreground and end at app will resign active, app did enter background, or app will terminate. Sessions that start shortly after an end continue the session instead of starting a new one.
|
Sessions automatically start at when the app becomes active and end when the app resigns active. Sessions that start shortly after an end continue the session instead of starting a new one.
|
||||||
|
|
||||||
|
NB: Sessions do not start when `takeOff:` is called, `takeOff:` registers callbacks to start sessions when the app is active.
|
||||||
|
|
||||||
For **beta** users, you can see who the users are if you are **setting the UDID**, they have a TestFlight account, and their device is registered to TestFlight. (See Setting the UDID for more information).
|
For **beta** users, you can see who the users are if you are **setting the UDID**, they have a TestFlight account, and their device is registered to TestFlight. (See Setting the UDID for more information).
|
||||||
|
|
||||||
@@ -125,6 +126,8 @@ Use `passCheckpoint:` to track when a user performs certain tasks in your applic
|
|||||||
|
|
||||||
Checkpoints are meant to tell you if a user visited a place in your app or completed a task. They should not be used for debugging purposes. Instead, use Remote Logging for debugging information (more information below).
|
Checkpoints are meant to tell you if a user visited a place in your app or completed a task. They should not be used for debugging purposes. Instead, use Remote Logging for debugging information (more information below).
|
||||||
|
|
||||||
|
NB: Checkpoints are only recorded during sessions.
|
||||||
|
|
||||||
|
|
||||||
### Custom Environment Information
|
### Custom Environment Information
|
||||||
|
|
||||||
@@ -162,6 +165,8 @@ For even better information in your remote logs, such as file name and line numb
|
|||||||
Which will produce output that looks like
|
Which will produce output that looks like
|
||||||
|
|
||||||
-[MyAppDelegate application:didFinishLaunchingWithOptions:] [Line 45] Launched!
|
-[MyAppDelegate application:didFinishLaunchingWithOptions:] [Line 45] Launched!
|
||||||
|
|
||||||
|
NB: Logs are only recorded during sessions.
|
||||||
|
|
||||||
**Custom Logging**
|
**Custom Logging**
|
||||||
|
|
||||||
|
|||||||
9
External/TestFlight/TestFlight.h
vendored
9
External/TestFlight/TestFlight.h
vendored
@@ -6,7 +6,7 @@
|
|||||||
// Copyright 2011 TestFlight. All rights reserved.
|
// Copyright 2011 TestFlight. All rights reserved.
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#define TESTFLIGHT_SDK_VERSION @"2.0.0"
|
#define TESTFLIGHT_SDK_VERSION @"2.1.4"
|
||||||
#undef TFLog
|
#undef TFLog
|
||||||
|
|
||||||
#if __cplusplus
|
#if __cplusplus
|
||||||
@@ -41,7 +41,12 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a TestFlight session using the Application Token for this Application
|
* Sets up TestFlight's infrastructure.
|
||||||
|
*
|
||||||
|
* - Saves App Token
|
||||||
|
* - Starts automatic session management
|
||||||
|
* - Installs Crash Handlers
|
||||||
|
* - Kicks off sending of old session data
|
||||||
*
|
*
|
||||||
* @param applicationToken Will be the application token for the current application.
|
* @param applicationToken Will be the application token for the current application.
|
||||||
* The token for this application can be retrieved by going to https://testflightapp.com/dashboard/applications/
|
* The token for this application can be retrieved by going to https://testflightapp.com/dashboard/applications/
|
||||||
|
|||||||
BIN
External/TestFlight/libTestFlight.a
vendored
BIN
External/TestFlight/libTestFlight.a
vendored
Binary file not shown.
32
External/TestFlight/release_notes.md
vendored
32
External/TestFlight/release_notes.md
vendored
@@ -1,4 +1,34 @@
|
|||||||
## 2.0
|
## 2.1.4
|
||||||
|
|
||||||
|
- Consolidate both SDK versions into one which removes all access to `ASIdentifierManager`
|
||||||
|
|
||||||
|
## 2.1.3
|
||||||
|
|
||||||
|
- Fix bug in 2.1.2-noadid which caused adid to be collected
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
- Fix for bug that caused events to not get sent properly when using the `TFOptionSessionKeepAliveTimeout` option
|
||||||
|
- Fix for bug that caused logs that were sent immediately after start session to sometimes not be sent to server
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
- Create sdk version that removes all access to `ASIdentifierManager`
|
||||||
|
- Add UIDevice's `identifierForVendor`
|
||||||
|
|
||||||
|
## 2.1
|
||||||
|
|
||||||
|
- Full support for the iPhone 5s’ ARM64 processor while still supporting down to iOS 4.3
|
||||||
|
|
||||||
|
## 2.0.2
|
||||||
|
|
||||||
|
- Fixed a bug where the sdk would cause an app's CPU usage to rise significantly if the device had no internet connection when the app started
|
||||||
|
|
||||||
|
## 2.0.1
|
||||||
|
|
||||||
|
- Fixed rare `8badf00d` crash in TFNetworkManager that happened when the app was in the background
|
||||||
|
|
||||||
|
## 2.0 - August 12, 2013
|
||||||
|
|
||||||
Improvements
|
Improvements
|
||||||
|
|
||||||
|
|||||||
2
External/UbiquityStoreManager
vendored
2
External/UbiquityStoreManager
vendored
Submodule External/UbiquityStoreManager updated: fbf5309ddc...c02affe877
@@ -5,13 +5,11 @@
|
|||||||
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
|
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>IDESourceControlProjectIdentifier</key>
|
<key>IDESourceControlProjectIdentifier</key>
|
||||||
<string>D4AB9F0C-D746-4319-AABF-B24705099AED</string>
|
<string>3D68B2F1-988A-48C3-8450-B37D43BDFE92</string>
|
||||||
<key>IDESourceControlProjectName</key>
|
<key>IDESourceControlProjectName</key>
|
||||||
<string>MasterPassword</string>
|
<string>MasterPassword</string>
|
||||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
<key>IDESourceControlProjectOriginsDictionary</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>2B6DA448-3730-4F84-B2C3-51272E0D42F3</key>
|
|
||||||
<string>ssh://github.com/lhunath/DCIntrospect.git</string>
|
|
||||||
<key>5263993D-5FE8-464F-B66E-B0F7C2DFF410</key>
|
<key>5263993D-5FE8-464F-B66E-B0F7C2DFF410</key>
|
||||||
<string>ssh://github.com/lhunath/UbiquityStoreManager.git</string>
|
<string>ssh://github.com/lhunath/UbiquityStoreManager.git</string>
|
||||||
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
|
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
|
||||||
@@ -24,8 +22,10 @@
|
|||||||
<string>git://github.com/lhunath/uicolor-utilities.git</string>
|
<string>git://github.com/lhunath/uicolor-utilities.git</string>
|
||||||
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
|
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
|
||||||
<string>git://github.com/lhunath/RHStatusItemView.git</string>
|
<string>git://github.com/lhunath/RHStatusItemView.git</string>
|
||||||
<key>CBA93B91-B799-4CC6-85B6-749792B76DD4</key>
|
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
|
||||||
<string>ssh://github.com/lhunath/InAppSettingsKit.git</string>
|
<string>git://github.com/lhunath/InAppSettingsKit.git</string>
|
||||||
|
<key>D5CE8AB8-2F69-4A08-A2CE-93C70E0F0567</key>
|
||||||
|
<string>https://github.com/lhunath/DCIntrospect.git</string>
|
||||||
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
|
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
|
||||||
<string>git://github.com/jonmarimba/jrswizzle.git</string>
|
<string>git://github.com/jonmarimba/jrswizzle.git</string>
|
||||||
<key>FF42A9E0-F41C-42FC-88CD-F2CCDE15DBB6</key>
|
<key>FF42A9E0-F41C-42FC-88CD-F2CCDE15DBB6</key>
|
||||||
@@ -35,8 +35,6 @@
|
|||||||
<string>MasterPassword.xcworkspace</string>
|
<string>MasterPassword.xcworkspace</string>
|
||||||
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>2B6DA448-3730-4F84-B2C3-51272E0D42F3</key>
|
|
||||||
<string>../External/DCIntrospect</string>
|
|
||||||
<key>5263993D-5FE8-464F-B66E-B0F7C2DFF410</key>
|
<key>5263993D-5FE8-464F-B66E-B0F7C2DFF410</key>
|
||||||
<string>../External/UbiquityStoreManager</string>
|
<string>../External/UbiquityStoreManager</string>
|
||||||
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
|
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
|
||||||
@@ -49,8 +47,10 @@
|
|||||||
<string>../External/Pearl/External/uicolor-utilities</string>
|
<string>../External/Pearl/External/uicolor-utilities</string>
|
||||||
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
|
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
|
||||||
<string>../External/RHStatusItemView</string>
|
<string>../External/RHStatusItemView</string>
|
||||||
<key>CBA93B91-B799-4CC6-85B6-749792B76DD4</key>
|
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
|
||||||
<string>../External/InAppSettingsKit</string>
|
<string>../External/InAppSettingsKit</string>
|
||||||
|
<key>D5CE8AB8-2F69-4A08-A2CE-93C70E0F0567</key>
|
||||||
|
<string>../External/DCIntrospect</string>
|
||||||
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
|
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
|
||||||
<string>../External/Pearl/External/jrswizzle</string>
|
<string>../External/Pearl/External/jrswizzle</string>
|
||||||
<key>FF42A9E0-F41C-42FC-88CD-F2CCDE15DBB6</key>
|
<key>FF42A9E0-F41C-42FC-88CD-F2CCDE15DBB6</key>
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||||
<string>public.vcs.git</string>
|
<string>public.vcs.git</string>
|
||||||
<key>IDESourceControlWCCIdentifierKey</key>
|
<key>IDESourceControlWCCIdentifierKey</key>
|
||||||
<string>2B6DA448-3730-4F84-B2C3-51272E0D42F3</string>
|
<string>D5CE8AB8-2F69-4A08-A2CE-93C70E0F0567</string>
|
||||||
<key>IDESourceControlWCCName</key>
|
<key>IDESourceControlWCCName</key>
|
||||||
<string>DCIntrospect</string>
|
<string>DCIntrospect</string>
|
||||||
</dict>
|
</dict>
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||||
<string>public.vcs.git</string>
|
<string>public.vcs.git</string>
|
||||||
<key>IDESourceControlWCCIdentifierKey</key>
|
<key>IDESourceControlWCCIdentifierKey</key>
|
||||||
<string>CBA93B91-B799-4CC6-85B6-749792B76DD4</string>
|
<string>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</string>
|
||||||
<key>IDESourceControlWCCName</key>
|
<key>IDESourceControlWCCName</key>
|
||||||
<string>InAppSettingsKit</string>
|
<string>InAppSettingsKit</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
0
MasterPassword/Java/.mvn-tools
Normal file
0
MasterPassword/Java/.mvn-tools
Normal file
@@ -32,10 +32,16 @@ public class MPTemplates extends MetaObject {
|
|||||||
this.templates = templates;
|
this.templates = templates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MPTemplates load() {
|
||||||
|
|
||||||
|
return loadFromPList( "ciphers.plist" );
|
||||||
|
}
|
||||||
|
|
||||||
public static MPTemplates loadFromPList(final String templateResource) {
|
public static MPTemplates loadFromPList(final String templateResource) {
|
||||||
|
|
||||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||||
InputStream templateStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( templateResource );
|
InputStream templateStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( templateResource );
|
||||||
|
Preconditions.checkNotNull( templateStream, "Not found: %s", templateResource );
|
||||||
try {
|
try {
|
||||||
NSObject plistObject = PropertyListParser.parse( templateStream );
|
NSObject plistObject = PropertyListParser.parse( templateStream );
|
||||||
Preconditions.checkState( NSDictionary.class.isAssignableFrom( plistObject.getClass() ) );
|
Preconditions.checkState( NSDictionary.class.isAssignableFrom( plistObject.getClass() ) );
|
||||||
@@ -98,6 +104,6 @@ public class MPTemplates extends MetaObject {
|
|||||||
|
|
||||||
public static void main(final String... arguments) {
|
public static void main(final String... arguments) {
|
||||||
|
|
||||||
loadFromPList( "templates.plist" );
|
load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public abstract class MasterPassword {
|
|||||||
private static final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN;
|
private static final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN;
|
||||||
private static final MessageDigests MP_hash = MessageDigests.SHA256;
|
private static final MessageDigests MP_hash = MessageDigests.SHA256;
|
||||||
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
|
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
|
||||||
private static final MPTemplates templates = MPTemplates.loadFromPList( "templates.plist" );
|
private static final MPTemplates templates = MPTemplates.load();
|
||||||
|
|
||||||
public static byte[] keyForPassword(final String password, final String username) {
|
public static byte[] keyForPassword(final String password, final String username) {
|
||||||
|
|
||||||
|
|||||||
@@ -29,30 +29,49 @@
|
|||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-antrun-plugin</artifactId>
|
||||||
<configuration>
|
<version>1.7</version>
|
||||||
<archive>
|
<executions>
|
||||||
<manifest>
|
<execution>
|
||||||
<mainClass>com.lyndir.lhunath.masterpassword.CLI</mainClass>
|
<id>prepare-package</id>
|
||||||
<addClasspath>true</addClasspath>
|
<phase>prepare-package</phase>
|
||||||
<classpathPrefix>lib/</classpathPrefix>
|
<configuration>
|
||||||
</manifest>
|
<target>
|
||||||
</archive>
|
<chmod file="${project.build.directory}/install" perm="755"/>
|
||||||
</configuration>
|
</target>
|
||||||
|
</configuration>
|
||||||
|
<goals>
|
||||||
|
<goal>run</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.4</version>
|
<version>2.2</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>copy-dependencies</id>
|
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>copy-dependencies</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>com.lyndir.lhunath.masterpassword.CLI</mainClass>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|||||||
1958
MasterPassword/Java/masterpassword-cli/src/main/scripts/bashlib
Executable file
1958
MasterPassword/Java/masterpassword-cli/src/main/scripts/bashlib
Executable file
File diff suppressed because it is too large
Load Diff
56
MasterPassword/Java/masterpassword-cli/src/main/scripts/install
Executable file
56
MasterPassword/Java/masterpassword-cli/src/main/scripts/install
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Install the Master Password CLI tool.
|
||||||
|
set -e
|
||||||
|
cd "${BASH_SOURCE%/*}"
|
||||||
|
source bashlib
|
||||||
|
|
||||||
|
inf "This will install the mpw tool."
|
||||||
|
|
||||||
|
# Try to guess then ask for the bin dir to install to.
|
||||||
|
IFS=: read -a paths <<< "$PATH"
|
||||||
|
if inArray ~/bin "${paths[@]}"; then
|
||||||
|
bindir=~/bin
|
||||||
|
elif inArray ~/.bin "${paths[@]}"; then
|
||||||
|
bindir=~/.bin
|
||||||
|
elif inArray /usr/local/bin "${paths[@]}"; then
|
||||||
|
bindir=/usr/local/bin
|
||||||
|
else
|
||||||
|
bindir=~/bin
|
||||||
|
fi
|
||||||
|
bindir=$(ask -d "$bindir" "What bin directory should I install to?")
|
||||||
|
[[ -d "$bindir" ]] || mkdir "$bindir" || ftl 'Cannot create missing bin directory: %s' "$bindir" || exit
|
||||||
|
[[ -w "$bindir" ]] || ftl 'Cannot write to bin directory: %s' "$bindir" || exit
|
||||||
|
|
||||||
|
# Try to guess then ask for the share dir to install to.
|
||||||
|
sharedir=$(cd -P "$bindir/.."; [[ $bindir = */.bin ]] && printf '%s/.share' "$PWD" || printf '%s/share' "$PWD")
|
||||||
|
sharedir=$(ask -d "$sharedir" "What share directory should I install to?")
|
||||||
|
[[ -d "$sharedir" ]] || mkdir "$sharedir" || ftl 'Cannot create missing share directory: %s' "$sharedir" || exit
|
||||||
|
[[ -w "$sharedir" ]] || ftl 'Cannot write to share directory: %s' "$sharedir" || exit
|
||||||
|
|
||||||
|
# Install Master Password.
|
||||||
|
sharepath=$sharedir/masterpassword
|
||||||
|
mkdir -p "$sharepath"
|
||||||
|
cp -a "masterpassword-cli-"*".jar" bashlib mpw "$sharepath"
|
||||||
|
ex -c "%s~%SHAREPATH%~$sharepath~g|x" "$sharepath/mpw"
|
||||||
|
ln -sf "$sharepath/mpw" "$bindir/mpw"
|
||||||
|
chmod +x "$sharepath/mpw"
|
||||||
|
[[ ! -e "$bindir/bashlib" ]] && ln -s "$sharepath/bashlib" "$bindir/bashlib" ||:
|
||||||
|
|
||||||
|
# Convenience bash function.
|
||||||
|
inf "Installation successful!"
|
||||||
|
echo
|
||||||
|
inf "To improve usability, you can install an mpw function in your bash shell."
|
||||||
|
inf "This function adds the following features:"
|
||||||
|
inf " - Ask the Master Password once, remember in the shell."
|
||||||
|
inf " - Automatically put the password in the clipboard (some platforms)."
|
||||||
|
echo
|
||||||
|
inf "To do this you need the following function in ~/.bashrc:\n%s" "$(<mpw.bashrc)"
|
||||||
|
echo
|
||||||
|
inf "We can do this for you automatically now."
|
||||||
|
if ask -c Y!n "Append the mpw function to your .bashrc?"; then
|
||||||
|
cat mpw.bashrc >> ~/.bashrc
|
||||||
|
inf "Done! Don't forget to run '%s' to apply the changes!" "source ~/.bashrc"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
inf "To begin using Master Password, type: mpw [site name]"
|
||||||
@@ -5,5 +5,5 @@
|
|||||||
# Uncomment this to hardcode your master password. Make sure this file's permissions are tight. Master Password will not ask you for your master password anymore. This is probably not a good idea.
|
# Uncomment this to hardcode your master password. Make sure this file's permissions are tight. Master Password will not ask you for your master password anymore. This is probably not a good idea.
|
||||||
# export MP_PASSWORD="banana colored duckling"
|
# export MP_PASSWORD="banana colored duckling"
|
||||||
|
|
||||||
cd "${BASH_SOURCE[0]%/*}"
|
cd "%SHAREPATH%"
|
||||||
java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"
|
exec java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
source bashlib
|
||||||
|
mpw() {
|
||||||
|
_nocopy() { echo >&2 "$(cat)"; }
|
||||||
|
_copy() { "$(type -P pbcopy || type -P xclip || echo _nocopy)"; }
|
||||||
|
|
||||||
|
# Empty the clipboard
|
||||||
|
:| _copy 2>/dev/null
|
||||||
|
|
||||||
|
# Ask for the user's name and password if not yet known.
|
||||||
|
MP_USERNAME=${MP_USERNAME:-$(ask -s 'Your Full Name:')}
|
||||||
|
MP_PASSWORD=${MP_PASSWORD:-$(ask -s 'Master Password:')}
|
||||||
|
|
||||||
|
# Start Master Password and copy the output.
|
||||||
|
printf %s "$(MP_USERNAME=$MP_USERNAME MP_PASSWORD=$MP_PASSWORD command mpw "$@")" | _copy
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module>masterpassword-algorithm</module>
|
<module>masterpassword-algorithm</module>
|
||||||
<module>masterpassword-cli</module>
|
<module>masterpassword-cli</module>
|
||||||
<module>masterpassword-android</module>
|
<!--module>masterpassword-android</module-->
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<!-- REMOTE ARTIFACT REPOSITORIES -->
|
<!-- REMOTE ARTIFACT REPOSITORIES -->
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
- (NSString *)shortNameOfType:(MPElementType)type;
|
- (NSString *)shortNameOfType:(MPElementType)type;
|
||||||
- (NSString *)classNameOfType:(MPElementType)type;
|
- (NSString *)classNameOfType:(MPElementType)type;
|
||||||
- (Class)classOfType:(MPElementType)type;
|
- (Class)classOfType:(MPElementType)type;
|
||||||
|
- (MPElementType)nextType:(MPElementType)type;
|
||||||
|
- (MPElementType)previousType:(MPElementType)type;
|
||||||
|
|
||||||
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key;
|
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key;
|
||||||
- (NSString *)storedContentForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
|
- (NSString *)storedContentForElement:(MPElementStoredEntity *)element usingKey:(MPKey *)key;
|
||||||
|
|||||||
@@ -31,6 +31,21 @@
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)description {
|
||||||
|
|
||||||
|
return strf( @"<%@: version=%d>", NSStringFromClass( [self class] ), self.version );
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)other {
|
||||||
|
|
||||||
|
if (other == self)
|
||||||
|
return YES;
|
||||||
|
if (!other || ![other conformsToProtocol:@protocol(MPAlgorithm)])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return [(id<MPAlgorithm>)other version] == [self version];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)migrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
|
- (BOOL)migrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
|
||||||
|
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
@@ -127,7 +142,7 @@
|
|||||||
return @"Device Private Password";
|
return @"Device Private Password";
|
||||||
}
|
}
|
||||||
|
|
||||||
Throw(@"Type not supported: %d", type);
|
Throw(@"Type not supported: %lu", (long)type);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)shortNameOfType:(MPElementType)type {
|
- (NSString *)shortNameOfType:(MPElementType)type {
|
||||||
@@ -161,7 +176,7 @@
|
|||||||
return @"Device";
|
return @"Device";
|
||||||
}
|
}
|
||||||
|
|
||||||
Throw(@"Type not supported: %d", type);
|
Throw(@"Type not supported: %lu", (long)type);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)classNameOfType:(MPElementType)type {
|
- (NSString *)classNameOfType:(MPElementType)type {
|
||||||
@@ -200,7 +215,43 @@
|
|||||||
return [MPElementStoredEntity class];
|
return [MPElementStoredEntity class];
|
||||||
}
|
}
|
||||||
|
|
||||||
Throw(@"Type not supported: %d", type);
|
Throw(@"Type not supported: %lu", (long)type);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementType)nextType:(MPElementType)type {
|
||||||
|
|
||||||
|
if (!type)
|
||||||
|
Throw(@"No type given.");
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MPElementTypeGeneratedMaximum:
|
||||||
|
return MPElementTypeStoredDevicePrivate;
|
||||||
|
case MPElementTypeGeneratedLong:
|
||||||
|
return MPElementTypeGeneratedMaximum;
|
||||||
|
case MPElementTypeGeneratedMedium:
|
||||||
|
return MPElementTypeGeneratedLong;
|
||||||
|
case MPElementTypeGeneratedBasic:
|
||||||
|
return MPElementTypeGeneratedMedium;
|
||||||
|
case MPElementTypeGeneratedShort:
|
||||||
|
return MPElementTypeGeneratedBasic;
|
||||||
|
case MPElementTypeGeneratedPIN:
|
||||||
|
return MPElementTypeGeneratedShort;
|
||||||
|
case MPElementTypeStoredPersonal:
|
||||||
|
return MPElementTypeGeneratedPIN;
|
||||||
|
case MPElementTypeStoredDevicePrivate:
|
||||||
|
return MPElementTypeStoredPersonal;
|
||||||
|
}
|
||||||
|
|
||||||
|
Throw(@"Type not supported: %lu", (long)type);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementType)previousType:(MPElementType)type {
|
||||||
|
|
||||||
|
MPElementType previousType = type, nextType = type;
|
||||||
|
while ((nextType = [self nextType:nextType]) != type)
|
||||||
|
previousType = nextType;
|
||||||
|
|
||||||
|
return previousType;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key {
|
- (NSString *)generateContentNamed:(NSString *)name ofType:(MPElementType)type withCounter:(NSUInteger)counter usingKey:(MPKey *)key {
|
||||||
@@ -214,23 +265,24 @@
|
|||||||
uint32_t ncounter = htonl(counter), nnameLength = htonl(name.length);
|
uint32_t ncounter = htonl(counter), nnameLength = htonl(name.length);
|
||||||
NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof(ncounter)];
|
NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof(ncounter)];
|
||||||
NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof(nnameLength)];
|
NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof(nnameLength)];
|
||||||
trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64], [nameLengthBytes encodeHex], name, [counterBytes encodeHex]);
|
trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key.keyData encodeBase64],
|
||||||
|
[nameLengthBytes encodeHex], name, [counterBytes encodeHex]);
|
||||||
NSData *seed = [[NSData dataByConcatenatingDatas:
|
NSData *seed = [[NSData dataByConcatenatingDatas:
|
||||||
[@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding],
|
[@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding],
|
||||||
nameLengthBytes,
|
nameLengthBytes, [name dataUsingEncoding:NSUTF8StringEncoding],
|
||||||
[name dataUsingEncoding:NSUTF8StringEncoding],
|
counterBytes, nil]
|
||||||
counterBytes,
|
|
||||||
nil]
|
|
||||||
hmacWith:PearlHashSHA256 key:key.keyData];
|
hmacWith:PearlHashSHA256 key:key.keyData];
|
||||||
trc(@"seed is: %@", [seed encodeBase64]);
|
trc(@"seed is: %@", [seed encodeBase64]);
|
||||||
const char *seedBytes = seed.bytes;
|
const char *seedBytes = seed.bytes;
|
||||||
|
|
||||||
// Determine the cipher from the first seed byte.
|
// Determine the cipher from the first seed byte.
|
||||||
NSAssert([seed length], @"Missing seed.");
|
NSAssert([seed length], @"Missing seed.");
|
||||||
NSArray *typeCiphers = [[MPTypes_ciphers valueForKey:[self classNameOfType:type]]
|
NSString *typeClass = [self classNameOfType:type];
|
||||||
valueForKey:[self nameOfType:type]];
|
NSString *typeName = [self nameOfType:type];
|
||||||
|
id classCiphers = [MPTypes_ciphers valueForKey:typeClass];
|
||||||
|
NSArray *typeCiphers = [classCiphers valueForKey:typeName];
|
||||||
NSString *cipher = typeCiphers[htons(seedBytes[0]) % [typeCiphers count]];
|
NSString *cipher = typeCiphers[htons(seedBytes[0]) % [typeCiphers count]];
|
||||||
trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher);
|
trc(@"type %@, ciphers: %@, selected: %@", typeName, typeCiphers, cipher);
|
||||||
|
|
||||||
// Encode the content, character by character, using subsequent seed bytes and the cipher.
|
// Encode the content, character by character, using subsequent seed bytes and the cipher.
|
||||||
NSAssert([seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher.");
|
NSAssert([seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher.");
|
||||||
@@ -239,8 +291,7 @@
|
|||||||
uint16_t keyByte = htons(seedBytes[c + 1]);
|
uint16_t keyByte = htons(seedBytes[c + 1]);
|
||||||
NSString *cipherClass = [cipher substringWithRange:NSMakeRange( c, 1 )];
|
NSString *cipherClass = [cipher substringWithRange:NSMakeRange( c, 1 )];
|
||||||
NSString *cipherClassCharacters = [[MPTypes_ciphers valueForKey:@"MPCharacterClasses"] valueForKey:cipherClass];
|
NSString *cipherClassCharacters = [[MPTypes_ciphers valueForKey:@"MPCharacterClasses"] valueForKey:cipherClass];
|
||||||
NSString *character = [cipherClassCharacters substringWithRange:NSMakeRange( keyByte % [cipherClassCharacters length],
|
NSString *character = [cipherClassCharacters substringWithRange:NSMakeRange( keyByte % [cipherClassCharacters length], 1 )];
|
||||||
1 )];
|
|
||||||
|
|
||||||
trc(@"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character);
|
trc(@"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character);
|
||||||
[content appendString:character];
|
[content appendString:character];
|
||||||
@@ -264,13 +315,13 @@
|
|||||||
case MPElementTypeGeneratedBasic:
|
case MPElementTypeGeneratedBasic:
|
||||||
case MPElementTypeGeneratedShort:
|
case MPElementTypeGeneratedShort:
|
||||||
case MPElementTypeGeneratedPIN: {
|
case MPElementTypeGeneratedPIN: {
|
||||||
NSAssert(NO, @"Cannot save content to element with generated type %d.", element.type);
|
NSAssert(NO, @"Cannot save content to element with generated type %lu.", (long)element.type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, [element class]);
|
||||||
|
|
||||||
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||||
@@ -279,7 +330,7 @@
|
|||||||
}
|
}
|
||||||
case MPElementTypeStoredDevicePrivate: {
|
case MPElementTypeStoredDevicePrivate: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, [element class]);
|
||||||
|
|
||||||
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
encryptWithSymmetricKey:[elementKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||||
@@ -324,7 +375,7 @@
|
|||||||
case MPElementTypeGeneratedShort:
|
case MPElementTypeGeneratedShort:
|
||||||
case MPElementTypeGeneratedPIN: {
|
case MPElementTypeGeneratedPIN: {
|
||||||
NSAssert([element isKindOfClass:[MPElementGeneratedEntity class]],
|
NSAssert([element isKindOfClass:[MPElementGeneratedEntity class]],
|
||||||
@"Element with generated type %d is not an MPElementGeneratedEntity, but a %@.", element.type, [element class]);
|
@"Element with generated type %lu is not an MPElementGeneratedEntity, but a %@.", (long)element.type, [element class]);
|
||||||
|
|
||||||
NSString *name = element.name;
|
NSString *name = element.name;
|
||||||
MPElementType type = element.type;
|
MPElementType type = element.type;
|
||||||
@@ -346,7 +397,7 @@
|
|||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, [element class]);
|
||||||
|
|
||||||
NSData *encryptedContent = ((MPElementStoredEntity *)element).contentObject;
|
NSData *encryptedContent = ((MPElementStoredEntity *)element).contentObject;
|
||||||
|
|
||||||
@@ -358,7 +409,7 @@
|
|||||||
}
|
}
|
||||||
case MPElementTypeStoredDevicePrivate: {
|
case MPElementTypeStoredDevicePrivate: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, [element class]);
|
||||||
|
|
||||||
NSDictionary *elementQuery = [self queryForDevicePrivateElementNamed:element.name];
|
NSDictionary *elementQuery = [self queryForDevicePrivateElementNamed:element.name];
|
||||||
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:elementQuery];
|
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:elementQuery];
|
||||||
@@ -387,7 +438,7 @@
|
|||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, [element class]);
|
||||||
if ([importKey.keyID isEqualToData:elementKey.keyID])
|
if ([importKey.keyID isEqualToData:elementKey.keyID])
|
||||||
((MPElementStoredEntity *)element).contentObject = [protectedContent decodeBase64];
|
((MPElementStoredEntity *)element).contentObject = [protectedContent decodeBase64];
|
||||||
|
|
||||||
@@ -445,7 +496,7 @@
|
|||||||
|
|
||||||
case MPElementTypeStoredPersonal: {
|
case MPElementTypeStoredPersonal: {
|
||||||
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
NSAssert([element isKindOfClass:[MPElementStoredEntity class]],
|
||||||
@"Element with stored type %d is not an MPElementStoredEntity, but a %@.", element.type, [element class]);
|
@"Element with stored type %lu is not an MPElementStoredEntity, but a %@.", (long)element.type, [element class]);
|
||||||
result = [((MPElementStoredEntity *)element).contentObject encodeBase64];
|
result = [((MPElementStoredEntity *)element).contentObject encodeBase64];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
|||||||
|
|
||||||
if (password)
|
if (password)
|
||||||
NSAssert(![NSThread isMainThread], @"Computing key must not happen from the main thread.");
|
NSAssert(![NSThread isMainThread], @"Computing key must not happen from the main thread.");
|
||||||
|
if (!user)
|
||||||
|
return NO;
|
||||||
|
|
||||||
MPKey *tryKey = nil;
|
MPKey *tryKey = nil;
|
||||||
|
|
||||||
@@ -166,7 +168,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
|||||||
|
|
||||||
MPKey *recoverKey = newKey;
|
MPKey *recoverKey = newKey;
|
||||||
#ifdef PEARL_UIKIT
|
#ifdef PEARL_UIKIT
|
||||||
PearlOverlay *activityOverlay = [PearlOverlay showOverlayWithTitle:PearlString( @"Migrating %ld sites...", (long)[user.elements count] )];
|
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:PearlString( @"Migrating %ld sites...", (long)[user.elements count] )];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (MPElementEntity *element in user.elements) {
|
for (MPElementEntity *element in user.elements) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
@property(strong, nonatomic) MPKey *key;
|
@property(strong, nonatomic) MPKey *key;
|
||||||
|
@property(strong, nonatomic) NSManagedObjectID *activeUserOID;
|
||||||
|
|
||||||
+ (instancetype)get;
|
+ (instancetype)get;
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,7 @@
|
|||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
|
|
||||||
@implementation MPAppDelegate_Shared {
|
@implementation MPAppDelegate_Shared
|
||||||
NSManagedObjectID *_activeUserOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (MPAppDelegate_Shared *)get {
|
+ (MPAppDelegate_Shared *)get {
|
||||||
|
|
||||||
@@ -32,11 +30,12 @@
|
|||||||
|
|
||||||
- (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc {
|
- (MPUserEntity *)activeUserInContext:(NSManagedObjectContext *)moc {
|
||||||
|
|
||||||
if (!_activeUserOID || !moc)
|
NSManagedObjectID *activeUserOID = self.activeUserOID;
|
||||||
|
if (!activeUserOID || !moc)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
NSError *error;
|
NSError *error;
|
||||||
MPUserEntity *activeUser = (MPUserEntity *)[moc existingObjectWithID:_activeUserOID error:&error];
|
MPUserEntity *activeUser = (MPUserEntity *)[moc existingObjectWithID:activeUserOID error:&error];
|
||||||
if (!activeUser) {
|
if (!activeUser) {
|
||||||
[self signOutAnimated:YES];
|
[self signOutAnimated:YES];
|
||||||
err(@"Failed to retrieve active user: %@", error);
|
err(@"Failed to retrieve active user: %@", error);
|
||||||
@@ -51,7 +50,7 @@
|
|||||||
if (activeUser.objectID.isTemporaryID && ![activeUser.managedObjectContext obtainPermanentIDsForObjects:@[ activeUser ] error:&error])
|
if (activeUser.objectID.isTemporaryID && ![activeUser.managedObjectContext obtainPermanentIDsForObjects:@[ activeUser ] error:&error])
|
||||||
err(@"Failed to obtain a permanent object ID after setting active user: %@", error);
|
err(@"Failed to obtain a permanent object ID after setting active user: %@", error);
|
||||||
|
|
||||||
_activeUserOID = activeUser.objectID;
|
self.activeUserOID = activeUser.objectID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ typedef enum {
|
|||||||
@interface MPAppDelegate_Shared(Store)<UbiquityStoreManagerDelegate>
|
@interface MPAppDelegate_Shared(Store)<UbiquityStoreManagerDelegate>
|
||||||
|
|
||||||
+ (NSManagedObjectContext *)managedObjectContextForMainThreadIfReady;
|
+ (NSManagedObjectContext *)managedObjectContextForMainThreadIfReady;
|
||||||
|
+ (BOOL)managedObjectContextForMainThreadPerformBlock:(void (^)(NSManagedObjectContext *mainContext))mocBlock;
|
||||||
|
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void (^)(NSManagedObjectContext *mainContext))mocBlock;
|
||||||
+ (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock;
|
+ (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock;
|
||||||
+ (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock;
|
+ (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock;
|
||||||
|
|
||||||
@@ -28,10 +30,10 @@ typedef enum {
|
|||||||
|
|
||||||
/** @param completion The block to execute after adding the element, executed from the main thread with the new element in the main MOC. */
|
/** @param completion The block to execute after adding the element, executed from the main thread with the new element in the main MOC. */
|
||||||
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(MPElementEntity *element))completion;
|
- (void)addElementNamed:(NSString *)siteName completion:(void (^)(MPElementEntity *element))completion;
|
||||||
- (MPElementEntity *)changeElement:(MPElementEntity *)element inContext:(NSManagedObjectContext *)context toType:(MPElementType)type;
|
- (MPElementEntity *)changeElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context toType:(MPElementType)type;
|
||||||
- (MPImportResult)importSites:(NSString *)importedSitesString
|
- (MPImportResult)importSites:(NSString *)importedSitesString
|
||||||
askImportPassword:(NSString *(^)(NSString *userName))importPassword
|
askImportPassword:(NSString *(^)(NSString *userName))importPassword
|
||||||
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;
|
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;
|
||||||
- (NSString *)exportSitesShowingPasswords:(BOOL)showPasswords;
|
- (NSString *)exportSitesRevealPasswords:(BOOL)revealPasswords;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ typedef NS_ENUM(NSInteger, MPMigrationLevelCloudStore) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@implementation MPAppDelegate_Shared(Store)
|
@implementation MPAppDelegate_Shared(Store)
|
||||||
PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext);
|
PearlAssociatedObjectProperty(id, SaveObserver, saveObserver);
|
||||||
|
PearlAssociatedObjectProperty(NSManagedObjectContext*, PrivateManagedObjectContext, privateManagedObjectContext);
|
||||||
PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext);
|
PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, mainManagedObjectContext);
|
||||||
|
|
||||||
|
|
||||||
@@ -48,14 +49,40 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
return mainManagedObjectContext;
|
return mainManagedObjectContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock {
|
+ (BOOL)managedObjectContextForMainThreadPerformBlock:(void (^)(NSManagedObjectContext *mainContext))mocBlock {
|
||||||
|
|
||||||
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady];
|
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady];
|
||||||
if (!mainManagedObjectContext)
|
if (!mainManagedObjectContext)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
|
[mainManagedObjectContext performBlock:^{
|
||||||
|
mocBlock( mainManagedObjectContext );
|
||||||
|
}];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void (^)(NSManagedObjectContext *mainContext))mocBlock {
|
||||||
|
|
||||||
|
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady];
|
||||||
|
if (!mainManagedObjectContext)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[mainManagedObjectContext performBlockAndWait:^{
|
||||||
|
mocBlock( mainManagedObjectContext );
|
||||||
|
}];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)managedObjectContextPerformBlock:(void (^)(NSManagedObjectContext *context))mocBlock {
|
||||||
|
|
||||||
|
NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady];
|
||||||
|
if (!privateManagedObjectContextIfReady)
|
||||||
|
return NO;
|
||||||
|
|
||||||
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||||
moc.parentContext = mainManagedObjectContext;
|
moc.parentContext = privateManagedObjectContextIfReady;
|
||||||
[moc performBlock:^{
|
[moc performBlock:^{
|
||||||
mocBlock( moc );
|
mocBlock( moc );
|
||||||
}];
|
}];
|
||||||
@@ -65,12 +92,12 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
+ (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock {
|
+ (BOOL)managedObjectContextPerformBlockAndWait:(void (^)(NSManagedObjectContext *context))mocBlock {
|
||||||
|
|
||||||
NSManagedObjectContext *mainManagedObjectContext = [[self get] mainManagedObjectContextIfReady];
|
NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady];
|
||||||
if (!mainManagedObjectContext)
|
if (!privateManagedObjectContextIfReady)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||||
moc.parentContext = mainManagedObjectContext;
|
moc.parentContext = privateManagedObjectContextIfReady;
|
||||||
[moc performBlockAndWait:^{
|
[moc performBlockAndWait:^{
|
||||||
mocBlock( moc );
|
mocBlock( moc );
|
||||||
}];
|
}];
|
||||||
@@ -98,7 +125,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
storeManager = [[UbiquityStoreManager alloc] initStoreNamed:nil withManagedObjectModel:nil localStoreURL:nil
|
storeManager = [[UbiquityStoreManager alloc] initStoreNamed:nil withManagedObjectModel:nil localStoreURL:nil
|
||||||
containerIdentifier:MPCloudContainerIdentifier
|
containerIdentifier:MPCloudContainerIdentifier
|
||||||
additionalStoreOptions:@{ STORE_OPTIONS }
|
storeConfiguration:nil storeOptions:@{ STORE_OPTIONS }
|
||||||
delegate:self];
|
delegate:self];
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
@@ -197,7 +224,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
URLByAppendingPathComponent:@"Database.nosync" isDirectory:YES]
|
URLByAppendingPathComponent:@"Database.nosync" isDirectory:YES]
|
||||||
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
|
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
|
||||||
|
|
||||||
return [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL contentName:uuid];
|
return [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)migrateV2CloudStore {
|
- (BOOL)migrateV2CloudStore {
|
||||||
@@ -218,7 +245,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
URLByAppendingPathComponent:@"CloudStore.nosync" isDirectory:YES]
|
URLByAppendingPathComponent:@"CloudStore.nosync" isDirectory:YES]
|
||||||
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
|
URLByAppendingPathComponent:uuid isDirectory:NO] URLByAppendingPathExtension:@"sqlite"];
|
||||||
|
|
||||||
return [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL contentName:uuid];
|
return [self migrateFromCloudStore:oldCloudStoreURL cloudContent:oldCloudContentURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)migrateV1LocalStore {
|
- (BOOL)migrateV1LocalStore {
|
||||||
@@ -255,7 +282,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)migrateFromCloudStore:(NSURL *)oldCloudStoreURL cloudContent:(NSURL *)oldCloudContentURL contentName:(NSString *)contentName {
|
- (BOOL)migrateFromCloudStore:(NSURL *)oldCloudStoreURL cloudContent:(NSURL *)oldCloudContentURL {
|
||||||
|
|
||||||
if (![self.storeManager cloudSafeForSeeding]) {
|
if (![self.storeManager cloudSafeForSeeding]) {
|
||||||
inf(@"Can't migrate cloud store: A new cloud store already exists.");
|
inf(@"Can't migrate cloud store: A new cloud store already exists.");
|
||||||
@@ -274,7 +301,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
#pragma mark - UbiquityStoreManagerDelegate
|
#pragma mark - UbiquityStoreManagerDelegate
|
||||||
|
|
||||||
- (NSManagedObjectContext *)managedObjectContextForUbiquityChangesInManager:(UbiquityStoreManager *)manager {
|
- (NSManagedObjectContext *)ubiquityStoreManager:(UbiquityStoreManager *)manager
|
||||||
|
managedObjectContextForUbiquityChanges:(NSNotification *)note {
|
||||||
|
|
||||||
return [self mainManagedObjectContextIfReady];
|
return [self mainManagedObjectContextIfReady];
|
||||||
}
|
}
|
||||||
@@ -291,6 +319,11 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
[moc saveToStore];
|
[moc saveToStore];
|
||||||
[moc reset];
|
[moc reset];
|
||||||
|
|
||||||
|
if (self.saveObserver) {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
|
||||||
|
self.saveObserver = nil;
|
||||||
|
}
|
||||||
|
|
||||||
self.privateManagedObjectContext = nil;
|
self.privateManagedObjectContext = nil;
|
||||||
self.mainManagedObjectContext = nil;
|
self.mainManagedObjectContext = nil;
|
||||||
}];
|
}];
|
||||||
@@ -307,8 +340,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
// Create our contexts.
|
// Create our contexts.
|
||||||
NSManagedObjectContext
|
NSManagedObjectContext *privateManagedObjectContext =
|
||||||
*privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||||
[privateManagedObjectContext performBlockAndWait:^{
|
[privateManagedObjectContext performBlockAndWait:^{
|
||||||
privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
||||||
privateManagedObjectContext.persistentStoreCoordinator = coordinator;
|
privateManagedObjectContext.persistentStoreCoordinator = coordinator;
|
||||||
@@ -331,6 +364,17 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
NSManagedObjectContext *mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
NSManagedObjectContext *mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||||
mainManagedObjectContext.parentContext = privateManagedObjectContext;
|
mainManagedObjectContext.parentContext = privateManagedObjectContext;
|
||||||
|
|
||||||
|
if (self.saveObserver)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self.saveObserver];
|
||||||
|
self.saveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification
|
||||||
|
object:privateManagedObjectContext queue:nil usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
|
||||||
|
[mainManagedObjectContext performBlock:^{
|
||||||
|
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:note];
|
||||||
|
}];
|
||||||
|
}];
|
||||||
|
|
||||||
self.privateManagedObjectContext = privateManagedObjectContext;
|
self.privateManagedObjectContext = privateManagedObjectContext;
|
||||||
self.mainManagedObjectContext = mainManagedObjectContext;
|
self.mainManagedObjectContext = mainManagedObjectContext;
|
||||||
}
|
}
|
||||||
@@ -359,46 +403,45 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
MPUserEntity *activeUser = [self activeUserInContext:context];
|
MPUserEntity *activeUser = [self activeUserInContext:context];
|
||||||
NSAssert(activeUser, @"Missing user.");
|
NSAssert(activeUser, @"Missing user.");
|
||||||
if (!activeUser)
|
if (!activeUser) {
|
||||||
|
completion( nil );
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MPElementType type = activeUser.defaultType;
|
MPElementType type = activeUser.defaultType;
|
||||||
if (!type)
|
NSString *typeEntityName = [MPAlgorithmDefault classNameOfType:type];
|
||||||
type = activeUser.defaultType = MPElementTypeGeneratedLong;
|
|
||||||
NSString *typeEntityClassName = [MPAlgorithmDefault classNameOfType:type];
|
|
||||||
|
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityClassName
|
|
||||||
inManagedObjectContext:context];
|
|
||||||
|
|
||||||
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
|
||||||
element.name = siteName;
|
element.name = siteName;
|
||||||
element.user = activeUser;
|
element.user = activeUser;
|
||||||
element.type = type;
|
element.type = type;
|
||||||
element.lastUsed = [NSDate date];
|
element.lastUsed = [NSDate date];
|
||||||
element.version = MPAlgorithmDefaultVersion;
|
element.version = MPAlgorithmDefaultVersion;
|
||||||
[context saveToStore];
|
|
||||||
|
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
if (element.objectID.isTemporaryID && ![context obtainPermanentIDsForObjects:@[ element ] error:&error])
|
if (element.objectID.isTemporaryID && ![context obtainPermanentIDsForObjects:@[ element ] error:&error])
|
||||||
err(@"Failed to obtain a permanent object ID after creating new element: %@", error);
|
err(@"Failed to obtain a permanent object ID after creating new element: %@", error);
|
||||||
|
|
||||||
NSManagedObjectID *elementOID = [element objectID];
|
[context saveToStore];
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
|
||||||
completion(
|
completion( element );
|
||||||
(MPElementEntity *)[[MPAppDelegate_Shared managedObjectContextForMainThreadIfReady] objectRegisteredForID:elementOID] );
|
|
||||||
} );
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (MPElementEntity *)changeElement:(MPElementEntity *)element inContext:(NSManagedObjectContext *)context toType:(MPElementType)type {
|
- (MPElementEntity *)changeElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context toType:(MPElementType)type {
|
||||||
|
|
||||||
if ([element.algorithm classOfType:type] == element.typeClass)
|
if (element.type == type)
|
||||||
|
return element;
|
||||||
|
|
||||||
|
if ([element.algorithm classOfType:type] == element.typeClass) {
|
||||||
element.type = type;
|
element.type = type;
|
||||||
|
[context saveToStore];
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
// Type requires a different class of element. Recreate the element.
|
// Type requires a different class of element. Recreate the element.
|
||||||
MPElementEntity *newElement
|
NSString *typeEntityName = [element.algorithm classNameOfType:type];
|
||||||
= [NSEntityDescription insertNewObjectForEntityForName:[element.algorithm classNameOfType:type]
|
MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
|
||||||
inManagedObjectContext:context];
|
|
||||||
newElement.type = type;
|
newElement.type = type;
|
||||||
newElement.name = element.name;
|
newElement.name = element.name;
|
||||||
newElement.user = element.user;
|
newElement.user = element.user;
|
||||||
@@ -407,13 +450,14 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
newElement.version = element.version;
|
newElement.version = element.version;
|
||||||
newElement.loginName = element.loginName;
|
newElement.loginName = element.loginName;
|
||||||
|
|
||||||
[context deleteObject:element];
|
NSError *error = nil;
|
||||||
[context saveToStore];
|
|
||||||
|
|
||||||
NSError *error;
|
|
||||||
if (![context obtainPermanentIDsForObjects:@[ newElement ] error:&error])
|
if (![context obtainPermanentIDsForObjects:@[ newElement ] error:&error])
|
||||||
err(@"Failed to obtain a permanent object ID after changing object type: %@", error);
|
err(@"Failed to obtain a permanent object ID after changing object type: %@", error);
|
||||||
|
|
||||||
|
[context deleteObject:element];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPElementUpdatedNotification object:element.objectID];
|
||||||
element = newElement;
|
element = newElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,7 +622,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
// Ask for confirmation to import these sites and the master password of the user.
|
// Ask for confirmation to import these sites and the master password of the user.
|
||||||
inf(@"Importing %lu sites, deleting %lu sites, for user: %@", (unsigned long)[importedSiteElements count], (unsigned long)[elementsToDelete count], [MPUserEntity idFor:importUserName]);
|
inf(@"Importing %lu sites, deleting %lu sites, for user: %@", (unsigned long)[importedSiteElements count], (unsigned long)[elementsToDelete count], [MPUserEntity idFor:importUserName]);
|
||||||
NSString *userMasterPassword = askUserPassword( user? user.name: importUserName, [importedSiteElements count], [elementsToDelete count] );
|
NSString *userMasterPassword = askUserPassword( user? user.name: importUserName, [importedSiteElements count],
|
||||||
|
[elementsToDelete count] );
|
||||||
if (!userMasterPassword) {
|
if (!userMasterPassword) {
|
||||||
inf(@"Import cancelled.");
|
inf(@"Import cancelled.");
|
||||||
return MPImportResultCancelled;
|
return MPImportResultCancelled;
|
||||||
@@ -602,8 +647,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
// Make sure there is a user.
|
// Make sure there is a user.
|
||||||
if (!user) {
|
if (!user) {
|
||||||
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] )
|
user = [MPUserEntity insertNewObjectInContext:context];
|
||||||
inManagedObjectContext:context];
|
|
||||||
user.name = importUserName;
|
user.name = importUserName;
|
||||||
user.keyID = importKeyID;
|
user.keyID = importKeyID;
|
||||||
dbg(@"Created User: %@", [user debugDescription]);
|
dbg(@"Created User: %@", [user debugDescription]);
|
||||||
@@ -619,9 +663,8 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
NSString *exportContent = siteElements[5];
|
NSString *exportContent = siteElements[5];
|
||||||
|
|
||||||
// Create new site.
|
// Create new site.
|
||||||
MPElementEntity
|
NSString *typeEntityName = [MPAlgorithmForVersion( version ) classNameOfType:type];
|
||||||
*element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmForVersion( version ) classNameOfType:type]
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:typeEntityName inManagedObjectContext:context];
|
||||||
inManagedObjectContext:context];
|
|
||||||
element.name = name;
|
element.name = name;
|
||||||
element.user = user;
|
element.user = user;
|
||||||
element.type = type;
|
element.type = type;
|
||||||
@@ -645,21 +688,21 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
MPCheckpoint( MPCheckpointSitesImported, nil );
|
MPCheckpoint( MPCheckpointSitesImported, nil );
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPSitesImportedNotification object:nil userInfo:@{
|
[[NSNotificationCenter defaultCenter] postNotificationName:MPSitesImportedNotification object:nil userInfo:@{
|
||||||
MPSitesImportedNotificationUserKey: user
|
MPSitesImportedNotificationUserKey : user
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return MPImportResultSuccess;
|
return MPImportResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)exportSitesShowingPasswords:(BOOL)showPasswords {
|
- (NSString *)exportSitesRevealPasswords:(BOOL)revealPasswords {
|
||||||
|
|
||||||
MPUserEntity *activeUser = [self activeUserForMainThread];
|
MPUserEntity *activeUser = [self activeUserForMainThread];
|
||||||
inf(@"Exporting sites, %@, for: %@", showPasswords? @"showing passwords": @"omitting passwords", activeUser.userID);
|
inf(@"Exporting sites, %@, for: %@", revealPasswords? @"revealing passwords": @"omitting passwords", activeUser.userID);
|
||||||
|
|
||||||
// Header.
|
// Header.
|
||||||
NSMutableString *export = [NSMutableString new];
|
NSMutableString *export = [NSMutableString new];
|
||||||
[export appendFormat:@"# Master Password site export\n"];
|
[export appendFormat:@"# Master Password site export\n"];
|
||||||
if (showPasswords)
|
if (revealPasswords)
|
||||||
[export appendFormat:@"# Export of site names and passwords in clear-text.\n"];
|
[export appendFormat:@"# Export of site names and passwords in clear-text.\n"];
|
||||||
else
|
else
|
||||||
[export appendFormat:@"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n"];
|
[export appendFormat:@"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n"];
|
||||||
@@ -669,7 +712,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
[export appendFormat:@"# User Name: %@\n", activeUser.name];
|
[export appendFormat:@"# User Name: %@\n", activeUser.name];
|
||||||
[export appendFormat:@"# Key ID: %@\n", [activeUser.keyID encodeHex]];
|
[export appendFormat:@"# Key ID: %@\n", [activeUser.keyID encodeHex]];
|
||||||
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
|
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
|
||||||
if (showPasswords)
|
if (revealPasswords)
|
||||||
[export appendFormat:@"# Passwords: VISIBLE\n"];
|
[export appendFormat:@"# Passwords: VISIBLE\n"];
|
||||||
else
|
else
|
||||||
[export appendFormat:@"# Passwords: PROTECTED\n"];
|
[export appendFormat:@"# Passwords: PROTECTED\n"];
|
||||||
@@ -689,7 +732,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
// Determine the content to export.
|
// Determine the content to export.
|
||||||
if (!(type & MPElementFeatureDevicePrivate)) {
|
if (!(type & MPElementFeatureDevicePrivate)) {
|
||||||
if (showPasswords)
|
if (revealPasswords)
|
||||||
content = [element.algorithm resolveContentForElement:element usingKey:self.key];
|
content = [element.algorithm resolveContentForElement:element usingKey:self.key];
|
||||||
else if (type & MPElementFeatureExportContent)
|
else if (type & MPElementFeatureExportContent)
|
||||||
content = [element.algorithm exportContentForElement:element usingKey:self.key];
|
content = [element.algorithm exportContentForElement:element usingKey:self.key];
|
||||||
@@ -697,12 +740,12 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
|
|||||||
|
|
||||||
[export appendFormat:@"%@ %8ld %8s %20s\t%@\n",
|
[export appendFormat:@"%@ %8ld %8s %20s\t%@\n",
|
||||||
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:lastUsed], (long)uses,
|
[[NSDateFormatter rfc3339DateFormatter] stringFromDate:lastUsed], (long)uses,
|
||||||
[PearlString( @"%u:%lu", type, (unsigned long)version ) UTF8String], [name UTF8String], content
|
[PearlString( @"%lu:%lu", (long)type, (unsigned long)version ) UTF8String], [name UTF8String], content
|
||||||
? content: @""];
|
? content: @""];
|
||||||
}
|
}
|
||||||
|
|
||||||
MPCheckpoint( MPCheckpointSitesExported, @{
|
MPCheckpoint( MPCheckpointSitesExported, @{
|
||||||
@"showPasswords" : @(showPasswords)
|
@"showPasswords" : @(revealPasswords)
|
||||||
} );
|
} );
|
||||||
|
|
||||||
return export;
|
return export;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
- (NSUInteger)use;
|
- (NSUInteger)use;
|
||||||
- (BOOL)migrateExplicitly:(BOOL)explicit;
|
- (BOOL)migrateExplicitly:(BOOL)explicit;
|
||||||
|
- (NSString *)resolveContentUsingKey:(MPKey *)key;
|
||||||
|
- (void)resolveContentUsingKey:(MPKey *)key result:(void (^)(NSString *))result;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,14 @@
|
|||||||
|
|
||||||
#import "MPEntities.h"
|
#import "MPEntities.h"
|
||||||
#import "MPAppDelegate_Shared.h"
|
#import "MPAppDelegate_Shared.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
@implementation NSManagedObjectContext(MP)
|
@implementation NSManagedObjectContext(MP)
|
||||||
|
|
||||||
- (BOOL)saveToStore {
|
- (BOOL)saveToStore {
|
||||||
|
|
||||||
__block BOOL success = YES;
|
__block BOOL success = YES;
|
||||||
if ([self hasChanges])
|
if ([self hasChanges]) {
|
||||||
[self performBlockAndWait:^{
|
[self performBlockAndWait:^{
|
||||||
@try {
|
@try {
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
err(@"While saving: %@", exception);
|
err(@"While saving: %@", exception);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
return success && (!self.parentContext || [self.parentContext saveToStore]);
|
return success && (!self.parentContext || [self.parentContext saveToStore]);
|
||||||
}
|
}
|
||||||
@@ -42,6 +44,14 @@
|
|||||||
type = [self.user defaultType];
|
type = [self.user defaultType];
|
||||||
if (!type || type == (MPElementType)NSNotFound)
|
if (!type || type == (MPElementType)NSNotFound)
|
||||||
type = MPElementTypeGeneratedLong;
|
type = MPElementTypeGeneratedLong;
|
||||||
|
if (![self isKindOfClass:[self.algorithm classOfType:type]]) {
|
||||||
|
// NSAssert(NO, @"This object's class does not support the type: %lu", (long)type);
|
||||||
|
for (MPElementType aType = type; type != (aType = [self.algorithm nextType:aType]);)
|
||||||
|
if ([self isKindOfClass:[self.algorithm classOfType:aType]]) {
|
||||||
|
err(@"Invalid type for: %@, type: %lu. Will use %lu instead.", self.name, (long)type, (long)aType);
|
||||||
|
return aType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@@ -53,6 +63,8 @@
|
|||||||
aType = [self.user defaultType];
|
aType = [self.user defaultType];
|
||||||
if (!aType || aType == (MPElementType)NSNotFound)
|
if (!aType || aType == (MPElementType)NSNotFound)
|
||||||
aType = MPElementTypeGeneratedLong;
|
aType = MPElementTypeGeneratedLong;
|
||||||
|
if (![self isKindOfClass:[self.algorithm classOfType:aType]])
|
||||||
|
Throw(@"This object's class does not support the type: %lu", (long)aType);
|
||||||
|
|
||||||
self.type_ = @(aType);
|
self.type_ = @(aType);
|
||||||
}
|
}
|
||||||
@@ -125,8 +137,8 @@
|
|||||||
|
|
||||||
- (NSString *)debugDescription {
|
- (NSString *)debugDescription {
|
||||||
|
|
||||||
return PearlString( @"{%@: name=%@, user=%@, type=%d, uses=%ld, lastUsed=%@, version=%ld, loginName=%@, requiresExplicitMigration=%d}",
|
return PearlString( @"{%@: name=%@, user=%@, type=%lu, uses=%ld, lastUsed=%@, version=%ld, loginName=%@, requiresExplicitMigration=%d}",
|
||||||
NSStringFromClass( [self class] ), self.name, self.user.name, self.type, (long)self.uses, self.lastUsed, (long)self.version,
|
NSStringFromClass( [self class] ), self.name, self.user.name, (long)self.type, (long)self.uses, self.lastUsed, (long)self.version,
|
||||||
self.loginName, self.requiresExplicitMigration );
|
self.loginName, self.requiresExplicitMigration );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +155,16 @@
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)resolveContentUsingKey:(MPKey *)key {
|
||||||
|
|
||||||
|
return [self.algorithm resolveContentForElement:self usingKey:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resolveContentUsingKey:(MPKey *)key result:(void (^)(NSString *))result {
|
||||||
|
|
||||||
|
[self.algorithm resolveContentForElement:self usingKey:key result:result];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPElementGeneratedEntity(MP)
|
@implementation MPElementGeneratedEntity(MP)
|
||||||
@@ -187,7 +209,7 @@
|
|||||||
|
|
||||||
- (MPElementType)defaultType {
|
- (MPElementType)defaultType {
|
||||||
|
|
||||||
return (MPElementType)[self.defaultType_ unsignedIntegerValue];
|
return IfElse((MPElementType)[self.defaultType_ unsignedIntegerValue], MPElementTypeGeneratedLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDefaultType:(MPElementType)aDefaultType {
|
- (void)setDefaultType:(MPElementType)aDefaultType {
|
||||||
|
|||||||
@@ -8,27 +8,27 @@
|
|||||||
|
|
||||||
#import "MPKey.h"
|
#import "MPKey.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementContentType) {
|
||||||
MPElementContentTypePassword,
|
MPElementContentTypePassword,
|
||||||
MPElementContentTypeNote,
|
MPElementContentTypeNote,
|
||||||
MPElementContentTypePicture,
|
MPElementContentTypePicture,
|
||||||
} MPElementContentType;
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementTypeClass) {
|
||||||
/** Generate the password. */
|
/** Generate the password. */
|
||||||
MPElementTypeClassGenerated = 1 << 4,
|
MPElementTypeClassGenerated = 1 << 4,
|
||||||
/** Store the password. */
|
/** Store the password. */
|
||||||
MPElementTypeClassStored = 1 << 5,
|
MPElementTypeClassStored = 1 << 5,
|
||||||
} MPElementTypeClass;
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementFeature) {
|
||||||
/** Export the key-protected content data. */
|
/** Export the key-protected content data. */
|
||||||
MPElementFeatureExportContent = 1 << 10,
|
MPElementFeatureExportContent = 1 << 10,
|
||||||
/** Never export content. */
|
/** Never export content. */
|
||||||
MPElementFeatureDevicePrivate = 1 << 11,
|
MPElementFeatureDevicePrivate = 1 << 11,
|
||||||
} MPElementFeature;
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef NS_ENUM(NSUInteger, MPElementType) {
|
||||||
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
|
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
|
||||||
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
|
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
|
||||||
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
|
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
|
||||||
@@ -38,7 +38,7 @@ typedef enum {
|
|||||||
|
|
||||||
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
|
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
|
||||||
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
|
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
|
||||||
} MPElementType;
|
};
|
||||||
|
|
||||||
#define MPErrorDomain @"MPErrorDomain"
|
#define MPErrorDomain @"MPErrorDomain"
|
||||||
|
|
||||||
|
|||||||
33
MasterPassword/ObjC/Mac/MPElementCollectionView.h
Normal file
33
MasterPassword/ObjC/Mac/MPElementCollectionView.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPElementCollectionView.h
|
||||||
|
// MPElementCollectionView
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2/11/2014.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
@class MPElementModel;
|
||||||
|
|
||||||
|
@interface MPElementCollectionView : NSCollectionViewItem
|
||||||
|
|
||||||
|
@property (nonatomic) MPElementModel *representedObject;
|
||||||
|
@property (nonatomic) BOOL counterHidden;
|
||||||
|
@property (nonatomic) BOOL updateContentHidden;
|
||||||
|
|
||||||
|
- (IBAction)toggleType:(id)sender;
|
||||||
|
- (IBAction)updateLoginName:(id)sender;
|
||||||
|
- (IBAction)updateContent:(id)sender;
|
||||||
|
- (IBAction)delete:(id)sender;
|
||||||
|
|
||||||
|
@end
|
||||||
225
MasterPassword/ObjC/Mac/MPElementCollectionView.m
Normal file
225
MasterPassword/ObjC/Mac/MPElementCollectionView.m
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPElementCollectionView.h
|
||||||
|
// MPElementCollectionView
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2/11/2014.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPElementCollectionView.h"
|
||||||
|
#import "MPElementModel.h"
|
||||||
|
#import "MPMacAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
|
#define MPAlertChangeType @"MPAlertChangeType"
|
||||||
|
#define MPAlertChangeLogin @"MPAlertChangeLogin"
|
||||||
|
#define MPAlertChangeContent @"MPAlertChangeContent"
|
||||||
|
#define MPAlertDeleteSite @"MPAlertDeleteSite"
|
||||||
|
|
||||||
|
@implementation MPElementCollectionView {
|
||||||
|
}
|
||||||
|
|
||||||
|
@dynamic representedObject;
|
||||||
|
|
||||||
|
- (id)initWithCoder:(NSCoder *)coder {
|
||||||
|
|
||||||
|
if (!(self = [super initWithCoder:coder]))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
[self addObserver:self forKeyPath:@"representedObject" options:0 context:nil];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||||
|
|
||||||
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||||
|
self.counterHidden = !(MPElementTypeClassGenerated & self.representedObject.type);
|
||||||
|
self.updateContentHidden = !(MPElementTypeClassStored & self.representedObject.type);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
|
||||||
|
[self removeObserver:self forKeyPath:@"representedObject"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)toggleType:(id)sender {
|
||||||
|
|
||||||
|
id<MPAlgorithm> algorithm = self.representedObject.algorithm;
|
||||||
|
NSString *previousType = [algorithm nameOfType:[algorithm previousType:self.representedObject.type]];
|
||||||
|
NSString *nextType = [algorithm nameOfType:[algorithm nextType:self.representedObject.type]];
|
||||||
|
|
||||||
|
[[NSAlert alertWithMessageText:@"Change Password Type"
|
||||||
|
defaultButton:nextType alternateButton:@"Cancel" otherButton:previousType
|
||||||
|
informativeTextWithFormat:@"Changing the password type for this site will cause the password to change.\n"
|
||||||
|
@"You will need to update your account with the new password.\n\n"
|
||||||
|
@"Changing back to the old type will restore your current password."]
|
||||||
|
beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertChangeType];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)updateLoginName:(id)sender {
|
||||||
|
|
||||||
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Update Login Name"
|
||||||
|
defaultButton:@"Update" alternateButton:@"Cancel" otherButton:nil
|
||||||
|
informativeTextWithFormat:@"Enter the login name for %@:", self.representedObject.site];
|
||||||
|
NSTextField *passwordField = [[NSTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||||
|
[alert setAccessoryView:passwordField];
|
||||||
|
[alert layout];
|
||||||
|
[passwordField becomeFirstResponder];
|
||||||
|
[alert beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertChangeLogin];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)updateContent:(id)sender {
|
||||||
|
|
||||||
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Update Password"
|
||||||
|
defaultButton:@"Update" alternateButton:@"Cancel" otherButton:nil
|
||||||
|
informativeTextWithFormat:@"Enter the new password for %@:", self.representedObject.site];
|
||||||
|
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||||
|
[alert setAccessoryView:passwordField];
|
||||||
|
[alert layout];
|
||||||
|
[passwordField becomeFirstResponder];
|
||||||
|
[alert beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertChangeContent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)delete:(id)sender {
|
||||||
|
|
||||||
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Delete Site"
|
||||||
|
defaultButton:@"Delete" alternateButton:@"Cancel" otherButton:nil
|
||||||
|
informativeTextWithFormat:@"Are you sure you want to delete the site: %@?", self.representedObject.site];
|
||||||
|
[alert beginSheetModalForWindow:self.view.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertDeleteSite];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
||||||
|
|
||||||
|
if (contextInfo == MPAlertChangeType) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "Next type" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
element = [[MPMacAppDelegate get] changeElement:element saveInContext:context
|
||||||
|
toType:[element.algorithm nextType:element.type]];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertOtherReturn: {
|
||||||
|
// "Previous type" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
element = [[MPMacAppDelegate get] changeElement:element saveInContext:context
|
||||||
|
toType:[element.algorithm previousType:element.type]];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertChangeLogin) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "Update" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
element.loginName = [(NSTextField *)alert.accessoryView stringValue];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertChangeContent) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "Update" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
[element.algorithm saveContent:[(NSSecureTextField *)alert.accessoryView stringValue]
|
||||||
|
toElement:element usingKey:[MPMacAppDelegate get].key];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.representedObject = [[MPElementModel alloc] initWithEntity:element];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertDeleteSite) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertDefaultReturn: {
|
||||||
|
// "Delete" button.
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [self.representedObject entityInContext:context];
|
||||||
|
[context deleteObject:element];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
[((MPPasswordWindowController *)self.collectionView.window.windowController) updateElements];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertAlternateReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
38
MasterPassword/ObjC/Mac/MPElementModel.h
Normal file
38
MasterPassword/ObjC/Mac/MPElementModel.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPElementModel.h
|
||||||
|
// MPElementModel
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2/11/2014.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
@class MPElementEntity;
|
||||||
|
|
||||||
|
@interface MPElementModel : NSObject
|
||||||
|
@property (nonatomic, readonly) NSString *site;
|
||||||
|
@property (nonatomic, readonly) MPElementType type;
|
||||||
|
@property (nonatomic, readonly) NSString *typeName;
|
||||||
|
@property (nonatomic, readonly) NSString *content;
|
||||||
|
@property (nonatomic, readonly) NSString *loginName;
|
||||||
|
@property (nonatomic, readonly) NSNumber *uses;
|
||||||
|
@property (nonatomic) NSUInteger counter;
|
||||||
|
@property (nonatomic, readonly) NSDate *lastUsed;
|
||||||
|
@property (nonatomic, readonly) id<MPAlgorithm> algorithm;
|
||||||
|
@property (nonatomic, readonly) NSArray *types;
|
||||||
|
@property (nonatomic) NSUInteger typeIndex;
|
||||||
|
|
||||||
|
- (id)initWithEntity:(MPElementEntity *)entity;
|
||||||
|
- (MPElementEntity *)entityInContext:(NSManagedObjectContext *)moc;
|
||||||
|
|
||||||
|
@end
|
||||||
113
MasterPassword/ObjC/Mac/MPElementModel.m
Normal file
113
MasterPassword/ObjC/Mac/MPElementModel.m
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPElementModel.h
|
||||||
|
// MPElementModel
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2/11/2014.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPElementModel.h"
|
||||||
|
#import "MPElementEntity.h"
|
||||||
|
#import "MPEntities.h"
|
||||||
|
#import "MPAppDelegate_Shared.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "MPMacAppDelegate.h"
|
||||||
|
|
||||||
|
@interface MPElementModel()
|
||||||
|
|
||||||
|
@property(nonatomic, strong) NSManagedObjectID *entityOID;
|
||||||
|
@property(nonatomic, readwrite) NSString *content;
|
||||||
|
@property(nonatomic, readwrite) MPElementType type;
|
||||||
|
@property(nonatomic, readwrite) NSString *typeName;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPElementModel {
|
||||||
|
NSMutableDictionary *_typesByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithEntity:(MPElementEntity *)entity {
|
||||||
|
|
||||||
|
if (!(self = [super init]))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
_site = entity.name;
|
||||||
|
_lastUsed = entity.lastUsed;
|
||||||
|
_loginName = entity.loginName;
|
||||||
|
_type = entity.type;
|
||||||
|
_typeName = entity.typeName;
|
||||||
|
_uses = entity.uses_;
|
||||||
|
_counter = [entity isKindOfClass:[MPElementGeneratedEntity class]]? [(MPElementGeneratedEntity *)entity counter]: 0;
|
||||||
|
_content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key];
|
||||||
|
_algorithm = entity.algorithm;
|
||||||
|
_entityOID = entity.objectID;
|
||||||
|
|
||||||
|
// Find all password types and the index of the current type amongst them.
|
||||||
|
_typesByName = [NSMutableDictionary dictionary];
|
||||||
|
MPElementType type = _type;
|
||||||
|
do {
|
||||||
|
[_typesByName setObject:@(type) forKey:[_algorithm shortNameOfType:type]];
|
||||||
|
} while (_type != (type = [_algorithm nextType:type]));
|
||||||
|
_types = [_typesByName keysSortedByValueUsingSelector:@selector(compare:)];
|
||||||
|
_typeIndex = [[[_typesByName allValues] sortedArrayUsingSelector:@selector(compare:)] indexOfObject:@(_type)];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementEntity *)entityInContext:(NSManagedObjectContext *)moc {
|
||||||
|
|
||||||
|
if (!_entityOID)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
MPElementEntity *entity = (MPElementEntity *)[moc existingObjectWithID:_entityOID error:&error];
|
||||||
|
if (!entity)
|
||||||
|
err(@"Couldn't retrieve active element: %@", error);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setCounter:(NSUInteger)counter {
|
||||||
|
|
||||||
|
if (counter == _counter)
|
||||||
|
return;
|
||||||
|
_counter = counter;
|
||||||
|
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *entity = [self entityInContext:context];
|
||||||
|
if ([entity isKindOfClass:[MPElementGeneratedEntity class]]) {
|
||||||
|
((MPElementGeneratedEntity *)entity).counter = counter;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTypeIndex:(NSUInteger)typeIndex {
|
||||||
|
|
||||||
|
if (typeIndex == _typeIndex)
|
||||||
|
return;
|
||||||
|
_typeIndex = typeIndex;
|
||||||
|
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *entity = [self entityInContext:context];
|
||||||
|
entity.type_ = _typesByName[_types[typeIndex]];
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
self.type = entity.type;
|
||||||
|
self.typeName = entity.typeName;
|
||||||
|
self.content = [entity.algorithm resolveContentForElement:entity usingKey:[MPAppDelegate_Shared get].key];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,7 @@
|
|||||||
- (IBAction)newUser:(NSMenuItem *)sender;
|
- (IBAction)newUser:(NSMenuItem *)sender;
|
||||||
- (IBAction)lock:(id)sender;
|
- (IBAction)lock:(id)sender;
|
||||||
- (IBAction)rebuildCloud:(id)sender;
|
- (IBAction)rebuildCloud:(id)sender;
|
||||||
|
- (IBAction)corruptCloud:(id)sender;
|
||||||
- (IBAction)terminate:(id)sender;
|
- (IBAction)terminate:(id)sender;
|
||||||
- (IBAction)iphoneAppStore:(id)sender;
|
- (IBAction)iphoneAppStore:(id)sender;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
#define LOGIN_HELPER_BUNDLE_ID @"com.lyndir.lhunath.MasterPassword.Mac.LoginHelper"
|
#define LOGIN_HELPER_BUNDLE_ID @"com.lyndir.lhunath.MasterPassword.Mac.LoginHelper"
|
||||||
|
|
||||||
|
@interface UbiquityStoreManager (Private)
|
||||||
|
|
||||||
|
- (void)markCloudStoreCorrupted;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface MPMacAppDelegate()
|
@interface MPMacAppDelegate()
|
||||||
|
|
||||||
@property(nonatomic, strong) NSWindowController *initialWindow;
|
@property(nonatomic, strong) NSWindowController *initialWindow;
|
||||||
@@ -129,16 +135,23 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
- (IBAction)togglePreference:(id)sender {
|
- (IBAction)togglePreference:(id)sender {
|
||||||
|
|
||||||
if (sender == self.enableCloudButton)
|
if (sender == self.enableCloudButton) {
|
||||||
[self storeManager].cloudEnabled = (self.enableCloudButton.state == NSOnState);
|
if (([self storeManager].cloudEnabled = self.enableCloudButton.state == NSOnState)) {
|
||||||
|
NSAlert *alert = [NSAlert new];
|
||||||
|
alert.messageText = @"iCloud Enabled";
|
||||||
|
alert.informativeText = @"If you already have a user on another iCloud-enabled device, "
|
||||||
|
@"it may take a moment for that user to sync down to this device.";
|
||||||
|
[alert runModal];
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sender == self.useCloudItem)
|
if (sender == self.useCloudItem)
|
||||||
[self storeManager].cloudEnabled = !(self.useCloudItem.state == NSOnState);
|
[self storeManager].cloudEnabled = self.useCloudItem.state != NSOnState;
|
||||||
if (sender == self.rememberPasswordItem)
|
if (sender == self.rememberPasswordItem)
|
||||||
[MPConfig get].rememberLogin = [NSNumber numberWithBool:![[MPConfig get].rememberLogin boolValue]];
|
[MPConfig get].rememberLogin = [NSNumber numberWithBool:![[MPConfig get].rememberLogin boolValue]];
|
||||||
if (sender == self.openAtLoginButton)
|
if (sender == self.openAtLoginButton)
|
||||||
[self setLoginItemEnabled:(self.openAtLoginButton.state == NSOnState)];
|
[self setLoginItemEnabled:self.openAtLoginButton.state == NSOnState];
|
||||||
if (sender == self.openAtLoginItem)
|
if (sender == self.openAtLoginItem)
|
||||||
[self setLoginItemEnabled:!(self.openAtLoginItem.state == NSOnState)];
|
[self setLoginItemEnabled:self.openAtLoginItem.state != NSOnState];
|
||||||
if (sender == self.savePasswordItem) {
|
if (sender == self.savePasswordItem) {
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
||||||
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:context];
|
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:context];
|
||||||
@@ -194,14 +207,24 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
- (IBAction)rebuildCloud:(id)sender {
|
- (IBAction)rebuildCloud:(id)sender {
|
||||||
|
|
||||||
if ([[NSAlert alertWithMessageText:@"iCloud Truth Sync" defaultButton:@"Continue"
|
if ([[NSAlert alertWithMessageText:@"iCloud Truth Push" defaultButton:@"Continue"
|
||||||
alternateButton:nil otherButton:@"Cancel"
|
alternateButton:nil otherButton:@"Cancel"
|
||||||
informativeTextWithFormat:@"This action will force all your iCloud enabled devices to revert to this device's version of the truth."
|
informativeTextWithFormat:@"This action will force all your iCloud enabled devices to switch to this device's version of the truth."
|
||||||
@"\n\nThis is only necessary if you notice that your devices aren't syncing properly anymore. "
|
@"\n\nThis is only necessary if you notice that your devices aren't syncing properly anymore. "
|
||||||
"Any data on other devices not available from here will be lost."] runModal] == NSAlertDefaultReturn)
|
"Any data on other devices not available from here will be lost."] runModal] == NSAlertDefaultReturn)
|
||||||
[self.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:NO];
|
[self.storeManager rebuildCloudContentFromCloudStoreOrLocalStore:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)corruptCloud:(id)sender {
|
||||||
|
|
||||||
|
if ([[NSAlert alertWithMessageText:@"iCloud Truth Pull" defaultButton:@"Continue"
|
||||||
|
alternateButton:nil otherButton:@"Cancel"
|
||||||
|
informativeTextWithFormat:@"This action will force another iCloud enabled device to push their version of the truth on all."
|
||||||
|
@"\n\nThis is only necessary if you notice that your devices aren't syncing properly anymore. "
|
||||||
|
"Any data on this device not available from the other will be lost."] runModal] == NSAlertDefaultReturn)
|
||||||
|
[self.storeManager markCloudStoreCorrupted];
|
||||||
|
}
|
||||||
|
|
||||||
- (IBAction)terminate:(id)sender {
|
- (IBAction)terminate:(id)sender {
|
||||||
|
|
||||||
[self.passwordWindow close];
|
[self.passwordWindow close];
|
||||||
@@ -301,8 +324,11 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
// Initial display.
|
// Initial display.
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
if ([[MPMacConfig get].firstRun boolValue])
|
if ([[MPMacConfig get].firstRun boolValue]) {
|
||||||
[self.initialWindow = [[NSWindowController alloc] initWithWindowNibName:@"MPInitialWindow" owner:self] showWindow:self];
|
self.initialWindow = [[NSWindowController alloc] initWithWindowNibName:@"MPInitialWindow" owner:self];
|
||||||
|
[self.initialWindow.window setLevel:NSFloatingWindowLevel];
|
||||||
|
[self.initialWindow showWindow:self];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
- (void)setActiveUser:(MPUserEntity *)activeUser {
|
||||||
|
|||||||
@@ -7,16 +7,17 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
@class MPElementModel;
|
||||||
|
|
||||||
@interface MPPasswordWindowController : NSWindowController<NSTextFieldDelegate, NSComboBoxDelegate>
|
@interface MPPasswordWindowController : NSWindowController<NSTextFieldDelegate, NSCollectionViewDelegate>
|
||||||
|
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *siteLabel;
|
@property(nonatomic, strong) NSMutableArray *elements;
|
||||||
|
@property(nonatomic, strong) NSIndexSet *elementSelectionIndexes;
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *siteField;
|
@property(nonatomic, weak) IBOutlet NSTextField *siteField;
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *contentField;
|
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *tipField;
|
|
||||||
@property(nonatomic, weak) IBOutlet NSComboBox *typeField;
|
|
||||||
@property(nonatomic, weak) IBOutlet NSView *contentContainer;
|
@property(nonatomic, weak) IBOutlet NSView *contentContainer;
|
||||||
@property(nonatomic, weak) IBOutlet NSProgressIndicator *progressView;
|
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
|
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
|
||||||
|
@property(nonatomic, weak) IBOutlet NSCollectionView *siteCollectionView;
|
||||||
|
|
||||||
|
- (void)updateElements;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,44 +10,40 @@
|
|||||||
#import "MPMacAppDelegate.h"
|
#import "MPMacAppDelegate.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "MPElementModel.h"
|
||||||
|
|
||||||
#define MPAlertUnlockMP @"MPAlertUnlockMP"
|
#define MPAlertUnlockMP @"MPAlertUnlockMP"
|
||||||
#define MPAlertIncorrectMP @"MPAlertIncorrectMP"
|
#define MPAlertIncorrectMP @"MPAlertIncorrectMP"
|
||||||
#define MPAlertCreateSite @"MPAlertCreateSite"
|
#define MPAlertCreateSite @"MPAlertCreateSite"
|
||||||
#define MPAlertChangeType @"MPAlertChangeType"
|
|
||||||
|
|
||||||
@interface MPPasswordWindowController()
|
@interface MPPasswordWindowController()
|
||||||
|
|
||||||
@property(nonatomic) BOOL inProgress;
|
@property(nonatomic) BOOL inProgress;
|
||||||
@property(nonatomic) BOOL siteFieldPreventCompletion;
|
|
||||||
|
|
||||||
@property(nonatomic, strong) NSOperationQueue *backgroundQueue;
|
@property(nonatomic, strong) NSOperationQueue *backgroundQueue;
|
||||||
@property(nonatomic, strong) NSAlert *loadingDataAlert;
|
@property(nonatomic, strong) NSAlert *loadingDataAlert;
|
||||||
@property(nonatomic) BOOL closing;
|
@property(nonatomic) BOOL closing;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPPasswordWindowController {
|
@implementation MPPasswordWindowController
|
||||||
NSManagedObjectID *_activeElementOID;
|
|
||||||
}
|
#pragma mark - Life
|
||||||
|
|
||||||
- (void)windowDidLoad {
|
- (void)windowDidLoad {
|
||||||
|
|
||||||
if ([[MPMacConfig get].dialogStyleHUD boolValue]) {
|
if ([[MPMacConfig get].dialogStyleHUD boolValue]) {
|
||||||
self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask;
|
self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask;
|
||||||
self.siteLabel.textColor = [NSColor whiteColor];
|
self.userLabel.textColor = [NSColor whiteColor];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.window.styleMask = NSTexturedBackgroundWindowMask | NSResizableWindowMask | NSTitledWindowMask | NSClosableWindowMask;
|
self.window.styleMask = NSTexturedBackgroundWindowMask | NSResizableWindowMask | NSTitledWindowMask | NSClosableWindowMask;
|
||||||
self.siteLabel.textColor = [NSColor controlTextColor];
|
self.userLabel.textColor = [NSColor controlTextColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
self.backgroundQueue = [NSOperationQueue new];
|
self.backgroundQueue = [NSOperationQueue new];
|
||||||
self.backgroundQueue.maxConcurrentOperationCount = 1;
|
self.backgroundQueue.maxConcurrentOperationCount = 1;
|
||||||
|
|
||||||
[self setContent:@""];
|
|
||||||
[self.tipField setStringValue:@""];
|
|
||||||
|
|
||||||
[self.userLabel setStringValue:PearlString( @"%@'s password for:", [[MPMacAppDelegate get] activeUserForMainThread].name )];
|
|
||||||
[[MPMacAppDelegate get] addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
[[MPMacAppDelegate get] addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
||||||
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
// if (![MPAlgorithmDefault migrateUser:[[MPMacAppDelegate get] activeUserInContext:moc]])
|
// if (![MPAlgorithmDefault migrateUser:[[MPMacAppDelegate get] activeUserInContext:moc]])
|
||||||
@@ -57,40 +53,46 @@
|
|||||||
// @"their passwords to change. You'll need to update your profile for that site with the new password."];
|
// @"their passwords to change. You'll need to update your profile for that site with the new password."];
|
||||||
// [moc saveToStore];
|
// [moc saveToStore];
|
||||||
// }];
|
// }];
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||||
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
|
||||||
});
|
}];
|
||||||
} forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
|
} forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window
|
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowDidBecomeKeyNotification object:self.window
|
||||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
|
||||||
[self.siteField selectText:nil];
|
[self.siteField selectText:nil];
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window
|
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillCloseNotification object:self.window
|
||||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
NSWindow *sheet = [self.window attachedSheet];
|
NSWindow *sheet = [self.window attachedSheet];
|
||||||
if (sheet)
|
if (sheet)
|
||||||
[NSApp endSheet:sheet];
|
[NSApp endSheet:sheet];
|
||||||
|
|
||||||
[NSApp hide:nil];
|
[NSApp hide:nil];
|
||||||
self.closing = NO;
|
self.closing = NO;
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil
|
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedOutNotification object:nil
|
||||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
_activeElementOID = nil;
|
self.userLabel.stringValue = @"";
|
||||||
[self.siteField setStringValue:@""];
|
self.siteField.stringValue = @"";
|
||||||
[self.typeField deselectItemAtIndex:[self.typeField indexOfSelectedItem]];
|
self.elements = nil;
|
||||||
[self trySiteWithAction:NO];
|
|
||||||
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
|
||||||
}];
|
}];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserverForName:MPSignedInNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
|
^(NSNotification *note) {
|
||||||
|
self.userLabel.stringValue = PearlString( @"%@'s password for:",
|
||||||
|
[[MPMacAppDelegate get] activeUserForMainThread].name );
|
||||||
|
}];
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
|
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
|
||||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[super windowDidLoad];
|
[super windowDidLoad];
|
||||||
}
|
}
|
||||||
@@ -101,6 +103,152 @@
|
|||||||
[super close];
|
[super close];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSAlert
|
||||||
|
|
||||||
|
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
||||||
|
|
||||||
|
if (contextInfo == MPAlertIncorrectMP) {
|
||||||
|
[self close];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertUnlockMP) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertFirstButtonReturn: {
|
||||||
|
// "Unlock" button.
|
||||||
|
self.contentContainer.alphaValue = 0;
|
||||||
|
self.inProgress = YES;
|
||||||
|
|
||||||
|
NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
|
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
|
||||||
|
NSString *userName = activeUser.name;
|
||||||
|
BOOL success = [[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc
|
||||||
|
usingMasterPassword:password];
|
||||||
|
self.inProgress = NO;
|
||||||
|
|
||||||
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||||
|
if (success)
|
||||||
|
self.contentContainer.alphaValue = 1;
|
||||||
|
else {
|
||||||
|
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
|
||||||
|
NSLocalizedDescriptionKey : PearlString( @"Incorrect master password for user %@", userName )
|
||||||
|
}]] beginSheetModalForWindow:self.window modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertSecondButtonReturn: {
|
||||||
|
// "Change" button.
|
||||||
|
NSAlert *alert_ = [NSAlert new];
|
||||||
|
[alert_ addButtonWithTitle:@"Update"];
|
||||||
|
[alert_ addButtonWithTitle:@"Cancel"];
|
||||||
|
[alert_ setMessageText:@"Changing Master Password"];
|
||||||
|
[alert_ setInformativeText:@"This will allow you to log in with a different master password.\n\n"
|
||||||
|
@"Note that you will only see the sites and passwords for the master password you log in with.\n"
|
||||||
|
@"If you log in with a different master password, your current sites will be unavailable.\n\n"
|
||||||
|
@"You can always change back to your current master password later.\n"
|
||||||
|
@"Your current sites and passwords will then become available again."];
|
||||||
|
|
||||||
|
if ([alert_ runModal] == NSAlertFirstButtonReturn) {
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:context];
|
||||||
|
activeUser.keyID = nil;
|
||||||
|
[[MPMacAppDelegate get] forgetSavedKeyFor:activeUser];
|
||||||
|
[[MPMacAppDelegate get] signOutAnimated:YES];
|
||||||
|
[context saveToStore];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NSAlertThirdButtonReturn: {
|
||||||
|
// "Cancel" button.
|
||||||
|
[self close];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (contextInfo == MPAlertCreateSite) {
|
||||||
|
switch (returnCode) {
|
||||||
|
case NSAlertFirstButtonReturn: {
|
||||||
|
// "Create" button.
|
||||||
|
[[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element) {
|
||||||
|
if (element)
|
||||||
|
PearlMainQueue( ^{ [self updateElements]; } );
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NSAlertThirdButtonReturn:
|
||||||
|
// "Cancel" button.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSCollectionViewDelegate
|
||||||
|
|
||||||
|
#pragma mark - NSTextFieldDelegate
|
||||||
|
- (void)doCommandBySelector:(SEL)commandSelector {
|
||||||
|
|
||||||
|
if (commandSelector == @selector(insertNewline:))
|
||||||
|
[self useSite];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
|
||||||
|
|
||||||
|
if (commandSelector == @selector(cancel:))
|
||||||
|
[self close];
|
||||||
|
if (commandSelector == @selector(moveUp:))
|
||||||
|
self.elementSelectionIndexes =
|
||||||
|
[NSIndexSet indexSetWithIndex:MAX(self.elementSelectionIndexes.firstIndex, (NSUInteger)1) - 1];
|
||||||
|
if (commandSelector == @selector(moveDown:))
|
||||||
|
self.elementSelectionIndexes =
|
||||||
|
[NSIndexSet indexSetWithIndex:MIN(self.elementSelectionIndexes.firstIndex + 1, self.elements.count - 1)];
|
||||||
|
if (commandSelector == @selector(moveLeft:))
|
||||||
|
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
|
||||||
|
if (commandSelector == @selector(moveRight:))
|
||||||
|
[[self selectedView].animator setBoundsOrigin:NSMakePoint( self.siteCollectionView.frame.size.width / 2, 0 )];
|
||||||
|
if (commandSelector == @selector(insertNewline:))
|
||||||
|
[self useSite];
|
||||||
|
else
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controlTextDidChange:(NSNotification *)note {
|
||||||
|
|
||||||
|
if (note.object != self.siteField)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update the site content as the site name changes.
|
||||||
|
if ([[NSApp currentEvent] type] == NSKeyDown &&
|
||||||
|
[[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@"\r"]) { // Return while completing.
|
||||||
|
[self useSite];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ([[NSApp currentEvent] type] == NSKeyDown &&
|
||||||
|
// [[[NSApp currentEvent] charactersIgnoringModifiers] characterAtIndex:0] == 0x1b) { // Escape while completing.
|
||||||
|
// [self trySiteWithAction:NO];
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
[self updateElements];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
- (BOOL)ensureLoadedAndUnlockedOrCloseIfLoggedOut:(BOOL)closeIfLoggedOut {
|
- (BOOL)ensureLoadedAndUnlockedOrCloseIfLoggedOut:(BOOL)closeIfLoggedOut {
|
||||||
|
|
||||||
if (![self ensureStoreLoaded])
|
if (![self ensureStoreLoaded])
|
||||||
@@ -163,188 +311,35 @@
|
|||||||
if ([MPMacAppDelegate get].key)
|
if ([MPMacAppDelegate get].key)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self.content = @"";
|
|
||||||
[self.siteField setStringValue:@""];
|
[self.siteField setStringValue:@""];
|
||||||
[self.typeField deselectItemAtIndex:[self.typeField indexOfSelectedItem]];
|
|
||||||
[self.tipField setStringValue:@""];
|
|
||||||
|
|
||||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Master Password is locked."
|
NSAlert *alert = [NSAlert new];
|
||||||
defaultButton:@"Unlock" alternateButton:@"Change" otherButton:@"Cancel"
|
[alert addButtonWithTitle:@"Unlock"];
|
||||||
informativeTextWithFormat:@"The master password is required to unlock the application for:\n\n%@",
|
[alert addButtonWithTitle:@"Change"];
|
||||||
userName];
|
[alert addButtonWithTitle:@"Cancel"];
|
||||||
|
[alert setMessageText:@"Master Password is locked."];
|
||||||
|
[alert setInformativeText:PearlString( @"The master password is required to unlock the application for:\n\n%@", userName )];
|
||||||
|
|
||||||
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||||
[alert setAccessoryView:passwordField];
|
[alert setAccessoryView:passwordField];
|
||||||
[alert layout];
|
[alert layout];
|
||||||
[passwordField becomeFirstResponder];
|
|
||||||
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
||||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
|
||||||
|
[passwordField becomeFirstResponder];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
return unlocked;
|
return unlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
- (void)updateElements {
|
||||||
|
|
||||||
if (contextInfo == MPAlertIncorrectMP) {
|
NSString *query = [self.siteField.currentEditor string];
|
||||||
[self close];
|
if (![query length] || ![MPMacAppDelegate get].key) {
|
||||||
|
self.elements = nil;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (contextInfo == MPAlertUnlockMP) {
|
|
||||||
switch (returnCode) {
|
|
||||||
case NSAlertAlternateReturn: {
|
|
||||||
// "Change" button.
|
|
||||||
NSInteger returnCode_ = [[NSAlert
|
|
||||||
alertWithMessageText:@"Changing Master Password" defaultButton:nil
|
|
||||||
alternateButton:[PearlStrings get].commonButtonCancel otherButton:nil informativeTextWithFormat:
|
|
||||||
@"This will allow you to log in with a different master password.\n\n"
|
|
||||||
@"Note that you will only see the sites and passwords for the master password you log in with.\n"
|
|
||||||
@"If you log in with a different master password, your current sites will be unavailable.\n\n"
|
|
||||||
@"You can always change back to your current master password later.\n"
|
|
||||||
@"Your current sites and passwords will then become available again."]
|
|
||||||
runModal];
|
|
||||||
|
|
||||||
if (returnCode_ == NSAlertDefaultReturn) {
|
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
||||||
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:context];
|
|
||||||
activeUser.keyID = nil;
|
|
||||||
[[MPMacAppDelegate get] forgetSavedKeyFor:activeUser];
|
|
||||||
[[MPMacAppDelegate get] signOutAnimated:YES];
|
|
||||||
[context saveToStore];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NSAlertOtherReturn: {
|
|
||||||
// "Cancel" button.
|
|
||||||
[self close];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NSAlertDefaultReturn: {
|
|
||||||
// "Unlock" button.
|
|
||||||
self.contentContainer.alphaValue = 0;
|
|
||||||
[self.progressView startAnimation:nil];
|
|
||||||
self.inProgress = YES;
|
|
||||||
|
|
||||||
NSString *password = [(NSSecureTextField *)alert.accessoryView stringValue];
|
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
|
||||||
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
|
|
||||||
NSString *userName = activeUser.name;
|
|
||||||
BOOL success = [[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc
|
|
||||||
usingMasterPassword:password];
|
|
||||||
self.inProgress = NO;
|
|
||||||
|
|
||||||
dispatch_async( dispatch_get_current_queue(), ^{
|
|
||||||
[self.progressView stopAnimation:nil];
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
self.contentContainer.alphaValue = 1;
|
|
||||||
else {
|
|
||||||
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
|
|
||||||
NSLocalizedDescriptionKey : PearlString( @"Incorrect master password for user %@", userName )
|
|
||||||
}]] beginSheetModalForWindow:self.window modalDelegate:self
|
|
||||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (contextInfo == MPAlertCreateSite) {
|
|
||||||
switch (returnCode) {
|
|
||||||
case NSAlertDefaultReturn: {
|
|
||||||
[[MPMacAppDelegate get] addElementNamed:[self.siteField stringValue] completion:^(MPElementEntity *element) {
|
|
||||||
if (element) {
|
|
||||||
_activeElementOID = element.objectID;
|
|
||||||
[self trySiteWithAction:NO];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (contextInfo == MPAlertChangeType) {
|
|
||||||
switch (returnCode) {
|
|
||||||
case NSAlertDefaultReturn: {
|
|
||||||
MPElementType type = [self selectedType];
|
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
||||||
MPElementEntity *activeElement = [self activeElementInContext:context];
|
|
||||||
_activeElementOID = [[MPMacAppDelegate get] changeElement:activeElement inContext:context
|
|
||||||
toType:type].objectID;
|
|
||||||
[context saveToStore];
|
|
||||||
|
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
|
||||||
[self trySiteWithAction:NO];
|
|
||||||
} );
|
|
||||||
}];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPElementType)selectedType {
|
|
||||||
|
|
||||||
if (self.typeField.indexOfSelectedItem == 0)
|
|
||||||
return MPElementTypeGeneratedMaximum;
|
|
||||||
if (self.typeField.indexOfSelectedItem == 1)
|
|
||||||
return MPElementTypeGeneratedLong;
|
|
||||||
if (self.typeField.indexOfSelectedItem == 2)
|
|
||||||
return MPElementTypeGeneratedMedium;
|
|
||||||
if (self.typeField.indexOfSelectedItem == 3)
|
|
||||||
return MPElementTypeGeneratedBasic;
|
|
||||||
if (self.typeField.indexOfSelectedItem == 4)
|
|
||||||
return MPElementTypeGeneratedShort;
|
|
||||||
if (self.typeField.indexOfSelectedItem == 5)
|
|
||||||
return MPElementTypeGeneratedPIN;
|
|
||||||
if (self.typeField.indexOfSelectedItem == 6)
|
|
||||||
return MPElementTypeStoredPersonal;
|
|
||||||
if (self.typeField.indexOfSelectedItem == 7)
|
|
||||||
return MPElementTypeStoredDevicePrivate;
|
|
||||||
|
|
||||||
wrn(@"Unsupported type selected: %li, assuming Long.", self.typeField.indexOfSelectedItem);
|
|
||||||
return MPElementTypeGeneratedLong;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)comboBoxSelectionDidChange:(NSNotification *)notification {
|
|
||||||
|
|
||||||
if (notification.object == self.typeField) {
|
|
||||||
if ([self.typeField indexOfSelectedItem] < 0)
|
|
||||||
return;
|
|
||||||
MPElementEntity *activeElement = [self activeElementForMainThread];
|
|
||||||
MPElementType selectedType = [self selectedType];
|
|
||||||
if (!activeElement || activeElement.type == selectedType || !(selectedType & MPElementTypeClassGenerated))
|
|
||||||
return;
|
|
||||||
|
|
||||||
[[NSAlert alertWithMessageText:@"Change Password Type" defaultButton:@"Change Password"
|
|
||||||
alternateButton:@"Cancel" otherButton:nil
|
|
||||||
informativeTextWithFormat:@"Changing the password type for this site will cause the password to change.\n"
|
|
||||||
@"You will need to update your account with the new password."]
|
|
||||||
beginSheetModalForWindow:self.window modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
|
|
||||||
contextInfo:MPAlertChangeType];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words
|
|
||||||
forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index {
|
|
||||||
|
|
||||||
NSString *query = [[textView string] substringWithRange:charRange];
|
|
||||||
if (![query length] || ![MPMacAppDelegate get].key)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
__block NSMutableArray *mutableResults = [NSMutableArray array];
|
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
|
||||||
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO]];
|
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO]];
|
||||||
@@ -353,162 +348,77 @@
|
|||||||
|
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
|
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
|
||||||
if (!siteResults)
|
if (!siteResults) {
|
||||||
err(@"While fetching elements for completion: %@", error);
|
err(@"While fetching elements for completion: %@", error);
|
||||||
else if ([siteResults count]) {
|
return;
|
||||||
_activeElementOID = ((NSManagedObject *)[siteResults objectAtIndex:0]).objectID;
|
|
||||||
for (MPElementEntity *element in siteResults)
|
|
||||||
[mutableResults addObject:element.name];
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
_activeElementOID = nil;
|
NSMutableArray *newElements = [NSMutableArray arrayWithCapacity:[siteResults count]];
|
||||||
|
for (MPElementEntity *element in siteResults)
|
||||||
|
[newElements addObject:[[MPElementModel alloc] initWithEntity:element]];
|
||||||
|
self.elements = newElements;
|
||||||
|
if (!self.selectedElement)
|
||||||
|
self.elementSelectionIndexes = [newElements count]? [NSIndexSet indexSetWithIndex:0]: nil;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if ([mutableResults count] < 2) {
|
|
||||||
//[textView setString:[(MPElementEntity *)[siteResults objectAtIndex:0] name]];
|
|
||||||
//[textView setSelectedRange:NSMakeRange( [query length], [[textView string] length] - [query length] )];
|
|
||||||
[self trySiteWithAction:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
return mutableResults;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
|
- (NSUInteger)selectedIndex {
|
||||||
|
|
||||||
if (commandSelector == @selector(cancel:)) { // Escape without completion.
|
if (!self.elementSelectionIndexes)
|
||||||
[self close];
|
return NSNotFound;
|
||||||
return YES;
|
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
|
||||||
}
|
if (selectedIndex >= self.elements.count)
|
||||||
if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"])) { // Backspace any time.
|
return NSNotFound;
|
||||||
_activeElementOID = nil;
|
|
||||||
[self trySiteWithAction:NO];
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
if (commandSelector == @selector(insertNewline:)) { // Return without completion.
|
|
||||||
[self trySiteWithAction:YES];
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
return selectedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)controlTextDidEndEditing:(NSNotification *)note {
|
- (NSBox *)selectedView {
|
||||||
|
|
||||||
if (note.object != self.siteField)
|
NSUInteger selectedIndex = [self selectedIndex];
|
||||||
return;
|
if (selectedIndex == NSNotFound)
|
||||||
|
|
||||||
[self trySiteWithAction:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)controlTextDidChange:(NSNotification *)note {
|
|
||||||
|
|
||||||
if (note.object != self.siteField)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Update the site content as the site name changes.
|
|
||||||
if ([[NSApp currentEvent] type] == NSKeyDown &&
|
|
||||||
[[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@"\r"]) { // Return while completing.
|
|
||||||
[self trySiteWithAction:YES];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([[NSApp currentEvent] type] == NSKeyDown &&
|
|
||||||
[[[NSApp currentEvent] charactersIgnoringModifiers] characterAtIndex:0] == 0x1b) { // Escape while completing.
|
|
||||||
_activeElementOID = nil;
|
|
||||||
[self trySiteWithAction:NO];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.siteFieldPreventCompletion) {
|
|
||||||
self.siteFieldPreventCompletion = NO;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.siteFieldPreventCompletion = YES;
|
|
||||||
[(NSText *)[note.userInfo objectForKey:@"NSFieldEditor"] complete:self];
|
|
||||||
self.siteFieldPreventCompletion = NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPElementEntity *)activeElementForMainThread {
|
|
||||||
|
|
||||||
return [self activeElementInContext:[MPMacAppDelegate managedObjectContextForMainThreadIfReady]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPElementEntity *)activeElementInContext:(NSManagedObjectContext *)moc {
|
|
||||||
|
|
||||||
if (!_activeElementOID)
|
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
NSError *error;
|
return (NSBox *)[self.siteCollectionView itemAtIndex:selectedIndex].view;
|
||||||
MPElementEntity *activeElement = (MPElementEntity *)[moc existingObjectWithID:_activeElementOID error:&error];
|
|
||||||
if (!activeElement)
|
|
||||||
err(@"Couldn't retrieve active element: %@", error);
|
|
||||||
|
|
||||||
return activeElement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setContent:(NSString *)content {
|
- (MPElementModel *)selectedElement {
|
||||||
|
|
||||||
NSMutableParagraphStyle *paragraph = [NSMutableParagraphStyle new];
|
NSUInteger selectedIndex = [self selectedIndex];
|
||||||
paragraph.alignment = NSCenterTextAlignment;
|
if (selectedIndex == NSNotFound)
|
||||||
|
return nil;
|
||||||
|
|
||||||
[self.contentField setAttributedStringValue:[[NSAttributedString alloc] initWithString:content attributes:@{
|
return (MPElementModel *)self.elements[selectedIndex];
|
||||||
NSParagraphStyleAttributeName : paragraph
|
|
||||||
}]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)trySiteWithAction:(BOOL)doAction {
|
- (void)setSelectedElement:(MPElementModel *)element {
|
||||||
|
|
||||||
NSString *siteName = [self.siteField stringValue];
|
self.elementSelectionIndexes = [NSIndexSet indexSetWithIndex:[self.elements indexOfObject:element]];
|
||||||
[self.progressView startAnimation:nil];
|
}
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
||||||
BOOL actionHandled = NO;
|
|
||||||
MPElementEntity *activeElement = [self activeElementInContext:context];
|
|
||||||
NSString *content = [activeElement.content description];
|
|
||||||
NSString *typeName = [activeElement typeShortName];
|
|
||||||
if (!content)
|
|
||||||
content = @"";
|
|
||||||
|
|
||||||
if (doAction) {
|
- (void)useSite {
|
||||||
if ([content length]) {
|
|
||||||
// Performing action while content is available. Copy it.
|
MPElementModel *selectedElement = [self selectedElement];
|
||||||
[self copyContent:content];
|
if (selectedElement) {
|
||||||
}
|
// Performing action while content is available. Copy it.
|
||||||
else if ([siteName length]) {
|
[self copyContent:selectedElement.content];
|
||||||
|
|
||||||
|
[self close];
|
||||||
|
|
||||||
|
NSUserNotification *notification = [NSUserNotification new];
|
||||||
|
notification.title = @"Password Copied";
|
||||||
|
if (selectedElement.loginName.length)
|
||||||
|
notification.subtitle = PearlString( @"%@ at %@", selectedElement.loginName, selectedElement.site );
|
||||||
|
else
|
||||||
|
notification.subtitle = selectedElement.site;
|
||||||
|
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSString *siteName = [self.siteField stringValue];
|
||||||
|
if ([siteName length])
|
||||||
// Performing action without content but a site name is written.
|
// Performing action without content but a site name is written.
|
||||||
[self createNewSite:siteName];
|
[self createNewSite:siteName];
|
||||||
actionHandled = YES;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
|
||||||
[self setContent:content];
|
|
||||||
[self.progressView stopAnimation:nil];
|
|
||||||
if (![[self.typeField stringValue] isEqualToString:typeName])
|
|
||||||
[self.typeField selectItemWithObjectValue:typeName];
|
|
||||||
|
|
||||||
self.tipField.alphaValue = 1;
|
|
||||||
if (actionHandled)
|
|
||||||
[self.tipField setStringValue:@""];
|
|
||||||
else if ([content length] == 0) {
|
|
||||||
if ([siteName length])
|
|
||||||
[self.tipField setStringValue:@"Hit ⌤ (ENTER) to create a new site."];
|
|
||||||
else
|
|
||||||
[self.tipField setStringValue:@""];
|
|
||||||
}
|
|
||||||
else if (!doAction)
|
|
||||||
[self.tipField setStringValue:@"Hit ⌤ (ENTER) to copy the password."];
|
|
||||||
else {
|
|
||||||
[self.tipField setStringValue:@"Copied! Hit ⎋ (ESC) to close window."];
|
|
||||||
dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) ), dispatch_get_main_queue(), ^{
|
|
||||||
[NSAnimationContext beginGrouping];
|
|
||||||
[[NSAnimationContext currentContext] setDuration:0.2f];
|
|
||||||
[self.tipField.animator setAlphaValue:0];
|
|
||||||
[NSAnimationContext endGrouping];
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)copyContent:(NSString *)content {
|
- (void)copyContent:(NSString *)content {
|
||||||
@@ -520,7 +430,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
[[self activeElementInContext:moc] use];
|
[[self.selectedElement entityInContext:moc] use];
|
||||||
[moc saveToStore];
|
[moc saveToStore];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@@ -528,12 +438,38 @@
|
|||||||
- (void)createNewSite:(NSString *)siteName {
|
- (void)createNewSite:(NSString *)siteName {
|
||||||
|
|
||||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Create site?"
|
NSAlert *alert = [NSAlert new];
|
||||||
defaultButton:@"Create" alternateButton:nil otherButton:@"Cancel"
|
[alert addButtonWithTitle:@"Create"];
|
||||||
informativeTextWithFormat:@"Do you want to create a new site named:\n\n%@", siteName];
|
[alert addButtonWithTitle:@"Cancel"];
|
||||||
|
[alert setMessageText:@"Create site?"];
|
||||||
|
[alert setInformativeText:PearlString( @"Do you want to create a new site named:\n\n%@", siteName )];
|
||||||
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
||||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertCreateSite];
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertCreateSite];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - KVO
|
||||||
|
|
||||||
|
- (void)setElementSelectionIndexes:(NSIndexSet *)elementSelectionIndexes {
|
||||||
|
|
||||||
|
// First reset bounds.
|
||||||
|
PearlMainThread(^{
|
||||||
|
NSUInteger selectedIndex = self.elementSelectionIndexes.firstIndex;
|
||||||
|
if (selectedIndex != NSNotFound && selectedIndex < self.elements.count)
|
||||||
|
[[self selectedView].animator setBoundsOrigin:NSZeroPoint];
|
||||||
|
} );
|
||||||
|
|
||||||
|
_elementSelectionIndexes = elementSelectionIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertObject:(MPElementModel *)model inElementsAtIndex:(NSUInteger)index {
|
||||||
|
|
||||||
|
[self.elements insertObject:model atIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObjectFromElementsAtIndex:(NSUInteger)index {
|
||||||
|
|
||||||
|
[self.elements removeObjectAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,8 @@
|
|||||||
<string>Master Password</string>
|
<string>Master Password</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>MasterPassword</string>
|
<string>MasterPassword</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.lyndir.lhunath.MasterPassword.Mac</string>
|
<string>com.lyndir.lhunath.MasterPassword.Mac</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
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 */; };
|
||||||
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 */; };
|
||||||
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 */; };
|
||||||
|
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */; };
|
||||||
|
93D39C7C2BE7C0E0763B0177 /* MPElementCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D394495528B10D1B61A2C3 /* MPElementCollectionView.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 */; };
|
||||||
DA0933CA1747A56A00DE1CEF /* MPInitialWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */; };
|
|
||||||
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
|
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
|
||||||
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
|
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
|
||||||
DA16B33F170661D4000A0EAB /* libUbiquityStoreManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; };
|
DA16B33F170661D4000A0EAB /* libUbiquityStoreManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4425CB1557BED40052177D /* libUbiquityStoreManager.a */; };
|
||||||
@@ -20,6 +21,12 @@
|
|||||||
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
|
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
|
||||||
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
||||||
DA1E4D50176E0E280065E0EF /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA1E4D4F176E0E280065E0EF /* Media.xcassets */; };
|
DA1E4D50176E0E280065E0EF /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA1E4D4F176E0E280065E0EF /* Media.xcassets */; };
|
||||||
|
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */; };
|
||||||
|
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */; };
|
||||||
|
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */; };
|
||||||
|
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */; };
|
||||||
|
DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */; };
|
||||||
|
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */; };
|
||||||
DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */; };
|
DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */; };
|
||||||
DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */; };
|
DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */; };
|
||||||
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
||||||
@@ -32,15 +39,6 @@
|
|||||||
DA3EF17D15A47744003ABF4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
DA3EF17D15A47744003ABF4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||||
DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
DA4425CC1557BED40052177D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||||
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
||||||
DA5E5C8817248AA1003798D8 /* crypto_aesctr.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7B17248AA1003798D8 /* crypto_aesctr.h */; };
|
|
||||||
DA5E5C8917248AA1003798D8 /* crypto_scrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7C17248AA1003798D8 /* crypto_scrypt.h */; };
|
|
||||||
DA5E5C8A17248AA1003798D8 /* memlimit.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7D17248AA1003798D8 /* memlimit.h */; };
|
|
||||||
DA5E5C8B17248AA1003798D8 /* readpass.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7E17248AA1003798D8 /* readpass.h */; };
|
|
||||||
DA5E5C8C17248AA1003798D8 /* scryptenc.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C7F17248AA1003798D8 /* scryptenc.h */; };
|
|
||||||
DA5E5C8D17248AA1003798D8 /* scryptenc_cpuperf.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C8017248AA1003798D8 /* scryptenc_cpuperf.h */; };
|
|
||||||
DA5E5C8E17248AA1003798D8 /* sha256.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C8117248AA1003798D8 /* sha256.h */; };
|
|
||||||
DA5E5C8F17248AA1003798D8 /* sysendian.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C8217248AA1003798D8 /* sysendian.h */; };
|
|
||||||
DA5E5C9017248AA1003798D8 /* warn.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5E5C8317248AA1003798D8 /* warn.h */; };
|
|
||||||
DA5E5C9417248AA1003798D8 /* libscryptenc-osx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5E5C8717248AA1003798D8 /* libscryptenc-osx.a */; };
|
DA5E5C9417248AA1003798D8 /* libscryptenc-osx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5E5C8717248AA1003798D8 /* libscryptenc-osx.a */; };
|
||||||
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5C981724A667003798D8 /* MPAlgorithm.m */; };
|
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5C981724A667003798D8 /* MPAlgorithm.m */; };
|
||||||
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5C9A1724A667003798D8 /* MPAlgorithmV0.m */; };
|
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5C9A1724A667003798D8 /* MPAlgorithmV0.m */; };
|
||||||
@@ -130,6 +128,88 @@
|
|||||||
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
|
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
|
||||||
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; };
|
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; };
|
||||||
DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; };
|
DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; };
|
||||||
|
DAEB93D918AB0FFD000490CC /* aes.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938718AB0FFD000490CC /* aes.h */; };
|
||||||
|
DAEB93DA18AB0FFD000490CC /* asn1.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938818AB0FFD000490CC /* asn1.h */; };
|
||||||
|
DAEB93DB18AB0FFD000490CC /* asn1_mac.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938918AB0FFD000490CC /* asn1_mac.h */; };
|
||||||
|
DAEB93DC18AB0FFD000490CC /* asn1t.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938A18AB0FFD000490CC /* asn1t.h */; };
|
||||||
|
DAEB93DD18AB0FFD000490CC /* bio.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938B18AB0FFD000490CC /* bio.h */; };
|
||||||
|
DAEB93DE18AB0FFD000490CC /* blowfish.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938C18AB0FFD000490CC /* blowfish.h */; };
|
||||||
|
DAEB93DF18AB0FFD000490CC /* bn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938D18AB0FFD000490CC /* bn.h */; };
|
||||||
|
DAEB93E018AB0FFD000490CC /* buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938E18AB0FFD000490CC /* buffer.h */; };
|
||||||
|
DAEB93E118AB0FFD000490CC /* camellia.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB938F18AB0FFD000490CC /* camellia.h */; };
|
||||||
|
DAEB93E218AB0FFD000490CC /* cast.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939018AB0FFD000490CC /* cast.h */; };
|
||||||
|
DAEB93E318AB0FFD000490CC /* cms.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939118AB0FFD000490CC /* cms.h */; };
|
||||||
|
DAEB93E418AB0FFD000490CC /* comp.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939218AB0FFD000490CC /* comp.h */; };
|
||||||
|
DAEB93E518AB0FFD000490CC /* conf.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939318AB0FFD000490CC /* conf.h */; };
|
||||||
|
DAEB93E618AB0FFD000490CC /* conf_api.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939418AB0FFD000490CC /* conf_api.h */; };
|
||||||
|
DAEB93E718AB0FFD000490CC /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939518AB0FFD000490CC /* crypto.h */; };
|
||||||
|
DAEB93E818AB0FFD000490CC /* des.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939618AB0FFD000490CC /* des.h */; };
|
||||||
|
DAEB93E918AB0FFD000490CC /* des_old.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939718AB0FFD000490CC /* des_old.h */; };
|
||||||
|
DAEB93EA18AB0FFD000490CC /* dh.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939818AB0FFD000490CC /* dh.h */; };
|
||||||
|
DAEB93EB18AB0FFD000490CC /* dsa.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939918AB0FFD000490CC /* dsa.h */; };
|
||||||
|
DAEB93EC18AB0FFD000490CC /* dso.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939A18AB0FFD000490CC /* dso.h */; };
|
||||||
|
DAEB93ED18AB0FFD000490CC /* dtls1.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939B18AB0FFD000490CC /* dtls1.h */; };
|
||||||
|
DAEB93EE18AB0FFD000490CC /* e_os2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939C18AB0FFD000490CC /* e_os2.h */; };
|
||||||
|
DAEB93EF18AB0FFD000490CC /* ebcdic.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939D18AB0FFD000490CC /* ebcdic.h */; };
|
||||||
|
DAEB93F018AB0FFD000490CC /* ec.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939E18AB0FFD000490CC /* ec.h */; };
|
||||||
|
DAEB93F118AB0FFD000490CC /* ecdh.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB939F18AB0FFD000490CC /* ecdh.h */; };
|
||||||
|
DAEB93F218AB0FFD000490CC /* ecdsa.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A018AB0FFD000490CC /* ecdsa.h */; };
|
||||||
|
DAEB93F318AB0FFD000490CC /* engine.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A118AB0FFD000490CC /* engine.h */; };
|
||||||
|
DAEB93F418AB0FFD000490CC /* err.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A218AB0FFD000490CC /* err.h */; };
|
||||||
|
DAEB93F518AB0FFD000490CC /* evp.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A318AB0FFD000490CC /* evp.h */; };
|
||||||
|
DAEB93F618AB0FFD000490CC /* hmac.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A418AB0FFD000490CC /* hmac.h */; };
|
||||||
|
DAEB93F718AB0FFD000490CC /* idea.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A518AB0FFD000490CC /* idea.h */; };
|
||||||
|
DAEB93F818AB0FFD000490CC /* krb5_asn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A618AB0FFD000490CC /* krb5_asn.h */; };
|
||||||
|
DAEB93F918AB0FFD000490CC /* kssl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A718AB0FFD000490CC /* kssl.h */; };
|
||||||
|
DAEB93FA18AB0FFD000490CC /* lhash.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A818AB0FFD000490CC /* lhash.h */; };
|
||||||
|
DAEB93FB18AB0FFD000490CC /* md4.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93A918AB0FFD000490CC /* md4.h */; };
|
||||||
|
DAEB93FC18AB0FFD000490CC /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93AA18AB0FFD000490CC /* md5.h */; };
|
||||||
|
DAEB93FD18AB0FFD000490CC /* mdc2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93AB18AB0FFD000490CC /* mdc2.h */; };
|
||||||
|
DAEB93FE18AB0FFD000490CC /* modes.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93AC18AB0FFD000490CC /* modes.h */; };
|
||||||
|
DAEB93FF18AB0FFD000490CC /* obj_mac.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93AD18AB0FFD000490CC /* obj_mac.h */; };
|
||||||
|
DAEB940018AB0FFD000490CC /* objects.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93AE18AB0FFD000490CC /* objects.h */; };
|
||||||
|
DAEB940118AB0FFD000490CC /* ocsp.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93AF18AB0FFD000490CC /* ocsp.h */; };
|
||||||
|
DAEB940218AB0FFD000490CC /* opensslconf.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B018AB0FFD000490CC /* opensslconf.h */; };
|
||||||
|
DAEB940318AB0FFD000490CC /* opensslv.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B118AB0FFD000490CC /* opensslv.h */; };
|
||||||
|
DAEB940418AB0FFD000490CC /* ossl_typ.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B218AB0FFD000490CC /* ossl_typ.h */; };
|
||||||
|
DAEB940518AB0FFD000490CC /* pem.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B318AB0FFD000490CC /* pem.h */; };
|
||||||
|
DAEB940618AB0FFD000490CC /* pem2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B418AB0FFD000490CC /* pem2.h */; };
|
||||||
|
DAEB940718AB0FFD000490CC /* pkcs12.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B518AB0FFD000490CC /* pkcs12.h */; };
|
||||||
|
DAEB940818AB0FFD000490CC /* pkcs7.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B618AB0FFD000490CC /* pkcs7.h */; };
|
||||||
|
DAEB940918AB0FFD000490CC /* pqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B718AB0FFD000490CC /* pqueue.h */; };
|
||||||
|
DAEB940A18AB0FFD000490CC /* rand.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B818AB0FFD000490CC /* rand.h */; };
|
||||||
|
DAEB940B18AB0FFD000490CC /* rc2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93B918AB0FFD000490CC /* rc2.h */; };
|
||||||
|
DAEB940C18AB0FFD000490CC /* rc4.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93BA18AB0FFD000490CC /* rc4.h */; };
|
||||||
|
DAEB940D18AB0FFD000490CC /* ripemd.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93BB18AB0FFD000490CC /* ripemd.h */; };
|
||||||
|
DAEB940E18AB0FFD000490CC /* rsa.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93BC18AB0FFD000490CC /* rsa.h */; };
|
||||||
|
DAEB940F18AB0FFD000490CC /* safestack.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93BD18AB0FFD000490CC /* safestack.h */; };
|
||||||
|
DAEB941018AB0FFD000490CC /* seed.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93BE18AB0FFD000490CC /* seed.h */; };
|
||||||
|
DAEB941118AB0FFD000490CC /* sha.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93BF18AB0FFD000490CC /* sha.h */; };
|
||||||
|
DAEB941218AB0FFD000490CC /* ssl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C018AB0FFD000490CC /* ssl.h */; };
|
||||||
|
DAEB941318AB0FFD000490CC /* ssl2.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C118AB0FFD000490CC /* ssl2.h */; };
|
||||||
|
DAEB941418AB0FFD000490CC /* ssl23.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C218AB0FFD000490CC /* ssl23.h */; };
|
||||||
|
DAEB941518AB0FFD000490CC /* ssl3.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C318AB0FFD000490CC /* ssl3.h */; };
|
||||||
|
DAEB941618AB0FFD000490CC /* stack.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C418AB0FFD000490CC /* stack.h */; };
|
||||||
|
DAEB941718AB0FFD000490CC /* symhacks.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C518AB0FFD000490CC /* symhacks.h */; };
|
||||||
|
DAEB941818AB0FFD000490CC /* tls1.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C618AB0FFD000490CC /* tls1.h */; };
|
||||||
|
DAEB941918AB0FFD000490CC /* ts.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C718AB0FFD000490CC /* ts.h */; };
|
||||||
|
DAEB941A18AB0FFD000490CC /* txt_db.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C818AB0FFD000490CC /* txt_db.h */; };
|
||||||
|
DAEB941B18AB0FFD000490CC /* ui.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93C918AB0FFD000490CC /* ui.h */; };
|
||||||
|
DAEB941C18AB0FFD000490CC /* ui_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93CA18AB0FFD000490CC /* ui_compat.h */; };
|
||||||
|
DAEB941D18AB0FFD000490CC /* whrlpool.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93CB18AB0FFD000490CC /* whrlpool.h */; };
|
||||||
|
DAEB941E18AB0FFD000490CC /* x509.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93CC18AB0FFD000490CC /* x509.h */; };
|
||||||
|
DAEB941F18AB0FFD000490CC /* x509_vfy.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93CD18AB0FFD000490CC /* x509_vfy.h */; };
|
||||||
|
DAEB942018AB0FFD000490CC /* x509v3.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93CE18AB0FFD000490CC /* x509v3.h */; };
|
||||||
|
DAEB942118AB0FFD000490CC /* crypto_aesctr.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D018AB0FFD000490CC /* crypto_aesctr.h */; };
|
||||||
|
DAEB942218AB0FFD000490CC /* crypto_scrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D118AB0FFD000490CC /* crypto_scrypt.h */; };
|
||||||
|
DAEB942318AB0FFD000490CC /* memlimit.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D218AB0FFD000490CC /* memlimit.h */; };
|
||||||
|
DAEB942418AB0FFD000490CC /* readpass.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D318AB0FFD000490CC /* readpass.h */; };
|
||||||
|
DAEB942518AB0FFD000490CC /* scryptenc.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D418AB0FFD000490CC /* scryptenc.h */; };
|
||||||
|
DAEB942618AB0FFD000490CC /* scryptenc_cpuperf.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D518AB0FFD000490CC /* scryptenc_cpuperf.h */; };
|
||||||
|
DAEB942718AB0FFD000490CC /* sha256.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D618AB0FFD000490CC /* sha256.h */; };
|
||||||
|
DAEB942818AB0FFD000490CC /* sysendian.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D718AB0FFD000490CC /* sysendian.h */; };
|
||||||
|
DAEB942918AB0FFD000490CC /* warn.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB93D818AB0FFD000490CC /* warn.h */; };
|
||||||
|
DAEB942E18B47FB3000490CC /* MPInitialWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA0933C91747A56A00DE1CEF /* MPInitialWindow.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 */; };
|
||||||
@@ -221,15 +301,25 @@
|
|||||||
|
|
||||||
/* 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>"; };
|
||||||
|
93D39240B5143E01F0B75E96 /* MPElementModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementModel.h; 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>"; };
|
||||||
|
93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementCollectionView.m; sourceTree = "<group>"; };
|
||||||
|
93D3960D320FF8A072B092E3 /* MPElementCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementCollectionView.h; 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>"; };
|
||||||
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>"; };
|
||||||
|
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementModel.m; sourceTree = "<group>"; };
|
||||||
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPInitialWindow.xib; sourceTree = "<group>"; };
|
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPInitialWindow.xib; sourceTree = "<group>"; };
|
||||||
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = "<group>"; };
|
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = "<group>"; };
|
||||||
DA0933CF1747B91B00DE1CEF /* appstore.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = appstore.png; sourceTree = "<group>"; };
|
DA0933CF1747B91B00DE1CEF /* appstore.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = appstore.png; sourceTree = "<group>"; };
|
||||||
DA16B340170661DB000A0EAB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
DA16B340170661DB000A0EAB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
||||||
DA16B343170661EE000A0EAB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
DA16B343170661EE000A0EAB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||||
DA1E4D4F176E0E280065E0EF /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Media.xcassets; path = MasterPassword/Media.xcassets; sourceTree = "<group>"; };
|
DA1E4D4F176E0E280065E0EF /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Media.xcassets; path = MasterPassword/Media.xcassets; sourceTree = "<group>"; };
|
||||||
|
DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
|
||||||
|
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
|
||||||
|
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
|
||||||
|
DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; };
|
||||||
|
DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+PearlBlock.m"; sourceTree = "<group>"; };
|
||||||
|
DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+PearlBlock.h"; sourceTree = "<group>"; };
|
||||||
DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+PearlMutableInfo.h"; sourceTree = "<group>"; };
|
DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+PearlMutableInfo.h"; sourceTree = "<group>"; };
|
||||||
DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+PearlMutableInfo.m"; sourceTree = "<group>"; };
|
DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+PearlMutableInfo.m"; sourceTree = "<group>"; };
|
||||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
||||||
@@ -245,15 +335,6 @@
|
|||||||
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
DA5BFA4E147E415C00F98B1E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||||
DA5E5C7B17248AA1003798D8 /* crypto_aesctr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_aesctr.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C7C17248AA1003798D8 /* crypto_scrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_scrypt.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C7D17248AA1003798D8 /* memlimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memlimit.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C7E17248AA1003798D8 /* readpass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readpass.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C7F17248AA1003798D8 /* scryptenc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scryptenc.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C8017248AA1003798D8 /* scryptenc_cpuperf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scryptenc_cpuperf.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C8117248AA1003798D8 /* sha256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha256.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C8217248AA1003798D8 /* sysendian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sysendian.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C8317248AA1003798D8 /* warn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = warn.h; sourceTree = "<group>"; };
|
|
||||||
DA5E5C8717248AA1003798D8 /* libscryptenc-osx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libscryptenc-osx.a"; sourceTree = "<group>"; };
|
DA5E5C8717248AA1003798D8 /* libscryptenc-osx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libscryptenc-osx.a"; sourceTree = "<group>"; };
|
||||||
DA5E5C971724A667003798D8 /* MPAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithm.h; sourceTree = "<group>"; };
|
DA5E5C971724A667003798D8 /* MPAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithm.h; sourceTree = "<group>"; };
|
||||||
DA5E5C981724A667003798D8 /* MPAlgorithm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithm.m; sourceTree = "<group>"; };
|
DA5E5C981724A667003798D8 /* MPAlgorithm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithm.m; sourceTree = "<group>"; };
|
||||||
@@ -373,6 +454,87 @@
|
|||||||
DAD312C01552A20800A3F9ED /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
|
DAD312C01552A20800A3F9ED /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
|
||||||
DAD9B5E1176299B9001835F9 /* MasterPassword-Mac-LoginHelper.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "MasterPassword-Mac-LoginHelper.xcodeproj"; path = "MasterPassword-Mac-LoginHelper/MasterPassword-Mac-LoginHelper.xcodeproj"; sourceTree = "<group>"; };
|
DAD9B5E1176299B9001835F9 /* MasterPassword-Mac-LoginHelper.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "MasterPassword-Mac-LoginHelper.xcodeproj"; path = "MasterPassword-Mac-LoginHelper/MasterPassword-Mac-LoginHelper.xcodeproj"; sourceTree = "<group>"; };
|
||||||
DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
|
DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
|
||||||
|
DAEB938718AB0FFD000490CC /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938818AB0FFD000490CC /* asn1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938918AB0FFD000490CC /* asn1_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1_mac.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938A18AB0FFD000490CC /* asn1t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1t.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938B18AB0FFD000490CC /* bio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bio.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938C18AB0FFD000490CC /* blowfish.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blowfish.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938D18AB0FFD000490CC /* bn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bn.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938E18AB0FFD000490CC /* buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = buffer.h; sourceTree = "<group>"; };
|
||||||
|
DAEB938F18AB0FFD000490CC /* camellia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = camellia.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939018AB0FFD000490CC /* cast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cast.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939118AB0FFD000490CC /* cms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cms.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939218AB0FFD000490CC /* comp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = comp.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939318AB0FFD000490CC /* conf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conf.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939418AB0FFD000490CC /* conf_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conf_api.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939518AB0FFD000490CC /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939618AB0FFD000490CC /* des.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = des.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939718AB0FFD000490CC /* des_old.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = des_old.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939818AB0FFD000490CC /* dh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dh.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939918AB0FFD000490CC /* dsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsa.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939A18AB0FFD000490CC /* dso.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dso.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939B18AB0FFD000490CC /* dtls1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtls1.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939C18AB0FFD000490CC /* e_os2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = e_os2.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939D18AB0FFD000490CC /* ebcdic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ebcdic.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939E18AB0FFD000490CC /* ec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ec.h; sourceTree = "<group>"; };
|
||||||
|
DAEB939F18AB0FFD000490CC /* ecdh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecdh.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A018AB0FFD000490CC /* ecdsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecdsa.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A118AB0FFD000490CC /* engine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = engine.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A218AB0FFD000490CC /* err.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = err.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A318AB0FFD000490CC /* evp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = evp.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A418AB0FFD000490CC /* hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmac.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A518AB0FFD000490CC /* idea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idea.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A618AB0FFD000490CC /* krb5_asn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = krb5_asn.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A718AB0FFD000490CC /* kssl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kssl.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A818AB0FFD000490CC /* lhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lhash.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93A918AB0FFD000490CC /* md4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md4.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93AA18AB0FFD000490CC /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93AB18AB0FFD000490CC /* mdc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mdc2.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93AC18AB0FFD000490CC /* modes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modes.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93AD18AB0FFD000490CC /* obj_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = obj_mac.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93AE18AB0FFD000490CC /* objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objects.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93AF18AB0FFD000490CC /* ocsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ocsp.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B018AB0FFD000490CC /* opensslconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opensslconf.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B118AB0FFD000490CC /* opensslv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opensslv.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B218AB0FFD000490CC /* ossl_typ.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ossl_typ.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B318AB0FFD000490CC /* pem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pem.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B418AB0FFD000490CC /* pem2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pem2.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B518AB0FFD000490CC /* pkcs12.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pkcs12.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B618AB0FFD000490CC /* pkcs7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pkcs7.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B718AB0FFD000490CC /* pqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pqueue.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B818AB0FFD000490CC /* rand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rand.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93B918AB0FFD000490CC /* rc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rc2.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93BA18AB0FFD000490CC /* rc4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rc4.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93BB18AB0FFD000490CC /* ripemd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ripemd.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93BC18AB0FFD000490CC /* rsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rsa.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93BD18AB0FFD000490CC /* safestack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = safestack.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93BE18AB0FFD000490CC /* seed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seed.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93BF18AB0FFD000490CC /* sha.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C018AB0FFD000490CC /* ssl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C118AB0FFD000490CC /* ssl2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl2.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C218AB0FFD000490CC /* ssl23.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl23.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C318AB0FFD000490CC /* ssl3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl3.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C418AB0FFD000490CC /* stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C518AB0FFD000490CC /* symhacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = symhacks.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C618AB0FFD000490CC /* tls1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tls1.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C718AB0FFD000490CC /* ts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ts.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C818AB0FFD000490CC /* txt_db.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = txt_db.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93C918AB0FFD000490CC /* ui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93CA18AB0FFD000490CC /* ui_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui_compat.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93CB18AB0FFD000490CC /* whrlpool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = whrlpool.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93CC18AB0FFD000490CC /* x509.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93CD18AB0FFD000490CC /* x509_vfy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509_vfy.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93CE18AB0FFD000490CC /* x509v3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509v3.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D018AB0FFD000490CC /* crypto_aesctr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_aesctr.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D118AB0FFD000490CC /* crypto_scrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_scrypt.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D218AB0FFD000490CC /* memlimit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memlimit.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D318AB0FFD000490CC /* readpass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readpass.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D418AB0FFD000490CC /* scryptenc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scryptenc.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D518AB0FFD000490CC /* scryptenc_cpuperf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scryptenc_cpuperf.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D618AB0FFD000490CC /* sha256.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha256.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D718AB0FFD000490CC /* sysendian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sysendian.h; sourceTree = "<group>"; };
|
||||||
|
DAEB93D818AB0FFD000490CC /* warn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = warn.h; 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; };
|
||||||
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>"; };
|
||||||
@@ -530,28 +692,12 @@
|
|||||||
DA5E5C7917248AA1003798D8 /* lib */ = {
|
DA5E5C7917248AA1003798D8 /* lib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
DA5E5C7A17248AA1003798D8 /* include */,
|
DAEB938518AB0FFD000490CC /* include */,
|
||||||
DA5E5C8717248AA1003798D8 /* libscryptenc-osx.a */,
|
DA5E5C8717248AA1003798D8 /* libscryptenc-osx.a */,
|
||||||
);
|
);
|
||||||
path = lib;
|
path = lib;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
DA5E5C7A17248AA1003798D8 /* include */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
DA5E5C7B17248AA1003798D8 /* crypto_aesctr.h */,
|
|
||||||
DA5E5C7C17248AA1003798D8 /* crypto_scrypt.h */,
|
|
||||||
DA5E5C7D17248AA1003798D8 /* memlimit.h */,
|
|
||||||
DA5E5C7E17248AA1003798D8 /* readpass.h */,
|
|
||||||
DA5E5C7F17248AA1003798D8 /* scryptenc.h */,
|
|
||||||
DA5E5C8017248AA1003798D8 /* scryptenc_cpuperf.h */,
|
|
||||||
DA5E5C8117248AA1003798D8 /* sha256.h */,
|
|
||||||
DA5E5C8217248AA1003798D8 /* sysendian.h */,
|
|
||||||
DA5E5C8317248AA1003798D8 /* warn.h */,
|
|
||||||
);
|
|
||||||
path = include;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
DA5E5C961724A667003798D8 /* ObjC */ = {
|
DA5E5C961724A667003798D8 /* ObjC */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -608,6 +754,10 @@
|
|||||||
DA5E5CC41724A667003798D8 /* MainMenu.xib */,
|
DA5E5CC41724A667003798D8 /* MainMenu.xib */,
|
||||||
DA5E5CC61724A667003798D8 /* main.m */,
|
DA5E5CC61724A667003798D8 /* main.m */,
|
||||||
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */,
|
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */,
|
||||||
|
93D394495528B10D1B61A2C3 /* MPElementCollectionView.m */,
|
||||||
|
93D3960D320FF8A072B092E3 /* MPElementCollectionView.h */,
|
||||||
|
93D39E73BF5CBF8E5B005CD3 /* MPElementModel.m */,
|
||||||
|
93D39240B5143E01F0B75E96 /* MPElementModel.h */,
|
||||||
);
|
);
|
||||||
path = Mac;
|
path = Mac;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -793,9 +943,119 @@
|
|||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
DAEB938518AB0FFD000490CC /* include */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
DAEB938618AB0FFD000490CC /* openssl */,
|
||||||
|
DAEB93CF18AB0FFD000490CC /* scrypt */,
|
||||||
|
);
|
||||||
|
path = include;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
DAEB938618AB0FFD000490CC /* openssl */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
DAEB938718AB0FFD000490CC /* aes.h */,
|
||||||
|
DAEB938818AB0FFD000490CC /* asn1.h */,
|
||||||
|
DAEB938918AB0FFD000490CC /* asn1_mac.h */,
|
||||||
|
DAEB938A18AB0FFD000490CC /* asn1t.h */,
|
||||||
|
DAEB938B18AB0FFD000490CC /* bio.h */,
|
||||||
|
DAEB938C18AB0FFD000490CC /* blowfish.h */,
|
||||||
|
DAEB938D18AB0FFD000490CC /* bn.h */,
|
||||||
|
DAEB938E18AB0FFD000490CC /* buffer.h */,
|
||||||
|
DAEB938F18AB0FFD000490CC /* camellia.h */,
|
||||||
|
DAEB939018AB0FFD000490CC /* cast.h */,
|
||||||
|
DAEB939118AB0FFD000490CC /* cms.h */,
|
||||||
|
DAEB939218AB0FFD000490CC /* comp.h */,
|
||||||
|
DAEB939318AB0FFD000490CC /* conf.h */,
|
||||||
|
DAEB939418AB0FFD000490CC /* conf_api.h */,
|
||||||
|
DAEB939518AB0FFD000490CC /* crypto.h */,
|
||||||
|
DAEB939618AB0FFD000490CC /* des.h */,
|
||||||
|
DAEB939718AB0FFD000490CC /* des_old.h */,
|
||||||
|
DAEB939818AB0FFD000490CC /* dh.h */,
|
||||||
|
DAEB939918AB0FFD000490CC /* dsa.h */,
|
||||||
|
DAEB939A18AB0FFD000490CC /* dso.h */,
|
||||||
|
DAEB939B18AB0FFD000490CC /* dtls1.h */,
|
||||||
|
DAEB939C18AB0FFD000490CC /* e_os2.h */,
|
||||||
|
DAEB939D18AB0FFD000490CC /* ebcdic.h */,
|
||||||
|
DAEB939E18AB0FFD000490CC /* ec.h */,
|
||||||
|
DAEB939F18AB0FFD000490CC /* ecdh.h */,
|
||||||
|
DAEB93A018AB0FFD000490CC /* ecdsa.h */,
|
||||||
|
DAEB93A118AB0FFD000490CC /* engine.h */,
|
||||||
|
DAEB93A218AB0FFD000490CC /* err.h */,
|
||||||
|
DAEB93A318AB0FFD000490CC /* evp.h */,
|
||||||
|
DAEB93A418AB0FFD000490CC /* hmac.h */,
|
||||||
|
DAEB93A518AB0FFD000490CC /* idea.h */,
|
||||||
|
DAEB93A618AB0FFD000490CC /* krb5_asn.h */,
|
||||||
|
DAEB93A718AB0FFD000490CC /* kssl.h */,
|
||||||
|
DAEB93A818AB0FFD000490CC /* lhash.h */,
|
||||||
|
DAEB93A918AB0FFD000490CC /* md4.h */,
|
||||||
|
DAEB93AA18AB0FFD000490CC /* md5.h */,
|
||||||
|
DAEB93AB18AB0FFD000490CC /* mdc2.h */,
|
||||||
|
DAEB93AC18AB0FFD000490CC /* modes.h */,
|
||||||
|
DAEB93AD18AB0FFD000490CC /* obj_mac.h */,
|
||||||
|
DAEB93AE18AB0FFD000490CC /* objects.h */,
|
||||||
|
DAEB93AF18AB0FFD000490CC /* ocsp.h */,
|
||||||
|
DAEB93B018AB0FFD000490CC /* opensslconf.h */,
|
||||||
|
DAEB93B118AB0FFD000490CC /* opensslv.h */,
|
||||||
|
DAEB93B218AB0FFD000490CC /* ossl_typ.h */,
|
||||||
|
DAEB93B318AB0FFD000490CC /* pem.h */,
|
||||||
|
DAEB93B418AB0FFD000490CC /* pem2.h */,
|
||||||
|
DAEB93B518AB0FFD000490CC /* pkcs12.h */,
|
||||||
|
DAEB93B618AB0FFD000490CC /* pkcs7.h */,
|
||||||
|
DAEB93B718AB0FFD000490CC /* pqueue.h */,
|
||||||
|
DAEB93B818AB0FFD000490CC /* rand.h */,
|
||||||
|
DAEB93B918AB0FFD000490CC /* rc2.h */,
|
||||||
|
DAEB93BA18AB0FFD000490CC /* rc4.h */,
|
||||||
|
DAEB93BB18AB0FFD000490CC /* ripemd.h */,
|
||||||
|
DAEB93BC18AB0FFD000490CC /* rsa.h */,
|
||||||
|
DAEB93BD18AB0FFD000490CC /* safestack.h */,
|
||||||
|
DAEB93BE18AB0FFD000490CC /* seed.h */,
|
||||||
|
DAEB93BF18AB0FFD000490CC /* sha.h */,
|
||||||
|
DAEB93C018AB0FFD000490CC /* ssl.h */,
|
||||||
|
DAEB93C118AB0FFD000490CC /* ssl2.h */,
|
||||||
|
DAEB93C218AB0FFD000490CC /* ssl23.h */,
|
||||||
|
DAEB93C318AB0FFD000490CC /* ssl3.h */,
|
||||||
|
DAEB93C418AB0FFD000490CC /* stack.h */,
|
||||||
|
DAEB93C518AB0FFD000490CC /* symhacks.h */,
|
||||||
|
DAEB93C618AB0FFD000490CC /* tls1.h */,
|
||||||
|
DAEB93C718AB0FFD000490CC /* ts.h */,
|
||||||
|
DAEB93C818AB0FFD000490CC /* txt_db.h */,
|
||||||
|
DAEB93C918AB0FFD000490CC /* ui.h */,
|
||||||
|
DAEB93CA18AB0FFD000490CC /* ui_compat.h */,
|
||||||
|
DAEB93CB18AB0FFD000490CC /* whrlpool.h */,
|
||||||
|
DAEB93CC18AB0FFD000490CC /* x509.h */,
|
||||||
|
DAEB93CD18AB0FFD000490CC /* x509_vfy.h */,
|
||||||
|
DAEB93CE18AB0FFD000490CC /* x509v3.h */,
|
||||||
|
);
|
||||||
|
path = openssl;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
DAEB93CF18AB0FFD000490CC /* scrypt */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
DAEB93D018AB0FFD000490CC /* crypto_aesctr.h */,
|
||||||
|
DAEB93D118AB0FFD000490CC /* crypto_scrypt.h */,
|
||||||
|
DAEB93D218AB0FFD000490CC /* memlimit.h */,
|
||||||
|
DAEB93D318AB0FFD000490CC /* readpass.h */,
|
||||||
|
DAEB93D418AB0FFD000490CC /* scryptenc.h */,
|
||||||
|
DAEB93D518AB0FFD000490CC /* scryptenc_cpuperf.h */,
|
||||||
|
DAEB93D618AB0FFD000490CC /* sha256.h */,
|
||||||
|
DAEB93D718AB0FFD000490CC /* sysendian.h */,
|
||||||
|
DAEB93D818AB0FFD000490CC /* warn.h */,
|
||||||
|
);
|
||||||
|
path = scrypt;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
DAFE45D715039823003ABA7C /* Pearl */ = {
|
DAFE45D715039823003ABA7C /* Pearl */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DA2CA4E718D323D3007798F8 /* NSError+PearlFullDescription.m */,
|
||||||
|
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */,
|
||||||
|
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */,
|
||||||
|
DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */,
|
||||||
|
DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */,
|
||||||
|
DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */,
|
||||||
DA3509FC15F101A500C14A8E /* PearlQueue.h */,
|
DA3509FC15F101A500C14A8E /* PearlQueue.h */,
|
||||||
DA3509FD15F101A500C14A8E /* PearlQueue.m */,
|
DA3509FD15F101A500C14A8E /* PearlQueue.m */,
|
||||||
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */,
|
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */,
|
||||||
@@ -896,42 +1156,117 @@
|
|||||||
isa = PBXHeadersBuildPhase;
|
isa = PBXHeadersBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
DAEB941818AB0FFD000490CC /* tls1.h in Headers */,
|
||||||
|
DAEB940C18AB0FFD000490CC /* rc4.h in Headers */,
|
||||||
|
DAEB93F418AB0FFD000490CC /* err.h in Headers */,
|
||||||
|
DAEB93F118AB0FFD000490CC /* ecdh.h in Headers */,
|
||||||
|
DAEB93FD18AB0FFD000490CC /* mdc2.h in Headers */,
|
||||||
|
DAEB942718AB0FFD000490CC /* sha256.h in Headers */,
|
||||||
|
DAEB940818AB0FFD000490CC /* pkcs7.h in Headers */,
|
||||||
|
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */,
|
||||||
|
DAEB93DF18AB0FFD000490CC /* bn.h in Headers */,
|
||||||
|
DAEB940718AB0FFD000490CC /* pkcs12.h in Headers */,
|
||||||
|
DAEB941A18AB0FFD000490CC /* txt_db.h in Headers */,
|
||||||
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
|
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
|
||||||
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
|
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
|
||||||
|
DAEB942218AB0FFD000490CC /* crypto_scrypt.h in Headers */,
|
||||||
|
DAEB941018AB0FFD000490CC /* seed.h in Headers */,
|
||||||
|
DAEB942618AB0FFD000490CC /* scryptenc_cpuperf.h in Headers */,
|
||||||
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
|
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
|
||||||
|
DAEB93F518AB0FFD000490CC /* evp.h in Headers */,
|
||||||
|
DAEB941918AB0FFD000490CC /* ts.h in Headers */,
|
||||||
|
DAEB93F818AB0FFD000490CC /* krb5_asn.h in Headers */,
|
||||||
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
||||||
|
DAEB93F318AB0FFD000490CC /* engine.h in Headers */,
|
||||||
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
||||||
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
||||||
|
DAEB940918AB0FFD000490CC /* pqueue.h in Headers */,
|
||||||
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
||||||
|
DAEB941B18AB0FFD000490CC /* ui.h in Headers */,
|
||||||
|
DAEB941D18AB0FFD000490CC /* whrlpool.h in Headers */,
|
||||||
|
DAEB940418AB0FFD000490CC /* ossl_typ.h in Headers */,
|
||||||
|
DAEB93DC18AB0FFD000490CC /* asn1t.h in Headers */,
|
||||||
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
||||||
|
DAEB93E518AB0FFD000490CC /* conf.h in Headers */,
|
||||||
DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */,
|
DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */,
|
||||||
|
DAEB940618AB0FFD000490CC /* pem2.h in Headers */,
|
||||||
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
||||||
|
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */,
|
||||||
|
DAEB93FC18AB0FFD000490CC /* md5.h in Headers */,
|
||||||
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
||||||
DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */,
|
DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */,
|
||||||
|
DAEB93E318AB0FFD000490CC /* cms.h in Headers */,
|
||||||
|
DAEB942518AB0FFD000490CC /* scryptenc.h in Headers */,
|
||||||
|
DAEB93FA18AB0FFD000490CC /* lhash.h in Headers */,
|
||||||
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
||||||
|
DAEB940B18AB0FFD000490CC /* rc2.h in Headers */,
|
||||||
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
||||||
|
DAEB93DA18AB0FFD000490CC /* asn1.h in Headers */,
|
||||||
|
DAEB93EA18AB0FFD000490CC /* dh.h in Headers */,
|
||||||
|
DAEB93F918AB0FFD000490CC /* kssl.h in Headers */,
|
||||||
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
||||||
|
DAEB940318AB0FFD000490CC /* opensslv.h in Headers */,
|
||||||
|
DAEB93ED18AB0FFD000490CC /* dtls1.h in Headers */,
|
||||||
|
DAEB93E018AB0FFD000490CC /* buffer.h in Headers */,
|
||||||
|
DAEB940218AB0FFD000490CC /* opensslconf.h in Headers */,
|
||||||
|
DAEB93E918AB0FFD000490CC /* des_old.h in Headers */,
|
||||||
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
||||||
|
DAEB941C18AB0FFD000490CC /* ui_compat.h in Headers */,
|
||||||
|
DAEB93E218AB0FFD000490CC /* cast.h in Headers */,
|
||||||
|
DAEB942318AB0FFD000490CC /* memlimit.h in Headers */,
|
||||||
DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */,
|
DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */,
|
||||||
|
DAEB940018AB0FFD000490CC /* objects.h in Headers */,
|
||||||
|
DAEB93E818AB0FFD000490CC /* des.h in Headers */,
|
||||||
|
DAEB941418AB0FFD000490CC /* ssl23.h in Headers */,
|
||||||
|
DAEB93EB18AB0FFD000490CC /* dsa.h in Headers */,
|
||||||
|
DAEB941218AB0FFD000490CC /* ssl.h in Headers */,
|
||||||
|
DAEB93FE18AB0FFD000490CC /* modes.h in Headers */,
|
||||||
|
DAEB940A18AB0FFD000490CC /* rand.h in Headers */,
|
||||||
|
DAEB93EE18AB0FFD000490CC /* e_os2.h in Headers */,
|
||||||
|
DAEB940E18AB0FFD000490CC /* rsa.h in Headers */,
|
||||||
|
DAEB93E618AB0FFD000490CC /* conf_api.h in Headers */,
|
||||||
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
||||||
|
DAEB941518AB0FFD000490CC /* ssl3.h in Headers */,
|
||||||
|
DAEB941618AB0FFD000490CC /* stack.h in Headers */,
|
||||||
DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */,
|
DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */,
|
||||||
|
DAEB93DD18AB0FFD000490CC /* bio.h in Headers */,
|
||||||
|
DAEB942418AB0FFD000490CC /* readpass.h in Headers */,
|
||||||
|
DAEB93F018AB0FFD000490CC /* ec.h in Headers */,
|
||||||
|
DAEB93E418AB0FFD000490CC /* comp.h in Headers */,
|
||||||
DAFE4A3A15039824003ABA7C /* PearlSCrypt.h in Headers */,
|
DAFE4A3A15039824003ABA7C /* PearlSCrypt.h in Headers */,
|
||||||
|
DAEB93D918AB0FFD000490CC /* aes.h in Headers */,
|
||||||
DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */,
|
DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */,
|
||||||
|
DAEB93FB18AB0FFD000490CC /* md4.h in Headers */,
|
||||||
|
DAEB941118AB0FFD000490CC /* sha.h in Headers */,
|
||||||
|
DAEB941F18AB0FFD000490CC /* x509_vfy.h in Headers */,
|
||||||
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
|
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
|
||||||
|
DAEB93EC18AB0FFD000490CC /* dso.h in Headers */,
|
||||||
|
DAEB940118AB0FFD000490CC /* ocsp.h in Headers */,
|
||||||
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
|
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
|
||||||
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
|
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
|
||||||
|
DAEB93F718AB0FFD000490CC /* idea.h in Headers */,
|
||||||
|
DAEB940F18AB0FFD000490CC /* safestack.h in Headers */,
|
||||||
|
DAEB941E18AB0FFD000490CC /* x509.h in Headers */,
|
||||||
|
DAEB93EF18AB0FFD000490CC /* ebcdic.h in Headers */,
|
||||||
|
DAEB93DE18AB0FFD000490CC /* blowfish.h in Headers */,
|
||||||
|
DAEB941718AB0FFD000490CC /* symhacks.h in Headers */,
|
||||||
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */,
|
93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */,
|
||||||
|
DAEB942118AB0FFD000490CC /* crypto_aesctr.h in Headers */,
|
||||||
|
DAEB93F218AB0FFD000490CC /* ecdsa.h in Headers */,
|
||||||
|
DAEB942018AB0FFD000490CC /* x509v3.h in Headers */,
|
||||||
|
DAEB93E118AB0FFD000490CC /* camellia.h in Headers */,
|
||||||
|
DAEB93F618AB0FFD000490CC /* hmac.h in Headers */,
|
||||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */,
|
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */,
|
||||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
||||||
DA5E5C8817248AA1003798D8 /* crypto_aesctr.h in Headers */,
|
DAEB942918AB0FFD000490CC /* warn.h in Headers */,
|
||||||
DA5E5C8917248AA1003798D8 /* crypto_scrypt.h in Headers */,
|
DAEB93DB18AB0FFD000490CC /* asn1_mac.h in Headers */,
|
||||||
DA5E5C8A17248AA1003798D8 /* memlimit.h in Headers */,
|
DAEB940518AB0FFD000490CC /* pem.h in Headers */,
|
||||||
DA5E5C8B17248AA1003798D8 /* readpass.h in Headers */,
|
DAEB942818AB0FFD000490CC /* sysendian.h in Headers */,
|
||||||
DA5E5C8C17248AA1003798D8 /* scryptenc.h in Headers */,
|
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */,
|
||||||
DA5E5C8D17248AA1003798D8 /* scryptenc_cpuperf.h in Headers */,
|
DAEB93FF18AB0FFD000490CC /* obj_mac.h in Headers */,
|
||||||
DA5E5C8E17248AA1003798D8 /* sha256.h in Headers */,
|
DAEB93E718AB0FFD000490CC /* crypto.h in Headers */,
|
||||||
DA5E5C8F17248AA1003798D8 /* sysendian.h in Headers */,
|
DAEB941318AB0FFD000490CC /* ssl2.h in Headers */,
|
||||||
DA5E5C9017248AA1003798D8 /* warn.h in Headers */,
|
DAEB940D18AB0FFD000490CC /* ripemd.h in Headers */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -1138,6 +1473,7 @@
|
|||||||
DACA27231705DF81002C6C22 /* avatar-15@2x.png in Resources */,
|
DACA27231705DF81002C6C22 /* avatar-15@2x.png in Resources */,
|
||||||
DACA27241705DF81002C6C22 /* avatar-5@2x.png in Resources */,
|
DACA27241705DF81002C6C22 /* avatar-5@2x.png in Resources */,
|
||||||
DACA27251705DF81002C6C22 /* avatar-6.png in Resources */,
|
DACA27251705DF81002C6C22 /* avatar-6.png in Resources */,
|
||||||
|
DAEB942E18B47FB3000490CC /* MPInitialWindow.xib in Resources */,
|
||||||
DACA27261705DF81002C6C22 /* avatar-6@2x.png in Resources */,
|
DACA27261705DF81002C6C22 /* avatar-6@2x.png in Resources */,
|
||||||
DACA27271705DF81002C6C22 /* avatar-16@2x.png in Resources */,
|
DACA27271705DF81002C6C22 /* avatar-16@2x.png in Resources */,
|
||||||
DACA27281705DF81002C6C22 /* avatar-10.png in Resources */,
|
DACA27281705DF81002C6C22 /* avatar-10.png in Resources */,
|
||||||
@@ -1172,7 +1508,6 @@
|
|||||||
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
||||||
DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */,
|
DA5E5D0B1724A667003798D8 /* MainMenu.xib in Resources */,
|
||||||
DA5E5D551724F9C8003798D8 /* MasterPassword.iconset in Resources */,
|
DA5E5D551724F9C8003798D8 /* MasterPassword.iconset in Resources */,
|
||||||
DA0933CA1747A56A00DE1CEF /* MPInitialWindow.xib in Resources */,
|
|
||||||
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */,
|
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */,
|
||||||
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */,
|
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */,
|
||||||
);
|
);
|
||||||
@@ -1265,6 +1600,8 @@
|
|||||||
DA5E5D051724A667003798D8 /* MPPasswordWindowController.m in Sources */,
|
DA5E5D051724A667003798D8 /* MPPasswordWindowController.m in Sources */,
|
||||||
DA5E5D0C1724A667003798D8 /* main.m in Sources */,
|
DA5E5D0C1724A667003798D8 /* main.m in Sources */,
|
||||||
DA5E5D0D1724A667003798D8 /* MasterPassword.xcdatamodeld in Sources */,
|
DA5E5D0D1724A667003798D8 /* MasterPassword.xcdatamodeld in Sources */,
|
||||||
|
93D39C7C2BE7C0E0763B0177 /* MPElementCollectionView.m in Sources */,
|
||||||
|
93D39C5789EFA607CF788082 /* MPElementModel.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -1291,6 +1628,7 @@
|
|||||||
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
|
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
|
||||||
DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
|
DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
|
||||||
DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
|
DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
|
||||||
|
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */,
|
||||||
DAFE4A1B15039824003ABA7C /* PearlAbstractStrings.m in Sources */,
|
DAFE4A1B15039824003ABA7C /* PearlAbstractStrings.m in Sources */,
|
||||||
DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
|
DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
|
||||||
DAFE4A2115039824003ABA7C /* PearlConfig.m in Sources */,
|
DAFE4A2115039824003ABA7C /* PearlConfig.m in Sources */,
|
||||||
@@ -1306,8 +1644,10 @@
|
|||||||
DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */,
|
DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */,
|
||||||
DAFE4A3B15039824003ABA7C /* PearlSCrypt.m in Sources */,
|
DAFE4A3B15039824003ABA7C /* PearlSCrypt.m in Sources */,
|
||||||
DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */,
|
DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */,
|
||||||
|
DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */,
|
||||||
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */,
|
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */,
|
||||||
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */,
|
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */,
|
||||||
|
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */,
|
||||||
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
|
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
|
||||||
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
||||||
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
|
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
|
||||||
@@ -1578,7 +1918,7 @@
|
|||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@@ -1644,7 +1984,6 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
||||||
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
||||||
@@ -1659,7 +1998,6 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
||||||
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
||||||
@@ -1689,7 +2027,7 @@
|
|||||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||||
CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
@@ -1755,7 +2093,6 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements;
|
CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch";
|
||||||
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
INFOPLIST_FILE = "MasterPassword-Info.plist";
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.developer.ubiquity-container-identifiers</key>
|
<key>com.apple.developer.ubiquity-container-identifiers</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword.Mac</string>
|
<string>HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.Mac</string>
|
||||||
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword.shared</string>
|
<string>HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared</string>
|
||||||
</array>
|
</array>
|
||||||
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
|
||||||
<string>$(TeamIdentifierPrefix)com.lyndir.lhunath.MasterPassword.shared</string>
|
<string>HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared</string>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
@@ -1,780 +1,204 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B3116" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<data>
|
<dependencies>
|
||||||
<int key="IBDocument.SystemTarget">1070</int>
|
<deployment version="1070" defaultVersion="1080" identifier="macosx"/>
|
||||||
<string key="IBDocument.SystemVersion">12D78</string>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
|
||||||
<string key="IBDocument.InterfaceBuilderVersion">3084</string>
|
</dependencies>
|
||||||
<string key="IBDocument.AppKitVersion">1187.37</string>
|
<objects>
|
||||||
<string key="IBDocument.HIToolboxVersion">626.00</string>
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
<connections>
|
||||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<outlet property="delegate" destination="494" id="495"/>
|
||||||
<string key="NS.object.0">3084</string>
|
</connections>
|
||||||
</object>
|
</customObject>
|
||||||
<array key="IBDocument.IntegratedClassDependencies">
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
<string>NSCustomObject</string>
|
<customObject id="-3" userLabel="Application"/>
|
||||||
<string>NSMenu</string>
|
<menu title="AMainMenu" systemMenu="main" id="29"/>
|
||||||
<string>NSMenuItem</string>
|
<customObject id="494" customClass="MPMacAppDelegate">
|
||||||
<string>NSUserDefaultsController</string>
|
<connections>
|
||||||
</array>
|
<outlet property="createUserItem" destination="757" id="763"/>
|
||||||
<array key="IBDocument.PluginDependencies">
|
<outlet property="dialogStyleHUD" destination="768" id="771"/>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<outlet property="dialogStyleRegular" destination="767" id="772"/>
|
||||||
</array>
|
<outlet property="lockItem" destination="720" id="726"/>
|
||||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
<outlet property="openAtLoginItem" destination="785" id="788"/>
|
||||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
<outlet property="rememberPasswordItem" destination="744" id="750"/>
|
||||||
<integer value="1" key="NS.object.0"/>
|
<outlet property="savePasswordItem" destination="747" id="751"/>
|
||||||
</object>
|
<outlet property="showItem" destination="719" id="783"/>
|
||||||
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
|
<outlet property="statusMenu" destination="716" id="731"/>
|
||||||
<object class="NSCustomObject" id="1021">
|
<outlet property="useCloudItem" destination="743" id="749"/>
|
||||||
<string key="NSClassName">NSApplication</string>
|
<outlet property="usersItem" destination="755" id="762"/>
|
||||||
</object>
|
</connections>
|
||||||
<object class="NSCustomObject" id="1014">
|
</customObject>
|
||||||
<string key="NSClassName">FirstResponder</string>
|
<userDefaultsController representsSharedInstance="YES" id="548"/>
|
||||||
</object>
|
<menu autoenablesItems="NO" id="716">
|
||||||
<object class="NSCustomObject" id="1050">
|
<items>
|
||||||
<string key="NSClassName">NSApplication</string>
|
<menuItem title="Users" id="755">
|
||||||
</object>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<object class="NSMenu" id="649796088">
|
<menu key="submenu" title="Users" id="756">
|
||||||
<string key="NSTitle">AMainMenu</string>
|
<items>
|
||||||
<array class="NSMutableArray" key="NSMenuItems"/>
|
<menuItem title="New User" enabled="NO" toolTip="Creating users is not yet supported. Please use the iOS app with iCloud enabled to create users and sites." id="757">
|
||||||
<string key="NSName">_NSMainMenu</string>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
</object>
|
<connections>
|
||||||
<object class="NSCustomObject" id="976324537">
|
<action selector="newUser:" target="494" id="761"/>
|
||||||
<string key="NSClassName">MPMacAppDelegate</string>
|
</connections>
|
||||||
</object>
|
</menuItem>
|
||||||
<object class="NSUserDefaultsController" id="705910970">
|
<menuItem isSeparatorItem="YES" id="759"/>
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
</items>
|
||||||
</object>
|
</menu>
|
||||||
<object class="NSMenu" id="764588027">
|
</menuItem>
|
||||||
<string key="NSTitle"/>
|
<menuItem title="Preferences" id="739">
|
||||||
<array class="NSMutableArray" key="NSMenuItems">
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<object class="NSMenuItem" id="11982480">
|
<menu key="submenu" title="Preferences" autoenablesItems="NO" id="742">
|
||||||
<reference key="NSMenu" ref="764588027"/>
|
<items>
|
||||||
<string key="NSTitle">Users</string>
|
<menuItem title="Use iCloud" id="743">
|
||||||
<string key="NSKeyEquiv"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<connections>
|
||||||
<object class="NSCustomResource" key="NSOnImage" id="269450960">
|
<action selector="togglePreference:" target="494" id="752"/>
|
||||||
<string key="NSClassName">NSImage</string>
|
</connections>
|
||||||
<string key="NSResourceName">NSMenuCheckmark</string>
|
</menuItem>
|
||||||
</object>
|
<menuItem title="Synchronize available sites from your iCloud account." enabled="NO" id="746">
|
||||||
<object class="NSCustomResource" key="NSMixedImage" id="977440657">
|
<attributedString key="attributedTitle">
|
||||||
<string key="NSClassName">NSImage</string>
|
<fragment content="Synchronize available sites from your iCloud account.">
|
||||||
<string key="NSResourceName">NSMenuMixedState</string>
|
<attributes>
|
||||||
</object>
|
<font key="NSFont" size="12" name="Helvetica"/>
|
||||||
<string key="NSAction">submenuAction:</string>
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
<object class="NSMenu" key="NSSubmenu" id="934187555">
|
</attributes>
|
||||||
<string key="NSTitle">Users</string>
|
</fragment>
|
||||||
<array class="NSMutableArray" key="NSMenuItems">
|
</attributedString>
|
||||||
<object class="NSMenuItem" id="576787569">
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<reference key="NSMenu" ref="934187555"/>
|
</menuItem>
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
<menuItem title="Open At Login" id="785">
|
||||||
<string key="NSTitle">New User</string>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<string key="NSKeyEquiv"/>
|
<connections>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<action selector="togglePreference:" target="494" id="787"/>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
</connections>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
</menuItem>
|
||||||
</object>
|
<menuItem title="Always open Master Password at start-up." enabled="NO" id="786">
|
||||||
<object class="NSMenuItem" id="925131766">
|
<attributedString key="attributedTitle">
|
||||||
<reference key="NSMenu" ref="934187555"/>
|
<fragment content="Always open Master Password at start-up.">
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
<attributes>
|
||||||
<bool key="NSIsSeparator">YES</bool>
|
<font key="NSFont" size="12" name="Helvetica"/>
|
||||||
<string key="NSTitle"/>
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
<string key="NSKeyEquiv"/>
|
</attributes>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
</fragment>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
</attributedString>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
</object>
|
</menuItem>
|
||||||
</array>
|
<menuItem title="Remember Password" id="744">
|
||||||
</object>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
</object>
|
<connections>
|
||||||
<object class="NSMenuItem" id="851296005">
|
<action selector="togglePreference:" target="494" id="753"/>
|
||||||
<reference key="NSMenu" ref="764588027"/>
|
</connections>
|
||||||
<string key="NSTitle">Preferences</string>
|
</menuItem>
|
||||||
<string key="NSKeyEquiv"/>
|
<menuItem title="Remember the password while the application is running." enabled="NO" id="745">
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<attributedString key="attributedTitle">
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
<fragment content="Remember the password while the application is running.">
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
<attributes>
|
||||||
<string key="NSAction">submenuAction:</string>
|
<font key="NSFont" size="12" name="Helvetica"/>
|
||||||
<object class="NSMenu" key="NSSubmenu" id="800575174">
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
<string key="NSTitle">Preferences</string>
|
</attributes>
|
||||||
<array class="NSMutableArray" key="NSMenuItems">
|
</fragment>
|
||||||
<object class="NSMenuItem" id="14397049">
|
</attributedString>
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<string key="NSTitle">Use iCloud</string>
|
</menuItem>
|
||||||
<string key="NSKeyEquiv"/>
|
<menuItem title="Save Password" id="747">
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
<connections>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
<action selector="togglePreference:" target="494" id="754"/>
|
||||||
</object>
|
</connections>
|
||||||
<object class="NSMenuItem" id="461686112">
|
</menuItem>
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
<menuItem title="Save the password in your keychain so you don't need to enter it again." enabled="NO" id="748">
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
<attributedString key="attributedTitle">
|
||||||
<string key="NSTitle">Synchronize available sites from your iCloud account.</string>
|
<fragment content="Save the password in your keychain so you don't need to enter it again.">
|
||||||
<string key="NSKeyEquiv"/>
|
<attributes>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<font key="NSFont" size="12" name="Helvetica"/>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
</attributes>
|
||||||
<object class="NSAttributedString" key="NSAttributedTitle">
|
</fragment>
|
||||||
<string key="NSString">Synchronize available sites from your iCloud account.</string>
|
</attributedString>
|
||||||
<dictionary key="NSAttributes" id="583461090">
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<object class="NSFont" key="NSFont">
|
</menuItem>
|
||||||
<string key="NSName">Helvetica</string>
|
<menuItem title="Password Dialog Style" id="765">
|
||||||
<double key="NSSize">12</double>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<int key="NSfFlags">16</int>
|
<menu key="submenu" title="Password Dialog Style" id="766">
|
||||||
</object>
|
<items>
|
||||||
<object class="NSParagraphStyle" key="NSParagraphStyle">
|
<menuItem title="Regular" id="767">
|
||||||
<int key="NSAlignment">4</int>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<nil key="NSTabStops"/>
|
<connections>
|
||||||
</object>
|
<action selector="togglePreference:" target="494" id="773"/>
|
||||||
</dictionary>
|
</connections>
|
||||||
</object>
|
</menuItem>
|
||||||
</object>
|
<menuItem title="HUD" tag="1" id="768">
|
||||||
<object class="NSMenuItem" id="362714849">
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
<connections>
|
||||||
<string key="NSTitle">Open At Login</string>
|
<action selector="togglePreference:" target="494" id="774"/>
|
||||||
<string key="NSKeyEquiv"/>
|
</connections>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
</menuItem>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
</items>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
</menu>
|
||||||
</object>
|
</menuItem>
|
||||||
<object class="NSMenuItem" id="409463580">
|
<menuItem title="Advanced" id="776">
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
<menu key="submenu" title="Advanced" id="777">
|
||||||
<string key="NSTitle">Always open Master Password at start-up.</string>
|
<items>
|
||||||
<string key="NSKeyEquiv"/>
|
<menuItem title="iCloud Truth Push" id="778">
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
<connections>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
<action selector="rebuildCloud:" target="494" id="780"/>
|
||||||
<object class="NSAttributedString" key="NSAttributedTitle">
|
</connections>
|
||||||
<string key="NSString">Always open Master Password at start-up.</string>
|
</menuItem>
|
||||||
<reference key="NSAttributes" ref="583461090"/>
|
<menuItem title="Force our version of the truth upon all other devices." enabled="NO" id="779">
|
||||||
</object>
|
<attributedString key="attributedTitle">
|
||||||
</object>
|
<fragment content="Force this device's version of the truth upon all others.">
|
||||||
<object class="NSMenuItem" id="290760748">
|
<attributes>
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
<font key="NSFont" size="12" name="Helvetica"/>
|
||||||
<string key="NSTitle">Remember Password</string>
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
<string key="NSKeyEquiv"/>
|
</attributes>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
</fragment>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
</attributedString>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
</object>
|
</menuItem>
|
||||||
<object class="NSMenuItem" id="907921953">
|
<menuItem title="iCloud Truth Pull" id="cLQ-kc-cYN">
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
<connections>
|
||||||
<string key="NSTitle">Remember the password while the application is running.</string>
|
<action selector="corruptCloud:" target="494" id="asr-sb-Zkz"/>
|
||||||
<string key="NSKeyEquiv"/>
|
</connections>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
</menuItem>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
<menuItem title="Mark ourselves as corrupt and pull the truth from another." enabled="NO" id="6NL-ki-Jff">
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
<attributedString key="attributedTitle">
|
||||||
<object class="NSAttributedString" key="NSAttributedTitle">
|
<fragment content="Force this device's version of the truth upon all others.">
|
||||||
<string key="NSString">Remember the password while the application is running.</string>
|
<attributes>
|
||||||
<reference key="NSAttributes" ref="583461090"/>
|
<font key="NSFont" size="12" name="Helvetica"/>
|
||||||
</object>
|
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
|
||||||
</object>
|
</attributes>
|
||||||
<object class="NSMenuItem" id="110488020">
|
</fragment>
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
</attributedString>
|
||||||
<string key="NSTitle">Save Password</string>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<string key="NSKeyEquiv"/>
|
</menuItem>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
</items>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
</menu>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
</menuItem>
|
||||||
</object>
|
</items>
|
||||||
<object class="NSMenuItem" id="123831322">
|
</menu>
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
</menuItem>
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
<menuItem isSeparatorItem="YES" id="718"/>
|
||||||
<string key="NSTitle">Save the password in your keychain so you don't need to enter it again.</string>
|
<menuItem title="Open" keyEquivalent="p" id="719">
|
||||||
<string key="NSKeyEquiv"/>
|
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<connections>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
<action selector="showPasswordWindow:" target="494" id="782"/>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
</connections>
|
||||||
<object class="NSAttributedString" key="NSAttributedTitle">
|
</menuItem>
|
||||||
<string key="NSString">Save the password in your keychain so you don't need to enter it again.</string>
|
<menuItem title="Lock" enabled="NO" keyEquivalent="p" id="720">
|
||||||
<reference key="NSAttributes" ref="583461090"/>
|
<modifierMask key="keyEquivalentModifierMask" control="YES" option="YES" command="YES"/>
|
||||||
</object>
|
<connections>
|
||||||
</object>
|
<action selector="lock:" target="494" id="764"/>
|
||||||
<object class="NSMenuItem" id="123543264">
|
</connections>
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
</menuItem>
|
||||||
<string key="NSTitle">Password Dialog Style</string>
|
<menuItem title="Quit" keyEquivalent="q" id="717">
|
||||||
<string key="NSKeyEquiv"/>
|
<connections>
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
<action selector="terminate:" target="494" id="784"/>
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
</connections>
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
</menuItem>
|
||||||
<string key="NSAction">submenuAction:</string>
|
</items>
|
||||||
<object class="NSMenu" key="NSSubmenu" id="293904698">
|
</menu>
|
||||||
<string key="NSTitle">Password Dialog Style</string>
|
</objects>
|
||||||
<array class="NSMutableArray" key="NSMenuItems">
|
</document>
|
||||||
<object class="NSMenuItem" id="560371092">
|
|
||||||
<reference key="NSMenu" ref="293904698"/>
|
|
||||||
<string key="NSTitle">Regular</string>
|
|
||||||
<string key="NSKeyEquiv"/>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
</object>
|
|
||||||
<object class="NSMenuItem" id="117792016">
|
|
||||||
<reference key="NSMenu" ref="293904698"/>
|
|
||||||
<string key="NSTitle">HUD</string>
|
|
||||||
<string key="NSKeyEquiv"/>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
<int key="NSTag">1</int>
|
|
||||||
</object>
|
|
||||||
</array>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="NSMenuItem" id="939693094">
|
|
||||||
<reference key="NSMenu" ref="800575174"/>
|
|
||||||
<string key="NSTitle">Advanced</string>
|
|
||||||
<string key="NSKeyEquiv"/>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
<string key="NSAction">submenuAction:</string>
|
|
||||||
<object class="NSMenu" key="NSSubmenu" id="534220172">
|
|
||||||
<string key="NSTitle">Advanced</string>
|
|
||||||
<array class="NSMutableArray" key="NSMenuItems">
|
|
||||||
<object class="NSMenuItem" id="842321178">
|
|
||||||
<reference key="NSMenu" ref="534220172"/>
|
|
||||||
<string key="NSTitle">iCloud Truth Sync</string>
|
|
||||||
<string key="NSKeyEquiv"/>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
</object>
|
|
||||||
<object class="NSMenuItem" id="946018575">
|
|
||||||
<reference key="NSMenu" ref="534220172"/>
|
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
|
||||||
<string key="NSTitle">Force this device's version of the truth upon all others.</string>
|
|
||||||
<string key="NSKeyEquiv"/>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
<object class="NSAttributedString" key="NSAttributedTitle">
|
|
||||||
<string key="NSString">Force this device's version of the truth upon all others.</string>
|
|
||||||
<reference key="NSAttributes" ref="583461090"/>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
</array>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
</array>
|
|
||||||
<bool key="NSNoAutoenable">YES</bool>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<object class="NSMenuItem" id="466252869">
|
|
||||||
<reference key="NSMenu" ref="764588027"/>
|
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
|
||||||
<bool key="NSIsSeparator">YES</bool>
|
|
||||||
<string key="NSTitle"/>
|
|
||||||
<string key="NSKeyEquiv"/>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
</object>
|
|
||||||
<object class="NSMenuItem" id="846612332">
|
|
||||||
<reference key="NSMenu" ref="764588027"/>
|
|
||||||
<string key="NSTitle">Show</string>
|
|
||||||
<string key="NSKeyEquiv">p</string>
|
|
||||||
<int key="NSKeyEquivModMask">1310720</int>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
</object>
|
|
||||||
<object class="NSMenuItem" id="229948989">
|
|
||||||
<reference key="NSMenu" ref="764588027"/>
|
|
||||||
<bool key="NSIsDisabled">YES</bool>
|
|
||||||
<string key="NSTitle">Lock</string>
|
|
||||||
<string key="NSKeyEquiv">p</string>
|
|
||||||
<int key="NSKeyEquivModMask">1835008</int>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
</object>
|
|
||||||
<object class="NSMenuItem" id="291035877">
|
|
||||||
<reference key="NSMenu" ref="764588027"/>
|
|
||||||
<string key="NSTitle">Quit</string>
|
|
||||||
<string key="NSKeyEquiv">q</string>
|
|
||||||
<int key="NSKeyEquivModMask">1048576</int>
|
|
||||||
<int key="NSMnemonicLoc">2147483647</int>
|
|
||||||
<reference key="NSOnImage" ref="269450960"/>
|
|
||||||
<reference key="NSMixedImage" ref="977440657"/>
|
|
||||||
</object>
|
|
||||||
</array>
|
|
||||||
<bool key="NSNoAutoenable">YES</bool>
|
|
||||||
</object>
|
|
||||||
</array>
|
|
||||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
|
||||||
<array class="NSMutableArray" key="connectionRecords">
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">delegate</string>
|
|
||||||
<reference key="source" ref="1021"/>
|
|
||||||
<reference key="destination" ref="976324537"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">495</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">lockItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="229948989"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">726</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">statusMenu</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="764588027"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">731</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">useCloudItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="14397049"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">749</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">rememberPasswordItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="290760748"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">750</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">savePasswordItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="110488020"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">751</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">togglePreference:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="14397049"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">752</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">togglePreference:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="290760748"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">753</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">togglePreference:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="110488020"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">754</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">newUser:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="576787569"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">761</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">usersItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="11982480"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">762</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">createUserItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="576787569"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">763</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">lock:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="229948989"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">764</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">dialogStyleHUD</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="117792016"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">771</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">dialogStyleRegular</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="560371092"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">772</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">togglePreference:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="560371092"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">773</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">togglePreference:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="117792016"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">774</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">rebuildCloud:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="842321178"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">780</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">showPasswordWindow:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="846612332"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">782</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">showItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="846612332"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">783</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">terminate:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="291035877"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">784</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBActionConnection" key="connection">
|
|
||||||
<string key="label">togglePreference:</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="362714849"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">787</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBOutletConnection" key="connection">
|
|
||||||
<string key="label">openAtLoginItem</string>
|
|
||||||
<reference key="source" ref="976324537"/>
|
|
||||||
<reference key="destination" ref="362714849"/>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">788</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="1048"/>
|
|
||||||
<nil key="parent"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">-2</int>
|
|
||||||
<reference key="object" ref="1021"/>
|
|
||||||
<reference key="parent" ref="0"/>
|
|
||||||
<string key="objectName">File's Owner</string>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">-1</int>
|
|
||||||
<reference key="object" ref="1014"/>
|
|
||||||
<reference key="parent" ref="0"/>
|
|
||||||
<string key="objectName">First Responder</string>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">-3</int>
|
|
||||||
<reference key="object" ref="1050"/>
|
|
||||||
<reference key="parent" ref="0"/>
|
|
||||||
<string key="objectName">Application</string>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">29</int>
|
|
||||||
<reference key="object" ref="649796088"/>
|
|
||||||
<array class="NSMutableArray" key="children"/>
|
|
||||||
<reference key="parent" ref="0"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">494</int>
|
|
||||||
<reference key="object" ref="976324537"/>
|
|
||||||
<reference key="parent" ref="0"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">548</int>
|
|
||||||
<reference key="object" ref="705910970"/>
|
|
||||||
<reference key="parent" ref="0"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">716</int>
|
|
||||||
<reference key="object" ref="764588027"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="291035877"/>
|
|
||||||
<reference ref="466252869"/>
|
|
||||||
<reference ref="229948989"/>
|
|
||||||
<reference ref="851296005"/>
|
|
||||||
<reference ref="846612332"/>
|
|
||||||
<reference ref="11982480"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="0"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">717</int>
|
|
||||||
<reference key="object" ref="291035877"/>
|
|
||||||
<reference key="parent" ref="764588027"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">718</int>
|
|
||||||
<reference key="object" ref="466252869"/>
|
|
||||||
<reference key="parent" ref="764588027"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">719</int>
|
|
||||||
<reference key="object" ref="846612332"/>
|
|
||||||
<reference key="parent" ref="764588027"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">720</int>
|
|
||||||
<reference key="object" ref="229948989"/>
|
|
||||||
<reference key="parent" ref="764588027"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">739</int>
|
|
||||||
<reference key="object" ref="851296005"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="800575174"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="764588027"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">742</int>
|
|
||||||
<reference key="object" ref="800575174"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="14397049"/>
|
|
||||||
<reference ref="290760748"/>
|
|
||||||
<reference ref="907921953"/>
|
|
||||||
<reference ref="461686112"/>
|
|
||||||
<reference ref="110488020"/>
|
|
||||||
<reference ref="123831322"/>
|
|
||||||
<reference ref="123543264"/>
|
|
||||||
<reference ref="939693094"/>
|
|
||||||
<reference ref="409463580"/>
|
|
||||||
<reference ref="362714849"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="851296005"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">743</int>
|
|
||||||
<reference key="object" ref="14397049"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">745</int>
|
|
||||||
<reference key="object" ref="907921953"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">744</int>
|
|
||||||
<reference key="object" ref="290760748"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">746</int>
|
|
||||||
<reference key="object" ref="461686112"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">747</int>
|
|
||||||
<reference key="object" ref="110488020"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">748</int>
|
|
||||||
<reference key="object" ref="123831322"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">755</int>
|
|
||||||
<reference key="object" ref="11982480"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="934187555"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="764588027"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">756</int>
|
|
||||||
<reference key="object" ref="934187555"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="576787569"/>
|
|
||||||
<reference ref="925131766"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="11982480"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">757</int>
|
|
||||||
<reference key="object" ref="576787569"/>
|
|
||||||
<reference key="parent" ref="934187555"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">759</int>
|
|
||||||
<reference key="object" ref="925131766"/>
|
|
||||||
<reference key="parent" ref="934187555"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">765</int>
|
|
||||||
<reference key="object" ref="123543264"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="293904698"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">766</int>
|
|
||||||
<reference key="object" ref="293904698"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="560371092"/>
|
|
||||||
<reference ref="117792016"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="123543264"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">767</int>
|
|
||||||
<reference key="object" ref="560371092"/>
|
|
||||||
<reference key="parent" ref="293904698"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">768</int>
|
|
||||||
<reference key="object" ref="117792016"/>
|
|
||||||
<reference key="parent" ref="293904698"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">776</int>
|
|
||||||
<reference key="object" ref="939693094"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="534220172"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">777</int>
|
|
||||||
<reference key="object" ref="534220172"/>
|
|
||||||
<array class="NSMutableArray" key="children">
|
|
||||||
<reference ref="842321178"/>
|
|
||||||
<reference ref="946018575"/>
|
|
||||||
</array>
|
|
||||||
<reference key="parent" ref="939693094"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">778</int>
|
|
||||||
<reference key="object" ref="842321178"/>
|
|
||||||
<reference key="parent" ref="534220172"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">779</int>
|
|
||||||
<reference key="object" ref="946018575"/>
|
|
||||||
<reference key="parent" ref="534220172"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">785</int>
|
|
||||||
<reference key="object" ref="362714849"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
<object class="IBObjectRecord">
|
|
||||||
<int key="objectID">786</int>
|
|
||||||
<reference key="object" ref="409463580"/>
|
|
||||||
<reference key="parent" ref="800575174"/>
|
|
||||||
</object>
|
|
||||||
</array>
|
|
||||||
</object>
|
|
||||||
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
|
||||||
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="494.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="548.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="716.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="717.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="718.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="719.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="720.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="739.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="742.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="743.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="744.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="745.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="746.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="747.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="748.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="755.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="756.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<object class="NSMutableDictionary" key="757.IBAttributePlaceholdersKey">
|
|
||||||
<string key="NS.key.0">ToolTip</string>
|
|
||||||
<object class="IBToolTipAttribute" key="NS.object.0">
|
|
||||||
<string key="name">ToolTip</string>
|
|
||||||
<reference key="object" ref="576787569"/>
|
|
||||||
<string key="toolTip">Creating users is not yet supported. Please use the iOS app with iCloud enabled to create users and sites.</string>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<string key="757.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="759.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="765.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="766.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="767.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="768.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="776.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="777.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="778.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="779.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="785.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string key="786.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
</dictionary>
|
|
||||||
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
|
|
||||||
<nil key="activeLocalization"/>
|
|
||||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
|
||||||
<nil key="sourceID"/>
|
|
||||||
<int key="maxID">788</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
|
||||||
<int key="IBDocument.localizationMode">0</int>
|
|
||||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
|
||||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
|
||||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
|
||||||
<integer value="1070" key="NS.object.0"/>
|
|
||||||
</object>
|
|
||||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
|
||||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
|
||||||
<dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
|
|
||||||
<string key="NSMenuCheckmark">{11, 11}</string>
|
|
||||||
<string key="NSMenuMixedState">{10, 3}</string>
|
|
||||||
</dictionary>
|
|
||||||
<bool key="IBDocument.UseAutolayout">YES</bool>
|
|
||||||
</data>
|
|
||||||
</archive>
|
|
||||||
23
MasterPassword/ObjC/iOS/MPAppSettingsViewController.h
Normal file
23
MasterPassword/ObjC/iOS/MPAppSettingsViewController.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAppSettingsViewController.h
|
||||||
|
// MPAppSettingsViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-18.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "IASKAppSettingsViewController.h"
|
||||||
|
|
||||||
|
@interface MPAppSettingsViewController : IASKAppSettingsViewController
|
||||||
|
@end
|
||||||
63
MasterPassword/ObjC/iOS/MPAppSettingsViewController.m
Normal file
63
MasterPassword/ObjC/iOS/MPAppSettingsViewController.m
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAppSettingsViewController.h
|
||||||
|
// MPAppSettingsViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-18.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPAppSettingsViewController.h"
|
||||||
|
#import "UIColor+Expanded.h"
|
||||||
|
|
||||||
|
@interface MPTableView:UITableView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPTableView
|
||||||
|
|
||||||
|
- (void)layoutSubviews {
|
||||||
|
|
||||||
|
[super layoutSubviews];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContentInset:(UIEdgeInsets)contentInset {
|
||||||
|
|
||||||
|
[super setContentInset:contentInset];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPAppSettingsViewController {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
|
||||||
|
self.tableView.contentInset = UIEdgeInsetsMake( 64, 0, 49, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||||
|
cell.backgroundColor = [UIColor clearColor];
|
||||||
|
cell.textLabel.textColor = [UIColor whiteColor];
|
||||||
|
|
||||||
|
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
|
||||||
|
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
|
||||||
|
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRGBAHex:0x78DDFB33];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
47
MasterPassword/ObjC/iOS/MPAvatarCell.h
Normal file
47
MasterPassword/ObjC/iOS/MPAvatarCell.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAvatarCell.h
|
||||||
|
// MPAvatarCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-11.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPEntities.h"
|
||||||
|
@class MPAvatarCell;
|
||||||
|
|
||||||
|
/* Avatar with a "+" symbol. */
|
||||||
|
extern const long MPAvatarAdd;
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSUInteger, MPAvatarMode) {
|
||||||
|
MPAvatarModeLowered,
|
||||||
|
MPAvatarModeRaisedButInactive,
|
||||||
|
MPAvatarModeRaisedAndActive,
|
||||||
|
MPAvatarModeRaisedAndHidden,
|
||||||
|
MPAvatarModeRaisedAndMinimized,
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface MPAvatarCell : UICollectionViewCell
|
||||||
|
@property (copy, nonatomic) NSString *name;
|
||||||
|
@property (assign, nonatomic) long avatar;
|
||||||
|
@property (assign, nonatomic) MPAvatarMode mode;
|
||||||
|
@property (assign, nonatomic) CGFloat visibility;
|
||||||
|
@property (assign, nonatomic) BOOL spinnerActive;
|
||||||
|
@property (assign, nonatomic, readonly) BOOL newUser;
|
||||||
|
|
||||||
|
+ (NSString *)reuseIdentifier;
|
||||||
|
|
||||||
|
- (void)setVisibility:(CGFloat)visibility animated:(BOOL)animated;
|
||||||
|
- (void)setMode:(MPAvatarMode)mode animated:(BOOL)animated;
|
||||||
|
|
||||||
|
@end
|
||||||
287
MasterPassword/ObjC/iOS/MPAvatarCell.m
Normal file
287
MasterPassword/ObjC/iOS/MPAvatarCell.m
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAvatarCell.h
|
||||||
|
// MPAvatarCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-11.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPAvatarCell.h"
|
||||||
|
#import "MPPasswordLargeCell.h"
|
||||||
|
|
||||||
|
const long MPAvatarAdd = 10000;
|
||||||
|
|
||||||
|
@interface MPAvatarCell()
|
||||||
|
|
||||||
|
@property(strong, nonatomic) IBOutlet UIImageView *avatarImageView;
|
||||||
|
@property(strong, nonatomic) IBOutlet UILabel *nameLabel;
|
||||||
|
@property(strong, nonatomic) IBOutlet UIView *nameContainer;
|
||||||
|
@property(strong, nonatomic) IBOutlet UIImageView *spinner;
|
||||||
|
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *nameToCenterConstraint;
|
||||||
|
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarSizeConstraint;
|
||||||
|
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarToTopConstraint;
|
||||||
|
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarRaisedConstraint;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPAvatarCell {
|
||||||
|
CAAnimationGroup *_targetedShadowAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)reuseIdentifier {
|
||||||
|
|
||||||
|
return NSStringFromClass( self );
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Life cycle
|
||||||
|
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
self.alpha = 0;
|
||||||
|
|
||||||
|
self.nameContainer.layer.cornerRadius = 5;
|
||||||
|
|
||||||
|
self.avatarImageView.hidden = NO;
|
||||||
|
self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.size.height / 2;
|
||||||
|
self.avatarImageView.layer.masksToBounds = NO;
|
||||||
|
self.avatarImageView.backgroundColor = [UIColor clearColor];
|
||||||
|
|
||||||
|
[self observeKeyPath:@"selected" withBlock:^(id from, id to, NSKeyValueChange cause, id _self) {
|
||||||
|
[_self updateAnimated:YES];
|
||||||
|
}];
|
||||||
|
[self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, id _self) {
|
||||||
|
[_self updateAnimated:YES];
|
||||||
|
}];
|
||||||
|
|
||||||
|
CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
|
||||||
|
toShadowOpacityAnimation.toValue = @0.2f;
|
||||||
|
toShadowOpacityAnimation.duration = 0.5f;
|
||||||
|
|
||||||
|
CABasicAnimation *pulseShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
|
||||||
|
pulseShadowOpacityAnimation.fromValue = @0.2f;
|
||||||
|
pulseShadowOpacityAnimation.toValue = @0.6f;
|
||||||
|
pulseShadowOpacityAnimation.beginTime = 0.5f;
|
||||||
|
pulseShadowOpacityAnimation.duration = 2.0f;
|
||||||
|
pulseShadowOpacityAnimation.autoreverses = YES;
|
||||||
|
pulseShadowOpacityAnimation.repeatCount = MAXFLOAT;
|
||||||
|
|
||||||
|
_targetedShadowAnimation = [CAAnimationGroup new];
|
||||||
|
_targetedShadowAnimation.animations = @[ toShadowOpacityAnimation, pulseShadowOpacityAnimation ];
|
||||||
|
_targetedShadowAnimation.duration = MAXFLOAT;
|
||||||
|
self.avatarImageView.layer.shadowColor = [UIColor whiteColor].CGColor;
|
||||||
|
self.avatarImageView.layer.shadowOffset = CGSizeZero;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForReuse {
|
||||||
|
|
||||||
|
[super prepareForReuse];
|
||||||
|
|
||||||
|
_newUser = NO;
|
||||||
|
[self setVisibility:0 animated:NO];
|
||||||
|
[self setMode:MPAvatarModeLowered animated:NO];
|
||||||
|
[self setSpinnerActive:NO animated:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
|
||||||
|
[self removeKeyPathObservers];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (void)setAvatar:(long)avatar {
|
||||||
|
|
||||||
|
_avatar = avatar == MPAvatarAdd? MPAvatarAdd: (avatar + MPAvatarCount) % MPAvatarCount;
|
||||||
|
|
||||||
|
if (_avatar == MPAvatarAdd) {
|
||||||
|
self.avatarImageView.image = [UIImage imageNamed:@"avatar-add"];
|
||||||
|
self.name = strl( @"New User" );
|
||||||
|
_newUser = YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
self.avatarImageView.image = [UIImage imageNamed:strf( @"avatar-%ld", _avatar )];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)name {
|
||||||
|
|
||||||
|
return self.nameLabel.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setName:(NSString *)name {
|
||||||
|
|
||||||
|
self.nameLabel.text = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setVisibility:(CGFloat)visibility {
|
||||||
|
|
||||||
|
[self setVisibility:visibility animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setVisibility:(CGFloat)visibility animated:(BOOL)animated {
|
||||||
|
|
||||||
|
_visibility = visibility;
|
||||||
|
|
||||||
|
[self updateAnimated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlighted:(BOOL)highlighted {
|
||||||
|
|
||||||
|
super.highlighted = highlighted;
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.1f animations:^{
|
||||||
|
self.avatarImageView.transform = highlighted? CGAffineTransformMakeScale( 1.1f, 1.1f ): CGAffineTransformIdentity;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMode:(MPAvatarMode)mode {
|
||||||
|
|
||||||
|
[self setMode:mode animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMode:(MPAvatarMode)mode animated:(BOOL)animated {
|
||||||
|
|
||||||
|
_mode = mode;
|
||||||
|
|
||||||
|
[self updateAnimated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSpinnerActive:(BOOL)spinnerActive {
|
||||||
|
|
||||||
|
[self setSpinnerActive:spinnerActive animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSpinnerActive:(BOOL)spinnerActive animated:(BOOL)animated {
|
||||||
|
|
||||||
|
if (_spinnerActive == spinnerActive)
|
||||||
|
return;
|
||||||
|
_spinnerActive = spinnerActive;
|
||||||
|
|
||||||
|
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
|
||||||
|
rotate.toValue = [NSNumber numberWithDouble:2 * M_PI];
|
||||||
|
rotate.duration = 5.0;
|
||||||
|
|
||||||
|
if (spinnerActive) {
|
||||||
|
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
|
||||||
|
rotate.fromValue = @0.0;
|
||||||
|
rotate.repeatCount = MAXFLOAT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
|
||||||
|
rotate.repeatCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.spinner.layer removeAnimationForKey:@"rotation"];
|
||||||
|
[self.spinner.layer addAnimation:rotate forKey:@"rotation"];
|
||||||
|
|
||||||
|
[self updateAnimated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (void)updateAnimated:(BOOL)animated {
|
||||||
|
|
||||||
|
[UIView animateWithDuration:animated? 0.2f: 0 animations:^{
|
||||||
|
self.avatarImageView.transform = CGAffineTransformIdentity;
|
||||||
|
}];
|
||||||
|
[UIView animateWithDuration:animated? 0.3f: 0 delay:0 options:UIViewAnimationOptionOverrideInheritedDuration animations:^{
|
||||||
|
self.alpha = 1;
|
||||||
|
|
||||||
|
if (self.newUser) {
|
||||||
|
if (self.mode == MPAvatarModeLowered)
|
||||||
|
self.avatar = MPAvatarAdd;
|
||||||
|
else if (self.avatar == MPAvatarAdd)
|
||||||
|
self.avatar = arc4random() % MPAvatarCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (self.mode) {
|
||||||
|
|
||||||
|
case MPAvatarModeLowered: {
|
||||||
|
|
||||||
|
self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
|
||||||
|
self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.nameToCenterConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.nameContainer.alpha = self.visibility;
|
||||||
|
self.nameContainer.backgroundColor = [UIColor clearColor];
|
||||||
|
self.avatarImageView.alpha = self.visibility / 0.7f + 0.3f;
|
||||||
|
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPAvatarModeRaisedButInactive: {
|
||||||
|
self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
|
||||||
|
self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.nameToCenterConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.nameContainer.alpha = self.visibility;
|
||||||
|
self.nameContainer.backgroundColor = [UIColor clearColor];
|
||||||
|
self.avatarImageView.alpha = 0;
|
||||||
|
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPAvatarModeRaisedAndActive: {
|
||||||
|
self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
|
||||||
|
self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
self.nameContainer.alpha = self.visibility;
|
||||||
|
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||||
|
self.avatarImageView.alpha = 1;
|
||||||
|
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPAvatarModeRaisedAndHidden: {
|
||||||
|
self.avatarSizeConstraint.constant = self.avatarImageView.image.size.height;
|
||||||
|
self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
self.avatarToTopConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
self.nameContainer.alpha = 0;
|
||||||
|
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||||
|
self.avatarImageView.alpha = 0;
|
||||||
|
self.avatarImageView.layer.shadowRadius = 15 * self.visibility * self.visibility;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPAvatarModeRaisedAndMinimized: {
|
||||||
|
self.avatarSizeConstraint.constant = 36;
|
||||||
|
self.avatarRaisedConstraint.priority = UILayoutPriorityDefaultLow;
|
||||||
|
self.avatarToTopConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
self.nameToCenterConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
self.nameContainer.alpha = 0;
|
||||||
|
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||||
|
self.avatarImageView.alpha = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self.avatarSizeConstraint apply];
|
||||||
|
[self.avatarRaisedConstraint apply];
|
||||||
|
[self.avatarToTopConstraint apply];
|
||||||
|
[self.nameToCenterConstraint apply];
|
||||||
|
|
||||||
|
// Avatar minimized.
|
||||||
|
if (self.mode == MPAvatarModeRaisedAndMinimized)
|
||||||
|
[self.avatarImageView.layer removeAllAnimations];
|
||||||
|
else if (![self.avatarImageView.layer animationForKey:@"targetedShadow"])
|
||||||
|
[self.avatarImageView.layer addAnimation:_targetedShadowAnimation forKey:@"targetedShadow"];
|
||||||
|
|
||||||
|
// Avatar selection and spinner.
|
||||||
|
if (self.mode != MPAvatarModeRaisedAndMinimized && (self.selected || self.highlighted) && !self.spinnerActive)
|
||||||
|
self.avatarImageView.backgroundColor = self.avatarImageView.tintColor;
|
||||||
|
else
|
||||||
|
self.avatarImageView.backgroundColor = [UIColor clearColor];
|
||||||
|
self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.size.height / 2;
|
||||||
|
self.spinner.alpha = self.spinnerActive? 1: 0;
|
||||||
|
} completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
23
MasterPassword/ObjC/iOS/MPCell.h
Normal file
23
MasterPassword/ObjC/iOS/MPCell.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCell.h
|
||||||
|
// MPCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-27.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface MPCell : UICollectionViewCell
|
||||||
|
|
||||||
|
@end
|
||||||
24
MasterPassword/ObjC/iOS/MPCell.m
Normal file
24
MasterPassword/ObjC/iOS/MPCell.m
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCell.h
|
||||||
|
// MPCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-27.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPCell.h"
|
||||||
|
|
||||||
|
@implementation MPCell {
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
37
MasterPassword/ObjC/iOS/MPCoachmarkViewController.h
Normal file
37
MasterPassword/ObjC/iOS/MPCoachmarkViewController.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCoachmarkViewController.h
|
||||||
|
// MPCoachmarkViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-22.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface MPCoachmark : NSObject
|
||||||
|
|
||||||
|
@property(nonatomic, strong) Class coachedClass;
|
||||||
|
@property(nonatomic) int coachedVersion;
|
||||||
|
@property(nonatomic) BOOL coached;
|
||||||
|
|
||||||
|
+ (instancetype)coachmarkForClass:(Class)class version:(NSInteger)version;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MPCoachmarkViewController : UIViewController
|
||||||
|
|
||||||
|
@property(nonatomic, strong) MPCoachmark *coachmark;
|
||||||
|
|
||||||
|
- (IBAction)close:(id)sender;
|
||||||
|
|
||||||
|
@end
|
||||||
53
MasterPassword/ObjC/iOS/MPCoachmarkViewController.m
Normal file
53
MasterPassword/ObjC/iOS/MPCoachmarkViewController.m
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCoachmarkViewController.h
|
||||||
|
// MPCoachmarkViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-22.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPCoachmarkViewController.h"
|
||||||
|
|
||||||
|
@implementation MPCoachmarkViewController {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)close:(id)sender {
|
||||||
|
|
||||||
|
[self dismissViewControllerAnimated:YES completion:^{
|
||||||
|
self.coachmark.coached = YES;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPCoachmark
|
||||||
|
|
||||||
|
+ (instancetype)coachmarkForClass:(Class)coachedClass version:(NSInteger)coachedVersion {
|
||||||
|
MPCoachmark *coachmark = [self new];
|
||||||
|
coachmark.coachedClass = coachedClass;
|
||||||
|
coachmark.coachedVersion = coachedVersion;
|
||||||
|
|
||||||
|
return coachmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)coached {
|
||||||
|
|
||||||
|
return [[NSUserDefaults standardUserDefaults] boolForKey:strf( @"%@.%d.coached", self.coachedClass, self.coachedVersion )];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setCoached:(BOOL)coached {
|
||||||
|
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:coached forKey:strf( @"%@.%d.coached", self.coachedClass, self.coachedVersion )];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
29
MasterPassword/ObjC/iOS/MPCombinedViewController.h
Normal file
29
MasterPassword/ObjC/iOS/MPCombinedViewController.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCombinedViewController.h
|
||||||
|
// MPCombinedViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-08.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSUInteger, MPCombinedMode) {
|
||||||
|
MPCombinedModeUserSelection,
|
||||||
|
MPCombinedModePasswordSelection,
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface MPCombinedViewController : UIViewController
|
||||||
|
|
||||||
|
@property(assign, nonatomic) MPCombinedMode mode;
|
||||||
|
@property(strong, nonatomic) IBOutlet UIView *usersView;
|
||||||
|
|
||||||
|
@end
|
||||||
187
MasterPassword/ObjC/iOS/MPCombinedViewController.m
Normal file
187
MasterPassword/ObjC/iOS/MPCombinedViewController.m
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCombinedViewController.h
|
||||||
|
// MPCombinedViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-08.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPCombinedViewController.h"
|
||||||
|
#import "MPUsersViewController.h"
|
||||||
|
#import "MPPasswordsViewController.h"
|
||||||
|
#import "MPEmergencySegue.h"
|
||||||
|
#import "MPEmergencyViewController.h"
|
||||||
|
#import "MPPasswordsSegue.h"
|
||||||
|
|
||||||
|
@interface MPCombinedViewController()
|
||||||
|
|
||||||
|
@property(nonatomic, weak) MPUsersViewController *usersVC;
|
||||||
|
@property(nonatomic, weak) MPEmergencyViewController *emergencyVC;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPCombinedViewController {
|
||||||
|
NSArray *_notificationObservers;
|
||||||
|
MPPasswordsViewController *_passwordsVC;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
[self setMode:MPCombinedModeUserSelection animated:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
|
||||||
|
[[self navigationController] setNavigationBarHidden:YES animated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
|
||||||
|
[self registerObservers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillDisappear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewWillDisappear:animated];
|
||||||
|
|
||||||
|
[self removeObservers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
|
||||||
|
if ([segue.identifier isEqualToString:@"users"])
|
||||||
|
self.usersVC = segue.destinationViewController;
|
||||||
|
if ([segue.identifier isEqualToString:@"passwords"]) {
|
||||||
|
NSAssert([segue isKindOfClass:[MPPasswordsSegue class]], @"passwords segue should be MPPasswordsSegue: %@", segue);
|
||||||
|
NSAssert([sender isKindOfClass:[NSDictionary class]], @"sender should be dictionary: %@", sender);
|
||||||
|
NSAssert([[sender objectForKey:@"animated"] isKindOfClass:[NSNumber class]], @"sender should contain 'animated': %@", sender);
|
||||||
|
[(MPPasswordsSegue *)segue setAnimated:[sender[@"animated"] boolValue]];
|
||||||
|
UIViewController *destinationVC = segue.destinationViewController;
|
||||||
|
_passwordsVC = [destinationVC isKindOfClass:[MPPasswordsViewController class]]? (MPPasswordsViewController *)destinationVC: nil;
|
||||||
|
}
|
||||||
|
if ([segue.identifier isEqualToString:@"emergency"])
|
||||||
|
self.emergencyVC = segue.destinationViewController;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)prefersStatusBarHidden {
|
||||||
|
|
||||||
|
return self.mode == MPCombinedModeUserSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||||
|
|
||||||
|
return UIStatusBarStyleLightContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeFirstResponder {
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
|
||||||
|
|
||||||
|
if (motion == UIEventSubtypeMotionShake && !self.emergencyVC)
|
||||||
|
[self performSegueWithIdentifier:@"emergency" sender:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
|
||||||
|
fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
|
||||||
|
|
||||||
|
if ([identifier isEqualToString:@"unwind-emergency"]) {
|
||||||
|
MPEmergencySegue *segue = [[MPEmergencySegue alloc] initWithIdentifier:identifier
|
||||||
|
source:fromViewController destination:toViewController];
|
||||||
|
segue.unwind = YES;
|
||||||
|
dbg_return(segue);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_return((id)nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (void)setMode:(MPCombinedMode)mode {
|
||||||
|
|
||||||
|
[self setMode:mode animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMode:(MPCombinedMode)mode animated:(BOOL)animated {
|
||||||
|
|
||||||
|
if (_mode == mode && animated)
|
||||||
|
return;
|
||||||
|
_mode = mode;
|
||||||
|
|
||||||
|
[self setNeedsStatusBarAppearanceUpdate];
|
||||||
|
[self becomeFirstResponder];
|
||||||
|
[self.usersVC setNeedsStatusBarAppearanceUpdate];
|
||||||
|
[self.usersVC.view setNeedsUpdateConstraints];
|
||||||
|
[self.usersVC.view setNeedsLayout];
|
||||||
|
|
||||||
|
switch (self.mode) {
|
||||||
|
case MPCombinedModeUserSelection: {
|
||||||
|
self.usersView.userInteractionEnabled = YES;
|
||||||
|
[self.usersVC setActive:YES animated:animated];
|
||||||
|
if (_passwordsVC) {
|
||||||
|
MPPasswordsSegue *segue = [[MPPasswordsSegue alloc] initWithIdentifier:@"passwords" source:_passwordsVC destination:self];
|
||||||
|
[self prepareForSegue:segue sender:@{ @"animated" : @(animated) }];
|
||||||
|
[segue perform];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPCombinedModePasswordSelection: {
|
||||||
|
self.usersView.userInteractionEnabled = NO;
|
||||||
|
[self.usersVC setActive:NO animated:animated];
|
||||||
|
[self performSegueWithIdentifier:@"passwords" sender:@{ @"animated" : @(animated) }];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (void)registerObservers {
|
||||||
|
|
||||||
|
if ([_notificationObservers count])
|
||||||
|
return;
|
||||||
|
|
||||||
|
Weakify(self);
|
||||||
|
_notificationObservers = @[
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:MPSignedInNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
Strongify(self);
|
||||||
|
|
||||||
|
[self setMode:MPCombinedModePasswordSelection];
|
||||||
|
}],
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:MPSignedOutNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
Strongify(self);
|
||||||
|
|
||||||
|
[self setMode:MPCombinedModeUserSelection animated:[note.userInfo[@"animated"] boolValue]];
|
||||||
|
}],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObservers {
|
||||||
|
|
||||||
|
for (id observer in _notificationObservers)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:observer];
|
||||||
|
_notificationObservers = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -66,10 +66,11 @@
|
|||||||
|
|
||||||
__weak MPElementListAllViewController *wSelf = self;
|
__weak MPElementListAllViewController *wSelf = self;
|
||||||
[[MPiOSAppDelegate get] addElementNamed:[alert textFieldAtIndex:0].text completion:^(MPElementEntity *element) {
|
[[MPiOSAppDelegate get] addElementNamed:[alert textFieldAtIndex:0].text completion:^(MPElementEntity *element) {
|
||||||
if (element) {
|
if (element)
|
||||||
[wSelf.delegate didSelectElement:element];
|
PearlMainQueue( ^{
|
||||||
[wSelf close:nil];
|
[wSelf.delegate didSelectElement:element];
|
||||||
}
|
[wSelf close:nil];
|
||||||
|
} );
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
||||||
@@ -85,7 +86,7 @@
|
|||||||
if (buttonIndex == [alert cancelButtonIndex])
|
if (buttonIndex == [alert cancelButtonIndex])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PearlOverlay *activity = [PearlOverlay showOverlayWithTitle:@"Upgrading Sites"];
|
PearlOverlay *activity = [PearlOverlay showProgressOverlayWithTitle:@"Upgrading Sites"];
|
||||||
[self performUpgradeAllWithCompletion:^(BOOL success, NSDictionary *changes) {
|
[self performUpgradeAllWithCompletion:^(BOOL success, NSDictionary *changes) {
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
[self showUpgradeChanges:changes];
|
[self showUpgradeChanges:changes];
|
||||||
@@ -149,7 +150,7 @@
|
|||||||
if (buttonIndex == [alert cancelButtonIndex])
|
if (buttonIndex == [alert cancelButtonIndex])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[PearlEMail sendEMailTo:nil subject:@"[Master Password] Upgrade Changes" body:formattedChanges];
|
[PearlEMail sendEMailTo:nil fromVC:self subject:@"[Master Password] Upgrade Changes" body:formattedChanges];
|
||||||
} cancelTitle:@"Don't Email" otherTitles:@"Send Email", nil];
|
} cancelTitle:@"Don't Email" otherTitles:@"Send Email", nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
|
|
||||||
UISearchBar *searchBar = self.searchDisplayController.searchBar;
|
UISearchBar *searchBar = self.searchDisplayController.searchBar;
|
||||||
CGRect searchBarFrame = searchBar.frame;
|
CGRect searchBarFrame = searchBar.frame;
|
||||||
[searchBar.superview enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
[searchBar.superview enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
||||||
|
|
||||||
if ([subview isKindOfClass:[UIControl class]] &&
|
if ([subview isKindOfClass:[UIControl class]] &&
|
||||||
CGPointEqualToPoint(
|
CGPointEqualToPoint(
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
|
|
||||||
*stop = YES;
|
*stop = YES;
|
||||||
}
|
}
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)newSiteSectionNeeded {
|
- (BOOL)newSiteSectionNeeded {
|
||||||
@@ -193,7 +193,7 @@
|
|||||||
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
NSString *query = [self.searchDisplayController.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
cell.textLabel.text = query;
|
cell.textLabel.text = query;
|
||||||
cell.detailTextLabel.text = PearlString( @"New site: %@",
|
cell.detailTextLabel.text = PearlString( @"New site: %@",
|
||||||
[MPAlgorithmDefault shortNameOfType:[[[MPiOSAppDelegate get] activeUserForMainThread] defaultType]] );
|
[MPAlgorithmDefault shortNameOfType:[[MPiOSAppDelegate get] activeUserForMainThread].defaultType] );
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
@@ -220,7 +220,9 @@
|
|||||||
__weak MPElementListController *wSelf = self;
|
__weak MPElementListController *wSelf = self;
|
||||||
[[MPiOSAppDelegate get] addElementNamed:siteName completion:^(MPElementEntity *element) {
|
[[MPiOSAppDelegate get] addElementNamed:siteName completion:^(MPElementEntity *element) {
|
||||||
if (element)
|
if (element)
|
||||||
[wSelf.delegate didSelectElement:element];
|
PearlMainQueue( ^{
|
||||||
|
[wSelf.delegate didSelectElement:element];
|
||||||
|
} );
|
||||||
}];
|
}];
|
||||||
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
|
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
|
||||||
}
|
}
|
||||||
|
|||||||
24
MasterPassword/ObjC/iOS/MPEmergencySegue.h
Normal file
24
MasterPassword/ObjC/iOS/MPEmergencySegue.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPEmergencySegue.h
|
||||||
|
// MPEmergencySegue
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-09.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface MPEmergencySegue : UIStoryboardSegue
|
||||||
|
|
||||||
|
@property(nonatomic) BOOL unwind;
|
||||||
|
@end
|
||||||
57
MasterPassword/ObjC/iOS/MPEmergencySegue.m
Normal file
57
MasterPassword/ObjC/iOS/MPEmergencySegue.m
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPEmergencySegue.h
|
||||||
|
// MPEmergencySegue
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-09.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPEmergencySegue.h"
|
||||||
|
|
||||||
|
@implementation MPEmergencySegue {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)perform {
|
||||||
|
|
||||||
|
UIViewController *sourceViewController = self.sourceViewController;
|
||||||
|
UIViewController *destinationViewController = self.destinationViewController;
|
||||||
|
|
||||||
|
if (!self.unwind) {
|
||||||
|
// Winding
|
||||||
|
[sourceViewController addChildViewController:destinationViewController];
|
||||||
|
[sourceViewController.view addSubview:destinationViewController.view];
|
||||||
|
CGRectSetY(destinationViewController.view.bounds, sourceViewController.view.frame.size.height);
|
||||||
|
[UIView transitionWithView:sourceViewController.view duration:0.3f options:UIViewAnimationOptionAllowAnimatedContent
|
||||||
|
animations:^{
|
||||||
|
CGRectSetY(destinationViewController.view.bounds, 0);
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
if (finished)
|
||||||
|
[destinationViewController didMoveToParentViewController:sourceViewController];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Unwinding
|
||||||
|
[sourceViewController willMoveToParentViewController:nil];
|
||||||
|
[UIView transitionWithView:sourceViewController.parentViewController.view duration:0.3f options:UIViewAnimationOptionAllowAnimatedContent
|
||||||
|
animations:^{
|
||||||
|
CGRectSetY(sourceViewController.view.bounds, sourceViewController.parentViewController.view.frame.size.height);
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
if (finished) {
|
||||||
|
[sourceViewController.view removeFromSuperview];
|
||||||
|
[sourceViewController removeFromParentViewController];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
38
MasterPassword/ObjC/iOS/MPEmergencyViewController.h
Normal file
38
MasterPassword/ObjC/iOS/MPEmergencyViewController.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCombinedViewController.h
|
||||||
|
// MPCombinedViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-08.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "LLGitTip.h"
|
||||||
|
|
||||||
|
@interface MPEmergencyViewController : UIViewController <UITextFieldDelegate>
|
||||||
|
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *dialogView;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *containerView;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITextField *userNameField;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITextField *masterPasswordField;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITextField *siteField;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIStepper *counterStepper;
|
||||||
|
@property(weak, nonatomic) IBOutlet UISegmentedControl *typeControl;
|
||||||
|
@property(weak, nonatomic) IBOutlet UILabel *counterLabel;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *activity;
|
||||||
|
@property(weak, nonatomic) IBOutlet UILabel *passwordLabel;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *tipContainer;
|
||||||
|
|
||||||
|
- (IBAction)controlChanged:(UIControl *)control;
|
||||||
|
- (IBAction)copyPassword:(UITapGestureRecognizer *)recognizer;
|
||||||
|
|
||||||
|
@end
|
||||||
202
MasterPassword/ObjC/iOS/MPEmergencyViewController.m
Normal file
202
MasterPassword/ObjC/iOS/MPEmergencyViewController.m
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCombinedViewController.h
|
||||||
|
// MPCombinedViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-08.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPEmergencyViewController.h"
|
||||||
|
#import "MPEntities.h"
|
||||||
|
|
||||||
|
@implementation MPEmergencyViewController {
|
||||||
|
MPKey *_key;
|
||||||
|
NSOperationQueue *_emergencyKeyQueue;
|
||||||
|
NSOperationQueue *_emergencyPasswordQueue;
|
||||||
|
NSArray *_notificationObservers;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
[_emergencyKeyQueue = [NSOperationQueue new] setMaxConcurrentOperationCount:1];
|
||||||
|
[_emergencyPasswordQueue = [NSOperationQueue new] setMaxConcurrentOperationCount:1];
|
||||||
|
|
||||||
|
self.view.backgroundColor = [UIColor clearColor];
|
||||||
|
self.dialogView.layer.cornerRadius = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
|
||||||
|
[self reset];
|
||||||
|
[self registerObservers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidDisappear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewDidDisappear:animated];
|
||||||
|
|
||||||
|
[self removeObservers];
|
||||||
|
[self reset];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
|
||||||
|
|
||||||
|
return [self respondsToSelector:action];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (IBAction)unwindToCombined:(UIStoryboardSegue *)sender {
|
||||||
|
|
||||||
|
dbg(@"unwindToCombined:%@", sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UITextFieldDelegate
|
||||||
|
|
||||||
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||||
|
|
||||||
|
[textField resignFirstResponder];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (IBAction)controlChanged:(UIControl *)control {
|
||||||
|
|
||||||
|
if (control == self.userNameField || control == self.masterPasswordField)
|
||||||
|
[self updateKey];
|
||||||
|
else
|
||||||
|
[self updatePassword];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)copyPassword:(UITapGestureRecognizer *)recognizer {
|
||||||
|
|
||||||
|
if (recognizer.state == UIGestureRecognizerStateEnded) {
|
||||||
|
NSString *sitePassword = self.passwordLabel.text;
|
||||||
|
if ([sitePassword length]) {
|
||||||
|
[UIPasteboard generalPasteboard].string = sitePassword;
|
||||||
|
[UIView animateWithDuration:0.3f animations:^{
|
||||||
|
self.tipContainer.alpha = 1;
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
if (finished)
|
||||||
|
PearlMainQueueAfter( 3, ^{
|
||||||
|
self.tipContainer.alpha = 0;
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (void)updateKey {
|
||||||
|
|
||||||
|
NSString *userName = self.userNameField.text;
|
||||||
|
NSString *masterPassword = self.masterPasswordField.text;
|
||||||
|
|
||||||
|
self.passwordLabel.text = nil;
|
||||||
|
[self.activity startAnimating];
|
||||||
|
[_emergencyKeyQueue cancelAllOperations];
|
||||||
|
[_emergencyKeyQueue addOperationWithBlock:^{
|
||||||
|
if ([masterPassword length] && [userName length])
|
||||||
|
_key = [MPAlgorithmDefault keyForPassword:masterPassword ofUserNamed:userName];
|
||||||
|
else
|
||||||
|
_key = nil;
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self updatePassword];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updatePassword {
|
||||||
|
|
||||||
|
NSString *siteName = self.siteField.text;
|
||||||
|
MPElementType siteType = [self siteType];
|
||||||
|
NSUInteger siteCounter = (NSUInteger)self.counterStepper.value;
|
||||||
|
self.counterLabel.text = strf( @"%d", siteCounter );
|
||||||
|
|
||||||
|
self.passwordLabel.text = nil;
|
||||||
|
[self.activity startAnimating];
|
||||||
|
[_emergencyPasswordQueue cancelAllOperations];
|
||||||
|
[_emergencyPasswordQueue addOperationWithBlock:^{
|
||||||
|
NSString *sitePassword = nil;
|
||||||
|
if (_key && [siteName length])
|
||||||
|
sitePassword = [MPAlgorithmDefault generateContentNamed:siteName ofType:siteType withCounter:siteCounter usingKey:_key];
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self.activity stopAnimating];
|
||||||
|
self.passwordLabel.text = sitePassword;
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (enum MPElementType)siteType {
|
||||||
|
|
||||||
|
switch (self.typeControl.selectedSegmentIndex) {
|
||||||
|
case 0:
|
||||||
|
return MPElementTypeGeneratedMaximum;
|
||||||
|
case 1:
|
||||||
|
return MPElementTypeGeneratedLong;
|
||||||
|
case 2:
|
||||||
|
return MPElementTypeGeneratedMedium;
|
||||||
|
case 3:
|
||||||
|
return MPElementTypeGeneratedBasic;
|
||||||
|
case 4:
|
||||||
|
return MPElementTypeGeneratedShort;
|
||||||
|
case 5:
|
||||||
|
return MPElementTypeGeneratedPIN;
|
||||||
|
default:
|
||||||
|
Throw(@"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reset {
|
||||||
|
|
||||||
|
self.userNameField.text = nil;
|
||||||
|
self.masterPasswordField.text = nil;
|
||||||
|
self.siteField.text = nil;
|
||||||
|
self.counterStepper.value = 1;
|
||||||
|
self.typeControl.selectedSegmentIndex = 1;
|
||||||
|
[self updateKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registerObservers {
|
||||||
|
|
||||||
|
if ([_notificationObservers count])
|
||||||
|
return;
|
||||||
|
|
||||||
|
Weakify(self);
|
||||||
|
_notificationObservers = @[
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:UIApplicationWillResignActiveNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
Strongify(self);
|
||||||
|
|
||||||
|
[self performSegueWithIdentifier:@"unwind-emergency" sender:self];
|
||||||
|
}],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObservers {
|
||||||
|
|
||||||
|
for (id observer in _notificationObservers)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:observer];
|
||||||
|
_notificationObservers = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
@interface MPGuideViewController : UIViewController<UIScrollViewDelegate>
|
@interface MPGuideViewController : UIViewController<UIScrollViewDelegate>
|
||||||
|
|
||||||
|
@property(weak, nonatomic) IBOutlet UISearchBar *searchBar;
|
||||||
@property(weak, nonatomic) IBOutlet UIView *siteNameTip;
|
@property(weak, nonatomic) IBOutlet UIView *siteNameTip;
|
||||||
@property(weak, nonatomic) IBOutlet UIView *contentTip;
|
@property(weak, nonatomic) IBOutlet UIView *contentTip;
|
||||||
@property(weak, nonatomic) IBOutlet UILabel *contentTipText;
|
@property(weak, nonatomic) IBOutlet UILabel *contentTipText;
|
||||||
|
|||||||
@@ -64,6 +64,7 @@
|
|||||||
// Via setup
|
// Via setup
|
||||||
self.smallPlayButton.hidden = YES;
|
self.smallPlayButton.hidden = YES;
|
||||||
|
|
||||||
|
self.searchBar.text = nil;
|
||||||
self.siteNameTip.alpha = 0;
|
self.siteNameTip.alpha = 0;
|
||||||
self.content.alpha = 0;
|
self.content.alpha = 0;
|
||||||
self.content.frame = CGRectSetHeight( self.content.frame, 180 );
|
self.content.frame = CGRectSetHeight( self.content.frame, 180 );
|
||||||
@@ -81,6 +82,7 @@
|
|||||||
// Via segue
|
// Via segue
|
||||||
self.largePlayButton.hidden = YES;
|
self.largePlayButton.hidden = YES;
|
||||||
|
|
||||||
|
self.searchBar.text = @"gmail.com";
|
||||||
self.siteNameTip.alpha = 1;
|
self.siteNameTip.alpha = 1;
|
||||||
self.content.alpha = 1;
|
self.content.alpha = 1;
|
||||||
self.content.frame = CGRectSetHeight( self.content.frame, 231 );
|
self.content.frame = CGRectSetHeight( self.content.frame, 231 );
|
||||||
@@ -147,6 +149,7 @@
|
|||||||
|
|
||||||
if (self.currentTick < 5) {
|
if (self.currentTick < 5) {
|
||||||
[UIView animateWithDuration:0.5 animations:^{
|
[UIView animateWithDuration:0.5 animations:^{
|
||||||
|
self.searchBar.text = nil;
|
||||||
self.siteNameTip.alpha = 1;
|
self.siteNameTip.alpha = 1;
|
||||||
self.content.alpha = 0;
|
self.content.alpha = 0;
|
||||||
self.content.frame = CGRectSetHeight( self.content.frame, 180 );
|
self.content.frame = CGRectSetHeight( self.content.frame, 180 );
|
||||||
@@ -159,6 +162,7 @@
|
|||||||
}
|
}
|
||||||
else if (self.currentTick < 10) {
|
else if (self.currentTick < 10) {
|
||||||
[UIView animateWithDuration:0.5 animations:^{
|
[UIView animateWithDuration:0.5 animations:^{
|
||||||
|
self.searchBar.text = @"gmail.com";
|
||||||
self.siteNameTip.alpha = 0;
|
self.siteNameTip.alpha = 0;
|
||||||
self.content.alpha = 1;
|
self.content.alpha = 1;
|
||||||
self.contentTip.alpha = 1;
|
self.contentTip.alpha = 1;
|
||||||
@@ -171,6 +175,7 @@
|
|||||||
}
|
}
|
||||||
else if (self.currentTick < 15) {
|
else if (self.currentTick < 15) {
|
||||||
[UIView animateWithDuration:0.5 animations:^{
|
[UIView animateWithDuration:0.5 animations:^{
|
||||||
|
self.searchBar.text = @"gmail.com";
|
||||||
self.siteNameTip.alpha = 0;
|
self.siteNameTip.alpha = 0;
|
||||||
self.content.alpha = 1;
|
self.content.alpha = 1;
|
||||||
self.contentTip.alpha = 1;
|
self.contentTip.alpha = 1;
|
||||||
@@ -185,6 +190,7 @@
|
|||||||
}
|
}
|
||||||
else if (self.currentTick < 20) {
|
else if (self.currentTick < 20) {
|
||||||
[UIView animateWithDuration:0.5 animations:^{
|
[UIView animateWithDuration:0.5 animations:^{
|
||||||
|
self.searchBar.text = @"gmail.com";
|
||||||
self.siteNameTip.alpha = 0;
|
self.siteNameTip.alpha = 0;
|
||||||
self.content.alpha = 1;
|
self.content.alpha = 1;
|
||||||
self.content.frame = CGRectSetHeight( self.content.frame, 231 );
|
self.content.frame = CGRectSetHeight( self.content.frame, 231 );
|
||||||
@@ -199,6 +205,7 @@
|
|||||||
}
|
}
|
||||||
else if (self.currentTick < 25) {
|
else if (self.currentTick < 25) {
|
||||||
[UIView animateWithDuration:0.5 animations:^{
|
[UIView animateWithDuration:0.5 animations:^{
|
||||||
|
self.searchBar.text = @"gmail.com";
|
||||||
self.siteNameTip.alpha = 0;
|
self.siteNameTip.alpha = 0;
|
||||||
self.content.alpha = 1;
|
self.content.alpha = 1;
|
||||||
self.contentTip.alpha = 0;
|
self.contentTip.alpha = 0;
|
||||||
@@ -212,6 +219,7 @@
|
|||||||
}
|
}
|
||||||
else if (self.currentTick < 30) {
|
else if (self.currentTick < 30) {
|
||||||
[UIView animateWithDuration:0.5 animations:^{
|
[UIView animateWithDuration:0.5 animations:^{
|
||||||
|
self.searchBar.text = @"gmail.com";
|
||||||
self.siteNameTip.alpha = 0;
|
self.siteNameTip.alpha = 0;
|
||||||
self.content.alpha = 1;
|
self.content.alpha = 1;
|
||||||
self.contentTip.alpha = 0;
|
self.contentTip.alpha = 0;
|
||||||
@@ -230,6 +238,7 @@
|
|||||||
self.currentTick = 0;
|
self.currentTick = 0;
|
||||||
[UIView animateWithDuration:0.5 animations:^{
|
[UIView animateWithDuration:0.5 animations:^{
|
||||||
[self.smallPlayButton setImage:[UIImage imageNamed:@"icon_play"] forState:UIControlStateNormal];
|
[self.smallPlayButton setImage:[UIImage imageNamed:@"icon_play"] forState:UIControlStateNormal];
|
||||||
|
self.searchBar.text = @"gmail.com";
|
||||||
self.siteNameTip.alpha = 1;
|
self.siteNameTip.alpha = 1;
|
||||||
self.content.alpha = 1;
|
self.content.alpha = 1;
|
||||||
self.contentTip.alpha = 1;
|
self.contentTip.alpha = 1;
|
||||||
|
|||||||
@@ -28,12 +28,12 @@
|
|||||||
|
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
self.view.backgroundColor = [UIColor clearColor];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil
|
[[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil
|
||||||
queue:nil usingBlock:
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
^(NSNotification *note) {
|
^(NSNotification *note) {
|
||||||
dispatch_async( dispatch_get_main_queue(), ^{
|
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
|
||||||
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
|
|
||||||
} );
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +41,8 @@
|
|||||||
|
|
||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
|
|
||||||
|
self.logView.contentInset = UIEdgeInsetsMake( 64, 0, 93, 0 );
|
||||||
|
|
||||||
[self refresh:nil];
|
[self refresh:nil];
|
||||||
|
|
||||||
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
|
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
|
||||||
@@ -62,7 +64,7 @@
|
|||||||
if (buttonIndex_ == alert.cancelButtonIndex)
|
if (buttonIndex_ == alert.cancelButtonIndex)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_switchCloudStoreProgress = [PearlOverlay showOverlayWithTitle:@"Enumerating Stores"];
|
_switchCloudStoreProgress = [PearlOverlay showProgressOverlayWithTitle:@"Enumerating Stores"];
|
||||||
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
|
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
|
||||||
[self switchCloudStore];
|
[self switchCloudStore];
|
||||||
} );
|
} );
|
||||||
|
|||||||
@@ -715,11 +715,6 @@
|
|||||||
[self setHelpHidden:NO animated:YES];
|
[self setHelpHidden:NO animated:YES];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: {
|
|
||||||
inf(@"Action: Guide");
|
|
||||||
[[MPiOSAppDelegate get] showGuide];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: {
|
case 2: {
|
||||||
inf(@"Action: Preferences");
|
inf(@"Action: Preferences");
|
||||||
[self performSegueWithIdentifier:@"MP_UserProfile" sender:self];
|
[self performSegueWithIdentifier:@"MP_UserProfile" sender:self];
|
||||||
@@ -776,7 +771,7 @@
|
|||||||
@"If you continue, the password for this site will change. "
|
@"If you continue, the password for this site will change. "
|
||||||
@"You will need to update your account's old password to the new one."
|
@"You will need to update your account's old password to the new one."
|
||||||
do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
|
do:^BOOL(MPElementEntity *activeElement, NSManagedObjectContext *context) {
|
||||||
_activeElementOID = [[MPiOSAppDelegate get] changeElement:activeElement inContext:context
|
_activeElementOID = [[MPiOSAppDelegate get] changeElement:activeElement saveInContext:context
|
||||||
toType:type].objectID;
|
toType:type].objectID;
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
|
|||||||
34
MasterPassword/ObjC/iOS/MPPasswordCell.h
Normal file
34
MasterPassword/ObjC/iOS/MPPasswordCell.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAvatarCell.h
|
||||||
|
// MPAvatarCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-11.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPEntities.h"
|
||||||
|
#import "MPCell.h"
|
||||||
|
|
||||||
|
@interface MPPasswordCell : MPCell
|
||||||
|
|
||||||
|
@property(strong, nonatomic) IBOutlet UILabel *nameLabel;
|
||||||
|
@property(strong, nonatomic) IBOutlet UIButton *loginButton;
|
||||||
|
|
||||||
|
/** Populate our UI to reflect the current state. */
|
||||||
|
- (void)updateAnimated:(BOOL)animated;
|
||||||
|
|
||||||
|
- (void)reloadWithElement:(MPElementEntity *)mainElement;
|
||||||
|
- (void)reloadWithTransientSite:(NSString *)siteName;
|
||||||
|
|
||||||
|
@end
|
||||||
96
MasterPassword/ObjC/iOS/MPPasswordCell.m
Normal file
96
MasterPassword/ObjC/iOS/MPPasswordCell.m
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAvatarCell.h
|
||||||
|
// MPAvatarCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-11.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordCell.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordCell
|
||||||
|
|
||||||
|
#pragma mark - Life cycle
|
||||||
|
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
self.layer.cornerRadius = 5;
|
||||||
|
self.layer.shadowOffset = CGSizeZero;
|
||||||
|
self.layer.shadowRadius = 5;
|
||||||
|
self.layer.shadowOpacity = 0;
|
||||||
|
self.layer.shadowColor = [UIColor whiteColor].CGColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForReuse {
|
||||||
|
|
||||||
|
[super prepareForReuse];
|
||||||
|
[self updateAnimated:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unblocks animations for all CALayer properties (eg. shadowOpacity)
|
||||||
|
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
|
||||||
|
|
||||||
|
id<CAAction> defaultAction = [super actionForLayer:layer forKey:event];
|
||||||
|
if (defaultAction == (id)[NSNull null] && [event isEqualToString:@"position"])
|
||||||
|
return defaultAction;
|
||||||
|
|
||||||
|
return NSNullToNil(defaultAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (void)setSelected:(BOOL)selected {
|
||||||
|
|
||||||
|
[super setSelected:selected];
|
||||||
|
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlighted:(BOOL)highlighted {
|
||||||
|
|
||||||
|
[super setHighlighted:highlighted];
|
||||||
|
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (void)updateAnimated:(BOOL)animated {
|
||||||
|
|
||||||
|
if (![NSThread isMainThread]) {
|
||||||
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||||
|
[self updateAnimated:animated];
|
||||||
|
}];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[UIView animateWithDuration:animated? 0.3f: 0 animations:^{
|
||||||
|
self.layer.shadowOpacity = self.selected? 1: self.highlighted? 0.3f: 0;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||||
|
|
||||||
|
self.nameLabel.text = mainElement.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadWithTransientSite:(NSString *)siteName {
|
||||||
|
|
||||||
|
self.nameLabel.text = strl( @"%@ - Tap to create", siteName );
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
31
MasterPassword/ObjC/iOS/MPPasswordElementCell.h
Normal file
31
MasterPassword/ObjC/iOS/MPPasswordElementCell.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordElementCell.h
|
||||||
|
// MPPasswordElementCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-03.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPPasswordCell.h"
|
||||||
|
|
||||||
|
@interface MPPasswordElementCell : MPPasswordCell
|
||||||
|
|
||||||
|
@property(nonatomic, copy) NSString *transientSite;
|
||||||
|
|
||||||
|
- (MPElementEntity *)mainElement;
|
||||||
|
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context;
|
||||||
|
- (void)setElement:(MPElementEntity *)element;
|
||||||
|
- (void)reloadData;
|
||||||
|
|
||||||
|
@end
|
||||||
95
MasterPassword/ObjC/iOS/MPPasswordElementCell.m
Normal file
95
MasterPassword/ObjC/iOS/MPPasswordElementCell.m
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordElementCell.h
|
||||||
|
// MPPasswordElementCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-03.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordElementCell.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordElementCell {
|
||||||
|
NSManagedObjectID *_elementOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForReuse {
|
||||||
|
|
||||||
|
_elementOID = nil;
|
||||||
|
_transientSite = nil;
|
||||||
|
|
||||||
|
[super prepareForReuse];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTransientSite:(NSString *)transientSite {
|
||||||
|
|
||||||
|
if ([_transientSite isEqualToString:transientSite])
|
||||||
|
return;
|
||||||
|
|
||||||
|
dbg(@"transientSite: %@ -> %@", _transientSite, transientSite);
|
||||||
|
|
||||||
|
_transientSite = transientSite;
|
||||||
|
_elementOID = nil;
|
||||||
|
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
[self reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setElement:(MPElementEntity *)element {
|
||||||
|
|
||||||
|
NSManagedObjectID *newElementOID = element.objectID;
|
||||||
|
NSAssert(!newElementOID.isTemporaryID, @"Element doesn't have a permanent objectID: %@", element);
|
||||||
|
if ([_elementOID isEqual:newElementOID])
|
||||||
|
return;
|
||||||
|
|
||||||
|
dbg(@"element: %@ -> %@", _elementOID, newElementOID);
|
||||||
|
|
||||||
|
_transientSite = nil;
|
||||||
|
_elementOID = newElementOID;
|
||||||
|
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
[self reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementEntity *)mainElement {
|
||||||
|
|
||||||
|
return [self elementInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementEntity *)elementInContext:(NSManagedObjectContext *)context {
|
||||||
|
|
||||||
|
if (!_elementOID)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
MPElementEntity *element = _elementOID? (MPElementEntity *)[context existingObjectWithID:_elementOID error:&error]: nil;
|
||||||
|
if (_elementOID && !element)
|
||||||
|
err(@"Failed to load element: %@", error);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadData {
|
||||||
|
|
||||||
|
if (self.transientSite)
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self reloadWithTransientSite:self.transientSite];
|
||||||
|
} );
|
||||||
|
else
|
||||||
|
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||||
|
[self reloadWithElement:[self elementInContext:mainContext]];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
44
MasterPassword/ObjC/iOS/MPPasswordLargeCell.h
Normal file
44
MasterPassword/ObjC/iOS/MPPasswordLargeCell.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAvatarCell.h
|
||||||
|
// MPAvatarCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-11.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPEntities.h"
|
||||||
|
#import "MPCell.h"
|
||||||
|
#import "MPPasswordCell.h"
|
||||||
|
|
||||||
|
typedef NS_ENUM (NSUInteger, MPContentFieldMode) {
|
||||||
|
MPContentFieldModePassword,
|
||||||
|
MPContentFieldModeUser,
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface MPPasswordLargeCell : MPPasswordCell <UITextFieldDelegate>
|
||||||
|
|
||||||
|
@property(nonatomic) MPElementType type;
|
||||||
|
@property(nonatomic) MPContentFieldMode contentFieldMode;
|
||||||
|
@property(nonatomic, strong) IBOutlet UILabel *typeLabel;
|
||||||
|
@property(nonatomic, strong) IBOutlet UITextField *contentField;
|
||||||
|
@property(nonatomic, strong) IBOutlet UIButton *upgradeButton;
|
||||||
|
|
||||||
|
+ (instancetype)dequeueCellWithType:(MPElementType)type fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
|
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock;
|
||||||
|
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock;
|
||||||
|
|
||||||
|
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context;
|
||||||
|
|
||||||
|
@end
|
||||||
231
MasterPassword/ObjC/iOS/MPPasswordLargeCell.m
Normal file
231
MasterPassword/ObjC/iOS/MPPasswordLargeCell.m
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPAvatarCell.h
|
||||||
|
// MPAvatarCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-11.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordLargeCell.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "MPPasswordLargeGeneratedCell.h"
|
||||||
|
#import "MPPasswordLargeStoredCell.h"
|
||||||
|
#import "MPPasswordTypesCell.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordLargeCell
|
||||||
|
|
||||||
|
#pragma mark - Life
|
||||||
|
|
||||||
|
+ (instancetype)dequeueCellWithType:(MPElementType)type fromCollectionView:(UICollectionView *)collectionView
|
||||||
|
atIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
NSString *reuseIdentifier;
|
||||||
|
if (type & MPElementTypeClassGenerated)
|
||||||
|
reuseIdentifier = NSStringFromClass( [MPPasswordLargeGeneratedCell class] );
|
||||||
|
else if (type & MPElementTypeClassStored)
|
||||||
|
reuseIdentifier = NSStringFromClass( [MPPasswordLargeStoredCell class] );
|
||||||
|
else
|
||||||
|
Throw(@"Unexpected password type: %@", [MPAlgorithmDefault nameOfType:type]);
|
||||||
|
|
||||||
|
MPPasswordLargeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
|
||||||
|
cell.type = type;
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
[self prepareForReuse];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForReuse {
|
||||||
|
|
||||||
|
_contentFieldMode = 0;
|
||||||
|
self.contentField.text = nil;
|
||||||
|
|
||||||
|
[super prepareForReuse];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadWithTransientSite:(NSString *)siteName {
|
||||||
|
|
||||||
|
[super reloadWithTransientSite:siteName];
|
||||||
|
|
||||||
|
self.loginButton.alpha = 0;
|
||||||
|
self.upgradeButton.alpha = 0;
|
||||||
|
self.typeLabel.text = [MPAlgorithmDefault nameOfType:self.type];
|
||||||
|
if (self.type & MPElementTypeClassStored) {
|
||||||
|
self.contentField.enabled = YES;
|
||||||
|
self.contentField.placeholder = strl( @"Set custom password" );
|
||||||
|
}
|
||||||
|
else if (self.type & MPElementTypeClassGenerated) {
|
||||||
|
self.contentField.enabled = NO;
|
||||||
|
self.contentField.placeholder = strl( @"Generating..." );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.contentField.enabled = NO;
|
||||||
|
self.contentField.placeholder = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.contentField.text = nil;
|
||||||
|
[self resolveContentOfCellTypeForTransientSite:siteName usingKey:[MPiOSAppDelegate get].key result:^(NSString *string) {
|
||||||
|
PearlMainQueue( ^{ self.contentField.text = string; } );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||||
|
|
||||||
|
[super reloadWithElement:mainElement];
|
||||||
|
|
||||||
|
self.loginButton.alpha = 1;
|
||||||
|
self.typeLabel.text = [mainElement.algorithm nameOfType:self.type];
|
||||||
|
|
||||||
|
if (mainElement.requiresExplicitMigration)
|
||||||
|
self.upgradeButton.alpha = 1;
|
||||||
|
else
|
||||||
|
self.upgradeButton.alpha = 0;
|
||||||
|
|
||||||
|
switch (self.contentFieldMode) {
|
||||||
|
case MPContentFieldModePassword: {
|
||||||
|
if (self.type & MPElementTypeClassStored) {
|
||||||
|
self.contentField.enabled = YES;
|
||||||
|
self.contentField.placeholder = strl( @"Set custom password" );
|
||||||
|
}
|
||||||
|
else if (self.type & MPElementTypeClassGenerated) {
|
||||||
|
self.contentField.enabled = NO;
|
||||||
|
self.contentField.placeholder = strl( @"Generating..." );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.contentField.enabled = NO;
|
||||||
|
self.contentField.placeholder = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.contentField.text = nil;
|
||||||
|
MPKey *key = [MPiOSAppDelegate get].key;
|
||||||
|
if (self.type == mainElement.type)
|
||||||
|
[mainElement resolveContentUsingKey:key result:^(NSString *string) {
|
||||||
|
PearlMainQueue( ^{ self.contentField.text = string; } );
|
||||||
|
}];
|
||||||
|
else
|
||||||
|
[self resolveContentOfCellTypeForElement:mainElement usingKey:key result:^(NSString *string) {
|
||||||
|
PearlMainQueue( ^{ self.contentField.text = string; } );
|
||||||
|
}];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPContentFieldModeUser: {
|
||||||
|
self.contentField.enabled = YES;
|
||||||
|
self.contentField.placeholder = strl( @"Enter login name" );
|
||||||
|
self.contentField.text = mainElement.loginName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||||
|
|
||||||
|
resultBlock( nil );
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||||
|
|
||||||
|
resultBlock( nil );
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||||
|
|
||||||
|
return [[MPiOSAppDelegate get] changeElement:element saveInContext:context toType:self.type];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UITextFieldDelegate
|
||||||
|
|
||||||
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||||
|
|
||||||
|
[textField resignFirstResponder];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||||
|
|
||||||
|
if (textField == self.contentField) {
|
||||||
|
NSString *newContent = textField.text;
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementEntity *element = [[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context];
|
||||||
|
|
||||||
|
switch (self.contentFieldMode) {
|
||||||
|
case MPContentFieldModePassword:
|
||||||
|
break;
|
||||||
|
case MPContentFieldModeUser: {
|
||||||
|
element.loginName = newContent;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Login Updated" dismissAfter:2];
|
||||||
|
} );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (IBAction)doUser:(id)sender {
|
||||||
|
|
||||||
|
switch (self.contentFieldMode) {
|
||||||
|
case MPContentFieldModePassword: {
|
||||||
|
self.contentFieldMode = MPContentFieldModeUser;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPContentFieldModeUser: {
|
||||||
|
self.contentFieldMode = MPContentFieldModePassword;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)doUpgrade:(UIButton *)sender {
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
if ([[[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context] migrateExplicitly:YES]) {
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[[MPPasswordElementCell findAsSuperviewOf:self] reloadData];
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Site Upgraded" dismissAfter:2];
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Site Not Upgraded" dismissAfter:2];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (void)setContentFieldMode:(MPContentFieldMode)contentFieldMode {
|
||||||
|
|
||||||
|
if (_contentFieldMode == contentFieldMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_contentFieldMode = contentFieldMode;
|
||||||
|
|
||||||
|
[[MPPasswordElementCell findAsSuperviewOf:self] reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
27
MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h
Normal file
27
MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordLargeGeneratedCell.h
|
||||||
|
// MPPasswordLargeGeneratedCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-19.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPPasswordLargeCell.h"
|
||||||
|
|
||||||
|
@interface MPPasswordLargeGeneratedCell : MPPasswordLargeCell
|
||||||
|
|
||||||
|
@property(strong, nonatomic) IBOutlet UILabel *counterLabel;
|
||||||
|
@property(strong, nonatomic) IBOutlet UIButton *counterButton;
|
||||||
|
|
||||||
|
@end
|
||||||
139
MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m
Normal file
139
MasterPassword/ObjC/iOS/MPPasswordLargeGeneratedCell.m
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordLargeGeneratedCell.h
|
||||||
|
// MPPasswordLargeGeneratedCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-19.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordLargeGeneratedCell.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "MPPasswordElementCell.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordLargeGeneratedCell
|
||||||
|
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc]
|
||||||
|
initWithTarget:self action:@selector(doResetCounterRecognizer:)];
|
||||||
|
[self.counterButton addGestureRecognizer:gestureRecognizer];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||||
|
|
||||||
|
[super reloadWithElement:mainElement];
|
||||||
|
|
||||||
|
MPElementGeneratedEntity *generatedElement = [self generatedElement:mainElement];
|
||||||
|
if (generatedElement)
|
||||||
|
self.counterLabel.text = strf( @"%lu", (unsigned long)generatedElement.counter );
|
||||||
|
else
|
||||||
|
self.counterLabel.text = @"1";
|
||||||
|
|
||||||
|
if (!mainElement || mainElement.requiresExplicitMigration) {
|
||||||
|
self.counterLabel.alpha = 0;
|
||||||
|
self.counterButton.alpha = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.counterLabel.alpha = 1;
|
||||||
|
self.counterButton.alpha = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resolveContentOfCellTypeForTransientSite:(NSString *)siteName usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||||
|
|
||||||
|
PearlNotMainQueue( ^{
|
||||||
|
resultBlock( [MPAlgorithmDefault generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||||
|
|
||||||
|
id<MPAlgorithm> algorithm = element.algorithm;
|
||||||
|
NSString *siteName = element.name;
|
||||||
|
|
||||||
|
PearlNotMainQueue( ^{
|
||||||
|
resultBlock( [algorithm generateContentNamed:siteName ofType:self.type withCounter:1 usingKey:key] );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||||
|
|
||||||
|
element = [super saveContentTypeWithElement:element saveInContext:context];
|
||||||
|
|
||||||
|
MPElementGeneratedEntity *generatedElement = [self generatedElement:element];
|
||||||
|
if (generatedElement) {
|
||||||
|
generatedElement.counter = [self.counterLabel.text intValue];
|
||||||
|
[context saveToStore];
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (IBAction)doIncrementCounter:(UIButton *)sender {
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementGeneratedEntity *generatedElement = [self generatedElementInContext:context];
|
||||||
|
if (!generatedElement)
|
||||||
|
return;
|
||||||
|
|
||||||
|
++generatedElement.counter;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Incremented" dismissAfter:2];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)doResetCounterRecognizer:(UILongPressGestureRecognizer *)gestureRecognizer {
|
||||||
|
|
||||||
|
if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementGeneratedEntity *generatedElement = [self generatedElementInContext:context];
|
||||||
|
if (!generatedElement)
|
||||||
|
return;
|
||||||
|
|
||||||
|
generatedElement.counter = 1;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Counter Reset" dismissAfter:2];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (MPElementGeneratedEntity *)generatedElementInContext:(NSManagedObjectContext *)context {
|
||||||
|
|
||||||
|
return [self generatedElement:[[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementGeneratedEntity *)generatedElement:(MPElementEntity *)element {
|
||||||
|
|
||||||
|
if (![element isKindOfClass:[MPElementGeneratedEntity class]])
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return (MPElementGeneratedEntity *)element;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
24
MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.h
Normal file
24
MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordLargeStoredCell.h
|
||||||
|
// MPPasswordLargeStoredCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-19.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPPasswordLargeCell.h"
|
||||||
|
|
||||||
|
@interface MPPasswordLargeStoredCell : MPPasswordLargeCell
|
||||||
|
|
||||||
|
@end
|
||||||
112
MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.m
Normal file
112
MasterPassword/ObjC/iOS/MPPasswordLargeStoredCell.m
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordLargeGeneratedCell.h
|
||||||
|
// MPPasswordLargeGeneratedCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-19.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordLargeStoredCell.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "MPPasswordElementCell.h"
|
||||||
|
|
||||||
|
@interface MPPasswordLargeStoredCell()
|
||||||
|
|
||||||
|
@property(strong, nonatomic) IBOutlet UIButton *editButton;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPPasswordLargeStoredCell
|
||||||
|
|
||||||
|
#pragma mark - Lifecycle
|
||||||
|
|
||||||
|
- (void)resolveContentOfCellTypeForElement:(MPElementEntity *)element usingKey:(MPKey *)key result:(void (^)(NSString *))resultBlock {
|
||||||
|
|
||||||
|
if (element.type & MPElementTypeClassStored)
|
||||||
|
[element resolveContentUsingKey:key result:resultBlock];
|
||||||
|
else
|
||||||
|
[super resolveContentOfCellTypeForElement:element usingKey:key result:resultBlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementEntity *)saveContentTypeWithElement:(MPElementEntity *)element saveInContext:(NSManagedObjectContext *)context {
|
||||||
|
|
||||||
|
element = [super saveContentTypeWithElement:element saveInContext:context];
|
||||||
|
|
||||||
|
MPElementStoredEntity *storedElement = [self storedElement:element];
|
||||||
|
if (storedElement) {
|
||||||
|
storedElement.contentObject = self.contentField.text;
|
||||||
|
[context saveToStore];
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (IBAction)doEditContent:(UIButton *)sender {
|
||||||
|
|
||||||
|
UITextField *field = self.contentField;
|
||||||
|
field.enabled = YES;
|
||||||
|
[field becomeFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UITextFieldDelegate
|
||||||
|
|
||||||
|
- (void)textFieldDidEndEditing:(UITextField *)textField {
|
||||||
|
|
||||||
|
[super textFieldDidEndEditing:textField];
|
||||||
|
|
||||||
|
if (textField == self.contentField) {
|
||||||
|
NSString *newContent = textField.text;
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPElementStoredEntity *storedElement = [self storedElementInContext:context];
|
||||||
|
if (!storedElement)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (self.contentFieldMode) {
|
||||||
|
case MPContentFieldModePassword: {
|
||||||
|
storedElement.contentObject = newContent;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self updateAnimated:YES];
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Updated" dismissAfter:2];
|
||||||
|
} );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPContentFieldModeUser:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (MPElementStoredEntity *)storedElementInContext:(NSManagedObjectContext *)context {
|
||||||
|
|
||||||
|
return [self storedElement:[[MPPasswordElementCell findAsSuperviewOf:self] elementInContext:context]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementStoredEntity *)storedElement:(MPElementEntity *)element {
|
||||||
|
|
||||||
|
if (![element isKindOfClass:[MPElementStoredEntity class]])
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return (MPElementStoredEntity *)element;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
33
MasterPassword/ObjC/iOS/MPPasswordSmallCell.h
Normal file
33
MasterPassword/ObjC/iOS/MPPasswordSmallCell.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordSmallCell.h
|
||||||
|
// MPPasswordSmallCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-28.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPPasswordCell.h"
|
||||||
|
|
||||||
|
@interface MPPasswordSmallCell : MPPasswordElementCell
|
||||||
|
|
||||||
|
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element
|
||||||
|
fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MPPasswordSmallGeneratedCell : MPPasswordSmallCell
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MPPasswordSmallStoredCell : MPPasswordSmallCell
|
||||||
|
@end
|
||||||
48
MasterPassword/ObjC/iOS/MPPasswordSmallCell.m
Normal file
48
MasterPassword/ObjC/iOS/MPPasswordSmallCell.m
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordSmallCell.h
|
||||||
|
// MPPasswordSmallCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-28.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordElementCell.h"
|
||||||
|
#import "MPPasswordSmallCell.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordSmallCell {
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element fromCollectionView:(UICollectionView *)collectionView
|
||||||
|
atIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
NSString *reuseIdentifier;
|
||||||
|
if (element.type & MPElementTypeClassGenerated)
|
||||||
|
reuseIdentifier = NSStringFromClass( [MPPasswordSmallGeneratedCell class] );
|
||||||
|
else if (element.type & MPElementTypeClassStored)
|
||||||
|
reuseIdentifier = NSStringFromClass( [MPPasswordSmallStoredCell class] );
|
||||||
|
else
|
||||||
|
Throw(@"Unexpected password type: %@", [MPAlgorithmDefault nameOfType:element.type]);
|
||||||
|
|
||||||
|
MPPasswordSmallCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
|
||||||
|
[cell setElement:element];
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPPasswordSmallGeneratedCell
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPPasswordSmallStoredCell
|
||||||
|
@end
|
||||||
34
MasterPassword/ObjC/iOS/MPPasswordTypesCell.h
Normal file
34
MasterPassword/ObjC/iOS/MPPasswordTypesCell.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordTypesCell.h
|
||||||
|
// MPPasswordTypesCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-27.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPCell.h"
|
||||||
|
#import "MPPasswordCell.h"
|
||||||
|
#import "MPPasswordElementCell.h"
|
||||||
|
|
||||||
|
@interface MPPasswordTypesCell : MPPasswordElementCell <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||||
|
|
||||||
|
@property(nonatomic, strong) IBOutlet UICollectionView *contentCollectionView;
|
||||||
|
@property(nonatomic, strong) id<MPAlgorithm> algorithm;
|
||||||
|
|
||||||
|
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element
|
||||||
|
fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
+ (instancetype)dequeueCellForTransientSite:(NSString *)siteName
|
||||||
|
fromCollectionView:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
|
@end
|
||||||
218
MasterPassword/ObjC/iOS/MPPasswordTypesCell.m
Normal file
218
MasterPassword/ObjC/iOS/MPPasswordTypesCell.m
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordTypesCell.h
|
||||||
|
// MPPasswordTypesCell
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-27.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordTypesCell.h"
|
||||||
|
#import "MPPasswordLargeCell.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordTypesCell
|
||||||
|
|
||||||
|
#pragma mark - Lifecycle
|
||||||
|
|
||||||
|
+ (instancetype)dequeueCellForTransientSite:(NSString *)siteName fromCollectionView:(UICollectionView *)collectionView
|
||||||
|
atIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
MPPasswordTypesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass( [MPPasswordTypesCell class] )
|
||||||
|
forIndexPath:indexPath];
|
||||||
|
[cell setTransientSite:siteName];
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)dequeueCellForElement:(MPElementEntity *)element fromCollectionView:(UICollectionView *)collectionView
|
||||||
|
atIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
MPPasswordTypesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass( [MPPasswordTypesCell class] )
|
||||||
|
forIndexPath:indexPath];
|
||||||
|
[cell setElement:element];
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)awakeFromNib {
|
||||||
|
|
||||||
|
[super awakeFromNib];
|
||||||
|
|
||||||
|
self.backgroundColor = [UIColor clearColor];
|
||||||
|
self.layer.shadowColor = [UIColor clearColor].CGColor;
|
||||||
|
|
||||||
|
[self prepareForReuse];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForReuse {
|
||||||
|
|
||||||
|
_algorithm = MPAlgorithmDefault;
|
||||||
|
|
||||||
|
[super prepareForReuse];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadWithTransientSite:(NSString *)siteName {
|
||||||
|
|
||||||
|
[super reloadWithTransientSite:siteName];
|
||||||
|
|
||||||
|
[self.contentCollectionView reloadData];
|
||||||
|
NSIndexPath *visibleIndexPath = [self contentIndexPathForType:
|
||||||
|
IfElse([[MPiOSAppDelegate get] activeUserForMainThread].defaultType, MPElementTypeGeneratedLong)];
|
||||||
|
[self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath
|
||||||
|
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadWithElement:(MPElementEntity *)mainElement {
|
||||||
|
|
||||||
|
[super reloadWithElement:mainElement];
|
||||||
|
|
||||||
|
self.algorithm = IfNotNilElse([self mainElement].algorithm, MPAlgorithmDefault);
|
||||||
|
|
||||||
|
[self.contentCollectionView reloadData];
|
||||||
|
NSIndexPath *visibleIndexPath = [self contentIndexPathForType:mainElement.type];
|
||||||
|
[self.contentCollectionView scrollToItemAtIndexPath:visibleIndexPath
|
||||||
|
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UICollectionViewDataSource
|
||||||
|
|
||||||
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
if (!self.algorithm)
|
||||||
|
dbg_return_tr(0, @, @(section));
|
||||||
|
|
||||||
|
NSInteger types = 1;
|
||||||
|
|
||||||
|
MPElementType type = [self typeForContentIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
|
||||||
|
for (MPElementType nextType = type; type != (nextType = [self.algorithm nextType:nextType]);)
|
||||||
|
++types;
|
||||||
|
|
||||||
|
dbg_return_tr(types, @, @(section));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPPasswordLargeCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
MPPasswordLargeCell *cell = [MPPasswordLargeCell dequeueCellWithType:[self typeForContentIndexPath:indexPath]
|
||||||
|
fromCollectionView:collectionView atIndexPath:indexPath];
|
||||||
|
if (self.transientSite)
|
||||||
|
[cell reloadWithTransientSite:self.transientSite];
|
||||||
|
else
|
||||||
|
[cell reloadWithElement:self.mainElement];
|
||||||
|
|
||||||
|
dbg_return(cell, indexPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||||
|
|
||||||
|
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
UICollectionView *passwordCollectionView = [UICollectionView findAsSuperviewOf:self];
|
||||||
|
[passwordCollectionView.delegate collectionView:passwordCollectionView didSelectItemAtIndexPath:[passwordCollectionView indexPathForCell:self]];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UIScrollViewDelegate
|
||||||
|
|
||||||
|
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity
|
||||||
|
targetContentOffset:(inout CGPoint *)targetContentOffset {
|
||||||
|
|
||||||
|
if (scrollView == self.contentCollectionView) {
|
||||||
|
NSIndexPath *targetIndexPath = [self.contentCollectionView indexPathForItemAtPoint:
|
||||||
|
CGPointPlusCGPoint( *targetContentOffset, self.contentCollectionView.center )];
|
||||||
|
*targetContentOffset = CGPointFromCGRectTopLeft(
|
||||||
|
[self.contentCollectionView layoutAttributesForItemAtIndexPath:targetIndexPath].frame );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
|
||||||
|
|
||||||
|
if (scrollView == self.contentCollectionView && !decelerate)
|
||||||
|
[self saveContentType];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||||
|
|
||||||
|
if (scrollView == self.contentCollectionView)
|
||||||
|
[self saveContentType];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (MPElementType)typeForContentIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
MPElementType type = MPElementTypeGeneratedPIN;
|
||||||
|
|
||||||
|
for (NSUInteger i = 0; i < indexPath.item; ++i)
|
||||||
|
type = [self.algorithm nextType:type];
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSIndexPath *)contentIndexPathForType:(MPElementType)type {
|
||||||
|
|
||||||
|
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
||||||
|
while ([self typeForContentIndexPath:indexPath] != type) {
|
||||||
|
indexPath = [NSIndexPath indexPathForItem:indexPath.item + 1 inSection:indexPath.section];
|
||||||
|
NSAssert1(indexPath.item < [self.contentCollectionView numberOfItemsInSection:0],
|
||||||
|
@"No item found for type: %@", [self.algorithm nameOfType:type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return indexPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)saveContentType {
|
||||||
|
|
||||||
|
if (self.transientSite)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CGPoint centerPoint = CGPointFromCGRectCenter( self.contentCollectionView.bounds );
|
||||||
|
NSIndexPath *centerIndexPath = [self.contentCollectionView indexPathForItemAtPoint:centerPoint];
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPPasswordLargeCell *cell = (MPPasswordLargeCell *)[self.contentCollectionView cellForItemAtIndexPath:centerIndexPath];
|
||||||
|
if (!cell) {
|
||||||
|
err(@"Couldn't find cell to change type: centerIndexPath=%@", centerIndexPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPElementEntity *element = [self elementInContext:context];
|
||||||
|
if (element.type == cell.type)
|
||||||
|
// Nothing changed.
|
||||||
|
return;
|
||||||
|
|
||||||
|
self.element = [cell saveContentTypeWithElement:element saveInContext:context];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (void)setSelected:(BOOL)selected {
|
||||||
|
|
||||||
|
[super setSelected:selected];
|
||||||
|
|
||||||
|
if (!selected)
|
||||||
|
for (NSIndexPath *indexPath in [self.contentCollectionView indexPathsForSelectedItems])
|
||||||
|
[self.contentCollectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAlgorithm:(id<MPAlgorithm>)algorithm {
|
||||||
|
|
||||||
|
if ([_algorithm isEqual:algorithm])
|
||||||
|
return;
|
||||||
|
|
||||||
|
_algorithm = algorithm;
|
||||||
|
|
||||||
|
[self.contentCollectionView reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
23
MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.h
Normal file
23
MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordsCoachmarkViewController.h
|
||||||
|
// MPPasswordsCoachmarkViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-23.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "MPCoachmarkViewController.h"
|
||||||
|
|
||||||
|
@interface MPPasswordsCoachmarkViewController : MPCoachmarkViewController <UICollectionViewDataSource>
|
||||||
|
@end
|
||||||
51
MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.m
Normal file
51
MasterPassword/ObjC/iOS/MPPasswordsCoachmarkViewController.m
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordsCoachmarkViewController.h
|
||||||
|
// MPPasswordsCoachmarkViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-23.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordsCoachmarkViewController.h"
|
||||||
|
#import "MPPasswordLargeGeneratedCell.h"
|
||||||
|
#import "MPPasswordLargeStoredCell.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordsCoachmarkViewController
|
||||||
|
|
||||||
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
if (indexPath.item == 0) {
|
||||||
|
MPPasswordLargeGeneratedCell *cell = [MPPasswordLargeGeneratedCell dequeueCellWithType:MPElementTypeGeneratedLong
|
||||||
|
fromCollectionView:collectionView atIndexPath:indexPath];
|
||||||
|
[cell reloadWithTransientSite:@"apple.com"];
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
else if (indexPath.item == 1) {
|
||||||
|
MPPasswordLargeStoredCell *cell = [MPPasswordLargeStoredCell dequeueCellWithType:MPElementTypeStoredPersonal
|
||||||
|
fromCollectionView:collectionView atIndexPath:indexPath];
|
||||||
|
[cell reloadWithTransientSite:@"gmail.com"];
|
||||||
|
[cell.contentField setText:@"PaS$w0rD"];
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
Throw(@"Unexpected item for indexPath: %@", indexPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
25
MasterPassword/ObjC/iOS/MPPasswordsSegue.h
Normal file
25
MasterPassword/ObjC/iOS/MPPasswordsSegue.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordsSegue.h
|
||||||
|
// MPPasswordsSegue
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-12.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface MPPasswordsSegue : UIStoryboardSegue
|
||||||
|
|
||||||
|
@property (nonatomic, assign) BOOL animated;
|
||||||
|
|
||||||
|
@end
|
||||||
65
MasterPassword/ObjC/iOS/MPPasswordsSegue.m
Normal file
65
MasterPassword/ObjC/iOS/MPPasswordsSegue.m
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordsSegue.h
|
||||||
|
// MPPasswordsSegue
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-12.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordsSegue.h"
|
||||||
|
#import "MPPasswordsViewController.h"
|
||||||
|
#import "MPCombinedViewController.h"
|
||||||
|
|
||||||
|
@implementation MPPasswordsSegue {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination {
|
||||||
|
|
||||||
|
if (!(self = [super initWithIdentifier:identifier source:source destination:destination]))
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
self.animated = YES;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)perform {
|
||||||
|
|
||||||
|
if ([self.destinationViewController isKindOfClass:[MPPasswordsViewController class]]) {
|
||||||
|
__weak MPPasswordsViewController *passwordsVC = self.destinationViewController;
|
||||||
|
__weak MPCombinedViewController *combinedVC = self.sourceViewController;
|
||||||
|
|
||||||
|
[combinedVC addChildViewController:passwordsVC];
|
||||||
|
[combinedVC.view insertSubview:passwordsVC.view belowSubview:combinedVC.usersView];
|
||||||
|
passwordsVC.active = NO;
|
||||||
|
[passwordsVC setActive:YES animated:self.animated completion:^(BOOL finished) {
|
||||||
|
if (!finished)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[passwordsVC didMoveToParentViewController:combinedVC];
|
||||||
|
}];
|
||||||
|
} else if ([self.sourceViewController isKindOfClass:[MPPasswordsViewController class]]) {
|
||||||
|
__weak MPPasswordsViewController *passwordsVC = self.sourceViewController;
|
||||||
|
|
||||||
|
[passwordsVC willMoveToParentViewController:nil];
|
||||||
|
[passwordsVC setActive:NO animated:self.animated completion:^(BOOL finished) {
|
||||||
|
if (!finished)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[passwordsVC.view removeFromSuperview];
|
||||||
|
[passwordsVC removeFromParentViewController];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
44
MasterPassword/ObjC/iOS/MPPasswordsViewController.h
Normal file
44
MasterPassword/ObjC/iOS/MPPasswordsViewController.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCombinedViewController.h
|
||||||
|
// MPCombinedViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-08.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "LLGitTip.h"
|
||||||
|
@class MPElementEntity;
|
||||||
|
@class MPCoachmark;
|
||||||
|
|
||||||
|
@interface MPPasswordsViewController : UIViewController<UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||||
|
|
||||||
|
@property(strong, nonatomic) IBOutlet UIView *passwordSelectionContainer;
|
||||||
|
@property(strong, nonatomic) IBOutlet UICollectionView *passwordCollectionView;
|
||||||
|
@property(strong, nonatomic) IBOutlet UISearchBar *passwordsSearchBar;
|
||||||
|
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *passwordsToBottomConstraint;
|
||||||
|
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *navigationBarToTopConstraint;
|
||||||
|
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *popdownToTopConstraint;
|
||||||
|
@property(strong, nonatomic) IBOutlet UIView *popdownView;
|
||||||
|
@property(strong, nonatomic) IBOutlet UIView *popdownContainer;
|
||||||
|
|
||||||
|
@property(assign, nonatomic) BOOL active;
|
||||||
|
|
||||||
|
@property(nonatomic, copy) NSString *originalQuery;
|
||||||
|
@property(nonatomic, readonly) MPCoachmark *coachmark;
|
||||||
|
|
||||||
|
- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void (^)(BOOL finished))completion;
|
||||||
|
|
||||||
|
- (IBAction)dismissPopdown:(id)sender;
|
||||||
|
- (IBAction)signOut:(id)sender;
|
||||||
|
|
||||||
|
@end
|
||||||
622
MasterPassword/ObjC/iOS/MPPasswordsViewController.m
Normal file
622
MasterPassword/ObjC/iOS/MPPasswordsViewController.m
Normal file
@@ -0,0 +1,622 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPasswordsViewController.h
|
||||||
|
// MPPasswordsViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-08.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPasswordsViewController.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "MPPasswordLargeCell.h"
|
||||||
|
#import "MPPasswordTypesCell.h"
|
||||||
|
#import "MPPasswordSmallCell.h"
|
||||||
|
#import "MPPopdownSegue.h"
|
||||||
|
#import "MPAppDelegate_Key.h"
|
||||||
|
#import "MPCoachmarkViewController.h"
|
||||||
|
|
||||||
|
@interface MPPasswordsViewController()<NSFetchedResultsControllerDelegate>
|
||||||
|
|
||||||
|
@property(nonatomic, strong) IBOutlet UINavigationBar *navigationBar;
|
||||||
|
@property(nonatomic, readonly) NSString *query;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPPasswordsViewController {
|
||||||
|
__weak id _storeObserver;
|
||||||
|
__weak id _mocObserver;
|
||||||
|
NSArray *_notificationObservers;
|
||||||
|
__weak UITapGestureRecognizer *_passwordsDismissRecognizer;
|
||||||
|
NSFetchedResultsController *_fetchedResultsController;
|
||||||
|
BOOL _exactMatch;
|
||||||
|
NSMutableDictionary *_fetchedUpdates;
|
||||||
|
UIColor *_backgroundColor;
|
||||||
|
UIColor *_darkenedBackgroundColor;
|
||||||
|
__weak UIViewController *_popdownVC;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Life
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
_fetchedUpdates = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||||
|
_backgroundColor = self.passwordCollectionView.backgroundColor;
|
||||||
|
_darkenedBackgroundColor = [_backgroundColor colorWithAlphaComponent:0.6f];
|
||||||
|
_coachmark = [MPCoachmark coachmarkForClass:[self class] version:0];
|
||||||
|
|
||||||
|
self.view.backgroundColor = [UIColor clearColor];
|
||||||
|
self.passwordCollectionView.contentInset = UIEdgeInsetsMake( 108, 0, 0, 0 );
|
||||||
|
[self.passwordCollectionView automaticallyAdjustInsetsForKeyboard];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
|
||||||
|
[self registerObservers];
|
||||||
|
[self observeStore];
|
||||||
|
[self updatePasswords];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
|
||||||
|
PearlMainQueueAfter( 1, ^{
|
||||||
|
if (!self.coachmark.coached)
|
||||||
|
[self performSegueWithIdentifier:@"coachmarks" sender:self];
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillDisappear:(BOOL)animated {
|
||||||
|
|
||||||
|
[super viewWillDisappear:animated];
|
||||||
|
|
||||||
|
[self removeObservers];
|
||||||
|
[self stopObservingStore];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
|
||||||
|
if ([segue.identifier isEqualToString:@"popdown"])
|
||||||
|
_popdownVC = segue.destinationViewController;
|
||||||
|
if ([segue.identifier isEqualToString:@"coachmarks"])
|
||||||
|
((MPCoachmarkViewController *)segue.destinationViewController).coachmark = self.coachmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||||
|
|
||||||
|
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
|
||||||
|
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
if (collectionView == self.passwordCollectionView) {
|
||||||
|
if (indexPath.item < 3 ||
|
||||||
|
indexPath.item >= ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects)
|
||||||
|
return CGSizeMake( 300, 100 );
|
||||||
|
|
||||||
|
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout;
|
||||||
|
return CGSizeMake( (300 - layout.minimumInteritemSpacing) / 2, 44 );
|
||||||
|
}
|
||||||
|
|
||||||
|
Throw(@"Unexpected collection view: %@", collectionView);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UICollectionViewDataSource
|
||||||
|
|
||||||
|
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||||
|
|
||||||
|
if (collectionView == self.passwordCollectionView)
|
||||||
|
return [self.fetchedResultsController.sections count];
|
||||||
|
|
||||||
|
Throw(@"Unexpected collection view: %@", collectionView);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
if (collectionView == self.passwordCollectionView)
|
||||||
|
return ![MPiOSAppDelegate get].activeUserOID? 0:
|
||||||
|
((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[section]).numberOfObjects +
|
||||||
|
(!_exactMatch && [[self query] length]? 1: 0);
|
||||||
|
|
||||||
|
Throw(@"Unexpected collection view: %@", collectionView);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
if (collectionView == self.passwordCollectionView) {
|
||||||
|
[UIView setAnimationsEnabled:NO];
|
||||||
|
MPPasswordElementCell *cell;
|
||||||
|
if (indexPath.item < ((id<NSFetchedResultsSectionInfo>)self.fetchedResultsController.sections[indexPath.section]).numberOfObjects) {
|
||||||
|
MPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
|
||||||
|
if (indexPath.item < 3)
|
||||||
|
cell = [MPPasswordTypesCell dequeueCellForElement:element fromCollectionView:collectionView atIndexPath:indexPath];
|
||||||
|
else
|
||||||
|
cell = [MPPasswordSmallCell dequeueCellForElement:element fromCollectionView:collectionView atIndexPath:indexPath];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// New Site.
|
||||||
|
cell = [MPPasswordTypesCell dequeueCellForTransientSite:self.query fromCollectionView:collectionView atIndexPath:indexPath];
|
||||||
|
|
||||||
|
[UIView setAnimationsEnabled:YES];
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
Throw(@"Unexpected collection view: %@", collectionView);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
MPPasswordElementCell *cell = (MPPasswordElementCell *)[collectionView cellForItemAtIndexPath:indexPath];
|
||||||
|
NSString *newSiteName = cell.transientSite;
|
||||||
|
if (newSiteName) {
|
||||||
|
[PearlAlert showAlertWithTitle:@"Create Site"
|
||||||
|
message:strf( @"Do you want to create a new site named:\n%@", newSiteName )
|
||||||
|
viewStyle:UIAlertViewStyleDefault
|
||||||
|
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
|
||||||
|
if (buttonIndex == [alert cancelButtonIndex]) {
|
||||||
|
// Cancel
|
||||||
|
NSIndexPath *indexPath_ = [collectionView indexPathForCell:cell];
|
||||||
|
[collectionView selectItemAtIndexPath:indexPath_ animated:NO
|
||||||
|
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||||
|
[collectionView deselectItemAtIndexPath:indexPath_ animated:YES];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create
|
||||||
|
[[MPiOSAppDelegate get] addElementNamed:newSiteName completion:^(MPElementEntity *element) {
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:strf( @"Added %@", newSiteName ) dismissAfter:2];
|
||||||
|
PearlMainQueueAfter( 0.2f, ^{
|
||||||
|
NSIndexPath *indexPath_ = [collectionView indexPathForCell:cell];
|
||||||
|
[collectionView selectItemAtIndexPath:indexPath_ animated:NO
|
||||||
|
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||||
|
[collectionView deselectItemAtIndexPath:indexPath_ animated:YES];
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPElementEntity *element = [cell mainElement];
|
||||||
|
if (!element) {
|
||||||
|
[collectionView selectItemAtIndexPath:indexPath animated:NO
|
||||||
|
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||||
|
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf(@"Copying password for: %@", element.name);
|
||||||
|
MPCheckpoint( MPCheckpointCopyToPasteboard, @{
|
||||||
|
@"type" : NilToNSNull(element.typeName),
|
||||||
|
@"version" : @(element.version),
|
||||||
|
@"emergency" : @NO
|
||||||
|
} );
|
||||||
|
|
||||||
|
[element resolveContentUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
|
||||||
|
if (![result length]) {
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
NSIndexPath *indexPath_ = [collectionView indexPathForCell:cell];
|
||||||
|
[collectionView selectItemAtIndexPath:indexPath_ animated:NO
|
||||||
|
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||||
|
[collectionView deselectItemAtIndexPath:indexPath_ animated:YES];
|
||||||
|
} );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[UIPasteboard generalPasteboard].string = result;
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[PearlOverlay showTemporaryOverlayWithTitle:@"Password Copied" dismissAfter:2];
|
||||||
|
PearlMainQueueAfter( 0.2f, ^{
|
||||||
|
NSIndexPath *indexPath_ = [collectionView indexPathForCell:cell];
|
||||||
|
[collectionView selectItemAtIndexPath:indexPath_ animated:NO
|
||||||
|
scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
|
||||||
|
[collectionView deselectItemAtIndexPath:indexPath_ animated:YES];
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
[[cell elementInContext:context] use];
|
||||||
|
[context saveToStore];
|
||||||
|
}];
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSFetchedResultsControllerDelegate
|
||||||
|
|
||||||
|
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
|
||||||
|
|
||||||
|
if (controller == _fetchedResultsController) {
|
||||||
|
dbg(@"controllerWillChangeContent");
|
||||||
|
NSAssert(![_fetchedUpdates count], @"Didn't finish a previous change update?");
|
||||||
|
if ([_fetchedUpdates count]) {
|
||||||
|
[_fetchedUpdates removeAllObjects];
|
||||||
|
[self.passwordCollectionView reloadData];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
|
||||||
|
forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
|
||||||
|
|
||||||
|
if (controller == _fetchedResultsController) {
|
||||||
|
NSMutableArray *updatesForType = _fetchedUpdates[@(type)];
|
||||||
|
if (!updatesForType)
|
||||||
|
_fetchedUpdates[@(type)] = updatesForType = [NSMutableArray new];
|
||||||
|
|
||||||
|
[updatesForType addObject:@{
|
||||||
|
@"object" : NilToNSNull(anObject),
|
||||||
|
@"indexPath" : NilToNSNull(indexPath),
|
||||||
|
@"newIndexPath" : NilToNSNull(newIndexPath)
|
||||||
|
}];
|
||||||
|
switch (type) {
|
||||||
|
case NSFetchedResultsChangeInsert:
|
||||||
|
dbg(@"didChangeObject: insert: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeDelete:
|
||||||
|
dbg(@"didChangeObject: delete: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeMove:
|
||||||
|
dbg(@"didChangeObject: move: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeUpdate:
|
||||||
|
dbg(@"didChangeObject: update: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
|
||||||
|
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
|
||||||
|
|
||||||
|
if (controller == _fetchedResultsController) {
|
||||||
|
NSMutableArray *updatesForType = _fetchedUpdates[@(type << 3)];
|
||||||
|
if (!updatesForType)
|
||||||
|
_fetchedUpdates[@(type << 3)] = updatesForType = [NSMutableArray new];
|
||||||
|
|
||||||
|
[updatesForType addObject:@{
|
||||||
|
@"sectionInfo" : NilToNSNull(sectionInfo),
|
||||||
|
@"index" : @(sectionIndex)
|
||||||
|
}];
|
||||||
|
switch (type) {
|
||||||
|
case NSFetchedResultsChangeInsert:
|
||||||
|
dbg(@"didChangeSection: insert: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeDelete:
|
||||||
|
dbg(@"didChangeSection: delete: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeMove:
|
||||||
|
dbg(@"didChangeSection: move: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeUpdate:
|
||||||
|
dbg(@"didChangeSection: update: %@", [updatesForType lastObject]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
|
||||||
|
|
||||||
|
if (controller == _fetchedResultsController && [_fetchedUpdates count]) {
|
||||||
|
[self.passwordCollectionView performBatchUpdates:^{
|
||||||
|
[_fetchedUpdates enumerateKeysAndObjectsUsingBlock:^(NSNumber *typeNumber, NSArray *updates, BOOL *stop) {
|
||||||
|
BOOL updateIsSection = NO;
|
||||||
|
NSFetchedResultsChangeType type = [typeNumber unsignedIntegerValue];
|
||||||
|
if (type >= 1 << 3) {
|
||||||
|
updateIsSection = YES;
|
||||||
|
type = type >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case NSFetchedResultsChangeInsert:
|
||||||
|
if (updateIsSection) {
|
||||||
|
for (NSDictionary *update in updates) {
|
||||||
|
dbg(@"insertSections:%@", update[@"index"]);
|
||||||
|
[self.passwordCollectionView insertSections:
|
||||||
|
[NSIndexSet indexSetWithIndex:[update[@"index"] unsignedIntegerValue]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dbg(@"insertItemsAtIndexPaths:%@", [updates valueForKeyPath:@"@unionOfObjects.newIndexPath"]);
|
||||||
|
[self.passwordCollectionView insertItemsAtIndexPaths:[updates valueForKeyPath:@"@unionOfObjects.newIndexPath"]];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeDelete:
|
||||||
|
if (updateIsSection) {
|
||||||
|
for (NSDictionary *update in updates) {
|
||||||
|
dbg(@"deleteSections:%@", update[@"index"]);
|
||||||
|
[self.passwordCollectionView deleteSections:
|
||||||
|
[NSIndexSet indexSetWithIndex:[update[@"index"] unsignedIntegerValue]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dbg(@"deleteItemsAtIndexPaths:%@", [updates valueForKeyPath:@"@unionOfObjects.indexPath"]);
|
||||||
|
[self.passwordCollectionView deleteItemsAtIndexPaths:[updates valueForKeyPath:@"@unionOfObjects.indexPath"]];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeMove:
|
||||||
|
NSAssert(!updateIsSection, @"Move not supported for sections");
|
||||||
|
for (NSDictionary *update in updates) {
|
||||||
|
dbg(@"moveItemAtIndexPath:%@ toIndexPath:%@", update[@"indexPath"], update[@"newIndexPath"]);
|
||||||
|
[self.passwordCollectionView moveItemAtIndexPath:update[@"indexPath"] toIndexPath:update[@"newIndexPath"]];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NSFetchedResultsChangeUpdate:
|
||||||
|
NSAssert(!updateIsSection, @"Update not supported for sections");
|
||||||
|
dbg(@"reloadItemsAtIndexPaths:%@", [updates valueForKeyPath:@"@unionOfObjects.indexPath"]);
|
||||||
|
[self.passwordCollectionView reloadItemsAtIndexPaths:[updates valueForKeyPath:@"@unionOfObjects.indexPath"]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
} completion:nil];
|
||||||
|
[_fetchedUpdates removeAllObjects];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - UIScrollViewDelegate
|
||||||
|
|
||||||
|
#pragma mark - UISearchBarDelegate
|
||||||
|
|
||||||
|
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
if (searchBar == self.passwordsSearchBar) {
|
||||||
|
searchBar.text = nil;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
if (searchBar == self.passwordsSearchBar) {
|
||||||
|
self.originalQuery = self.query;
|
||||||
|
self.passwordsSearchBar.showsCancelButton = YES;
|
||||||
|
_passwordsDismissRecognizer = [self.view dismissKeyboardForField:self.passwordsSearchBar onTouchForced:NO];
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.3f animations:^{
|
||||||
|
self.passwordCollectionView.backgroundColor = _darkenedBackgroundColor;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
if (searchBar == self.passwordsSearchBar) {
|
||||||
|
self.passwordsSearchBar.showsCancelButton = NO;
|
||||||
|
if (_passwordsDismissRecognizer)
|
||||||
|
[self.view removeGestureRecognizer:_passwordsDismissRecognizer];
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.3f animations:^{
|
||||||
|
self.passwordCollectionView.backgroundColor = _backgroundColor;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
[searchBar resignFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
|
||||||
|
|
||||||
|
[searchBar resignFirstResponder];
|
||||||
|
|
||||||
|
if (searchBar == self.passwordsSearchBar) {
|
||||||
|
self.passwordsSearchBar.text = self.originalQuery;
|
||||||
|
[self updatePasswords];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
|
||||||
|
|
||||||
|
if (searchBar == self.passwordsSearchBar)
|
||||||
|
[self updatePasswords];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (void)registerObservers {
|
||||||
|
|
||||||
|
if ([_notificationObservers count])
|
||||||
|
return;
|
||||||
|
|
||||||
|
Weakify(self);
|
||||||
|
_notificationObservers = @[
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:UIApplicationWillResignActiveNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
Strongify(self);
|
||||||
|
|
||||||
|
self.passwordSelectionContainer.alpha = 0;
|
||||||
|
}],
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:MPSignedOutNotification object:nil
|
||||||
|
queue:nil usingBlock:^(NSNotification *note) {
|
||||||
|
Strongify(self);
|
||||||
|
|
||||||
|
_fetchedResultsController = nil;
|
||||||
|
self.passwordsSearchBar.text = nil;
|
||||||
|
[self updatePasswords];
|
||||||
|
}],
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
Strongify(self);
|
||||||
|
|
||||||
|
[self updatePasswords];
|
||||||
|
[UIView animateWithDuration:1 animations:^{
|
||||||
|
self.passwordSelectionContainer.alpha = 1;
|
||||||
|
}];
|
||||||
|
}],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObservers {
|
||||||
|
|
||||||
|
for (id observer in _notificationObservers)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:observer];
|
||||||
|
_notificationObservers = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeStore {
|
||||||
|
|
||||||
|
Weakify(self);
|
||||||
|
|
||||||
|
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
|
||||||
|
if (!_mocObserver && mainContext)
|
||||||
|
_mocObserver = [[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
// Strongify(self);
|
||||||
|
// [self updatePasswords];
|
||||||
|
}];
|
||||||
|
if (!_storeObserver)
|
||||||
|
_storeObserver = [[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:USMStoreDidChangeNotification object:nil
|
||||||
|
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
Strongify(self);
|
||||||
|
_fetchedResultsController = nil;
|
||||||
|
[self updatePasswords];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopObservingStore {
|
||||||
|
|
||||||
|
if (_mocObserver)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:_mocObserver];
|
||||||
|
if (_storeObserver)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:_storeObserver];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updatePasswords {
|
||||||
|
|
||||||
|
NSString *query = self.query;
|
||||||
|
NSManagedObjectID *activeUserOID = [MPiOSAppDelegate get].activeUserOID;
|
||||||
|
if (!activeUserOID) {
|
||||||
|
self.passwordsSearchBar.text = nil;
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self.passwordCollectionView reloadData];
|
||||||
|
[self.passwordCollectionView setContentOffset:CGPointMake( 0, -self.passwordCollectionView.contentInset.top ) animated:YES];
|
||||||
|
} );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||||
|
NSError *error = nil;
|
||||||
|
self.fetchedResultsController.fetchRequest.predicate =
|
||||||
|
[query length]?
|
||||||
|
[NSPredicate predicateWithFormat:@"user == %@ AND name BEGINSWITH[cd] %@", activeUserOID, query]:
|
||||||
|
[NSPredicate predicateWithFormat:@"user == %@", activeUserOID];
|
||||||
|
if (![self.fetchedResultsController performFetch:&error])
|
||||||
|
err(@"Couldn't fetch elements: %@", error);
|
||||||
|
|
||||||
|
_exactMatch = NO;
|
||||||
|
for (MPElementEntity *entity in self.fetchedResultsController.fetchedObjects)
|
||||||
|
if ([entity.name isEqualToString:query]) {
|
||||||
|
_exactMatch = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
[self.passwordCollectionView performBatchUpdates:^{
|
||||||
|
NSInteger fromSections = self.passwordCollectionView.numberOfSections;
|
||||||
|
NSInteger toSections = [self numberOfSectionsInCollectionView:self.passwordCollectionView];
|
||||||
|
for (int section = 0; section < MAX(toSections, fromSections); section++) {
|
||||||
|
if (section >= fromSections) {
|
||||||
|
dbg(@"insertSections:%d", section);
|
||||||
|
[self.passwordCollectionView insertSections:[NSIndexSet indexSetWithIndex:section]];
|
||||||
|
}
|
||||||
|
else if (section >= toSections) {
|
||||||
|
dbg(@"deleteSections:%d", section);
|
||||||
|
[self.passwordCollectionView deleteSections:[NSIndexSet indexSetWithIndex:section]];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dbg(@"reloadSections:%d", section);
|
||||||
|
[self.passwordCollectionView reloadSections:[NSIndexSet indexSetWithIndex:section]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
if (finished)
|
||||||
|
[self.passwordCollectionView setContentOffset:CGPointMake( 0, -self.passwordCollectionView.contentInset.top )
|
||||||
|
animated:YES];
|
||||||
|
}];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Properties
|
||||||
|
|
||||||
|
- (NSString *)query {
|
||||||
|
|
||||||
|
return [self.passwordsSearchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSFetchedResultsController *)fetchedResultsController {
|
||||||
|
|
||||||
|
if (!_fetchedResultsController) {
|
||||||
|
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
|
||||||
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
|
||||||
|
fetchRequest.sortDescriptors = @[
|
||||||
|
[[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector(lastUsed) ) ascending:NO]
|
||||||
|
];
|
||||||
|
fetchRequest.fetchBatchSize = 10;
|
||||||
|
_fetchedResultsController = [[NSFetchedResultsController alloc]
|
||||||
|
initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
|
||||||
|
_fetchedResultsController.delegate = self;
|
||||||
|
}];
|
||||||
|
[self observeStore];
|
||||||
|
}
|
||||||
|
|
||||||
|
return _fetchedResultsController;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setActive:(BOOL)active {
|
||||||
|
|
||||||
|
[self setActive:active animated:NO completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setActive:(BOOL)active animated:(BOOL)animated completion:(void (^)(BOOL finished))completion {
|
||||||
|
|
||||||
|
_active = active;
|
||||||
|
|
||||||
|
[UIView animateWithDuration:animated? 0.4f: 0 animations:^{
|
||||||
|
self.navigationBarToTopConstraint.priority = active? 1: UILayoutPriorityDefaultHigh;
|
||||||
|
self.passwordsToBottomConstraint.priority = active? 1: UILayoutPriorityDefaultHigh;
|
||||||
|
|
||||||
|
[self.navigationBarToTopConstraint apply];
|
||||||
|
[self.passwordsToBottomConstraint apply];
|
||||||
|
} completion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Actions
|
||||||
|
|
||||||
|
- (IBAction)dismissPopdown:(id)sender {
|
||||||
|
|
||||||
|
if (_popdownVC)
|
||||||
|
[[[MPPopdownSegue alloc] initWithIdentifier:@"unwind-popdown" source:_popdownVC destination:self] perform];
|
||||||
|
else
|
||||||
|
self.popdownToTopConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)signOut:(id)sender {
|
||||||
|
|
||||||
|
[[MPiOSAppDelegate get] signOutAnimated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
22
MasterPassword/ObjC/iOS/MPPopdownSegue.h
Normal file
22
MasterPassword/ObjC/iOS/MPPopdownSegue.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPopdownSegue.h
|
||||||
|
// MPPopdownSegue
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-17.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface MPPopdownSegue : UIStoryboardSegue
|
||||||
|
@end
|
||||||
65
MasterPassword/ObjC/iOS/MPPopdownSegue.m
Normal file
65
MasterPassword/ObjC/iOS/MPPopdownSegue.m
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPPopdownSegue.h
|
||||||
|
// MPPopdownSegue
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-04-17.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPPopdownSegue.h"
|
||||||
|
#import "MPPasswordsViewController.h"
|
||||||
|
|
||||||
|
@implementation MPPopdownSegue {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)perform {
|
||||||
|
|
||||||
|
MPPasswordsViewController *passwordsVC;
|
||||||
|
UIViewController *popdownVC;
|
||||||
|
if ([self.sourceViewController isKindOfClass:[MPPasswordsViewController class]]) {
|
||||||
|
passwordsVC = self.sourceViewController;
|
||||||
|
popdownVC = self.destinationViewController;
|
||||||
|
UIView *popdownView = popdownVC.view;
|
||||||
|
popdownView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
|
|
||||||
|
[passwordsVC addChildViewController:popdownVC];
|
||||||
|
[passwordsVC.popdownContainer addSubview:popdownView];
|
||||||
|
[passwordsVC.popdownContainer addConstraintsWithVisualFormats:@[ @"H:|[popdownView]|", @"V:|[popdownView]|" ] options:0
|
||||||
|
metrics:nil views:NSDictionaryOfVariableBindings(popdownView)];
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.3f animations:^{
|
||||||
|
passwordsVC.popdownToTopConstraint.priority = 1;
|
||||||
|
[passwordsVC.popdownToTopConstraint apply];
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
if (finished)
|
||||||
|
[popdownVC didMoveToParentViewController:passwordsVC];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
else if ([self.destinationViewController isKindOfClass:[MPPasswordsViewController class]]) {
|
||||||
|
popdownVC = self.sourceViewController;
|
||||||
|
passwordsVC = self.destinationViewController;
|
||||||
|
|
||||||
|
[popdownVC willMoveToParentViewController:nil];
|
||||||
|
[UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionOverrideInheritedDuration animations:^{
|
||||||
|
passwordsVC.popdownToTopConstraint.priority = UILayoutPriorityDefaultHigh;
|
||||||
|
[passwordsVC.popdownToTopConstraint apply];
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
if (finished) {
|
||||||
|
[popdownVC.view removeFromSuperview];
|
||||||
|
[popdownVC removeFromParentViewController];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -9,15 +9,17 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import "MPTypeViewController.h"
|
#import "MPTypeViewController.h"
|
||||||
|
|
||||||
@interface MPPreferencesViewController : UITableViewController<MPTypeDelegate>
|
@interface MPPreferencesViewController : UITableViewController
|
||||||
|
|
||||||
@property(weak, nonatomic) IBOutlet UIScrollView *avatarsView;
|
|
||||||
@property(weak, nonatomic) IBOutlet UIButton *avatarTemplate;
|
|
||||||
@property(weak, nonatomic) IBOutlet UISwitch *savePasswordSwitch;
|
@property(weak, nonatomic) IBOutlet UISwitch *savePasswordSwitch;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITableViewCell *feedbackCell;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITableViewCell *coachmarksCell;
|
||||||
@property(weak, nonatomic) IBOutlet UITableViewCell *exportCell;
|
@property(weak, nonatomic) IBOutlet UITableViewCell *exportCell;
|
||||||
@property(weak, nonatomic) IBOutlet UITableViewCell *changeMPCell;
|
@property(weak, nonatomic) IBOutlet UIImageView *avatarImage;
|
||||||
@property(weak, nonatomic) IBOutlet UILabel *defaultTypeLabel;
|
@property(weak, nonatomic) IBOutlet UISegmentedControl *typeControl;
|
||||||
|
|
||||||
- (IBAction)didToggleSwitch:(UISwitch *)sender;
|
- (IBAction)previousAvatar:(id)sender;
|
||||||
|
- (IBAction)nextAvatar:(id)sender;
|
||||||
|
- (IBAction)valueChanged:(id)sender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,12 +6,13 @@
|
|||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <QuartzCore/QuartzCore.h>
|
|
||||||
|
|
||||||
#import "MPPreferencesViewController.h"
|
#import "MPPreferencesViewController.h"
|
||||||
#import "MPiOSAppDelegate.h"
|
#import "MPiOSAppDelegate.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "UIColor+Expanded.h"
|
||||||
|
#import "MPPasswordsViewController.h"
|
||||||
|
#import "MPCoachmarkViewController.h"
|
||||||
|
|
||||||
@interface MPPreferencesViewController()
|
@interface MPPreferencesViewController()
|
||||||
|
|
||||||
@@ -21,158 +22,146 @@
|
|||||||
|
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
self.avatarTemplate.hidden = YES;
|
|
||||||
|
|
||||||
for (int a = 0; a < MPAvatarCount; ++a) {
|
|
||||||
UIButton *avatar = [self.avatarTemplate clone];
|
|
||||||
avatar.tag = a;
|
|
||||||
avatar.hidden = NO;
|
|
||||||
avatar.center = CGPointMake(
|
|
||||||
self.avatarTemplate.center.x * (a + 1) + self.avatarTemplate.bounds.size.width / 2 * a,
|
|
||||||
self.avatarTemplate.center.y );
|
|
||||||
[avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%d", a )]
|
|
||||||
forState:UIControlStateNormal];
|
|
||||||
[avatar setSelectionInSuperviewCandidate:YES isClearable:NO];
|
|
||||||
|
|
||||||
avatar.layer.cornerRadius = avatar.bounds.size.height / 2;
|
|
||||||
avatar.layer.shadowColor = [UIColor blackColor].CGColor;
|
|
||||||
avatar.layer.shadowOpacity = 1;
|
|
||||||
avatar.layer.shadowRadius = 5;
|
|
||||||
avatar.backgroundColor = [UIColor clearColor];
|
|
||||||
|
|
||||||
[avatar onHighlightOrSelect:^(BOOL highlighted, BOOL selected) {
|
|
||||||
if (highlighted || selected)
|
|
||||||
avatar.backgroundColor = self.avatarTemplate.backgroundColor;
|
|
||||||
else
|
|
||||||
avatar.backgroundColor = [UIColor clearColor];
|
|
||||||
} options:0];
|
|
||||||
[avatar onSelect:^(BOOL selected) {
|
|
||||||
if (selected) {
|
|
||||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
|
||||||
[[MPiOSAppDelegate get] activeUserInContext:moc].avatar = (unsigned)avatar.tag;
|
|
||||||
[moc saveToStore];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
} options:0];
|
|
||||||
avatar.selected = (a == [[MPiOSAppDelegate get] activeUserForMainThread].avatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
self.view.backgroundColor = [UIColor clearColor];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated {
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
inf(@"Preferences will appear");
|
inf(@"Preferences will appear");
|
||||||
[self.avatarsView autoSizeContent];
|
[super viewWillAppear:animated];
|
||||||
[self.avatarsView enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
|
||||||
if (subview.tag && ((UIControl *)subview).selected) {
|
|
||||||
[self.avatarsView setContentOffset:CGPointMake( subview.center.x - self.avatarsView.bounds.size.width / 2, 0 )
|
|
||||||
animated:animated];
|
|
||||||
}
|
|
||||||
} recurse:NO];
|
|
||||||
|
|
||||||
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
|
||||||
|
self.typeControl.selectedSegmentIndex = [self segmentIndexForType:activeUser.defaultType];
|
||||||
|
self.avatarImage.image = [UIImage imageNamed:strf( @"avatar-%ld", (long)activeUser.avatar )];
|
||||||
self.savePasswordSwitch.on = activeUser.saveKey;
|
self.savePasswordSwitch.on = activeUser.saveKey;
|
||||||
self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType];
|
|
||||||
|
|
||||||
[super viewWillAppear:animated];
|
self.tableView.contentInset = UIEdgeInsetsMake( 64, 0, 49, 0 );
|
||||||
}
|
|
||||||
|
|
||||||
- (void)viewDidAppear:(BOOL)animated {
|
|
||||||
|
|
||||||
#ifdef LOCALYTICS
|
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Preferences"];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[super viewDidAppear:animated];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)viewWillDisappear:(BOOL)animated {
|
|
||||||
|
|
||||||
inf(@"Preferences will disappear");
|
|
||||||
[super viewWillDisappear:animated];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)canBecomeFirstResponder {
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
|
|
||||||
|
|
||||||
if (motion == UIEventSubtypeMotionShake) {
|
|
||||||
MPCheckpoint( MPCheckpointLogs, @{
|
|
||||||
@"trace" : [MPiOSConfig get].traceMode
|
|
||||||
} );
|
|
||||||
[self performSegueWithIdentifier:@"MP_Logs" sender:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)shouldAutorotate {
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
|
||||||
|
|
||||||
return UIInterfaceOrientationPortrait;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
|
||||||
|
|
||||||
if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
|
|
||||||
((MPTypeViewController *)[segue destinationViewController]).delegate = self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - UITableViewDelegate
|
#pragma mark - UITableViewDelegate
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||||
|
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
|
||||||
|
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
|
||||||
|
cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRGBAHex:0x78DDFB33];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
|
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||||
|
if (cell == self.feedbackCell)
|
||||||
|
[[MPiOSAppDelegate get] showFeedbackWithLogs:YES forVC:self];
|
||||||
if (cell == self.exportCell)
|
if (cell == self.exportCell)
|
||||||
[[MPiOSAppDelegate get] export];
|
[[MPiOSAppDelegate get] showExportForVC:self];
|
||||||
|
if (cell == self.coachmarksCell) {
|
||||||
else if (cell == self.changeMPCell) {
|
for (UIViewController *vc = self; (vc = vc.parentViewController); )
|
||||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
if ([vc isKindOfClass:[MPPasswordsViewController class]]) {
|
||||||
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
|
MPPasswordsViewController *passwordsVC = (MPPasswordsViewController *)vc;
|
||||||
[[MPiOSAppDelegate get] changeMasterPasswordFor:activeUser saveInContext:moc didResetBlock:nil];
|
passwordsVC.coachmark.coached = NO;
|
||||||
}];
|
[passwordsVC dismissPopdown:self];
|
||||||
|
[vc performSegueWithIdentifier:@"coachmarks" sender:self];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - MPTypeDelegate
|
|
||||||
|
|
||||||
- (void)didSelectType:(MPElementType)type {
|
|
||||||
|
|
||||||
self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:type];
|
|
||||||
|
|
||||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
|
||||||
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
|
|
||||||
activeUser.defaultType = type;
|
|
||||||
[context saveToStore];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (MPElementType)selectedType {
|
|
||||||
|
|
||||||
return [[MPiOSAppDelegate get] activeUserForMainThread].defaultType;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - IBActions
|
#pragma mark - IBActions
|
||||||
|
|
||||||
- (IBAction)didToggleSwitch:(UISwitch *)sender {
|
- (IBAction)valueChanged:(id)sender {
|
||||||
|
|
||||||
if (sender == self.savePasswordSwitch)
|
if (sender == self.savePasswordSwitch)
|
||||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
|
||||||
if ((activeUser.saveKey = sender.on))
|
if ((activeUser.saveKey = self.savePasswordSwitch.on))
|
||||||
[[MPiOSAppDelegate get] storeSavedKeyFor:activeUser];
|
[[MPiOSAppDelegate get] storeSavedKeyFor:activeUser];
|
||||||
else
|
else
|
||||||
[[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser];
|
[[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser];
|
||||||
[moc saveToStore];
|
[context saveToStore];
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (sender == self.typeControl)
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType = [self typeForSelectedSegment];
|
||||||
|
[context saveToStore];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)previousAvatar:(id)sender {
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
|
||||||
|
activeUser.avatar = (activeUser.avatar - 1 + MPAvatarCount) % MPAvatarCount;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
long avatar = activeUser.avatar;
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
self.avatarImage.image = [UIImage imageNamed:strf( @"avatar-%ld", avatar )];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)nextAvatar:(id)sender {
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
|
||||||
|
activeUser.avatar = (activeUser.avatar + 1 + MPAvatarCount) % MPAvatarCount;
|
||||||
|
[context saveToStore];
|
||||||
|
|
||||||
|
long avatar = activeUser.avatar;
|
||||||
|
PearlMainQueue( ^{
|
||||||
|
self.avatarImage.image = [UIImage imageNamed:strf( @"avatar-%ld", avatar )];
|
||||||
|
} );
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (enum MPElementType)typeForSelectedSegment {
|
||||||
|
|
||||||
|
switch (self.typeControl.selectedSegmentIndex) {
|
||||||
|
case 0:
|
||||||
|
return MPElementTypeGeneratedMaximum;
|
||||||
|
case 1:
|
||||||
|
return MPElementTypeGeneratedLong;
|
||||||
|
case 2:
|
||||||
|
return MPElementTypeGeneratedMedium;
|
||||||
|
case 3:
|
||||||
|
return MPElementTypeGeneratedBasic;
|
||||||
|
case 4:
|
||||||
|
return MPElementTypeGeneratedShort;
|
||||||
|
case 5:
|
||||||
|
return MPElementTypeGeneratedPIN;
|
||||||
|
default:
|
||||||
|
Throw(@"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)segmentIndexForType:(MPElementType)type {
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MPElementTypeGeneratedMaximum:
|
||||||
|
return 0;
|
||||||
|
case MPElementTypeGeneratedLong:
|
||||||
|
return 1;
|
||||||
|
case MPElementTypeGeneratedMedium:
|
||||||
|
return 2;
|
||||||
|
case MPElementTypeGeneratedBasic:
|
||||||
|
return 3;
|
||||||
|
case MPElementTypeGeneratedShort:
|
||||||
|
return 4;
|
||||||
|
case MPElementTypeGeneratedPIN:
|
||||||
|
return 5;
|
||||||
|
default:
|
||||||
|
Throw(@"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
23
MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.h
Normal file
23
MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// MPPreferencesViewController.h
|
||||||
|
// MasterPassword-iOS
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 04/06/12.
|
||||||
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "MPTypeViewController.h"
|
||||||
|
|
||||||
|
@interface MPPreferencesViewControllerOld : UITableViewController<MPTypeDelegate>
|
||||||
|
|
||||||
|
@property(weak, nonatomic) IBOutlet UIScrollView *avatarsView;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIButton *avatarTemplate;
|
||||||
|
@property(weak, nonatomic) IBOutlet UISwitch *savePasswordSwitch;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITableViewCell *exportCell;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITableViewCell *changeMPCell;
|
||||||
|
@property(weak, nonatomic) IBOutlet UILabel *defaultTypeLabel;
|
||||||
|
|
||||||
|
- (IBAction)didToggleSwitch:(UISwitch *)sender;
|
||||||
|
|
||||||
|
@end
|
||||||
178
MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.m
Normal file
178
MasterPassword/ObjC/iOS/MPPreferencesViewControllerOld.m
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
//
|
||||||
|
// MPPreferencesViewController.m
|
||||||
|
// MasterPassword-iOS
|
||||||
|
//
|
||||||
|
// Created by Maarten Billemont on 04/06/12.
|
||||||
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
|
#import "MPPreferencesViewControllerOld.h"
|
||||||
|
#import "MPiOSAppDelegate.h"
|
||||||
|
#import "MPAppDelegate_Key.h"
|
||||||
|
#import "MPAppDelegate_Store.h"
|
||||||
|
|
||||||
|
@interface MPPreferencesViewControllerOld()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MPPreferencesViewControllerOld
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
|
self.avatarTemplate.hidden = YES;
|
||||||
|
|
||||||
|
for (NSUInteger a = 0; a < MPAvatarCount; ++a) {
|
||||||
|
UIButton *avatar = [self.avatarTemplate clone];
|
||||||
|
avatar.tag = a;
|
||||||
|
avatar.hidden = NO;
|
||||||
|
avatar.center = CGPointMake(
|
||||||
|
self.avatarTemplate.center.x * (a + 1) + self.avatarTemplate.bounds.size.width / 2 * a,
|
||||||
|
self.avatarTemplate.center.y );
|
||||||
|
[avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%ld", (long)a )]
|
||||||
|
forState:UIControlStateNormal];
|
||||||
|
[avatar setSelectionInSuperviewCandidate:YES isClearable:NO];
|
||||||
|
|
||||||
|
avatar.layer.cornerRadius = avatar.bounds.size.height / 2;
|
||||||
|
avatar.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||||
|
avatar.layer.shadowOpacity = 1;
|
||||||
|
avatar.layer.shadowRadius = 5;
|
||||||
|
avatar.backgroundColor = [UIColor clearColor];
|
||||||
|
|
||||||
|
[avatar onHighlightOrSelect:^(BOOL highlighted, BOOL selected) {
|
||||||
|
if (highlighted || selected)
|
||||||
|
avatar.backgroundColor = self.avatarTemplate.backgroundColor;
|
||||||
|
else
|
||||||
|
avatar.backgroundColor = [UIColor clearColor];
|
||||||
|
} options:0];
|
||||||
|
[avatar onSelect:^(BOOL selected) {
|
||||||
|
if (selected) {
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
|
[[MPiOSAppDelegate get] activeUserInContext:moc].avatar = (unsigned)avatar.tag;
|
||||||
|
[moc saveToStore];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
} options:0];
|
||||||
|
avatar.selected = (a == [[MPiOSAppDelegate get] activeUserForMainThread].avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
[super viewDidLoad];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
inf(@"Preferences will appear");
|
||||||
|
[self.avatarsView autoSizeContent];
|
||||||
|
[self.avatarsView enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
||||||
|
if (subview.tag && ((UIControl *)subview).selected) {
|
||||||
|
[self.avatarsView setContentOffset:CGPointMake( subview.center.x - self.avatarsView.bounds.size.width / 2, 0 )
|
||||||
|
animated:animated];
|
||||||
|
}
|
||||||
|
} recurse:NO];
|
||||||
|
|
||||||
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserForMainThread];
|
||||||
|
self.savePasswordSwitch.on = activeUser.saveKey;
|
||||||
|
self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:activeUser.defaultType];
|
||||||
|
|
||||||
|
[super viewWillAppear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
|
|
||||||
|
#ifdef LOCALYTICS
|
||||||
|
[[LocalyticsSession sharedLocalyticsSession] tagScreen:@"Preferences"];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillDisappear:(BOOL)animated {
|
||||||
|
|
||||||
|
inf(@"Preferences will disappear");
|
||||||
|
[super viewWillDisappear:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canBecomeFirstResponder {
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
|
||||||
|
|
||||||
|
if (motion == UIEventSubtypeMotionShake) {
|
||||||
|
MPCheckpoint( MPCheckpointLogs, @{
|
||||||
|
@"trace" : [MPiOSConfig get].traceMode
|
||||||
|
} );
|
||||||
|
[self performSegueWithIdentifier:@"MP_Logs" sender:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldAutorotate {
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||||
|
|
||||||
|
return UIInterfaceOrientationPortrait;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
|
||||||
|
if ([[segue identifier] isEqualToString:@"MP_ChooseType"])
|
||||||
|
((MPTypeViewController *)[segue destinationViewController]).delegate = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UITableViewDelegate
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||||
|
if (cell == self.exportCell)
|
||||||
|
[[MPiOSAppDelegate get] showExportForVC:self];
|
||||||
|
|
||||||
|
else if (cell == self.changeMPCell) {
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
|
||||||
|
[[MPiOSAppDelegate get] changeMasterPasswordFor:activeUser saveInContext:moc didResetBlock:nil];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - MPTypeDelegate
|
||||||
|
|
||||||
|
- (void)didSelectType:(MPElementType)type {
|
||||||
|
|
||||||
|
self.defaultTypeLabel.text = [[MPiOSAppDelegate get].key.algorithm shortNameOfType:type];
|
||||||
|
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:context];
|
||||||
|
activeUser.defaultType = type;
|
||||||
|
[context saveToStore];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (MPElementType)selectedType {
|
||||||
|
|
||||||
|
return [[MPiOSAppDelegate get] activeUserForMainThread].defaultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - IBActions
|
||||||
|
|
||||||
|
- (IBAction)didToggleSwitch:(UISwitch *)sender {
|
||||||
|
|
||||||
|
if (sender == self.savePasswordSwitch)
|
||||||
|
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
||||||
|
MPUserEntity *activeUser = [[MPiOSAppDelegate get] activeUserInContext:moc];
|
||||||
|
if ((activeUser.saveKey = sender.on))
|
||||||
|
[[MPiOSAppDelegate get] storeSavedKeyFor:activeUser];
|
||||||
|
else
|
||||||
|
[[MPiOSAppDelegate get] forgetSavedKeyFor:activeUser];
|
||||||
|
[moc saveToStore];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -54,12 +54,4 @@
|
|||||||
[self dismissViewControllerAnimated:YES completion:nil];
|
[self dismissViewControllerAnimated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)showGuide:(UIBarButtonItem *)sender {
|
|
||||||
|
|
||||||
[MPiOSConfig get].showSetup = @NO;
|
|
||||||
[self dismissViewControllerAnimated:YES completion:^{
|
|
||||||
[[MPiOSAppDelegate get] showGuide];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "LLGitTip.h"
|
||||||
|
|
||||||
@interface MPUnlockViewController : UIViewController<UITextFieldDelegate, UIScrollViewDelegate, UIWebViewDelegate>
|
@interface MPUnlockViewController : UIViewController<UITextFieldDelegate, UIScrollViewDelegate, UIWebViewDelegate>
|
||||||
|
|
||||||
@@ -26,6 +27,8 @@
|
|||||||
@property(strong, nonatomic) IBOutlet UILongPressGestureRecognizer *targetedUserActionGesture;
|
@property(strong, nonatomic) IBOutlet UILongPressGestureRecognizer *targetedUserActionGesture;
|
||||||
@property(weak, nonatomic) IBOutlet UIView *uiContainer;
|
@property(weak, nonatomic) IBOutlet UIView *uiContainer;
|
||||||
@property(weak, nonatomic) IBOutlet UIView *shareContainer;
|
@property(weak, nonatomic) IBOutlet UIView *shareContainer;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *tipsTipContainer;
|
||||||
|
@property(weak, nonatomic) IBOutlet LLGitTip *gitTipButton;
|
||||||
@property(weak, nonatomic) IBOutlet UIWebView *newsView;
|
@property(weak, nonatomic) IBOutlet UIWebView *newsView;
|
||||||
@property(weak, nonatomic) IBOutlet UIView *emergencyGeneratorContainer;
|
@property(weak, nonatomic) IBOutlet UIView *emergencyGeneratorContainer;
|
||||||
@property(weak, nonatomic) IBOutlet UITextField *emergencyName;
|
@property(weak, nonatomic) IBOutlet UITextField *emergencyName;
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Social/Social.h>
|
#import <Social/Social.h>
|
||||||
#import <QuartzCore/QuartzCore.h>
|
|
||||||
|
|
||||||
#import "MPUnlockViewController.h"
|
#import "MPUnlockViewController.h"
|
||||||
#import "MPiOSAppDelegate.h"
|
#import "MPiOSAppDelegate.h"
|
||||||
#import "MPAppDelegate_Key.h"
|
#import "MPAppDelegate_Key.h"
|
||||||
#import "MPAppDelegate_Store.h"
|
#import "MPAppDelegate_Store.h"
|
||||||
|
#import "LLGitTip.h"
|
||||||
|
|
||||||
@interface MPUnlockViewController()
|
@interface MPUnlockViewController()
|
||||||
|
|
||||||
@@ -26,12 +26,18 @@
|
|||||||
@property(nonatomic, strong) NSTimer *marqueeTipTimer;
|
@property(nonatomic, strong) NSTimer *marqueeTipTimer;
|
||||||
@property(nonatomic) NSUInteger marqueeTipTextIndex;
|
@property(nonatomic) NSUInteger marqueeTipTextIndex;
|
||||||
@property(nonatomic, strong) NSArray *marqueeTipTexts;
|
@property(nonatomic, strong) NSArray *marqueeTipTexts;
|
||||||
|
@property(nonatomic, strong) id mocObserver;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPUnlockViewController {
|
@implementation MPUnlockViewController {
|
||||||
NSManagedObjectID *_selectedUserOID;
|
NSManagedObjectID *_selectedUserOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
if (self.mocObserver)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self.mocObserver];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
|
- (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
|
||||||
|
|
||||||
UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake( 12, 30, 260, 150 )];
|
UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake( 12, 30, 260, 150 )];
|
||||||
@@ -40,15 +46,15 @@
|
|||||||
[alert addSubview:alertAvatarScrollView];
|
[alert addSubview:alertAvatarScrollView];
|
||||||
|
|
||||||
CGPoint selectedOffset = CGPointZero;
|
CGPoint selectedOffset = CGPointZero;
|
||||||
for (int a = 0; a < MPAvatarCount; ++a) {
|
for (NSUInteger a = 0; a < MPAvatarCount; ++a) {
|
||||||
UIButton *avatar = [self.avatarTemplate cloneAddedTo:alertAvatarScrollView];
|
UIButton *avatar = [self.avatarTemplate cloneAddedTo:alertAvatarScrollView];
|
||||||
|
|
||||||
avatar.tag = a;
|
avatar.tag = (NSInteger)a;
|
||||||
avatar.hidden = NO;
|
avatar.hidden = NO;
|
||||||
avatar.center = CGPointMake(
|
avatar.center = CGPointMake(
|
||||||
(20 + self.avatarTemplate.bounds.size.width / 2) * (a + 1) + self.avatarTemplate.bounds.size.width / 2 * a,
|
(20 + self.avatarTemplate.bounds.size.width / 2) * (a + 1) + self.avatarTemplate.bounds.size.width / 2 * a,
|
||||||
20 + self.avatarTemplate.bounds.size.height / 2 );
|
20 + self.avatarTemplate.bounds.size.height / 2 );
|
||||||
[avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%d", a )] forState:UIControlStateNormal];
|
[avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%ld", (long)a )] forState:UIControlStateNormal];
|
||||||
[avatar setSelectionInSuperviewCandidate:YES isClearable:NO];
|
[avatar setSelectionInSuperviewCandidate:YES isClearable:NO];
|
||||||
|
|
||||||
avatar.layer.cornerRadius = avatar.bounds.size.height / 2;
|
avatar.layer.cornerRadius = avatar.bounds.size.height / 2;
|
||||||
@@ -96,11 +102,7 @@
|
|||||||
UILabel *alertNameLabel = [self.nameLabel cloneAddedTo:container];
|
UILabel *alertNameLabel = [self.nameLabel cloneAddedTo:container];
|
||||||
alertNameLabel.center = alertAvatar.center;
|
alertNameLabel.center = alertAvatar.center;
|
||||||
alertNameLabel.text = user.name;
|
alertNameLabel.text = user.name;
|
||||||
alertNameLabel.bounds = CGRectSetHeight( alertNameLabel.bounds,
|
[alertNameLabel sizeToFit];
|
||||||
[alertNameLabel.text sizeWithFont:self.nameLabel.font
|
|
||||||
constrainedToSize:CGSizeMake( alertNameLabel.bounds.size.width - 10,
|
|
||||||
100 )
|
|
||||||
lineBreakMode:self.nameLabel.lineBreakMode].height );
|
|
||||||
alertNameLabel.layer.cornerRadius = 5;
|
alertNameLabel.layer.cornerRadius = 5;
|
||||||
alertNameLabel.backgroundColor = [UIColor blackColor];
|
alertNameLabel.backgroundColor = [UIColor blackColor];
|
||||||
}
|
}
|
||||||
@@ -122,6 +124,7 @@
|
|||||||
|
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
|
|
||||||
|
self.gitTipButton.iTunesID = [MPConfig get].iTunesID;
|
||||||
self.avatarToUserOID = [NSMutableDictionary dictionaryWithCapacity:3];
|
self.avatarToUserOID = [NSMutableDictionary dictionaryWithCapacity:3];
|
||||||
|
|
||||||
[self.avatarsView addGestureRecognizer:self.targetedUserActionGesture];
|
[self.avatarsView addGestureRecognizer:self.targetedUserActionGesture];
|
||||||
@@ -136,12 +139,12 @@
|
|||||||
self.emergencyGeneratorContainer.alpha = 0;
|
self.emergencyGeneratorContainer.alpha = 0;
|
||||||
self.emergencyGeneratorContainer.hidden = YES;
|
self.emergencyGeneratorContainer.hidden = YES;
|
||||||
self.emergencyQueue = [NSOperationQueue new];
|
self.emergencyQueue = [NSOperationQueue new];
|
||||||
[self.emergencyCounterStepper addTargetBlock:^(id sender, UIControlEvents event) {
|
[self.emergencyCounterStepper addTargetBlock:^(id sender, UIControlEvents event, id weakSelf) {
|
||||||
self.emergencyCounter.text = PearlString( @"%lu", (unsigned long)self.emergencyCounterStepper.value );
|
self.emergencyCounter.text = PearlString( @"%lu", (unsigned long)self.emergencyCounterStepper.value );
|
||||||
|
|
||||||
[self updateEmergencyPassword];
|
[self updateEmergencyPassword];
|
||||||
} forControlEvents:UIControlEventValueChanged];
|
} forControlEvents:UIControlEventValueChanged];
|
||||||
[self.emergencyTypeControl addTargetBlock:^(id sender, UIControlEvents event) {
|
[self.emergencyTypeControl addTargetBlock:^(id sender, UIControlEvents event, id weakSelf) {
|
||||||
[self updateEmergencyPassword];
|
[self updateEmergencyPassword];
|
||||||
} forControlEvents:UIControlEventValueChanged];
|
} forControlEvents:UIControlEventValueChanged];
|
||||||
self.emergencyContentTipContainer.alpha = 0;
|
self.emergencyContentTipContainer.alpha = 0;
|
||||||
@@ -159,11 +162,11 @@
|
|||||||
self.wordList = wordListLines;
|
self.wordList = wordListLines;
|
||||||
|
|
||||||
self.wordWall.alpha = 0;
|
self.wordWall.alpha = 0;
|
||||||
[self.wordWall enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
[self.wordWall enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
||||||
UILabel *wordLabel = (UILabel *)subview;
|
UILabel *wordLabel = (UILabel *)subview;
|
||||||
|
|
||||||
[self initializeWordLabel:wordLabel];
|
[self initializeWordLabel:wordLabel];
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
|
[[NSNotificationCenter defaultCenter] addObserverForName:USMStoreDidChangeNotification object:nil
|
||||||
queue:[NSOperationQueue mainQueue] usingBlock:
|
queue:[NSOperationQueue mainQueue] usingBlock:
|
||||||
@@ -225,6 +228,7 @@
|
|||||||
self.uiContainer.alpha = 0;
|
self.uiContainer.alpha = 0;
|
||||||
self.shareContainer.alpha = 0;
|
self.shareContainer.alpha = 0;
|
||||||
self.spinner.alpha = 0;
|
self.spinner.alpha = 0;
|
||||||
|
self.tipsTipContainer.alpha = 0;
|
||||||
|
|
||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
}
|
}
|
||||||
@@ -240,10 +244,12 @@
|
|||||||
|
|
||||||
[UIView animateWithDuration:1 animations:^{
|
[UIView animateWithDuration:1 animations:^{
|
||||||
self.uiContainer.alpha = 1;
|
self.uiContainer.alpha = 1;
|
||||||
} completion:^(BOOL finished) {
|
} completion:^(BOOL finished) {
|
||||||
if (finished)
|
if (finished)
|
||||||
[UIView animateWithDuration:1 animations:^{
|
[UIView animateWithDuration:1 animations:^{
|
||||||
self.shareContainer.alpha = 1;
|
self.shareContainer.alpha = 1;
|
||||||
|
if ([MPConfig get].firstVersionRun)
|
||||||
|
self.tipsTipContainer.alpha = 1;
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@@ -266,12 +272,6 @@
|
|||||||
[super viewWillDisappear:animated];
|
[super viewWillDisappear:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
|
||||||
|
|
||||||
if ([segue.identifier isEqualToString:@"MP_Settings"])
|
|
||||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)prefersStatusBarHidden {
|
- (BOOL)prefersStatusBarHidden {
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
@@ -282,6 +282,12 @@
|
|||||||
return UIStatusBarAnimationSlide;
|
return UIStatusBarAnimationSlide;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
|
||||||
|
if ([segue.identifier isEqualToString:@"MP_Settings"])
|
||||||
|
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)canBecomeFirstResponder {
|
- (BOOL)canBecomeFirstResponder {
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
@@ -310,6 +316,17 @@
|
|||||||
|
|
||||||
- (void)updateUsers {
|
- (void)updateUsers {
|
||||||
|
|
||||||
|
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
|
||||||
|
if (mainContext) {
|
||||||
|
if (self.mocObserver)
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self.mocObserver];
|
||||||
|
self.mocObserver = [[NSNotificationCenter defaultCenter]
|
||||||
|
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext
|
||||||
|
queue:nil usingBlock:^(NSNotification *note) {
|
||||||
|
[self updateUsers];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
[MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
[MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
|
||||||
@@ -347,7 +364,7 @@
|
|||||||
avatar.layer.shadowRadius = 20;
|
avatar.layer.shadowRadius = 20;
|
||||||
avatar.layer.masksToBounds = NO;
|
avatar.layer.masksToBounds = NO;
|
||||||
avatar.backgroundColor = [UIColor clearColor];
|
avatar.backgroundColor = [UIColor clearColor];
|
||||||
avatar.tag = user.avatar;
|
avatar.tag = (NSInteger)user.avatar;
|
||||||
|
|
||||||
[avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%lu", (unsigned long)user.avatar )]
|
[avatar setBackgroundImage:[UIImage imageNamed:PearlString( @"avatar-%lu", (unsigned long)user.avatar )]
|
||||||
forState:UIControlStateNormal];
|
forState:UIControlStateNormal];
|
||||||
@@ -367,7 +384,6 @@
|
|||||||
[self didSelectNewUserAvatar:avatar];
|
[self didSelectNewUserAvatar:avatar];
|
||||||
else if ([self setSelectedUser:user])
|
else if ([self setSelectedUser:user])
|
||||||
[self didToggleUserSelection];
|
[self didToggleUserSelection];
|
||||||
|
|
||||||
} options:0];
|
} options:0];
|
||||||
|
|
||||||
(self.avatarToUserOID)[[NSValue valueWithNonretainedObject:avatar]] = NilToNSNull([user objectID]);
|
(self.avatarToUserOID)[[NSValue valueWithNonretainedObject:avatar]] = NilToNSNull([user objectID]);
|
||||||
@@ -400,8 +416,7 @@
|
|||||||
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
|
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
|
||||||
|
|
||||||
if (![MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
if (![MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||||
MPUserEntity *newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass( [MPUserEntity class] )
|
MPUserEntity *newUser = [MPUserEntity insertNewObjectInContext:context];
|
||||||
inManagedObjectContext:context];
|
|
||||||
|
|
||||||
[self showNewUserNameAlertFor:newUser saveInContext:context completion:^(BOOL finished) {
|
[self showNewUserNameAlertFor:newUser saveInContext:context completion:^(BOOL finished) {
|
||||||
newUserAvatar.selected = NO;
|
newUserAvatar.selected = NO;
|
||||||
@@ -432,7 +447,7 @@
|
|||||||
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
|
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
|
||||||
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||||
[self showNewUserNameAlertFor:newUser saveInContext:context completion:completion];
|
[self showNewUserNameAlertFor:newUser saveInContext:context completion:completion];
|
||||||
} cancelTitle:@"Try Again" otherTitles:nil];
|
} cancelTitle:@"Try Again" otherTitles:nil];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +472,7 @@
|
|||||||
|
|
||||||
// Okay
|
// Okay
|
||||||
[self showNewUserConfirmationAlertFor:newUser saveInContext:context completion:completion];
|
[self showNewUserConfirmationAlertFor:newUser saveInContext:context completion:completion];
|
||||||
} cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
} cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showNewUserConfirmationAlertFor:(MPUserEntity *)newUser saveInContext:(NSManagedObjectContext *)context
|
- (void)showNewUserConfirmationAlertFor:(MPUserEntity *)newUser saveInContext:(NSManagedObjectContext *)context
|
||||||
@@ -570,7 +585,7 @@
|
|||||||
targetedUser = [self userForAvatar:targetedAvatar inContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
targetedUser = [self userForAvatar:targetedAvatar inContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.avatarsView enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
[self.avatarsView enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
||||||
if (![[self.avatarToUserOID allKeys] containsObject:[NSValue valueWithNonretainedObject:subview]])
|
if (![[self.avatarToUserOID allKeys] containsObject:[NSValue valueWithNonretainedObject:subview]])
|
||||||
// This subview is not one of the user avatars.
|
// This subview is not one of the user avatars.
|
||||||
return;
|
return;
|
||||||
@@ -579,10 +594,10 @@
|
|||||||
BOOL isTargeted = avatar == targetedAvatar;
|
BOOL isTargeted = avatar == targetedAvatar;
|
||||||
|
|
||||||
avatar.userInteractionEnabled = isTargeted;
|
avatar.userInteractionEnabled = isTargeted;
|
||||||
avatar.alpha = isTargeted? 1: [self selectedUserForThread]? 0.1: 0.4;
|
avatar.alpha = isTargeted? 1: [self selectedUserForThread]? 0.1F: 0.4F;
|
||||||
|
|
||||||
[self updateAvatarShadowColor:avatar isTargeted:isTargeted];
|
[self updateAvatarShadowColor:avatar isTargeted:isTargeted];
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
|
|
||||||
if (allowScroll) {
|
if (allowScroll) {
|
||||||
CGPoint targetContentOffset = CGPointMake(
|
CGPoint targetContentOffset = CGPointMake(
|
||||||
@@ -594,10 +609,7 @@
|
|||||||
|
|
||||||
// Lay out user name label.
|
// Lay out user name label.
|
||||||
self.nameLabel.text = targetedAvatar? (targetedUser? targetedUser.name: @"New User"): nil;
|
self.nameLabel.text = targetedAvatar? (targetedUser? targetedUser.name: @"New User"): nil;
|
||||||
self.nameLabel.bounds = CGRectSetHeight( self.nameLabel.bounds,
|
[self.nameLabel sizeToFit];
|
||||||
[self.nameLabel.text sizeWithFont:self.nameLabel.font
|
|
||||||
constrainedToSize:CGSizeMake( self.nameLabel.bounds.size.width - 10, 100 )
|
|
||||||
lineBreakMode:self.nameLabel.lineBreakMode].height );
|
|
||||||
self.oldNameLabel.bounds = self.nameLabel.bounds;
|
self.oldNameLabel.bounds = self.nameLabel.bounds;
|
||||||
if (completion)
|
if (completion)
|
||||||
completion( YES );
|
completion( YES );
|
||||||
@@ -605,22 +617,22 @@
|
|||||||
|
|
||||||
- (void)beginWordWallAnimation {
|
- (void)beginWordWallAnimation {
|
||||||
|
|
||||||
[self.wordWall enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
[self.wordWall enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
||||||
UILabel *wordLabel = (UILabel *)subview;
|
UILabel *wordLabel = (UILabel *)subview;
|
||||||
|
|
||||||
if (wordLabel.frame.origin.x < -self.wordWall.frame.size.width / 3) {
|
if (wordLabel.frame.origin.x < -self.wordWall.frame.size.width / 3) {
|
||||||
wordLabel.frame = CGRectSetX( wordLabel.frame, wordLabel.frame.origin.x + self.wordWall.frame.size.width );
|
wordLabel.frame = CGRectSetX( wordLabel.frame, wordLabel.frame.origin.x + self.wordWall.frame.size.width );
|
||||||
[self initializeWordLabel:wordLabel];
|
[self initializeWordLabel:wordLabel];
|
||||||
}
|
}
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
|
|
||||||
if (self.wordWallAnimating)
|
if (self.wordWallAnimating)
|
||||||
[UIView animateWithDuration:15 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
|
[UIView animateWithDuration:15 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||||
[self.wordWall enumerateSubviews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
[self.wordWall enumerateViews:^(UIView *subview, BOOL *stop, BOOL *recurse) {
|
||||||
UILabel *wordLabel = (UILabel *)subview;
|
UILabel *wordLabel = (UILabel *)subview;
|
||||||
|
|
||||||
wordLabel.frame = CGRectSetX( wordLabel.frame, wordLabel.frame.origin.x - self.wordWall.frame.size.width / 3 );
|
wordLabel.frame = CGRectSetX( wordLabel.frame, wordLabel.frame.origin.x - self.wordWall.frame.size.width / 3 );
|
||||||
} recurse:NO];
|
} recurse:NO];
|
||||||
} completion:^(BOOL finished) {
|
} completion:^(BOOL finished) {
|
||||||
if (finished)
|
if (finished)
|
||||||
[self beginWordWallAnimation];
|
[self beginWordWallAnimation];
|
||||||
@@ -629,7 +641,7 @@
|
|||||||
|
|
||||||
- (void)initializeWordLabel:(UILabel *)wordLabel {
|
- (void)initializeWordLabel:(UILabel *)wordLabel {
|
||||||
|
|
||||||
wordLabel.alpha = 0.05 + (random() % 35) / 100.0F;
|
wordLabel.alpha = 0.05F + (random() % 35) / 100.0F;
|
||||||
wordLabel.text = (self.wordList)[(NSUInteger)random() % [self.wordList count]];
|
wordLabel.text = (self.wordList)[(NSUInteger)random() % [self.wordList count]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,7 +717,7 @@
|
|||||||
|
|
||||||
- (void)setSpinnerActive:(BOOL)active {
|
- (void)setSpinnerActive:(BOOL)active {
|
||||||
|
|
||||||
PearlMainThread(^{
|
PearlMainQueue( ^{
|
||||||
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
|
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
|
||||||
rotate.toValue = [NSNumber numberWithDouble:2 * M_PI];
|
rotate.toValue = [NSNumber numberWithDouble:2 * M_PI];
|
||||||
rotate.duration = 5.0;
|
rotate.duration = 5.0;
|
||||||
@@ -731,7 +743,7 @@
|
|||||||
else
|
else
|
||||||
[self avatarForUser:[self selectedUserForThread]].backgroundColor = self.avatarTemplate.backgroundColor;
|
[self avatarForUser:[self selectedUserForThread]].backgroundColor = self.avatarTemplate.backgroundColor;
|
||||||
}];
|
}];
|
||||||
});
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateAvatarShadowColor:(UIButton *)avatar isTargeted:(BOOL)targeted {
|
- (void)updateAvatarShadowColor:(UIButton *)avatar isTargeted:(BOOL)targeted {
|
||||||
@@ -740,7 +752,7 @@
|
|||||||
if (![avatar.layer animationForKey:@"targetedShadow"]) {
|
if (![avatar.layer animationForKey:@"targetedShadow"]) {
|
||||||
CABasicAnimation *toShadowColorAnimation = [CABasicAnimation animationWithKeyPath:@"shadowColor"];
|
CABasicAnimation *toShadowColorAnimation = [CABasicAnimation animationWithKeyPath:@"shadowColor"];
|
||||||
toShadowColorAnimation.toValue = (__bridge id)(avatar.selected? self.avatarTemplate.backgroundColor
|
toShadowColorAnimation.toValue = (__bridge id)(avatar.selected? self.avatarTemplate.backgroundColor
|
||||||
: [UIColor whiteColor]).CGColor;
|
: [UIColor whiteColor]).CGColor;
|
||||||
toShadowColorAnimation.beginTime = 0.0f;
|
toShadowColorAnimation.beginTime = 0.0f;
|
||||||
toShadowColorAnimation.duration = 0.5f;
|
toShadowColorAnimation.duration = 0.5f;
|
||||||
toShadowColorAnimation.fillMode = kCAFillModeForwards;
|
toShadowColorAnimation.fillMode = kCAFillModeForwards;
|
||||||
@@ -1166,7 +1178,7 @@
|
|||||||
}
|
}
|
||||||
if (buttonIndex == [sheet firstOtherButtonIndex] + 3) {
|
if (buttonIndex == [sheet firstOtherButtonIndex] + 3) {
|
||||||
// Mailing List
|
// Mailing List
|
||||||
[PearlEMail sendEMailTo:@"masterpassword-join@lists.lyndir.com" subject:@"Subscribe"
|
[PearlEMail sendEMailTo:@"masterpassword-join@lists.lyndir.com" fromVC:self subject:@"Subscribe"
|
||||||
body:@"Press 'Send' now to subscribe to the Master Password mailing list.\n\n"
|
body:@"Press 'Send' now to subscribe to the Master Password mailing list.\n\n"
|
||||||
@"You'll be kept up-to-date on the evolution of and discussions revolving Master Password."];
|
@"You'll be kept up-to-date on the evolution of and discussions revolving Master Password."];
|
||||||
return;
|
return;
|
||||||
@@ -1194,8 +1206,11 @@
|
|||||||
|
|
||||||
NSError *error;
|
NSError *error;
|
||||||
MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error];
|
MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error];
|
||||||
if (!selectedUser)
|
if (!selectedUser) {
|
||||||
err(@"Failed to retrieve selected user: %@", error);
|
err(@"Failed to retrieve selected user: %@", error);
|
||||||
|
_selectedUserOID = nil;
|
||||||
|
[self updateUsers];
|
||||||
|
}
|
||||||
|
|
||||||
return selectedUser;
|
return selectedUser;
|
||||||
}
|
}
|
||||||
@@ -1207,8 +1222,11 @@
|
|||||||
|
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
if (selectedUser.objectID.isTemporaryID &&
|
if (selectedUser.objectID.isTemporaryID &&
|
||||||
![selectedUser.managedObjectContext obtainPermanentIDsForObjects:@[ selectedUser ] error:&error])
|
![selectedUser.managedObjectContext obtainPermanentIDsForObjects:@[ selectedUser ] error:&error]) {
|
||||||
err(@"Failed to obtain a permanent object ID after setting selected user: %@", error);
|
err(@"Failed to obtain a permanent object ID after setting selected user: %@", error);
|
||||||
|
_selectedUserOID = nil;
|
||||||
|
[self updateUsers];
|
||||||
|
}
|
||||||
|
|
||||||
_selectedUserOID = selectedUser.objectID;
|
_selectedUserOID = selectedUser.objectID;
|
||||||
return YES;
|
return YES;
|
||||||
|
|||||||
46
MasterPassword/ObjC/iOS/MPUsersViewController.h
Normal file
46
MasterPassword/ObjC/iOS/MPUsersViewController.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// MPCombinedViewController.h
|
||||||
|
// MPCombinedViewController
|
||||||
|
//
|
||||||
|
// Created by lhunath on 2014-03-08.
|
||||||
|
// Copyright, lhunath (Maarten Billemont) 2014. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "LLGitTip.h"
|
||||||
|
|
||||||
|
@interface MPUsersViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITextFieldDelegate>
|
||||||
|
|
||||||
|
@property (strong, nonatomic) IBOutlet UINavigationBar *navigationBar;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *userSelectionContainer;
|
||||||
|
@property(weak, nonatomic) IBOutlet UILabel *hintLabel;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *gitTipTip;
|
||||||
|
@property(weak, nonatomic) IBOutlet LLGitTip *gitTipButton;
|
||||||
|
@property(weak, nonatomic) IBOutlet UITextField *entryField;
|
||||||
|
@property(weak, nonatomic) IBOutlet UILabel *entryLabel;
|
||||||
|
@property(weak, nonatomic) IBOutlet UILabel *entryTipTitleLabel;
|
||||||
|
@property(weak, nonatomic) IBOutlet UILabel *entryTipSubtitleLabel;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *entryTipContainer;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *entryContainer;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIView *footerContainer;
|
||||||
|
@property(weak, nonatomic) IBOutlet UIActivityIndicatorView *storeLoadingActivity;
|
||||||
|
@property(weak, nonatomic) IBOutlet UICollectionView *avatarCollectionView;
|
||||||
|
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *navigationBarToTopConstraint;
|
||||||
|
@property (strong, nonatomic) IBOutlet UIButton *nextAvatarButton;
|
||||||
|
@property (strong, nonatomic) IBOutlet UIButton *previousAvatarButton;
|
||||||
|
|
||||||
|
@property(assign, nonatomic) BOOL active;
|
||||||
|
|
||||||
|
- (void)setActive:(BOOL)active animated:(BOOL)animated;
|
||||||
|
- (IBAction)changeAvatar:(UIButton *)sender;
|
||||||
|
|
||||||
|
@end
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user