Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nazmulkp/761cfb16308891d998a163059c26bd55 to your computer and use it in GitHub Desktop.
Save nazmulkp/761cfb16308891d998a163059c26bd55 to your computer and use it in GitHub Desktop.
The initial feed will download with 4 post for previewing, but if the user scrolling down then load more posts, so i need to add section to the bottom table view and section remove from the top.
import UIKit
//import XCGLogger
typealias CheckResult = (Bool)->()
class NewsViewController: BaseViewController {
let newsfeedCellId = "newsfeedCellId"
// inject object dependency
lazy var apiClient: APINewsFeedsProtocol = APINewsFeedWebClient()
var tableViewIndex : IndexPath?
var states : [[State]]?
// variable to save the last position visited, default to zero
fileprivate var lastContentOffset: CGFloat = 0
//variable to save the section added from top
var sectionFromTop : Int?
//variable to save the section added from bottom
var sectionFromBottom : Int?
var newestStateTime : Date?
var oldestStateTime : Date?
var searchBar : LeftAlignedSearchBar!
override func viewDidLoad() {
self.registerViews()
self.setupViews()
self.loadDataToTheView()
states = [[State]]()
initUpdateUI(createdAfter: nil, createdBefore: nil, completion: nil)
}
lazy var newsFeedTableView : UITableView = {
var tableView = UITableView()
tableView.backgroundColor = UIColor.white
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.delegate = self
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}()
}
extension NewsViewController {
override func setupViews() {
self.view.addSubview(newsFeedTableView)
self.newsFeedTableView.fillSuperview()//rander the full screen
}
override func registerViews() {
newsFeedTableView.register(NewsTableViewViewCell.self, forCellReuseIdentifier: newsfeedCellId)
}
}
extension NewsViewController : UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return states?.count ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return states?[section].count ?? 0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let _states = self.states?[indexPath.section]
let _state = _states?[indexPath.row]
//let's get an estimation of the height of our cell based on user.bioText
let approximateWidthOfStateTextView = view.frame.width - 10
return 250 + (_state?.text.height(withConstrainedWidth: approximateWidthOfStateTextView, font: UIFont(name: Constants.FontNames.SFNSText.SFNSTextRegular, size: 14)!))!
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let indexpath = tableViewIndex else { return }
if self.lastContentOffset > scrollView.contentOffset.y {
if let _states = states?[indexpath.section]{
if _states.count / 2 == indexpath.row + 1 {
if sectionFromTop != indexpath.section {
sectionFromTop = indexpath.section
self.newestState(createdAfter: _states.first?.createdAt, completion: nil)
}
}
}
} else if self.lastContentOffset < scrollView.contentOffset.y {
if let _states = states?[indexpath.section]{
if _states.count / 2 == indexpath.row + 1 {
if sectionFromBottom != indexpath.section {
sectionFromBottom = indexpath.section
self.oldestState(createdBefore: _states.last?.createdAt, completion: nil)
}
}
}
}
self.lastContentOffset = scrollView.contentOffset.y
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: newsfeedCellId, for: indexPath) as! NewsTableViewViewCell
if let _states = states?[indexPath.section]{
tableViewIndex = indexPath
cell.state = _states[indexPath.row]
cell.backgroundColor = UIColor.blue
}
return cell
}
}
extension NewsViewController : UITableViewDelegate {
}
//MARK:- Load Data to the UI
extension NewsViewController {
func initUpdateUI(createdAfter: Date?, createdBefore: Date?, completion: CheckResult?){
self.loadNewsFeeds(createdAfter: nil, createdBefore: nil, completion: {(states) in
if let sortedStates = states {
self.states?.append(sortedStates) //Update states property
self.newestStateTime = sortedStates.first?.createdAt
self.oldestStateTime = sortedStates.last?.createdAt
DispatchQueue.main.async{
self.newsFeedTableView.reloadData()
completion?(true)
}
}
} )
}
func newestState(createdAfter createdAt: Date?, completion : CheckResult?){
self.loadNewsFeeds(createdAfter: createdAt, createdBefore: nil, completion: {(states) in
if let sortedStates = states {
guard let firstCreatedAt = sortedStates.first?.createdAt else {
completion?(false)
return
}
guard let _newestStateTime = self.newestStateTime , _newestStateTime < firstCreatedAt else {
completion?(false)
return
}
self.newestStateTime = firstCreatedAt
self.states?.appendAtBeginning(newItem: sortedStates)
self.newsFeedTableView.insertSections([(self.states?.count)! - 3], with: UITableViewRowAnimation.none)
if (self.states?.count)! > 3 {
self.states?.removeLast()
let statesForoldestStateTime = self.states?.last
self.oldestStateTime = statesForoldestStateTime?.last?.createdAt
self.newsFeedTableView.deleteSections([(self.states?.count)! - 1], with: UITableViewRowAnimation.none)
}
completion?(true)
return
}
} )
}
func oldestState(createdBefore createdAt: Date?, completion : CheckResult? ){
self.loadNewsFeeds(createdAfter: nil, createdBefore: createdAt, completion: {(states) in
if let sortedStates = states {
guard let lastCreatedAt = sortedStates.last?.createdAt else {
completion?(false)
return
}
guard let _oldestStateTime = self.oldestStateTime , _oldestStateTime > lastCreatedAt else {
completion?(false)
return
}
self.oldestStateTime = lastCreatedAt
self.states?.append(sortedStates) //Update state property
self.newsFeedTableView.insertSections([(self.states?.count)! - 1], with: .none)
if (self.states?.count)! > 3 {
self.states?.removeFirst()
let statesForoldestStateTime = self.states?.first
self.newestStateTime = statesForoldestStateTime?.first?.createdAt
let indexpostion = (self.states?.count)! - 3
self.newsFeedTableView.deleteSections([indexpostion], with: UITableViewRowAnimation.none)
}
completion?(true)
return
}
} )
}
private func loadNewsFeeds(createdAfter: Date?, createdBefore: Date?, completion: @escaping ([State]?)
-> ()) {
var friendScopeId : UUID?
for (key , value) in (Global.account?.scopesDict)!{
if key == "friends" { friendScopeId = value.id }
}
guard let _friendScopeId = friendScopeId else { return }
let statesByScope = StatesByScope(scopeId: String(describing: _friendScopeId), start: 0, limit: 0, createdAfter: createdAfter, createdBefore: createdBefore)
apiClient.loadNewsFeeds(forScope: statesByScope, completion: {(states, serviceError) in
if let error = serviceError {
print(error.localizedDescription) //Handle service error
} else if let _states = states {
let sortedStates = _states.sorted(by: {$0.createdAt! > $1.createdAt!})
completion(sortedStates)
}
} )
}
}
class NewsTableViewViewCell : BaseTableViewCell{
var state : State?{
didSet{
statesTextView.text = state?.text
}
}
lazy var statesTextView: UITextView = {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
override func setupViews() {
super.setupViews()
addSubview(statesTextView)
statesTextView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 5, leftConstant: 10, bottomConstant: 2, rightConstant: 5, widthConstant: 0, heightConstant: 0)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment