first add sdk

This commit is contained in:
jialexd 2019-04-02 16:34:25 +08:00
commit f91efd1250
3915 changed files with 1291882 additions and 0 deletions

View file

@ -0,0 +1,17 @@
//
// AppDelegate.h
// uartadapter
//
// Created by isaiah on 8/26/15.
// Copyright (c) 2015 realtek. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View file

@ -0,0 +1,45 @@
//
// AppDelegate.m
// uartadapter
//
// Created by isaiah on 8/26/15.
// Copyright (c) 2015 realtek. All rights reserved.
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 realtek. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Realtek" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View file

@ -0,0 +1,256 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="1Pd-eg-9KV">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Navigation Controller-->
<scene sceneID="Z5v-pO-fDj">
<objects>
<navigationController definesPresentationContext="YES" id="1Pd-eg-9KV" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="3C6-QB-18H">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="Ncl-Ly-ig6" kind="relationship" relationship="rootViewController" id="Wkd-LN-Ngo"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vuA-ba-keF" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-150.40000000000001" y="208.26666666666665"/>
</scene>
<!--View Controller-->
<scene sceneID="MS6-5N-OFm">
<objects>
<collectionViewController autoresizesArchivedViewToFullSize="NO" clearsSelectionOnViewWillAppear="NO" id="Ncl-Ly-ig6" customClass="ViewController" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" dataMode="prototypes" id="e7m-gh-n99">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.79215693473815918" green="0.97254908084869385" blue="0.85098046064376831" alpha="1" colorSpace="deviceRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="qjF-PG-Xfp">
<size key="itemSize" width="155" height="149"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cellID" id="ZOT-Jp-0u5" customClass="Cell">
<rect key="frame" x="0.0" y="64" width="155" height="149"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="155" height="149"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JUJ-aT-Vg2">
<rect key="frame" x="0.0" y="120" width="155" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="10"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" id="l8r-Fv-CoH">
<rect key="frame" x="25" y="13" width="106" height="104"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<connections>
<outlet property="image" destination="l8r-Fv-CoH" id="9Cu-iE-zAT"/>
<outlet property="label" destination="JUJ-aT-Vg2" id="h6D-S5-rXw"/>
</connections>
</collectionViewCell>
</cells>
<connections>
<outlet property="dataSource" destination="Ncl-Ly-ig6" id="CTs-Vx-EvJ"/>
<outlet property="delegate" destination="Ncl-Ly-ig6" id="nWX-TH-lIf"/>
</connections>
</collectionView>
<navigationItem key="navigationItem" id="ce6-Wp-ltA">
<nil key="title"/>
<barButtonItem key="rightBarButtonItem" style="done" id="2oE-Kv-sfo">
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="Q3E-M5-mSe">
<rect key="frame" x="269" y="7" width="35" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Scan">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="scanButton" destination="Ncl-Ly-ig6" eventType="touchUpInside" id="YyT-5V-CXa"/>
</connections>
</button>
</barButtonItem>
</navigationItem>
<connections>
<segue destination="YFM-wW-kmf" kind="push" identifier="showDetail" id="u0H-uv-HwD"/>
<segue destination="oWX-tt-vKZ" kind="push" identifier="showSetting" id="948-TD-nhp"/>
</connections>
</collectionViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="OOw-UZ-8Yt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="243" y="208"/>
</scene>
<!--Setting Page View Controller-->
<scene sceneID="PDn-ND-rhY">
<objects>
<viewController id="oWX-tt-vKZ" customClass="SettingPageViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Dpb-L4-mnY">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Serial Port Setup" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UUa-Hs-pNl">
<rect key="frame" x="68" y="72" width="185" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Baud Rate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Zwm-F2-aef">
<rect key="frame" x="16" y="126" width="89" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Parity Bit" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="K3d-Js-h4x">
<rect key="frame" x="16" y="285" width="89" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stop Bit" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="NEj-Sy-XUA">
<rect key="frame" x="16" y="364" width="89" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Data Bit" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8Qx-J6-Ohg">
<rect key="frame" x="16" y="207" width="89" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="EMe-Jg-qG8">
<rect key="frame" x="182" y="501" width="66" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Apply">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="saveSettings" destination="oWX-tt-vKZ" eventType="touchUpInside" id="vNL-h1-Wla"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Flow Control" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dRn-mU-pEL">
<rect key="frame" x="20" y="444" width="106" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" clipsSubviews="YES" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" id="bFa-tH-gKE">
<rect key="frame" x="129" y="276" width="172" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" id="qQL-8R-FG9">
<rect key="frame" x="128" y="355" width="172" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="Not Support" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" id="1xk-ab-wen">
<rect key="frame" x="129" y="435" width="172" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" id="jzD-fD-Enl">
<rect key="frame" x="129" y="117" width="172" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<textField opaque="NO" clipsSubviews="YES" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" id="mpK-rA-jHO">
<rect key="frame" x="129" y="198" width="172" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="79g-JQ-I6P">
<rect key="frame" x="69" y="501" width="66" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Restore">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="restoreSettings" destination="oWX-tt-vKZ" eventType="touchUpInside" id="fjO-FY-ZIz"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="0.79215693470000004" green="0.97254908080000002" blue="0.85098046059999999" alpha="1" colorSpace="deviceRGB"/>
</view>
<navigationItem key="navigationItem" id="YOa-9T-3sQ"/>
<connections>
<outlet property="StopBitField" destination="qQL-8R-FG9" id="cm0-Cz-z6n"/>
<outlet property="baudRateField" destination="jzD-fD-Enl" id="7jg-ka-vX1"/>
<outlet property="dataBitField" destination="mpK-rA-jHO" id="fbH-Mv-wCK"/>
<outlet property="parityBitField" destination="bFa-tH-gKE" id="g4N-Js-Fmb"/>
<outlet property="stopBitField" destination="qQL-8R-FG9" id="dRr-xb-mwx"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="c2o-dX-yNd" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="707" y="556"/>
</scene>
<!--Chat View Controller-->
<scene sceneID="72O-QX-vQv">
<objects>
<viewController id="YFM-wW-kmf" customClass="ChatViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" id="4Lr-nv-ban">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" minimumFontSize="17" id="OMp-fG-Ui9">
<rect key="frame" x="16" y="530" width="222" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="yyF-WX-t25">
<rect key="frame" x="258" y="529" width="46" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="SEND">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="sendMessage" destination="YFM-wW-kmf" eventType="touchUpInside" id="O1x-kX-9H2"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" placeholderIntrinsicWidth="320" placeholderIntrinsicHeight="457" editable="NO" id="cNU-xq-X0W">
<rect key="frame" x="0.0" y="64" width="320" height="457"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="0.79215693470000004" green="0.97254908080000002" blue="0.85098046059999999" alpha="1" colorSpace="deviceRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="f0I-FI-aV5"/>
<connections>
<outlet property="chatMessageField" destination="cNU-xq-X0W" id="QFT-cC-FdH"/>
<outlet property="inputMessageField" destination="OMp-fG-Ui9" id="xES-Px-tg8"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="IiU-Ky-z4A" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="706" y="-96"/>
</scene>
</scenes>
</document>

View file

@ -0,0 +1,16 @@
/*
Copyright (C) 2015 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Custom collection view cell for image and its label.
*/
@import UIKit;
@interface Cell : UICollectionViewCell
@property (strong, nonatomic) IBOutlet UIImageView *image;
@property (strong, nonatomic) IBOutlet UILabel *label;
@end

