Time until next day starts in UTC (Swift)

Although users interact with NewsWave on their iOS and -soon- Mac, some features are provided by a server.

So, how can I let users know when the server triggers certain tasks? If they are triggered at regular intervals you can simply calculate on the device how long until it will be triggered again. This reduces calls to the server, which in turn reduces cost.

In this example, the function calculates how many hours until the next day -in UTC timezone- starts:

var calendarIso8601 = Calendar(identifier: .iso8601) // Gregorian calendar, which “serves as an international standard for civil use.

calendarIso8601.timeZone = TimeZone(identifier: “UTC”)!

let startOfDayTodayUTC = calendarIso8601.startOfDay(for: Date()) //Start day at UTC

let endOfDayTodayUTC = Calendar.current.date(byAdding: .day, value: 1, to: startOfDayTodayUTC)

let secondsToTomo = endOfDayTodayUTC?.timeIntervalSince(Date())

let hoursToTomo = secondsToTomo!/60/60

The app can then show this number to the user. 

 

Marc

NewsWave for Mac – Dark Mode

NewsWave for Mac is moving along quite well. In fact, 1.0 is feature complete, meaning all features I planned to ship in the first Mac release are already in. I’m now focusing on testing and polish. 

Speaking of polish, here’s a couple screenshots of the -mostly- final version of Dark Mode, updated icons and all 🙂  Let me know if you have any feedback. 

Screen Shot 2020 05 06 at 16 39 30

Screen Shot 2020 05 06 at 16 39 36

Screen Shot 2020 05 06 at 16 39 46

While working on the icons I’ve used Pixelmator Pro for the first time, I’ve been blown away by how good and fast it is. In the past I used Acorn and the standard Pixelmator and… Oh my oh my. Pixelmator Pro is AMAZING. 

Back to NewsWave, I’ll keep you posted on progress, can’t wait to share it with all of you. 

Marc

Making Sense Podcast #201 Yuval Noah Harari

One of the podcasts I typically follow is “Making Sense” by Sam Harris. I found his latest episode, where he had a discussion with Yuval Noah Harari especially insightful. 

“[…] They discuss the failures of global leadership, the widespread distrust of institutions, the benefits of nationalism and its current unraveling in the U.S., politics as a way of reconciling competing desires, the consequences of misinformation, the enduring respect for science, the future of surveillance, the changing role of religion, and other topics.”

Here’s a link to the episode if you’re interested. 

 

Marc

Create a NSButton in code (swift)

Some time ago I shared a simple way to create custom UIButtons in code. As I’m starting to polish NewsWave for Mac, I wanted the same ability to easily create custom buttons. So, I ported the function to macOS, feel free to leverage:

 

    func createNewNSButton(title: String, textSizeDelta: CGFloat?, textColor: NSColor?,  backgroundColor: NSColor?, cornerRadius: Bool, cornerColor: NSColor?) -> NSButton{

        

        let button = NSButton()

        

        button.translatesAutoresizingMaskIntoConstraints = false

        button.attributedTitle = NSMutableAttributedString(string: ”  \(title)  “, attributes: [NSAttributedString.Key.foregroundColor: (textColor ?? NSColor.white), NSAttributedString.Key.font: NSFont.systemFont(ofSize: (NSFont.systemFontSize + (textSizeDelta ?? 0)))])

       

        button.isBordered = false

        button.wantsLayer = true

        button.layer?.backgroundColor = backgroundColor?.cgColor ?? .clear

 

        if cornerRadius == true{

            button.layer!.masksToBounds = true

            button.layer!.cornerRadius = 22

            button.layer!.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMinYCorner]

            if cornerColor != nil{

                button.layer!.borderWidth = 2

                button.layer!.borderColor = cornerColor!.cgColor

            }

        }

        

        return button

    }

 

And to add an action you just:

button.action = #selector(whateverActionGoesHere)

