Develop the iOS App using the Swift - Part #2

in #utopian-io7 years ago (edited)

New Features

  • What feature(s) did you add?

On the basis of the previous version, the following features were updated: steemconnect login, comment, vote, release function

  • How did you implement it/them?

This function is updated, mainly related to two files.

STClient.swift

//
//  SteemClient.swift
//  SteemThink
//
//  Created by zhouzhiwei on 2018/2/22.
//  Copyright © 2018年 zijinph. All rights reserved.
//
import UIKit
import MBProgressHUD
let baseURL:String = "https://v2.steemconnect.com"
let appId:String = ""
//GET /get_discussions_by_trending
let discussions_by_trending = "https://api.steemjs.com/get_discussions_by_trending?"
//GET /get_discussions_by_created
let discussions_by_created = "https://api.steemjs.com/get_discussions_by_created?"
//GET /get_discussions_by_hot
let discussions_by_hot = "https://api.steemjs.com/get_discussions_by_hot?"
//GET /get_accounts
let get_accounts = "https://api.steemjs.com/get_accounts?"
let get_content_replies = "https://api.steemjs.com/get_content_replies?"
let get_login_url = "https://v2.steemconnect.com/oauth2/authorize?client_id=steemthink.com&redirect_uri=https://cnsteem.github.io/sc2-angular&scope=vote,comment"
//POST /broadcast
let post_broadcast = "https://v2.steemconnect.com/api/broadcast/"
class STClient: NSObject {    
    typealias STClientCallBack = (_ response: Any?,_ error: Error?)->()    
    //MARK: - vote
    class func vote(
                    voter:String,
                    author:String,
                    permlink:String,
                    weight:NSInteger,
                    finished:@escaping STClientCallBack){
        let param = ["voter": voter,
                     "author": author,
                     "permlink":permlink,
                     "weight":weight,
                     ] as [String : Any]
        self.broadcast(body: ["operations":[["vote",param]]],finished: finished)
    }
    //MARK: - post&comment
    class func comment(
                 parentAuthor:String,
                 parentPermlink:String,
                 author:String,
                 permlink:String,
                 body:String,
                 finished:@escaping STClientCallBack) {
        let param = ["parent_author": parentAuthor,
                     "parent_permlink": parentPermlink,
                     "author":author,
                     "permlink":permlink,
                     "title":"",
                     "body":body,
                     "json_metadata": ""]        
        self.broadcast(body: ["operations":[["comment",param]]],finished: finished)
    }    
    class func broadcast(body:Dictionary<String, Any>,
        finished:@escaping STClientCallBack) {
//        print("jsonData ==============="+"\(NSDictionary_STExtension.getJSONStringFromDictionary(dictionary: body))")
        self.post(url: post_broadcast, body: body, finished: finished)
    }    
    class func post(url:String,body:Dictionary<String, Any>,finished:@escaping STClientCallBack) -> Void {
        let client = STAFNetworkTools.sharedTools;
//        Set the requested header tag
        client.requestSerializer.setValue(UserDataManager.sharedInstance.getToken(), forHTTPHeaderField: "Authorization")
        client.request(method: .POST, urlString: url, parameters: body as AnyObject) { (response, error) in
            finished(response,error)
        }
    }    
    class func get(url:String!,parameters:AnyObject?,to:UIView?,finished:@escaping STClientCallBack){
        var hud:MBProgressHUD?
        if (to != nil){
            hud = MBProgress_STExtension.ST_ShowHUDAddedToView(view: to!, title: "", animated: true)
        }
        STAFNetworkTools.sharedTools.request(method: .GET, urlString: url, parameters: parameters) { (response: Any?,error: Error?) in
            if (hud != nil) {
                hud?.hide(animated: true)
            }
            if (error != nil) && (to != nil) {
                MBProgress_STExtension.ST_ShowHUDHidAfterSecondWithMsgType(title: (error?.localizedDescription)!, view: to!, afterSecond: 1.5, msgType: STMBProgress.Error)
            }
            finished(response,error)
        }
    }
}

STAFNetworkTools.swift

//
//  AFNetworkTools.swift
//  SteemThink
//
//  Created by zhouzhiwei on 2018/2/22.
//  Copyright © 2018 zijinph. All rights reserved.
//
import UIKit
import AFNetworking
/// Request method
/// - GET:  get
/// - POST: post
enum AFRequestMethod: String {
    case GET = "GET"
    case POST = "POST"
}
class STAFNetworkTools: AFHTTPSessionManager {
    static let sharedTools: STAFNetworkTools = {
        let instance = STAFNetworkTools()
        instance.responseSerializer.acceptableContentTypes?.insert("text/html")
        instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
        instance.requestSerializer = AFJSONRequestSerializer.init()
        instance.requestSerializer.timeoutInterval = 20.0
        return instance
    }()     
    // (response: AnyObject?, error: NSError?)->()
    typealias AFNRequestCallBack = (_ response: Any?,_ error: Error?)->()
    ///
  /// - parameter urlString: request address
     /// - parameter parameters: Request parameters
     /// - parameter finished: The callback for the success or failure of the request
    func request(method: AFRequestMethod = .GET, urlString: String, parameters: AnyObject?, finished:@escaping AFNRequestCallBack){        
        print("urlString ============  " + urlString)
        print("parameters ============  " + String(describing: parameters))        
// dataTaskWithHttp is written in the. M file
         // corresponds to Swift, is a private modification method
         // Define the closure for which the request succeeded
        let success = { (dataTask: URLSessionDataTask, responseObject: Any?) -> Void in
            print("responseObject =========" + "\(String(describing: responseObject))")
            finished(responseObject, nil)
        }
// Define the closure of the request failed
        let failure = { (dataTask: URLSessionDataTask?, error: Error) -> Void in
            print("request Error =========" + error.localizedDescription)
            finished(nil, error)
        }        
        if method == .GET {
            get(urlString,parameters:parameters,progress:nil,success:success,failure:failure)
        }else{
            post(urlString, parameters: parameters, progress: nil, success:success, failure: failure)
        }
    }    
    func requestBack(method: AFRequestMethod = .GET, urlString: String, parameters: AnyObject?, finished:@escaping AFNRequestCallBack) -> URLSessionDataTask{
        print("urlString ============  " + urlString)
        print("parameters ============  " + String(describing: parameters))
// dataTaskWithHttp is written in the. M file
         // corresponds to Swift, is a private modification method
         // Define the closure for which the request succeeded
        let success = { (dataTask: URLSessionDataTask, responseObject: Any?) -> Void in
            print("responseObject =========" + "\(String(describing: responseObject))")
            finished(responseObject, nil)
        }
// Define the closure of the request failed
        let failure = { (dataTask: URLSessionDataTask?, error: Error) -> Void in
            print("request Error =========" + error.localizedDescription)
            finished(nil, error)
        }        
        if method == .GET {
            return get(urlString,parameters:parameters,progress:nil,success:success,failure:failure)!
        }else{
            return post(urlString, parameters: parameters, progress: nil, success:success, failure: failure)!
        }
    }   
/// send request (upload file)
    func requestWithData(data: NSData, name: String, urlString: String, parameters: AnyObject?, finished:@escaping AFNRequestCallBack) {
        // Define the closure for which the request succeeded
        let success = { (dataTask: URLSessionDataTask, responseObject: AnyObject?) -> Void in
            finished(responseObject, nil)
        }        
        // Define the closure of the request failed
        let failure = { (dataTask: URLSessionDataTask?, error: NSError) -> Void in
            finished(nil, error)
        }        
        post(urlString, parameters: parameters, constructingBodyWith: { (formData) -> Void in
            formData.appendPart(withFileData: data as Data, name: name, fileName: "aa", mimeType: "application/octet-stream")
        }, progress: nil, success: success as? (URLSessionDataTask, Any?) -> Void, failure: (failure as! (URLSessionDataTask?, Error) -> Void))
    }
}
  • The following is a detailed code description

