Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
4ab6fbb
Remove Me accessibility lavels and identifiers
koke Nov 13, 2015
f9f966e
Merge branch 'develop' into feature/my-profile
koke Nov 16, 2015
4b02332
Merge branch 'develop' into feature/my-profile
koke Nov 17, 2015
5c8490c
Fixed Settings controller restoration
koke Nov 17, 2015
cd9d064
Add My Profile to Me
koke Nov 17, 2015
6619f94
Initial implementation of My Profile (read only)
koke Nov 17, 2015
1e91f98
Merge branch 'develop' into feature/my-profile
koke Nov 17, 2015
86ae455
ImmuTable v2
koke Nov 19, 2015
8b2bca6
Use an intermediate TypedImmuTableRow protocol
koke Nov 19, 2015
d2c1a16
Renamed Reusable protocol
koke Nov 19, 2015
c4902ca
ImmuTable v3: cell registration
koke Nov 19, 2015
fd90d4a
Moved app specific code to separate file
koke Nov 19, 2015
6aa5838
Implement edit actions for My Profile
koke Nov 19, 2015
63e084e
Merge branch 'develop' into feature/my-profile
koke Nov 19, 2015
732f7b7
Adds ImmuTable tests
koke Nov 20, 2015
e25a739
Remove header from test
koke Nov 20, 2015
0ab7917
Added Account Settings model and remote
koke Nov 20, 2015
5dff34b
Merge branch 'develop' into feature/my-profile
koke Nov 23, 2015
7436147
New data model for account settings
koke Nov 23, 2015
275a4b0
Adds nullability to AccountService
koke Nov 23, 2015
064604c
Adds missing @dynamic to WPAccount
koke Nov 23, 2015
dc54d70
Only call onValueChanged if the value actually changed
koke Nov 23, 2015
f9289a3
Added data/service layer for account settings
koke Nov 23, 2015
a6c2d38
Reuse editable row action handler
koke Nov 23, 2015
a0fbef0
Fixed cascade option on account settings
koke Nov 24, 2015
11c275a
Save My Profile changes
koke Nov 24, 2015
6b6e679
Merge branch 'develop' into feature/my-profile
koke Nov 25, 2015
24644d0
Merge branch 'develop' into feature/my-profile
koke Nov 25, 2015
56d22ec
Data model changes for account settings (v43)
koke Nov 25, 2015
eb3d35d
Added missing imports
koke Nov 25, 2015
f83498b
Merge branch 'develop' into feature/my-profile
koke Nov 26, 2015
448e102
Moved dataSource/delegate to ImmuTable
koke Nov 27, 2015
1565343
Refactored generic code into ImmuTableViewController
koke Nov 27, 2015
140bcb5
Fixed retain cycle on row action
koke Nov 27, 2015
1ce6954
Added some more custom cells
koke Nov 27, 2015
3145ee3
Merge branch 'develop' into feature/my-profile
koke Nov 30, 2015
cc39339
Use a handler instead of inheritance for ImmuTable
koke Nov 30, 2015
e8da51b
Fix typo
koke Dec 1, 2015
381fd33
Fix typo, take 2
koke Dec 1, 2015
5cdda3f
Removed extra `self`
koke Dec 2, 2015
0e50b11
Fix retain cycle on settings subscription
koke Dec 2, 2015
b153a99
Shorter syntax on closures
koke Dec 4, 2015
43190d1
Added translation comment
koke Dec 4, 2015
b77fe2b
s/accountID/userID/ for clarity
koke Dec 4, 2015
42c39e7
Reorganised managed object in separate files
koke Dec 4, 2015
68aa087
Shorter syntax on closures
koke Dec 4, 2015
0a08dff
Merge branch 'develop' into feature/my-profile
koke Dec 4, 2015
eb3af9f
Merge branch 'develop' into feature/my-profile
koke Dec 10, 2015
2e02293
Merge branch 'develop' into feature/my-profile
koke Dec 10, 2015
fbd65ff
Track when my profile is opened
koke Dec 10, 2015
74cb4c0
Merge branch 'develop' into feature/my-profile
koke Dec 16, 2015
09e3005
Use WPAppAnalytics
koke Dec 16, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 0 additions & 116 deletions WordPress/Classes/Models/AccountSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,90 +15,6 @@ struct AccountSettings {
let language: String // language
}