Here’s an example of the types of buttons you can create:

Screen Shot 2020 04 04 at 16 49 02

Stay safe & until next time,

 

Marc

—-

 

 

Twitter -> @MarcMasVi

NewsWave 2020.1

There’s many things that have changed since social distancing began about 15 days ago: meeting friends, going for morning coffees, weekend escapes and many other activities are now on hold. However, there are also some positive consequences: my wife and I have really gotten into board games (Forbidden Island, Exploding Kittens, Scrabble…), I’ve gotten a lot better at cooking and, probably the most relevant for this blog, I have significantly more time to code on weekends, so… NewsWave 2020.1 is now live! 

Header202010

NewsWave 2020.1 is a major update. In a nutshell it improves the onboarding experience and builds the foundation for the upcoming macOS version.

Here are the key changes in a bit more detail:

1. Onboarding:

This was the area the app that needed more work on and I’m very happy with the result. To recap, this is how it used to work:

“when you launch NewsWave RSS for the first time, you’re asked to create an account or restore an existing one before you can interact with the app. For privacy & simplicity reasons I do this with a free IAP.  Behind the scenes, when a user unlocks a free in-app-purchase (IAP), Apple provides me with a uniqueUserId I use to identify the customer. This allows me to grant the customer a 30 day free trial, allow him to try sync and easily migrate him to a Premium account if he so chooses. “

The new model is much simpler, users can create an anonymous account with the click of a button. When a new user downloads NewsWave, a new device-specific token is created for him, no emails, no IAP, no complexity. 

You may have spotted a significant downside vs. the old model. As the identifier is tied to the device, and because there’s no personal information shared, if the user deletes the app the device-token is gone too. What this means in practice is that if the user re-downloads the app, he would need to create a new account.

Wow! Big downside. Well, yes, and no.

Once the user becomes a subscriber, his device token is linked to the in-app-purchase (IAP) identifier. From then on he can restore his account from any device by tapping “Restore”. This is true even if the user is no longer subscribed. 

Therefore, the only time this could lead to a potential challenge is for users trying the app. Given that it’s only 30 days, and that they would need to remove the app, I’m confident the upside is a lot more significant than the potential downside. 

A final consequence of this changes is that the onboarding UX is significantly more streamlined. Here’s the new page:

Screen Shot 2020 03 29 at 18 54 05

 

I believe there will be significant impact on conversion-rate, which was the key challenge of the app in the past. I’ll keep you posted on how it changes. 

 

2. Default Feeds:

In the old model, once a user had created an account, they were taken to the “Feeds Section” and guided to start adding feeds. This was not a great first experience, and if the user tapped away from the “Feeds Section”, he would not be able to interact with anything as there was no content to show… Not great. 

In the new model, when a new user is created, he is automatically subscribed to a few starting feeds. Once the initial setup is complete, he is taken to the main screen -already populated with content- where he can start using the app. A huge improvement vs the past. 

This change resulted in something else, I had to choose these starting feeds. 

 

Default feeds should:

– Touch a variety of fields/subjects. 

– Be free to access (or have generous free access policies).

– Provide a good RSS summary and image to go along with the posts. 

– Post enough but not too much, ideally 5 to 20 times per day. 

– Represent both mass appeal and niche feeds. 

 

Here’s what I settled on:

1. Daring Fireball (Blog – Apple)

2. Six Colors (News – Products/Apple)

4. Ars Technica (Technology)

5. Vox (General News)

6. Mr. Money Mustache (Blog – Personal Finances)

7. The Intercept (General News & Reporting)

 

3. Synchronization & under the hood improvements:

It’s no secret I’m working on the macOS version of NewsWave.

To prepare for its upcoming release, I’ve invested a lot of time on refining synchronization between devices. All calls now use one streamlined framework, which makes testing a lot simpler and reduces the likelihood of bugs. 