The interface part is derived from the sc2.js code in steemconnect-sdk (https://github.com/steemit/steemconnect-sdk/blob/master/src/sc2.js).

Conversion process :

1. HTTPS request header

js:

headers:{
          Accept: 'application/json, text/plain, */*',
          'Content-Type': 'application/json',
          Authorization: this.options.accessToken,
    }

iOS:

instance.responseSerializer.acceptableContentTypes?.insert("text/html")
instance.responseSerializer.acceptableContentTypes?.insert("text/plain")
instance.requestSerializer = AFJSONRequestSerializer.init()

And we have to set the token, the token is obtained from the login screen callback

let client = STAFNetworkTools.sharedTools;
//    Set request header token   
client.requestSerializer.setValue(UserDataManager.sharedInstance.getToken(), forHTTPHeaderField: "Authorization")

2. Commenting and publishing articles (Publishing articles and comments is an API, which is a little strange)

js:

SteemConnect.prototype.broadcast = function broadcast(operations, cb) {
  return this.send('broadcast', 'POST', { operations }, cb);
};
SteemConnect.prototype.comment = function comment(
  parentAuthor,
  parentPermlink,
  author,
  permlink,
  title,
  body,
  jsonMetadata,
  cb
) {
  const params = {
    parent_author: parentAuthor,
    parent_permlink: parentPermlink,
    author,
    permlink,
    title,
    body,
    json_metadata: JSON.stringify(jsonMetadata),
  };
  return this.broadcast([['comment', params]], cb);
};

iOS:

    class func comment(
                 parentAuthor:String,
                 parentPermlink:String,
                 author:String,
                 permlink:String,
                 body:String,
                 finished:@escaping STClientCallBack) {        
        let param = ["parent_author": parentAuthor,
                     "parent_permlink": parentPermlink,
                     "author":author,
                     "permlink":permlink,
                     "title":"",
                     "body":body,
                     "json_metadata": ""]
        self.broadcast(body: ["operations":[["comment",param]]],finished: finished)
    }    
    class func broadcast(body:Dictionary<String, Any>,
        finished:@escaping STClientCallBack) {
//        print("jsonData ==============="+"\(NSDictionary_STExtension.getJSONStringFromDictionary(dictionary: body))")
        self.post(url: post_broadcast, body: body, finished: finished)
}

The contents of the body should be in strict accordance with ["operations": [["comment", param]]] This format, otherwise it will request failure.

3. vote

js:

SteemConnect.prototype.vote = function vote(voter, author, permlink, weight, cb) {
  const params = {
    voter,
    author,
    permlink,
    weight,
  };
  return this.broadcast([['vote', params]], cb);
};

iOS:

//MARK: - vote
    class func vote(
                    voter:String,
                    author:String,
                    permlink:String,
                    weight:NSInteger,
                    finished:@escaping STClientCallBack){
        let param = ["voter": voter,
                     "author": author,
                     "permlink":permlink,
                     "weight":weight,
                     ] as [String : Any]
        self.broadcast(body: ["operations":[["vote",param]]],finished: finished)
}



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Your contribution cannot be approved because it does not follow the Utopian Rules.

Contributions must have a comprehensible commit history. Larger projects or updates submitted in a single commit will not be accepted.

All the code changes have been done in a single commit by the user "zhouzhiwei", thus its very hard to evaluate the contribution. If it is a bigger project we want that it should also have a comprehensive commit history.

You can contact us on Discord.
[utopian-moderator]

Hi @codingdefined
You can find the reason for a single commit here.
https://steemit.com/utopian-io/@steemthinkcom/steemthink-use-angular-and-steem-api-create-steem-blockchain-based-sites

Because another mod(@eastmael) suggested that I separate the ios project from the html project, it would be more clear and convenient to maintain.

So, the submission history of ios items that cannot be seen in this contribution,
But you can see my first submission here.
https://steemit.com/utopian-io/@steemthinkcom/develop-the-ios-app-using-the-swift-part-1

This contribution is based on the previous contribution and has increased, the following features were updated: steemconnect login, comment, vote, release function.

Future ios project updates will find submission records in the same project

If you can please re-review.

Thanks again

Hello @steemthinkcom, thank you for considering my suggestion. @codingdefined did mention the rule:

Contributions must have a comprehensible commit history. Larger projects or updates submitted in a single commit will not be accepted.

This is for easier review of the changes done. So i think what you should have done here is make a commit of v1 (without the new features) as your initial/base codes, and another commit for the new features.

I also checked your commit history and i think it would have been best if you committed each feature in a separate pull requests to adhere to the rules.

And i would even suggest to publish a testable version of this app to give moderators the option to test the new features as well.

I support @codingdefined's decision here since I perceive that you overlooked the rule mentioned above.

hi @eastmael,thanks for you reply .
So, your suggestion is to resubmit this contribution as "new project" and provide a test version to facilitate the installation test?
Afterwards, new contributions will be submitted using "New Features" to facilitate mod review?

My suggestion is - do whatever you think is right with your project - focus on its development and adding value to it rather than adhering to rules just so that your contribution will be accepted.

I'm also suggesting to retain this contribution as is rahter than recreating and resubmitting it.

The reason being is that resubmitting it gives me the impression that your only resubmitting for it to be accepted, which is a complete waste of your and our time.

I understand that I will retain this contribution. The next IOS contribution will be based on this contribution.

Thank you for your understanding and looking forward to your next contributions.

Coin Marketplace

STEEM 0.23
TRX 0.25
JST 0.038
BTC 95317.76
ETH 3302.38
USDT 1.00
SBD 3.31