How to add two value by using UserDefault - swift

I'm trying to make a simple ToDo app in Swift.
I want to add not only task but also Date,
but I don't know how to add two values to a variable.
I want to add a text which get from UIDatePicker to TodoAdded.
Could you give me any advise please?
import UIKit
//Variable
var TodoAdded = [String]()
class AddController: UIViewController {
//TextField
#IBOutlet weak var TodoTextField: UITextField!
//TextField for Date
#IBOutlet weak var DateTextField: UITextField!
var datePicker: UIDatePicker = UIDatePicker()
//追加ボタンの設定
#IBAction func TodoAddButten(_ sender: Any) {
//Add typed text to variable
TodoAdded.append(TodoTextField.text!)
//Empty after tapped button
TodoTextField.text = ""
//Add to UD
UserDefaults.standard.set( TodoAdded, forKey: "TodoList" )
}
override func viewDidLoad() {
super.viewDidLoad()
// Picker Setting
datePicker.datePickerMode = UIDatePicker.Mode.dateAndTime
datePicker.timeZone = NSTimeZone.local
datePicker.locale = Locale.current
DateTextField.inputView = datePicker
//
let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 35))
let spacelItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(done))
toolbar.setItems([spacelItem, doneItem], animated: true)
// InputView
DateTextField.inputView = datePicker
DateTextField.inputAccessoryView = toolbar
}
//
#objc func done() {
DateTextField.endEditing(true)
// Format
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
DateTextField.text = "\(formatter.string(from: Date()))"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

You can try to save it as [String:[String]]
UserDefaults.standard.set([dateTextField.text!:todoAdded], forKey: "TodoList" )
A good approach is
struct Root:Codable {
let date:Date
let tasks:[String]
}
Then use JSONDecoder / JSONEncoder to convert to object / data , after that you can easily save / read them

Related

NSAttributedString not changing colour of certain text of NSTextview

I’m using NSAttributedString to change the text color of my NSTextview. When I want to change the color of a word, the color will not show. Here is my code for more detail
let main_string = “Hello World"
let string_to_color = “World"
let range = (main_string as NSString).range(of: string_to_color)
textView.textStorage?.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.orange, range: range);
When I want the change the text Colour of another string,
let main_string = "Hello World"
let string_to_color = "World"
let range = (main_string as NSString).range(of: string_to_color)
textView.textStorage?.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.orange, range: range)
let jhgfds = "Lorem Ipsum"
let tdftgdg = "ipsum"
let raresrgsdnge = (jhgfds as NSString).range(of: tdftgdg)
textView.textStorage?.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.orange, range: range)
This is what happens
Can you please help me with this
Here is my full code…
import Cocoa
import WebKit
class ViewController: NSViewController, NSTextViewDelegate {
struct Keys {
static let noteBook = "noteTaking"
static let title = "appTitle"
}
#IBOutlet weak var livePreviewOn: NSButton!
var isPaused = true
var timer = Timer()
#IBOutlet var textView: NSTextView!
let defaults = UserDefaults.standard
#IBOutlet weak var webView: WKWebView!
#IBOutlet weak var scrollView: NSScrollView!
/// - Tag: setRepresentedObjectExample
override var representedObject: Any? {
didSet {
// Pass down the represented object to all of the child view controllers.
for child in children {
child.representedObject = representedObject
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
scrollView.magnification = 1.5
textView.isAutomaticQuoteSubstitutionEnabled = false
checkSavedText()
Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(self.updater), userInfo: nil, repeats: true)
}
#IBAction func pauseResume(sender: AnyObject) {
if isPaused{
timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
isPaused = false
} else {
timer.invalidate()
isPaused = true
}
}
#IBAction func saveBTN(_ sender: Any) {
saveNoteBookText()
}
func saveNoteBookText() {
defaults.set(textView.string, forKey: Keys.noteBook)
}
func checkSavedText() {
let name = defaults.value(forKey: Keys.noteBook) as? String ?? ""
textView.string = name
}
#objc func update() {
saveBTN(self)
webView.loadHTMLString(textView.string, baseURL: nil)
}
#objc func updater() {
saveBTN(self)
let main_string = "Hello World"
let string_to_color = "World"
let range = (textView.textStorage!.string as NSString).range(of: string_to_color)
textView.textStorage?.addAttribute(NSAttributedString.Key.foregroundColor, value: NSColor.orange, range: range)
}
}

Centering a view with auto constraints - Swift