Finally and most importantly, today both iOS and the macOS versions of NewsWave share the same API back end code, this dramatically simplifies the effort needed to update and improve the apps.   

 

4. Other improvements:

There’s been many other refinements and under the hood improvements, including:

– Improved wording on several menus and notifications. 

– Improved saving & loading speeds for users with large amount of feeds. 

– Removed redundant code (I love this part, love it!). 

– Fixed a bug that, under rare circumstances, could show a black NavBar. 

– Updated Feed Recommendations. 

 

 

I’ll be monitoring the servers to make sure everything is going well. With this milestone out of the way, I’ll be fully focusing on NewsWave for Mac from now on. Hopefully will be able to ship sooner than  the original 2020 plan 🙂

I believe this will be a great year for RSS, if you’re not yet a user give NewsWave a try! And if you don’t like it, there’s other great options out there. 

 

Stay safe & until next time,

 

Marc

—-

 

 

 

Twitter -> @MarcMasVi

2020 Roadmap

If the last post was focused on looking back, this one is all about what’s to come. 

2020 will be all about focus. Only if I meet all objectives for the existing apps will I think about new ideas. Without further ado, here is the 2020 roadmap: 

NewsWave Onboarding (Spring 2020):

As mentioned in a previous post, the NewsWave onboarding experience needs work. As it stands, it’s severely limiting the number of users trying the app.

In the current version, when you launch NewsWave RSS for the first time, you’re asked to create an account or restore an existing one before you can interact with the app. For privacy & simplicity reasons I do this with a free IAP.  Behind the scenes, when a user unlocks a free in-app-purchase (IAP), Apple provides me with a uniqueUserId I use to identify the customer. This allows me to grant the customer a 30 day free trial, allow him to try sync and easily migrate him to a Premium account if he so chooses. 

IMG 5310

Here’s a high level chart I drew recently to refamiliarize myself with the current account creation steps

The problem with the approach is that many users are scared, with reason, of in-app-purchases. They have been burned so many times by shady companies with deceptive free content that now all developers face the consequences. 

So what’s the plan? I already did some minor changes last year, but I’m working on a complete redesign.

Here’s the idea:

a) When the user opens the app for the first app he’ll be assigned a randomID automatically. With the exception of sync, the user will be able to try all premium features for 30 days. 

There’s a clear con however, if the user deletes the app and is not a Premium user (if there’s no an IAP tied to the account) there’s no way to restore their data. I’ll make sure to reinforce that, probably with an in-app message, after the user has been active in NewsWave for 30 days. 

b) When the user migrates to a premium account all information will be linked to an IAP, which will also enable sync. 

c) If there’s a duplicate, for instance if the user already has an IAP but just installed the app on a new iPhone, the IAP account will prevail at restore time and the temporary one will be flagged as migrated. 

The fact that the users will be able to use the app from the get go opens the question: “should link them to some feeds from the start?”. I’m not keen on it. Alternatively, I’m considering having a few NewsWave articles explain how the app works. Still not sure, will decide in the next few weeks. 

 

NewsWave for Mac (Summer 2020):

It’s no secret I’ve been working on NewsWave for Mac for quite a while, what you may not know is that I’ve been using it for months 🙂

There’s still much polish to be done, but I’m very happy with it already. Here are some early screenshots:

NewsWaveAplha

I don’t want to share more just yet but will definitely post about it when I get closer to release.

 

Excelling (Autumn 2020):

Excelling continues to do moderately well since its release. Every year I update it to ensure it looks and feels currents with the new iOS versions.

ExcellingPost

Its codebase is old however, the codebase is also showing its age. It’s time for a more significant internal update that ensures it’ll continue to work for years to come. 

 

That’s the plan for 2020! Hit me on twitter if you have any questions, I’ll be sure to keep you posted on progress. 

 

Until next time,

 

Marc

—- 

 

 

Twitter -> @MarcMasVi

2019 in review

As we start 2020 I wanted to take a moment to look back into 2019. 