View file

@ -0,0 +1,27 @@
/*
Copyright (C) 2015 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Custom collection view cell for image and its label.
*/
#import "Cell.h"
#import "CustomCellBackground.h"
@implementation Cell
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
// change to our custom selected background view
CustomCellBackground *backgroundView = [[CustomCellBackground alloc] initWithFrame:CGRectZero];
self.selectedBackgroundView = backgroundView;
}
return self;
}
@end

View file

@ -0,0 +1,32 @@
/*
Copyright (C) 2015 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The secondary detailed view controller for this app.
*/
#import <UIKit/UIKit.h>
@interface ChatViewController : UIViewController <NSStreamDelegate, NSNetServiceBrowserDelegate, NSNetServiceDelegate, UITextFieldDelegate>
{
NSNetServiceBrowser *_netServiceBrowser;
NSMutableArray *_servicesArray;
NSMutableArray *messages;
NSInputStream *inputStream;
NSOutputStream *outputStream;
}
@property (nonatomic, retain) NSNetService *selectedService;
@property (nonatomic, retain) NSMutableArray *dataServicesArray;
@property (nonatomic, retain) NSInputStream *inputStream;
@property (nonatomic, retain) NSOutputStream *outputStream;
@property (nonatomic, retain) NSMutableArray *messages;
- (IBAction) sendMessage;
@property (nonatomic, retain) IBOutlet UITextView *chatMessageField;
@property (nonatomic, retain) IBOutlet UITextField *inputMessageField;
@end

View file