I am creating an XIB/class of datePicker which is called programatically from a calling viewController when the user taps a button. How can I use auto constraints to place this view immediately below and aligned with the centre of the calling button. My code works in portrait, but fails when the device is rotated (the datePicker does not re-center). Probably because I am passing a CGRect as an argument on init of the view, which doesn't change on rotate. I can't see any other way of overriding the passing of CGRect. When I add in auto constraints code, I get run-time auto formatting errors.
ViewController:
#IBAction func showMyDatePicker(_ sender: Any) {
showMyDatePicker.isEnabled = false
let today = Date()
let minDate = Calendar.current.date(byAdding: .month, value: -3, to: today)
let maxDate = Calendar.current.date(byAdding: .month, value: 3, to: today)
let datePickerWidth = 300
let datePickerHeight = 200
let datePickerX = Int(showMyDatePicker.center.x - CGFloat(datePickerWidth / 2))
let datePickerY = Int(showMyDatePicker.center.y + CGFloat(showMyDatePicker.bounds.height / 2))
let frame = CGRect(x: datePickerX, y: datePickerY, width: datePickerWidth, height: datePickerHeight)
myDatePicker = MyDatePicker(frame: frame)
myDatePicker?.setMyDatePicker(date: today, minimumDate: minDate!, maximumDate: maxDate!)
myDatePicker?.delegate = self
self.view.addSubview(myDatePicker!)
}
datePickerClass:
class MyDatePicker: UIView {
var delegate: MyDatePickerDelegate?
#IBOutlet var contentView: UIView!
#IBOutlet weak var datePicker: UIDatePicker!
#IBOutlet weak var returnButton: UIButton!
#IBAction func datePickerChanged(_ sender: Any) {
delegate?.dateFromDatePicker(date: datePicker.date, closeDatePickerView: false)
}
#IBAction func returnButtonTapped(_ sender: Any) {
delegate?.dateFromDatePicker(date: datePicker.date, closeDatePickerView: true)
}
override init(frame: CGRect) {
super.init(frame: frame)
initView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
initView()
}
private func initView() {//QUESTION: how can I set the datepicker initial values within here
// Instantiate the view from xib file
let contentView = Bundle.main.loadNibNamed("MyDatePicker", owner: self, options: nil)?.first as? UIView
// Check that it's not nil
guard contentView != nil else {
return
}
// Add the view and set its frame
addSubview(contentView!)
contentView?.frame = self.bounds
contentView?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
func setMyDatePicker(date: Date, minimumDate: Date, maximumDate: Date) {
datePicker.date = date
datePicker.minimumDate = minimumDate
datePicker.maximumDate = maximumDate
}
}
Just add the required constraint after addSubview and setting TAMIC to false as follows:
#IBAction func showMyDatePicker(_ sender: UIButton) {
// ...
view.addSubview(myDatePicker!)
myDatePicker.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
myDatePicker.topAnchor.constraint(equalTo: sender.bottomAnchor),
myDatePicker.centerXAnchor.constraint(equalTo: sender.centerXAnchor)])
}

UIImageView isUserInteractionEnabled = true doesn't work

The following DateField class has a date field and an icon on it. For some reason fieldIcon.isUserInteractionEnabled = true has zero affect and doesn't pass user tap to the field. Am I missing something?
import UIKit
import SnapKit
protocol DateFieldDelegate: class {
func dateSelected(_ dateField: DateField, date: Date)
}
class DateField: UIView, UITextFieldDelegate {
weak var delegate: DateFieldDelegate?
let field = UITextField()
private var datePicker: UIDatePicker?
convenience init(withStartDate startDate: Date) {
self.init()
datePicker = prepareDatePicker()
guard let datePicker = datePicker else { return }
field.inputView = datePicker
field.delegate = self
addSubview(field)
field.snp.makeConstraints { make in
make.top.equalToSuperview()
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.height.equalTo(37)
make.bottom.equalToSuperview()
}
let fieldIcon = UIImageView(image: UIImage(asset: Asset.calendar))
field.addSubview(fieldIcon)
fieldIcon.isUserInteractionEnabled = true // doesn't work
fieldIcon.snp.makeConstraints { make in
make.width.equalTo(21)
make.height.equalTo(23)
make.trailing.equalToSuperview().offset(-10)
make.centerY.equalToSuperview()
}
setStyle(.regular)
}
func textFieldDidEndEditing(_ textField: UITextField) {
guard let date = datePicker?.date else { return }
field.text = date.formatToString()
delegate?.dateSelected(self, date: date)
}
private func prepareDatePicker() -> UIDatePicker {
let datePicker = UIDatePicker()
datePicker.datePickerMode = .date
datePicker.setDate(Date(), animated: false)
datePicker.locale = Language.appLocale()
return datePicker
}
}
Not sure if I've missed something in your code but you need to add some kind of action to the image, enabling userInteractionEnabled does not tell it to recognise taps on the item and what to do when this happens. You need to add a UITapGestureRecogniser to the UIImageView
let fieldIcon = UIImageView(image: UIImage(asset: Asset.calendar))
field.addSubview(fieldIcon)
fieldIcon.isUserInteractionEnabled = true // doesn't work
let fieldIcon = UIImageView(image: UIImage(asset: Asset.calendar))
field.addSubview(fieldIcon)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(calenderIconTapped))
fieldIcon.addGestureRecognisor(tapGesture)
func calenderIconTapped() {
// show the picker
}
UPDATE:
After re-reading your question, I understand what your attempting to do now. If you want any taps on the image view to passthrough to the UITextField underneath you need to do the opposite of what you tried... you need to set userInteractionEnabled to false on the UIImageView
fieldIcon.isUserInteractionEnabled = false

AVAudioplayer no resetting on viewDidAppear

The idea is simple and I do not think that the question has been asked in the past.
I want to build a simple mp3 player.
some songs displayed in a collection view the user selects a song
segue to another view with options to play, pause or stop only issue
is when you go back to the home screen to select a new song with the
current still playing. It is impossible to deactivate the current
player. When you need to play the 2 songs, the 2 are playing together
I have tried a lot of things
- create a new instance of player (player = AVAudioPlayer())
- player.pause() and player.play()
I do not see what I am doing wrong really.
this is my code :
import UIKit
import AVFoundation
class LecteurViewController: UIViewController {
var chansonSelected: Chanson? = nil
var lecteur:AVAudioPlayer = AVAudioPlayer()
var timer1 = Timer()
var timer2 = Timer()
#IBOutlet weak var dureeChansonSlider: UISlider!
#IBOutlet weak var chansonImageView: UIImageView!
#IBOutlet weak var chansonVolumeSlider: UISlider!
#IBOutlet weak var debutLabel: UILabel!
#IBOutlet weak var finLabel: UILabel!
#IBAction func stopMusicAction(_ sender: UIBarButtonItem) {
var player = AVAudioPlayer()
lecteur.stop()
LecteurManager.isActive = false
}
#IBAction func pauseMusicAction(_ sender: UIBarButtonItem) {
var player = AVAudioPlayer()
lecteur.pause()
LecteurManager.isActive = false
}
#IBAction func jouerMusicAction(_ sender: UIButton) {
if LecteurManager.isActive {
changeSong()
print("lecteur déjà en cours")
} else {
var player = AVAudioPlayer()
lecteur.play()
}
print(LecteurManager.isActive )
LecteurManager.isActive = true
}
func changeSong() {
lecteur.stop()
//lecteur = AVAudioPlayer()
jouerLecteurMp3()
print(chansonSelected!)
lecteur.play()
}
override func viewDidLoad() {
super.viewDidLoad()
configureView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
jouerLecteurMp3()
}
func configureView() {
self.title = (chansonSelected!.titre!).capitalized
chansonImageView.image = UIImage(named: "\(chansonSelected!.image).jpgs")
//formatter 'back' button
let backBtn = UIBarButtonItem(title: "< Playlist", style: .plain, target: self, action: #selector(LecteurViewController.reset(_sender:)))
self.navigationItem.leftBarButtonItem = backBtn
self.navigationController?.navigationBar.tintColor = UIColor.white
//contrôler volume chanson
chansonVolumeSlider.addTarget(self, action: #selector(LecteurViewController.ajusterVolume(_ :)), for: UIControlEvents.valueChanged)
//contrôler durée chanson
dureeChansonSlider.addTarget(self, action: #selector(LecteurViewController.ajusterDurée(_ :)), for: UIControlEvents.valueChanged)
updateUI()
}
func updateUI() {
//indiquer position chanson
timer1 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(LecteurViewController.mettreAJourDurée), userInfo: nil, repeats: true)
//afficher durée chanson
timer2 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(LecteurViewController.afficherDurée), userInfo: nil, repeats: true)
}
func reset(_sender:UIBarButtonItem) {
self.navigationController?.popViewController(animated: true)
}
func ajusterVolume(_ sender:UISlider) {
//print("volume ajusté \(chansonVolumeSlider.value)")
lecteur.volume = chansonVolumeSlider.value
}
func ajusterDurée(_ sender:UISlider) {
lecteur.currentTime = TimeInterval(dureeChansonSlider.value)
}
func mettreAJourDurée() {
dureeChansonSlider.value = Float(lecteur.currentTime)
}
func afficherDurée() {
print("durée actuelle: \(lecteur.duration - lecteur.currentTime)")
debutLabel.text = retournerPositionActuelle()
finLabel.text = retournerDureeTotal()
}
func retournerPositionActuelle() -> String {
let seconds = Int(lecteur.currentTime) % 60
let minutes = (Int(lecteur.currentTime) / 60) % 60
return String(format: "%0.2i:%0.2i", minutes, seconds)
}
func retournerDureeTotal() -> String {
let seconds = Int(lecteur.currentTime) % 60
let minutes = (Int(lecteur.currentTime) / 60) % 60
return String(format: "%0.2i:%0.2i", minutes, seconds)
}
func jouerLecteurMp3() {
let chanson = "bensound-\(chansonSelected!.titre!)"
let fichierMp3 = Bundle.main.path(forResource: chanson, ofType: "mp3")
do {
try lecteur = AVAudioPlayer(contentsOf: URL(string: fichierMp3!)!)
dureeChansonSlider.maximumValue = Float(lecteur.duration)
} catch {
print("erreur lecture mp3")
}
}
}
Try this:
func reset(_sender:UIBarButtonItem)
{
self.navigationController?.popViewController(animated: true)
lecteur.stop()
}