The launch of NewsWave this past May was the indisputable highlight. Releasing a new app after months of work is always a nerve wracking experience.

Stacks image 2eadb64 1198x952

Fortunately the app was very positively received, since launch the app has been updated multiple times to improve and polish it. Even though there’s much else that can be done, more on that in the upcoming “2020 roadmap” post, I’m very happy with where the app is at today.  

Excelling, the first app I ever released (in 2013 no less), continues to have its stable niche audience. As every year, I updated it with UI improvements and under the hood changes to ensure it remains functional as iOS continues to move forward. 

ExcellingPost

Denarius, the finance app launched in 2017, continued to struggle to find an audience. When I built Denarius banks did not offer an easy way to manage your spending in Europe. This changed drastically since then though as most banks now offer a way to track where and how you’re spending your money. This, together with the fact that Denarius was designed around the European banking system, thus limiting its success elsewhere, made me realize it was time to sunset the app.

I’m very proud of Denarius, it’s hard to retire an app you’ve invested hundreds of hours into, but its time. 

Stacks image 3b458f4 714x454

 

RiverNews is a stand alone RSS reader for the Mac built in 2018 as a POC inspired by a post from Brent Simmons. Even thought it had no marketing it quickly gained traction and has convinced me to use it as a foundation for NewsWave for Mac (more on this soon).

Stacks image 3a8506e

 

And that is all! 2019 was a great year, thank’s to all my users and fellow developers that have helped. 

I’ll soon post about the 2020 roadmap, couldn’t be more excited about what’s to come for NewsWave and other apps. 

 

Until next time,

 

Marc

—-

 

 

 

Twitter -> @MarcMasVi

NSImage with Rounded Edges

Nothing like vacation to accelerate personal projects, very happy with how NewsWave for Mac is shaping up. No promises on when, but I’m planning to post more about its progress very soon. 

One of the items I worked on today is how icons and images will appear in the app, the intent is to show as much content as possible while making them attractive. To to that, images and icons will be scaled down, using “Aspect Fill’, and their edges will be rounded. This is a very simple thing to do in iOS, but it needs a bit more work on macOS. 

I wanted to go from this:

Screen Shot 2019 12 31 at 11 27 21

To this:

Screen Shot 2019 12 31 at 11 25 59

 

The cleanest way I’ve found is to subclass NSImageView, overriding the image variable, and simply use that new class for the images you want. Here’s the class code, works like a charm: 

import Cocoa

 

class ImageAspectFillView: NSImageView {

    

    override func draw(_ dirtyRect: NSRect) {

        super.draw(dirtyRect)

        

    }

 

    override var image: NSImage? {

        set {

            self.layer = CALayer()

            self.layer?.contentsGravity = CALayerContentsGravity.resizeAspectFill

            self.layer?.contents = newValue

            self.wantsLayer = true

            

 

            self.layer?.cornerRadius = 8.0

            self.layer?.masksToBounds = true

 

            

            super.image = newValue

        }

        

        get {

            return super.image

        }

    }

 

}

 

Until next time,

 

Marc

—-

 

 

Twitter -> @MarcMasVi

Creating a collage by combining an array of images (macOS & iOS)

In NewsWave, when you are in the “Add Feed” view you have the option to search the RSS repository, add a RSS URL or choose from ‘recommended feeds’. 

Recommended feeds may change over time so, instead of using static images, NewsWave looks at the feeds from each recommended category and creates a collage to represent the group. Here’s an example from NewsWave for iOS:IMG 4EB8598DD377 1

For the upcoming NewsWave for Mac version however, the code needed some tweaking. Below you’ll find both the mac and iOS versions -the function takes a rect (size of the desired outcome image) and a collection of images for the collage-.

In the version below it will output 2 rows and 3 columns but that can be easily tweaked by changing ’totalNumberOfColumns’ and ’totalNumberOfRows’. 

