When BROWSING forums and reading articles on official accounts, I saw a lot of wilddog advertisements. Since I have never seen this kind of thing before, and the official website is very simple and refreshing, which suits my personal taste, I decided to write a simple IM software to practice it.





Start with the code Dogchat_Swift

Written in my spare time last semester, it implements some simple functions, mainly using Wilddog’s server and its API:

  • Private chat (text, positioning)
  • Group chat (text, picture)
  • The address book
  • Being pushed
  • Other features

During the test, two test machines were used for group chat with the simulator, and one test machine was used for private chat and location with the simulator. The location of the simulator was manually set, and the response was quite fast.

Environment:

  • OS X 10.11.6
  • Xcode 7.3
  • Swift

The preparatory work

To run the code, change the WilddogURL value to your own WildDog database address in the constantValue. swift file.

Modify the root view in the AppDelegate to skip the login screen.

For convenience, add users directly using WildDog’s authentication feature.

The login

file:LoginViewController.swift

If you want to log in using the Wilddog object authUser method, use the newly added account. However, you need to modify the parameter of the transmitAccountMsg function in the authUserLogin method, which will affect the data acquisition after login.

Login screen missing only one art series:

User login:

func authUserLogin(user:String,password:String){ let myRootRef = Wilddog(url:WilddogURL) myRootRef.authUser(user, password: password) { error, authData in if error ! = nil {print(error) let alertController = UIAlertController(" error ", message: "error ", preferredStyle: .Alert) let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil) alertController.addAction(defaultAction) self.presentViewController(alertController, animated: true, completion: nil) } else { let mainVC = ViewController() mainVC.transmitAccountMsg(user) let nvc=UINavigationController(rootViewController:mainVC) self.presentViewController(nvc, animated: true, completion: nil)Copy the code


Data is stored

Background data, API provided by WildDog for related operations:

  • PrivateMsg: Private chat and location data
  • UserAccount: User information
  • UserMsg: Group chat data

Group chat

file:ViewController.swift

Modify the root view in the AppDelegate to skip the login screen.

After logging in, the interface is the group chat interface, and the chat content is visible to all members.

There is a loading animation of square rotation, as shown after loading:

Group chat data initialization:

func msgInitialAdd(){ let myRootRef = Wilddog(url:WilddogURL) let userRef = myRootRef.childByAppendingPath("UserMsg") userRef.observeSingleEventOfType(.Value, withBlock: { snapshot in let count = snapshot.value.count var i = 0 self.observerHandle = userRef.queryOrderedByKey().observeEventType(.ChildAdded, withBlock: { snapshot in if snapshot.value ! = nil{ self.dic[snapshot.key] = snapshot.value as? Dictionary self.chatMsgArray.append(snapshot.key) i=i+1 if i == count { self.loadingView.hidden = true self.timeAnime.tupleToAnime(self.parse.parseStr(self.dic[snapshot.key]! ["time"]!) ) userRef.removeAllObservers() self.initialAdds = false self.tableView! .reloadData()Copy the code


Sending pictures (ImagePickerControllerDelegate delegate) :

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) self.dismissViewControllerAnimated(true, completion: nil) if let image = info[UIImagePickerControllerOriginalImage] as? UIImage print("select photo") let newImageThumbnail = imageCompressForWidth(image, targetWidth: 100) let data = UIImageJPEGRepresentation (newImageThumbnail, 1.0). thumbnailImageStr = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength) let str = "image:" + thumbnailImageStr let myRootRef = Wilddog(url:WilddogURL) let msgRef = myRootRef.childByAppendingPath("UserMsg") msgRef.removeObserverWithHandle(self.observerHandle) let Ref = msgRef.childByAutoId() let msg = ["ID":self.userID,"nickname":self.userNickName,"message":str,"time":self.getTime()] Ref.setValue(msg)Copy the code


Background data storage:

You can input text chat, you can select pictures in the album and send them, and the pictures are transferred to Base64 code storage.

The background is an animation. As for that, I’ll say later.

The address book

file:ContactsViewController.swift

Click “Contact” in the upper left corner of the group chat interface to enter the address book and read the UserAccount data of WildDog:

Get address book data:

func transmitAccountMsg(mail:String,id:String,nickname:String){ print("Enter Contacts View") self.userID = id self.userNickname = nickname self.userArray = Array() let myRootRef = Wilddog(url:WilddogURL) let accountRef = myRootRef.childByAppendingPath("UserAccount") accountRef.queryOrderedByChild("mail").observeSingleEventOfType(.Value, withBlock: { snapshot in for i in (snapshot.value as! Dictionary>) { if i.1["mail"]! ! = mail { self.userArray.append(i.1["nickname"]!) self.mailArray.append(i.1["mail"]!)Copy the code


Background data storage:

The private chat

file:SingleChatViewController.swift

Click any entry in the address book to start a private chat.

Chat:

Private chat data initialization:

func initMessage(){ let userRef = myRootRef.childByAppendingPath("PrivateMsg"+"/"+self.userNickname+"/"+self.title!) userRef.observeSingleEventOfType(.Value, withBlock: { snapshot in if snapshot.value ! = nil{ print("Get msg!" ) self.msgPath = "PrivateMsg"+"/"+self.userNickname+"/"+self.title! self.refreshMessage() let count = snapshot.value.count var i = 0 userRef.queryOrderedByKey().observeEventType(.ChildAdded, withBlock: { snapshot in self.dic[snapshot.key] = snapshot.value as? Dictionary self.chatMsgArray.append(snapshot.key) i += 1 if i == count { userRef.removeAllObservers() self.tableView! .reloadData() self.initLoad = false }else { self.initMessageAgain() print("init successed,\(self.msgPath)")Copy the code


Background data storage:

Shared positioning:

There are bugs, not fixed, up and down.

Self position:

func MyLocationInit(){ if ! CLLocationManager. LocationServicesEnabled () {print (" location services may not be current open, open set, please!" ) if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.NotDetermined){ locationManager.requestWhenInUseAuthorization() }else if(CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse){ locationManager.delegate = self locationManager.desiredAccuracy = KCLLocationAccuracyBest let short: CLLocationDistance = 2.0 locationManager distanceFilter = short locationManager.startUpdatingLocation() mapView.userTrackingMode = MKUserTrackingMode.FollowCopy the code


Location of Others:

func otherLocationInit(){ print("OtherPositon is \(OtherPostion)") let objectAnnotation = MKPointAnnotation() let lati =  (OtherPostion["latitude"]! as NSString).doubleValue let longi = (OtherPostion["longitude"]! as NSString).doubleValue objectAnnotation.coordinate = CLLocation(latitude: lati, longitude: Longi). Coordinate objectAnnotation. Title = "\ (OtherName) the location of the" objectAnnotation. The subtitle = "subtitle" self.mapView.addAnnotation(objectAnnotation) mapSetRegion(longi, latitude: lati, isMy: False) func mapSetRegion (longitude: Double, latitude: Double, isMy: Bool) {let latDelta = 0.05 let longDelta = 0.05 let currentLocationSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta) let center:CLLocation = CLLocation(latitude: latitude, longitude: longitude) let currentRegion:MKCoordinateRegion = MKCoordinateRegion(center: center.coordinate, span: currentLocationSpan) if isMy { (self.longitude,self.latitude) = (center.coordinate.longitude,center.coordinate.latitude)  mapView.setRegion(currentRegion, animated: true)Copy the code


Being pushed

I can’t take screenshots if I don’t have a real computer around me. It is normal that I have tested it before, as shown in the picture:

Message push:

func newMsgNotifi(title:String? ,body:String?) { var msgBody:String! if body! .hasprefix ("image:") {msgBody = ""}else{msgBody = ":" + body! var notification = UILocalNotification() notification.timeZone = NSTimeZone.localTimeZone() notification.alertTitle = title notification.alertBody = title! + msgBody notification.alertAction = "OK" notification.soundName = UILocalNotificationDefaultSoundName notification.applicationIconBadgeNumber = 1 var userInfo:[NSObject : AnyObject] = [NSObject : AnyObject]() userInfo["kLocalNotificationID"] = "LocalNotificationID" userInfo["key"] = "Attention Please" notification.userInfo = userInfo UIApplication.sharedApplication().presentLocalNotificationNow(notification)Copy the code


other

The Other button in the upper right corner of the group chat screen looks like this:

A tangram view, originally an OC library, add a bridge to change the call function on the line. Forget where I found it before, the original author is Yuancan, as a collection of additional functions.

Put some interesting things, select album pictures to generate character painting, handwriting board, character random article, button animation and so on.

The background animation for the main screen

Since the data of sending chat records contain time field, I want to analyze the information of season, festival, morning and evening, weather and so on according to this time, and then display it through animation. However, the level is limited, only to achieve the simplest effect, the sun and moon and their height represents the time of day, the background color represents the season, the festival has been resolved but has not been processed, the weather has not written the relevant code to obtain. Specific parsing and animation code in ParseDateStringClass. Swift and ResponseToAnimeView. Swift.

1. Save time when uploading chat records:

func getTime() -> String {
  let date = NSDate()
  let timeFormatter = NSDateFormatter()
  timeFormatter.dateFormat = "yyy-MM-dd.HH:mm:ss"
  let strNowTime = timeFormatter.stringFromDate(date) as String
  return strNowTimeCopy the code


2. Filter time string:

func parseStr(str:String) -> (Int,Int,String,Int){ let onceSplit = str.characters.split{$0 == "."}.map(String.init) let month = String(Int(onceSplit[0].characters.split{$0 == "-"}.map(String.init)[1] )!) let day = String(Int(onceSplit[0].characters.split{$0 == "-"}.map(String.init)[2])!) let date = month + "-" + day let dayTime = Int(onceSplit[1].characters.split{$0 == ":"}.map(String.init)[0]) var season : Season var daytime : DayTimePeriod var weather : Weather = Weather.Sunny var festival : Festival switch Int(month)! {case 12,1,2: season = season.Winter case 3... 5 : season = Season.Spring case 6... 8 : season = Season.Summer case 9... 11 : season = Season.Autumn default : season = Season.Spring switch dayTime! { case 6... 9: daytime = DayTimePeriod.morning case 10... 14: daytime = DayTimePeriod.noon case 15... 18: daytime = DayTimePeriod.afternoon case 19... 22: Daytime = DayTimePeriod. Evening Case 22,23,24,0... 5: daytime = DayTimePeriod.night default: daytime = DayTimePeriod.morning switch day { case "1-1": festival = Festival.NewYearsDay case "3-8": festival = Festival.WomensDay case "3-12": festival = Festival.ArborDay case "5-1": festival = Festival.LaborDay case "5-4": festival = Festival.YouthDay case "6-1": festival = Festival.ChildrensDay case "10-1": festival = Festival.NationalDay case "12-31": festival = Festival.NewYearsEve default: festival = Festival.NewYearsDay return (season.rawValue,daytime.rawValue,festival.rawValue,weather.rawValue)Copy the code


3. Convert to animation:

func tupleToAnime(tuple:(Int,Int,String,Int))
    if cloudIsFired == false {
        cloudTimer.fire()
        cloudIsFired = true
    seasonNo = tuple.0
    daytimeNo = tuple.1
    festivalNo = tuple.2
    weatherNo = tuple.3
    self.sunAndMoonWithTime(daytimeNo)Copy the code


The background animation will change with the time of the chat record displayed at the bottom of the tableView on the current screen, that is, the animation will change with the time of the chat record when toggle the list, but there are some bugs, temporarily disabled, always display a fixed time animation.

The last

I have to say that the name of this cloud is really bold…