mirror of
https://github.com/wahyd4/Yep.git
synced 2026-08-15 07:45:55 +10:00
1345 lines
46 KiB
Swift
1345 lines
46 KiB
Swift
//
|
|
// FeedsViewController.swift
|
|
// Yep
|
|
//
|
|
// Created by nixzhu on 15/9/25.
|
|
// Copyright © 2015年 Catch Inc. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import RealmSwift
|
|
import AVFoundation
|
|
import MapKit
|
|
|
|
class FeedsViewController: BaseViewController {
|
|
|
|
var skill: Skill?
|
|
var needShowSkill: Bool {
|
|
return (skill == nil) ? true : false
|
|
}
|
|
|
|
var profileUser: ProfileUser?
|
|
var preparedFeedsCount = 0
|
|
|
|
var hideRightBarItem: Bool = false
|
|
|
|
var feeds = [DiscoveredFeed]()
|
|
|
|
@IBOutlet weak var feedsTableView: UITableView!
|
|
@IBOutlet private weak var activityIndicator: UIActivityIndicatorView!
|
|
|
|
private var filterBarItem: UIBarButtonItem?
|
|
|
|
private lazy var filterView: DiscoverFilterView = DiscoverFilterView()
|
|
|
|
private lazy var newFeedTypesView: NewFeedTypesView = {
|
|
let view = NewFeedTypesView()
|
|
|
|
view.createTextAndPhotosFeedAction = { [weak self] in
|
|
self?.performSegueWithIdentifier("presentNewFeed", sender: nil)
|
|
}
|
|
|
|
view.createVoiceFeedAction = { [weak self] in
|
|
self?.performSegueWithIdentifier("presentNewFeedVoiceRecord", sender: nil)
|
|
}
|
|
|
|
view.createShortMovieFeedAction = { [weak self] in
|
|
}
|
|
|
|
view.createLocationFeedAction = { [weak self] in
|
|
self?.performSegueWithIdentifier("presentPickLocation", sender: nil)
|
|
}
|
|
|
|
return view
|
|
}()
|
|
|
|
private lazy var skillTitleView: UIView = {
|
|
|
|
let titleLabel = UILabel()
|
|
|
|
let textAttributes = [
|
|
NSForegroundColorAttributeName: UIColor.whiteColor(),
|
|
NSFontAttributeName: UIFont.skillHomeTextLargeFont()
|
|
]
|
|
|
|
let titleAttr = NSMutableAttributedString(string: self.skill?.localName ?? "", attributes:textAttributes)
|
|
|
|
titleLabel.attributedText = titleAttr
|
|
titleLabel.textAlignment = NSTextAlignment.Center
|
|
titleLabel.backgroundColor = UIColor.yepTintColor()
|
|
titleLabel.sizeToFit()
|
|
|
|
titleLabel.bounds = CGRectInset(titleLabel.frame, -25.0, -4.0)
|
|
|
|
titleLabel.layer.cornerRadius = titleLabel.frame.size.height/2.0
|
|
titleLabel.layer.masksToBounds = true
|
|
|
|
return titleLabel
|
|
}()
|
|
|
|
lazy var pullToRefreshView: PullToRefreshView = {
|
|
|
|
let pullToRefreshView = PullToRefreshView()
|
|
pullToRefreshView.delegate = self
|
|
|
|
self.feedsTableView.insertSubview(pullToRefreshView, atIndex: 0)
|
|
|
|
pullToRefreshView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
let viewsDictionary = [
|
|
"pullToRefreshView": pullToRefreshView,
|
|
"view": self.view,
|
|
]
|
|
|
|
let constraintsV = NSLayoutConstraint.constraintsWithVisualFormat("V:|-(-200)-[pullToRefreshView(200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary)
|
|
|
|
// 非常奇怪,若直接用 "H:|[pullToRefreshView]|" 得到的实际宽度为 0
|
|
let constraintsH = NSLayoutConstraint.constraintsWithVisualFormat("H:|[pullToRefreshView(==view)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary)
|
|
|
|
NSLayoutConstraint.activateConstraints(constraintsV)
|
|
NSLayoutConstraint.activateConstraints(constraintsH)
|
|
|
|
return pullToRefreshView
|
|
}()
|
|
|
|
#if DEBUG
|
|
private lazy var feedsFPSLabel: FPSLabel = {
|
|
let label = FPSLabel()
|
|
return label
|
|
}()
|
|
#endif
|
|
|
|
private let feedSkillUsersCellID = "FeedSkillUsersCell"
|
|
private let feedBasicCellID = "FeedBasicCell"
|
|
private let feedBiggerImageCellID = "FeedBiggerImageCell"
|
|
private let feedNormalImagesCellID = "FeedNormalImagesCell"
|
|
private let feedAnyImagesCellID = "FeedAnyImagesCell"
|
|
private let feedGithubRepoCellID = "FeedGithubRepoCell"
|
|
private let feedDribbbleShotCellID = "FeedDribbbleShotCell"
|
|
private let feedVoiceCellID = "FeedVoiceCell"
|
|
private let feedLocationCellID = "FeedLocationCell"
|
|
private let loadMoreTableViewCellID = "LoadMoreTableViewCell"
|
|
|
|
private lazy var noFeedsFooterView: InfoView = InfoView(NSLocalizedString("No Feeds.", comment: ""))
|
|
|
|
private var audioPlayedDurations = [String: NSTimeInterval]()
|
|
|
|
private func audioPlayedDurationOfFeedAudio(feedAudio: FeedAudio) -> NSTimeInterval {
|
|
let key = feedAudio.feedID
|
|
|
|
if !key.isEmpty {
|
|
if let playedDuration = audioPlayedDurations[key] {
|
|
return playedDuration
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
private func setAudioPlayedDuration(audioPlayedDuration: NSTimeInterval, ofFeedAudio feedAudio: FeedAudio) {
|
|
let key = feedAudio.feedID
|
|
if !key.isEmpty {
|
|
audioPlayedDurations[key] = audioPlayedDuration
|
|
}
|
|
|
|
// recover audio cells' UI
|
|
|
|
if audioPlayedDuration == 0 {
|
|
|
|
let feedID = feedAudio.feedID
|
|
|
|
for index in 0..<feeds.count {
|
|
let feed = feeds[index]
|
|
if feed.id == feedID {
|
|
|
|
let indexPath = NSIndexPath(forRow: index, inSection: Section.Feed.rawValue)
|
|
|
|
if let cell = feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedVoiceCell {
|
|
cell.audioPlayedDuration = 0
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func updateFeedsTableViewOrInsertWithIndexPaths(indexPaths: [NSIndexPath]?) {
|
|
|
|
// refresh skillUsers
|
|
|
|
let skillUsersIndexPath = NSIndexPath(forRow: 0, inSection: Section.SkillUsers.rawValue)
|
|
if let cell = feedsTableView.cellForRowAtIndexPath(skillUsersIndexPath) as? FeedSkillUsersCell {
|
|
cell.configureWithFeeds(feeds)
|
|
}
|
|
|
|
if let indexPaths = indexPaths where feeds.count > 1 {
|
|
// insert
|
|
feedsTableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .Automatic)
|
|
|
|
} else {
|
|
// or reload
|
|
feedsTableView.reloadData()
|
|
}
|
|
|
|
feedsTableView.tableFooterView = feeds.isEmpty ? noFeedsFooterView : UIView()
|
|
}
|
|
|
|
private struct LayoutPool {
|
|
|
|
private var feedCellLayoutHash = [String: FeedCellLayout]()
|
|
|
|
private func feedCellLayoutOfFeed(feed: DiscoveredFeed) -> FeedCellLayout? {
|
|
let key = feed.id
|
|
|
|
return feedCellLayoutHash[key]
|
|
}
|
|
|
|
private mutating func updateFeedCellLayout(layout: FeedCellLayout, forFeed feed: DiscoveredFeed) {
|
|
|
|
let key = feed.id
|
|
|
|
if !key.isEmpty {
|
|
feedCellLayoutHash[key] = layout
|
|
}
|
|
|
|
//println("feedCellLayoutHash.count: \(feedCellLayoutHash.count)")
|
|
}
|
|
|
|
private mutating func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
|
|
|
|
if let layout = feedCellLayoutOfFeed(feed) {
|
|
return layout.height
|
|
|
|
} else {
|
|
let layout = FeedCellLayout(feed: feed)
|
|
updateFeedCellLayout(layout, forFeed: feed)
|
|
return layout.height
|
|
}
|
|
}
|
|
}
|
|
private static var layoutPool = LayoutPool()
|
|
|
|
private var feedSortStyle: FeedSortStyle = .Match {
|
|
didSet {
|
|
feeds = []
|
|
feedsTableView.reloadData()
|
|
|
|
filterBarItem?.title = feedSortStyle.nameWithArrow
|
|
|
|
updateFeeds()
|
|
|
|
YepUserDefaults.feedSortStyle.value = feedSortStyle.rawValue
|
|
}
|
|
}
|
|
|
|
//var navigationControllerDelegate: ConversationMessagePreviewNavigationControllerDelegate?
|
|
//var originalNavigationControllerDelegate: UINavigationControllerDelegate?
|
|
|
|
deinit {
|
|
|
|
feedsTableView?.delegate = nil
|
|
|
|
print("Deinit FeedsViewControler")
|
|
}
|
|
|
|
override func viewDidAppear(animated: Bool) {
|
|
super.viewDidAppear(animated)
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
// 优先处理侧滑,而不是 scrollView 的上下滚动,避免出现你想侧滑返回的时候,结果触发了 scrollView 的上下滚动
|
|
if let gestures = navigationController?.view.gestureRecognizers {
|
|
for recognizer in gestures {
|
|
if recognizer.isKindOfClass(UIScreenEdgePanGestureRecognizer) {
|
|
feedsTableView.panGestureRecognizer.requireGestureRecognizerToFail(recognizer as! UIScreenEdgePanGestureRecognizer)
|
|
println("Require UIScreenEdgePanGestureRecognizer to failed")
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
title = NSLocalizedString("Feeds", comment: "")
|
|
|
|
if skill != nil {
|
|
navigationItem.titleView = skillTitleView
|
|
// Add to Me
|
|
|
|
if let skillID = skill?.id {
|
|
if let
|
|
myUserID = YepUserDefaults.userID.value,
|
|
realm = try? Realm(),
|
|
me = userWithUserID(myUserID, inRealm: realm) {
|
|
|
|
let predicate = NSPredicate(format: "skillID = %@", skillID)
|
|
|
|
if me.masterSkills.filter(predicate).count == 0
|
|
&& me.learningSkills.filter(predicate).count == 0 {
|
|
let addSkillToMeButton = UIBarButtonItem(title: NSLocalizedString("Add to Me", comment: ""), style: .Plain, target: self, action: "addSkillToMe:")
|
|
navigationItem.rightBarButtonItem = addSkillToMeButton
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if profileUser != nil {
|
|
// do nothing
|
|
|
|
} else {
|
|
filterBarItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.Plain, target: self, action: "showFilter:")
|
|
navigationItem.leftBarButtonItem = filterBarItem
|
|
}
|
|
|
|
feedsTableView.backgroundColor = UIColor.whiteColor()
|
|
feedsTableView.tableFooterView = UIView()
|
|
feedsTableView.separatorColor = UIColor.yepCellSeparatorColor()
|
|
|
|
feedsTableView.registerNib(UINib(nibName: feedSkillUsersCellID, bundle: nil), forCellReuseIdentifier: feedSkillUsersCellID)
|
|
|
|
feedsTableView.registerClass(FeedBasicCell.self, forCellReuseIdentifier: feedBasicCellID)
|
|
feedsTableView.registerClass(FeedBiggerImageCell.self, forCellReuseIdentifier: feedBiggerImageCellID)
|
|
feedsTableView.registerClass(FeedNormalImagesCell.self, forCellReuseIdentifier: feedNormalImagesCellID)
|
|
feedsTableView.registerClass(FeedAnyImagesCell.self, forCellReuseIdentifier: feedAnyImagesCellID)
|
|
feedsTableView.registerClass(FeedGithubRepoCell.self, forCellReuseIdentifier: feedGithubRepoCellID)
|
|
feedsTableView.registerClass(FeedDribbbleShotCell.self, forCellReuseIdentifier: feedDribbbleShotCellID)
|
|
feedsTableView.registerClass(FeedVoiceCell.self, forCellReuseIdentifier: feedVoiceCellID)
|
|
feedsTableView.registerClass(FeedLocationCell.self, forCellReuseIdentifier: feedLocationCellID)
|
|
|
|
feedsTableView.registerNib(UINib(nibName: loadMoreTableViewCellID, bundle: nil), forCellReuseIdentifier: loadMoreTableViewCellID)
|
|
|
|
|
|
if hideRightBarItem {
|
|
navigationItem.rightBarButtonItem = nil
|
|
}
|
|
|
|
if preparedFeedsCount > 0 {
|
|
currentPageIndex = 2
|
|
}
|
|
|
|
// 没有 profileUser 才设置 feedSortStyle 以请求服务器
|
|
if profileUser == nil {
|
|
|
|
if let
|
|
value = YepUserDefaults.feedSortStyle.value,
|
|
_feedSortStyle = FeedSortStyle(rawValue: value) {
|
|
feedSortStyle = _feedSortStyle
|
|
|
|
} else {
|
|
feedSortStyle = .Match
|
|
}
|
|
|
|
if skill == nil {
|
|
if let realm = try? Realm(), offlineJSON = OfflineJSON.withName(.Feeds, inRealm: realm) {
|
|
if let JSON = offlineJSON.JSON, feeds = parseFeeds(JSON) {
|
|
self.feeds = feeds
|
|
activityIndicator.stopAnimating()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
view.addSubview(feedsFPSLabel)
|
|
#endif
|
|
}
|
|
|
|
// MARK: Actions
|
|
|
|
@objc private func addSkillToMe(sender: AnyObject) {
|
|
println("addSkillToMe")
|
|
|
|
if let skillID = skill?.id, skillLocalName = skill?.localName {
|
|
|
|
let doAddSkillToSkillSet: SkillSet -> Void = { skillSet in
|
|
|
|
addSkillWithSkillID(skillID, toSkillSet: skillSet, failureHandler: { reason, errorMessage in
|
|
defaultFailureHandler(reason, errorMessage: errorMessage)
|
|
|
|
}, completion: { [weak self] _ in
|
|
|
|
YepAlert.alert(title: NSLocalizedString("Success", comment: ""), message: String(format: NSLocalizedString("Added %@ to %@ successfully!", comment: ""), skillLocalName, skillSet.name), dismissTitle: NSLocalizedString("OK", comment: ""), inViewController: self, withDismissAction: nil)
|
|
|
|
dispatch_async(dispatch_get_main_queue()) {
|
|
self?.navigationItem.rightBarButtonItem = nil
|
|
}
|
|
|
|
syncMyInfoAndDoFurtherAction {
|
|
}
|
|
})
|
|
}
|
|
|
|
let alertController = UIAlertController(title: NSLocalizedString("Choose skill set", comment: ""), message: String(format: NSLocalizedString("Which skill set do you want %@ to be?", comment: ""), skillLocalName), preferredStyle: .Alert)
|
|
|
|
let cancelAction: UIAlertAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel) { action in
|
|
}
|
|
alertController.addAction(cancelAction)
|
|
|
|
let learningAction: UIAlertAction = UIAlertAction(title: SkillSet.Learning.name, style: .Default) { action in
|
|
doAddSkillToSkillSet(.Learning)
|
|
}
|
|
alertController.addAction(learningAction)
|
|
|
|
let masterAction: UIAlertAction = UIAlertAction(title: SkillSet.Master.name, style: .Default) { action in
|
|
doAddSkillToSkillSet(.Master)
|
|
}
|
|
alertController.addAction(masterAction)
|
|
|
|
presentViewController(alertController, animated: true, completion: nil)
|
|
}
|
|
}
|
|
|
|
override func viewWillAppear(animated: Bool) {
|
|
super.viewWillAppear(animated)
|
|
|
|
/*
|
|
// 尝试恢复原始的 NavigationControllerDelegate,如果自定义 push 了才需要
|
|
if let delegate = originalNavigationControllerDelegate {
|
|
navigationController?.delegate = delegate
|
|
navigationControllerDelegate = nil
|
|
}
|
|
*/
|
|
|
|
navigationController?.setNavigationBarHidden(false, animated: false)
|
|
|
|
//tabBarController?.tabBar.hidden = (skill == nil && profileUser == nil) ? false : true
|
|
}
|
|
|
|
// MARK: - Actions
|
|
|
|
@IBAction private func showFilter(sender: AnyObject) {
|
|
|
|
if feedSortStyle != .Time {
|
|
filterView.currentDiscoveredUserSortStyle = DiscoveredUserSortStyle(rawValue: feedSortStyle.rawValue)!
|
|
} else {
|
|
filterView.currentDiscoveredUserSortStyle = .LastSignIn
|
|
}
|
|
|
|
filterView.filterAction = { [weak self] discoveredUserSortStyle in
|
|
|
|
if discoveredUserSortStyle != .LastSignIn {
|
|
self?.feedSortStyle = FeedSortStyle(rawValue: discoveredUserSortStyle.rawValue)!
|
|
} else {
|
|
self?.feedSortStyle = .Time
|
|
}
|
|
}
|
|
|
|
if let window = view.window {
|
|
filterView.showInView(window)
|
|
}
|
|
}
|
|
|
|
private var currentPageIndex = 1
|
|
private var isFetchingFeeds = false
|
|
enum UpdateFeedsMode {
|
|
case Top
|
|
case LoadMore
|
|
case Static
|
|
}
|
|
private func updateFeeds(mode mode: UpdateFeedsMode = .Top, finish: (() -> Void)? = nil) {
|
|
|
|
if isFetchingFeeds {
|
|
finish?()
|
|
return
|
|
}
|
|
|
|
isFetchingFeeds = true
|
|
|
|
if mode == .Top && feeds.isEmpty {
|
|
activityIndicator.startAnimating()
|
|
}
|
|
|
|
switch mode {
|
|
case .Top:
|
|
currentPageIndex = 1
|
|
case .LoadMore:
|
|
currentPageIndex++
|
|
case .Static:
|
|
break
|
|
}
|
|
|
|
let failureHandler: (Reason, String?) -> Void = { reason, errorMessage in
|
|
|
|
dispatch_async(dispatch_get_main_queue()) { [weak self] in
|
|
|
|
self?.isFetchingFeeds = false
|
|
|
|
self?.activityIndicator.stopAnimating()
|
|
|
|
finish?()
|
|
}
|
|
|
|
defaultFailureHandler(reason, errorMessage: errorMessage)
|
|
}
|
|
|
|
let completion: [DiscoveredFeed] -> Void = { feeds in
|
|
|
|
dispatch_async(dispatch_get_main_queue()) { [weak self] in
|
|
|
|
self?.isFetchingFeeds = false
|
|
|
|
self?.activityIndicator.stopAnimating()
|
|
|
|
finish?()
|
|
}
|
|
|
|
dispatch_async(dispatch_get_main_queue()) { [weak self] in
|
|
|
|
if let strongSelf = self {
|
|
|
|
let newFeeds = feeds
|
|
let oldFeeds = strongSelf.feeds
|
|
|
|
var wayToUpdate: UITableView.WayToUpdate = .None
|
|
|
|
if strongSelf.feeds.isEmpty {
|
|
wayToUpdate = .ReloadData
|
|
}
|
|
|
|
switch mode {
|
|
case .Top:
|
|
strongSelf.feeds = newFeeds
|
|
|
|
case .LoadMore:
|
|
let oldFeedsCount = strongSelf.feeds.count
|
|
strongSelf.feeds += newFeeds
|
|
let newFeedsCount = strongSelf.feeds.count
|
|
|
|
let indexPaths = Array(oldFeedsCount..<newFeedsCount).map({ NSIndexPath(forRow: $0, inSection: Section.Feed.rawValue) })
|
|
if !indexPaths.isEmpty {
|
|
wayToUpdate = .Insert(indexPaths)
|
|
}
|
|
|
|
case .Static:
|
|
var indexesOfMessagesCountUpdated = [Int]()
|
|
newFeeds.forEach({ feed in
|
|
if let index = strongSelf.feeds.indexOf(feed) {
|
|
if strongSelf.feeds[index].messagesCount != feed.messagesCount {
|
|
strongSelf.feeds[index].messagesCount = feed.messagesCount
|
|
indexesOfMessagesCountUpdated.append(index)
|
|
}
|
|
}
|
|
})
|
|
|
|
let indexPaths = indexesOfMessagesCountUpdated.map({ NSIndexPath(forRow: $0, inSection: Section.Feed.rawValue) })
|
|
|
|
wayToUpdate = .ReloadIndexPaths(indexPaths)
|
|
}
|
|
|
|
if !wayToUpdate.needsLabor && !newFeeds.isEmpty {
|
|
|
|
var indexesOfMessagesCountUpdated = [Int]()
|
|
|
|
if newFeeds.count == oldFeeds.count {
|
|
|
|
var index = 0
|
|
while index < newFeeds.count {
|
|
let newFeed = newFeeds[index]
|
|
let oldFeed = oldFeeds[index]
|
|
|
|
if newFeed.id != oldFeed.id {
|
|
wayToUpdate = .ReloadData
|
|
break
|
|
} else if newFeed.messagesCount != oldFeed.messagesCount {
|
|
indexesOfMessagesCountUpdated.append(index)
|
|
}
|
|
|
|
index += 1
|
|
}
|
|
|
|
} else {
|
|
wayToUpdate = .ReloadData
|
|
}
|
|
|
|
if !wayToUpdate.needsLabor {
|
|
let indexPaths = indexesOfMessagesCountUpdated.map({ NSIndexPath(forRow: $0, inSection: Section.Feed.rawValue) })
|
|
|
|
wayToUpdate = .ReloadIndexPaths(indexPaths)
|
|
}
|
|
}
|
|
|
|
wayToUpdate.performWithTableView(strongSelf.feedsTableView)
|
|
}
|
|
}
|
|
}
|
|
|
|
let perPage = 20
|
|
|
|
if let profileUser = profileUser {
|
|
feedsOfUser(profileUser.userID, pageIndex: currentPageIndex, perPage: (preparedFeedsCount > 0) ? preparedFeedsCount : perPage, failureHandler: failureHandler, completion: completion)
|
|
|
|
} else {
|
|
|
|
var feedSortStyle = self.feedSortStyle
|
|
if skill != nil {
|
|
feedSortStyle = .Time
|
|
}
|
|
|
|
let maxFeedID = (mode == .LoadMore && (feedSortStyle == FeedSortStyle.Time)) ? feeds.last?.id : nil
|
|
|
|
discoverFeedsWithSortStyle(feedSortStyle, skill: skill, pageIndex: currentPageIndex, perPage: perPage, maxFeedID: maxFeedID, failureHandler:failureHandler, completion: completion)
|
|
}
|
|
}
|
|
|
|
@IBAction private func createNewFeed(sender: AnyObject) {
|
|
|
|
if let window = view.window {
|
|
newFeedTypesView.showInView(window)
|
|
}
|
|
}
|
|
|
|
@objc private func updateAudioPlaybackProgress(timer: NSTimer) {
|
|
|
|
func updateCellOfFeedAudio(feedAudio: FeedAudio, withCurrentTime currentTime: NSTimeInterval) {
|
|
|
|
let feedID = feedAudio.feedID
|
|
|
|
for index in 0..<feeds.count {
|
|
let feed = feeds[index]
|
|
if feed.id == feedID {
|
|
|
|
let indexPath = NSIndexPath(forRow: index, inSection: Section.Feed.rawValue)
|
|
|
|
if let cell = feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedVoiceCell {
|
|
cell.audioPlayedDuration = currentTime
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if let audioPlayer = YepAudioService.sharedManager.audioPlayer {
|
|
|
|
if let playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio {
|
|
|
|
let currentTime = audioPlayer.currentTime
|
|
|
|
setAudioPlayedDuration(currentTime, ofFeedAudio: playingFeedAudio )
|
|
|
|
updateCellOfFeedAudio(playingFeedAudio, withCurrentTime: currentTime)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Navigation
|
|
|
|
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
|
|
|
|
guard navigationController?.topViewController == self else {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
|
|
|
guard let identifier = segue.identifier else {
|
|
return
|
|
}
|
|
|
|
let afterCreatedFeedAction: DiscoveredFeed -> Void = { [weak self] feed in
|
|
|
|
dispatch_async(dispatch_get_main_queue()) {
|
|
|
|
if let strongSelf = self {
|
|
|
|
strongSelf.feeds.insert(feed, atIndex: 0)
|
|
|
|
let indexPath = NSIndexPath(forRow: 0, inSection: Section.Feed.rawValue)
|
|
strongSelf.updateFeedsTableViewOrInsertWithIndexPaths([indexPath])
|
|
}
|
|
}
|
|
|
|
joinGroup(groupID: feed.groupID, failureHandler: nil, completion: {
|
|
})
|
|
}
|
|
|
|
switch identifier {
|
|
|
|
case "showProfile":
|
|
|
|
let vc = segue.destinationViewController as! ProfileViewController
|
|
|
|
if let indexPath = sender as? NSIndexPath {
|
|
let discoveredUser = feeds[indexPath.row].creator
|
|
vc.profileUser = ProfileUser.DiscoveredUserType(discoveredUser)
|
|
}
|
|
|
|
vc.fromType = .None
|
|
vc.setBackButtonWithTitle()
|
|
|
|
vc.hidesBottomBarWhenPushed = true
|
|
|
|
case "showSkillHome":
|
|
|
|
let vc = segue.destinationViewController as! SkillHomeViewController
|
|
|
|
if let skill = skill {
|
|
vc.skill = SkillCell.Skill(ID: skill.id, localName: skill.localName, coverURLString: skill.coverURLString, category: nil)
|
|
}
|
|
|
|
vc.hidesBottomBarWhenPushed = true
|
|
|
|
case "showFeedsWithSkill":
|
|
|
|
let vc = segue.destinationViewController as! FeedsViewController
|
|
|
|
if let indexPath = sender as? NSIndexPath {
|
|
vc.skill = feeds[indexPath.row].skill
|
|
}
|
|
|
|
vc.hidesBottomBarWhenPushed = true
|
|
|
|
case "showConversation":
|
|
|
|
let vc = segue.destinationViewController as! ConversationViewController
|
|
|
|
guard let
|
|
indexPath = sender as? NSIndexPath,
|
|
feed = feeds[safe: indexPath.row],
|
|
realm = try? Realm() else {
|
|
return
|
|
}
|
|
|
|
realm.beginWrite()
|
|
let feedConversation = vc.prepareConversationForFeed(feed, inRealm: realm)
|
|
let _ = try? realm.commitWrite()
|
|
|
|
vc.conversation = feedConversation
|
|
vc.conversationFeed = ConversationFeed.DiscoveredFeedType(feed)
|
|
|
|
vc.afterDeletedFeedAction = { [weak self] in
|
|
self?.updateFeeds()
|
|
}
|
|
|
|
vc.conversationDirtyAction = { [weak self] in
|
|
self?.updateFeeds(mode: .Static)
|
|
}
|
|
|
|
case "presentNewFeed":
|
|
|
|
guard let
|
|
nvc = segue.destinationViewController as? UINavigationController,
|
|
vc = nvc.topViewController as? NewFeedViewController
|
|
else {
|
|
return
|
|
}
|
|
|
|
vc.preparedSkill = skill
|
|
|
|
vc.afterCreatedFeedAction = afterCreatedFeedAction
|
|
|
|
case "presentNewFeedVoiceRecord":
|
|
|
|
guard let
|
|
nvc = segue.destinationViewController as? UINavigationController,
|
|
vc = nvc.topViewController as? NewFeedVoiceRecordViewController
|
|
else {
|
|
return
|
|
}
|
|
|
|
vc.preparedSkill = skill
|
|
|
|
vc.afterCreatedFeedAction = afterCreatedFeedAction
|
|
|
|
case "presentPickLocation":
|
|
|
|
guard let
|
|
nvc = segue.destinationViewController as? UINavigationController,
|
|
vc = nvc.topViewController as? PickLocationViewController
|
|
else {
|
|
return
|
|
}
|
|
|
|
vc.purpose = .Feed
|
|
|
|
vc.preparedSkill = skill
|
|
|
|
vc.afterCreatedFeedAction = afterCreatedFeedAction
|
|
|
|
/*
|
|
case "showFeedMedia":
|
|
|
|
let info = sender as! [String: AnyObject]
|
|
|
|
let vc = segue.destinationViewController as! MessageMediaViewController
|
|
|
|
if let box = info["attachments"] as? Box<[DiscoveredAttachment]> {
|
|
let attachments = box.value
|
|
vc.previewMedias = attachments.map({ PreviewMedia.AttachmentType(attachment: $0) })
|
|
}
|
|
|
|
if let index = info["index"] as? Int {
|
|
vc.startIndex = index
|
|
}
|
|
|
|
let transitionView = info["transitionView"] as! UIImageView
|
|
|
|
let delegate = ConversationMessagePreviewNavigationControllerDelegate()
|
|
delegate.isFeedMedia = true
|
|
delegate.snapshot = UIScreen.mainScreen().snapshotViewAfterScreenUpdates(false)
|
|
|
|
var frame = transitionView.convertRect(transitionView.frame, toView: view)
|
|
delegate.frame = frame
|
|
if let image = transitionView.image {
|
|
let width = image.size.width
|
|
let height = image.size.height
|
|
if width > height {
|
|
let newWidth = frame.width * (width / height)
|
|
frame.origin.x -= (newWidth - frame.width) / 2
|
|
frame.size.width = newWidth
|
|
} else {
|
|
let newHeight = frame.height * (height / width)
|
|
frame.origin.y -= (newHeight - frame.height) / 2
|
|
frame.size.height = newHeight
|
|
}
|
|
delegate.thumbnailImage = image
|
|
}
|
|
delegate.thumbnailFrame = frame
|
|
|
|
delegate.transitionView = transitionView
|
|
|
|
navigationControllerDelegate = delegate
|
|
|
|
// 在自定义 push 之前,记录原始的 NavigationControllerDelegate 以便 pop 后恢复
|
|
originalNavigationControllerDelegate = navigationController!.delegate
|
|
|
|
navigationController?.delegate = delegate
|
|
*/
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - UITableViewDataSource, UITableViewDelegate
|
|
|
|
extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
|
|
|
|
private enum Section: Int {
|
|
case SkillUsers
|
|
case Feed
|
|
case LoadMore
|
|
}
|
|
|
|
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
|
|
|
|
return 3
|
|
}
|
|
|
|
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
|
|
switch section {
|
|
case Section.SkillUsers.rawValue:
|
|
return (skill == nil) ? 0 : 1
|
|
case Section.Feed.rawValue:
|
|
return feeds.count
|
|
case Section.LoadMore.rawValue:
|
|
return feeds.isEmpty ? 0 : 1
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
|
|
|
switch indexPath.section {
|
|
|
|
case Section.SkillUsers.rawValue:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedSkillUsersCellID) as! FeedSkillUsersCell
|
|
return cell
|
|
|
|
case Section.Feed.rawValue:
|
|
let feed = feeds[indexPath.row]
|
|
|
|
switch feed.kind {
|
|
|
|
case .Text:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedBasicCellID) as! FeedBasicCell
|
|
return cell
|
|
|
|
case .Image:
|
|
if feed.imageAttachmentsCount == 1 {
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedBiggerImageCellID) as! FeedBiggerImageCell
|
|
return cell
|
|
|
|
} else if feed.imageAttachmentsCount <= 3 {
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedNormalImagesCellID) as! FeedNormalImagesCell
|
|
return cell
|
|
|
|
} else {
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedAnyImagesCellID) as! FeedAnyImagesCell
|
|
return cell
|
|
}
|
|
|
|
case .GithubRepo:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedGithubRepoCellID) as! FeedGithubRepoCell
|
|
return cell
|
|
|
|
case .DribbbleShot:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedDribbbleShotCellID) as! FeedDribbbleShotCell
|
|
return cell
|
|
|
|
case .Audio:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedVoiceCellID) as! FeedVoiceCell
|
|
return cell
|
|
|
|
case .Location:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedLocationCellID) as! FeedLocationCell
|
|
return cell
|
|
|
|
default:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(feedBasicCellID) as! FeedBasicCell
|
|
return cell
|
|
}
|
|
|
|
case Section.LoadMore.rawValue:
|
|
let cell = tableView.dequeueReusableCellWithIdentifier(loadMoreTableViewCellID) as! LoadMoreTableViewCell
|
|
return cell
|
|
|
|
default:
|
|
return UITableViewCell()
|
|
}
|
|
}
|
|
|
|
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
|
|
|
|
switch indexPath.section {
|
|
|
|
case Section.SkillUsers.rawValue:
|
|
|
|
guard let cell = cell as? FeedSkillUsersCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeeds(feeds)
|
|
|
|
case Section.Feed.rawValue:
|
|
|
|
let feed = feeds[indexPath.row]
|
|
|
|
guard let cell = cell as? FeedBasicCell else {
|
|
break
|
|
}
|
|
|
|
cell.tapAvatarAction = { [weak self] cell in
|
|
if let indexPath = tableView.indexPathForCell(cell) { // 不直接捕捉 indexPath
|
|
self?.performSegueWithIdentifier("showProfile", sender: indexPath)
|
|
}
|
|
}
|
|
|
|
cell.tapSkillAction = { [weak self] cell in
|
|
if let indexPath = tableView.indexPathForCell(cell) { // 不直接捕捉 indexPath
|
|
self?.performSegueWithIdentifier("showFeedsWithSkill", sender: indexPath)
|
|
}
|
|
}
|
|
|
|
// simulate select effects when tap on messageTextView or cell.mediaCollectionView's space part
|
|
// 不能直接捕捉 indexPath,不然新插入后,之前捕捉的 indexPath 不能代表 cell 的新位置,模拟点击会错位到其它 cell
|
|
cell.touchesBeganAction = { [weak self] cell in
|
|
guard let indexPath = tableView.indexPathForCell(cell) else {
|
|
return
|
|
}
|
|
self?.tableView(tableView, willSelectRowAtIndexPath: indexPath)
|
|
tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
|
|
}
|
|
cell.touchesEndedAction = { [weak self] cell in
|
|
guard let indexPath = tableView.indexPathForCell(cell) else {
|
|
return
|
|
}
|
|
delay(0.03) { [weak self] in
|
|
self?.tableView(tableView, didSelectRowAtIndexPath: indexPath)
|
|
}
|
|
}
|
|
cell.touchesCancelledAction = { cell in
|
|
guard let indexPath = tableView.indexPathForCell(cell) else {
|
|
return
|
|
}
|
|
tableView.deselectRowAtIndexPath(indexPath, animated: true)
|
|
}
|
|
|
|
let layout = FeedsViewController.layoutPool.feedCellLayoutOfFeed(feed)
|
|
let update: FeedCellLayout.Update = { newLayout in
|
|
FeedsViewController.layoutPool.updateFeedCellLayout(newLayout, forFeed: feed)
|
|
}
|
|
let layoutCache = (layout: layout, update: update)
|
|
|
|
switch feed.kind {
|
|
|
|
case .Text:
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
case .Image:
|
|
|
|
let tapMediaAction: FeedTapMediaAction = { [weak self] transitionView, image, attachments, index in
|
|
|
|
guard image != nil else {
|
|
return
|
|
}
|
|
|
|
let vc = UIStoryboard(name: "MediaPreview", bundle: nil).instantiateViewControllerWithIdentifier("MediaPreviewViewController") as! MediaPreviewViewController
|
|
|
|
vc.previewMedias = attachments.map({ PreviewMedia.AttachmentType(attachment: $0) })
|
|
vc.startIndex = index
|
|
|
|
let transitionView = transitionView
|
|
let frame = transitionView.convertRect(transitionView.bounds, toView: self?.view)
|
|
vc.previewImageViewInitalFrame = frame
|
|
vc.bottomPreviewImage = image
|
|
|
|
vc.transitionView = transitionView
|
|
|
|
delay(0) {
|
|
transitionView.alpha = 0 // 放到下一个 Runloop 避免太快消失产生闪烁
|
|
}
|
|
vc.afterDismissAction = { [weak self] in
|
|
transitionView.alpha = 1
|
|
self?.view.window?.makeKeyAndVisible()
|
|
}
|
|
|
|
mediaPreviewWindow.rootViewController = vc
|
|
mediaPreviewWindow.windowLevel = UIWindowLevelAlert - 1
|
|
mediaPreviewWindow.makeKeyAndVisible()
|
|
}
|
|
|
|
if feed.imageAttachmentsCount == 1 {
|
|
guard let cell = cell as? FeedBiggerImageCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
cell.tapMediaAction = tapMediaAction
|
|
|
|
} else if feed.imageAttachmentsCount <= 3 {
|
|
|
|
guard let cell = cell as? FeedNormalImagesCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
cell.tapMediaAction = tapMediaAction
|
|
|
|
} else {
|
|
guard let cell = cell as? FeedAnyImagesCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
cell.tapMediaAction = tapMediaAction
|
|
}
|
|
|
|
case .GithubRepo:
|
|
|
|
guard let cell = cell as? FeedGithubRepoCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
cell.tapGithubRepoLinkAction = { [weak self] URL in
|
|
self?.yep_openURL(URL)
|
|
}
|
|
|
|
case .DribbbleShot:
|
|
|
|
guard let cell = cell as? FeedDribbbleShotCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
cell.tapDribbbleShotLinkAction = { [weak self] URL in
|
|
self?.yep_openURL(URL)
|
|
}
|
|
|
|
cell.tapDribbbleShotMediaAction = { [weak self] transitionView, image, imageURL, linkURL in
|
|
|
|
guard image != nil else {
|
|
return
|
|
}
|
|
|
|
let vc = UIStoryboard(name: "MediaPreview", bundle: nil).instantiateViewControllerWithIdentifier("MediaPreviewViewController") as! MediaPreviewViewController
|
|
|
|
vc.previewMedias = [PreviewMedia.WebImage(imageURL: imageURL, linkURL: linkURL)]
|
|
vc.startIndex = 0
|
|
|
|
let transitionView = transitionView
|
|
let frame = transitionView.convertRect(transitionView.bounds, toView: self?.view)
|
|
vc.previewImageViewInitalFrame = frame
|
|
vc.bottomPreviewImage = image
|
|
|
|
delay(0) {
|
|
transitionView.alpha = 0 // 放到下一个 Runloop 避免太快消失产生闪烁
|
|
}
|
|
vc.afterDismissAction = { [weak self] in
|
|
transitionView.alpha = 1
|
|
self?.view.window?.makeKeyAndVisible()
|
|
}
|
|
|
|
mediaPreviewWindow.rootViewController = vc
|
|
mediaPreviewWindow.windowLevel = UIWindowLevelAlert - 1
|
|
mediaPreviewWindow.makeKeyAndVisible()
|
|
}
|
|
|
|
case .Audio:
|
|
|
|
guard let cell = cell as? FeedVoiceCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
cell.playOrPauseAudioAction = { [weak self] cell in
|
|
|
|
guard let realm = try? Realm(), feedAudio = FeedAudio.feedAudioWithFeedID(feed.id, inRealm: realm) else {
|
|
return
|
|
}
|
|
|
|
let play: () -> Void = { [weak self] in
|
|
|
|
if let strongSelf = self {
|
|
|
|
let audioPlayedDuration = strongSelf.audioPlayedDurationOfFeedAudio(feedAudio)
|
|
YepAudioService.sharedManager.playAudioWithFeedAudio(feedAudio, beginFromTime: audioPlayedDuration, delegate: strongSelf, success: {
|
|
println("playAudioWithFeedAudio success!")
|
|
|
|
let playbackTimer = NSTimer.scheduledTimerWithTimeInterval(0.02, target: strongSelf, selector: "updateAudioPlaybackProgress:", userInfo: nil, repeats: true)
|
|
YepAudioService.sharedManager.playbackTimer = playbackTimer
|
|
|
|
cell.audioPlaying = true
|
|
})
|
|
}
|
|
}
|
|
|
|
if let strongSelf = self {
|
|
|
|
// 如果在播放,就暂停
|
|
if let playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio, audioPlayer = YepAudioService.sharedManager.audioPlayer where audioPlayer.playing {
|
|
|
|
audioPlayer.pause()
|
|
|
|
if let playbackTimer = YepAudioService.sharedManager.playbackTimer {
|
|
playbackTimer.invalidate()
|
|
}
|
|
|
|
let feedID = playingFeedAudio.feedID
|
|
for index in 0..<strongSelf.feeds.count {
|
|
let feed = strongSelf.feeds[index]
|
|
if feed.id == feedID {
|
|
|
|
let indexPath = NSIndexPath(forRow: index, inSection: Section.Feed.rawValue)
|
|
|
|
if let cell = strongSelf.feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedVoiceCell {
|
|
cell.audioPlaying = false
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if let playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio where playingFeedAudio.feedID == feed.id {
|
|
} else {
|
|
// 暂停的是别人,咱开始播放
|
|
play()
|
|
}
|
|
|
|
} else {
|
|
// 直接播放
|
|
play()
|
|
}
|
|
}
|
|
}
|
|
|
|
case .Location:
|
|
|
|
guard let cell = cell as? FeedLocationCell else {
|
|
break
|
|
}
|
|
|
|
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
|
|
|
|
cell.tapLocationAction = { locationName, locationCoordinate in
|
|
|
|
let mapItem = MKMapItem(placemark: MKPlacemark(coordinate: locationCoordinate, addressDictionary: nil))
|
|
mapItem.name = locationName
|
|
|
|
mapItem.openInMapsWithLaunchOptions(nil)
|
|
}
|
|
|
|
default:
|
|
break
|
|
}
|
|
|
|
case Section.LoadMore.rawValue:
|
|
|
|
guard let cell = cell as? LoadMoreTableViewCell else {
|
|
break
|
|
}
|
|
|
|
println("load more feeds")
|
|
|
|
if !cell.loadingActivityIndicator.isAnimating() {
|
|
cell.loadingActivityIndicator.startAnimating()
|
|
}
|
|
|
|
updateFeeds(mode: .LoadMore, finish: { [weak cell] in
|
|
cell?.loadingActivityIndicator.stopAnimating()
|
|
})
|
|
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
|
|
|
|
switch indexPath.section {
|
|
|
|
case Section.SkillUsers.rawValue:
|
|
return 70
|
|
|
|
case Section.Feed.rawValue:
|
|
let feed = feeds[indexPath.row]
|
|
return FeedsViewController.layoutPool.heightOfFeed(feed)
|
|
|
|
case Section.LoadMore.rawValue:
|
|
return 60
|
|
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
|
|
return indexPath
|
|
}
|
|
|
|
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
|
|
|
defer {
|
|
tableView.deselectRowAtIndexPath(indexPath, animated: true)
|
|
}
|
|
|
|
switch indexPath.section {
|
|
|
|
case Section.SkillUsers.rawValue:
|
|
performSegueWithIdentifier("showSkillHome", sender: nil)
|
|
|
|
case Section.Feed.rawValue:
|
|
performSegueWithIdentifier("showConversation", sender: indexPath)
|
|
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
// Report
|
|
|
|
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
|
|
|
|
switch indexPath.section {
|
|
|
|
case Section.SkillUsers.rawValue:
|
|
return false
|
|
|
|
case Section.Feed.rawValue:
|
|
let feed = feeds[indexPath.item]
|
|
if feed.creator.id == YepUserDefaults.userID.value {
|
|
return false
|
|
} else {
|
|
return true
|
|
}
|
|
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
|
|
|
|
let reportAction = UITableViewRowAction(style: .Default, title: NSLocalizedString("Report", comment: "")) { [weak self] action, indexPath in
|
|
|
|
if let feed = self?.feeds[indexPath.row] {
|
|
self?.report(.Feed(feed))
|
|
}
|
|
|
|
tableView.setEditing(false, animated: true)
|
|
}
|
|
|
|
return [reportAction]
|
|
}
|
|
|
|
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
|
|
}
|
|
|
|
// MARK: UIScrollViewDelegate
|
|
|
|
func scrollViewDidScroll(scrollView: UIScrollView) {
|
|
|
|
pullToRefreshView.scrollViewDidScroll(scrollView)
|
|
}
|
|
|
|
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
|
|
|
pullToRefreshView.scrollViewWillEndDragging(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
|
|
}
|
|
|
|
func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
|
|
|
|
pullToRefreshView.scrollViewDidEndScrollingAnimation(scrollView)
|
|
}
|
|
}
|
|
|
|
// MARK: PullToRefreshViewDelegate
|
|
|
|
extension FeedsViewController: PullToRefreshViewDelegate {
|
|
|
|
func pulllToRefreshViewDidRefresh(pulllToRefreshView: PullToRefreshView) {
|
|
|
|
activityIndicator.alpha = 0
|
|
|
|
let finish: () -> Void = { [weak self] in
|
|
delay(0.3) { // 人为延迟,增加等待感
|
|
pulllToRefreshView.endRefreshingAndDoFurtherAction() {}
|
|
|
|
self?.activityIndicator.alpha = 1
|
|
}
|
|
}
|
|
|
|
pullToRefreshView.refreshTimeoutAction = finish
|
|
|
|
updateFeeds(finish: finish)
|
|
}
|
|
|
|
func scrollView() -> UIScrollView {
|
|
return feedsTableView
|
|
}
|
|
}
|
|
|
|
// MARK: AVAudioPlayerDelegate
|
|
|
|
extension FeedsViewController: AVAudioPlayerDelegate {
|
|
|
|
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
|
|
|
|
println("audioPlayerDidFinishPlaying \(flag)")
|
|
|
|
if let playbackTimer = YepAudioService.sharedManager.playbackTimer {
|
|
playbackTimer.invalidate()
|
|
}
|
|
|
|
if let playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio {
|
|
setAudioPlayedDuration(0, ofFeedAudio: playingFeedAudio)
|
|
println("setAudioPlayedDuration to 0")
|
|
}
|
|
}
|
|
}
|
|
|
|
|