incrementing points going back to 0 swift

I have added a button, that adds points to a label.
Everything works fine, and the label is then persisted into core data and appears in a tableViewCell.
When I get back to my detailsVC, I get my label with the persisted number, but when I click on the button again to increment the points, the label goes back to zero.
Here's a part of my code:
import UIKit
import CoreData
class GoalDetailsVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// IBOutlets:
#IBOutlet weak var titleTF: UITextField!
#IBOutlet weak var detailsTextView: UITextView!
#IBOutlet weak var pointsLabel: UILabel!
#IBOutlet weak var dateOfEntry: UILabel!
#IBOutlet weak var thumbImage: UIImageView!
// properties
var currentScore = 0
var goalToEdit: Goal? // goalToEdit is now an optional, and it needs to be unwrapped when used.
var imagePicker: UIImagePickerController!
override func viewDidLoad() {
super.viewDidLoad()
if let topItem = self.navigationController?.navigationBar.topItem {
topItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
}
// now we need to say that if there is a goal to edit ( not equal to nil), then we load the Goal data with the loadGoalData() function.
if goalToEdit != nil {
loadGoalData()
}
imagePicker = UIImagePickerController()
imagePicker.delegate = self
}
// when button is pressed, I need to
// 1 : add a point to the pointsLabel
// 2 : put the current date to the dateLabel
// 3 : persist the new points and date labels.
#IBAction func plusOneBtnPressed(_ sender: UIButton) {
currentScore += 1
pointsLabel.text = "\(currentScore)"
}
#IBAction func minusOneBtnPressed(_ sender: Any) {
}
#IBAction func savePressed(_ sender: Any) {
var goal: Goal!
let picture = Image(context: context) // Image = Entity
picture.image = thumbImage.image // image = attribute
if goalToEdit == nil {
goal = Goal(context: context)
} else {
goal = goalToEdit
}
goal.toImage = picture
// this is unwrapping because the original goalToEdit is an optional.
if let title = titleTF.text {
goal.title = title
}
// we saveed, or persisted the TITLE
if let points = pointsLabel.text {
goal.plusOnes = (points as NSString).intValue
}
// we saveed, or persisted the POINTS
if let details = detailsTextView.text {
goal.details = details
}
// we saved, or persisted the DETAILS
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE MMM d yyyy"
if let date = dateFormatter.date(from: dateFormatter.dateFormat) {
goal.lastEntry = date as NSDate
}
// we saved, or persisted the DATE
ad.saveContext()
_ = navigationController?.popViewController(animated: true)
}
func loadGoalData() {
if let goal = goalToEdit {
titleTF.text = goal.title
pointsLabel.text = "\(goal.plusOnes)"
detailsTextView.text = goal.details
dateOfEntry.text = (String(describing: goal.lastEntry))
thumbImage.image = goal.toImage?.image as? UIImage
}
}
When you get the persisted number you should also set currentScore to that value (if greater than 0). I believe currently you only set it to 0 that's why the incrementation starts over.