I found the solution.
First of all, I had to remove the @IBInspectable from my code to avoid setting those values in Storyboard.
Then, I found a way to dynamically change the style when the user switches dark mode on or off.
So, the update code following the Apple Human Interface Guidelines is:
class MyAuthorizationAppleIDButton: UIButton {
private var authorizationButton: ASAuthorizationAppleIDButton!
var cornerRadius: CGFloat = 3.0
var authButtonType: Int = ASAuthorizationAppleIDButton.ButtonType.default.rawValue
var authButtonStyle: Int = UITraitCollection.current.userInterfaceStyle == .dark ? 0 : 2
override public init(frame: CGRect) {
super.init(frame: frame)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override public func draw(_ rect: CGRect) {
super.draw(rect)
// Create ASAuthorizationAppleIDButton
authorizationButton = ASAuthorizationAppleIDButton(authorizationButtonType: .signIn, authorizationButtonStyle: .black)
let type = ASAuthorizationAppleIDButton.ButtonType.init(rawValue: authButtonType) ?? .default
let style = ASAuthorizationAppleIDButton.Style.init(rawValue: authButtonStyle) ?? .black
authorizationButton = ASAuthorizationAppleIDButton(authorizationButtonType: type, authorizationButtonStyle: style)
authorizationButton.cornerRadius = cornerRadius
// Show authorizationButton
addSubview(authorizationButton)
// Use auto layout to make authorizationButton follow the MyAuthorizationAppleIDButton's dimension
authorizationButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
authorizationButton.topAnchor.constraint(equalTo: self.topAnchor, constant: 0.0),
authorizationButton.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0.0),
authorizationButton.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0.0),
authorizationButton.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0.0),
])
}
}
Post
Replies
Boosts
Views
Activity
On screen C, I have this piece of code to update an object.
func updateApplicationName(appl_name: String, secret_key: String, updatedApplication: String, updateAccount: String) {
do {
var account: AuthentAccount?
let fetchAccount: NSFetchRequest<AuthentAccount> = AuthentAccount.fetchRequest()
let key128 = "#############" // 16 bytes for AES128
let iviv = "#############" // 16 bytes for AES128
let aes128 = AES(key: key128, iv: iviv)
let encryptedSecretKey = aes128?.encrypt(string: secret_key)?.base32EncodedString
let encryptedApplicationName = aes128?.encrypt(string: appl_name)?.base32EncodedString
let encryptedUpdatedApplicationName = aes128?.encrypt(string: updatedApplication)?.base32EncodedString
let encryptedUpdatedAccount = aes128?.encrypt(string: updateAccount)?.base32EncodedString
let applicationNamePredicate = NSPredicate(format: "applicationName = %@", encryptedApplicationName!)
let secretKeyPredicate = NSPredicate(format: "secretKey = %@", encryptedSecretKey!)
let andPredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.and, subpredicates: [applicationNamePredicate, secretKeyPredicate])
fetchAccount.predicate = andPredicate
let results = try? context.fetch(fetchAccount)
if results?.count != 0 {
// here you are updating
account = results?.first
}
account?.applicationName = encryptedUpdatedApplicationName
account?.accountName = encryptedUpdatedAccount
try context.save()
}
catch {
}
self.accountSettingsDelegate?.updateApplicationName(text: self.appl_name)
self.accountSettingsDelegate?.updateAccountName(text: self.acc_name)
}
@deeje So, as far as I understand you are suggesting to create a new context for the screens B and C and let the "main" context on screen A ?
@Claude31
The following code is on screen A when I am trying to fetch data from Core Data:
` func getAccounts() {
self.accounts = []
self.noAccountsCells = []
let fetchRequest: NSFetchRequest<AuthentAccount> = AuthentAccount.fetchRequest()
do {
self.accountList = []
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "applicationName", ascending: true)]
self.accountList = try context.fetch(AuthentAccount.fetchRequest())
let key128 = "#############" // 16 bytes for AES128
let iv = "#############" // 16 bytes for AES128
let aes128 = AES(key: key128, iv: iv)
let accList = try context.fetch(fetchRequest)
accList.forEach({ account in
let decryptAccountName = aes128?.decrypt(data: account.accountName?.base32DecodedData)!
let decryptApplicationName = aes128?.decrypt(data: account.applicationName?.base32DecodedData)!
})
self.accountList = try context.fetch(fetchRequest)
if self.accountList.isEmpty {
UserDefaults.standard.setNoAccountsState(value: true)
}
else {
UserDefaults.standard.setNoAccountsState(value: false)
}
print("AccountList: \(accountList.count)")
for account in accountList {
guard let encryptedName = account.accountName, let encryptedIssuer = account.issuer, let encryptedAppl_name = account.applicationName, let encryptedSecretKey = account.secretKey, let encryptedDigits = account.digits, let encryptedPeriod = account.period, let encryptedCounter = account.counter, let encryptedOtpType = account.otpType, let encryptedAlgorithm = account.algorithm else {
return
}
var otpType: OTPType = .totp
var algorithm: OTPAlgorithm = .sha1
let key128 = "###########" // 16 bytes for AES128
let iv = "###########" // 16 bytes for AES128
let aes128 = AES(key: key128, iv: iv)
let decryptAccountName = aes128?.decrypt(data: encryptedName.base32DecodedData)!
let decryptIssuer = aes128?.decrypt(data: encryptedIssuer.base32DecodedData)!
let decryptApplicationName = aes128?.decrypt(data: encryptedAppl_name.base32DecodedData)!
let decryptSecretKey = aes128?.decrypt(data: encryptedSecretKey.base32DecodedData)!
let decryptDigits = aes128?.decrypt(data: encryptedDigits.base32DecodedData)!
let decryptPeriod = aes128?.decrypt(data: encryptedPeriod.base32DecodedData)!
let decryptCounter = aes128?.decrypt(data: encryptedCounter.base32DecodedData)!
let decryptOtpType = aes128?.decrypt(data: encryptedOtpType.base32DecodedData)
let decryptAlgorithm = aes128?.decrypt(data: encryptedAlgorithm.base32DecodedData)
if decryptOtpType == "HOTP" {
otpType = .hotp
}
if decryptAlgorithm == "SHA256" {
algorithm = .sha256
}
else {
if decryptAlgorithm == "SHA512" {
algorithm = .sha512
}
}
if self.accounts.isEmpty {
self.accounts.append(AccountsTypeModel(account: nil, cellType: .empty))
}
self.accounts.append(AccountsTypeModel(account: AccountModel(account_name: decryptAccountName, issuer: decryptIssuer, application_name: decryptApplicationName!, secretKey: decryptSecretKey!, period: TimeInterval(decryptPeriod!), digits: Int(decryptDigits ?? "6") ?? 6, algorithm: algorithm, otpType: otpType, counter: Int64(decryptCounter!)), cellType: .cell))
self.accounts.append(AccountsTypeModel(account: nil, cellType: .separator))
}
if !self.accounts.isEmpty {
self.accounts.append(AccountsTypeModel(account: nil, cellType: .empty))
}
self.accounts.forEach({ account in
print("Accountss - \(account.account?.application_name)")
print("Accountss - \(account.account?.account_name)")
})
}
catch {
// error
}
}`
As I said before, on screen A I refresh the tableView on viewWillAppear method after I am calling the getAccounts method:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.getAccounts()
if self.accountList.isEmpty {
self.setup()
}
self.setupNavigationItems()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
Also, on UITableViewDataSource method I have this piece of code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if UserDefaults.standard.noAccounts() {
return noAccountsCells.count
}
else {
return accounts.count
}
}
It's UIKit