class ManagedAccountSettings: NSManagedObject {
static let entityName = "AccountSettings"

@NSManaged var firstName: String
@NSManaged var lastName: String
@NSManaged var displayName: String
@NSManaged var aboutMe: String

@NSManaged var username: String
@NSManaged var email: String
@NSManaged var primarySiteID: Int
@NSManaged var webAddress: String
@NSManaged var language: String

@NSManaged var account: WPAccount

func updateWith(accountSettings: AccountSettings) {
firstName = accountSettings.firstName
lastName = accountSettings.lastName
displayName = accountSettings.displayName
aboutMe = accountSettings.aboutMe

username = accountSettings.username
email = accountSettings.email
primarySiteID = accountSettings.primarySiteID
webAddress = accountSettings.webAddress
language = accountSettings.language
}

/**
Applies a change to the account settings

To change a setting, you create a change and apply it to the AccountSettings object.
This method will return a new change object to apply if you want to revert the changes (for instance, if they failed to save)

- returns: the change object needed to revert this change
*/
func applyChange(change: AccountSettingsChange) -> AccountSettingsChange {
let reverse = reverseChange(change)

switch change {
case .FirstName(let value):
self.firstName = value
case .LastName(let value):
self.lastName = value
case .DisplayName(let value):
self.displayName = value
case .AboutMe(let value):
self.aboutMe = value
case .Email(let value):
self.email = value
case .PrimarySite(let value):
self.primarySiteID = value
case .WebAddress(let value):
self.webAddress = value
case .Language(let value):
self.language = value
}

return reverse
}

private func reverseChange(change: AccountSettingsChange) -> AccountSettingsChange {
switch change {
case .FirstName(_):
return .FirstName(self.firstName)
case .LastName(_):
return .LastName(self.lastName)
case .DisplayName(_):
return .DisplayName(self.displayName)
case .AboutMe(_):
return .AboutMe(self.aboutMe)
case .Email(_):
return .Email(self.email)
case .PrimarySite(_):
return .PrimarySite(self.primarySiteID)
case .WebAddress(_):
return .WebAddress(self.webAddress)
case .Language(_):
return .Language(self.language)
}
}
}