Here’s the macOS version:

    func collageImage(rect: CGRect, images: [NSImage]) -> NSImage {

        if images.count == 1 {

            return images.first!

        }

        

        let outcomeImage = NSImage(size: NSSize(width: rect.width, height: rect.height))

        outcomeImage.lockFocus()

        //Charecteristics of output

        let totalNumberOfColumns: CGFloat = 3

        let totalNumberOfRows: CGFloat = 2

        //Process

        let heightOfSubImage: CGFloat = rect.height/totalNumberOfRows

        let widthOfSubImage = rect.width/totalNumberOfColumns

        var columnNumber = 0

        var rowNumber = 0

        var i=0

        while i<images.count {

            let rectToDrawIn = CGRect(x: CGFloat(columnNumber)*widthOfSubImage, y: CGFloat(rowNumber)*heightOfSubImage, width: widthOfSubImage, height: heightOfSubImage)

            images[i].draw(in: rectToDrawIn)

            if columnNumber == (Int(totalNumberOfColumns) 1){

                rowNumber = rowNumber + 1

                columnNumber = 0

            }

            else {

                columnNumber = columnNumber + 1

            }

            i = i + 1

        }

        

        outcomeImage.unlockFocus()

        return outcomeImage

    }

 

And the iOS version:

    func collageImage(rect: CGRect, images: [UIImage]) -> UIImage {

        if images.count == 1 {

            return images.first!

        }

        

        UIGraphicsBeginImageContextWithOptions(rect.size, falseUIScreen.main.scale)

        //Charecteristics of output

        let totalNumberOfColumns: CGFloat = 3

        let totalNumberOfRows: CGFloat = 2

        //Process

        let heightOfSubImage: CGFloat = rect.height/totalNumberOfRows

        let widthOfSubImage = rect.width/totalNumberOfColumns

        var columnNumber = 0

        var rowNumber = 0

        var i=0

        while i<images.count {

            let rectToDrawIn = CGRect(x: CGFloat(columnNumber)*widthOfSubImage, y: CGFloat(rowNumber)*heightOfSubImage, width: widthOfSubImage, height: heightOfSubImage)

            images[i].drawInRectAspectFill(rect: rectToDrawIn)

            if columnNumber == (Int(totalNumberOfColumns) 1){

                rowNumber = rowNumber + 1

                columnNumber = 0

            }

            else {

                columnNumber = columnNumber + 1

            }

            i = i + 1

        }

        

        let outputImage = UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();

        return outputImage!

    }

 

Until next time, 

Marc

—-

 

Twitter -> @MarcMasVi

Why I will not ship a Catalyst port of NewsWave

When Catalyst was announced at WWDC I was very excited about the possibilities that it created for NewsWave. Even though NewsWave launched as an iOS-only app, bringing it to the Mac has always been a priority.

A couple of months ago I started woking on porting it. As it turns out, and as you probably figured out based on the title, there were complications…

I got the app working on the Mac with little work, almost none really. However, when I started to change it to make it more Mac-like is when I started to face difficulties. It became clear this would not be a relatively easy undertaking: missing APIs, non-Mac behaviors and bugs meant I would need to invest a lot of time to, at most, end up with a barely decent Mac port. If you look at the best Catalyst ports out there you’ll see what I mean, they’re not bad but they are certainly not great either…

When I look at how I spend my time (remember I’m doing this part time), I don’t believe using it to create something decent makes sense. Here’s the Catalyst port of NewsWave running on the Mac for your reference:

Screen Shot 2019 10 27 at 22 32 50

So, what am I doing in the end? Well, I’m building a native Mac app! I’m considering experimenting with SwiftUI but based on what fellow developers said, I’ll likely will stick to Storyboards for now.

It’ll take a bit more than a Catalyst port but certainly will be a significantly better app for the Mac and for my users.

Until next time,

Marc

—-

Twitter -> @MarcMasVi