神刀安全网

Babby's First Hack Day: Fast Queue

Technically this was not my first hack day, but this was the first hackday where I attempted to work on a project on my own. I am a QA Engineer, not a mobile developer, so my experience in making iOS apps is pretty light. I have been working with Swift for automation purposes, and for practicing coding on my own, and this was the first hack day since I started coding in earnest where I could put what I learned to the test.

I decided to limit myself to trying to create a well-implemented micro feature: Fast Queue. What is Fast Queue? Well, in Tumblr iOS, we have Fast Reblog, activated by long-pressing on a reblog icon on any post:

Babby's First Hack Day: Fast Queue

If you want to queue, though, that’s a different story. First you have to pop the post form. Then you tap on post options. THEN you tap on queue. Then, finally, after all those taps, when your brow is heavy with sweat, after you think you can tap no further, the Queue button appears. When you tap it, it adds the post to the end of your queue.

But what if you could queue without bringing up the post form? What if you could queue right from a post… fast?

Enter Fast Queue:

Babby's First Hack Day: Fast Queue

When you long press on a specific blog’s Fast Reblog menu item for a specified duration, then end the long press on the menu item, the post will queue instead of reblog instantly. I wanted to create this feature because I knew the queue experience was clunky, and users who like it would want an easier way to reach it. I’ve also heard co-workers at Tumblr talk about how they wish the queue experience was better. Therefore I decided this would be a good project for me, as an iOS engineer newbie, to get my feet wet with wedging a new and useful feature into an existing code base.

I started this project by planning the behavior I wanted: WHEN the user long presses inside a Fast Reblog menu item for 2 seconds, AND the user releases the long press in the same menu item, THEN the post is queued to the blog contained within the menu item. Easy enough.

I pinged the wonderfully talented @coulton, creator of Fast Reblog, to ask where the code for Fast Reblog lived. He pointed me to a Swift file and I started reading through the code to see how it worked. After a bit of studying, a few instances of print("test") , and a couple more slack messages, I figured out the structure of the code that I needed to know: The post controller, which was in Objective-C, detected a long press on the reblog button, which in turn popped the fast reblog menu, written in Swift, which then in turn spawned 1-3 reblog menu items depending on how many blogs you had. Wherever you released your finger, the post controller was told which blog to send the post to (or none at all, if you released outside a menu item).

Babby's First Hack Day: Fast Queue

The first roadblock I hit was in the post controller. It was already capturing the long press gesture for other purposes, but I needed long press for fast queue. After a handful of attempts to add a UILongPressGestureRecognizer to the individual reblog menu items, I discovered I was heading in the wrong direction. Long press was already in use; you can’t long press while you were already long pressing , and I wanted to avoid using force touch so I could deliver this feature to as many users as possible.

I looked at my problem again and realized I only need to track how long you’re touching up inside the reblog menu item. Long press is just a construct, man. Luckily I already had a computed property that was tracking the menu item’s state within the reblog menu item’s object:

ReblogMenuItem.swift  ...  /// The current state of the item view. var state: ReblogMenuItemState = .Normal {     didSet {         if oldValue != state {             // Update the UI **ONLY** if the selected value changes.             self.updateInterface()         } }  ... 

Solid. So, there are four states:

ReblogMenuItem.swift  ...  /** The potential states for the reblog menu item view.  - Foreground: The item is highlighted. - Background: The item is not highlighted, but another one is. - Selected:   The item is highlighted and is animating out. - Normal:     Nothing is selected. */ enum ReblogMenuItemState {     case Foreground     case Background     case Selected     case Normal }  ... 

All we really care about, though, is .Foreground and .Normal . Let’s try this:

ReblogMenuItem.swift  ...  /// The current state of the item view. var state: ReblogMenuItemState = .Normal {     didSet {         if oldValue != state {             // Update the UI **ONLY** if the selected value changes.             self.updateInterface()         }         if state == .Foreground {             print("I'm inside the menu item!")         }         if state == .Normal {             print("I'm outside the menu item!")         }     } }  ... 

Unfortunately due to the nature of the existing Fast Reblog animation, one touch inside, followed by moving outside, resulted in this output:

Console output: > I'm inside the menu item! > I'm inside the menu item! > I'm inside the menu item! > I'm inside the menu item! > I'm inside the menu item! > I'm inside the menu item! > I'm inside the menu item! > I'm inside the menu item! > I'm outside the menu item! 

I decided to counter this spam by filtering with a bool touchInsideStarted , which set to true once touching inside the menu item, and false when outside. A check for !self.touchInsideStarted prevented my block from being called repeatedly like in the output shown above. The end result was this:

ReblogMenuItem.swift  ...  private var touchInsideStarted = false private(set) var fastQueueEnabled = false  ...  /// The current state of the item view. var state: ReblogMenuItemState = .Normal {     didSet {         if oldValue != state {             // Update the UI **ONLY** if the selected value changes.             self.updateInterface()         }         if state == .Foreground {             if !self.touchInsideStarted {                 self.touchInsideStarted = true                 self.fastQueueTimer = NSTimer.scheduledTimerWithTimeInterval(fastQueueTimerDuration, target: self, selector: #selector(ReblogMenuItemView.enableFastQueue), userInfo: nil, repeats: false)             }         }         if state == .Normal {             if self.touchInsideStarted {                 self.touchInsideStarted = false                 invalidateTimer()             }         }     } }  ...  /** Flips the fast queue bool on */ @objc private func enableFastQueue() {     self.fastQueueEnabled = true     switchReblogColorTo(UIColor.tumblrDarkBlueColor())     jiggle() }  ... 

An NSTimer was used to fire enableFastQueue() if you hold your touch inside the menu item for a specified duration (in this case, fastQueueTimerDuration is 2 seconds). enableFastQueue() will switch the color to blue and jiggle the menu item.

If you stop touching inside the reblog menu item, the block within if state == .Normal ensures that fast queue is disabled and interrupts the timer in progress.

The fastQueueEnabled property was made read-only outside the reblog menu item class. The reblog menu controller, which spawned all the menu items, determined where to route the post when the long press gesture was completed inside a menu item, then sent the blog and post ID to the post controller where the API call was made. Using the read-only fastQueueEnabled property, I added a conditional where it would route the post to the correct blog’s queue if the property was true , or simply reblog it if false .

All I had to do after that was create an appropriate animation, then smooth out a bug where the timer would continue to tick if no blogs were selected and the menu was dismissed. In the end, I was able to complete my project on time. Now I just have to round out the corners I cut into solid, production-ready code.

Keep an eye out for Fast Queue in the near future!

@sreegs

Babby's First Hack Day: Fast Queue

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Babby's First Hack Day: Fast Queue

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址