extension AccountSettings {
init(managed: ManagedAccountSettings) {
firstName = managed.firstName
Expand All @@ -113,35 +29,3 @@ extension AccountSettings {
language = managed.language
}
}

enum AccountSettingsChange {
case FirstName(String)
case LastName(String)
case DisplayName(String)
case AboutMe(String)
case Email(String)
case PrimarySite(Int)
case WebAddress(String)
case Language(String)

var stringValue: String {
switch self {
case .FirstName(let value):
return value
case .LastName(let value):
return value
case .DisplayName(let value):
return value
case .AboutMe(let value):
return value
case .Email(let value):
return value
case .PrimarySite(let value):
return String(value)
case .WebAddress(let value):
return value
case .Language(let value):
return value
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation
import CoreData

extension ManagedAccountSettings {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still find a bit weird that the properties that define an object are in an extension, and the helper methods in the class

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its sort of a take on Protocol-Based Programming in Swift. We should, ideally, be regenerating those Core Data accessors and not manually adding the properties to the classes. Over time those generated properties will change based upon newer best practices - this forces us to keep those accessors that would normally get overwritten separate.

I like/hate it too. 😄

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the separation. I just think the contents of the class/extension should be swapped. My main reason is that none of the code currently in the class would work if you take away the extension, but not the other way around

@NSManaged var firstName: String
@NSManaged var lastName: String
@NSManaged var displayName: String
@NSManaged var aboutMe: String

@NSManaged var username: String
@NSManaged var email: String
@NSManaged var primarySiteID: Int
@NSManaged var webAddress: String
@NSManaged var language: String

@NSManaged var account: WPAccount
}
105 changes: 105 additions & 0 deletions WordPress/Classes/Models/ManagedAccountSettings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import Foundation
import CoreData

class ManagedAccountSettings: NSManagedObject {
static let entityName = "AccountSettings"

func updateWith(accountSettings: AccountSettings) {
firstName = accountSettings.firstName
lastName = accountSettings.lastName
displayName = accountSettings.displayName
aboutMe = accountSettings.aboutMe

username = accountSettings.username
email = accountSettings.email
primarySiteID = accountSettings.primarySiteID
webAddress = accountSettings.webAddress
language = accountSettings.language
}

/**
Applies a change to the account settings

To change a setting, you create a change and apply it to the AccountSettings object.
This method will return a new change object to apply if you want to revert the changes (for instance, if they failed to save)

- returns: the change object needed to revert this change
*/
func applyChange(change: AccountSettingsChange) -> AccountSettingsChange {
let reverse = reverseChange(change)

switch change {
case .FirstName(let value):
self.firstName = value
case .LastName(let value):
self.lastName = value
case .DisplayName(let value):
self.displayName = value
case .AboutMe(let value):
self.aboutMe = value
case .Email(let value):
self.email = value
case .PrimarySite(let value):
self.primarySiteID = value
case .WebAddress(let value):
self.webAddress = value
case .Language(let value):
self.language = value
}

return reverse
}

private func reverseChange(change: AccountSettingsChange) -> AccountSettingsChange {
switch change {
case .FirstName(_):
return .FirstName(self.firstName)
case .LastName(_):
return .LastName(self.lastName)
case .DisplayName(_):
return .DisplayName(self.displayName)
case .AboutMe(_):
return .AboutMe(self.aboutMe)
case .Email(_):
return .Email(self.email)
case .PrimarySite(_):
return .PrimarySite(self.primarySiteID)
case .WebAddress(_):
return .WebAddress(self.webAddress)
case .Language(_):
return .Language(self.language)
}
}
}

enum AccountSettingsChange {
case FirstName(String)
case LastName(String)
case DisplayName(String)
case AboutMe(String)
case Email(String)
case PrimarySite(Int)
case WebAddress(String)
case Language(String)

var stringValue: String {
switch self {
case .FirstName(let value):
return value
case .LastName(let value):
return value
case .DisplayName(let value):
return value
case .AboutMe(let value):
return value
case .Email(let value):
return value
case .PrimarySite(let value):
return String(value)
case .WebAddress(let value):
return value
case .Language(let value):
return value
}
}
}
2 changes: 2 additions & 0 deletions WordPress/Classes/Models/WPAccount.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#import "WordPressComApi.h"

@class Blog;
@class ManagedAccountSettings;

@interface WPAccount : NSManagedObject

Expand All @@ -21,6 +22,7 @@
@property (nonatomic, strong) NSSet *jetpackBlogs;
@property (nonatomic, readonly) NSArray *visibleBlogs;
@property (nonatomic, strong) Blog *defaultBlog;
@property (nonatomic, strong) ManagedAccountSettings *managedSettings;

/**
The OAuth2 auth token for WordPress.com accounts
Expand Down
1 change: 1 addition & 0 deletions WordPress/Classes/Models/WPAccount.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ @implementation WPAccount
@dynamic displayName;
@dynamic userID;
@dynamic avatarURL;
@dynamic managedSettings;
@synthesize restApi = _restApi;

#pragma mark - NSManagedObject subclass methods
Expand Down
85 changes: 85 additions & 0 deletions WordPress/Classes/Networking/AccountSettingsRemote.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import Foundation

class AccountSettingsRemote: ServiceRemoteREST {
func getSettings(success success: AccountSettings -> Void, failure: ErrorType -> Void) {
let endpoint = "me/settings"
let path = pathForEndpoint(endpoint, withVersion: ServiceRemoteRESTApiVersion_1_1)

api.GET(path,
parameters: nil,
success: {
operation, responseObject in

do {
let settings = try self.settingsFromResponse(responseObject)
success(settings)
} catch {
failure(error)
}
},
failure: { operation, error in
failure(error)
})
}

func updateSetting(change: AccountSettingsChange, success: () -> Void, failure: ErrorType -> Void) {
let endpoint = "me/settings"
let path = pathForEndpoint(endpoint, withVersion: ServiceRemoteRESTApiVersion_1_1)
let parameters = [fieldNameForChange(change): change.stringValue]

api.POST(path,
parameters: parameters,
success: {
operation, responseObject in

success()
},
failure: { operation, error in
failure(error)
})
}

private func settingsFromResponse(responseObject: AnyObject) throws -> AccountSettings {
guard let
response = responseObject as? [String: AnyObject],
firstName = response["first_name"] as? String,
lastName = response["last_name"] as? String,
displayName = response["display_name"] as? String,
aboutMe = response["description"] as? String,
username = response["user_login"] as? String,
email = response["user_email"] as? String,
primarySiteID = response["primary_site_ID"] as? Int,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is primary site ID required? I can create a WordPress.com account without any sites.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch. I think when I wrote this there was still no documentation for /me/settings. Docs aren't very explicit about it, but I tried on an account with no sites and it returns 0.

I'm not doing anything with this for profile, but I wanted to get the extra properties in since Account Settings is next

webAddress = response["user_URL"] as? String,
language = response["language"] as? String else {
DDLogSwift.logError("Error decoding me/settings response: \(responseObject)")
throw Error.DecodeError
}

return AccountSettings(firstName: firstName, lastName: lastName, displayName: displayName, aboutMe: aboutMe, username: username, email: email, primarySiteID: primarySiteID, webAddress: webAddress, language: language)
}

private func fieldNameForChange(change: AccountSettingsChange) -> String {
switch change {
case .FirstName(_):
return "first_name"
case .LastName(_):
return "last_name"
case .DisplayName(_):
return "display_name"
case .AboutMe(_):
return "description"
case .Email(_):
return "email"
case .PrimarySite(_):
return "primary_site_ID"
case .WebAddress(_):
return "user_URL"
case .Language(_):
return "language"
}
}

enum Error: ErrorType {
case DecodeError
}
}
10 changes: 9 additions & 1 deletion WordPress/Classes/Services/AccountService.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,15 @@ extern NSString *const WPAccountEmailAndDefaultBlogUpdatedNotification;
@param username the account's username
@return a `WPAccount` object if there's one for the specified username. Otherwise it returns nil
*/
- (WPAccount *)findAccountWithUsername:(NSString *)username;
- (nullable WPAccount *)findAccountWithUsername:(NSString *)username;

/**
Returns a WordPress.com account with the specified user ID, if it exists

@param userID the account's user ID
@return a `WPAccount` object if there's one for the specified username. Otherwise it returns nil
*/
- (nullable WPAccount *)findAccountWithUserID:(NSNumber *)userID;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the new nullability qualifiers in Objective-C!


/**
Updates user details including username, email, userID, avatarURL, and default blog.
Expand Down
10 changes: 10 additions & 0 deletions WordPress/Classes/Services/AccountService.m
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,16 @@ - (WPAccount *)findAccountWithUsername:(NSString *)username
return [results firstObject];
}

- (WPAccount *)findAccountWithUserID:(NSNumber *)userID
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Account"];
[request setPredicate:[NSPredicate predicateWithFormat:@"userID = %@", userID]];
[request setIncludesPendingChanges:YES];

NSArray *results = [self.managedObjectContext executeFetchRequest:request error:nil];
return [results firstObject];
}

- (void)updateUserDetailsForAccount:(WPAccount *)account success:(void (^)())success failure:(void (^)(NSError *error))failure
{
NSAssert(account, @"Account can not be nil");
Expand Down
Loading