I have a list of quotes.
I want to have a label that changes every 24H to a new Quote.
How can I do this? Like how can I manage a day?
I know I could just use an API but I want to use my own quotes and I am not able to create an API on my own yet.
Supposing you have an array of quotes:
let numberOfQuotes = 3
let quotes = ["quote a", "quote b", "quote c"]
override func viewDidLoad() {
_ = Timer.scheduledTimer(timeInterval: TimeInterval(60),
target: self,
selector: #selector(self.updateQuote),
userInfo: nil,
repeats: true)
}
func updateQuote() {
let lastUpdate = UserDefaults.standard.object(forKey: "lastUpdate") as? Date
if lastUpdate != nil {
let date1:Date = Date() // Same you did before with timeNow variable
let date2: Date = Date(timeIntervalSince1970: lastUpdate)
let calender:Calendar = Calendar.current
let components: DateComponents = calender.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date1, to: date2)
// you can use components month, hour, second.... to update your message, in your case, we will day
if components.day! >= 1 {
UserDefaults.standard.set(Date(), forKey: "lastUpdate")
yourLabel.text = quotes[randomInt(0,numberOfQuotes)]
}
} else { //firstTime running
UserDefaults.standard.set(Date(), forKey: "lastUpdate")
yourLabel.text = quotes[randomInt(0,numberOfQuotes)]
}
}
func randomInt(min: Int, max:Int) -> Int {
return min + Int(arc4random_uniform(UInt32((max - 1) - min + 1)))
}
This code is as is, by your description, it does exactly what you want.
Related
I make my iOS app islamic prayer, so I need to View countdown time next prayer.
this is code from Adhan project:
so I have 5 prayer for every day, and I need countdown time between every prayer.
func formattedPrayerTime(prayer: Prayer, times: PrayerTimes?) -> some View {
guard let time = times?.time(for: prayer) else {
return Text("-")
}
return Text("\(time, formatter: dateFormatter)")
}
func formattedPrayerName(prayer: Prayer) -> some View {
switch prayer {
case .fajr:
return Text("Fajr")
case .sunrise:
return Text("Sunrise")
case .dhuhr:
return Text("Dhuhr")
case .asr:
return Text("Asr")
case .maghrib:
return Text("Maghrib")
case .isha:
return Text("Isha")
}
}
}
I use something like this before
in viewdidload in releasedate prayer time and add target for #objc func
update time func will automatically will updated if time changed every second ( timeInterval ) in scheduledTimer
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let releaseDateString = "7:07:43" // <- prayer time
let releaseDateFormatter = DateFormatter()
releaseDateFormatter.dateFormat = "HH:mm:ss"
releaseDate = releaseDateFormatter.date(from: releaseDateString)! as NSDate
countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}
#objc func updateTime() {
let currentDate = Date()
let calendar = Calendar.current
let diffDateComponents = calendar.dateComponents([.hour, .minute, .second], from: currentDate, to: releaseDate! as Date)
DispatchQueue.global().sync
{
hours.text = "\(diffDateComponents.hour ?? 0)"
min.text = "\(diffDateComponents.minute ?? 0)"
sec.text = "\(diffDateComponents.second ?? 0)"
}
you can use SwiftDate also it's awesome library
You could use this function:
func timeUntilNextPrayer(_ nextPrayer: Date) {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
let difference = Calendar.current.dateComponents([.hour, .minute, .second], from: Date(), to: nextPrayer)
print(difference)
if nextPrayer == Date() {
timer.invalidate()
}
}
}
Call this function by passing the next prayer time as parameter. Example:
timeUntilNextPrayer(Date().addingTimeInterval(50))
I would like to send a local notification once 24 hours has passed after a button is selected. The button is currently only enabled once 24 hours has passed and the waiting time is saved in UserDegaults. I would like to know how I will be able to send a local notification to the user automatically once the 24 hours has passed.
func getNextQuote(){
let defaults = UserDefaults.standard
defaults.integer(forKey: "savedIndexKey")
let currentIndex = defaults.integer(forKey: "savedIndexKey")
var nextIndex = currentIndex+1
nextIndex = quotes.indices.contains(nextIndex) ? nextIndex : 0
defaults.set(nextIndex, forKey: "savedIndexKey")
let savedInteger = defaults.integer(forKey: "savedIndexKey")
saved = savedInteger
quotesLabel.text = quotes[savedInteger]
self.quotesLabel.fadeIn()
set24HrTimer()
update()
}
func update(){
if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date{
if let waitingDate = UserDefaults.standard.object(forKey: "waitingDate") as? Date,
waitingDate < Date() {
self.timeLabel.text = "Please check in for the day"
self.remainingLabel.text = "Did you stay clean today?"
self.remainingLabel.font = UIFont(name: "Arial", size: 32)
self.quotesLabel.isHidden = true
addButton.isHidden = false
noButton.isHidden = false
gridButton.isHidden = false
self.view.setNeedsDisplay()
print("time is up")
}else if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
self.timeLabel.attributedText = self.timeLeftExtended(date: waitingDate)
addButton.isHidden = true
noButton.isHidden = true
gridButton.isHidden = true
self.quotesLabel.isHidden = false
self.remainingLabel.text = "Until next check in"
self.quotesLabel.fadeIn()
print("still running")
}else{
let newDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())
UserDefaults.standard.set(newDate, forKey: "waitingDate")
self.timeLabel.attributedText = self.timeLeftExtended(date: newDate!)
print("last option")
}
}
}
func set24HrTimer() {
let currentDate = Date()
let newDate = Date(timeInterval: 86400, since: currentDate as Date)
UserDefaults.standard.setValue(newDate, forKey: "waitingDate")
print("24 hours started")
}
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = cal.dateComponents([.hour, .minute, .second], from: now, to: date)
let fullCountDownStr = "\(components.hour!)h \(components.minute!)m \(components.second!)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedString.Key.foregroundColor:UIColor.white])
for (index, char) in mutableStr.string.enumerated()
{
if(char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedString.Key.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
func setupTimer()
{
if(!timeWorking)
{
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateCountDown), userInfo: nil, repeats: true)
self.timeWorking = true
}
}
You shouldn't use a timer to trigger a local notification. This function could be added as an extension to UIViewController that will let you create a UNCalendarNotificationTrigger:
import UserNotifications
import UIKit
extension UIViewController {
func createLocalNotification(title: String, hours: Int) {
let seconds = hours * 3600
let content = UNMutableNotificationContent()
content.sound = UNNotificationSound.default
content.title = title
let nextTriggerDate = Calendar.current.date(byAdding: .second, value: seconds, to: Date())!
let comps = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: nextTriggerDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: comps, repeats: false)
let request = UNNotificationRequest(identifier: "\(seconds)", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
}
And can be used within your UIViewController as follows:
let MyViewController: UIViewController {
#IBAction func buttonPressed(_ sender: Any) {
self.createLocalNotification(title: "24 hours have passed!", hours: 24)
}
}
I have a UILabel which displays my current 24 hour countdown. I would like to check if the countdown is at zero and when it is to update my UILabel. The way it is set up now if it is reached 24 hours it keeps running as negative numbers. For example -1h-55m-54s
I have tried to check if UILabel contains "-" and also if the value is less than 0 however have not got it to work.
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = (cal as NSCalendar).components(calendarUnits, from: now, to: date, options: [])
let fullCountDownStr = "\(components.hour!.description)h " + "\(components.minute!.description)m " + "\(components.second!.description)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedString.Key.foregroundColor:UIColor.white])
for (index, char) in mutableStr.string.enumerated()
{
if(char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedString.Key.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
func updateCountDown() {
if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
if let waitingDate = UserDefaults.standard.object(forKey: "waitingDate") as? Date,
waitingDate < Date() {
self.timeLabel.text = "Time ran out"
print("It is time for you to check in")
}
// if self.timeLeftExtended(date: waitingDate) <= 0{
//change label
}
self.timeLabel.attributedText = self.timeLeftExtended(date: waitingDate)
} else {
let newDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())
UserDefaults.standard.set(newDate, forKey: "waitingDate")
self.timeLabel.attributedText = self.timeLeftExtended(date: newDate!)
}
}
Just compare the dates
if let waitingDate = UserDefaults.standard.object(forKey: "waitingDate") as? Date,
waitingDate < Date() {
// waitingDate exists and is earlier than the current date
}
And you can create the countdown string much shorter
let components = cal.dateComponents([.hour, .minute, .second], from: now, to: date)
let fullCountDownStr = "\(components.hour!)h \(components.minute!)m \(components.second!)s "
Here is how I use UILabel to display count down timer
First, these are my variables
#IBOutlet weak var lblCountDownTime: UILabel! //label to display count down
var countDownTimer: Timer? // timer to count down
Second, this is how I display count down, hope it help
self.countDownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.countDownTime), userInfo: nil, repeats: true);
func countDownTime() {
let now = Date();
let calendar = Calendar.current;
let comps = calendar.dateComponents(Set<Calendar.Component>([.minute, .second]), from: now, to: self.startTime);
var strMinute = "\(comps.minute!)";
var strSecond = "\(comps.second!)";
if (comps.minute! < 10) {
strMinute = "0\(comps.minute!)";
}
if (comps.second! < 10) {
strSecond = "0\(comps.second!)";
}
if (comps.minute! <= 0 && comps.second! <= 0) {
self.countDownTimer?.invalidate();
}
else {
self.lblCountDownTime.text = "\(strMinute):\(strSecond)\"";
}
}
Once my button is pressed I would like to disable my button for 24 hours and displaying a countdown on a label display a countdown until the button will be active again.
I have saved the waiting date and compared it to current date but I am not sure how to display the countdown of how much time is left in hours, minutes, and seconds.
let todaysDate = Date()
func set24HrTimer() {
let currentDate = Date()
let newDate = Date(timeInterval: 86400, since: currentDate as Date)
UserDefaults.standard.set(newDate, forKey: "waitingDate")
print("24 hours started")
//disable the button
}
if let waitingDate:Date = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
if (todaysDate.compare(waitingDate as Date) == ComparisonResult.orderedDescending) {
print("show button")
}
else {
print("hide button")
}
}
You can add following code to create time countdown.
First add two variable ass follow:
fileprivate var timeWorking : Bool = false // To check is timer already scheduled
var timer:Timer? // Instance of timer
Then add following code which will calculate remaining hour, minute and second.
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = (cal as NSCalendar).components(calendarUnits, from: now, to: date, options: [])
let fullCountDownStr = "\(components.hour!.description)h " + "\(components.minute!.description)m " + "\(components.second!.description)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedString.Key.foregroundColor:UIColor.white])
for (index, char) in mutableStr.string.enumerated()
{
if(char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedString.Key.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
Next, add code which is scheduledTimer if not scheduled.
func setupTimer()
{
if(!timeWorking)
{
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateCountDown), userInfo: nil, repeats: true)
self.timeWorking = true
}
}
Add code to display count down in label.
#objc func updateCountDown()
{
if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
self.labelCountDown.attributedText = self.timeLeftExtended(date: waitingDate)
} else {
let newDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())
UserDefaults.standard.set(newDate, forKey: "waitingDate")
self.labelCountDown.attributedText = self.timeLeftExtended(date: newDate!)
}
}
Call setupTimer() method to continue timer.
Output:
In my application i have an option to enter the data for every 15days.I have to maintain this for an current year.Please help me to figure out this problem.
For ex: [
"1-1-2018 to 15-1-2018", "16-1-2018 to 31-1-2018",
"1-2-2018 to 15-2-2018", "16-2-2018 to 28-2-2018",
"1-3-2018 to 15-3-2018", "16-3-2018 to 31-3-2018",
"1-4-2018 to 15-4-2018", "16-4-2018 to 30-4-2018",
"1-5-2018 to 15-5-2018", "16-5-2018 to 31-5-2018",
"1-6-2018 to 15-6-2018", "16-6-2018 to 30-6-2018",
"1-7-2018 to 15-7-2018", "16-7-2018 to 31-7-2018",
"1-8-2018 to 15-8-2018", "16-8-2018 to 31-8-2018",
"1-9-2018 to 15-9-2018", "16-9-2018 to 30-9-2018",
"1-10-2018 to 15-10-2018", "16-10-2018 to 31-10-2018",
"1-11-2018 to 15-11-2018", "16-11-2018 to 30-11-2018",
"1-12-2018 to 15-12-2018", "16-12-2018 to 31-12-2018"
]
From Calendar API you can get total number of days for any month in the given date and also first day of the month like below,
extension Calendar {
public func firstDayOfMonth(date: Date) -> Date {
let components = self.dateComponents([.year, .month], from: date)
return self.date(from: components) ?? date
}
public func numberOfDaysInMonthFor(date: Date) -> Int {
let range = self.range(of: .day, in: .month, for: date)
return range?.count ?? 0
}
public func lowerHalfOfMonthFor(date: Date) -> (Date, Date) {
let startDate = self.firstDayOfMonth(date: date)
let endDate = startDate.dateByAppending(day: 14)
return (startDate, endDate)
}
public func upperHalfOfMonthFor(date: Date) -> (Date, Date) {
let firstDayOfMonthDate = self.firstDayOfMonth(date: date)
let totalNoOfDaysInMonth = self.numberOfDaysInMonthFor(date: firstDayOfMonthDate)
let startDate = firstDayOfMonthDate.dateByAppending(day: 15)
let endDate = firstDayOfMonthDate.dateByAppending(day: totalNoOfDaysInMonth - 1)
return (startDate, endDate)
}
}
you can also extend Date to get new date by appending any number of days,
extension Date {
public func dateByAppending(day: Int) -> Date {
let newDate = Calendar.current.date(byAdding: .day, value: day, to: self)
return newDate ?? self
}
public func daysDifference(_ date: Date?) -> Int? {
guard let date = date else { return nil }
return Calendar.current.dateComponents([.day], from: self, to: date).day
}
With the mix of above helper methods, you should be able to achieve the required result like below,
let date = Date()
let lowerHalf = Calendar.current.lowerHalfOfMonthFor(date: date)
let uppperHalf = Calendar.current.upperHalfOfMonthFor(date: date)
Below code will calculate the 15th day if you give the input,
static func getFortnightly(selectedDate : String) -> String?{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yy" //Your date format
if let dateSelected = dateFormatter.date(from: selectedDate) {//according to d
let newDate = Calendar.current.date(byAdding: .weekOfYear, value: 2, to: dateSelected)
let convertedDateToString = dateFormatter.string(from: newDate!)
return convertedDateToString
}
return nil
}
}