@ -0,0 +1,348 @@
/*
Copyright (C) 2015 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
The secondary detailed view controller for this app.
*/
#import "ChatViewController.h"
#include <ifaddrs.h>
#include <arpa/inet.h>
@interface ChatViewController ()
@end
@implementation ChatViewController
@synthesize inputStream, outputStream;
@synthesize inputMessageField,chatMessageField;
@synthesize selectedService = _selectedService;
@synthesize messages;
NSString *UART_DATA_TYPE=@"_uart_data._tcp.local.";
NSDateFormatter *formatter;
NSString *timeString;
NSMutableAttributedString *attrMessage;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIGraphicsBeginImageContext(self.view.frame.size);
[[UIImage imageNamed:@"background.png"] drawInRect:self.view.bounds];
UIImage *bgImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.chatMessageField.contentMode = UIViewContentModeScaleToFill;
self.chatMessageField.backgroundColor=[UIColor colorWithPatternImage:bgImage];
self.dataServicesArray = [[NSMutableArray alloc] init];
[self startDiscover:UART_DATA_TYPE];
self.inputMessageField.delegate = self;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:@"UIKeyboardWillShowNotification"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidHide:)
name:@"UIKeyboardWillHideNotification"
object:nil];
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"HH:mm"];
NSAttributedString *objectString =
[[NSAttributedString alloc] initWithString:@""
attributes:@{
NSForegroundColorAttributeName : [UIColor redColor],
NSFontAttributeName : [UIFont boldSystemFontOfSize:20]
}];
attrMessage = [[NSMutableAttributedString alloc] initWithAttributedString:objectString];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
- (void) keyboardWillShow:(NSNotification *)note {
NSDictionary *userInfo = [note userInfo];
CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// move the view up by 30 pts
CGRect frame = self.view.frame;
frame.origin.y = -kbSize.height;
[UIView animateWithDuration:0.01 animations:^{
self.view.frame = frame;
}];
}
- (void) keyboardDidHide:(NSNotification *)note {
// move the view back to the origin
CGRect frame = self.view.frame;
frame.origin.y = 0;
self.view.frame = frame;
}
-(void) startDiscover:(NSString *)browseType
{
self->_netServiceBrowser = [[NSNetServiceBrowser alloc] init];
self->_netServiceBrowser.delegate = self;
NSArray *domainNameParts = [browseType componentsSeparatedByString:@"."];
browseType = [NSString stringWithFormat:@"%@.%@.", [domainNameParts objectAtIndex:0], [domainNameParts objectAtIndex:1]];
[self->_netServiceBrowser searchForServicesOfType:browseType inDomain:@""];
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
[self.dataServicesArray addObject:aNetService];
if (moreComing == NO) {
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
[self.dataServicesArray sortUsingDescriptors:[NSArray arrayWithObject:sd]];
//[sd release];
self->_netServiceBrowser.delegate = nil;
[self->_netServiceBrowser stop];
self->_netServiceBrowser = nil;
self.title = self.selectedService.name;
}
if([self.selectedService.name isEqualToString:aNetService.name])
{
aNetService.delegate = self;
[aNetService resolveWithTimeout:10.0];
}
}
-(void)netServiceDidResolveAddress:(NSNetService *)service {
NSData *address = [service.addresses objectAtIndex:0];
char addressString[INET6_ADDRSTRLEN];
int inetType;
struct sockaddr_in6 addr6;
memcpy(&addr6, address.bytes, address.length);
if (address.length == 16) { // IPv4
inetType = AF_INET;
struct sockaddr_in addr4;
memcpy(&addr4, address.bytes, address.length);
inet_ntop(AF_INET, &addr4.sin_addr, addressString, 512);
[self initNetworkCommunication:[NSString stringWithCString:addressString encoding:NSASCIIStringEncoding] Port:(int)service.port];
}
}
- (void)netServiceBrowser:(NSNetServiceBrowser *)netServiceBrowser didRemoveService:(NSNetService *)netService moreComing:(BOOL)moreComing {
for (int i = 0; i < self.dataServicesArray.count; i++) {
if ([((NSNetService *)[self.dataServicesArray objectAtIndex:i]).name isEqualToString:netService.name]) {
[self.dataServicesArray removeObjectAtIndex:i];
break;
}
}
if (moreComing == NO) {
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
[self.dataServicesArray sortUsingDescriptors:[NSArray arrayWithObject:sd]];
}
}
#pragma mark -
#pragma mark NSNetServiceDelegate methods
-(void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict {
NSNumber *errorCode = [errorDict valueForKey:NSNetServicesErrorCode];
NSString *errorMessage;
switch ([errorCode intValue]) {
case NSNetServicesActivityInProgress:
errorMessage = @"Service Resolution Currently in Progress. Please Wait.";
break;
case NSNetServicesTimeoutError:
errorMessage = @"Service Resolution Timeout";
[sender stop];
//UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Bonjour Browser" message:errorMessage delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
// [alert show];
break;
}
//[alert release];
}
#pragma mark -
#pragma mark NSNetServiceBrowserDelegate methods
-(void)netServiceBrowser:(NSNetServiceBrowser *)browser didNotSearch:(NSDictionary *)errorDict {
self->_netServiceBrowser.delegate = nil;
[self->_netServiceBrowser stop];
self->_netServiceBrowser = nil;
}
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser {
self->_netServiceBrowser.delegate = nil;
self->_netServiceBrowser = nil;
}
- (void) initNetworkCommunication:(NSString *)mIP Port:(int)mPort {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)mIP, mPort, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (IBAction) sendMessage {
NSAttributedString *sendingString;
timeString = [formatter stringFromDate:[NSDate date]];
NSString *response = [NSString stringWithFormat:@"%@\n", inputMessageField.text];
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
response = [NSString stringWithFormat:@"%@ [Me] %@\n",timeString, inputMessageField.text];
sendingString =
[[NSAttributedString alloc] initWithString:response
attributes:@{
NSForegroundColorAttributeName : [UIColor blueColor],
NSFontAttributeName : [UIFont boldSystemFontOfSize:20]
}];
inputMessageField.text = @"";
[attrMessage appendAttributedString:sendingString];
[chatMessageField setAttributedText:attrMessage];
[inputMessageField resignFirstResponder];
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(@"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable]) {
len = [[NSNumber numberWithInteger:[inputStream read:buffer maxLength: sizeof(buffer)]] intValue] ;
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output) {
[self messageReceived:output];
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(@"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//[theStream release];
theStream = nil;
break;
default:
NSLog(@"Unknown event");
}
}
- (void) messageReceived:(NSString *)message {
NSAttributedString *receivedString;
[self.chatMessageField setTintColor:[UIColor greenColor]];
timeString = [formatter stringFromDate:[NSDate date]];
receivedString =
[[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@ [Ameba] %@\n", timeString ,message]
attributes:@{
NSForegroundColorAttributeName : [UIColor purpleColor],
NSFontAttributeName : [UIFont boldSystemFontOfSize:20]
}];
[attrMessage appendAttributedString:receivedString];
[chatMessageField setAttributedText:attrMessage];
}
- (void)viewDidUnload {
[super viewDidUnload];
self->_netServiceBrowser.delegate = nil;
[self->_netServiceBrowser stop];
self->_netServiceBrowser = nil;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[inputStream close];
[outputStream close];
self->_netServiceBrowser = nil;
self.dataServicesArray = nil;
self.selectedService = nil;
}
@end

View file

@ -0,0 +1,13 @@
/*
Copyright (C) 2015 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Custom UIView to draw a rounded blue box to represent a selected cell.
*/
@import UIKit;
@interface CustomCellBackground : UIView
@end

View file

@ -0,0 +1,30 @@
/*
Copyright (C) 2015 Apple Inc. All Rights Reserved.
See LICENSE.txt for this samples licensing information
Abstract:
Custom UIView to draw a rounded blue box to represent a selected cell.
*/
#import "CustomCellBackground.h"
@implementation CustomCellBackground
- (void)drawRect:(CGRect)rect
{
// draw a rounded rect bezier path filled with blue
CGContextRef aRef = UIGraphicsGetCurrentContext();
CGContextSaveGState(aRef);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5.0f];
bezierPath.lineWidth = 5.0f;
[[UIColor blackColor] setStroke];
UIColor *fillColor = [UIColor colorWithRed:0.529 green:0.808 blue:0.922 alpha:1]; // color equivalent is #87ceeb
[fillColor setFill];
[bezierPath stroke];
[bezierPath fill];
CGContextRestoreGState(aRef);
}
@end

View file

@ -0,0 +1,73 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "action_icon@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "ameba_group.png"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "background.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "chat.png"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "device.png"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "settings.png"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "ungroup.png"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,67 @@
//
// KxMenu.h
// kxmenu project
// https://github.com/kolyvan/kxmenu/
//
// Created by Kolyvan on 17.05.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <Foundation/Foundation.h>
@interface KxMenuItem : NSObject
@property (readwrite, nonatomic, strong) UIImage *image;
@property (readwrite, nonatomic, strong) NSString *title;
@property (readwrite, nonatomic, weak) id target;
@property (readwrite, nonatomic) SEL action;
@property (readwrite, nonatomic, strong) UIColor *foreColor;
@property (readwrite, nonatomic) NSTextAlignment alignment;
+ (instancetype) menuItem:(NSString *) title
image:(UIImage *) image
target:(id)target
action:(SEL) action;
@end
@interface KxMenu : NSObject
+ (void) showMenuInView:(UIView *)view
fromRect:(CGRect)rect
menuItems:(NSArray *)menuItems;
+ (void) dismissMenu;
+ (UIColor *) tintColor;
+ (void) setTintColor: (UIColor *) tintColor;
+ (UIFont *) titleFont;
+ (void) setTitleFont: (UIFont *) titleFont;
@end

View file

@ -0,0 +1,889 @@
//
// KxMenu.m
// kxmenu project
// https://github.com/kolyvan/kxmenu/
//
// Created by Kolyvan on 17.05.13.
//
/*
Copyright (c) 2013 Konstantin Bukreev. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Some ideas was taken from QBPopupMenu project by Katsuma Tanaka.
https://github.com/questbeat/QBPopupMenu
*/
#import "KxMenu.h"
#import <QuartzCore/QuartzCore.h>
const CGFloat kArrowSize = 12.f;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@interface KxMenuView : UIView
- (void)dismissMenu:(BOOL) animated;
@end
@interface KxMenuOverlay : UIView
@end
@implementation KxMenuOverlay
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
UITapGestureRecognizer *gestureRecognizer;
gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(singleTap:)];
[self addGestureRecognizer:gestureRecognizer];
}
return self;
}
// thank horaceho https://github.com/horaceho
// for his solution described in https://github.com/kolyvan/kxmenu/issues/9
- (void)singleTap:(UITapGestureRecognizer *)recognizer
{
for (UIView *v in self.subviews) {
if ([v isKindOfClass:[KxMenuView class]] && [v respondsToSelector:@selector(dismissMenu:)]) {
[v performSelector:@selector(dismissMenu:) withObject:@(YES)];
}
}
}
@end
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@implementation KxMenuItem
+ (instancetype) menuItem:(NSString *) title
image:(UIImage *) image
target:(id)target
action:(SEL) action
{
return [[KxMenuItem alloc] init:title
image:image
target:target
action:action];
}
- (id) init:(NSString *) title
image:(UIImage *) image
target:(id)target
action:(SEL) action
{
NSParameterAssert(title.length || image);
self = [super init];
if (self) {
_title = title;
_image = image;
_target = target;
_action = action;
}
return self;
}
- (BOOL) enabled
{
return _target != nil && _action != NULL;
}
- (void) performAction
{
__strong id target = self.target;
if (target && [target respondsToSelector:_action]) {
[target performSelectorOnMainThread:_action withObject:self waitUntilDone:YES];
}
}
- (NSString *) description
{
return [NSString stringWithFormat:@"<%@ #%p %@>", [self class], self, _title];
}
@end
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
typedef enum {
KxMenuViewArrowDirectionNone,
KxMenuViewArrowDirectionUp,
KxMenuViewArrowDirectionDown,
KxMenuViewArrowDirectionLeft,
KxMenuViewArrowDirectionRight,
} KxMenuViewArrowDirection;
@implementation KxMenuView {
KxMenuViewArrowDirection _arrowDirection;
CGFloat _arrowPosition;
UIView *_contentView;
NSArray *_menuItems;
}
- (id)init
{
self = [super initWithFrame:CGRectZero];
if(self) {
self.backgroundColor = [UIColor clearColor];
self.opaque = YES;
self.alpha = 0;
self.layer.shadowOpacity = 0.5;
self.layer.shadowOffset = CGSizeMake(2, 2);
self.layer.shadowRadius = 2;
}
return self;
}
- (void) setupFrameInView:(UIView *)view
fromRect:(CGRect)fromRect
{
const CGSize contentSize = _contentView.frame.size;
const CGFloat outerWidth = view.bounds.size.width;
const CGFloat outerHeight = view.bounds.size.height;
const CGFloat rectX0 = fromRect.origin.x;
const CGFloat rectX1 = fromRect.origin.x + fromRect.size.width;
const CGFloat rectXM = fromRect.origin.x + fromRect.size.width * 0.5f;
const CGFloat rectY0 = fromRect.origin.y;
const CGFloat rectY1 = fromRect.origin.y + fromRect.size.height;
const CGFloat rectYM = fromRect.origin.y + fromRect.size.height * 0.5f;;
const CGFloat widthPlusArrow = contentSize.width + kArrowSize;
const CGFloat heightPlusArrow = contentSize.height + kArrowSize;
const CGFloat widthHalf = contentSize.width * 0.5f;
const CGFloat heightHalf = contentSize.height * 0.5f;
const CGFloat kMargin = 5.f;
if (heightPlusArrow < (outerHeight - rectY1)) {
_arrowDirection = KxMenuViewArrowDirectionUp;
CGPoint point = (CGPoint){
rectXM - widthHalf,
rectY1
};
if (point.x < kMargin)
point.x = kMargin;
if ((point.x + contentSize.width + kMargin) > outerWidth)
point.x = outerWidth - contentSize.width - kMargin;
_arrowPosition = rectXM - point.x;
//_arrowPosition = MAX(16, MIN(_arrowPosition, contentSize.width - 16));
_contentView.frame = (CGRect){0, kArrowSize, contentSize};
self.frame = (CGRect) {
point,
contentSize.width,
contentSize.height + kArrowSize
};
} else if (heightPlusArrow < rectY0) {
_arrowDirection = KxMenuViewArrowDirectionDown;
CGPoint point = (CGPoint){
rectXM - widthHalf,
rectY0 - heightPlusArrow
};
if (point.x < kMargin)
point.x = kMargin;
if ((point.x + contentSize.width + kMargin) > outerWidth)
point.x = outerWidth - contentSize.width - kMargin;
_arrowPosition = rectXM - point.x;
_contentView.frame = (CGRect){CGPointZero, contentSize};
self.frame = (CGRect) {
point,
contentSize.width,
contentSize.height + kArrowSize
};
} else if (widthPlusArrow < (outerWidth - rectX1)) {
_arrowDirection = KxMenuViewArrowDirectionLeft;
CGPoint point = (CGPoint){
rectX1,
rectYM - heightHalf
};
if (point.y < kMargin)
point.y = kMargin;
if ((point.y + contentSize.height + kMargin) > outerHeight)
point.y = outerHeight - contentSize.height - kMargin;
_arrowPosition = rectYM - point.y;
_contentView.frame = (CGRect){kArrowSize, 0, contentSize};
self.frame = (CGRect) {
point,
contentSize.width + kArrowSize,
contentSize.height
};
} else if (widthPlusArrow < rectX0) {
_arrowDirection = KxMenuViewArrowDirectionRight;
CGPoint point = (CGPoint){
rectX0 - widthPlusArrow,
rectYM - heightHalf
};
if (point.y < kMargin)
point.y = kMargin;
if ((point.y + contentSize.height + 5) > outerHeight)
point.y = outerHeight - contentSize.height - kMargin;
_arrowPosition = rectYM - point.y;
_contentView.frame = (CGRect){CGPointZero, contentSize};
self.frame = (CGRect) {
point,
contentSize.width + kArrowSize,
contentSize.height
};
} else {
_arrowDirection = KxMenuViewArrowDirectionNone;
self.frame = (CGRect) {
(outerWidth - contentSize.width) * 0.5f,
(outerHeight - contentSize.height) * 0.5f,
contentSize,
};
}
}
- (void)showMenuInView:(UIView *)view
fromRect:(CGRect)rect
menuItems:(NSArray *)menuItems
{
_menuItems = menuItems;
_contentView = [self mkContentView];
[self addSubview:_contentView];
[self setupFrameInView:view fromRect:rect];
KxMenuOverlay *overlay = [[KxMenuOverlay alloc] initWithFrame:view.bounds];
[overlay addSubview:self];
[view addSubview:overlay];
_contentView.hidden = YES;
const CGRect toFrame = self.frame;
self.frame = (CGRect){self.arrowPoint, 1, 1};
[UIView animateWithDuration:0.2
animations:^(void) {
self.alpha = 1.0f;
self.frame = toFrame;
} completion:^(BOOL completed) {
_contentView.hidden = NO;
}];
}
- (void)dismissMenu:(BOOL) animated
{
if (self.superview) {
if (animated) {
_contentView.hidden = YES;
const CGRect toFrame = (CGRect){self.arrowPoint, 1, 1};
[UIView animateWithDuration:0.2
animations:^(void) {
self.alpha = 0;
self.frame = toFrame;
} completion:^(BOOL finished) {
if ([self.superview isKindOfClass:[KxMenuOverlay class]])
[self.superview removeFromSuperview];
[self removeFromSuperview];
}];
} else {
if ([self.superview isKindOfClass:[KxMenuOverlay class]])
[self.superview removeFromSuperview];
[self removeFromSuperview];
}
}
}
- (void)performAction:(id)sender
{
[self dismissMenu:YES];
UIButton *button = (UIButton *)sender;
KxMenuItem *menuItem = _menuItems[button.tag];
[menuItem performAction];
}
- (UIView *) mkContentView
{
for (UIView *v in self.subviews) {
[v removeFromSuperview];
}
if (!_menuItems.count)
return nil;
const CGFloat kMinMenuItemHeight = 32.f;
const CGFloat kMinMenuItemWidth = 32.f;
const CGFloat kMarginX = 10.f;
const CGFloat kMarginY = 5.f;
UIFont *titleFont = [KxMenu titleFont];
if (!titleFont) titleFont = [UIFont boldSystemFontOfSize:16];
CGFloat maxImageWidth = 0;
CGFloat maxItemHeight = 0;
CGFloat maxItemWidth = 0;
for (KxMenuItem *menuItem in _menuItems) {
const CGSize imageSize = menuItem.image.size;
if (imageSize.width > maxImageWidth)
maxImageWidth = imageSize.width;
}
if (maxImageWidth) {
maxImageWidth += kMarginX;
}
for (KxMenuItem *menuItem in _menuItems) {
NSDictionary *attributes = @{NSFontAttributeName:titleFont};
const CGSize titleSize = [menuItem.title sizeWithAttributes:attributes];
const CGSize imageSize = menuItem.image.size;
const CGFloat itemHeight = MAX(titleSize.height, imageSize.height) + kMarginY * 2;
const CGFloat itemWidth = ((!menuItem.enabled && !menuItem.image) ? titleSize.width : maxImageWidth + titleSize.width) + kMarginX * 4;
if (itemHeight > maxItemHeight)
maxItemHeight = itemHeight;
if (itemWidth > maxItemWidth)
maxItemWidth = itemWidth;
}
maxItemWidth = MAX(maxItemWidth, kMinMenuItemWidth);
maxItemHeight = MAX(maxItemHeight, kMinMenuItemHeight);
const CGFloat titleX = kMarginX * 2 + maxImageWidth;
const CGFloat titleWidth = maxItemWidth - titleX - kMarginX * 2;
UIImage *selectedImage = [KxMenuView selectedImage:(CGSize){maxItemWidth, maxItemHeight + 2}];
UIImage *gradientLine = [KxMenuView gradientLine: (CGSize){maxItemWidth - kMarginX * 4, 1}];
UIView *contentView = [[UIView alloc] initWithFrame:CGRectZero];
contentView.autoresizingMask = UIViewAutoresizingNone;
contentView.backgroundColor = [UIColor clearColor];
contentView.opaque = NO;
CGFloat itemY = kMarginY * 2;
NSUInteger itemNum = 0;
for (KxMenuItem *menuItem in _menuItems) {
const CGRect itemFrame = (CGRect){0, itemY, maxItemWidth, maxItemHeight};
UIView *itemView = [[UIView alloc] initWithFrame:itemFrame];
itemView.autoresizingMask = UIViewAutoresizingNone;
itemView.backgroundColor = [UIColor clearColor];
itemView.opaque = NO;
[contentView addSubview:itemView];
if (menuItem.enabled) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = itemNum;
button.frame = itemView.bounds;
button.enabled = menuItem.enabled;
button.backgroundColor = [UIColor clearColor];
button.opaque = NO;
button.autoresizingMask = UIViewAutoresizingNone;
[button addTarget:self
action:@selector(performAction:)
forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundImage:selectedImage forState:UIControlStateHighlighted];
[itemView addSubview:button];
}
if (menuItem.title.length) {
CGRect titleFrame;
if (!menuItem.enabled && !menuItem.image) {
titleFrame = (CGRect){
kMarginX * 2,
kMarginY,
maxItemWidth - kMarginX * 4,
maxItemHeight - kMarginY * 2
};
} else {
titleFrame = (CGRect){
titleX,
kMarginY,
titleWidth,
maxItemHeight - kMarginY * 2
};
}
UILabel *titleLabel = [[UILabel alloc] initWithFrame:titleFrame];
titleLabel.text = menuItem.title;
titleLabel.font = titleFont;
titleLabel.textAlignment = menuItem.alignment;
titleLabel.textColor = menuItem.foreColor ? menuItem.foreColor : [UIColor whiteColor];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.autoresizingMask = UIViewAutoresizingNone;
//titleLabel.backgroundColor = [UIColor greenColor];
[itemView addSubview:titleLabel];
}
if (menuItem.image) {
const CGRect imageFrame = {kMarginX * 2, kMarginY, maxImageWidth, maxItemHeight - kMarginY * 2};
UIImageView *imageView = [[UIImageView alloc] initWithFrame:imageFrame];
imageView.image = menuItem.image;
imageView.clipsToBounds = YES;
imageView.contentMode = UIViewContentModeCenter;
imageView.autoresizingMask = UIViewAutoresizingNone;
[itemView addSubview:imageView];
}
if (itemNum < _menuItems.count - 1) {
UIImageView *gradientView = [[UIImageView alloc] initWithImage:gradientLine];
gradientView.frame = (CGRect){kMarginX * 2, maxItemHeight + 1, gradientLine.size};
gradientView.contentMode = UIViewContentModeLeft;
[itemView addSubview:gradientView];
itemY += 2;
}
itemY += maxItemHeight;
++itemNum;
}
contentView.frame = (CGRect){0, 0, maxItemWidth, itemY + kMarginY * 2};
return contentView;
}
- (CGPoint) arrowPoint
{
CGPoint point;
if (_arrowDirection == KxMenuViewArrowDirectionUp) {
point = (CGPoint){ CGRectGetMinX(self.frame) + _arrowPosition, CGRectGetMinY(self.frame) };
} else if (_arrowDirection == KxMenuViewArrowDirectionDown) {
point = (CGPoint){ CGRectGetMinX(self.frame) + _arrowPosition, CGRectGetMaxY(self.frame) };
} else if (_arrowDirection == KxMenuViewArrowDirectionLeft) {
point = (CGPoint){ CGRectGetMinX(self.frame), CGRectGetMinY(self.frame) + _arrowPosition };
} else if (_arrowDirection == KxMenuViewArrowDirectionRight) {
point = (CGPoint){ CGRectGetMaxX(self.frame), CGRectGetMinY(self.frame) + _arrowPosition };
} else {
point = self.center;
}
return point;
}
+ (UIImage *) selectedImage: (CGSize) size
{
const CGFloat locations[] = {0,1};
const CGFloat components[] = {
0.216, 0.471, 0.871, 1,
0.059, 0.353, 0.839, 1,
};
return [self gradientImageWithSize:size locations:locations components:components count:2];
}
+ (UIImage *) gradientLine: (CGSize) size
{
const CGFloat locations[5] = {0,0.2,0.5,0.8,1};
const CGFloat R = 0.44f, G = 0.44f, B = 0.44f;
const CGFloat components[20] = {
R,G,B,0.1,
R,G,B,0.4,
R,G,B,0.7,
R,G,B,0.4,
R,G,B,0.1
};
return [self gradientImageWithSize:size locations:locations components:components count:5];
}
+ (UIImage *) gradientImageWithSize:(CGSize) size
locations:(const CGFloat []) locations
components:(const CGFloat []) components
count:(NSUInteger)count
{
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef colorGradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
CGColorSpaceRelease(colorSpace);
CGContextDrawLinearGradient(context, colorGradient, (CGPoint){0, 0}, (CGPoint){size.width, 0}, 0);
CGGradientRelease(colorGradient);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
- (void) drawRect:(CGRect)rect
{
[self drawBackground:self.bounds
inContext:UIGraphicsGetCurrentContext()];
}
- (void)drawBackground:(CGRect)frame
inContext:(CGContextRef) context
{
CGFloat R0 = 0.267, G0 = 0.303, B0 = 0.335;
CGFloat R1 = 0.040, G1 = 0.040, B1 = 0.040;
UIColor *tintColor = [KxMenu tintColor];
if (tintColor) {
CGFloat a;
[tintColor getRed:&R0 green:&G0 blue:&B0 alpha:&a];
}
CGFloat X0 = frame.origin.x;
CGFloat X1 = frame.origin.x + frame.size.width;
CGFloat Y0 = frame.origin.y;
CGFloat Y1 = frame.origin.y + frame.size.height;
// render arrow
UIBezierPath *arrowPath = [UIBezierPath bezierPath];
// fix the issue with gap of arrow's base if on the edge
const CGFloat kEmbedFix = 3.f;
if (_arrowDirection == KxMenuViewArrowDirectionUp) {
const CGFloat arrowXM = _arrowPosition;
const CGFloat arrowX0 = arrowXM - kArrowSize;
const CGFloat arrowX1 = arrowXM + kArrowSize;
const CGFloat arrowY0 = Y0;
const CGFloat arrowY1 = Y0 + kArrowSize + kEmbedFix;
[arrowPath moveToPoint: (CGPoint){arrowXM, arrowY0}];
[arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
[arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY1}];
[arrowPath addLineToPoint: (CGPoint){arrowXM, arrowY0}];
[[UIColor colorWithRed:R0 green:G0 blue:B0 alpha:1] set];
Y0 += kArrowSize;
} else if (_arrowDirection == KxMenuViewArrowDirectionDown) {
const CGFloat arrowXM = _arrowPosition;
const CGFloat arrowX0 = arrowXM - kArrowSize;
const CGFloat arrowX1 = arrowXM + kArrowSize;
const CGFloat arrowY0 = Y1 - kArrowSize - kEmbedFix;
const CGFloat arrowY1 = Y1;
[arrowPath moveToPoint: (CGPoint){arrowXM, arrowY1}];
[arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
[arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY0}];
[arrowPath addLineToPoint: (CGPoint){arrowXM, arrowY1}];
[[UIColor colorWithRed:R1 green:G1 blue:B1 alpha:1] set];
Y1 -= kArrowSize;
} else if (_arrowDirection == KxMenuViewArrowDirectionLeft) {
const CGFloat arrowYM = _arrowPosition;
const CGFloat arrowX0 = X0;
const CGFloat arrowX1 = X0 + kArrowSize + kEmbedFix;
const CGFloat arrowY0 = arrowYM - kArrowSize;;
const CGFloat arrowY1 = arrowYM + kArrowSize;
[arrowPath moveToPoint: (CGPoint){arrowX0, arrowYM}];
[arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
[arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
[arrowPath addLineToPoint: (CGPoint){arrowX0, arrowYM}];
[[UIColor colorWithRed:R0 green:G0 blue:B0 alpha:1] set];
X0 += kArrowSize;
} else if (_arrowDirection == KxMenuViewArrowDirectionRight) {
const CGFloat arrowYM = _arrowPosition;
const CGFloat arrowX0 = X1;
const CGFloat arrowX1 = X1 - kArrowSize - kEmbedFix;
const CGFloat arrowY0 = arrowYM - kArrowSize;;
const CGFloat arrowY1 = arrowYM + kArrowSize;
[arrowPath moveToPoint: (CGPoint){arrowX0, arrowYM}];
[arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
[arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
[arrowPath addLineToPoint: (CGPoint){arrowX0, arrowYM}];
[[UIColor colorWithRed:R1 green:G1 blue:B1 alpha:1] set];
X1 -= kArrowSize;
}
[arrowPath fill];
// render body
const CGRect bodyFrame = {X0, Y0, X1 - X0, Y1 - Y0};
UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:bodyFrame
cornerRadius:8];
const CGFloat locations[] = {0, 1};
const CGFloat components[] = {
R0, G0, B0, 1,
R1, G1, B1, 1,
};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace,
components,
locations,
sizeof(locations)/sizeof(locations[0]));
CGColorSpaceRelease(colorSpace);
[borderPath addClip];
CGPoint start, end;
if (_arrowDirection == KxMenuViewArrowDirectionLeft ||
_arrowDirection == KxMenuViewArrowDirectionRight) {
start = (CGPoint){X0, Y0};
end = (CGPoint){X1, Y0};
} else {
start = (CGPoint){X0, Y0};
end = (CGPoint){X0, Y1};
}
CGContextDrawLinearGradient(context, gradient, start, end, 0);
CGGradientRelease(gradient);
}
@end
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
static KxMenu *gMenu;
static UIColor *gTintColor;
static UIFont *gTitleFont;
@implementation KxMenu {
KxMenuView *_menuView;
BOOL _observing;
}
+ (instancetype) sharedMenu
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
gMenu = [[KxMenu alloc] init];
});
return gMenu;
}
- (id) init
{
NSAssert(!gMenu, @"singleton object");
self = [super init];
if (self) {
}
return self;
}
- (void) dealloc
{
if (_observing) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
- (void) showMenuInView:(UIView *)view
fromRect:(CGRect)rect
menuItems:(NSArray *)menuItems
{
NSParameterAssert(view);
NSParameterAssert(menuItems.count);
if (_menuView) {
[_menuView dismissMenu:NO];
_menuView = nil;
}
if (!_observing) {
_observing = YES;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationWillChange:)
name:UIApplicationWillChangeStatusBarOrientationNotification
object:nil];
}
_menuView = [[KxMenuView alloc] init];
[_menuView showMenuInView:view fromRect:rect menuItems:menuItems];
}
- (void) dismissMenu
{
if (_menuView) {
[_menuView dismissMenu:NO];
_menuView = nil;
}
if (_observing) {
_observing = NO;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
- (void) orientationWillChange: (NSNotification *) n
{
[self dismissMenu];
}
+ (void) showMenuInView:(UIView *)view
fromRect:(CGRect)rect
menuItems:(NSArray *)menuItems
{
[[self sharedMenu] showMenuInView:view fromRect:rect menuItems:menuItems];
}
+ (void) dismissMenu
{
[[self sharedMenu] dismissMenu];
}
+ (UIColor *) tintColor
{
return gTintColor;
}
+ (void) setTintColor: (UIColor *) tintColor
{
if (tintColor != gTintColor) {
gTintColor = tintColor;
}
}
+ (UIFont *) titleFont
{
return gTitleFont;
}
+ (void) setTitleFont: (UIFont *) titleFont
{
if (titleFont != gTitleFont) {
gTitleFont = titleFont;
}
}
@end

View file

@ -0,0 +1,46 @@
//
// SettingPageViewController.h
// uartadapter
//
// Created by isaiah on 9/1/15.
// Copyright (c) 2015 realtek. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface SettingPageViewController : UIViewController<
UIPickerViewDataSource,
UIPickerViewDelegate,
UITextFieldDelegate,
NSStreamDelegate,
NSNetServiceBrowserDelegate,
NSNetServiceDelegate,
UIAlertViewDelegate>
{
}
+ (void) initSettingIOTInfoArray;
+ (void) copyIOTInfo:(NSNetService *)mService;
@property (nonatomic, retain) NSData *allSettings;
@property (nonatomic, retain) NSInputStream *inputStream;
@property (nonatomic, retain) NSOutputStream *outputStream;
//@property (nonatomic, retain) NSMutableArray *settingIOTInfoArray;
@property (nonatomic, retain) NSNetService *selectedService;
@property (nonatomic, assign) NSInteger selectedGroupID;
@property (nonatomic, retain) IBOutlet UITextField *baudRateField;
@property (nonatomic, retain) IBOutlet UITextField *dataBitField;
@property (nonatomic, retain) IBOutlet UITextField *parityBitField;
@property (nonatomic, retain) IBOutlet UITextField *stopBitField;
//@property (nonatomic, retain) IBOutlet UIPickerView *datapicker;
- (IBAction) saveSettings;
- (IBAction) restoreSettings;
@end

View file

@ -0,0 +1,580 @@
//
// SettingPageViewController.m
// uartadapter
//
// Created by isaiah on 9/1/15.
// Copyright (c) 2015 realtek. All rights reserved.
//
//#import <Foundation/Foundation.h>
#import "ViewController.h"
#import "SettingPageViewController.h"
#include <ifaddrs.h>
#include <arpa/inet.h>
uint8_t const cmdPrefix[] = { 0x41, 0x4D, 0x45, 0x42, 0x41, 0x5F, 0x55, 0x41, 0x52, 0x54 };;
uint8_t const cmdGetAllSetting[] = { 0x02, 0x00, 0x0f };
NSMutableArray *settingIOTInfoArray;
@interface SettingPageViewController ()
@end
@implementation SettingPageViewController
@synthesize inputStream, outputStream;
@synthesize selectedService = _selectedService;
@synthesize baudRateField, dataBitField, parityBitField, stopBitField;
@synthesize allSettings = _allSettings;
//@synthesize datapicker;
//UIAlertView *alert;
NSArray * baurateData ;
NSArray * bitData;
NSArray * parityBitData;
NSArray * stopBitdata;
int mBardRate = 0;
int mDataBit = 0;
int mParityBit = 0;
int mStopBit = 0;
UIPickerView *datapicker;
int mTextFieldTag = -1;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background.png"]];
baurateData = [[NSArray alloc] initWithObjects:@"1200", @"9600", @"14400", @"19200", @"28800", @"38400", @"57600", @"76800", @"115200", @"128000", @"153600", @"230400", @"460800", @"500000", @"921600", nil];
bitData = [[NSArray alloc] initWithObjects:@"7", @"8", nil];
parityBitData = [[NSArray alloc] initWithObjects:@"none", @"odd", @"even", nil];
stopBitdata = [[NSArray alloc] initWithObjects:@"none", @"1", nil];
datapicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 50, 100, 150)];
[datapicker setDataSource: self];
[datapicker setDelegate: self];
[baudRateField setDelegate:self];
[dataBitField setDelegate:self];
[parityBitField setDelegate:self];
[stopBitField setDelegate:self];
datapicker.showsSelectionIndicator = YES;
self.baudRateField.inputView = datapicker;
self.dataBitField.inputView = datapicker;
self.parityBitField.inputView = datapicker;
self.stopBitField.inputView = datapicker;
if([self inputStreamReceivedParser:self.allSettings] == 1)//update ui
{
self.baudRateField.text = [NSString stringWithFormat:@"%d",mBardRate];
self.dataBitField.text = [NSString stringWithFormat:@"%d",mDataBit];
if (mParityBit == 0)
self.parityBitField.text = @"none";
else if (mParityBit == 1)
self.parityBitField.text = @"odd";
else if (mParityBit == 2)
self.parityBitField.text = @"even";
if (mStopBit == 0)
self.stopBitField.text = @"none";
else if (mStopBit == 1)
self.stopBitField.text = @"1";
// [alert dismissWithClickedButtonIndex:0 animated:YES];
}
//[self prepareForInitNetworkCommunication];
/*
alert = [[UIAlertView alloc] initWithTitle:@"UART Adapter" message:@"Connecting" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
UIActivityIndicatorView * alertIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(125.0, 00.0, 30.0, 30.0) ];
alertIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
//alertIndicator.center = CGPointMake(alert.bounds.size.width/2 , (alert.bounds.size.height/2) + 10);
[alertIndicator startAnimating];
if ([[[UIDevice currentDevice] systemVersion]compare:@"7.0"] != NSOrderedAscending)
[alert setValue:alertIndicator forKey:@"accessoryView"];
else
[alert addSubview:alertIndicator];
// [alert show];
*/
/*
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self queryAllSettings];
});
*/
}
- (IBAction) restoreSettings
{
self.baudRateField.text = [NSString stringWithFormat:@"%d",mBardRate];
self.dataBitField.text = [NSString stringWithFormat:@"%d",mDataBit];
if (mParityBit == 0)
self.parityBitField.text = @"none";
else if (mParityBit == 1)
self.parityBitField.text = @"odd";
else if (mParityBit == 2)
self.parityBitField.text = @"even";
if (mStopBit == 0)
self.stopBitField.text = @"none";
else if (mStopBit == 1)
self.stopBitField.text = @"1";
[datapicker reloadAllComponents];
}
- (IBAction) saveSettings{
NSString * stringTxtField;
uint8_t cmdReq[] = {0x00};
uint8_t *cmdBaudrate = NULL;
uint8_t *cmdDatabit = NULL;
uint8_t *cmdParity = NULL;
uint8_t *cmdStopbit = NULL;
stringTxtField = self.baudRateField.text;
if([stringTxtField isEqualToString:@"1200"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0xB0, 0x04, 0x00, 0x00 };
}else if([stringTxtField isEqualToString:@"9600"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x80, 0x25, 0x00, 0x00 };
}else if([stringTxtField isEqualToString:@"14400"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x40, 0x38, 0x00, 0x00 };
}else if([stringTxtField isEqualToString:@"19200"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0x4B, 0x00, 0x00 };
}else if([stringTxtField isEqualToString:@"28800"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x80, 0x70, 0x00, 0x00 };
}else if([stringTxtField isEqualToString:@"38400"]){
cmdBaudrate = (uint8_t []){ 0x00, 0x01, 0x04, 0x00, 0x96, 0x00, 0x00 };
}else if([stringTxtField isEqualToString:@"57600"]){
cmdBaudrate = (uint8_t []){ 0x00, 0x01, 0x04, 0x00, 0xE1, 0x00, 0x00 };
}else if([stringTxtField isEqualToString:@"76800"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0x2C, 0x01, 0x00 };
}else if([stringTxtField isEqualToString:@"115200"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0xC2, 0x01, 0x00 };
}else if([stringTxtField isEqualToString:@"128000"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0xF4, 0x01, 0x00 };
}else if([stringTxtField isEqualToString:@"153600"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0x58, 0x02, 0x00 };
}else if([stringTxtField isEqualToString:@"230400"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0x84, 0x03, 0x00 };
}else if([stringTxtField isEqualToString:@"460800"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0x08, 0x07, 0x00 };
}else if([stringTxtField isEqualToString:@"500000"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x20, 0xA1, 0x07, 0x00 };
}else if([stringTxtField isEqualToString:@"921600"]){
cmdBaudrate = (uint8_t []) { 0x00, 0x01, 0x04, 0x00, 0x10, 0x0E, 0x00 };
}
stringTxtField = self.dataBitField.text;
if([stringTxtField isEqualToString:@"8"]){
cmdDatabit = (uint8_t []) { 0x00, 0x02, 0x01, 0x08 };
}else{
cmdDatabit = (uint8_t []) { 0x00, 0x02, 0x01, 0x07 };
}
stringTxtField = self.parityBitField.text;
if([stringTxtField isEqualToString:@"none"]){
cmdParity = (uint8_t []) { 0x00, 0x04, 0x01, 0x00 };
}else if([stringTxtField isEqualToString:@"odd"]){
cmdParity = (uint8_t []) { 0x00, 0x04, 0x01, 0x01 };
}else if([stringTxtField isEqualToString:@"even"]){
cmdParity = (uint8_t []) { 0x00, 0x04, 0x01, 0x02 };
}
stringTxtField = self.stopBitField.text;
if([stringTxtField isEqualToString:@"none"]){
cmdStopbit = (uint8_t []) { 0x00, 0x08, 0x01, 0x00 };
}else if([stringTxtField isEqualToString:@"1"]){
cmdStopbit = (uint8_t []) { 0x00, 0x08, 0x01, 0x01 };
}
NSMutableData *cmdSetSettings = [[NSMutableData alloc] initWithBytes:cmdPrefix length:sizeof(cmdPrefix)];
[cmdSetSettings appendBytes:cmdReq length:1];
[cmdSetSettings appendBytes:cmdBaudrate length:7];
[cmdSetSettings appendBytes:cmdDatabit length:4];
[cmdSetSettings appendBytes:cmdParity length:4];
[cmdSetSettings appendBytes:cmdStopbit length:4];
if (self.selectedGroupID != 0) {
for (int i=0 ; i < settingIOTInfoArray.count; i++) {
NSNetService * groupIOTDevice = [settingIOTInfoArray objectAtIndex:i];
[self prepareForInitNetworkCommunication:[groupIOTDevice.addresses objectAtIndex:0 ] Port:(int)groupIOTDevice.port];
[outputStream write:[cmdSetSettings bytes] maxLength:[cmdSetSettings length]];
}
}else{
[self prepareForInitNetworkCommunication:[self.selectedService.addresses objectAtIndex:0 ] Port:(int)self.selectedService.port];
[outputStream write:[cmdSetSettings bytes] maxLength:[cmdSetSettings length]];
}
}
+ (void) initSettingIOTInfoArray
{
settingIOTInfoArray = [[NSMutableArray alloc] init];
}
+ (void) copyIOTInfo:(NSNetService *)mService
{
[settingIOTInfoArray addObject:mService];
// struct _IOTInfo IOTInfo;
//settingIOTInfoArray = [[NSMutableArray alloc] init];
// for (int i = 0; i < mIOTInfoArray.count; i++) {
// [[mIOTInfoArray objectAtIndex:i] getValue:&IOTInfo];
// [settingIOTInfoArray addObject:[NSValue valueWithBytes:&IOTInfo objCType:@encode(struct _IOTInfo)]];
//}
}
- (void) queryAllSettings {
NSMutableData *cmd = [[NSMutableData alloc] initWithBytes:cmdPrefix length:sizeof(cmdPrefix)];
[cmd appendBytes:cmdGetAllSetting length:sizeof(cmdGetAllSetting)];
[outputStream write:[cmd bytes] maxLength:[cmd length]];
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(@"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[64] = {0};
int len;
while ([inputStream hasBytesAvailable]) {
len = [[NSNumber numberWithInteger:[inputStream read:buffer maxLength: sizeof(buffer)]] intValue] ;
if (len > 0) {
NSData *output = [[NSData alloc] initWithBytes:buffer length:len];
if (nil != output) {
if([self inputStreamReceivedParser:output] == 1)//update ui
{
self.baudRateField.text = [NSString stringWithFormat:@"%d",mBardRate];
self.dataBitField.text = [NSString stringWithFormat:@"%d",mDataBit];
if (mParityBit == 0)
self.parityBitField.text = @"none";
else if (mParityBit == 1)
self.parityBitField.text = @"odd";
else if (mParityBit == 2)
self.parityBitField.text = @"even";
if (mStopBit == 0)
self.stopBitField.text = @"none";
else if (mStopBit == 1)
self.stopBitField.text = @"1";
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Serial Port Setup" message:@"Success!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(@"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//[theStream release];
theStream = nil;
break;
default:
NSLog(@"Unknown event");
}
}
- (int) inputStreamReceivedParser:(NSData *)message {
uint8_t *recvCmd = (uint8_t *)[message bytes] ;
if ([self checkPrefix:recvCmd]){
int readbit = 10;
if (recvCmd[readbit] == 0x01) { //response for ack
return 0;//ok
}else if (recvCmd[readbit] == 0x03) { //response for getting
mBardRate = 0;
mDataBit = 0;
mParityBit = 0;
mStopBit = 0;
readbit+=2;
do{
if (recvCmd[readbit] == 0x01) { //baudrate
int bit = 0;
int tmp = 0;
int byteLen = recvCmd[++readbit];
readbit++;
for (int i=readbit; i < (readbit+byteLen); i++) {
tmp = (recvCmd[i] & 0xFF) << (8*bit);
mBardRate += tmp;
bit++;
}
readbit+=(byteLen+1);
}else if (recvCmd[readbit] == 0x02) { //data
int byteLen = recvCmd[++readbit];
readbit++;
if (byteLen == 1)
mDataBit = recvCmd[readbit];
else{
return -1;
}
readbit+=(byteLen+1);
}else if (recvCmd[readbit] == 0x04) { //parity
int byteLen = recvCmd[++readbit];
readbit++;
if (byteLen == 1)
mParityBit = recvCmd[readbit];
else{
return -1;
}
readbit+=(byteLen+1);
}else if (recvCmd[readbit] == 0x08) { //stopbit
int byteLen = recvCmd[++readbit];
readbit++;
if (byteLen == 1)
mStopBit = recvCmd[readbit];
else{
return -1;
}
readbit+=(byteLen+1);
}else
readbit++;
}while (readbit < [message length]);
return 1;//update UI
}//if (recvCmd[readbit] == 0x01)
}
return 2;//other
}
- (Boolean) checkPrefix:(uint8_t *) recvPrefix
{
for (int i = 0; i < sizeof(cmdPrefix); i++) {
if(recvPrefix[i] != cmdPrefix[i])
return false;
}
return true;
}
-(void)prepareForInitNetworkCommunication:(NSData *)mAddress Port:(int)mPort {
NSData *address = mAddress;
char addressString[INET6_ADDRSTRLEN];
int inetType;
struct sockaddr_in6 addr6;
memcpy(&addr6, address.bytes, address.length);
if (address.length == 16) { // IPv4
inetType = AF_INET;
struct sockaddr_in addr4;
memcpy(&addr4, address.bytes, address.length);
inet_ntop(AF_INET, &addr4.sin_addr, addressString, 512);
[self initNetworkCommunication:[NSString stringWithCString:addressString encoding:NSASCIIStringEncoding] Port:mPort];
}
}
- (void) initNetworkCommunication:(NSString *)mIP Port:(int)mPort {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)mIP, mPort, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
mTextFieldTag = (int)textField.tag;
[datapicker reloadAllComponents];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
switch (mTextFieldTag) {
case 0:
self.baudRateField.text = baurateData[row];
break;
case 1:
self.dataBitField.text = bitData[row];
break;
case 2:
self.parityBitField.text = parityBitData[row];
break;
case 3:
self.stopBitField.text = stopBitdata[row];
break;
default:
break;
}
[[self view] endEditing:YES];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
switch (mTextFieldTag) {
case 0:
return baurateData[row];
break;
case 1:
return bitData[row];
break;
case 2:
return parityBitData[row];
break;
case 3:
return stopBitdata[row];
break;
default:
return 0;
break;
}
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1 ;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
switch (mTextFieldTag) {
case 0:
return baurateData.count;
break;
case 1:
return bitData.count;
break;
case 2:
return parityBitData.count;
break;
case 3:
return stopBitdata.count;
break;
default:
return 0;
break;
}
}
- (void)viewDidUnload {
[super viewDidUnload];
settingIOTInfoArray = nil;
}
- (void)dealloc
{
[inputStream close];
[outputStream close];
self.selectedService = nil;
settingIOTInfoArray = nil;
}
@end

View file

@ -0,0 +1,40 @@
//
// ViewController.h
// uartadapter
//
// Created by isaiah on 8/26/15.
// Copyright (c) 2015 realtek. All rights reserved.
//
#import <UIKit/UIKit.h>
struct _IOTInfo {
__unsafe_unretained NSNetService *service;
__unsafe_unretained NSString *groupName;
NSInteger groupID;
};
@interface ViewController : UICollectionViewController < /*UICollectionViewDelegateFlowLayout*/ NSNetServiceBrowserDelegate,
NSNetServiceDelegate,
UIAlertViewDelegate,
NSStreamDelegate,
NSNetServiceBrowserDelegate,
NSNetServiceDelegate,
UIGestureRecognizerDelegate> {
NSNetServiceBrowser *_netServiceBrowser;
NSMutableArray *_servicesArray;
NSNetService *_selectedService;
}
@property (nonatomic, retain) NSMutableArray *IOTInfoArray;
@property (nonatomic, retain) NSNetServiceBrowser *netServiceBrowser;
@property (nonatomic, retain) NSMutableArray *controlServicesArray;
@property (nonatomic, retain) NSMutableArray *dataServicesArray;
@property (nonatomic, retain) NSNetService *selectedService;
- (IBAction) scanButton;
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
//
// main.m
// uartadapter
//
// Created by isaiah on 8/26/15.
// Copyright (c) 2015 realtek. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,14 @@
//
// Prefix header for all source files of the 'KxMenuExample' target in the 'KxMenuExample' project
//
#import <Availability.h>
#ifndef __IPHONE_4_0
#warning "This project uses features only available in iOS SDK 4.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif