iOS app sources copied from https://github.com/cennydavidsson/GF. Not yet tested with current GF.
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:GF Offline Translator.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0630"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "CC57C2371AEE23D000051DE4"
|
||||
BuildableName = "GF Offline Translator.app"
|
||||
BlueprintName = "GF Offline Translator"
|
||||
ReferencedContainer = "container:GF Offline Translator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "CC57C2501AEE23D000051DE4"
|
||||
BuildableName = "GF Offline TranslatorTests.xctest"
|
||||
BlueprintName = "GF Offline TranslatorTests"
|
||||
ReferencedContainer = "container:GF Offline Translator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "CC57C2501AEE23D000051DE4"
|
||||
BuildableName = "GF Offline TranslatorTests.xctest"
|
||||
BlueprintName = "GF Offline TranslatorTests"
|
||||
ReferencedContainer = "container:GF Offline Translator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "CC57C2371AEE23D000051DE4"
|
||||
BuildableName = "GF Offline Translator.app"
|
||||
BlueprintName = "GF Offline Translator"
|
||||
ReferencedContainer = "container:GF Offline Translator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "CC57C2371AEE23D000051DE4"
|
||||
BuildableName = "GF Offline Translator.app"
|
||||
BlueprintName = "GF Offline Translator"
|
||||
ReferencedContainer = "container:GF Offline Translator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "CC57C2371AEE23D000051DE4"
|
||||
BuildableName = "GF Offline Translator.app"
|
||||
BlueprintName = "GF Offline Translator"
|
||||
ReferencedContainer = "container:GF Offline Translator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>GF Offline Translator.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>CC57C2371AEE23D000051DE4</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>CC57C2501AEE23D000051DE4</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
10
src/ui/ios/GF-Offline-Translator/GF Offline Translator.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:GF Offline Translator.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?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>HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
|
||||
<true/>
|
||||
<key>SnapshotAutomaticallyBeforeSignificantChanges</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// AppDelegate.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class Translator;
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
@property (strong, nonatomic) Translator *translator;
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// AppDelegate.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "TranslatorStore.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.
|
||||
[TranslatorStore saveCurrentGrammarsFromTranslator:self.translator];
|
||||
}
|
||||
|
||||
- (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
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// ArrowsButton.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ArrowsButton : UIButton
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// ArrowsButton.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ArrowsButton.h"
|
||||
#import "StyleKitGF.h"
|
||||
|
||||
@implementation ArrowsButton
|
||||
|
||||
|
||||
// Only override drawRect: if you perform custom drawing.
|
||||
// An empty implementation adversely affects performance during animation.
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
// Drawing code
|
||||
[StyleKitGF drawArrowsWithFrame:rect];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,311 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="xFI-0W-N5x">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Translation Text View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="TranslationTextViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="St3-7e-rXA">
|
||||
<barButtonItem key="rightBarButtonItem" title="Info" id="pCM-e5-4xf">
|
||||
<connections>
|
||||
<segue destination="dgk-2A-luy" kind="show" identifier="Info" id="X1I-na-NNV"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<segue destination="B6l-9t-iLr" kind="presentation" identifier="ChangeLanguage" id="wkV-br-4Id"/>
|
||||
<segue destination="Vu1-QE-7az" kind="show" identifier="TranslationOptions" id="zeM-mX-HkR"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1166" y="-372"/>
|
||||
</scene>
|
||||
<!--Choose language-->
|
||||
<scene sceneID="vPx-fF-xJR">
|
||||
<objects>
|
||||
<tableViewController id="Fe0-Ou-Rlf" customClass="LanguagesViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="2Mo-cK-SuX">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="LanguageCell" textLabel="qme-rd-ja5" style="IBUITableViewCellStyleDefault" id="NLI-62-k37">
|
||||
<rect key="frame" x="0.0" y="114" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="NLI-62-k37" id="fZN-04-6Tc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Swedish" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="qme-rd-ja5">
|
||||
<rect key="frame" x="15" y="0.0" width="570" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="hKD-Nt-QPD" style="IBUITableViewCellStyleDefault" id="JwG-RO-i9T">
|
||||
<rect key="frame" x="0.0" y="158" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JwG-RO-i9T" id="JAV-RA-w7z">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="English" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hKD-Nt-QPD">
|
||||
<rect key="frame" x="15" y="0.0" width="570" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="9kF-jW-ZZq" style="IBUITableViewCellStyleDefault" id="haA-Gu-nbG">
|
||||
<rect key="frame" x="0.0" y="202" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="haA-Gu-nbG" id="T9t-BH-xD6">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Spanish" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9kF-jW-ZZq">
|
||||
<rect key="frame" x="15" y="0.0" width="570" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<sections/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="Fe0-Ou-Rlf" id="aoc-Vz-oLo"/>
|
||||
<outlet property="delegate" destination="Fe0-Ou-Rlf" id="Dst-b0-Mzq"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Choose language" id="iGz-3o-bcY">
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="XEa-C1-DUt">
|
||||
<connections>
|
||||
<action selector="cancel:" destination="Fe0-Ou-Rlf" id="uO1-fV-m5z"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="ADZ-WF-Rrq" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2690" y="30"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="Huc-dh-g8v">
|
||||
<objects>
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="xFI-0W-N5x" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="xvB-hQ-an3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
<connections>
|
||||
<segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="CD4-Hh-94z"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="1PJ-ar-1KV" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="426" y="-372"/>
|
||||
</scene>
|
||||
<!--Info-->
|
||||
<scene sceneID="nXS-Na-9ij">
|
||||
<objects>
|
||||
<viewController title="Info" id="dgk-2A-luy" customClass="WebViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="muk-1p-gTk"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wdN-RZ-bap"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="0BT-Mn-C5l">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<webView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rac-eS-ve4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</webView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="rac-eS-ve4" firstAttribute="top" secondItem="0BT-Mn-C5l" secondAttribute="top" id="7cM-HO-6vz"/>
|
||||
<constraint firstItem="rac-eS-ve4" firstAttribute="leading" secondItem="0BT-Mn-C5l" secondAttribute="leading" id="F2R-VX-m9g"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rac-eS-ve4" secondAttribute="trailing" id="Prv-Ph-Otq"/>
|
||||
<constraint firstItem="wdN-RZ-bap" firstAttribute="top" secondItem="rac-eS-ve4" secondAttribute="bottom" id="Row-Zp-YvG"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="webView" destination="rac-eS-ve4" id="GhE-qg-QnW"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="RKo-u1-dmE" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1880" y="-1478"/>
|
||||
</scene>
|
||||
<!--Translation Options View Controller-->
|
||||
<scene sceneID="Gym-bd-J1L">
|
||||
<objects>
|
||||
<tableViewController id="Vu1-QE-7az" customClass="TranslationOptionsViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="52" sectionHeaderHeight="10" sectionFooterHeight="10" id="9Ly-b2-546">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="Cell" id="bD0-ad-CEO" customClass="SentenceTranslationUITableViewCell">
|
||||
<rect key="frame" x="0.0" y="114" width="600" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bD0-ad-CEO" id="ZlP-Qe-UAj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="249" text="Label" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lB8-TQ-gOC">
|
||||
<rect key="frame" x="14" y="29" width="548" height="14"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<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="249" verticalCompressionResistancePriority="751" text="Label" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gZT-bJ-Kpt">
|
||||
<rect key="frame" x="8" y="8" width="554" height="21"/>
|
||||
<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="infoLight" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nkL-os-Edb">
|
||||
<rect key="frame" x="570" y="15" width="22" height="22"/>
|
||||
<connections>
|
||||
<action selector="showTree:" destination="bD0-ad-CEO" eventType="touchUpInside" id="mwb-KY-CKE"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="gZT-bJ-Kpt" firstAttribute="leading" secondItem="ZlP-Qe-UAj" secondAttribute="leadingMargin" id="0dY-24-331"/>
|
||||
<constraint firstItem="nkL-os-Edb" firstAttribute="trailing" secondItem="ZlP-Qe-UAj" secondAttribute="trailingMargin" id="62L-Lw-qMg"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="gZT-bJ-Kpt" secondAttribute="bottom" constant="14" id="7R4-WV-G6b"/>
|
||||
<constraint firstItem="lB8-TQ-gOC" firstAttribute="top" secondItem="gZT-bJ-Kpt" secondAttribute="bottom" id="8io-C1-3lS"/>
|
||||
<constraint firstItem="lB8-TQ-gOC" firstAttribute="leading" secondItem="ZlP-Qe-UAj" secondAttribute="leadingMargin" constant="6" id="FPJ-ge-w3P"/>
|
||||
<constraint firstItem="gZT-bJ-Kpt" firstAttribute="trailing" secondItem="ZlP-Qe-UAj" secondAttribute="trailingMargin" constant="-30" id="WO6-jN-5Sg"/>
|
||||
<constraint firstItem="nkL-os-Edb" firstAttribute="leading" secondItem="gZT-bJ-Kpt" secondAttribute="trailing" constant="8" id="X3h-hy-uPh"/>
|
||||
<constraint firstItem="lB8-TQ-gOC" firstAttribute="trailing" secondItem="ZlP-Qe-UAj" secondAttribute="trailingMargin" constant="-30" id="e2a-zj-bAf"/>
|
||||
<constraint firstItem="nkL-os-Edb" firstAttribute="top" secondItem="ZlP-Qe-UAj" secondAttribute="topMargin" constant="7" id="kHq-Qe-pd8"/>
|
||||
<constraint firstItem="gZT-bJ-Kpt" firstAttribute="top" secondItem="ZlP-Qe-UAj" secondAttribute="topMargin" id="rQg-rd-NdA"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="nkL-os-Edb" secondAttribute="bottom" constant="6" id="tod-J2-c7w"/>
|
||||
<constraint firstItem="lB8-TQ-gOC" firstAttribute="bottom" secondItem="ZlP-Qe-UAj" secondAttribute="bottomMargin" id="uU7-Mw-1Hj"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="7R4-WV-G6b"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="translationSentance" destination="gZT-bJ-Kpt" id="CkR-a4-myk"/>
|
||||
<outlet property="translationTree" destination="lB8-TQ-gOC" id="R1v-e6-Dec"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Basic" textLabel="Whx-GO-JX3" style="IBUITableViewCellStyleDefault" id="8A5-Qc-R0d" customClass="SentenceTranslationUITableViewCell">
|
||||
<rect key="frame" x="0.0" y="166" width="600" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8A5-Qc-R0d" id="2HZ-Yy-h5F">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Whx-GO-JX3">
|
||||
<rect key="frame" x="15" y="0.0" width="570" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="Vu1-QE-7az" id="aaA-LZ-lYo"/>
|
||||
<outlet property="delegate" destination="Vu1-QE-7az" id="MZf-as-uDy"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" id="gHe-8r-vSO"/>
|
||||
<connections>
|
||||
<segue destination="4Hm-Xx-a85" kind="show" identifier="WebView" id="maE-LZ-yt0"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="VmA-sb-BbB" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1880" y="-784"/>
|
||||
</scene>
|
||||
<!--Web View Controller-->
|
||||
<scene sceneID="X2Q-9F-hid">
|
||||
<objects>
|
||||
<viewController id="4Hm-Xx-a85" customClass="WebViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="UCN-ya-kgJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="8GP-cw-HP4"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="e4f-Yd-GYs">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<webView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Spb-gc-bFg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</webView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Spb-gc-bFg" firstAttribute="top" secondItem="e4f-Yd-GYs" secondAttribute="top" id="2Iw-Fw-8mr"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Spb-gc-bFg" secondAttribute="trailing" id="LPO-8J-Adk"/>
|
||||
<constraint firstItem="Spb-gc-bFg" firstAttribute="leading" secondItem="e4f-Yd-GYs" secondAttribute="leading" id="nDD-5G-4me"/>
|
||||
<constraint firstItem="8GP-cw-HP4" firstAttribute="top" secondItem="Spb-gc-bFg" secondAttribute="bottom" id="rhL-KZ-bwq"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="webView" destination="Spb-gc-bFg" id="aHr-v4-S6W"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="yzz-Gx-TbE" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2606" y="-784"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="WFo-Wh-qjb">
|
||||
<objects>
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="B6l-9t-iLr" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="lfh-gu-V91">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
<connections>
|
||||
<segue destination="Fe0-Ou-Rlf" kind="relationship" relationship="rootViewController" id="mmI-Sf-zMe"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="saS-qW-BUT" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1880" y="30"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Grammar.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "pgf/pgf.h"
|
||||
|
||||
@class Language;
|
||||
@class Translator;
|
||||
|
||||
@interface Grammar : NSObject
|
||||
@property (nonatomic) Language *language;
|
||||
@property (nonatomic) PgfConcr *concrete;
|
||||
|
||||
+ (Grammar *)loadGrammarFromLanguage:(Language *)language withTranslator:(Translator *)translator;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Grammar.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Grammar.h"
|
||||
#import "Translator.h"
|
||||
#import "Language.h"
|
||||
|
||||
// Grammatical Framework
|
||||
#import "pgf/pgf.h"
|
||||
#import "gu/mem.h"
|
||||
#import "gu/exn.h"
|
||||
#import "gu/file.h"
|
||||
|
||||
@implementation Grammar
|
||||
|
||||
+ (Grammar *)loadGrammarFromLanguage:(Language *)language withTranslator:(Translator *)translator {
|
||||
Grammar *grammar = [Grammar new];
|
||||
|
||||
// Load the file
|
||||
NSString *appLanguage = [NSString stringWithFormat:@"App%@",language.abbreviation];
|
||||
|
||||
PgfConcr *concr = pgf_get_language(translator.pgf, [appLanguage UTF8String]);
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:appLanguage ofType:@"pgf_c"];
|
||||
FILE *file = fopen([path UTF8String], "r");
|
||||
|
||||
GuIn *guIn = gu_file_in(file, translator.pool);
|
||||
|
||||
pgf_concrete_load(concr, guIn, translator.err);
|
||||
|
||||
grammar.concrete = concr;
|
||||
grammar.language = language;
|
||||
|
||||
return grammar;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
pgf_concrete_unload(self.concrete);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-Small.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-Small@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-Spotlight-40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Spotlight-40.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-Spotlight-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-76.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "24x24",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "notificationCenter",
|
||||
"subtype" : "38mm"
|
||||
},
|
||||
{
|
||||
"size" : "27.5x27.5",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "notificationCenter",
|
||||
"subtype" : "42mm"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "watch",
|
||||
"role" : "companionSettings",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "watch",
|
||||
"filename" : "Icon-Small@3x.png",
|
||||
"role" : "companionSettings",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "appLauncher",
|
||||
"subtype" : "38mm"
|
||||
},
|
||||
{
|
||||
"size" : "44x44",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "longLook",
|
||||
"subtype" : "42mm"
|
||||
},
|
||||
{
|
||||
"size" : "86x86",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "quickLook",
|
||||
"subtype" : "38mm"
|
||||
},
|
||||
{
|
||||
"size" : "98x98",
|
||||
"idiom" : "watch",
|
||||
"scale" : "2x",
|
||||
"role" : "quickLook",
|
||||
"subtype" : "42mm"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1011 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
@@ -0,0 +1,47 @@
|
||||
<?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>GF.$(PRODUCT_NAME:rfc1034identifier)</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>0.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>8</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>Main</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Language.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface Language : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
@property (nonatomic, copy) NSString *abbreviation;
|
||||
@property (nonatomic, copy) NSString *bcp;
|
||||
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
abbreviation:(NSString *)abbreviation
|
||||
bcp:(NSString *)bcp;
|
||||
|
||||
- (BOOL)isEqualToLanguage:(Language *)language;
|
||||
+ (NSArray *)allLanguages;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Language.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Language.h"
|
||||
|
||||
|
||||
@implementation Language
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
abbreviation:(NSString *)abbreviation
|
||||
bcp:(NSString *)bcp {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_name = name;
|
||||
_abbreviation = abbreviation;
|
||||
_bcp = bcp;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToLanguage:(Language *)language {
|
||||
if (!language) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL haveEqualNames = (!self.name && !language.name) || [self.name isEqualToString:language.name];
|
||||
BOOL haveEqualBcp = (!self.bcp && !language.bcp) || [self.bcp isEqualToString:language.bcp];
|
||||
|
||||
return haveEqualNames && haveEqualBcp;
|
||||
}
|
||||
|
||||
+ (NSArray *)allLanguages {
|
||||
return @[
|
||||
[[Language alloc] initWithName:@"Bulgarian" abbreviation:@"Bul" bcp:@"en-GB"],
|
||||
[[Language alloc] initWithName:@"Chinese" abbreviation:@"Chi" bcp:@"zh-CN"],
|
||||
[[Language alloc] initWithName:@"Catalan" abbreviation:@"Cat" bcp:@"ca-ES"],
|
||||
[[Language alloc] initWithName:@"Dutch" abbreviation:@"Dut" bcp:@"nl-NL"],
|
||||
[[Language alloc] initWithName:@"English" abbreviation:@"Eng" bcp:@"en-GB"],
|
||||
[[Language alloc] initWithName:@"Finnish" abbreviation:@"Fin" bcp:@"fi-FI"],
|
||||
[[Language alloc] initWithName:@"French" abbreviation:@"Fre" bcp:@"fr-FR"],
|
||||
[[Language alloc] initWithName:@"German" abbreviation:@"Ger" bcp:@"de-DE"],
|
||||
[[Language alloc] initWithName:@"Hindi" abbreviation:@"Hin" bcp:@"hi-IN"],
|
||||
[[Language alloc] initWithName:@"Italian" abbreviation:@"Ita" bcp:@"it-IT"],
|
||||
[[Language alloc] initWithName:@"Japanese" abbreviation:@"Jpn" bcp:@"ja-JP"],
|
||||
[[Language alloc] initWithName:@"Spanish" abbreviation:@"Spa" bcp:@"es-ES"],
|
||||
[[Language alloc] initWithName:@"Swedish" abbreviation:@"Swe" bcp:@"sv-SE"],
|
||||
[[Language alloc] initWithName:@"Thai" abbreviation:@"Tha" bcp:@"th-TH"]
|
||||
];
|
||||
}
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (![object isKindOfClass:[Language class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return [self isEqualToLanguage:(Language *)object];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return [self.name hash] ^ [self.bcp hash];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// LanguagesViewController.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TranslationTextViewController.h"
|
||||
@class Language;
|
||||
|
||||
|
||||
@interface LanguagesViewController : UITableViewController
|
||||
@property (nonatomic, weak) id<TranslationTextViewControllerDelegate> delegate;
|
||||
@property (nonatomic) NSArray *currentLanguages;
|
||||
@property (nonatomic) BOOL fromLanguage;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// LanguagesViewController.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "LanguagesViewController.h"
|
||||
#import "Language.h"
|
||||
#import "UITableViewCell+Customize.h"
|
||||
|
||||
@interface LanguagesViewController ()
|
||||
|
||||
@property (nonatomic) NSArray *languages;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LanguagesViewController
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Removes already used languages
|
||||
NSMutableArray *allLanguagesMutableCopy = Language.allLanguages.mutableCopy;
|
||||
[allLanguagesMutableCopy removeObjectsInArray:self.currentLanguages];
|
||||
self.languages = allLanguagesMutableCopy.copy;
|
||||
}
|
||||
|
||||
#pragma mark - User Interaction
|
||||
|
||||
- (IBAction)cancel:(UIBarButtonItem *)sender {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.languages.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LanguageCell" forIndexPath:indexPath];
|
||||
|
||||
Language *language = self.languages[indexPath.row];
|
||||
cell.textLabel.text = language.name;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
Language *language = self.languages[indexPath.row];
|
||||
|
||||
[self.delegate changeLanguageToLanguage:language isFrom:self.fromLanguage];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// MenuViewItem.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface MenuView : UIButton
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// MenuViewItem.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MenuView.h"
|
||||
#import "StyleKitGF.h"
|
||||
|
||||
@implementation MenuView
|
||||
|
||||
|
||||
// Only override drawRect: if you perform custom drawing.
|
||||
// An empty implementation adversely affects performance during animation.
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
// Drawing code
|
||||
[StyleKitGF drawMenyItemWithFrame:rect];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// MorphAnalyser.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-24.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Grammitcal framework
|
||||
#import "pgf.h"
|
||||
|
||||
@class Grammar;
|
||||
|
||||
@interface MorphAnalyser : NSObject
|
||||
|
||||
@property (nonatomic) PgfPGF *pgf;
|
||||
@property (nonatomic) GuExn *err;
|
||||
|
||||
@property (nonatomic, strong) Grammar *to;
|
||||
@property (nonatomic, strong) Grammar *from;
|
||||
|
||||
@property (nonatomic, readonly) NSArray *analysedWords;
|
||||
@property (nonatomic, readonly) NSString *bestTranslation;
|
||||
@property (nonatomic, readonly) NSMutableArray *html;
|
||||
|
||||
|
||||
- (instancetype)initWithPgf:(PgfPGF *)pgf err:(GuExn *)err to:(Grammar *)to from:(Grammar *)from;
|
||||
- (void)analysWord:(NSString *)word;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// MorphAnalyser.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-24.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MorphAnalyser.h"
|
||||
|
||||
// Model
|
||||
#import "Grammar.h"
|
||||
|
||||
// Grammatical Framework
|
||||
#import "pgf/pgf.h"
|
||||
#import "gu/mem.h"
|
||||
#import "gu/exn.h"
|
||||
#import "gu/file.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
PgfMorphoCallback callback;
|
||||
PgfPGF* pgf;
|
||||
PgfConcr* src;
|
||||
PgfConcr* tgt;
|
||||
} PgfLinLemmasCallback;
|
||||
|
||||
NSMutableArray *morphWords;
|
||||
NSMutableArray *htmls;
|
||||
|
||||
void print_lemma(PgfMorphoCallback* _self,
|
||||
PgfCId lemma, GuString analysis, prob_t prob,
|
||||
GuExn* err) {
|
||||
|
||||
PgfLinLemmasCallback* this = gu_container(_self, PgfMorphoCallback, callback);
|
||||
|
||||
// Here we print the lemmas. One and the same lemma could
|
||||
// appear several times if there are different analyses.
|
||||
// In this case "barn" is child but it could be in singular,
|
||||
// in plural or it could be used as a compound form.
|
||||
// Duplications should be eliminated in the user interface.
|
||||
|
||||
printf("%s (%s)\n", lemma, analysis);
|
||||
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
GuStringBuf* buf = gu_string_buf(tmp_pool);
|
||||
GuOut* out = gu_string_buf_out(buf);
|
||||
|
||||
// Now we build an expression from the lemma.
|
||||
PgfApplication app = {lemma, 0};
|
||||
PgfExpr expr = pgf_expr_apply(&app, tmp_pool);
|
||||
|
||||
// Now we linearize the expression in the source language
|
||||
pgf_linearize(this->src, expr, out, err);
|
||||
|
||||
if (pgf_has_linearization(this->tgt, lemma))
|
||||
gu_puts(" - ", out, err);
|
||||
else
|
||||
gu_puts(" ", out, err);
|
||||
|
||||
// Here we extract the type of the lemma
|
||||
// N for nouns, V,V2,V3,V2V,... for verbs, A for adjectives,
|
||||
// Prep for prepositions, etc.
|
||||
PgfType* ty = pgf_function_type(this->pgf, lemma);
|
||||
|
||||
NSString *inflectionCid = [NSString stringWithFormat:@"Inflection%@",
|
||||
[NSString stringWithUTF8String:ty->cid]];
|
||||
|
||||
BOOL hasLinearization = pgf_has_linearization(this->tgt, [inflectionCid UTF8String]);
|
||||
|
||||
// Here we get the tag that should be shown in the UI
|
||||
{
|
||||
// The purpose of this buffer is to just construct an expression.
|
||||
// Maybe there is an easier way in ObjectiveC
|
||||
GuStringBuf* expr_buf = gu_string_buf(tmp_pool);
|
||||
GuOut* expr_out = gu_string_buf_out(expr_buf);
|
||||
|
||||
|
||||
|
||||
if (hasLinearization) {
|
||||
gu_printf(expr_out, err, "MkTag (Inflection%s %s)",ty->cid ,lemma);
|
||||
GuString s = gu_string_buf_freeze(expr_buf, tmp_pool);
|
||||
GuIn* in = gu_string_in(s, tmp_pool);
|
||||
PgfExpr tag_expr = pgf_read_expr(in, tmp_pool, err);
|
||||
|
||||
pgf_linearize(this->tgt, tag_expr, out, err);
|
||||
|
||||
gu_puts(". ", out, err);
|
||||
}
|
||||
}
|
||||
|
||||
if (pgf_has_linearization(this->tgt, lemma)) {
|
||||
|
||||
|
||||
// Now we linearize the expression in the target language
|
||||
// This is the only thing that needs to be done for
|
||||
// visualization in the first view. Everything else
|
||||
// is useful only for the second view which shows
|
||||
// inflection tables and alternative translations.
|
||||
pgf_linearize(this->tgt, expr, out, err);
|
||||
} else {
|
||||
// gu_puts(".", out, err);
|
||||
}
|
||||
|
||||
// Finally we get the string which is used for describing
|
||||
// the different lexical entries in the translations view
|
||||
GuString s = gu_string_buf_freeze(buf, tmp_pool);
|
||||
printf("entry: %s\n", s);
|
||||
|
||||
NSString *translation = [NSString stringWithUTF8String:s];
|
||||
if ([morphWords containsObject:translation]) { //||
|
||||
// [[translation stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] hasSuffix:@"."]) {
|
||||
return;
|
||||
}
|
||||
|
||||
[morphWords addObject:translation];
|
||||
|
||||
// Here we get the html for the inflection table
|
||||
if (hasLinearization) {
|
||||
// The purpose of this buffer is to just construct an expression.
|
||||
// Maybe there is an easier way in ObjectiveC
|
||||
GuStringBuf* expr_buf = gu_string_buf(tmp_pool);
|
||||
GuOut* expr_out = gu_string_buf_out(expr_buf);
|
||||
gu_printf(expr_out, err, "MkDocument \"\" (Inflection%s %s) \"\"",ty->cid, lemma);
|
||||
GuString s = gu_string_buf_freeze(expr_buf, tmp_pool);
|
||||
GuIn* in = gu_string_in(s, tmp_pool);
|
||||
PgfExpr html_expr = pgf_read_expr(in, tmp_pool, err);
|
||||
|
||||
GuStringBuf* html_buf = gu_string_buf(tmp_pool);
|
||||
GuOut* html_out = gu_string_buf_out(html_buf);
|
||||
pgf_linearize(this->tgt, html_expr, html_out, err);
|
||||
GuString lin = gu_string_buf_freeze(html_buf, tmp_pool);
|
||||
printf("html:\n%s\n", lin);
|
||||
|
||||
NSString *htmlString = [NSString stringWithUTF8String:lin];
|
||||
|
||||
if (htmlString.length > 0) {
|
||||
NSMutableString *html = [NSMutableString stringWithString: @"<html><head><title></title></head><body style=\"background:transparent;\">"];
|
||||
[html appendString:htmlString];
|
||||
[html appendString:@"</body></html>"];
|
||||
[htmls addObject:html];
|
||||
}
|
||||
} else {
|
||||
[htmls addObject:@""];
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
gu_pool_free(tmp_pool);
|
||||
}
|
||||
|
||||
|
||||
@implementation MorphAnalyser
|
||||
|
||||
- (instancetype)initWithPgf:(PgfPGF *)pgf err:(GuExn *)err to:(Grammar *)to from:(Grammar *)from {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_pgf = pgf;
|
||||
_err = err;
|
||||
_to = to;
|
||||
_from = from;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)bestTranslation {
|
||||
if (self.analysedWords.count) {
|
||||
for (NSString *translation in self.analysedWords) {
|
||||
if (![[translation stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] hasSuffix:@"."]) {
|
||||
return [[translation componentsSeparatedByString:@" "].lastObject stringByAppendingString:@" "];
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)analysWord:(NSString *)word {
|
||||
|
||||
morphWords = [NSMutableArray new];
|
||||
htmls = [NSMutableArray new];
|
||||
|
||||
PgfLinLemmasCallback callback = { { print_lemma }, self.pgf, self.from.concrete, self.to.concrete };
|
||||
pgf_lookup_morpho(self.from.concrete, [word UTF8String], &callback.callback, self.err);
|
||||
|
||||
_analysedWords = morphWords;
|
||||
_html = htmls;
|
||||
|
||||
htmls = nil;
|
||||
morphWords = nil;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// NSString+stringToArray.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-03.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSString (StringToArray)
|
||||
|
||||
- (NSArray *)stringToArray;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NSString+stringToArray.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-03.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+stringToArray.h"
|
||||
|
||||
@implementation NSString (StringToArray)
|
||||
|
||||
- (NSArray *)stringToArray {
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
for (int i = 0; i < [self length]; i++) {
|
||||
NSString *character = [self substringWithRange:NSMakeRange(i, 1)];
|
||||
[array addObject:character];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Translation.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-04.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Translation.h"
|
||||
|
||||
|
||||
|
||||
@interface PhraseTranslation : Translation
|
||||
|
||||
@property (nonatomic, strong) NSArray *sequences;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Translation.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-04.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "PhraseTranslation.h"
|
||||
#import "UIColor+TranslationsResults.h"
|
||||
|
||||
|
||||
|
||||
@implementation PhraseTranslation
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// SLKTextView+TextInputMode.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-05.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SLKTextView.h"
|
||||
|
||||
@interface SLKTextView (TextInputMode)
|
||||
|
||||
@property (nonatomic,retain) NSString *userDefinedKeyboardLanguage;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// SLKTextView+TextInputMode.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-05.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SLKTextView+TextInputMode.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation SLKTextView (TextInputMode)
|
||||
|
||||
static char userDefinedKeyboardLanguageKey;
|
||||
|
||||
- (NSString *)userDefinedKeyboardLanguage {
|
||||
return objc_getAssociatedObject(self, &userDefinedKeyboardLanguageKey);
|
||||
}
|
||||
|
||||
- (void)setUserDefinedKeyboardLanguage:(NSString *)aString {
|
||||
objc_setAssociatedObject(self, &userDefinedKeyboardLanguageKey, aString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (UITextInputMode *) textInputMode {
|
||||
for (UITextInputMode *tim in [UITextInputMode activeInputModes]) {
|
||||
if ([[SLKTextView langFromLocale:self.userDefinedKeyboardLanguage] isEqualToString:[SLKTextView langFromLocale:tim.primaryLanguage]]) {
|
||||
return tim;
|
||||
}
|
||||
}
|
||||
return [super textInputMode];
|
||||
}
|
||||
|
||||
+ (NSString *)langFromLocale:(NSString *)locale {
|
||||
NSRange rangeOne = [locale rangeOfString:@"_"];
|
||||
if (rangeOne.length == 0)
|
||||
rangeOne.location = locale.length;
|
||||
|
||||
NSRange rangeTwo = [locale rangeOfString:@"-"];
|
||||
if (rangeTwo.length == 0)
|
||||
rangeTwo.location = locale.length;
|
||||
|
||||
return [[locale substringToIndex:MIN(rangeOne.location, rangeTwo.location)] lowercaseString];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// SentenceTranslationUITableViewCell.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-18.
|
||||
// Copyright © 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
@interface SentenceTranslationUITableViewCell : UITableViewCell
|
||||
|
||||
- (void)configureCellWithSentenceInTableView:(UITableView *)tableView withTranslation:(NSString *)translation andTree:(NSString *)tree;
|
||||
@end
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// SentenceTranslationUITableViewCell.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-18.
|
||||
// Copyright © 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SentenceTranslationUITableViewCell.h"
|
||||
#import "PhraseTranslation.h"
|
||||
|
||||
@interface SentenceTranslationUITableViewCell ()
|
||||
@property (weak, nonatomic) IBOutlet UILabel *translationSentance;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *translationTree;
|
||||
|
||||
@property (weak, nonatomic) UITableView *tableView;
|
||||
|
||||
@property (strong, nonatomic) NSString *translationTreeText;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SentenceTranslationUITableViewCell
|
||||
|
||||
- (void)configureCellWithSentenceInTableView:(UITableView *)tableView withTranslation:(NSString *)translation andTree:(NSString *)tree {
|
||||
self.tableView = tableView;
|
||||
self.translationSentance.text = translation;
|
||||
self.translationTreeText = tree;
|
||||
|
||||
self.translationTree.text = @"";
|
||||
}
|
||||
- (IBAction)showTree:(id)sender {
|
||||
|
||||
if ([self.translationTree.text isEqualToString:@""]) {
|
||||
self.translationTree.alpha = 0;
|
||||
|
||||
[self.tableView beginUpdates];
|
||||
self.translationTree.text = self.translationTreeText;
|
||||
[self.tableView endUpdates];
|
||||
|
||||
[UIView animateWithDuration:0.25 delay:0.15 options:0 animations:^{
|
||||
self.translationTree.alpha = 1;
|
||||
} completion:nil];
|
||||
|
||||
} else {
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
self.translationTree.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
[self.tableView beginUpdates];
|
||||
self.translationTree.text = @"";
|
||||
[self.tableView endUpdates];
|
||||
}];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// StyleKitGF.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-19.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
// Generated by PaintCode (www.paintcodeapp.com)
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
@interface StyleKitGF : NSObject
|
||||
|
||||
// Drawing Methods
|
||||
+ (void)drawArrowsWithFrame: (CGRect)frame;
|
||||
+ (void)drawMenyItemWithFrame: (CGRect)frame;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// StyleKitGF.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-19.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
// Generated by PaintCode (www.paintcodeapp.com)
|
||||
//
|
||||
|
||||
#import "StyleKitGF.h"
|
||||
|
||||
|
||||
@implementation StyleKitGF
|
||||
|
||||
#pragma mark Initialization
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark Drawing Methods
|
||||
|
||||
+ (void)drawArrowsWithFrame: (CGRect)frame
|
||||
{
|
||||
//// Color Declarations
|
||||
UIColor* color = [UIColor colorWithRed: 0 green: 0.478 blue: 1 alpha: 1];
|
||||
|
||||
//// Bezier Drawing
|
||||
UIBezierPath* bezierPath = UIBezierPath.bezierPath;
|
||||
[bezierPath moveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77855 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.53483 * CGRectGetHeight(frame))];
|
||||
[bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.31140 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.53483 * CGRectGetHeight(frame))];
|
||||
[bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.31140 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.45788 * CGRectGetHeight(frame))];
|
||||
[bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77855 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.45788 * CGRectGetHeight(frame))];
|
||||
[bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77855 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.53483 * CGRectGetHeight(frame))];
|
||||
[bezierPath closePath];
|
||||
[bezierPath moveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77855 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.34247 * CGRectGetHeight(frame))];
|
||||
[bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77855 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.64384 * CGRectGetHeight(frame))];
|
||||
[bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.95436 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.50918 * CGRectGetHeight(frame))];
|
||||
[bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.77855 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.34247 * CGRectGetHeight(frame))];
|
||||
[bezierPath closePath];
|
||||
[color setFill];
|
||||
[bezierPath fill];
|
||||
|
||||
|
||||
//// Bezier 2 Drawing
|
||||
UIBezierPath* bezier2Path = UIBezierPath.bezierPath;
|
||||
[bezier2Path moveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.22452 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.53483 * CGRectGetHeight(frame))];
|
||||
[bezier2Path addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.68880 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.53483 * CGRectGetHeight(frame))];
|
||||
[bezier2Path addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.68880 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.45788 * CGRectGetHeight(frame))];
|
||||
[bezier2Path addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.22452 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.45788 * CGRectGetHeight(frame))];
|
||||
[bezier2Path addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.22452 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.53483 * CGRectGetHeight(frame))];
|
||||
[bezier2Path closePath];
|
||||
[bezier2Path moveToPoint: CGPointMake(CGRectGetMinX(frame) + 0.22452 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.34247 * CGRectGetHeight(frame))];
|
||||
[bezier2Path addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.22452 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.64384 * CGRectGetHeight(frame))];
|
||||
[bezier2Path addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.04979 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.50918 * CGRectGetHeight(frame))];
|
||||
[bezier2Path addLineToPoint: CGPointMake(CGRectGetMinX(frame) + 0.22452 * CGRectGetWidth(frame), CGRectGetMinY(frame) + 0.34247 * CGRectGetHeight(frame))];
|
||||
[bezier2Path closePath];
|
||||
[color setFill];
|
||||
[bezier2Path fill];
|
||||
}
|
||||
|
||||
+ (void)drawMenyItemWithFrame: (CGRect)frame
|
||||
{
|
||||
//// Color Declarations
|
||||
UIColor* color = [UIColor colorWithRed: 0 green: 0.478 blue: 1 alpha: 1];
|
||||
|
||||
//// Oval Drawing
|
||||
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(CGRectGetMinX(frame) + 1, CGRectGetMinY(frame) + 3, floor((CGRectGetWidth(frame) - 1) * 0.28037 + 0.5), CGRectGetHeight(frame) - 6)];
|
||||
[color setFill];
|
||||
[ovalPath fill];
|
||||
|
||||
|
||||
//// Oval 2 Drawing
|
||||
UIBezierPath* oval2Path = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(CGRectGetMinX(frame) + floor(CGRectGetWidth(frame) * 0.36111 + 0.5), CGRectGetMinY(frame) + 3, floor(CGRectGetWidth(frame) * 0.63889 + 0.5) - floor(CGRectGetWidth(frame) * 0.36111 + 0.5), CGRectGetHeight(frame) - 6)];
|
||||
[color setFill];
|
||||
[oval2Path fill];
|
||||
|
||||
|
||||
//// Oval 3 Drawing
|
||||
UIBezierPath* oval3Path = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(CGRectGetMinX(frame) + floor((CGRectGetWidth(frame) - 2) * 0.71698 + 0.5), CGRectGetMinY(frame) + 3, CGRectGetWidth(frame) - 2 - floor((CGRectGetWidth(frame) - 2) * 0.71698 + 0.5), CGRectGetHeight(frame) - 6)];
|
||||
[color setFill];
|
||||
[oval3Path fill];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Translation.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-03.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Language;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, TranslationResult) {
|
||||
WorstResult,
|
||||
BestResult,
|
||||
DefaultResult,
|
||||
ParseByChunksResult,
|
||||
InputSentence
|
||||
};
|
||||
|
||||
@interface Translation : NSObject
|
||||
|
||||
@property (nonatomic) NSString *fromText;
|
||||
@property (nonatomic) NSString *toText;
|
||||
@property (nonatomic) NSArray *toTexts;
|
||||
@property (nonatomic) Language *fromLanguage;
|
||||
@property (nonatomic) Language *toLanguage;
|
||||
@property (nonatomic) TranslationResult result;
|
||||
|
||||
+ (instancetype)translationWithText:(NSString *)fromText
|
||||
toText:(NSString *)toText
|
||||
fromLanguage:(Language *)fromLanguage
|
||||
toLanguage:(Language *)toLanguage;
|
||||
- (void)speak;
|
||||
@end
|
||||
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// Translation.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-03.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Translation.h"
|
||||
#import "Language.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
|
||||
@implementation Translation
|
||||
|
||||
@synthesize toTexts = _toTexts;
|
||||
|
||||
+ (instancetype)translationWithText:(NSString *)fromText
|
||||
toText:(NSString *)toText
|
||||
fromLanguage:(Language *)fromLanguage
|
||||
toLanguage:(Language *)toLanguage {
|
||||
Translation *translation = [self new];
|
||||
|
||||
translation.result = [Translation resultForText:toText];
|
||||
|
||||
translation.toText = [Translation formatTranslation:toText];
|
||||
translation.fromText = fromText;
|
||||
|
||||
translation.fromLanguage = fromLanguage;
|
||||
translation.toLanguage = toLanguage;
|
||||
|
||||
return translation;
|
||||
}
|
||||
|
||||
+ (TranslationResult)resultForText:(NSString *)text {
|
||||
|
||||
NSString *firstChar = [text substringToIndex:1];
|
||||
|
||||
if (text.length == 0) {
|
||||
return DefaultResult;
|
||||
}
|
||||
|
||||
if ([firstChar isEqualToString:@"%"] ||
|
||||
[text rangeOfString:@"parse error:"].location != NSNotFound ||
|
||||
[text rangeOfString:@"["].location != NSNotFound) {
|
||||
return WorstResult;
|
||||
}
|
||||
|
||||
if ([firstChar isEqualToString:@"*"]) {
|
||||
return ParseByChunksResult;
|
||||
}
|
||||
|
||||
if ([firstChar isEqualToString:@"+"]) {
|
||||
return BestResult;
|
||||
}
|
||||
|
||||
return DefaultResult;
|
||||
}
|
||||
|
||||
+ (NSString *)formatTranslation:(NSString *)text {
|
||||
|
||||
if (text.length == 0) {
|
||||
return text;
|
||||
}
|
||||
|
||||
NSCharacterSet *charsToRemove = [NSCharacterSet characterSetWithCharactersInString:@"+*% "];
|
||||
NSString *trimmedText = [text stringByTrimmingCharactersInSet:charsToRemove];
|
||||
|
||||
for (NSString *charToRemove in @[@"[", @"]", @"_"]) {
|
||||
trimmedText =[trimmedText stringByReplacingOccurrencesOfString:charToRemove withString:@" "];
|
||||
}
|
||||
|
||||
return trimmedText;
|
||||
}
|
||||
|
||||
- (void)speak {
|
||||
AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:self.toText];
|
||||
utterance.rate = AVSpeechUtteranceMinimumSpeechRate;
|
||||
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:self.toLanguage.bcp];
|
||||
|
||||
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];
|
||||
[synthesizer speakUtterance:utterance];
|
||||
}
|
||||
|
||||
#pragma mark - Setters & getters
|
||||
|
||||
- (NSString *)toText {
|
||||
if (!_toText) {
|
||||
return _fromText;
|
||||
}
|
||||
return _toText;
|
||||
}
|
||||
|
||||
- (NSArray *)toTexts {
|
||||
if (nil) {
|
||||
return @[_fromText];
|
||||
}
|
||||
return _toTexts;
|
||||
}
|
||||
|
||||
- (void)setToTexts:(NSArray *)toTexts {
|
||||
NSMutableArray *formatedTexts = [NSMutableArray new];
|
||||
for (NSString *text in toTexts) {
|
||||
[formatedTexts addObject:[Translation formatTranslation:text]];
|
||||
}
|
||||
_toTexts = formatedTexts.copy;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="TranslationInput" id="UIw-HO-3Uj" customClass="TranslationTextTableViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="UIw-HO-3Uj" id="7tu-Bs-CSE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7To-y6-ppO">
|
||||
<rect key="frame" x="9" y="2" width="58" height="39"/>
|
||||
<color key="backgroundColor" red="0.30855830201242807" green="0.77903700374603524" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="249" verticalCompressionResistancePriority="751" misplaced="YES" text="Label" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="adT-pY-vJo">
|
||||
<rect key="frame" x="18" y="8" width="40" height="27"/>
|
||||
<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>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="7To-y6-ppO" firstAttribute="leading" secondItem="7tu-Bs-CSE" secondAttribute="leading" id="5hM-ra-fKy"/>
|
||||
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="adT-pY-vJo" secondAttribute="trailing" constant="25" id="69O-6f-UoR"/>
|
||||
<constraint firstItem="adT-pY-vJo" firstAttribute="leading" secondItem="7tu-Bs-CSE" secondAttribute="leadingMargin" id="9Vd-9J-Rlw"/>
|
||||
<constraint firstItem="adT-pY-vJo" firstAttribute="leading" secondItem="7tu-Bs-CSE" secondAttribute="leadingMargin" constant="10" id="IkA-0z-tjq"/>
|
||||
<constraint firstItem="7To-y6-ppO" firstAttribute="trailing" secondItem="adT-pY-vJo" secondAttribute="trailing" id="NvK-qx-qu9"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="adT-pY-vJo" secondAttribute="bottom" id="OoV-Kh-Bco"/>
|
||||
<constraint firstItem="adT-pY-vJo" firstAttribute="top" secondItem="7tu-Bs-CSE" secondAttribute="topMargin" id="WIB-Kb-Qc8"/>
|
||||
<constraint firstItem="7To-y6-ppO" firstAttribute="trailing" secondItem="adT-pY-vJo" secondAttribute="trailing" constant="9" id="fs7-hl-Qh7"/>
|
||||
<constraint firstAttribute="trailing" secondItem="7To-y6-ppO" secondAttribute="trailing" id="kaU-fi-tBu"/>
|
||||
<constraint firstAttribute="bottom" secondItem="7To-y6-ppO" secondAttribute="bottom" constant="2" id="lcW-9e-wSN"/>
|
||||
<constraint firstItem="7To-y6-ppO" firstAttribute="leading" secondItem="adT-pY-vJo" secondAttribute="leading" constant="-9" id="oN5-mX-1Gl"/>
|
||||
<constraint firstItem="7To-y6-ppO" firstAttribute="top" secondItem="7tu-Bs-CSE" secondAttribute="top" constant="2" id="voa-C4-ldW"/>
|
||||
</constraints>
|
||||
<variation key="default">
|
||||
<mask key="constraints">
|
||||
<exclude reference="5hM-ra-fKy"/>
|
||||
<exclude reference="NvK-qx-qu9"/>
|
||||
<exclude reference="kaU-fi-tBu"/>
|
||||
<exclude reference="9Vd-9J-Rlw"/>
|
||||
</mask>
|
||||
</variation>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="decorationView" destination="7To-y6-ppO" id="yF5-JS-aJv"/>
|
||||
<outlet property="translationTextLabel" destination="adT-pY-vJo" id="Yma-rH-iaF"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="678" y="412"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// TranslationOptionsViewController.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-11.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class Translation;
|
||||
|
||||
@interface TranslationOptionsViewController : UITableViewController
|
||||
@property (nonatomic) Translation *translation;
|
||||
@end
|
||||
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// TranslationOptionsViewController.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-11.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TranslationOptionsViewController.h"
|
||||
#import "PhraseTranslation.h"
|
||||
#import "WordTranslation.h"
|
||||
#import "WebViewController.h"
|
||||
#import "SentenceTranslationUITableViewCell.h"
|
||||
|
||||
@implementation TranslationOptionsViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
self.tableView.estimatedRowHeight = 19;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.translation.toTexts.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
|
||||
if ([self.translation isMemberOfClass:[WordTranslation class]]) {
|
||||
|
||||
NSString *identifier = @"Basic";
|
||||
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
|
||||
|
||||
WordTranslation *translation = (WordTranslation *)self.translation;
|
||||
NSString *html = translation.html[indexPath.row];
|
||||
|
||||
cell.textLabel.text = translation.toTexts[indexPath.row];
|
||||
|
||||
if (html.length > 0) {
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
} else {
|
||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
}
|
||||
|
||||
return cell;
|
||||
} else if ([self.translation isMemberOfClass:[PhraseTranslation class]]) {
|
||||
|
||||
NSString *identifier = @"Cell";
|
||||
|
||||
SentenceTranslationUITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
|
||||
|
||||
PhraseTranslation *translation = (PhraseTranslation *)self.translation;
|
||||
|
||||
[cell configureCellWithSentenceInTableView:tableView
|
||||
withTranslation:translation.toTexts[indexPath.row]
|
||||
andTree:translation.sequences[indexPath.row]];
|
||||
return cell;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
if ([self.translation isMemberOfClass:[WordTranslation class]]) {
|
||||
WordTranslation *translation = (WordTranslation *)self.translation;
|
||||
NSString *html = translation.html[indexPath.row];
|
||||
|
||||
if (html.length > 0) {
|
||||
[self performSegueWithIdentifier:@"WebView" sender:indexPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Navigation
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
[super prepareForSegue:segue sender:sender];
|
||||
|
||||
// WebView
|
||||
if ([sender isKindOfClass:[NSIndexPath class]] &&
|
||||
[self.translation isMemberOfClass:[WordTranslation class]]) {
|
||||
|
||||
WordTranslation *translation = (WordTranslation *)self.translation;
|
||||
NSIndexPath *indexPath = (NSIndexPath *)sender;
|
||||
|
||||
WebViewController *webVC = segue.destinationViewController;
|
||||
webVC.title = translation.toText;
|
||||
webVC.htmlToRender = translation.html[indexPath.row];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="TranslationOutput" id="KGk-i7-Jjw" customClass="TranslationTextTableViewCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="X0L-SM-Oy6">
|
||||
<rect key="frame" x="251" y="2" width="61" height="39"/>
|
||||
<color key="backgroundColor" red="1" green="0.26915805189999997" blue="0.054802574200000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="249" verticalCompressionResistancePriority="751" text="Label" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uQa-0I-JXG">
|
||||
<rect key="frame" x="261" y="8" width="42" height="27"/>
|
||||
<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>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="uQa-0I-JXG" firstAttribute="bottom" secondItem="H2p-sc-9uM" secondAttribute="bottomMargin" id="0kp-2S-9HE"/>
|
||||
<constraint firstItem="uQa-0I-JXG" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="25" id="7tz-W5-sjO"/>
|
||||
<constraint firstItem="uQa-0I-JXG" firstAttribute="leading" secondItem="X0L-SM-Oy6" secondAttribute="leading" constant="10" id="PeL-5E-g6c"/>
|
||||
<constraint firstItem="X0L-SM-Oy6" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="2" id="Y0H-g2-j15"/>
|
||||
<constraint firstItem="uQa-0I-JXG" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="aF2-US-9FV"/>
|
||||
<constraint firstItem="uQa-0I-JXG" firstAttribute="trailing" secondItem="X0L-SM-Oy6" secondAttribute="trailing" constant="-9" id="iCN-4t-n07"/>
|
||||
<constraint firstAttribute="bottom" secondItem="X0L-SM-Oy6" secondAttribute="bottom" constant="2" id="uf5-yE-V0h"/>
|
||||
<constraint firstItem="uQa-0I-JXG" firstAttribute="trailing" secondItem="H2p-sc-9uM" secondAttribute="trailingMargin" constant="-9" id="vz1-Ju-XEr"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="decorationView" destination="X0L-SM-Oy6" id="hyg-YB-kiu"/>
|
||||
<outlet property="translationTextLabel" destination="uQa-0I-JXG" id="E0m-m4-PbH"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TranslationInputTableViewCell.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class PhraseTranslation;
|
||||
|
||||
@interface TranslationTextTableViewCell : UITableViewCell
|
||||
|
||||
|
||||
- (void)setCellWithLanguage:(PhraseTranslation *)translation fromLanguage:(BOOL)fromLanguage;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// TranslationInputTableViewCell.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TranslationTextTableViewCell.h"
|
||||
#import "PhraseTranslation.h"
|
||||
#import "Language.h"
|
||||
#import "UIColor+TranslationsResults.h"
|
||||
|
||||
@interface TranslationTextTableViewCell ()
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UILabel *translationTextLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *flagImageView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *decorationView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TranslationTextTableViewCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
self.decorationView.layer.cornerRadius = 5;
|
||||
self.decorationView.layer.masksToBounds = YES;
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
||||
[super setSelected:selected animated:animated];
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
- (void)setCellWithLanguage:(PhraseTranslation *)translation fromLanguage:(BOOL)fromLanguage {
|
||||
|
||||
Language *language = fromLanguage ? translation.fromLanguage : translation.toLanguage;
|
||||
NSString *text = fromLanguage ? translation.fromText : translation.toText;
|
||||
|
||||
NSString *imageName = language.abbreviation;
|
||||
[self.flagImageView setImage:[UIImage imageNamed:imageName]];
|
||||
self.translationTextLabel.text = text;
|
||||
TranslationResult resultColor = fromLanguage ? InputSentence : translation.result;
|
||||
self.decorationView.backgroundColor = [UIColor colorForResult: resultColor];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// TranslationTextViewController.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SLKTextViewController.h"
|
||||
@class Language;
|
||||
|
||||
@protocol TranslationTextViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)changeLanguageToLanguage:(Language *)laguange isFrom:(BOOL)isFrom;
|
||||
|
||||
@end
|
||||
|
||||
@interface TranslationTextViewController : SLKTextViewController <TranslationTextViewControllerDelegate>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,307 @@
|
||||
//
|
||||
// TranslationTextViewController.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TranslationTextViewController.h"
|
||||
|
||||
// Models
|
||||
#import "Translator.h"
|
||||
#import "Grammar.h"
|
||||
#import "Language.h"
|
||||
#import "PhraseTranslation.h"
|
||||
#import "MorphAnalyser.h"
|
||||
#import "TranslatorStore.h"
|
||||
#import "NSString+StringToArray.h"
|
||||
|
||||
// Views
|
||||
#import "TranslationTextTableViewCell.h"
|
||||
#import "ArrowsButton.h"
|
||||
#import "MenuView.h"
|
||||
#import "SLKTextView+TextInputMode.h"
|
||||
|
||||
// Grammatical framework
|
||||
#import "pgf/pgf.h"
|
||||
#import "gu/mem.h"
|
||||
#import "gu/exn.h"
|
||||
#import "gu/file.h"
|
||||
|
||||
// View controllers
|
||||
#import "LanguagesViewController.h"
|
||||
#import "TranslationOptionsViewController.h"
|
||||
#import "WebViewController.h"
|
||||
|
||||
@interface TranslationTextViewController ()
|
||||
|
||||
@property (nonatomic) Translator *translator;
|
||||
@property (nonatomic, strong) NSMutableArray *inputs;
|
||||
@property (nonatomic) BOOL isLoadingGrammar;
|
||||
@property (nonatomic) UIBarButtonItem *leftLanguageButton;
|
||||
@property (nonatomic) UIBarButtonItem *rightLanguageButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TranslationTextViewController
|
||||
|
||||
#pragma mark - Getters & setters
|
||||
|
||||
- (NSMutableArray *)inputs {
|
||||
if (!_inputs) {
|
||||
_inputs = [NSMutableArray new];
|
||||
}
|
||||
return _inputs;
|
||||
}
|
||||
|
||||
- (void)setIsLoadingGrammar:(BOOL)isLoadingGrammar {
|
||||
_isLoadingGrammar = isLoadingGrammar;
|
||||
|
||||
self.leftLanguageButton.enabled = !isLoadingGrammar;
|
||||
self.rightLanguageButton.enabled = !isLoadingGrammar;
|
||||
}
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
+ (UITableViewStyle)tableViewStyleForCoder:(NSCoder *)decoder {
|
||||
return (UITableViewStyleGrouped);
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Setup keyboard
|
||||
self.textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
[self.textInputbar.rightButton setTitle:@"Translate" forState:UIControlStateNormal];
|
||||
[self.singleTapGesture addTarget:self action:@selector(didTapTableView:)];
|
||||
|
||||
// Register cells
|
||||
UINib *nib = [UINib nibWithNibName:@"TranslationInputTableViewCell" bundle:nil];
|
||||
[[self tableView] registerNib:nib forCellReuseIdentifier:@"TranslationInput"];
|
||||
|
||||
nib = [UINib nibWithNibName:@"TranslationOutputTableViewCell" bundle:nil];
|
||||
[[self tableView] registerNib:nib forCellReuseIdentifier:@"TranslationOutput"];
|
||||
|
||||
// Setup table view
|
||||
self.tableView.estimatedRowHeight = 89;
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
self.tableView.allowsSelection = YES;
|
||||
self.inverted = NO;
|
||||
|
||||
// Setup buttons
|
||||
ArrowsButton *arrows = [[ArrowsButton alloc] initWithFrame:CGRectMake(0, 0, 50, 30)];
|
||||
[arrows addTarget:self action:@selector(switchLanguage:) forControlEvents:UIControlEventTouchUpInside];
|
||||
arrows.backgroundColor = [UIColor clearColor];
|
||||
UIBarButtonItem *arrowsButton = [[UIBarButtonItem alloc] initWithCustomView:arrows];
|
||||
|
||||
self.leftLanguageButton = [[UIBarButtonItem alloc] initWithTitle:@"Loading"
|
||||
style:(UIBarButtonItemStylePlain)
|
||||
target:self
|
||||
action:@selector(changeLanguage:)];
|
||||
self.rightLanguageButton = [[UIBarButtonItem alloc] initWithTitle:@"Loading"
|
||||
style:(UIBarButtonItemStylePlain)
|
||||
target:self
|
||||
action:@selector(changeLanguage:)];
|
||||
|
||||
self.navigationItem.leftBarButtonItems = @[self.leftLanguageButton, arrowsButton, self.rightLanguageButton];
|
||||
|
||||
// Load grammars
|
||||
self.isLoadingGrammar = YES;
|
||||
|
||||
[TranslatorStore loadTranslatorWithCompletion:^(Translator *translator) {
|
||||
self.translator = translator;
|
||||
|
||||
self.isLoadingGrammar = NO;
|
||||
[self updateButtonTitles];
|
||||
[self textDidUpdate:YES];
|
||||
self.textView.userDefinedKeyboardLanguage = self.translator.from.language.bcp;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
self.textView.userDefinedKeyboardLanguage = self.translator.from.language.bcp;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Navigation
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
[super prepareForSegue:segue sender:sender];
|
||||
|
||||
if ([segue.identifier isEqualToString:@"ChangeLanguage"]) {
|
||||
UINavigationController *navigationController = segue.destinationViewController;
|
||||
|
||||
LanguagesViewController *destinattionController = (LanguagesViewController *)navigationController.topViewController;
|
||||
BOOL fromLanguage = sender == self.leftLanguageButton;
|
||||
|
||||
destinattionController.currentLanguages = @[self.translator.from.language, self.translator.to.language];
|
||||
destinattionController.fromLanguage = fromLanguage;
|
||||
destinattionController.delegate = self;
|
||||
} else if ([segue.identifier isEqualToString:@"TranslationOptions"]) {
|
||||
TranslationOptionsViewController *destinattionController = segue.destinationViewController;
|
||||
destinattionController.title = ((Translation *)sender).fromText;
|
||||
destinattionController.translation = sender;
|
||||
} else if ([segue.identifier isEqualToString:@"Info"]) {
|
||||
WebViewController *destinationController = (WebViewController *)segue.destinationViewController;
|
||||
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:@"help_content" ofType:@"html"];
|
||||
NSString* htmlString = [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
destinationController.htmlToRender = htmlString;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)goToHelp:(id)sender {
|
||||
[self performSegueWithIdentifier:@"helpView" sender:nil];
|
||||
}
|
||||
|
||||
- (void)changeLanguage:(id)sender {
|
||||
[self performSegueWithIdentifier:@"ChangeLanguage" sender:sender];
|
||||
}
|
||||
|
||||
#pragma mark - TranslationTextViewControllerDelegate
|
||||
|
||||
- (void)changeLanguageToLanguage:(Language *)laguange isFrom:(BOOL)isFrom {
|
||||
UIBarButtonItem *button = isFrom ? self.leftLanguageButton : self.rightLanguageButton;
|
||||
button.title = @"loading";
|
||||
|
||||
self.isLoadingGrammar = YES;
|
||||
[self textDidUpdate:YES];
|
||||
|
||||
[self.translator changeLanguageToLanguage:laguange isFrom:isFrom withCompletion:^{
|
||||
[self updateButtonTitles];
|
||||
self.isLoadingGrammar = NO;
|
||||
[self textDidUpdate:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - SLKTextViewController Events
|
||||
|
||||
|
||||
- (BOOL)canPressRightButton {
|
||||
// Asks if the right button can be pressed
|
||||
if (self.isLoadingGrammar) {
|
||||
return NO;
|
||||
}
|
||||
return [super canPressRightButton];
|
||||
}
|
||||
|
||||
- (void)didPressRightButton:(id)sender {
|
||||
|
||||
// Notifies the view controller when the right button's action has been triggered, manually or by using the keyboard return key.
|
||||
// Must call super
|
||||
|
||||
NSString *input = self.textView.text;
|
||||
|
||||
// If chinese add input to chars
|
||||
if ([self.translator.from.language.bcp isEqualToString:@"zh-CN"]) {
|
||||
NSArray *array = [input stringToArray];
|
||||
input = [array componentsJoinedByString:@" "];
|
||||
}
|
||||
|
||||
NSInteger wordsCount = [input componentsSeparatedByString:@" "].count;
|
||||
|
||||
|
||||
dispatch_async(dispatch_queue_create("Load grammars",NULL), ^{
|
||||
Translation *newTranslation = (wordsCount == 1 ? (Translation *)[self.translator analysWord:input] : (Translation *)[self.translator translatePhrase:input]);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.inputs addObject:newTranslation];
|
||||
[self.tableView reloadData];
|
||||
|
||||
[newTranslation speak];
|
||||
|
||||
// [self.tableView slk_scrollToBottomAnimated:YES];
|
||||
//
|
||||
NSIndexPath *bottomIndexPath = [NSIndexPath indexPathForRow:(self.inputs.count*2)-1 inSection:0];
|
||||
[self.tableView scrollToRowAtIndexPath:bottomIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// This little trick validates any pending auto-correction or auto-spelling just after hitting the 'Send' button
|
||||
[self.textView refreshFirstResponder];
|
||||
[super didPressRightButton:sender];
|
||||
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - <UITableViewDataSource>
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.inputs.count*2;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
BOOL input = indexPath.row % 2 == 0;
|
||||
NSString *identifier = input ? @"TranslationInput" : @"TranslationOutput";
|
||||
|
||||
TranslationTextTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
|
||||
|
||||
PhraseTranslation *translation = self.inputs[indexPath.row/2];
|
||||
[cell setCellWithLanguage:translation fromLanguage:input];
|
||||
if (!input && (translation.toTexts.count || translation.sequences.count > 0)) {
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
|
||||
} else {
|
||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - <UITableViewDelegate>
|
||||
|
||||
|
||||
// Uncomment this method to handle the cell selection
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (self.inputs.count == 0) {
|
||||
return;
|
||||
}
|
||||
if ([tableView isEqual:self.tableView] && indexPath.row % 2 == 1) {
|
||||
PhraseTranslation *translation = self.inputs[indexPath.row/2];
|
||||
if (translation.toTexts.count > 0 || translation.sequences.count > 0) {
|
||||
[self performSegueWithIdentifier:@"TranslationOptions" sender:translation];
|
||||
}
|
||||
}
|
||||
if ([tableView isEqual:self.tableView] && indexPath.row % 2 == 0) {
|
||||
PhraseTranslation *translation = self.inputs[indexPath.row/2];
|
||||
self.textInputbar.textView.text = translation.fromText;
|
||||
}
|
||||
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Gesture method
|
||||
|
||||
- (void)didTapTableView:(UIGestureRecognizer *)gesture {
|
||||
if (![self.textView isFirstResponder]) {
|
||||
CGPoint touchLoaction = [gesture locationInView:self.tableView];
|
||||
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:touchLoaction];
|
||||
[self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private helpers
|
||||
|
||||
- (void)updateButtonTitles {
|
||||
self.leftLanguageButton.title = self.translator.from.language.name;
|
||||
self.rightLanguageButton.title = self.translator.to.language.name;
|
||||
}
|
||||
|
||||
- (void)switchLanguage:(id)sender {
|
||||
[TranslatorStore switchLanguage:self.translator];
|
||||
|
||||
[self updateButtonTitles];
|
||||
self.textView.userDefinedKeyboardLanguage = self.translator.from.language.bcp;
|
||||
[self.textView reloadInputViews];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Translator.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Grammitcal framework
|
||||
#import "pgf.h"
|
||||
|
||||
@class Grammar;
|
||||
@class PhraseTranslation;
|
||||
@class WordTranslation;
|
||||
@class Language;
|
||||
|
||||
@interface Translator : NSObject
|
||||
|
||||
@property (nonatomic) PgfPGF *pgf;
|
||||
@property (nonatomic) GuOut *fileOut;
|
||||
@property (nonatomic) GuExn *err;
|
||||
@property (nonatomic) GuPool *pool;
|
||||
|
||||
@property (nonatomic, strong) Grammar *to;
|
||||
@property (nonatomic, strong) Grammar *from;
|
||||
@property (nonatomic, strong) Grammar *previous;
|
||||
|
||||
- (PhraseTranslation *)translatePhrase:(NSString *)phrase;
|
||||
- (WordTranslation *)analysWord:(NSString *)word;
|
||||
- (void)changeLanguageToLanguage:(Language *)language isFrom:(BOOL)isFrom withCompletion:(void (^)(void))completion;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,286 @@
|
||||
//
|
||||
// Translator.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-28.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Translator.h"
|
||||
|
||||
// Model
|
||||
#import "Grammar.h"
|
||||
#import "PhraseTranslation.h"
|
||||
#import "WordTranslation.h"
|
||||
#import "MorphAnalyser.h"
|
||||
#import "Language.h"
|
||||
|
||||
|
||||
// Grammatical Framework
|
||||
#import "pgf/literals.h"
|
||||
#import "pgf/pgf.h"
|
||||
#import "gu/mem.h"
|
||||
#import "gu/exn.h"
|
||||
#import "gu/file.h"
|
||||
|
||||
|
||||
@interface Translator ()
|
||||
|
||||
@property (nonatomic, strong) NSArray *sequences;
|
||||
|
||||
@end
|
||||
|
||||
@implementation Translator
|
||||
|
||||
#pragma mark - inits
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
|
||||
NSBundle *bundle = [NSBundle mainBundle];
|
||||
NSString *path = [bundle pathForResource:@"App" ofType:@"pgf"];
|
||||
|
||||
// Create the pool that is used to allocate everything
|
||||
_pool = gu_new_pool();
|
||||
|
||||
// Create an exception frame that catches all errors.
|
||||
_err = gu_new_exn(_pool);
|
||||
|
||||
// Read the PGF grammar.
|
||||
_pgf = pgf_read([path UTF8String], _pool, _err);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public translation method
|
||||
|
||||
- (NSString *)getSequance:(NSString *)phrase ep:(PgfExprProb *)ep tmpErr:(GuExn *)tmpErr tmpPool:(GuPool *)tmpPool {
|
||||
|
||||
|
||||
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
GuStringBuf* buf = gu_string_buf(tmp_pool);
|
||||
GuOut* outt = gu_string_buf_out(buf);
|
||||
|
||||
|
||||
|
||||
// Write out the abstract syntax tree
|
||||
gu_printf(outt, self.err, "", [phrase UTF8String]);
|
||||
pgf_print_expr(ep->expr, NULL, 0, outt, self.err);
|
||||
gu_putc('\n', outt, self.err);
|
||||
|
||||
// pgf_linearize(self.to.concrete, html_expr, html_out, err);
|
||||
GuString lin = gu_string_buf_freeze(buf, tmp_pool);
|
||||
|
||||
NSString *string = [NSString stringWithUTF8String:lin];
|
||||
NSLog(@"%@", string);
|
||||
|
||||
gu_exn_clear(tmpErr);
|
||||
gu_pool_free(tmp_pool);
|
||||
tmpPool = nil;
|
||||
tmpErr = nil;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
- (PhraseTranslation *)translatePhrase:(NSString *)phrase {
|
||||
|
||||
GuPool *tmpPool = gu_new_pool();
|
||||
GuExn *tmpErr = gu_new_exn(tmpPool);
|
||||
|
||||
PgfExprEnum *parsedExpressions = [self parsePhrase:[phrase stringByAppendingString:@" "] startCat:@"Phr" tmpPool:tmpPool tmpErr:tmpErr];
|
||||
NSArray *translatedText = nil;
|
||||
|
||||
if (parsedExpressions != nil) {
|
||||
translatedText = [self linearizeResult:parsedExpressions tmpPool:tmpPool tmpErr:tmpErr];
|
||||
if (translatedText.count == 0) {
|
||||
translatedText = @[[self translateByLookUp:phrase]];
|
||||
}
|
||||
} else {
|
||||
translatedText = @[[self translateByLookUp:phrase]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
PhraseTranslation *translation = [PhraseTranslation translationWithText:phrase
|
||||
toText:translatedText.firstObject
|
||||
fromLanguage:self.from.language
|
||||
toLanguage:self.to.language];
|
||||
|
||||
translation.toTexts = translatedText;
|
||||
translation.sequences = self.sequences;
|
||||
|
||||
if ([translation.toLanguage.bcp isEqualToString:@"th-TH"] ||
|
||||
[translation.toLanguage.bcp isEqualToString:@"ja-JP"] ||
|
||||
[translation.toLanguage.bcp isEqualToString:@"ca-ES"]) {
|
||||
|
||||
NSMutableArray *trimmedArray = @[].mutableCopy;
|
||||
|
||||
for (NSString *string in translation.toTexts) {
|
||||
NSString *trimmed = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
[trimmedArray addObject:trimmed];
|
||||
}
|
||||
NSString *trimmed = [translation.toText stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
|
||||
translation.toText = trimmed;
|
||||
translation.toTexts = trimmedArray.copy;
|
||||
}
|
||||
|
||||
return translation;
|
||||
}
|
||||
|
||||
- (WordTranslation *)analysWord:(NSString *)word; {
|
||||
|
||||
MorphAnalyser *analyser = [[MorphAnalyser alloc] initWithPgf:self.pgf err:self.err to:self.to from:self.from];
|
||||
[analyser analysWord:word];
|
||||
|
||||
WordTranslation *translation = [WordTranslation translationWithText:word
|
||||
toText:analyser.bestTranslation
|
||||
fromLanguage:self.from.language
|
||||
toLanguage:self.to.language];
|
||||
|
||||
translation.toTexts = analyser.analysedWords;
|
||||
translation.html = analyser.html;
|
||||
|
||||
return translation;
|
||||
}
|
||||
|
||||
#pragma mark - Private helpers
|
||||
|
||||
- (NSString *)translateByLookUp:(NSString *)phrase {
|
||||
NSMutableString *translation = @"%".mutableCopy;
|
||||
NSArray *words = [phrase componentsSeparatedByString:@" "];
|
||||
|
||||
for (NSString *word in words) {
|
||||
NSString *translatedWord = [self translateWord:word];
|
||||
[translation appendString: translatedWord ? [NSString stringWithFormat:@" %@", translatedWord] : [NSString stringWithFormat:@" %@", word]];
|
||||
}
|
||||
return translation.copy;
|
||||
}
|
||||
|
||||
- (NSString *)translateWord:(NSString *)word {
|
||||
GuPool *tmpPool = gu_new_pool();
|
||||
GuExn *tmpErr = gu_new_exn(tmpPool);
|
||||
|
||||
PgfExprEnum *parse = [self parsePhrase:word startCat:@"Chunk" tmpPool:tmpPool tmpErr: tmpErr];
|
||||
NSString *translation = @"";
|
||||
|
||||
if (parse) {
|
||||
NSArray *results = [self linearizeResult:parse tmpPool:tmpPool tmpErr:tmpErr];
|
||||
|
||||
if (results.count) {
|
||||
translation = results.firstObject;
|
||||
} else {
|
||||
translation = [self translateByLookUp:word];
|
||||
}
|
||||
} else {
|
||||
MorphAnalyser *analyser = [[MorphAnalyser alloc] initWithPgf:self.pgf err:self.err to:self.to from:self.from];
|
||||
[analyser analysWord:word];
|
||||
translation = analyser.bestTranslation;
|
||||
}
|
||||
|
||||
// Clear up resources
|
||||
gu_exn_clear(tmpErr);
|
||||
gu_pool_free(tmpPool);
|
||||
tmpPool = nil;
|
||||
tmpErr = nil;
|
||||
|
||||
return translation;
|
||||
}
|
||||
|
||||
- (PgfExprEnum *)parsePhrase:(NSString *)phrase startCat:(NSString *)startCat tmpPool:(GuPool *)tmpPool tmpErr:(GuExn *)tmpErr {
|
||||
|
||||
PgfCallbacksMap* callbacks =
|
||||
pgf_new_callbacks_map(self.from.concrete, tmpPool);
|
||||
pgf_callbacks_map_add_literal(self.from.concrete, callbacks,
|
||||
"PN", &pgf_nerc_literal_callback);
|
||||
|
||||
pgf_callbacks_map_add_literal(self.from.concrete, callbacks,
|
||||
"Symb", &pgf_unknown_literal_callback);
|
||||
|
||||
PgfExprEnum *result = pgf_parse_with_heuristics(self.from.concrete, "Phr", [phrase UTF8String],
|
||||
-1, callbacks,
|
||||
tmpErr, tmpPool, tmpPool);
|
||||
|
||||
|
||||
|
||||
// PgfExprEnum *result = pgf_parse(self.from.concrete, [startCat UTF8String], [phrase UTF8String], tmpErr, tmpPool, tmpPool);
|
||||
return gu_ok(tmpErr) ? result : nil;
|
||||
}
|
||||
|
||||
-(NSArray *)linearizeResult:(PgfExprEnum *)result tmpPool:(GuPool *)tmpPool tmpErr:(GuExn *)tmpErr {
|
||||
|
||||
NSMutableArray *translations = [NSMutableArray new];
|
||||
NSMutableArray *sequences = [NSMutableArray new];
|
||||
|
||||
PgfExprProb *ep;
|
||||
gu_enum_next(result, &ep, tmpPool);
|
||||
|
||||
|
||||
// If null reutrun empty array
|
||||
if (!ep) {
|
||||
return @[];
|
||||
}
|
||||
|
||||
for (int i = 0; i <= 10 && ep != nil; i++) {
|
||||
PgfExprProb parse = ep[0];
|
||||
|
||||
// Get translation
|
||||
GuStringBuf *stringBuff = gu_string_buf(tmpPool);
|
||||
GuOut *tmpOut = gu_string_buf_out(stringBuff);
|
||||
pgf_linearize(self.to.concrete, parse.expr, tmpOut, tmpErr);
|
||||
|
||||
// Get sequence
|
||||
GuString lin = gu_string_buf_freeze(stringBuff, tmpPool);
|
||||
NSString *phrase = [NSString stringWithUTF8String:lin];
|
||||
|
||||
NSString *translated = [NSString stringWithUTF8String:gu_string_buf_freeze(stringBuff, tmpPool)];
|
||||
|
||||
NSInteger resultIndex = [translations indexOfObjectPassingTest:^BOOL(NSString *str, NSUInteger idx, BOOL *stop) {
|
||||
return [str isEqualToString:translated];
|
||||
}];
|
||||
|
||||
if (resultIndex == NSNotFound) {
|
||||
[translations addObject:translated];
|
||||
[sequences addObject:[self getSequance:phrase ep:ep tmpErr:tmpErr tmpPool:tmpPool]];
|
||||
}
|
||||
|
||||
gu_out_flush(tmpOut, tmpErr);
|
||||
tmpOut = nil;
|
||||
|
||||
gu_enum_next(result, &ep, tmpPool);
|
||||
}
|
||||
self.sequences = [sequences copy];
|
||||
|
||||
return [translations copy];
|
||||
}
|
||||
|
||||
- (void)changeLanguageToLanguage:(Language *)language isFrom:(BOOL)isFrom withCompletion:(void (^)(void))completion {
|
||||
|
||||
dispatch_async(dispatch_queue_create("Load grammars",NULL), ^{
|
||||
if ([self.previous.language isEqualToLanguage:language]) {
|
||||
Grammar *temp = isFrom ? self.from : self.to;
|
||||
if (isFrom) {
|
||||
self.from = self.previous;
|
||||
} else {
|
||||
self.to = self.previous;
|
||||
}
|
||||
self.previous = temp;
|
||||
} else {
|
||||
self.previous = isFrom ? self.from : self.to;
|
||||
if (isFrom) {
|
||||
self.from = [Grammar loadGrammarFromLanguage:language withTranslator:self];
|
||||
} else {
|
||||
self.to = [Grammar loadGrammarFromLanguage:language withTranslator:self];
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// TranslatorStore.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-22.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Translator;
|
||||
|
||||
@interface TranslatorStore : NSObject
|
||||
|
||||
/**
|
||||
* Loads a translator with the last saved grammars on a background thread, if can't find anyone it loads defaults grammars wich are
|
||||
* Swedish -> English.
|
||||
*
|
||||
* @param completion A completion block with the loaded grammars
|
||||
*/
|
||||
+ (void)loadTranslatorWithCompletion:(void (^)(Translator *translator))completion;
|
||||
|
||||
/**
|
||||
* Saves the current grammars names to NSUserDefaults.
|
||||
*
|
||||
* @param translator The translator that contains the current grammars.
|
||||
*/
|
||||
+ (void)saveCurrentGrammarsFromTranslator:(Translator *)translator;
|
||||
|
||||
+ (void)switchLanguage:(Translator *)translator;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// TranslatorStore.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-22.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TranslatorStore.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
// Model
|
||||
#import "Translator.h"
|
||||
#import "Language.h"
|
||||
#include "Grammar.h"
|
||||
|
||||
@implementation TranslatorStore
|
||||
|
||||
+ (void)loadTranslatorWithCompletion:(void (^)(Translator *translator))completion {
|
||||
|
||||
// Load grammars strings from NSUserDefaults
|
||||
NSString *fromLanguageString = [[NSUserDefaults standardUserDefaults] stringForKey:@"FromLanguage"];
|
||||
NSString *fromAbbreviationString = [[NSUserDefaults standardUserDefaults] stringForKey:@"FromAbbreviation"];
|
||||
NSString *fromBCPString = [[NSUserDefaults standardUserDefaults] stringForKey:@"FromBCP"];
|
||||
|
||||
NSString *toLanguageString = [[NSUserDefaults standardUserDefaults] stringForKey:@"toLanguage"];
|
||||
NSString *toAbbreviationString = [[NSUserDefaults standardUserDefaults] stringForKey:@"toAbbreviation"];
|
||||
NSString *toBCPString = [[NSUserDefaults standardUserDefaults] stringForKey:@"toBCP"];
|
||||
|
||||
if (!fromLanguageString) {
|
||||
fromLanguageString = @"Swedish";
|
||||
fromAbbreviationString = @"Swe";
|
||||
fromBCPString = @"sv-SE";
|
||||
|
||||
toLanguageString = @"English";
|
||||
toAbbreviationString = @"Eng";
|
||||
toBCPString = @"en-GB";
|
||||
}
|
||||
|
||||
// Setup translator
|
||||
Language *fromLanguage = [[Language alloc] initWithName:fromLanguageString abbreviation:fromAbbreviationString bcp:fromBCPString];
|
||||
Language *toLanguage = [[Language alloc] initWithName:toLanguageString abbreviation:toAbbreviationString bcp:toBCPString];
|
||||
__block Translator *translator = [[Translator alloc] init];
|
||||
|
||||
dispatch_async(dispatch_queue_create("Load grammars",NULL), ^{
|
||||
translator.from = [Grammar loadGrammarFromLanguage:fromLanguage withTranslator:translator];
|
||||
translator.to = [Grammar loadGrammarFromLanguage:toLanguage withTranslator:translator];
|
||||
|
||||
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
|
||||
appDelegate.translator = translator;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(translator);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)saveCurrentGrammarsFromTranslator:(Translator *)translator {
|
||||
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:translator.from.language.name forKey:@"FromLanguage"];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:translator.from.language.abbreviation forKey:@"FromAbbreviation"];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:translator.from.language.bcp forKey:@"FromBCP"];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:translator.to.language.name forKey:@"toLanguage"];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:translator.to.language.abbreviation forKey:@"toAbbreviation"];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:translator.to.language.bcp forKey:@"toBCP"];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
+ (void)switchLanguage:(Translator *)translator {
|
||||
|
||||
Grammar *temp = translator.from;
|
||||
translator.from = translator.to;
|
||||
translator.to = temp;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// UIColor+TranslationsResults.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-04.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "PhraseTranslation.h"
|
||||
|
||||
@interface UIColor (TranslationsResults)
|
||||
|
||||
+ (UIColor *)colorForResult:(TranslationResult)result;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// UIColor+TranslationsResults.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-04.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIColor+TranslationsResults.h"
|
||||
|
||||
@implementation UIColor (TranslationsResults)
|
||||
|
||||
+ (UIColor *)colorFromHexString:(NSString *)hexString {
|
||||
unsigned rgbValue = 0;
|
||||
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
||||
[scanner setScanLocation:1]; // bypass '#' character
|
||||
[scanner scanHexInt:&rgbValue];
|
||||
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
|
||||
}
|
||||
|
||||
+ (UIColor *)colorForResult:(TranslationResult)result {
|
||||
switch (result) {
|
||||
case BestResult:
|
||||
return [UIColor bestResultColor];
|
||||
case WorstResult:
|
||||
return [UIColor worstResultColor];
|
||||
case ParseByChunksResult:
|
||||
return [UIColor parseByChunksResultColor];
|
||||
case InputSentence:
|
||||
return [UIColor inputSentenceColor];
|
||||
default:
|
||||
return [UIColor defaultResultColor];
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIColor *)worstResultColor {
|
||||
return [UIColor colorFromHexString:@"#FF303e"];
|
||||
}
|
||||
|
||||
+ (UIColor *)defaultResultColor {
|
||||
return [UIColor colorFromHexString:@"#FFFF99"];
|
||||
}
|
||||
|
||||
|
||||
+ (UIColor *)parseByChunksResultColor {
|
||||
return [UIColor colorFromHexString:@"#FFB2A5"];
|
||||
}
|
||||
|
||||
+ (UIColor *)bestResultColor {
|
||||
return [UIColor colorFromHexString:@"#75CD75"];
|
||||
}
|
||||
|
||||
+ (UIColor *)inputSentenceColor {
|
||||
return [UIColor colorFromHexString:@"#CDCDED"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// UITableViewCell+Customize.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-11.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UITableViewCell (Customize)
|
||||
|
||||
- (void)sizeImageViewToSize:(CGSize)size;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// UITableViewCell+Customize.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-11.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UITableViewCell+Customize.h"
|
||||
|
||||
@implementation UITableViewCell (Customize)
|
||||
|
||||
- (void)sizeImageViewToSize:(CGSize)size {
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
|
||||
CGRect imageRect = CGRectMake(0.0, 0.0, size.width, size.height);
|
||||
[self.imageView.image drawInRect:imageRect];
|
||||
self.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// WebViewController.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-25.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface WebViewController : UIViewController
|
||||
@property (nonatomic, strong) NSString *htmlToRender;
|
||||
@end
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// WebViewController.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-05-25.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WebViewController.h"
|
||||
#import "MorphAnalyser.h"
|
||||
|
||||
|
||||
@interface WebViewController ()
|
||||
@property (weak, nonatomic) IBOutlet UIWebView *webView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation WebViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self.webView loadHTMLString:self.htmlToRender baseURL:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// WordTranslation.h
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-03.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Translation.h"
|
||||
|
||||
|
||||
@interface WordTranslation : Translation
|
||||
|
||||
@property (nonatomic, strong) NSArray *html;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// WordTranslation.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-06-03.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import "WordTranslation.h"
|
||||
|
||||
@implementation WordTranslation
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,131 @@
|
||||
<html>
|
||||
<body>
|
||||
</p>
|
||||
<b>GF Offline Translator</b>:
|
||||
text and speech translation for 14 languages with
|
||||
quality control
|
||||
</p>
|
||||
<p>
|
||||
<b>Speech input </b>: Tap microphone icon if available on the keyboard.
|
||||
<br>
|
||||
<b>Text input </b>: Select the text box at the bottom on the screen.
|
||||
<br>
|
||||
<b>Correction </b>: Tap input text to copy it to the text box.
|
||||
<br>
|
||||
<b>Alternatives </b>: Tap output text.
|
||||
<br>
|
||||
<b>Grammar info </b>: Tap any of the alternatives.
|
||||
<br>
|
||||
<b>Confidence </b>: colour of output text
|
||||
<ul>
|
||||
<li> <span style="background-color:palegreen">Green </span>: semantic, probably correct (but has alternatives) </li>
|
||||
<li> <span style="background-color:yellow">Yellow </span>: syntactic, often incorrect (has alternatives) </li>
|
||||
<li> <span style="background-color:pink">Light red </span>: chunk-based, probably incorrect (has alternatives) </li>
|
||||
<li> <span style="background-color:red">Dark red </span>: word-based, often very bad </li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>More details</h2>
|
||||
<p>
|
||||
GF Offline Translator is based on grammar and semantics. It is compact in size
|
||||
and gives control on quality. Its technology is inspired by compilers, which are
|
||||
programs that translate computer languages.
|
||||
Most other translators for human language are based on
|
||||
statistics and have less control of quality and are much bigger, so that
|
||||
they require either an internet connection or a huge storage on your phone.
|
||||
</p>
|
||||
The app indicates translation confidence with colours:
|
||||
<ul>
|
||||
<li><b>Green</b>:
|
||||
semantic translation, should be correct.
|
||||
But not necessarily the only correct one.
|
||||
You can tap the output to see alternatives.
|
||||
</li>
|
||||
<li><b>Yellow</b>:
|
||||
syntactic translation, should be grammatically correct.
|
||||
But can be very strange in its interpretation and choice of words.
|
||||
</li>
|
||||
<li><b>Light red</b>:
|
||||
chunk translation, probably incorrect.
|
||||
Builds the translation from small pieces.
|
||||
</li>
|
||||
<li><b>Dark red</b>:
|
||||
word-by-word translation, almost certainly incorrect.
|
||||
Builds the translation word by word.
|
||||
</li>
|
||||
</ul>
|
||||
The green translations come from a tourist phrasebook, which allows
|
||||
you to translate things like "hello" and "how far is the airport from
|
||||
the hotel".
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Translation works between any supported languages, which means 182
|
||||
language pairs in the current version. But different languages are on different levels of development.
|
||||
The following table gives a rough idea of what to expect:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<center>
|
||||
<table rules=all border=yes>
|
||||
<tr> <th></th> <th>coverage</th> <th>quality</th> <th>speed</th></tr>
|
||||
<tr> <th>Bulgarian</th> <td bgcolor=yellow></td> <td bgcolor=yellow></td> <td bgcolor=palegreen></td> </tr>
|
||||
<tr> <th>Catalan</th> <td bgcolor=pink></td> <td bgcolor=yellow></td> <td bgcolor=pink></td> </tr>
|
||||
<tr> <th>Chinese</th> <td bgcolor=pink></td> <td bgcolor=pink></td> <td bgcolor=palegreen></td> </tr>
|
||||
<tr> <th>Dutch</th> <td bgcolor=yellow></td> <td bgcolor=yellow></td> <td bgcolor=yellow></td> </tr>
|
||||
<tr> <th>English</th> <td bgcolor=palegreen></td> <td bgcolor=palegreen></td> <td bgcolor=palegreen></td> </tr>
|
||||
<tr> <th>Finnish</th> <td bgcolor=yellow></td> <td bgcolor=yellow></td> <td bgcolor=pink></td> </tr>
|
||||
<tr> <th>French</th> <td bgcolor=pink></td> <td bgcolor=yellow></td> <td bgcolor=pink></td> </tr>
|
||||
<tr> <th>German</th> <td bgcolor=pink></td> <td bgcolor=yellow></td> <td bgcolor=pink></td> </tr>
|
||||
<tr> <th>Hindi</th> <td bgcolor=pink></td> <td bgcolor=red></td> <td bgcolor=yellow></td> </tr>
|
||||
<tr> <th>Italian</th> <td bgcolor=pink></td> <td bgcolor=pink></td> <td bgcolor=pink></td> </tr>
|
||||
<tr> <th>Japanese</th> <td bgcolor=pink></td> <td bgcolor=pink></td> <td bgcolor=yellow></td> </tr>
|
||||
<tr> <th>Spanish</th> <td bgcolor=pink></td> <td bgcolor=yellow></td> <td bgcolor=pink></td> </tr>
|
||||
<tr> <th>Swedish</th> <td bgcolor=yellow></td> <td bgcolor=yellow></td> <td bgcolor=palegreen></td> </tr>
|
||||
<tr> <th>Thai</th> <td bgcolor=pink></td> <td bgcolor=red></td> <td bgcolor=yellow></td> </tr>
|
||||
</table>
|
||||
</center>
|
||||
<br>
|
||||
For <b>Japanse</b> and <b>Thai</b> input, words must be separated with spaces.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When you tap on a translation you get a screen with <b>alternative translations</b>.
|
||||
Tapping on each of the alternatives
|
||||
gives you <b>grammatical information</b>:
|
||||
an inflection table, if it is a single word,
|
||||
and a syntax tree otherwise.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To make it easier to input what you want to translate it is recommended to add that language keyboard in your settings on your iOS device.
|
||||
You can add keyboards from Settings > General > Keyboard > Keyboards.
|
||||
|
||||
If more than one language is added, you can change the language while typing. Follow these steps to change the language of your keyboard once you’ve added it:
|
||||
<li>Tap the globe icon in the lower left corner to choose the next language on your keyboard. The chosen language appears on the Space bar. </li>
|
||||
<li>Touch and hold the globe icon in the lower left to display a menu of enabled keyboards. Drag to choose a new keyboard. </li>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The translation works <b>completely off-line</b>, without
|
||||
internet connection, when doing text-based translation.
|
||||
Speech input needs an connection to work.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The GF Offline Translator is powered by
|
||||
<a href="http://www.grammaticalframework.org/">GF</a>, Grammatical Framework.
|
||||
It is open-source software,
|
||||
built by support from the GF community and from <a href="http://www.digitalgrammars.com/">Digital Grammars</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i>Digital Grammars is a company that can tailor this app to you needs and provide good
|
||||
translation for the kind of vocabulary you need. Just tell us what you want to see
|
||||
in the green area!</i>
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// main.m
|
||||
// GF Offline Translator
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. 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]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// GF_Offline_TranslatorTests.m
|
||||
// GF Offline TranslatorTests
|
||||
//
|
||||
// Created by Cenny Davidsson on 2015-04-27.
|
||||
// Copyright (c) 2015 Grammatical Framework. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface GF_Offline_TranslatorTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation GF_Offline_TranslatorTests
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testExample {
|
||||
// This is an example of a functional test case.
|
||||
XCTAssert(YES, @"Pass");
|
||||
}
|
||||
|
||||
- (void)testPerformanceExample {
|
||||
// This is an example of a performance test case.
|
||||
[self measureBlock:^{
|
||||
// Put the code you want to measure the time of here.
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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>GF.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
5
src/ui/ios/GF-Offline-Translator/Podfile
Normal file
@@ -0,0 +1,5 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, ’8.0’
|
||||
|
||||
pod 'SlackTextViewController'
|
||||
|
||||
10
src/ui/ios/GF-Offline-Translator/Podfile.lock
Normal file
@@ -0,0 +1,10 @@
|
||||
PODS:
|
||||
- SlackTextViewController (1.5.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- SlackTextViewController
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
SlackTextViewController: ab240cda4c7fe1f70f6c6cf64578f3fea495ce99
|
||||
|
||||
COCOAPODS: 0.36.1
|
||||
10
src/ui/ios/GF-Offline-Translator/Pods/Manifest.lock
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
PODS:
|
||||
- SlackTextViewController (1.5.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- SlackTextViewController
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
SlackTextViewController: ab240cda4c7fe1f70f6c6cf64578f3fea495ce99
|
||||
|
||||
COCOAPODS: 0.36.1
|
||||
499
src/ui/ios/GF-Offline-Translator/Pods/Pods.xcodeproj/project.pbxproj
generated
Normal file
@@ -0,0 +1,499 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
07DA840C480DEF98FC6F0E0D /* UIScrollView+SLKAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = F294343CD38A6789868EF3AB /* UIScrollView+SLKAdditions.m */; };
|
||||
16C7AE8DEA0077FB3D896BF0 /* SLKTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 7055B434E17A758334C4D690 /* SLKTextView.h */; };
|
||||
32678D01710471A868EEF0AE /* SLKUIConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 784A38EF52EB47CE5E03AFEA /* SLKUIConstants.h */; };
|
||||
32A92A492370904FDA401B29 /* UIView+SLKAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 201D11D9F140BA666D2ADC73 /* UIView+SLKAdditions.h */; };
|
||||
42927E531994B740240AD1F8 /* SLKTextViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0A7CDEDA02B55960040DCE /* SLKTextViewController.h */; };
|
||||
457D66B4156AA1908749B089 /* SLKInputAccessoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 60EFC05743E457629F6FA3BE /* SLKInputAccessoryView.m */; };
|
||||
5D47E178549F6D3808494181 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B41EF424A850AF9597402D7B /* Foundation.framework */; };
|
||||
5EC3EF97656A41D44CF363B4 /* SLKTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB2A620AECF49DF8EC027EB /* SLKTextView.m */; };
|
||||
63EEAE6BC1F6324007967880 /* UIView+SLKAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = E91CE9439FF285A3B1918133 /* UIView+SLKAdditions.m */; };
|
||||
8276AAEEBBAF4FEE31EEF70A /* SLKTypingIndicatorView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F3B904D76A0932EDC0DDC6C /* SLKTypingIndicatorView.h */; };
|
||||
8F8598074DC5378DE846D9F7 /* SLKTextInputbar.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD2299FFE62AC33DD5F6F21 /* SLKTextInputbar.h */; };
|
||||
A20C8CD4FA62A08EA32FB320 /* Pods-SlackTextViewController-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A33FBE323AB331AA8305AE77 /* Pods-SlackTextViewController-dummy.m */; };
|
||||
A7A374D1CD4744F4774FAD99 /* SLKTextView+SLKAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 2630AA286F47284320CEDD6D /* SLKTextView+SLKAdditions.h */; };
|
||||
A891E95D7B87B4E183738431 /* SLKTypingIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 172242421980D777AB0996D9 /* SLKTypingIndicatorView.m */; };
|
||||
B294EBBAAA27FB04D4FE8DE0 /* Pods-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E8468D560351CE3CFD012400 /* Pods-dummy.m */; };
|
||||
BF4B84A5AA10198C93EF73AB /* SLKTextView+SLKAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E88530B4D45296016366C45 /* SLKTextView+SLKAdditions.m */; };
|
||||
D484455BB70A68645DA6474A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B41EF424A850AF9597402D7B /* Foundation.framework */; };
|
||||
DAB3B22291DFA7F6D080EE66 /* UIResponder+SLKAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ADF674E34301784035DA916 /* UIResponder+SLKAdditions.m */; };
|
||||
E8035C87DFD1E736BE9CCD9A /* SLKInputAccessoryView.h in Headers */ = {isa = PBXBuildFile; fileRef = EAF2276CEA5924314C150535 /* SLKInputAccessoryView.h */; };
|
||||
F1221A6E5E840FB484D12BFD /* UIResponder+SLKAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9827A079F152A80A7F332466 /* UIResponder+SLKAdditions.h */; };
|
||||
F3F121D9C25CBF2C8C5CB6FD /* SLKTextInputbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FF5C109F0F229E7A27AE4D5 /* SLKTextInputbar.m */; };
|
||||
FA0F22AE0A83CE07B10A234A /* SLKTextViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1930DF3ED38A6053FBBC8322 /* SLKTextViewController.m */; };
|
||||
FB64B1B87CE3B6BBF828598E /* UIScrollView+SLKAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = B66AACC28C7F958977E64248 /* UIScrollView+SLKAdditions.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
542E4E1AA94F676B09AEE37B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 8B26729A3C6DF0B6B83B55BB /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = BB9541CC3748C1191DEF8D25;
|
||||
remoteInfo = "Pods-SlackTextViewController";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0E88530B4D45296016366C45 /* SLKTextView+SLKAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "SLKTextView+SLKAdditions.m"; path = "Source/Additions/SLKTextView+SLKAdditions.m"; sourceTree = "<group>"; };
|
||||
15722C6B56D29EE5F9D7B918 /* Pods-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-acknowledgements.markdown"; sourceTree = "<group>"; };
|
||||
172242421980D777AB0996D9 /* SLKTypingIndicatorView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SLKTypingIndicatorView.m; path = Source/Classes/SLKTypingIndicatorView.m; sourceTree = "<group>"; };
|
||||
1930DF3ED38A6053FBBC8322 /* SLKTextViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SLKTextViewController.m; path = Source/Classes/SLKTextViewController.m; sourceTree = "<group>"; };
|
||||
1B88B007510869623C9B933B /* Pods-SlackTextViewController.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SlackTextViewController.xcconfig"; sourceTree = "<group>"; };
|
||||
1F0A7CDEDA02B55960040DCE /* SLKTextViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SLKTextViewController.h; path = Source/Classes/SLKTextViewController.h; sourceTree = "<group>"; };
|
||||
1F3B904D76A0932EDC0DDC6C /* SLKTypingIndicatorView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SLKTypingIndicatorView.h; path = Source/Classes/SLKTypingIndicatorView.h; sourceTree = "<group>"; };
|
||||
201D11D9F140BA666D2ADC73 /* UIView+SLKAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+SLKAdditions.h"; path = "Source/Additions/UIView+SLKAdditions.h"; sourceTree = "<group>"; };
|
||||
2630AA286F47284320CEDD6D /* SLKTextView+SLKAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "SLKTextView+SLKAdditions.h"; path = "Source/Additions/SLKTextView+SLKAdditions.h"; sourceTree = "<group>"; };
|
||||
2ECB69507C18B14A1DD3CE5E /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.debug.xcconfig; sourceTree = "<group>"; };
|
||||
3665C875F733140A55AD452B /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
|
||||
383F6CE99248AAF4C3B60881 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.release.xcconfig; sourceTree = "<group>"; };
|
||||
3ADF674E34301784035DA916 /* UIResponder+SLKAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIResponder+SLKAdditions.m"; path = "Source/Additions/UIResponder+SLKAdditions.m"; sourceTree = "<group>"; };
|
||||
3D3783BDE4D26D1475521002 /* Pods-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-resources.sh"; sourceTree = "<group>"; };
|
||||
4449CD8C2533D423CEE6B594 /* libPods-SlackTextViewController.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SlackTextViewController.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
60EFC05743E457629F6FA3BE /* SLKInputAccessoryView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SLKInputAccessoryView.m; path = Source/Classes/SLKInputAccessoryView.m; sourceTree = "<group>"; };
|
||||
6591BD5CAF7C70A208E5C5DB /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7055B434E17A758334C4D690 /* SLKTextView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SLKTextView.h; path = Source/Classes/SLKTextView.h; sourceTree = "<group>"; };
|
||||
784A38EF52EB47CE5E03AFEA /* SLKUIConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SLKUIConstants.h; path = Source/Additions/SLKUIConstants.h; sourceTree = "<group>"; };
|
||||
9827A079F152A80A7F332466 /* UIResponder+SLKAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIResponder+SLKAdditions.h"; path = "Source/Additions/UIResponder+SLKAdditions.h"; sourceTree = "<group>"; };
|
||||
9C15325AC04364EFC436831E /* Pods-SlackTextViewController-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-SlackTextViewController-prefix.pch"; sourceTree = "<group>"; };
|
||||
9FF5C109F0F229E7A27AE4D5 /* SLKTextInputbar.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SLKTextInputbar.m; path = Source/Classes/SLKTextInputbar.m; sourceTree = "<group>"; };
|
||||
A33FBE323AB331AA8305AE77 /* Pods-SlackTextViewController-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-SlackTextViewController-dummy.m"; sourceTree = "<group>"; };
|
||||
A5535153937D8E4BC12C7188 /* Pods-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-acknowledgements.plist"; sourceTree = "<group>"; };
|
||||
B1C30DBE70E62F5C3FEF4944 /* Pods-SlackTextViewController-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-SlackTextViewController-Private.xcconfig"; sourceTree = "<group>"; };
|
||||
B41EF424A850AF9597402D7B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
|
||||
B66AACC28C7F958977E64248 /* UIScrollView+SLKAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIScrollView+SLKAdditions.h"; path = "Source/Additions/UIScrollView+SLKAdditions.h"; sourceTree = "<group>"; };
|
||||
CDD2299FFE62AC33DD5F6F21 /* SLKTextInputbar.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SLKTextInputbar.h; path = Source/Classes/SLKTextInputbar.h; sourceTree = "<group>"; };
|
||||
E8468D560351CE3CFD012400 /* Pods-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-dummy.m"; sourceTree = "<group>"; };
|
||||
E91CE9439FF285A3B1918133 /* UIView+SLKAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+SLKAdditions.m"; path = "Source/Additions/UIView+SLKAdditions.m"; sourceTree = "<group>"; };
|
||||
EAF2276CEA5924314C150535 /* SLKInputAccessoryView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SLKInputAccessoryView.h; path = Source/Classes/SLKInputAccessoryView.h; sourceTree = "<group>"; };
|
||||
F294343CD38A6789868EF3AB /* UIScrollView+SLKAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIScrollView+SLKAdditions.m"; path = "Source/Additions/UIScrollView+SLKAdditions.m"; sourceTree = "<group>"; };
|
||||
F66D65D2DDA9DCEB56C74350 /* Pods-environment.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-environment.h"; sourceTree = "<group>"; };
|
||||
FAB2A620AECF49DF8EC027EB /* SLKTextView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SLKTextView.m; path = Source/Classes/SLKTextView.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
C4247E842C0701BB7FF50710 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D484455BB70A68645DA6474A /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FBE955E2F286A978C3471329 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5D47E178549F6D3808494181 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
04FBB9A3894582C5C79339A6 /* Support Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1B88B007510869623C9B933B /* Pods-SlackTextViewController.xcconfig */,
|
||||
B1C30DBE70E62F5C3FEF4944 /* Pods-SlackTextViewController-Private.xcconfig */,
|
||||
A33FBE323AB331AA8305AE77 /* Pods-SlackTextViewController-dummy.m */,
|
||||
9C15325AC04364EFC436831E /* Pods-SlackTextViewController-prefix.pch */,
|
||||
);
|
||||
name = "Support Files";
|
||||
path = "../Target Support Files/Pods-SlackTextViewController";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
413C40B15216709EE64D28AF /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
15722C6B56D29EE5F9D7B918 /* Pods-acknowledgements.markdown */,
|
||||
A5535153937D8E4BC12C7188 /* Pods-acknowledgements.plist */,
|
||||
E8468D560351CE3CFD012400 /* Pods-dummy.m */,
|
||||
F66D65D2DDA9DCEB56C74350 /* Pods-environment.h */,
|
||||
3D3783BDE4D26D1475521002 /* Pods-resources.sh */,
|
||||
2ECB69507C18B14A1DD3CE5E /* Pods.debug.xcconfig */,
|
||||
383F6CE99248AAF4C3B60881 /* Pods.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = "Target Support Files/Pods";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
427BECA3398D88D929354AB6 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6591BD5CAF7C70A208E5C5DB /* libPods.a */,
|
||||
4449CD8C2533D423CEE6B594 /* libPods-SlackTextViewController.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7DE09A3B7A1C6B5C8C44A7EF /* Targets Support Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
413C40B15216709EE64D28AF /* Pods */,
|
||||
);
|
||||
name = "Targets Support Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9CFAE8514509E6C3EF2B39B3 /* SlackTextViewController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAF2276CEA5924314C150535 /* SLKInputAccessoryView.h */,
|
||||
60EFC05743E457629F6FA3BE /* SLKInputAccessoryView.m */,
|
||||
CDD2299FFE62AC33DD5F6F21 /* SLKTextInputbar.h */,
|
||||
9FF5C109F0F229E7A27AE4D5 /* SLKTextInputbar.m */,
|
||||
7055B434E17A758334C4D690 /* SLKTextView.h */,
|
||||
FAB2A620AECF49DF8EC027EB /* SLKTextView.m */,
|
||||
2630AA286F47284320CEDD6D /* SLKTextView+SLKAdditions.h */,
|
||||
0E88530B4D45296016366C45 /* SLKTextView+SLKAdditions.m */,
|
||||
1F0A7CDEDA02B55960040DCE /* SLKTextViewController.h */,
|
||||
1930DF3ED38A6053FBBC8322 /* SLKTextViewController.m */,
|
||||
1F3B904D76A0932EDC0DDC6C /* SLKTypingIndicatorView.h */,
|
||||
172242421980D777AB0996D9 /* SLKTypingIndicatorView.m */,
|
||||
784A38EF52EB47CE5E03AFEA /* SLKUIConstants.h */,
|
||||
9827A079F152A80A7F332466 /* UIResponder+SLKAdditions.h */,
|
||||
3ADF674E34301784035DA916 /* UIResponder+SLKAdditions.m */,
|
||||
B66AACC28C7F958977E64248 /* UIScrollView+SLKAdditions.h */,
|
||||
F294343CD38A6789868EF3AB /* UIScrollView+SLKAdditions.m */,
|
||||
201D11D9F140BA666D2ADC73 /* UIView+SLKAdditions.h */,
|
||||
E91CE9439FF285A3B1918133 /* UIView+SLKAdditions.m */,
|
||||
04FBB9A3894582C5C79339A6 /* Support Files */,
|
||||
);
|
||||
path = SlackTextViewController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B0D42594583157D20C51E87F /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F23F1F60BEAD735BCE6E238B /* iOS */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B1E0B2AD9C1688CCAC638A01 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3665C875F733140A55AD452B /* Podfile */,
|
||||
B0D42594583157D20C51E87F /* Frameworks */,
|
||||
D87B3D79ED4806259DDDFEF6 /* Pods */,
|
||||
427BECA3398D88D929354AB6 /* Products */,
|
||||
7DE09A3B7A1C6B5C8C44A7EF /* Targets Support Files */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D87B3D79ED4806259DDDFEF6 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9CFAE8514509E6C3EF2B39B3 /* SlackTextViewController */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F23F1F60BEAD735BCE6E238B /* iOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B41EF424A850AF9597402D7B /* Foundation.framework */,
|
||||
);
|
||||
name = iOS;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
03F7BD4F1B88344408E38DE6 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E8035C87DFD1E736BE9CCD9A /* SLKInputAccessoryView.h in Headers */,
|
||||
8F8598074DC5378DE846D9F7 /* SLKTextInputbar.h in Headers */,
|
||||
A7A374D1CD4744F4774FAD99 /* SLKTextView+SLKAdditions.h in Headers */,
|
||||
16C7AE8DEA0077FB3D896BF0 /* SLKTextView.h in Headers */,
|
||||
42927E531994B740240AD1F8 /* SLKTextViewController.h in Headers */,
|
||||
8276AAEEBBAF4FEE31EEF70A /* SLKTypingIndicatorView.h in Headers */,
|
||||
32678D01710471A868EEF0AE /* SLKUIConstants.h in Headers */,
|
||||
F1221A6E5E840FB484D12BFD /* UIResponder+SLKAdditions.h in Headers */,
|
||||
FB64B1B87CE3B6BBF828598E /* UIScrollView+SLKAdditions.h in Headers */,
|
||||
32A92A492370904FDA401B29 /* UIView+SLKAdditions.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
B54EC4326501540DDBBC9B97 /* Pods */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4B82C4FC01672BAF03F56AB0 /* Build configuration list for PBXNativeTarget "Pods" */;
|
||||
buildPhases = (
|
||||
7DE96EAA3669261071BAD3E4 /* Sources */,
|
||||
FBE955E2F286A978C3471329 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
B75877BB9EA23200B958B82E /* PBXTargetDependency */,
|
||||
);
|
||||
name = Pods;
|
||||
productName = Pods;
|
||||
productReference = 6591BD5CAF7C70A208E5C5DB /* libPods.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
BB9541CC3748C1191DEF8D25 /* Pods-SlackTextViewController */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D7E02682B457EF6A6280F9AE /* Build configuration list for PBXNativeTarget "Pods-SlackTextViewController" */;
|
||||
buildPhases = (
|
||||
2D95483827EDDA158405C5A3 /* Sources */,
|
||||
C4247E842C0701BB7FF50710 /* Frameworks */,
|
||||
03F7BD4F1B88344408E38DE6 /* Headers */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "Pods-SlackTextViewController";
|
||||
productName = "Pods-SlackTextViewController";
|
||||
productReference = 4449CD8C2533D423CEE6B594 /* libPods-SlackTextViewController.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
8B26729A3C6DF0B6B83B55BB /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0510;
|
||||
};
|
||||
buildConfigurationList = 8E9027938227B7173C82EA14 /* Build configuration list for PBXProject "Pods" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = B1E0B2AD9C1688CCAC638A01;
|
||||
productRefGroup = 427BECA3398D88D929354AB6 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
B54EC4326501540DDBBC9B97 /* Pods */,
|
||||
BB9541CC3748C1191DEF8D25 /* Pods-SlackTextViewController */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
2D95483827EDDA158405C5A3 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A20C8CD4FA62A08EA32FB320 /* Pods-SlackTextViewController-dummy.m in Sources */,
|
||||
457D66B4156AA1908749B089 /* SLKInputAccessoryView.m in Sources */,
|
||||
F3F121D9C25CBF2C8C5CB6FD /* SLKTextInputbar.m in Sources */,
|
||||
BF4B84A5AA10198C93EF73AB /* SLKTextView+SLKAdditions.m in Sources */,
|
||||
5EC3EF97656A41D44CF363B4 /* SLKTextView.m in Sources */,
|
||||
FA0F22AE0A83CE07B10A234A /* SLKTextViewController.m in Sources */,
|
||||
A891E95D7B87B4E183738431 /* SLKTypingIndicatorView.m in Sources */,
|
||||
DAB3B22291DFA7F6D080EE66 /* UIResponder+SLKAdditions.m in Sources */,
|
||||
07DA840C480DEF98FC6F0E0D /* UIScrollView+SLKAdditions.m in Sources */,
|
||||
63EEAE6BC1F6324007967880 /* UIView+SLKAdditions.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
7DE96EAA3669261071BAD3E4 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B294EBBAAA27FB04D4FE8DE0 /* Pods-dummy.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
B75877BB9EA23200B958B82E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = "Pods-SlackTextViewController";
|
||||
target = BB9541CC3748C1191DEF8D25 /* Pods-SlackTextViewController */;
|
||||
targetProxy = 542E4E1AA94F676B09AEE37B /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
2052550A748A76EA30695CE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 2ECB69507C18B14A1DD3CE5E /* Pods.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
OTHER_LIBTOOLFLAGS = "";
|
||||
PODS_ROOT = "$(SRCROOT)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
26FB7D7741DD11D9B15ADF7F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 383F6CE99248AAF4C3B60881 /* Pods.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "";
|
||||
OTHER_LIBTOOLFLAGS = "";
|
||||
PODS_ROOT = "$(SRCROOT)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
603F72B2BF325C2D14018DA6 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "RELEASE=1";
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SYMROOT = "${SRCROOT}/../build";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
940B952B180C96F7963E6571 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B1C30DBE70E62F5C3FEF4944 /* Pods-SlackTextViewController-Private.xcconfig */;
|
||||
buildSettings = {
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_PREFIX_HEADER = "Target Support Files/Pods-SlackTextViewController/Pods-SlackTextViewController-prefix.pch";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
OTHER_LDFLAGS = "";
|
||||
OTHER_LIBTOOLFLAGS = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A18066350F539C6D0471BE6B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B1C30DBE70E62F5C3FEF4944 /* Pods-SlackTextViewController-Private.xcconfig */;
|
||||
buildSettings = {
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_PREFIX_HEADER = "Target Support Files/Pods-SlackTextViewController/Pods-SlackTextViewController-prefix.pch";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "";
|
||||
OTHER_LIBTOOLFLAGS = "";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B1FB22DD2936B88C267CABCD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SYMROOT = "${SRCROOT}/../build";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
4B82C4FC01672BAF03F56AB0 /* Build configuration list for PBXNativeTarget "Pods" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2052550A748A76EA30695CE5 /* Debug */,
|
||||
26FB7D7741DD11D9B15ADF7F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
8E9027938227B7173C82EA14 /* Build configuration list for PBXProject "Pods" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B1FB22DD2936B88C267CABCD /* Debug */,
|
||||
603F72B2BF325C2D14018DA6 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D7E02682B457EF6A6280F9AE /* Build configuration list for PBXNativeTarget "Pods-SlackTextViewController" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
940B952B180C96F7963E6571 /* Debug */,
|
||||
A18066350F539C6D0471BE6B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 8B26729A3C6DF0B6B83B55BB /* Project object */;
|
||||
}
|
||||
14
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/LICENSE
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
Copyright 2015 Slack Technologies, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
324
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/README.md
generated
Normal file
@@ -0,0 +1,324 @@
|
||||
#SlackTextViewController
|
||||
|
||||
[](https://travis-ci.org/slackhq/SlackTextViewController)
|
||||
[](https://coveralls.io/r/slackhq/SlackTextViewController)
|
||||
|
||||
[](https://cocoadocs.org/docsets/SlackTextViewController)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](http://opensource.org/licenses/Apache2.0)
|
||||
|
||||
|
||||
A drop-in UIViewController subclass with a growing text input view and other useful messaging features. Meant to be a replacement for UITableViewController & UICollectionViewController.
|
||||
|
||||

|
||||
|
||||
This library is used in Slack's iOS app. It was built to fit our needs, but is flexible enough to be reused by others wanting to build great messaging apps for iOS.
|
||||
|
||||
## Features
|
||||
|
||||
### Core
|
||||
- Works out of the box with [UITableView or UICollectionView or UIScrollView](https://github.com/slackhq/SlackTextViewController/tree/swift-example#subclassing)
|
||||
- [Growing Text View](https://github.com/slackhq/SlackTextViewController#growing-text-view), with line count limit support
|
||||
- Flexible UI built with Auto Layout
|
||||
- Customizable: provides left and right button, and toolbar outlets
|
||||
- Tap Gesture for dismissing the keyboard
|
||||
- [Panning Gesture](https://github.com/slackhq/SlackTextViewController#panning-gesture) for sliding down the keyboard
|
||||
- [External keyboard](https://github.com/slackhq/SlackTextViewController#external-keyboard) commands support
|
||||
- Undo/Redo (with keyboard commands and UIMenuController)
|
||||
- Text Appending APIs
|
||||
|
||||
### Optional
|
||||
- [Autocomplete Mode](https://github.com/slackhq/SlackTextViewController#autocompletion) by registering any prefix key (`@`, `#`, `/`)
|
||||
- [Edit Mode](https://github.com/slackhq/SlackTextViewController#edit-mode)
|
||||
- [Typing Indicator](https://github.com/slackhq/SlackTextViewController#typing-indicator) display
|
||||
- [Shake Gesture](https://github.com/slackhq/SlackTextViewController#shake-gesture) for clearing text view
|
||||
- Multimedia Pasting (png, gif, mov, etc.)
|
||||
- [Inverted Mode](https://github.com/slackhq/SlackTextViewController#inverted-mode) for displaying cells upside-down (using CATransform) -- a necessary hack for some messaging apps. `YES` by default, so beware, your entire cells might be flipped!
|
||||
- Bouncy Animations
|
||||
|
||||
### Compatibility
|
||||
- Swift: [A sample project is available in a different branch] (https://github.com/slackhq/SlackTextViewController/tree/swift-example)
|
||||
- iOS 7 & 8
|
||||
- iPhone & iPad
|
||||
- [Storyboard](https://github.com/slackhq/SlackTextViewController#storyboard)
|
||||
- UIPopOverController & UITabBarController
|
||||
- Container View Controller
|
||||
- Auto-Rotation
|
||||
- Localization
|
||||
|
||||
## Installation
|
||||
|
||||
###### With [Cocoa Pods](http://cocoapods.org):
|
||||
```ruby
|
||||
pod 'SlackTextViewController'
|
||||
```
|
||||
|
||||
###### With [Carthage](https://github.com/Carthage/Carthage):
|
||||
```
|
||||
github "slackhq/SlackTextViewController"
|
||||
```
|
||||
|
||||
###### Manually:
|
||||
There are two ways to do this:
|
||||
- Copy and drag the `Source/` folder to your project.
|
||||
- or compile the project located in `Builder/SlackTextViewController.xcodeproj` to create a `SlackTextViewController.framework` package. You could also [link the library into your project](https://developer.apple.com/library/ios/recipes/xcode_help-project_editor/Articles/AddingaLibrarytoaTarget.html#//apple_ref/doc/uid/TP40010155-CH17-SW1).
|
||||
|
||||
##How to use
|
||||
|
||||
###Subclassing
|
||||
`SLKTextViewController` is meant to be subclassed, like you would normally do with UITableViewController or UICollectionViewController or UIScrollView. This pattern is a convenient way of extending UIViewController. SlackTextViewController manages a lot behind the scenes while still providing the ability to add custom behaviours. You may override methods, and decide to call super and perform additional logic, or not to call super and override default logic.
|
||||
|
||||
Start by creating a new subclass of `SLKTextViewController`.
|
||||
|
||||
In the init overriding method, if you wish to use the `UITableView` version, call:
|
||||
```objc
|
||||
[super initWithTableViewStyle:UITableViewStylePlain]
|
||||
```
|
||||
|
||||
or the `UICollectionView` version:
|
||||
```objc
|
||||
[super initWithCollectionViewLayout:[UICollectionViewFlowLayout new]]
|
||||
```
|
||||
|
||||
or the `UIScrollView` version:
|
||||
```objc
|
||||
[super initWithScrollView:self.myStrongScrollView]
|
||||
```
|
||||
|
||||
|
||||
Protocols like `UITableViewDelegate` and `UITableViewDataSource` are already setup for you. You will be able to call whatever delegate and data source methods you need for customising your control.
|
||||
|
||||
Calling `[super init]` will call `[super initWithTableViewStyle:UITableViewStylePlain]` by default.
|
||||
|
||||
|
||||
###Growing Text View
|
||||
|
||||

|
||||
|
||||
The text view expands automatically when a new line is required, until it reaches its `maxNumberOfLines`value. You may change this property's value in the textView.
|
||||
|
||||
By default, the number of lines is set to best fit each device dimensions:
|
||||
- iPhone 4 (<=480pts): 4 lines
|
||||
- iPhone 5/6 (>=568pts): 6 lines
|
||||
- iPad (>=768pts): 8 lines
|
||||
|
||||
On iPhone devices, in landscape orientation, the maximum number of lines is changed to fit the available space.
|
||||
|
||||
###Autocompletion
|
||||
|
||||
We use autocompletion for many things: names, channels, emoji, and more.
|
||||
|
||||

|
||||
|
||||
To set up autocompletion in your app, follow these simple steps:
|
||||
|
||||
#### 1. Registration
|
||||
You must first register all the prefixes you'd like to support for autocompletion detection:
|
||||
````objc
|
||||
[self registerPrefixesForAutoCompletion:@[@"#"]];
|
||||
````
|
||||
|
||||
#### 2. Processing
|
||||
Every time a new character is inserted in the text view, the nearest word to the caret will be processed and verified if it contains any of the registered prefixes.
|
||||
|
||||
Once the prefix has been detected, `-canShowAutoCompletion` will be called. This is the perfect place to populate your data source, and return a BOOL if the autocompletion view should actually be shown. So you must override it in your subclass, to be able to perform additional tasks. Default returns NO.
|
||||
|
||||
````objc
|
||||
- (BOOL)canShowAutoCompletion
|
||||
{
|
||||
NSString *prefix = self.foundPrefix;
|
||||
NSString *word = self.foundWord;
|
||||
|
||||
self.searchResult = [[NSArray alloc] initWithArray:self.channels];
|
||||
|
||||
if ([prefix isEqualToString:@"#"])
|
||||
{
|
||||
if (word.length > 0) {
|
||||
self.searchResult = [self.searchResult filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self BEGINSWITH[c] %@ AND self !=[c] %@", word, word]];
|
||||
}
|
||||
}
|
||||
|
||||
if (self.searchResult.count > 0) {
|
||||
self.searchResult = [self.searchResult sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
|
||||
}
|
||||
|
||||
return self.searchResult.count > 0;
|
||||
}
|
||||
````
|
||||
|
||||
The autocompletion view is a `UITableView` instance, so you will need to use `UITableViewDataSource` to populate its cells. You have complete freedom for customizing the cells.
|
||||
|
||||
You don't need to call `-reloadData` yourself, since it will be called automatically if you return `YES` in `-canShowAutoCompletion` method.
|
||||
|
||||
#### 3. Layout
|
||||
|
||||
The maximum height of the autocompletion view is set to 140 pts by default. You can update this value anytime, so the view automatically adjusts based on the amount of displayed cells.
|
||||
|
||||
````objc
|
||||
- (CGFloat)heightForAutoCompletionView
|
||||
{
|
||||
CGFloat cellHeight = 34.0;
|
||||
return cellHeight*self.searchResult.count;
|
||||
}
|
||||
````
|
||||
|
||||
#### 4. Confirmation
|
||||
|
||||
If the user selects any autocompletion view cell on `-tableView:didSelectRowAtIndexPath:`, you must call `-acceptAutoCompletionWithString:` to commit autocompletion. That method expects a string matching the selected item, that you would like to be inserted in the text view.
|
||||
|
||||
`````objc
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if ([tableView isEqual:self.autoCompletionView]) {
|
||||
|
||||
NSString *item = self.searchResult[indexPath.row];
|
||||
|
||||
[self acceptAutoCompletionWithString:item];
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
The autocompletion view will automatically be dismissed and the chosen string will be inserted in the text view, replacing the detected prefix and word.
|
||||
|
||||
You can always call `-cancelAutoCompletion` to exit the autocompletion mode and refresh the UI.
|
||||
|
||||
|
||||
###Edit Mode
|
||||
|
||||

|
||||
|
||||
To enable edit mode, you simply need to call `[self editText:@"hello"];`, and the text input will switch to edit mode, removing both left and right buttons, extending the input bar a bit higher with "Accept" and "Cancel" buttons. Both of this buttons are accessible in the `SLKTextInputbar` instance for customisation.
|
||||
|
||||
To capture the "Accept" or "Cancel" events, you must override the following methods.
|
||||
|
||||
````objc
|
||||
- (void)didCommitTextEditing:(id)sender
|
||||
{
|
||||
NSString *message = [self.textView.text copy];
|
||||
|
||||
[self.messages removeObjectAtIndex:0];
|
||||
[self.messages insertObject:message atIndex:0];
|
||||
[self.tableView reloadData];
|
||||
|
||||
[super didCommitTextEditing:sender];
|
||||
}
|
||||
|
||||
- (void)didCancelTextEditing:(id)sender
|
||||
{
|
||||
[super didCancelTextEditing:sender];
|
||||
}
|
||||
````
|
||||
|
||||
Notice that you must call `super` at some point, so the text input exits the edit mode, re-adjusting the layout and clearing the text view.
|
||||
Use the `editing` property to know if the editing mode is on.
|
||||
|
||||
|
||||
###Typing Indicator
|
||||
|
||||

|
||||
|
||||
Optionally, you can enable a simple typing indicator, which will be displayed right above the text input. It shows the name of the people that are typing, and if more than 2, it will display "Several are typing" message.
|
||||
|
||||
To enable the typing indicator, just call `[self.typingIndicatorView insertUsername:@"John"];` and the view will automatically be animated on top of the text input. After a default interval of 6 seconds, if the same name hasn't been assigned once more, the view will be dismissed with animation.
|
||||
|
||||
You can remove names from the list by calling `[self.typingIndicatorView removeUsername:@"John"];`
|
||||
|
||||
You can also dismiss it by calling `[self.typingIndicatorView dismissIndicator];`
|
||||
|
||||
###Panning Gesture
|
||||
|
||||
Dismissing the keyboard with a panning gesture is enabled by default with the `keyboardPanningEnabled` property. You can always disable it if you'd like.
|
||||
|
||||
###Shake Gesture
|
||||
|
||||

|
||||
|
||||
A shake gesture to clear text is enabled by default with the `undoShakingEnabled` property.
|
||||
|
||||
You can optionally override `-willRequestUndo`, to implement your UI to ask the users if he would like to clean the text view's text. If there is not text entered, the method will not be called.
|
||||
|
||||
If you don't override `-willRequestUndo` and `undoShakingEnabled` is set to `YES`, a system UIAlertView will prompt.
|
||||
|
||||
###Inverted Mode
|
||||
|
||||
Some UITableView layouts may require that new messages enter from bottom to top. To enable this, you must use the `inverted` flag property. This will actually invert the UITableView or UICollectionView, so you will need to do a transform adjustment in your UITableViewDataSource method `-tableView:cellForRowAtIndexPath:` for the cells to show correctly.
|
||||
|
||||
````objc
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:chatCellIdentifier];
|
||||
|
||||
// Cells must inherit the table view's transform
|
||||
// This is very important, since the main table view may be inverted
|
||||
cell.transform = self.tableView.transform;
|
||||
}
|
||||
````
|
||||
|
||||
###External Keyboard
|
||||
|
||||
There a few basic key commands enabled by default:
|
||||
- cmd + z -> undo
|
||||
- shift + cmd + z -> redo
|
||||
- return key -> calls `-didPressRightButton:`, or `-didCommitTextEditing:` if in edit mode
|
||||
- shift/cmd + return key -> line break
|
||||
- escape key -> exits edit mode, or auto-completion mode, or dismisses the keyboard
|
||||
- up & down arrows -> vertical cursor movement
|
||||
|
||||
To add additional key commands, simply override `-keyCommands` and append `super`'s array.
|
||||
|
||||
`````objc
|
||||
- (NSArray *)keyCommands
|
||||
{
|
||||
NSMutableArray *commands = [NSMutableArray arrayWithArray:[super keyCommands]];
|
||||
|
||||
// Edit last message
|
||||
[commands addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow
|
||||
modifierFlags:0
|
||||
action:@selector(editLastMessage:)]];
|
||||
|
||||
return commands;
|
||||
}
|
||||
````
|
||||
|
||||
##Storyboard
|
||||
|
||||
When using SlackTextViewController with storyboards, instead of overriding the traditional `initWithCoder:` you will need to override any of the two custom methods below. This approach helps preserving the exact same features from the programatic approach, but also limits the edition of the nib of your `SLKTextViewController` subclass since it doesn't layout subviews from the nib (subviews are still initialized and layed out programatically).
|
||||
|
||||
if you wish to use the `UITableView` version, call:
|
||||
```objc
|
||||
+ (UITableViewStyle)tableViewStyleForCoder:(NSCoder *)decoder
|
||||
{
|
||||
return UITableViewStylePlain;
|
||||
}
|
||||
```
|
||||
|
||||
or the `UICollectionView` version:
|
||||
```objc
|
||||
+ (UICollectionViewLayout *)collectionViewLayoutForCoder:(NSCoder *)decoder
|
||||
{
|
||||
return [UICollectionViewFlowLayout new];
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##Sample Project
|
||||
|
||||
Check out the sample project, everything is demo'd there.
|
||||
There are 2 main examples (different targets) for testing the programatic and storyboard approaches.
|
||||
|
||||
A CollectionView example, using Swift, is in progress on the `swift-example` branch. The idea with this project is to build a custom collection view layout allowing to display cells from the bottom (currently working but needs serious tweaks to make it perfect).
|
||||
Feel free to contribute!
|
||||
|
||||
|
||||
##XCode Templates
|
||||
|
||||

|
||||
|
||||
We have prepared a set of useful XCode templates so you can quickly start using SlackTextViewController.
|
||||
|
||||
To install them, open up your terminal and type:
|
||||
```bash
|
||||
sh ./SlackTextViewController/File\ Templates/install.sh
|
||||
```
|
||||
|
||||
These templates are also available in [Alcatraz](https://github.com/supermarin/Alcatraz).
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "SLKTextView.h"
|
||||
|
||||
/** @name SLKTextView additional features used for SlackTextViewController. */
|
||||
@interface SLKTextView (SLKAdditions)
|
||||
|
||||
/**
|
||||
Clears the text.
|
||||
|
||||
@param clearUndo YES if clearing the text should also clear the undo manager (if enabled).
|
||||
*/
|
||||
- (void)slk_clearText:(BOOL)clearUndo;
|
||||
|
||||
/**
|
||||
Scrolls to the very end of the content size, animated.
|
||||
|
||||
@param animated YES if the scrolling should be animated.
|
||||
*/
|
||||
- (void)slk_scrollToBottomAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Scrolls to the caret position, animated.
|
||||
|
||||
@param animated YES if the scrolling should be animated.
|
||||
*/
|
||||
- (void)slk_scrollToCaretPositonAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Inserts a line break at the caret's position.
|
||||
*/
|
||||
- (void)slk_insertNewLineBreak;
|
||||
|
||||
/**
|
||||
Inserts a string at the caret's position.
|
||||
|
||||
@param text The string to be appended to the current text.
|
||||
*/
|
||||
- (void)slk_insertTextAtCaretRange:(NSString *)text;
|
||||
|
||||
/**
|
||||
Adds a string to a specific range.
|
||||
|
||||
@param text The string to be appended to the current text.
|
||||
@param range The range where to insert text.
|
||||
|
||||
@return The range of the newly inserted text.
|
||||
*/
|
||||
- (NSRange)slk_insertText:(NSString *)text inRange:(NSRange)range;
|
||||
|
||||
/**
|
||||
Finds the word close to the caret's position, if any.
|
||||
|
||||
@param range Returns the range of the found word.
|
||||
@returns The found word.
|
||||
*/
|
||||
- (NSString *)slk_wordAtCaretRange:(NSRangePointer)range;
|
||||
|
||||
/**
|
||||
Registers the current text for future undo actions.
|
||||
|
||||
@param description A simple description associated with the Undo or Redo command.
|
||||
*/
|
||||
- (void)slk_prepareForUndo:(NSString *)description;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "SLKTextView+SLKAdditions.h"
|
||||
|
||||
@implementation SLKTextView (SLKAdditions)
|
||||
|
||||
- (void)slk_clearText:(BOOL)clearUndo
|
||||
{
|
||||
// Important to call self implementation, as SLKTextView overrides setText: to add additional features.
|
||||
[self setText:nil];
|
||||
|
||||
if (self.undoManagerEnabled && clearUndo) {
|
||||
[self.undoManager removeAllActions];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slk_scrollToCaretPositonAnimated:(BOOL)animated
|
||||
{
|
||||
if (animated) {
|
||||
[self scrollRangeToVisible:self.selectedRange];
|
||||
}
|
||||
else {
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self scrollRangeToVisible:self.selectedRange];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slk_scrollToBottomAnimated:(BOOL)animated
|
||||
{
|
||||
CGRect rect = [self caretRectForPosition:self.selectedTextRange.end];
|
||||
rect.size.height += self.textContainerInset.bottom;
|
||||
|
||||
if (animated) {
|
||||
[self scrollRectToVisible:rect animated:animated];
|
||||
}
|
||||
else {
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self scrollRectToVisible:rect animated:NO];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slk_insertNewLineBreak
|
||||
{
|
||||
[self slk_insertTextAtCaretRange:@"\n"];
|
||||
|
||||
// if the text view cannot expand anymore, scrolling to bottom are not animated to fix a UITextView issue scrolling twice.
|
||||
BOOL animated = !self.isExpanding;
|
||||
|
||||
//Detected break. Should scroll to bottom if needed.
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0125 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self slk_scrollToBottomAnimated:animated];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)slk_insertTextAtCaretRange:(NSString *)text
|
||||
{
|
||||
NSRange range = [self slk_insertText:text inRange:self.selectedRange];
|
||||
self.selectedRange = NSMakeRange(range.location, 0);
|
||||
}
|
||||
|
||||
- (NSRange)slk_insertText:(NSString *)text inRange:(NSRange)range
|
||||
{
|
||||
// Skip if the text is empty
|
||||
if (text.length == 0) {
|
||||
return NSMakeRange(0, 0);
|
||||
}
|
||||
|
||||
// Registers for undo management
|
||||
[self slk_prepareForUndo:@"Text appending"];
|
||||
|
||||
// Append the new string at the caret position
|
||||
if (range.length == 0)
|
||||
{
|
||||
NSString *leftString = [self.text substringToIndex:range.location];
|
||||
NSString *rightString = [self.text substringFromIndex: range.location];
|
||||
|
||||
self.text = [NSString stringWithFormat:@"%@%@%@", leftString, text, rightString];
|
||||
|
||||
range.location += [text length];
|
||||
return range;
|
||||
}
|
||||
// Some text is selected, so we replace it with the new text
|
||||
else if (range.location != NSNotFound && range.length > 0)
|
||||
{
|
||||
self.text = [self.text stringByReplacingCharactersInRange:range withString:text];
|
||||
|
||||
return NSMakeRange(range.location+[self.text rangeOfString:text].length, text.length);
|
||||
}
|
||||
|
||||
// No text has been inserted, but still return the caret range
|
||||
return self.selectedRange;
|
||||
}
|
||||
|
||||
- (NSString *)slk_wordAtCaretRange:(NSRangePointer)range
|
||||
{
|
||||
return [self slk_wordAtRange:self.selectedRange rangeInText:range];
|
||||
}
|
||||
|
||||
- (NSString *)slk_wordAtRange:(NSRange)range rangeInText:(NSRangePointer)rangePointer
|
||||
{
|
||||
NSString *text = self.text;
|
||||
NSInteger location = range.location;
|
||||
|
||||
// Aborts in case minimum requieres are not fufilled
|
||||
if (text.length == 0 || location < 0 || (range.location+range.length) > text.length) {
|
||||
*rangePointer = NSMakeRange(0, 0);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *leftPortion = [text substringToIndex:location];
|
||||
NSArray *leftComponents = [leftPortion componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
NSString *leftWordPart = [leftComponents lastObject];
|
||||
|
||||
NSString *rightPortion = [text substringFromIndex:location];
|
||||
NSArray *rightComponents = [rightPortion componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
NSString *rightPart = [rightComponents firstObject];
|
||||
|
||||
if (location > 0) {
|
||||
NSString *characterBeforeCursor = [text substringWithRange:NSMakeRange(location-1, 1)];
|
||||
|
||||
if ([characterBeforeCursor isEqualToString:@" "]) {
|
||||
// At the start of a word, just use the word behind the cursor for the current word
|
||||
*rangePointer = NSMakeRange(location, rightPart.length);
|
||||
|
||||
return rightPart;
|
||||
}
|
||||
}
|
||||
|
||||
// In the middle of a word, so combine the part of the word before the cursor, and after the cursor to get the current word
|
||||
*rangePointer = NSMakeRange(location-leftWordPart.length, leftWordPart.length+rightPart.length);
|
||||
NSString *word = [leftWordPart stringByAppendingString:rightPart];
|
||||
|
||||
// If a break is detected, return the last component of the string
|
||||
if ([word rangeOfString:@"\n"].location != NSNotFound) {
|
||||
*rangePointer = [text rangeOfString:word];
|
||||
word = [[word componentsSeparatedByString:@"\n"] lastObject];
|
||||
}
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
- (void)slk_prepareForUndo:(NSString *)description
|
||||
{
|
||||
if (!self.undoManagerEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
SLKTextView *prepareInvocation = [self.undoManager prepareWithInvocationTarget:self];
|
||||
[prepareInvocation setText:self.text];
|
||||
[self.undoManager setActionName:description];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
61
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Additions/SLKUIConstants.h
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#define SLK_IS_LANDSCAPE ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeRight)
|
||||
#define SLK_IS_IPAD ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
|
||||
#define SLK_IS_IPHONE ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
|
||||
#define SLK_IS_IPHONE4 (SLK_IS_IPHONE && [[UIScreen mainScreen] bounds].size.height < 568.0)
|
||||
#define SLK_IS_IPHONE5 (SLK_IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 568.0)
|
||||
#define SLK_IS_IPHONE6 (SLK_IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 667.0)
|
||||
#define SLK_IS_IPHONE6PLUS (SLK_IS_IPHONE && [[UIScreen mainScreen] bounds].size.height == 736.0 || [[UIScreen mainScreen] bounds].size.width == 736.0) // Both orientations
|
||||
#define SLK_IS_IOS8_AND_HIGHER ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
|
||||
|
||||
#define SLK_INPUT_ACCESSORY_DEBUG DEBUG && 0 // Renders a translucent red area representing the keyboard accessory view
|
||||
#define SLK_KEYBOARD_NOTIFICATION_DEBUG DEBUG && 0 // Logs every keyboard notification being sent
|
||||
|
||||
#if __has_attribute(objc_designated_initializer)
|
||||
#define SLK_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
#endif
|
||||
|
||||
static NSString *SLKTextViewControllerDomain = @"com.slack.TextViewController";
|
||||
|
||||
inline static CGFloat minimumKeyboardHeight()
|
||||
{
|
||||
if (SLK_IS_IPAD) {
|
||||
if (SLK_IS_LANDSCAPE) return 352.f;
|
||||
else return 264.f;
|
||||
}
|
||||
if (SLK_IS_IPHONE6PLUS) {
|
||||
if (SLK_IS_LANDSCAPE) return 162.f;
|
||||
else return 226.f;
|
||||
}
|
||||
else {
|
||||
if (SLK_IS_LANDSCAPE) return 162.f;
|
||||
else return 216.f;
|
||||
}
|
||||
}
|
||||
|
||||
inline static CGRect SLKRectInvert(CGRect rect)
|
||||
{
|
||||
CGRect invert = CGRectZero;
|
||||
|
||||
invert.origin.x = rect.origin.y;
|
||||
invert.origin.y = rect.origin.x;
|
||||
invert.size.width = rect.size.height;
|
||||
invert.size.height = rect.size.width;
|
||||
|
||||
return invert;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/** @name UIResponder additional features used for SlackTextViewController. */
|
||||
@interface UIResponder (SLKAdditions)
|
||||
|
||||
/**
|
||||
Returns the current first responder object.
|
||||
@discussion This is an experimental API. Use it at your own risk.
|
||||
|
||||
@return A UIResponder instance.
|
||||
*/
|
||||
+ (instancetype)slk_currentFirstResponder;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "UIResponder+SLKAdditions.h"
|
||||
|
||||
static __weak id ___currentFirstResponder;
|
||||
|
||||
@implementation UIResponder (SLKAdditions)
|
||||
|
||||
/**
|
||||
Based on Jakob Egger's answer in http://stackoverflow.com/a/14135456/590010
|
||||
*/
|
||||
+ (instancetype)slk_currentFirstResponder
|
||||
{
|
||||
___currentFirstResponder = nil;
|
||||
[[UIApplication sharedApplication] sendAction:@selector(slk_findFirstResponder:) to:nil from:nil forEvent:nil];
|
||||
|
||||
return ___currentFirstResponder;
|
||||
}
|
||||
|
||||
- (void)slk_findFirstResponder:(id)sender
|
||||
{
|
||||
___currentFirstResponder = self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/** @name UIScrollView additional features used for SlackTextViewController. */
|
||||
@interface UIScrollView (SLKAdditions)
|
||||
|
||||
/** YES if the scrollView's offset is at the very top. */
|
||||
@property (nonatomic, readonly) BOOL slk_isAtTop;
|
||||
/** YES if the scrollView's offset is at the very bottom. */
|
||||
@property (nonatomic, readonly) BOOL slk_isAtBottom;
|
||||
/** The visible area of the content size. */
|
||||
@property (nonatomic, readonly) CGRect slk_visibleRect;
|
||||
|
||||
/**
|
||||
Sets the content offset to the top.
|
||||
|
||||
@param animated YES to animate the transition at a constant velocity to the new offset, NO to make the transition immediate.
|
||||
*/
|
||||
- (void)slk_scrollToTopAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Sets the content offset to the bottom.
|
||||
|
||||
@param animated YES to animate the transition at a constant velocity to the new offset, NO to make the transition immediate.
|
||||
*/
|
||||
- (void)slk_scrollToBottomAnimated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Stops scrolling, if it was scrolling.
|
||||
*/
|
||||
- (void)slk_stopScrolling;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "UIScrollView+SLKAdditions.h"
|
||||
|
||||
@implementation UIScrollView (SLKAdditions)
|
||||
|
||||
- (void)slk_scrollToTopAnimated:(BOOL)animated
|
||||
{
|
||||
[self scrollRectToVisible:[self slk_topRect] animated:animated];
|
||||
}
|
||||
|
||||
- (void)slk_scrollToBottomAnimated:(BOOL)animated
|
||||
{
|
||||
[self scrollRectToVisible:[self slk_bottomRect] animated:animated];
|
||||
}
|
||||
|
||||
- (BOOL)slk_isAtTop
|
||||
{
|
||||
return CGRectGetMinY([self slk_visibleRect]) == CGRectGetMinY([self slk_topRect]);
|
||||
}
|
||||
|
||||
- (BOOL)slk_isAtBottom
|
||||
{
|
||||
return CGRectGetMaxY([self slk_visibleRect]) == CGRectGetMaxY([self slk_bottomRect]);
|
||||
}
|
||||
|
||||
- (CGRect)slk_visibleRect
|
||||
{
|
||||
CGRect visibleRect;
|
||||
visibleRect.origin = self.contentOffset;
|
||||
visibleRect.size = self.frame.size;
|
||||
return visibleRect;
|
||||
}
|
||||
|
||||
- (CGRect)slk_topRect
|
||||
{
|
||||
return CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
|
||||
}
|
||||
|
||||
- (CGRect)slk_bottomRect
|
||||
{
|
||||
return CGRectMake(0, self.contentSize.height - CGRectGetHeight(self.bounds), CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
|
||||
}
|
||||
|
||||
- (void)slk_stopScrolling
|
||||
{
|
||||
if (!self.isDragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGPoint offset = self.contentOffset;
|
||||
offset.y -= 1.0;
|
||||
[self setContentOffset:offset];
|
||||
|
||||
offset.y += 1.0;
|
||||
[self setContentOffset:offset];
|
||||
}
|
||||
|
||||
@end
|
||||
59
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Additions/UIView+SLKAdditions.h
generated
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/** @name UIView additional features used for SlackTextViewController. */
|
||||
@interface UIView (SLKAdditions)
|
||||
|
||||
/**
|
||||
Animates the view's constraints by calling layoutIfNeeded.
|
||||
|
||||
@param bounce YES if the animation should use spring damping and velocity to give a bouncy effect to animations.
|
||||
@param options A mask of options indicating how you want to perform the animations.
|
||||
@param animations An additional block for custom animations.
|
||||
*/
|
||||
- (void)slk_animateLayoutIfNeededWithBounce:(BOOL)bounce options:(UIViewAnimationOptions)options animations:(void (^)(void))animations;
|
||||
|
||||
/**
|
||||
Animates the view's constraints by calling layoutIfNeeded.
|
||||
|
||||
@param duration The total duration of the animations, measured in seconds.
|
||||
@param bounce YES if the animation should use spring damping and velocity to give a bouncy effect to animations.
|
||||
@param options A mask of options indicating how you want to perform the animations.
|
||||
@param animations An additional block for custom animations.
|
||||
*/
|
||||
- (void)slk_animateLayoutIfNeededWithDuration:(NSTimeInterval)duration bounce:(BOOL)bounce options:(UIViewAnimationOptions)options animations:(void (^)(void))animations;
|
||||
|
||||
/**
|
||||
Returns the view constraints matching a specific layout attribute (top, bottom, left, right, leading, trailing, etc.)
|
||||
|
||||
@param attribute The layout attribute to use for searching.
|
||||
@return An array of matching constraints.
|
||||
*/
|
||||
- (NSArray *)slk_constraintsForAttribute:(NSLayoutAttribute)attribute;
|
||||
|
||||
/**
|
||||
Returns a layout constraint matching a specific layout attribute and relationship between 2 items, first and second items.
|
||||
|
||||
@param attribute The layout attribute to use for searching.
|
||||
@param first The first item in the relationship.
|
||||
@param second The second item in the relationship.
|
||||
@return A layout constraint.
|
||||
*/
|
||||
- (NSLayoutConstraint *)slk_constraintForAttribute:(NSLayoutAttribute)attribute firstItem:(id)first secondItem:(id)second;
|
||||
|
||||
@end
|
||||
73
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Additions/UIView+SLKAdditions.m
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "UIView+SLKAdditions.h"
|
||||
|
||||
#import "SLKUIConstants.h"
|
||||
|
||||
@implementation UIView (SLKAdditions)
|
||||
|
||||
- (void)slk_animateLayoutIfNeededWithBounce:(BOOL)bounce options:(UIViewAnimationOptions)options animations:(void (^)(void))animations
|
||||
{
|
||||
NSTimeInterval duration = bounce ? 0.5 : 0.2;
|
||||
[self slk_animateLayoutIfNeededWithDuration:duration bounce:bounce options:options animations:animations];
|
||||
}
|
||||
|
||||
- (void)slk_animateLayoutIfNeededWithDuration:(NSTimeInterval)duration bounce:(BOOL)bounce options:(UIViewAnimationOptions)options animations:(void (^)(void))animations
|
||||
{
|
||||
if (bounce) {
|
||||
[UIView animateWithDuration:duration
|
||||
delay:0.0
|
||||
usingSpringWithDamping:0.7
|
||||
initialSpringVelocity:0.7
|
||||
options:options
|
||||
animations:^{
|
||||
[self layoutIfNeeded];
|
||||
|
||||
if (animations) {
|
||||
animations();
|
||||
}
|
||||
}
|
||||
completion:NULL];
|
||||
}
|
||||
else {
|
||||
[UIView animateWithDuration:duration
|
||||
delay:0.0
|
||||
options:options
|
||||
animations:^{
|
||||
[self layoutIfNeeded];
|
||||
|
||||
if (animations) {
|
||||
animations();
|
||||
}
|
||||
}
|
||||
completion:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)slk_constraintsForAttribute:(NSLayoutAttribute)attribute
|
||||
{
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstAttribute = %d", attribute];
|
||||
return [self.constraints filteredArrayUsingPredicate:predicate];
|
||||
}
|
||||
|
||||
- (NSLayoutConstraint *)slk_constraintForAttribute:(NSLayoutAttribute)attribute firstItem:(id)first secondItem:(id)second
|
||||
{
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstAttribute = %d AND firstItem = %@ AND secondItem = %@", attribute, first, second];
|
||||
return [[self.constraints filteredArrayUsingPredicate:predicate] firstObject];
|
||||
}
|
||||
|
||||
@end
|
||||
23
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKInputAccessoryView.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
UIKIT_EXTERN NSString * const SLKInputAccessoryViewKeyboardFrameDidChangeNotification;
|
||||
|
||||
@interface SLKInputAccessoryView : UIView
|
||||
|
||||
@end
|
||||
100
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKInputAccessoryView.m
generated
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "SLKInputAccessoryView.h"
|
||||
#import "SLKUIConstants.h"
|
||||
|
||||
NSString * const SLKInputAccessoryViewKeyboardFrameDidChangeNotification = @"SLKInputAccessoryViewKeyboardFrameDidChangeNotification";
|
||||
|
||||
@interface SLKInputAccessoryView ()
|
||||
@property (nonatomic, weak) UIView *observedSuperview;
|
||||
@end
|
||||
|
||||
@implementation SLKInputAccessoryView
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
NSString *SLKKeyboardHandlingKeyPath()
|
||||
{
|
||||
// Listening for the superview's frame doesn't work on iOS8 and above, so we use its center
|
||||
if (SLK_IS_IOS8_AND_HIGHER) {
|
||||
return NSStringFromSelector(@selector(center));
|
||||
}
|
||||
else {
|
||||
return NSStringFromSelector(@selector(frame));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Super Overrides
|
||||
|
||||
- (void)willMoveToSuperview:(UIView *)newSuperview
|
||||
{
|
||||
[self slk_removeSuperviewObserver];
|
||||
[self slk_addSuperviewObserver:newSuperview];
|
||||
|
||||
[super willMoveToSuperview:newSuperview];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Superview handling
|
||||
|
||||
- (void)slk_addSuperviewObserver:(UIView *)superview
|
||||
{
|
||||
if (!_observedSuperview && superview) {
|
||||
_observedSuperview = superview;
|
||||
[superview addObserver:self forKeyPath:SLKKeyboardHandlingKeyPath() options:0 context:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slk_removeSuperviewObserver
|
||||
{
|
||||
if (_observedSuperview) {
|
||||
[self.observedSuperview removeObserver:self forKeyPath:SLKKeyboardHandlingKeyPath()];
|
||||
_observedSuperview = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Events
|
||||
|
||||
- (void)slk_didChangeKeyboardFrame:(CGRect)frame
|
||||
{
|
||||
NSDictionary *userInfo = @{UIKeyboardFrameEndUserInfoKey:[NSValue valueWithCGRect:frame]};
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SLKInputAccessoryViewKeyboardFrameDidChangeNotification object:nil userInfo:userInfo];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - KVO Listener
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ([object isEqual:self.superview] && [keyPath isEqualToString:SLKKeyboardHandlingKeyPath()]) {
|
||||
[self slk_didChangeKeyboardFrame:self.superview.frame];
|
||||
}
|
||||
else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lifeterm
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self slk_removeSuperviewObserver];
|
||||
}
|
||||
|
||||
@end
|
||||
149
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKTextInputbar.h
generated
Normal file
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class SLKTextViewController;
|
||||
@class SLKTextView;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SLKCounterStyle) {
|
||||
SLKCounterStyleNone,
|
||||
SLKCounterStyleSplit,
|
||||
SLKCounterStyleCountdown,
|
||||
SLKCounterStyleCountdownReversed
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SLKCounterPosition) {
|
||||
SLKCounterPositionTop,
|
||||
SLKCounterPositionBottom
|
||||
};
|
||||
|
||||
/** @name A custom tool bar encapsulating messaging controls. */
|
||||
@interface SLKTextInputbar : UIToolbar
|
||||
|
||||
/** A weak reference to the core view controller. */
|
||||
@property (nonatomic, weak) SLKTextViewController *controller;
|
||||
|
||||
/** The centered text input view.
|
||||
The maximum number of lines is configured by default, to best fit each devices dimensions.
|
||||
For iPhone 4 (<=480pts): 4 lines
|
||||
For iPhone 5 & 6 (>=568pts): 6 lines
|
||||
For iPad (>=768pts): 8 lines
|
||||
*/
|
||||
@property (nonatomic, strong) SLKTextView *textView;
|
||||
|
||||
/** The left action button action. */
|
||||
@property (nonatomic, strong) UIButton *leftButton;
|
||||
|
||||
/** The right action button action. */
|
||||
@property (nonatomic, strong) UIButton *rightButton;
|
||||
|
||||
/** YES if the right button should be hidden animatedly in case the text view has no text in it. Default is YES. */
|
||||
@property (nonatomic, readwrite) BOOL autoHideRightButton;
|
||||
|
||||
/** The inner padding to use when laying out content in the view. Default is {5, 8, 5, 8}. */
|
||||
@property (nonatomic, assign) UIEdgeInsets contentInset;
|
||||
|
||||
/** The minimum height based on the intrinsic content size's. */
|
||||
@property (nonatomic, readonly) CGFloat minimumInputbarHeight;
|
||||
|
||||
/** The most appropriate height calculated based on the amount of lines of text and other factors. */
|
||||
@property (nonatomic, readonly) CGFloat appropriateHeight;
|
||||
|
||||
|
||||
#pragma mark - Initialization
|
||||
///------------------------------------------------
|
||||
/// @name Initialization
|
||||
///------------------------------------------------
|
||||
|
||||
/**
|
||||
Initializes a text input bar with a class to be used for the text view
|
||||
|
||||
@param textViewClass The class to be used when creating the text view. May be nil. If provided, the class must be a subclass of SLKTextView
|
||||
@return An initialized SLKTextInputbar object or nil if the object could not be created.
|
||||
*/
|
||||
- (instancetype)initWithTextViewClass:(Class)textViewClass;
|
||||
|
||||
|
||||
#pragma mark - Text Editing
|
||||
///------------------------------------------------
|
||||
/// @name Text Editing
|
||||
///------------------------------------------------
|
||||
|
||||
/** The view displayed on top if the text input bar, containing the button outlets, when editing is enabled. */
|
||||
@property (nonatomic, strong) UIView *editorContentView;
|
||||
|
||||
/** The title label displayed in the middle of the accessoryView. */
|
||||
@property (nonatomic, strong) UILabel *editorTitle;
|
||||
|
||||
/** The 'cancel' button displayed left in the accessoryView. */
|
||||
@property (nonatomic, strong) UIButton *editortLeftButton;
|
||||
|
||||
/** The 'accept' button displayed right in the accessoryView. */
|
||||
@property (nonatomic, strong) UIButton *editortRightButton;
|
||||
|
||||
/** The accessory view's maximum height. Default is 38 pts. */
|
||||
@property (nonatomic, assign) CGFloat editorContentViewHeight;
|
||||
|
||||
/** A Boolean value indicating whether the control is in edit mode. */
|
||||
@property (nonatomic, getter = isEditing) BOOL editing;
|
||||
|
||||
/**
|
||||
Verifies if the text can be edited.
|
||||
|
||||
@param text The text to be edited.
|
||||
@return YES if the text is editable.
|
||||
*/
|
||||
- (BOOL)canEditText:(NSString *)text;
|
||||
|
||||
/**
|
||||
Begins editing the text, by updating the 'editing' flag and the view constraints.
|
||||
*/
|
||||
- (void)beginTextEditing;
|
||||
|
||||
/**
|
||||
End editing the text, by updating the 'editing' flag and the view constraints.
|
||||
*/
|
||||
- (void)endTextEdition;
|
||||
|
||||
|
||||
#pragma mark - Text Counting
|
||||
///------------------------------------------------
|
||||
/// @name Text Counting
|
||||
///------------------------------------------------
|
||||
|
||||
/** The label used to display the character counts. */
|
||||
@property (nonatomic, readonly) UILabel *charCountLabel;
|
||||
|
||||
/** The maximum character count allowed. If larger than 0, a character count label will be displayed on top of the right button. Default is 0, which means limitless.*/
|
||||
@property (nonatomic, readwrite) NSUInteger maxCharCount;
|
||||
|
||||
/** The character counter formatting. Ignored if maxCharCount is 0. Default is None. */
|
||||
@property (nonatomic, assign) SLKCounterStyle counterStyle;
|
||||
|
||||
/** The character counter layout style. Ignored if maxCharCount is 0. Default is SLKCounterPositionTop. */
|
||||
@property (nonatomic, assign) SLKCounterPosition counterPosition;
|
||||
|
||||
/** YES if the maxmimum character count has been exceeded. */
|
||||
@property (nonatomic, readonly) BOOL limitExceeded;
|
||||
|
||||
/** The normal color used for character counter label. Default is lightGrayColor. */
|
||||
@property (nonatomic, strong, readwrite) UIColor *charCountLabelNormalColor;
|
||||
|
||||
/** The color used for character counter label when it has exceeded the limit. Default is redColor. */
|
||||
@property (nonatomic, strong, readwrite) UIColor *charCountLabelWarningColor;
|
||||
|
||||
@end
|
||||
707
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKTextInputbar.m
generated
Normal file
@@ -0,0 +1,707 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "SLKTextInputbar.h"
|
||||
#import "SLKTextViewController.h"
|
||||
#import "SLKTextView.h"
|
||||
#import "SLKTextView+SLKAdditions.h"
|
||||
#import "SLKUIConstants.h"
|
||||
#import "UIView+SLKAdditions.h"
|
||||
|
||||
@interface SLKTextInputbar ()
|
||||
|
||||
@property (nonatomic, strong) NSLayoutConstraint *leftButtonWC;
|
||||
@property (nonatomic, strong) NSLayoutConstraint *leftButtonHC;
|
||||
@property (nonatomic, strong) NSLayoutConstraint *leftMarginWC;
|
||||
@property (nonatomic, strong) NSLayoutConstraint *bottomMarginWC;
|
||||
@property (nonatomic, strong) NSLayoutConstraint *rightButtonWC;
|
||||
@property (nonatomic, strong) NSLayoutConstraint *rightMarginWC;
|
||||
@property (nonatomic, strong) NSLayoutConstraint *editorContentViewHC;
|
||||
@property (nonatomic, strong) NSArray *charCountLabelVCs;
|
||||
|
||||
@property (nonatomic, strong) UILabel *charCountLabel;
|
||||
|
||||
@property (nonatomic, strong) Class textViewClass;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SLKTextInputbar
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
- (instancetype)initWithTextViewClass:(Class)textViewClass
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.textViewClass = textViewClass;
|
||||
[self slk_commonInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self slk_commonInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
if (self = [super initWithCoder:coder]) {
|
||||
[self slk_commonInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)slk_commonInit
|
||||
{
|
||||
self.charCountLabelNormalColor = [UIColor lightGrayColor];
|
||||
self.charCountLabelWarningColor = [UIColor redColor];
|
||||
|
||||
self.autoHideRightButton = YES;
|
||||
self.editorContentViewHeight = 38.0;
|
||||
self.contentInset = UIEdgeInsetsMake(5.0, 8.0, 5.0, 8.0);
|
||||
|
||||
[self addSubview:self.editorContentView];
|
||||
[self addSubview:self.leftButton];
|
||||
[self addSubview:self.rightButton];
|
||||
[self addSubview:self.textView];
|
||||
[self addSubview:self.charCountLabel];
|
||||
|
||||
[self slk_setupViewConstraints];
|
||||
[self slk_updateConstraintConstants];
|
||||
|
||||
self.counterStyle = SLKCounterStyleNone;
|
||||
self.counterPosition = SLKCounterPositionTop;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didChangeTextViewText:) name:UITextViewTextDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didChangeTextViewContentSize:) name:SLKTextViewContentSizeDidChangeNotification object:nil];
|
||||
|
||||
[self.leftButton.imageView addObserver:self forKeyPath:NSStringFromSelector(@selector(image)) options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UIView Overrides
|
||||
|
||||
- (void)layoutIfNeeded
|
||||
{
|
||||
if (self.constraints.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self slk_updateConstraintConstants];
|
||||
[super layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (CGSize)intrinsicContentSize
|
||||
{
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, 44.0);
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (SLKTextView *)textView
|
||||
{
|
||||
if (!_textView)
|
||||
{
|
||||
Class class = self.textViewClass ? : [SLKTextView class];
|
||||
|
||||
_textView = [[class alloc] init];
|
||||
_textView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_textView.font = [UIFont systemFontOfSize:15.0];
|
||||
_textView.maxNumberOfLines = [self slk_defaultNumberOfLines];
|
||||
|
||||
_textView.typingSuggestionEnabled = YES;
|
||||
_textView.autocapitalizationType = UITextAutocapitalizationTypeSentences;
|
||||
_textView.keyboardType = UIKeyboardTypeTwitter;
|
||||
_textView.returnKeyType = UIReturnKeyDefault;
|
||||
_textView.enablesReturnKeyAutomatically = YES;
|
||||
_textView.scrollIndicatorInsets = UIEdgeInsetsMake(0.0, -1.0, 0.0, 1.0);
|
||||
_textView.textContainerInset = UIEdgeInsetsMake(8.0, 4.0, 8.0, 0.0);
|
||||
_textView.layer.cornerRadius = 5.0;
|
||||
_textView.layer.borderWidth = 0.5;
|
||||
_textView.layer.borderColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:205.0/255.0 alpha:1.0].CGColor;
|
||||
|
||||
// Adds an aditional action to a private gesture to detect when the magnifying glass becomes visible
|
||||
for (UIGestureRecognizer *gesture in _textView.gestureRecognizers) {
|
||||
if ([gesture isKindOfClass:NSClassFromString(@"UIVariableDelayLoupeGesture")]) {
|
||||
[gesture addTarget:self action:@selector(slk_willShowLoupe:)];
|
||||
}
|
||||
}
|
||||
}
|
||||
return _textView;
|
||||
}
|
||||
|
||||
- (UIButton *)leftButton
|
||||
{
|
||||
if (!_leftButton)
|
||||
{
|
||||
_leftButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
_leftButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_leftButton.titleLabel.font = [UIFont systemFontOfSize:15.0];
|
||||
}
|
||||
return _leftButton;
|
||||
}
|
||||
|
||||
- (UIButton *)rightButton
|
||||
{
|
||||
if (!_rightButton)
|
||||
{
|
||||
_rightButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
_rightButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_rightButton.titleLabel.font = [UIFont boldSystemFontOfSize:15.0];
|
||||
_rightButton.enabled = NO;
|
||||
|
||||
[_rightButton setTitle:NSLocalizedString(@"Send", nil) forState:UIControlStateNormal];
|
||||
}
|
||||
return _rightButton;
|
||||
}
|
||||
|
||||
- (UIView *)editorContentView
|
||||
{
|
||||
if (!_editorContentView)
|
||||
{
|
||||
_editorContentView = [UIView new];
|
||||
_editorContentView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_editorContentView.backgroundColor = self.backgroundColor;
|
||||
_editorContentView.clipsToBounds = YES;
|
||||
_editorContentView.hidden = YES;
|
||||
|
||||
_editorTitle = [UILabel new];
|
||||
_editorTitle.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_editorTitle.text = NSLocalizedString(@"Editing Message", nil);
|
||||
_editorTitle.textAlignment = NSTextAlignmentCenter;
|
||||
_editorTitle.backgroundColor = [UIColor clearColor];
|
||||
_editorTitle.font = [UIFont boldSystemFontOfSize:15.0];
|
||||
[_editorContentView addSubview:self.editorTitle];
|
||||
|
||||
_editortLeftButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
_editortLeftButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_editortLeftButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
||||
_editortLeftButton.titleLabel.font = [UIFont systemFontOfSize:15.0];
|
||||
[_editortLeftButton setTitle:NSLocalizedString(@"Cancel", nil) forState:UIControlStateNormal];
|
||||
[_editorContentView addSubview:self.editortLeftButton];
|
||||
|
||||
_editortRightButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
_editortRightButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_editortRightButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
|
||||
_editortRightButton.titleLabel.font = [UIFont boldSystemFontOfSize:15.0];
|
||||
_editortRightButton.enabled = NO;
|
||||
[_editortRightButton setTitle:NSLocalizedString(@"Save", nil) forState:UIControlStateNormal];
|
||||
[_editorContentView addSubview:self.editortRightButton];
|
||||
|
||||
NSDictionary *views = @{@"label": self.editorTitle,
|
||||
@"leftButton": self.editortLeftButton,
|
||||
@"rightButton": self.editortRightButton,
|
||||
};
|
||||
|
||||
NSDictionary *metrics = @{@"left" : @(self.contentInset.left),
|
||||
@"right" : @(self.contentInset.right)
|
||||
};
|
||||
|
||||
[_editorContentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(left)-[leftButton(60)]-(left)-[label(>=0)]-(right)-[rightButton(60)]-(<=right)-|" options:0 metrics:metrics views:views]];
|
||||
[_editorContentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[leftButton]|" options:0 metrics:metrics views:views]];
|
||||
[_editorContentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[rightButton]|" options:0 metrics:metrics views:views]];
|
||||
[_editorContentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]|" options:0 metrics:metrics views:views]];
|
||||
}
|
||||
return _editorContentView;
|
||||
}
|
||||
|
||||
- (UILabel *)charCountLabel
|
||||
{
|
||||
if (!_charCountLabel)
|
||||
{
|
||||
_charCountLabel = [UILabel new];
|
||||
_charCountLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_charCountLabel.backgroundColor = [UIColor clearColor];
|
||||
_charCountLabel.textAlignment = NSTextAlignmentRight;
|
||||
_charCountLabel.font = [UIFont systemFontOfSize:11.0];
|
||||
|
||||
_charCountLabel.hidden = NO;
|
||||
}
|
||||
return _charCountLabel;
|
||||
}
|
||||
|
||||
- (BOOL)isViewVisible
|
||||
{
|
||||
SEL selector = NSSelectorFromString(@"isViewVisible");
|
||||
|
||||
if ([self.controller respondsToSelector:selector]) {
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
BOOL visible = (BOOL)[self.controller performSelector:selector];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return visible;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CGFloat)minimumInputbarHeight
|
||||
{
|
||||
return self.intrinsicContentSize.height;
|
||||
}
|
||||
|
||||
- (CGFloat)appropriateHeight
|
||||
{
|
||||
CGFloat height = 0.0;
|
||||
CGFloat minimumHeight = [self minimumInputbarHeight];
|
||||
|
||||
if (self.textView.numberOfLines == 1) {
|
||||
height = minimumHeight;
|
||||
}
|
||||
else if (self.textView.numberOfLines < self.textView.maxNumberOfLines) {
|
||||
height = [self slk_inputBarHeightForLines:self.textView.numberOfLines];
|
||||
}
|
||||
else {
|
||||
height = [self slk_inputBarHeightForLines:self.textView.maxNumberOfLines];
|
||||
}
|
||||
|
||||
if (height < minimumHeight) {
|
||||
height = minimumHeight;
|
||||
}
|
||||
|
||||
if (self.isEditing) {
|
||||
height += self.editorContentViewHeight;
|
||||
}
|
||||
|
||||
return roundf(height);
|
||||
}
|
||||
|
||||
- (CGFloat)slk_deltaInputbarHeight
|
||||
{
|
||||
return self.textView.intrinsicContentSize.height-self.textView.font.lineHeight;
|
||||
}
|
||||
|
||||
- (CGFloat)slk_inputBarHeightForLines:(NSUInteger)numberOfLines
|
||||
{
|
||||
CGFloat height = [self slk_deltaInputbarHeight];
|
||||
|
||||
height += roundf(self.textView.font.lineHeight*numberOfLines);
|
||||
height += self.contentInset.top+self.contentInset.bottom;
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
- (BOOL)limitExceeded
|
||||
{
|
||||
NSString *text = [self.textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
if (self.maxCharCount > 0 && text.length > self.maxCharCount) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CGFloat)slk_appropriateRightButtonWidth
|
||||
{
|
||||
NSString *title = [self.rightButton titleForState:UIControlStateNormal];
|
||||
CGSize rigthButtonSize = [title sizeWithAttributes:@{NSFontAttributeName: self.rightButton.titleLabel.font}];
|
||||
|
||||
if (self.autoHideRightButton) {
|
||||
if (self.textView.text.length == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
return rigthButtonSize.width+self.contentInset.right;
|
||||
}
|
||||
|
||||
- (CGFloat)slk_appropriateRightButtonMargin
|
||||
{
|
||||
if (self.autoHideRightButton) {
|
||||
if (self.textView.text.length == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
return self.contentInset.right;
|
||||
}
|
||||
|
||||
- (NSUInteger)slk_defaultNumberOfLines
|
||||
{
|
||||
if (SLK_IS_IPAD) {
|
||||
return 8;
|
||||
}
|
||||
if (SLK_IS_IPHONE4) {
|
||||
return 4;
|
||||
}
|
||||
else {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setBackgroundColor:(UIColor *)color
|
||||
{
|
||||
self.barTintColor = color;
|
||||
self.textView.inputAccessoryView.backgroundColor = color;
|
||||
self.editorContentView.backgroundColor = color;
|
||||
}
|
||||
|
||||
- (void)setAutoHideRightButton:(BOOL)hide
|
||||
{
|
||||
if (self.autoHideRightButton == hide) {
|
||||
return;
|
||||
}
|
||||
|
||||
_autoHideRightButton = hide;
|
||||
|
||||
self.rightButtonWC.constant = [self slk_appropriateRightButtonWidth];
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)setContentInset:(UIEdgeInsets)insets
|
||||
{
|
||||
if (UIEdgeInsetsEqualToEdgeInsets(self.contentInset, insets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (UIEdgeInsetsEqualToEdgeInsets(self.contentInset, UIEdgeInsetsZero)) {
|
||||
_contentInset = insets;
|
||||
return;
|
||||
}
|
||||
|
||||
_contentInset = insets;
|
||||
|
||||
// Add new constraints
|
||||
[self removeConstraints:self.constraints];
|
||||
[self slk_setupViewConstraints];
|
||||
|
||||
// Add constant values and refresh layout
|
||||
[self slk_updateConstraintConstants];
|
||||
[super layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)setEditing:(BOOL)editing
|
||||
{
|
||||
if (self.isEditing == editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
_editing = editing;
|
||||
_editorContentView.hidden = !editing;
|
||||
}
|
||||
|
||||
- (void)setCounterPosition:(SLKCounterPosition)counterPosition
|
||||
{
|
||||
if (self.counterPosition == counterPosition && self.charCountLabelVCs) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clears the previous constraints
|
||||
if (_charCountLabelVCs.count > 0) {
|
||||
[self removeConstraints:_charCountLabelVCs];
|
||||
_charCountLabelVCs = nil;
|
||||
}
|
||||
|
||||
_counterPosition = counterPosition;
|
||||
|
||||
NSDictionary *views = @{@"rightButton": self.rightButton,
|
||||
@"charCountLabel": self.charCountLabel
|
||||
};
|
||||
|
||||
NSDictionary *metrics = @{@"top" : @(self.contentInset.top),
|
||||
@"bottom" : @(-self.contentInset.bottom/2.0)
|
||||
};
|
||||
|
||||
// Constraints are different depending of the counter's position type
|
||||
if (counterPosition == SLKCounterPositionBottom) {
|
||||
_charCountLabelVCs = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[charCountLabel]-(bottom)-[rightButton]" options:0 metrics:metrics views:views];
|
||||
}
|
||||
else {
|
||||
_charCountLabelVCs = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(<=top)-[charCountLabel]-(>=0)-|" options:0 metrics:metrics views:views];
|
||||
}
|
||||
|
||||
[self addConstraints:self.charCountLabelVCs];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Text Editing
|
||||
|
||||
- (BOOL)canEditText:(NSString *)text
|
||||
{
|
||||
if (self.isEditing && [self.textView.text isEqualToString:text]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)beginTextEditing
|
||||
{
|
||||
if (self.isEditing) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.editing = YES;
|
||||
|
||||
[self slk_updateConstraintConstants];
|
||||
|
||||
if (!self.isFirstResponder) {
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)endTextEdition
|
||||
{
|
||||
if (!self.isEditing) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.editing = NO;
|
||||
[self slk_updateConstraintConstants];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Character Counter
|
||||
|
||||
- (void)slk_updateCounter
|
||||
{
|
||||
NSString *text = [self.textView.text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
||||
NSString *counter = nil;
|
||||
|
||||
if (self.counterStyle == SLKCounterStyleNone) {
|
||||
counter = [NSString stringWithFormat:@"%lu", (unsigned long)text.length];
|
||||
}
|
||||
if (self.counterStyle == SLKCounterStyleSplit) {
|
||||
counter = [NSString stringWithFormat:@"%lu/%lu", (unsigned long)text.length, (unsigned long)self.maxCharCount];
|
||||
}
|
||||
if (self.counterStyle == SLKCounterStyleCountdown) {
|
||||
counter = [NSString stringWithFormat:@"%ld", (long)(text.length - self.maxCharCount)];
|
||||
}
|
||||
if (self.counterStyle == SLKCounterStyleCountdownReversed)
|
||||
{
|
||||
counter = [NSString stringWithFormat:@"%ld", (long)(self.maxCharCount - text.length)];
|
||||
}
|
||||
|
||||
self.charCountLabel.text = counter;
|
||||
self.charCountLabel.textColor = [self limitExceeded] ? self.charCountLabelWarningColor : self.charCountLabelNormalColor;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Magnifying Glass handling
|
||||
|
||||
- (void)slk_willShowLoupe:(UIGestureRecognizer *)gesture
|
||||
{
|
||||
if (gesture.state == UIGestureRecognizerStateChanged) {
|
||||
self.textView.loupeVisible = YES;
|
||||
}
|
||||
else {
|
||||
self.textView.loupeVisible = NO;
|
||||
}
|
||||
|
||||
// We still need to notify a selection change in the textview after the magnifying class is dismissed
|
||||
if (gesture.state == UIGestureRecognizerStateEnded) {
|
||||
if (self.textView.delegate && [self.textView.delegate respondsToSelector:@selector(textViewDidChangeSelection:)]) {
|
||||
[self.textView.delegate textViewDidChangeSelection:self.textView];
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SLKTextViewSelectedRangeDidChangeNotification object:self.textView userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Notification Events
|
||||
|
||||
- (void)slk_didChangeTextViewText:(NSNotification *)notification
|
||||
{
|
||||
SLKTextView *textView = (SLKTextView *)notification.object;
|
||||
|
||||
// Skips this it's not the expected textView.
|
||||
if (![textView isEqual:self.textView]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Updates the char counter label
|
||||
if (self.maxCharCount > 0) {
|
||||
[self slk_updateCounter];
|
||||
}
|
||||
|
||||
if (self.autoHideRightButton && !self.isEditing)
|
||||
{
|
||||
CGFloat rightButtonNewWidth = [self slk_appropriateRightButtonWidth];
|
||||
|
||||
if (self.rightButtonWC.constant == rightButtonNewWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.rightButtonWC.constant = rightButtonNewWidth;
|
||||
self.rightMarginWC.constant = [self slk_appropriateRightButtonMargin];
|
||||
|
||||
if (rightButtonNewWidth > 0) {
|
||||
[self.rightButton sizeToFit];
|
||||
}
|
||||
|
||||
BOOL bounces = self.controller.bounces && [self.textView isFirstResponder];
|
||||
|
||||
if ([self isViewVisible]) {
|
||||
[self slk_animateLayoutIfNeededWithBounce:bounces
|
||||
options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:NULL];
|
||||
}
|
||||
else {
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slk_didChangeTextViewContentSize:(NSNotification *)notification
|
||||
{
|
||||
if (self.maxCharCount > 0) {
|
||||
BOOL shouldHide = (self.textView.numberOfLines == 1) || self.editing;
|
||||
self.charCountLabel.hidden = shouldHide;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - View Auto-Layout
|
||||
|
||||
- (void)slk_setupViewConstraints
|
||||
{
|
||||
UIImage *leftButtonImg = [self.leftButton imageForState:UIControlStateNormal];
|
||||
|
||||
[self.rightButton sizeToFit];
|
||||
|
||||
CGFloat leftVerMargin = (self.intrinsicContentSize.height - leftButtonImg.size.height) / 2.0;
|
||||
CGFloat rightVerMargin = (self.intrinsicContentSize.height - CGRectGetHeight(self.rightButton.frame)) / 2.0;
|
||||
|
||||
NSDictionary *views = @{@"textView": self.textView,
|
||||
@"leftButton": self.leftButton,
|
||||
@"rightButton": self.rightButton,
|
||||
@"contentView": self.editorContentView,
|
||||
@"charCountLabel": self.charCountLabel
|
||||
};
|
||||
|
||||
NSDictionary *metrics = @{@"top" : @(self.contentInset.top),
|
||||
@"bottom" : @(self.contentInset.bottom),
|
||||
@"left" : @(self.contentInset.left),
|
||||
@"right" : @(self.contentInset.right),
|
||||
@"leftVerMargin" : @(leftVerMargin),
|
||||
@"rightVerMargin" : @(rightVerMargin),
|
||||
@"minTextViewHeight" : @(self.textView.intrinsicContentSize.height),
|
||||
};
|
||||
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(left)-[leftButton(0)]-(<=left)-[textView]-(right)-[rightButton(0)]-(right)-|" options:0 metrics:metrics views:views]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=0)-[leftButton(0)]-(0@750)-|" options:0 metrics:metrics views:views]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=rightVerMargin)-[rightButton]-(<=rightVerMargin)-|" options:0 metrics:metrics views:views]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(left@250)-[charCountLabel(<=50@1000)]-(right@750)-|" options:0 metrics:metrics views:views]];
|
||||
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView(0)]-(<=top)-[textView(minTextViewHeight@250)]-(bottom)-|" options:0 metrics:metrics views:views]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:metrics views:views]];
|
||||
|
||||
self.editorContentViewHC = [self slk_constraintForAttribute:NSLayoutAttributeHeight firstItem:self.editorContentView secondItem:nil];
|
||||
|
||||
self.leftButtonWC = [self slk_constraintForAttribute:NSLayoutAttributeWidth firstItem:self.leftButton secondItem:nil];
|
||||
self.leftButtonHC = [self slk_constraintForAttribute:NSLayoutAttributeHeight firstItem:self.leftButton secondItem:nil];
|
||||
|
||||
self.leftMarginWC = [self slk_constraintsForAttribute:NSLayoutAttributeLeading][0];
|
||||
self.bottomMarginWC = [self slk_constraintForAttribute:NSLayoutAttributeBottom firstItem:self secondItem:self.leftButton];
|
||||
|
||||
self.rightButtonWC = [self slk_constraintForAttribute:NSLayoutAttributeWidth firstItem:self.rightButton secondItem:nil];
|
||||
self.rightMarginWC = [self slk_constraintsForAttribute:NSLayoutAttributeTrailing][0];
|
||||
}
|
||||
|
||||
- (void)slk_updateConstraintConstants
|
||||
{
|
||||
CGFloat zero = 0.0;
|
||||
|
||||
if (self.isEditing)
|
||||
{
|
||||
self.editorContentViewHC.constant = self.editorContentViewHeight;
|
||||
self.leftButtonWC.constant = zero;
|
||||
self.leftButtonHC.constant = zero;
|
||||
self.leftMarginWC.constant = zero;
|
||||
self.bottomMarginWC.constant = zero;
|
||||
self.rightButtonWC.constant = zero;
|
||||
self.rightMarginWC.constant = zero;
|
||||
}
|
||||
else {
|
||||
self.editorContentViewHC.constant = zero;
|
||||
|
||||
CGSize leftButtonSize = [self.leftButton imageForState:self.leftButton.state].size;
|
||||
|
||||
if (leftButtonSize.width > 0) {
|
||||
self.leftButtonHC.constant = roundf(leftButtonSize.height);
|
||||
self.bottomMarginWC.constant = roundf((self.intrinsicContentSize.height - leftButtonSize.height) / 2.0);
|
||||
}
|
||||
|
||||
self.leftButtonWC.constant = roundf(leftButtonSize.width);
|
||||
self.leftMarginWC.constant = (leftButtonSize.width > 0) ? self.contentInset.left : zero;
|
||||
|
||||
self.rightButtonWC.constant = [self slk_appropriateRightButtonWidth];
|
||||
self.rightMarginWC.constant = [self slk_appropriateRightButtonMargin];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Observers
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ([object isEqual:self.leftButton.imageView] && [keyPath isEqualToString:NSStringFromSelector(@selector(image))]) {
|
||||
UIImage *newImage = change[NSKeyValueChangeNewKey];
|
||||
UIImage *oldImage = change[NSKeyValueChangeOldKey];
|
||||
|
||||
if ([newImage isEqual:oldImage]) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self slk_updateConstraintConstants];
|
||||
}
|
||||
else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Lifeterm
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:SLKTextViewContentSizeDidChangeNotification object:nil];
|
||||
|
||||
[_leftButton.imageView removeObserver:self forKeyPath:NSStringFromSelector(@selector(image))];
|
||||
|
||||
_leftButton = nil;
|
||||
_rightButton = nil;
|
||||
|
||||
_textView.delegate = nil;
|
||||
_textView = nil;
|
||||
|
||||
_editorContentView = nil;
|
||||
_editorTitle = nil;
|
||||
_editortLeftButton = nil;
|
||||
_editortRightButton = nil;
|
||||
|
||||
_leftButtonWC = nil;
|
||||
_leftButtonHC = nil;
|
||||
_leftMarginWC = nil;
|
||||
_bottomMarginWC = nil;
|
||||
_rightButtonWC = nil;
|
||||
_rightMarginWC = nil;
|
||||
_editorContentViewHC = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
90
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKTextView.h
generated
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
UIKIT_EXTERN NSString * const SLKTextViewTextWillChangeNotification;
|
||||
UIKIT_EXTERN NSString * const SLKTextViewContentSizeDidChangeNotification;
|
||||
UIKIT_EXTERN NSString * const SLKTextViewSelectedRangeDidChangeNotification;
|
||||
UIKIT_EXTERN NSString * const SLKTextViewDidPasteItemNotification;
|
||||
UIKIT_EXTERN NSString * const SLKTextViewDidShakeNotification;
|
||||
|
||||
UIKIT_EXTERN NSString * const SLKTextViewPastedItemContentType;
|
||||
UIKIT_EXTERN NSString * const SLKTextViewPastedItemMediaType;
|
||||
UIKIT_EXTERN NSString * const SLKTextViewPastedItemData;
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, SLKPastableMediaType) {
|
||||
SLKPastableMediaTypeNone = 0,
|
||||
SLKPastableMediaTypePNG = 1 << 0,
|
||||
SLKPastableMediaTypeJPEG = 1 << 1,
|
||||
SLKPastableMediaTypeTIFF = 1 << 2,
|
||||
SLKPastableMediaTypeGIF = 1 << 3,
|
||||
SLKPastableMediaTypeMOV = 1 << 4,
|
||||
SLKPastableMediaTypePassbook = 1 << 5,
|
||||
SLKPastableMediaTypeImages = SLKPastableMediaTypePNG|SLKPastableMediaTypeJPEG|SLKPastableMediaTypeTIFF|SLKPastableMediaTypeGIF,
|
||||
SLKPastableMediaTypeVideos = SLKPastableMediaTypeMOV,
|
||||
SLKPastableMediaTypeAll = SLKPastableMediaTypeImages|SLKPastableMediaTypeMOV
|
||||
};
|
||||
|
||||
/** @name A custom text input view. */
|
||||
@interface SLKTextView : UITextView
|
||||
|
||||
/** The placeholder text string. Default is nil. */
|
||||
@property (nonatomic, copy) NSString *placeholder;
|
||||
|
||||
/** The placeholder color. Default is lightGrayColor. */
|
||||
@property (nonatomic, copy) UIColor *placeholderColor;
|
||||
|
||||
/** The maximum number of lines before enabling scrolling. Default is 0 wich means limitless. */
|
||||
@property (nonatomic, readwrite) NSUInteger maxNumberOfLines;
|
||||
|
||||
/** The current displayed number of lines. */
|
||||
@property (nonatomic, readonly) NSUInteger numberOfLines;
|
||||
|
||||
/** The supported media types allowed to be pasted in the text view, such as images or videos. Default is None. */
|
||||
@property (nonatomic) SLKPastableMediaType pastableMediaTypes;
|
||||
|
||||
/** YES if the text view is and can still expand it self, depending if the maximum number of lines are reached. */
|
||||
@property (nonatomic, readonly) BOOL isExpanding;
|
||||
|
||||
/** YES if quickly refreshed the textview without the intension to dismiss the keyboard. @view -disableQuicktypeBar: for more details. */
|
||||
@property (nonatomic, readwrite) BOOL didNotResignFirstResponder;
|
||||
|
||||
/** YES if the magnifying glass is visible. */
|
||||
@property (nonatomic, getter=isLoupeVisible) BOOL loupeVisible;
|
||||
|
||||
/** YES if autocorrection and spell checking are enabled. On iOS8, this property also controls the predictive QuickType bar from being visible. Default is YES. */
|
||||
@property (nonatomic, getter=isTypingSuggestionEnabled) BOOL typingSuggestionEnabled;
|
||||
|
||||
/** YES if the text view supports undoing, either using UIMenuController, or with ctrl+z when using an external keyboard. Default is YES. */
|
||||
@property (nonatomic, readwrite) BOOL undoManagerEnabled;
|
||||
|
||||
/**
|
||||
Some text view properties don't update when it's already firstResponder (auto-correction, spelling-check, etc.)
|
||||
To be able to update the text view while still being first responder, requieres to switch quickly from -resignFirstResponder to -becomeFirstResponder.
|
||||
When doing so, the flag 'didNotResignFirstResponder' is momentarly set to YES before it goes back to -isFirstResponder, to be able to prevent some tasks to be excuted because of UIKeyboard notifications.
|
||||
|
||||
You can also use this method to confirm an auto-correction programatically, before the text view resigns first responder.
|
||||
*/
|
||||
- (void)refreshFirstResponder;
|
||||
- (void)refreshInputViews;
|
||||
|
||||
/**
|
||||
Notifies the text view that the user pressed any arrow key. This is used to move the cursor up and down while having multiple lines.
|
||||
*/
|
||||
- (void)didPressAnyArrowKey:(id)sender;
|
||||
|
||||
@end
|
||||
796
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKTextView.m
generated
Normal file
@@ -0,0 +1,796 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "SLKTextView.h"
|
||||
#import "SLKTextView+SLKAdditions.h"
|
||||
#import "SLKUIConstants.h"
|
||||
|
||||
NSString * const SLKTextViewTextWillChangeNotification = @"SLKTextViewTextWillChangeNotification";
|
||||
NSString * const SLKTextViewContentSizeDidChangeNotification = @"SLKTextViewContentSizeDidChangeNotification";
|
||||
NSString * const SLKTextViewSelectedRangeDidChangeNotification = @"SLKTextViewSelectedRangeDidChangeNotification";
|
||||
NSString * const SLKTextViewDidPasteItemNotification = @"SLKTextViewDidPasteItemNotification";
|
||||
NSString * const SLKTextViewDidShakeNotification = @"SLKTextViewDidShakeNotification";
|
||||
|
||||
NSString * const SLKTextViewPastedItemContentType = @"SLKTextViewPastedItemContentType";
|
||||
NSString * const SLKTextViewPastedItemMediaType = @"SLKTextViewPastedItemMediaType";
|
||||
NSString * const SLKTextViewPastedItemData = @"SLKTextViewPastedItemData";
|
||||
|
||||
@interface SLKTextView ()
|
||||
|
||||
// The label used as placeholder
|
||||
@property (nonatomic, strong) UILabel *placeholderLabel;
|
||||
|
||||
// The keyboard commands available for external keyboards
|
||||
@property (nonatomic, strong) NSArray *keyboardCommands;
|
||||
|
||||
// Used for moving the care up/down
|
||||
@property (nonatomic) UITextLayoutDirection verticalMoveDirection;
|
||||
@property (nonatomic) CGRect verticalMoveStartCaretRect;
|
||||
@property (nonatomic) CGRect verticalMoveLastCaretRect;
|
||||
|
||||
// Used for detecting if the scroll indicator was previously flashed
|
||||
@property (nonatomic) BOOL didFlashScrollIndicators;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SLKTextView
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer
|
||||
{
|
||||
if (self = [super initWithFrame:frame textContainer:textContainer]) {
|
||||
[self slk_commonInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
if (self = [super initWithCoder:coder]) {
|
||||
[self slk_commonInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)slk_commonInit
|
||||
{
|
||||
self.pastableMediaTypes = SLKPastableMediaTypeNone;
|
||||
self.undoManagerEnabled = YES;
|
||||
|
||||
self.font = [UIFont systemFontOfSize:14.0];
|
||||
self.editable = YES;
|
||||
self.selectable = YES;
|
||||
self.scrollEnabled = YES;
|
||||
self.scrollsToTop = NO;
|
||||
self.directionalLockEnabled = YES;
|
||||
self.dataDetectorTypes = UIDataDetectorTypeNone;
|
||||
|
||||
// UITextView notifications
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didChangeText:) name:UITextViewTextDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didEndEditing:) name:UITextViewTextDidEndEditingNotification object:nil];
|
||||
|
||||
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(contentSize)) options:NSKeyValueObservingOptionNew context:NULL];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UIView Overrides
|
||||
|
||||
- (CGSize)intrinsicContentSize
|
||||
{
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, 34.0);
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)layoutIfNeeded
|
||||
{
|
||||
[super layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
self.placeholderLabel.hidden = [self slk_shouldHidePlaceholder];
|
||||
|
||||
if (!self.placeholderLabel.hidden) {
|
||||
|
||||
[UIView performWithoutAnimation:^{
|
||||
self.placeholderLabel.frame = [self slk_placeholderRectThatFits:self.bounds];
|
||||
[self sendSubviewToBack:self.placeholderLabel];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UILabel *)placeholderLabel
|
||||
{
|
||||
if (!_placeholderLabel)
|
||||
{
|
||||
_placeholderLabel = [UILabel new];
|
||||
_placeholderLabel.clipsToBounds = NO;
|
||||
_placeholderLabel.autoresizesSubviews = NO;
|
||||
_placeholderLabel.numberOfLines = 1;
|
||||
_placeholderLabel.font = self.font;
|
||||
_placeholderLabel.backgroundColor = [UIColor clearColor];
|
||||
_placeholderLabel.textColor = [UIColor lightGrayColor];
|
||||
_placeholderLabel.hidden = YES;
|
||||
|
||||
[self addSubview:_placeholderLabel];
|
||||
}
|
||||
return _placeholderLabel;
|
||||
}
|
||||
|
||||
- (NSString *)placeholder
|
||||
{
|
||||
return self.placeholderLabel.text;
|
||||
}
|
||||
|
||||
- (UIColor *)placeholderColor
|
||||
{
|
||||
return self.placeholderLabel.textColor;
|
||||
}
|
||||
|
||||
- (NSUInteger)numberOfLines
|
||||
{
|
||||
return fabs(self.contentSize.height/self.font.lineHeight);
|
||||
}
|
||||
|
||||
// Returns a different number of lines when landscape and only on iPhone
|
||||
- (NSUInteger)maxNumberOfLines
|
||||
{
|
||||
if (SLK_IS_IPHONE && SLK_IS_LANDSCAPE) {
|
||||
return 2.0;
|
||||
}
|
||||
return _maxNumberOfLines;
|
||||
}
|
||||
|
||||
- (BOOL)isTypingSuggestionEnabled
|
||||
{
|
||||
return (self.autocorrectionType == UITextAutocorrectionTypeNo) ? NO : YES;
|
||||
}
|
||||
|
||||
// Returns only a supported pasted item
|
||||
- (id)slk_pastedItem
|
||||
{
|
||||
NSString *contentType = [self slk_pasteboardContentType];
|
||||
NSData *data = [[UIPasteboard generalPasteboard] dataForPasteboardType:contentType];
|
||||
|
||||
if (data && [data isKindOfClass:[NSData class]])
|
||||
{
|
||||
SLKPastableMediaType mediaType = SLKPastableMediaTypeFromNSString(contentType);
|
||||
|
||||
NSDictionary *userInfo = @{SLKTextViewPastedItemContentType: contentType,
|
||||
SLKTextViewPastedItemMediaType: @(mediaType),
|
||||
SLKTextViewPastedItemData: data};
|
||||
return userInfo;
|
||||
}
|
||||
if ([[UIPasteboard generalPasteboard] URL]) {
|
||||
return [[[UIPasteboard generalPasteboard] URL] absoluteString];
|
||||
}
|
||||
if ([[UIPasteboard generalPasteboard] string]) {
|
||||
return [[UIPasteboard generalPasteboard] string];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Checks if any supported media found in the general pasteboard
|
||||
- (BOOL)slk_isPasteboardItemSupported
|
||||
{
|
||||
if ([self slk_pasteboardContentType].length > 0) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)slk_pasteboardContentType
|
||||
{
|
||||
NSArray *pasteboardTypes = [[UIPasteboard generalPasteboard] pasteboardTypes];
|
||||
NSMutableArray *subpredicates = [NSMutableArray new];
|
||||
|
||||
for (NSString *type in [self slk_supportedMediaTypes]) {
|
||||
[subpredicates addObject:[NSPredicate predicateWithFormat:@"SELF == %@", type]];
|
||||
}
|
||||
|
||||
return [[pasteboardTypes filteredArrayUsingPredicate:[NSCompoundPredicate orPredicateWithSubpredicates:subpredicates]] firstObject];
|
||||
}
|
||||
|
||||
- (NSArray *)slk_supportedMediaTypes
|
||||
{
|
||||
if (self.pastableMediaTypes == SLKPastableMediaTypeNone) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *types = [NSMutableArray new];
|
||||
|
||||
if (self.pastableMediaTypes & SLKPastableMediaTypePNG) {
|
||||
[types addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePNG)];
|
||||
}
|
||||
if (self.pastableMediaTypes & SLKPastableMediaTypeJPEG) {
|
||||
[types addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeJPEG)];
|
||||
}
|
||||
if (self.pastableMediaTypes & SLKPastableMediaTypeTIFF) {
|
||||
[types addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeTIFF)];
|
||||
}
|
||||
if (self.pastableMediaTypes & SLKPastableMediaTypeGIF) {
|
||||
[types addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeGIF)];
|
||||
}
|
||||
if (self.pastableMediaTypes & SLKPastableMediaTypeMOV) {
|
||||
[types addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeMOV)];
|
||||
}
|
||||
if (self.pastableMediaTypes & SLKPastableMediaTypePassbook) {
|
||||
[types addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePassbook)];
|
||||
}
|
||||
|
||||
if (self.pastableMediaTypes & SLKPastableMediaTypeImages) {
|
||||
[types addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeImages)];
|
||||
}
|
||||
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
NSString *NSStringFromSLKPastableMediaType(SLKPastableMediaType type)
|
||||
{
|
||||
if (type == SLKPastableMediaTypePNG) {
|
||||
return @"public.png";
|
||||
}
|
||||
if (type == SLKPastableMediaTypeJPEG) {
|
||||
return @"public.jpeg";
|
||||
}
|
||||
if (type == SLKPastableMediaTypeTIFF) {
|
||||
return @"public.tiff";
|
||||
}
|
||||
if (type == SLKPastableMediaTypeGIF) {
|
||||
return @"com.compuserve.gif";
|
||||
}
|
||||
if (type == SLKPastableMediaTypeMOV) {
|
||||
return @"com.apple.quicktime";
|
||||
}
|
||||
if (type == SLKPastableMediaTypePassbook) {
|
||||
return @"com.apple.pkpass";
|
||||
}
|
||||
if (type == SLKPastableMediaTypeImages) {
|
||||
return @"com.apple.uikit.image";
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
SLKPastableMediaType SLKPastableMediaTypeFromNSString(NSString *string)
|
||||
{
|
||||
if ([string isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePNG)]) {
|
||||
return SLKPastableMediaTypePNG;
|
||||
}
|
||||
if ([string isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeJPEG)]) {
|
||||
return SLKPastableMediaTypeJPEG;
|
||||
}
|
||||
if ([string isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeTIFF)]) {
|
||||
return SLKPastableMediaTypeTIFF;
|
||||
}
|
||||
if ([string isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeGIF)]) {
|
||||
return SLKPastableMediaTypeGIF;
|
||||
}
|
||||
if ([string isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeMOV)]) {
|
||||
return SLKPastableMediaTypeMOV;
|
||||
}
|
||||
if ([string isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePassbook)]) {
|
||||
return SLKPastableMediaTypePassbook;
|
||||
}
|
||||
if ([string isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeImages)]) {
|
||||
return SLKPastableMediaTypeImages;
|
||||
}
|
||||
return SLKPastableMediaTypeNone;
|
||||
}
|
||||
|
||||
- (BOOL)isExpanding
|
||||
{
|
||||
if (self.numberOfLines >= self.maxNumberOfLines) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)slk_shouldHidePlaceholder
|
||||
{
|
||||
if (self.placeholder.length == 0 || self.text.length > 0) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CGRect)slk_placeholderRectThatFits:(CGRect)bounds
|
||||
{
|
||||
CGRect rect = CGRectZero;
|
||||
rect.size = [self.placeholderLabel sizeThatFits:bounds.size];
|
||||
rect.origin = UIEdgeInsetsInsetRect(bounds, self.textContainerInset).origin;
|
||||
|
||||
CGFloat padding = self.textContainer.lineFragmentPadding;
|
||||
rect.origin.x += padding;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setPlaceholder:(NSString *)placeholder
|
||||
{
|
||||
self.placeholderLabel.text = placeholder;
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderColor:(UIColor *)color
|
||||
{
|
||||
self.placeholderLabel.textColor = color;
|
||||
}
|
||||
|
||||
- (void)setUndoManagerEnabled:(BOOL)enabled
|
||||
{
|
||||
if (self.undoManagerEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.undoManager.levelsOfUndo = 10;
|
||||
[self.undoManager removeAllActions];
|
||||
[self.undoManager setActionIsDiscardable:YES];
|
||||
|
||||
_undoManagerEnabled = enabled;
|
||||
}
|
||||
|
||||
- (void)setTypingSuggestionEnabled:(BOOL)enabled
|
||||
{
|
||||
if (self.isTypingSuggestionEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.autocorrectionType = enabled ? UITextAutocorrectionTypeDefault : UITextAutocorrectionTypeNo;
|
||||
self.spellCheckingType = enabled ? UITextSpellCheckingTypeDefault : UITextSpellCheckingTypeNo;
|
||||
|
||||
[self refreshFirstResponder];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UITextView Overrides
|
||||
|
||||
- (void)setSelectedRange:(NSRange)selectedRange
|
||||
{
|
||||
[super setSelectedRange:selectedRange];
|
||||
}
|
||||
|
||||
- (void)setSelectedTextRange:(UITextRange *)selectedTextRange
|
||||
{
|
||||
[super setSelectedTextRange:selectedTextRange];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SLKTextViewSelectedRangeDidChangeNotification object:self userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)setText:(NSString *)text
|
||||
{
|
||||
// Registers for undo management
|
||||
[self slk_prepareForUndo:@"Text Set"];
|
||||
|
||||
[super setText:text];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:UITextViewTextDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
- (void)setAttributedText:(NSAttributedString *)attributedText
|
||||
{
|
||||
// Registers for undo management
|
||||
[self slk_prepareForUndo:@"Attributed Text Set"];
|
||||
|
||||
[super setAttributedText:attributedText];
|
||||
}
|
||||
|
||||
- (void)setFont:(UIFont *)font
|
||||
{
|
||||
[super setFont:font];
|
||||
|
||||
// Updates the placeholder font too
|
||||
self.placeholderLabel.font = self.font;
|
||||
}
|
||||
|
||||
- (void)setTextAlignment:(NSTextAlignment)textAlignment
|
||||
{
|
||||
[super setTextAlignment:textAlignment];
|
||||
|
||||
// Updates the placeholder text alignment too
|
||||
self.placeholderLabel.textAlignment = textAlignment;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UITextInputTraits Overrides
|
||||
|
||||
- (void)insertText:(NSString *)text
|
||||
{
|
||||
[super insertText:text];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UIResponder Overrides
|
||||
|
||||
- (BOOL)canBecomeFirstResponder
|
||||
{
|
||||
// Adds undo/redo items to the Menu Controller
|
||||
if (self.undoManagerEnabled) {
|
||||
UIMenuItem *undo = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Undo", nil) action:@selector(slk_undo:)];
|
||||
UIMenuItem *redo = [[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Redo", nil) action:@selector(slk_redo:)];
|
||||
[[UIMenuController sharedMenuController] setMenuItems:@[undo,redo]];
|
||||
}
|
||||
|
||||
return [super canBecomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
return [super becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)canResignFirstResponder
|
||||
{
|
||||
// Removes undo/redo items
|
||||
if (self.undoManagerEnabled) {
|
||||
[[UIMenuController sharedMenuController] setMenuItems:@[]];
|
||||
[self.undoManager removeAllActions];
|
||||
}
|
||||
|
||||
return [super canResignFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
return [super resignFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||
{
|
||||
if (action == @selector(delete:)) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ((action == @selector(copy:) || action == @selector(cut:))
|
||||
&& self.selectedRange.length > 0) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (action == @selector(paste:) && [self slk_isPasteboardItemSupported]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (self.undoManagerEnabled) {
|
||||
if (action == @selector(slk_undo:)) {
|
||||
if (self.undoManager.undoActionIsDiscardable) {
|
||||
return NO;
|
||||
}
|
||||
return [self.undoManager canUndo];
|
||||
}
|
||||
if (action == @selector(slk_redo:)) {
|
||||
if (self.undoManager.redoActionIsDiscardable) {
|
||||
return NO;
|
||||
}
|
||||
return [self.undoManager canRedo];
|
||||
}
|
||||
}
|
||||
|
||||
return [super canPerformAction:action withSender:sender];
|
||||
}
|
||||
|
||||
- (void)paste:(id)sender
|
||||
{
|
||||
id pastedItem = [self slk_pastedItem];
|
||||
|
||||
if ([pastedItem isKindOfClass:[NSDictionary class]]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SLKTextViewDidPasteItemNotification object:nil userInfo:pastedItem];
|
||||
}
|
||||
else if ([pastedItem isKindOfClass:[NSString class]]) {
|
||||
// Respect the delegate yo!
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)]) {
|
||||
if (![self.delegate textView:self shouldChangeTextInRange:self.selectedRange replacementText:pastedItem]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Inserting the text fixes a UITextView bug whitch automatically scrolls to the bottom
|
||||
// and beyond scroll content size sometimes when the text is too long
|
||||
[self slk_insertTextAtCaretRange:pastedItem];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Custom Actions
|
||||
|
||||
- (void)slk_flashScrollIndicatorsIfNeeded
|
||||
{
|
||||
if (self.numberOfLines == self.maxNumberOfLines+1) {
|
||||
if (!_didFlashScrollIndicators) {
|
||||
_didFlashScrollIndicators = YES;
|
||||
[super flashScrollIndicators];
|
||||
}
|
||||
}
|
||||
else if (_didFlashScrollIndicators) {
|
||||
_didFlashScrollIndicators = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)refreshFirstResponder
|
||||
{
|
||||
if (!self.isFirstResponder) {
|
||||
return;
|
||||
}
|
||||
|
||||
_didNotResignFirstResponder = YES;
|
||||
[self resignFirstResponder];
|
||||
|
||||
_didNotResignFirstResponder = NO;
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (void)refreshInputViews
|
||||
{
|
||||
_didNotResignFirstResponder = YES;
|
||||
|
||||
[super reloadInputViews];
|
||||
|
||||
_didNotResignFirstResponder = NO;
|
||||
}
|
||||
|
||||
- (void)slk_undo:(id)sender
|
||||
{
|
||||
[self.undoManager undo];
|
||||
}
|
||||
|
||||
- (void)slk_redo:(id)sender
|
||||
{
|
||||
[self.undoManager redo];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Notification Events
|
||||
|
||||
- (void)slk_didBeginEditing:(NSNotification *)notification
|
||||
{
|
||||
if (![notification.object isEqual:self]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do something
|
||||
}
|
||||
|
||||
- (void)slk_didChangeText:(NSNotification *)notification
|
||||
{
|
||||
if (![notification.object isEqual:self]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.placeholderLabel.hidden != [self slk_shouldHidePlaceholder]) {
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
[self slk_flashScrollIndicatorsIfNeeded];
|
||||
}
|
||||
|
||||
- (void)slk_didEndEditing:(NSNotification *)notification
|
||||
{
|
||||
if (![notification.object isEqual:self]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do something
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - KVO Listener
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ([object isEqual:self] && [keyPath isEqualToString:NSStringFromSelector(@selector(contentSize))]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SLKTextViewContentSizeDidChangeNotification object:self userInfo:nil];
|
||||
}
|
||||
else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Motion Events
|
||||
|
||||
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
|
||||
{
|
||||
if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:SLKTextViewDidShakeNotification object:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - External Keyboard Support
|
||||
|
||||
- (NSArray *)keyCommands
|
||||
{
|
||||
if (_keyboardCommands) {
|
||||
return _keyboardCommands;
|
||||
}
|
||||
|
||||
_keyboardCommands = @[
|
||||
// Return
|
||||
[UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:UIKeyModifierShift action:@selector(slk_didPressLineBreakKeys:)],
|
||||
[UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:UIKeyModifierAlternate action:@selector(slk_didPressLineBreakKeys:)],
|
||||
[UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:UIKeyModifierControl action:@selector(slk_didPressLineBreakKeys:)],
|
||||
|
||||
// Undo/Redo
|
||||
[UIKeyCommand keyCommandWithInput:@"z" modifierFlags:UIKeyModifierCommand action:@selector(slk_didPressCommandZKeys:)],
|
||||
[UIKeyCommand keyCommandWithInput:@"z" modifierFlags:UIKeyModifierShift|UIKeyModifierCommand action:@selector(slk_didPressCommandZKeys:)],
|
||||
];
|
||||
|
||||
return _keyboardCommands;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Line Break
|
||||
|
||||
- (void)slk_didPressLineBreakKeys:(id)sender
|
||||
{
|
||||
[self slk_insertNewLineBreak];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Undo/Redo Text
|
||||
|
||||
- (void)slk_didPressCommandZKeys:(id)sender
|
||||
{
|
||||
if (!self.undoManagerEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIKeyCommand *keyCommand = (UIKeyCommand *)sender;
|
||||
|
||||
if ((keyCommand.modifierFlags & UIKeyModifierShift) > 0) {
|
||||
|
||||
if ([self.undoManager canRedo]) {
|
||||
[self.undoManager redo];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ([self.undoManager canUndo]) {
|
||||
[self.undoManager undo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Up/Down Cursor Movement
|
||||
|
||||
- (void)didPressAnyArrowKey:(id)sender
|
||||
{
|
||||
if (self.text.length == 0 || self.numberOfLines < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIKeyCommand *keyCommand = (UIKeyCommand *)sender;
|
||||
|
||||
if ([keyCommand.input isEqualToString:UIKeyInputUpArrow]) {
|
||||
[self slk_moveCursorTodirection:UITextLayoutDirectionUp];
|
||||
}
|
||||
else if ([keyCommand.input isEqualToString:UIKeyInputDownArrow]) {
|
||||
[self slk_moveCursorTodirection:UITextLayoutDirectionDown];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slk_moveCursorTodirection:(UITextLayoutDirection)direction
|
||||
{
|
||||
UITextPosition *start = (direction == UITextLayoutDirectionUp) ? self.selectedTextRange.start : self.selectedTextRange.end;
|
||||
|
||||
if ([self slk_isNewVerticalMovementForPosition:start inDirection:direction]) {
|
||||
self.verticalMoveDirection = direction;
|
||||
self.verticalMoveStartCaretRect = [self caretRectForPosition:start];
|
||||
}
|
||||
|
||||
if (start) {
|
||||
|
||||
UITextPosition *end = [self slk_closestPositionToPosition:start inDirection:direction];
|
||||
|
||||
if (end) {
|
||||
self.verticalMoveLastCaretRect = [self caretRectForPosition:end];
|
||||
self.selectedTextRange = [self textRangeFromPosition:end toPosition:end];
|
||||
|
||||
[self slk_scrollToCaretPositonAnimated:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Based on code from Ruben Cabaco
|
||||
// https://gist.github.com/rcabaco/6765778
|
||||
|
||||
- (UITextPosition *)slk_closestPositionToPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
|
||||
{
|
||||
// Only up/down are implemented. No real need for left/right since that is native to UITextInput.
|
||||
NSParameterAssert(direction == UITextLayoutDirectionUp || direction == UITextLayoutDirectionDown);
|
||||
|
||||
// Translate the vertical direction to a horizontal direction.
|
||||
UITextLayoutDirection lookupDirection = (direction == UITextLayoutDirectionUp) ? UITextLayoutDirectionLeft : UITextLayoutDirectionRight;
|
||||
|
||||
// Walk one character at a time in `lookupDirection` until the next line is reached.
|
||||
UITextPosition *checkPosition = position;
|
||||
UITextPosition *closestPosition = position;
|
||||
CGRect startingCaretRect = [self caretRectForPosition:position];
|
||||
CGRect nextLineCaretRect;
|
||||
BOOL isInNextLine = NO;
|
||||
|
||||
while (YES) {
|
||||
UITextPosition *nextPosition = [self positionFromPosition:checkPosition inDirection:lookupDirection offset:1];
|
||||
|
||||
// End of line.
|
||||
if (!nextPosition || [self comparePosition:checkPosition toPosition:nextPosition] == NSOrderedSame) {
|
||||
break;
|
||||
}
|
||||
|
||||
checkPosition = nextPosition;
|
||||
CGRect checkRect = [self caretRectForPosition:checkPosition];
|
||||
if (CGRectGetMidY(startingCaretRect) != CGRectGetMidY(checkRect)) {
|
||||
// While on the next line stop just above/below the starting position.
|
||||
if (lookupDirection == UITextLayoutDirectionLeft && CGRectGetMidX(checkRect) <= CGRectGetMidX(self.verticalMoveStartCaretRect)) {
|
||||
closestPosition = checkPosition;
|
||||
break;
|
||||
}
|
||||
if (lookupDirection == UITextLayoutDirectionRight && CGRectGetMidX(checkRect) >= CGRectGetMidX(self.verticalMoveStartCaretRect)) {
|
||||
closestPosition = checkPosition;
|
||||
break;
|
||||
}
|
||||
// But don't skip lines.
|
||||
if (isInNextLine && CGRectGetMidY(checkRect) != CGRectGetMidY(nextLineCaretRect)) {
|
||||
break;
|
||||
}
|
||||
|
||||
isInNextLine = YES;
|
||||
nextLineCaretRect = checkRect;
|
||||
closestPosition = checkPosition;
|
||||
}
|
||||
}
|
||||
return closestPosition;
|
||||
}
|
||||
|
||||
- (BOOL)slk_isNewVerticalMovementForPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
|
||||
{
|
||||
CGRect caretRect = [self caretRectForPosition:position];
|
||||
BOOL noPreviousStartPosition = CGRectEqualToRect(self.verticalMoveStartCaretRect, CGRectZero);
|
||||
BOOL caretMovedSinceLastPosition = !CGRectEqualToRect(caretRect, self.verticalMoveLastCaretRect);
|
||||
BOOL directionChanged = self.verticalMoveDirection != direction;
|
||||
|
||||
BOOL newMovement = noPreviousStartPosition || caretMovedSinceLastPosition || directionChanged;
|
||||
return newMovement;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Lifeterm
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
[self removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentSize))];
|
||||
|
||||
_placeholderLabel = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
468
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKTextViewController.h
generated
Normal file
@@ -0,0 +1,468 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "SLKTextInputbar.h"
|
||||
#import "SLKTypingIndicatorView.h"
|
||||
#import "SLKTextView.h"
|
||||
|
||||
#import "SLKTextView+SLKAdditions.h"
|
||||
#import "UIScrollView+SLKAdditions.h"
|
||||
#import "UIView+SLKAdditions.h"
|
||||
|
||||
#import "SLKUIConstants.h"
|
||||
|
||||
/**
|
||||
UIKeyboard notification replacement, posting reliably only when showing/hiding the keyboard (not when resizing keyboard, or with inputAccessoryView reloads, etc).
|
||||
Only triggered when using SLKTextViewController's text view.
|
||||
*/
|
||||
UIKIT_EXTERN NSString *const SLKKeyboardWillShowNotification;
|
||||
UIKIT_EXTERN NSString *const SLKKeyboardDidShowNotification;
|
||||
UIKIT_EXTERN NSString *const SLKKeyboardWillHideNotification;
|
||||
UIKIT_EXTERN NSString *const SLKKeyboardDidHideNotification;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SLKKeyboardStatus) {
|
||||
SLKKeyboardStatusDidHide,
|
||||
SLKKeyboardStatusWillShow,
|
||||
SLKKeyboardStatusDidShow,
|
||||
SLKKeyboardStatusWillHide
|
||||
};
|
||||
|
||||
/** @name A drop-in UIViewController subclass with a growing text input view and other useful messaging features. */
|
||||
NS_CLASS_AVAILABLE_IOS(7_0) @interface SLKTextViewController : UIViewController <UITextViewDelegate, UITableViewDelegate, UITableViewDataSource, UICollectionViewDelegate, UICollectionViewDataSource, UIGestureRecognizerDelegate, UIAlertViewDelegate>
|
||||
|
||||
/** The main table view managed by the controller object. Created by default initializing with -init or initWithNibName:bundle: */
|
||||
@property (nonatomic, readonly) UITableView *tableView;
|
||||
|
||||
/** The main collection view managed by the controller object. Not nil if the controller is initialised with -initWithCollectionViewLayout: */
|
||||
@property (nonatomic, readonly) UICollectionView *collectionView;
|
||||
|
||||
/** The main scroll view managed by the controller object. Not nil if the controller is initialised with -initWithScrollView: */
|
||||
@property (nonatomic, readonly) UIScrollView *scrollView;
|
||||
|
||||
/** The bottom toolbar containing a text view and buttons. */
|
||||
@property (nonatomic, readonly) SLKTextInputbar *textInputbar;
|
||||
|
||||
/** The typing indicator used to display user names horizontally. */
|
||||
@property (nonatomic, readonly) SLKTypingIndicatorView *typingIndicatorView;
|
||||
|
||||
/** A single tap gesture used to dismiss the keyboard. */
|
||||
@property (nonatomic, readonly) UIGestureRecognizer *singleTapGesture;
|
||||
|
||||
/** A vertical pan gesture used for bringing the keyboard from the bottom. */
|
||||
@property (nonatomic, readonly) UIPanGestureRecognizer *verticalPanGesture;
|
||||
|
||||
/** YES if control's animation should have bouncy effects. Default is YES. */
|
||||
@property (nonatomic, assign) BOOL bounces;
|
||||
|
||||
/** YES if text view's content can be cleaned with a shake gesture. Default is NO. */
|
||||
@property (nonatomic, assign) BOOL shakeToClearEnabled;
|
||||
|
||||
/** YES if keyboard can be dismissed gradually with a vertical panning gesture. Default is YES. */
|
||||
@property (nonatomic, assign, getter = isKeyboardPanningEnabled) BOOL keyboardPanningEnabled;
|
||||
|
||||
/** YES if an external keyboard has been detected (this value updates only when the text view becomes first responder). */
|
||||
@property (nonatomic, readonly) BOOL isExternalKeyboardDetected;
|
||||
|
||||
/** YES if after right button press, the text view is cleared out. Default is YES. */
|
||||
@property (nonatomic, assign) BOOL shouldClearTextAtRightButtonPress;
|
||||
|
||||
/** YES if the text input bar should still move up/down when other text inputs interacts with the keyboard. Default is NO. */
|
||||
@property (nonatomic, assign) BOOL shouldForceTextInputbarAdjustment DEPRECATED_MSG_ATTRIBUTE("Use -forceTextInputbarAdjustmentForResponder:");
|
||||
|
||||
/** YES if the scrollView should scroll to bottom when the keyboard is shown. Default is NO.*/
|
||||
@property (nonatomic, assign) BOOL shouldScrollToBottomAfterKeyboardShows;
|
||||
|
||||
/**
|
||||
YES if the main table view is inverted. Default is YES.
|
||||
This allows the table view to start from the bottom like any typical messaging interface.
|
||||
If inverted, you must assign the same transform property to your cells to match the orientation (ie: cell.transform = tableView.transform;)
|
||||
Inverting the table view will enable some great features such as content offset corrections automatically when resizing the text input and/or showing autocompletion.
|
||||
|
||||
Updating this value also changes 'edgesForExtendedLayout' value. When inverted, it must be UIRectEdgeNone, to display correctly all the elements. Otherwise, UIRectEdgeAll is set.
|
||||
*/
|
||||
@property (nonatomic, assign, getter = isInverted) BOOL inverted;
|
||||
|
||||
/** YES if the view controller is presented inside of a popover controller. If YES, the keyboard won't move the text input bar and tapping on the tableView/collectionView will not cause the keyboard to be dismissed. This property is compatible only with iPad. */
|
||||
@property (nonatomic, assign, getter = isPresentedInPopover) BOOL presentedInPopover;
|
||||
|
||||
/** Convenience accessors (accessed through the text input bar) */
|
||||
@property (nonatomic, readonly) SLKTextView *textView;
|
||||
@property (nonatomic, readonly) UIButton *leftButton;
|
||||
@property (nonatomic, readonly) UIButton *rightButton;
|
||||
|
||||
|
||||
#pragma mark - Initialization
|
||||
///------------------------------------------------
|
||||
/// @name Initialization
|
||||
///------------------------------------------------
|
||||
|
||||
/**
|
||||
Initializes a text view controller to manage a table view of a given style.
|
||||
If you use the standard -init method, a table view with plain style will be created.
|
||||
|
||||
@param style A constant that specifies the style of main table view that the controller object is to manage (UITableViewStylePlain or UITableViewStyleGrouped).
|
||||
@return An initialized SLKTextViewController object or nil if the object could not be created.
|
||||
*/
|
||||
- (instancetype)initWithTableViewStyle:(UITableViewStyle)style SLK_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
Initializes a collection view controller and configures the collection view with the provided layout.
|
||||
If you use the standard -init method, a table view with plain style will be created.
|
||||
|
||||
@param layout The layout object to associate with the collection view. The layout controls how the collection view presents its cells and supplementary views.
|
||||
@return An initialized SLKTextViewController object or nil if the object could not be created.
|
||||
*/
|
||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout SLK_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
Initializes a text view controller to manage an arbitraty scroll view. The caller is responsible for configuration of the scroll view, including wiring the delegate.
|
||||
|
||||
@param a UISCrollView to be used as the main content area.
|
||||
@return An initialized SLKTextViewController object or nil if the object could not be created.
|
||||
*/
|
||||
- (instancetype)initWithScrollView:(UIScrollView *)scrollView SLK_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
Initializes either a table or collection view controller.
|
||||
You must override either +tableViewStyleForCoder: or +collectionViewLayoutForCoder: to define witch view to be layed out.
|
||||
|
||||
@param decoder An unarchiver object.
|
||||
@return An initialized SLKTextViewController object or nil if the object could not be created.
|
||||
*/
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder SLK_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
Returns the tableView style to be configured when using Interface Builder. Default is UITableViewStylePlain.
|
||||
You must override this method if you want to configure a tableView.
|
||||
|
||||
@param decoder An unarchiver object.
|
||||
@return The tableView style to be used in the new instantiated tableView.
|
||||
*/
|
||||
+ (UITableViewStyle)tableViewStyleForCoder:(NSCoder *)decoder;
|
||||
|
||||
/**
|
||||
Returns the tableView style to be configured when using Interface Builder. Default is nil.
|
||||
You must override this method if you want to configure a collectionView.
|
||||
|
||||
@param decoder An unarchiver object.
|
||||
@return The collectionView style to be used in the new instantiated collectionView.
|
||||
*/
|
||||
+ (UICollectionViewLayout *)collectionViewLayoutForCoder:(NSCoder *)decoder;
|
||||
|
||||
|
||||
#pragma mark - Keyboard Handling
|
||||
///------------------------------------------------
|
||||
/// @name Keyboard Handling
|
||||
///------------------------------------------------
|
||||
|
||||
/**
|
||||
Presents the keyboard, if not already, animated.
|
||||
|
||||
@param animated YES if the keyboard should show using an animation.
|
||||
*/
|
||||
- (void)presentKeyboard:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Dimisses the keyboard, if not already, animated.
|
||||
|
||||
@param animated YES if the keyboard should be dismissed using an animation.
|
||||
*/
|
||||
- (void)dismissKeyboard:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Verifies if the text input bar should still move up/down even if it is not first responder. Default is NO.
|
||||
You can override this method to perform additional tasks associated with presenting the view. You don't need call super since this method doesn't do anything.
|
||||
|
||||
@param responder The current first responder object.
|
||||
@return YES so the text input bar still move up/down.
|
||||
*/
|
||||
- (BOOL)forceTextInputbarAdjustmentForResponder:(UIResponder *)responder;
|
||||
|
||||
/**
|
||||
Notifies the view controller that the keyboard changed status.
|
||||
You can override this method to perform additional tasks associated with presenting the view. You don't need call super since this method doesn't do anything.
|
||||
|
||||
@param status The new keyboard status.
|
||||
*/
|
||||
- (void)didChangeKeyboardStatus:(SLKKeyboardStatus)status;
|
||||
|
||||
|
||||
#pragma mark - Interaction Notifications
|
||||
///------------------------------------------------
|
||||
/// @name Interaction Notifications
|
||||
///------------------------------------------------
|
||||
|
||||
/**
|
||||
Notifies the view controller that the text will update.
|
||||
You can override this method to perform additional tasks associated with text changes. You MUST call super at some point in your implementation.
|
||||
*/
|
||||
- (void)textWillUpdate NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Notifies the view controller that the text did update.
|
||||
You can override this method to perform additional tasks associated with text changes. You MUST call super at some point in your implementation.
|
||||
|
||||
@param If YES, the text input bar will be resized using an animation.
|
||||
*/
|
||||
- (void)textDidUpdate:(BOOL)animated NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Notifies the view controller that the text selection did change.
|
||||
Use this method a replacement of UITextViewDelegate's -textViewDidChangeSelection: which is not reliable enough when using third-party keyboards (they don't forward events properly sometimes).
|
||||
|
||||
You can override this method to perform additional tasks associated with text changes. You MUST call super at some point in your implementation.
|
||||
*/
|
||||
- (void)textSelectionDidChange NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the left button's action has been triggered, manually.
|
||||
You can override this method to perform additional tasks associated with the left button. You don't need call super since this method doesn't do anything.
|
||||
|
||||
@param sender The object calling this method.
|
||||
*/
|
||||
- (void)didPressLeftButton:(id)sender;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the right button's action has been triggered, manually or by using the keyboard return key.
|
||||
You can override this method to perform additional tasks associated with the right button. You MUST call super at some point in your implementation.
|
||||
|
||||
@param sender The object calling this method.
|
||||
*/
|
||||
- (void)didPressRightButton:(id)sender NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Verifies if the right button can be pressed. If NO, the button is disabled.
|
||||
You can override this method to perform additional tasks. You SHOULD call super to inherit some conditionals.
|
||||
|
||||
@return YES if the right button can be pressed.
|
||||
*/
|
||||
- (BOOL)canPressRightButton;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the user has pasted a supported media content (images and/or videos).
|
||||
You can override this method to perform additional tasks associated with image/video pasting. You don't need to call super since this method doesn't do anything.
|
||||
Only supported pastable medias configured in SLKTextView will be forwarded (take a look at SLKPastableMediaType).
|
||||
|
||||
@para userInfo The payload containing the media data, content and media types.
|
||||
*/
|
||||
- (void)didPasteMediaContent:(NSDictionary *)userInfo;
|
||||
|
||||
/**
|
||||
Verifies that the typing indicator view should be shown. Default is YES, if meeting some requierements.
|
||||
You can override this method to perform additional tasks. You SHOULD call super to inherit some conditionals.
|
||||
|
||||
@return YES if the typing indicator view should be shown.
|
||||
*/
|
||||
- (BOOL)canShowTypeIndicator;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the user has shaked the device for undoing text typing.
|
||||
You can override this method to perform additional tasks associated with the shake gesture. Calling super will prompt a system alert view with undo option. This will not be called if 'undoShakingEnabled' is set to NO and/or if the text view's content is empty.
|
||||
*/
|
||||
- (void)willRequestUndo;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the user has pressed the Return key (↵) with an external keyboard.
|
||||
You can override this method to perform additional tasks. You MUST call super at some point in your implementation.
|
||||
*/
|
||||
- (void)didPressReturnKey:(id)sender NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the user has pressed the Escape key (Esc) with an external keyboard.
|
||||
You can override this method to perform additional tasks. You MUST call super at some point in your implementation.
|
||||
*/
|
||||
- (void)didPressEscapeKey:(id)sender NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the user has pressed the arrow key with an external keyboard.
|
||||
You can override this method to perform additional tasks. You MUST call super at some point in your implementation.
|
||||
*/
|
||||
- (void)didPressArrowKey:(id)sender NS_REQUIRES_SUPER;
|
||||
|
||||
|
||||
#pragma mark - Text Edition
|
||||
///------------------------------------------------
|
||||
/// @name Text Edition
|
||||
///------------------------------------------------
|
||||
|
||||
/** YES if the text editing mode is active. */
|
||||
@property (nonatomic, readonly, getter = isEditing) BOOL editing;
|
||||
|
||||
/**
|
||||
Re-uses the text layout for edition, displaying an accessory view on top of the text input bar with options (cancel & save).
|
||||
You can override this method to perform additional tasks. You MUST call super at some point in your implementation.
|
||||
|
||||
@param text The string text to edit.
|
||||
*/
|
||||
- (void)editText:(NSString *)text NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the editing bar's right button's action has been triggered, manually or by using the external keyboard's Return key.
|
||||
You can override this method to perform additional tasks associated with accepting changes. You MUST call super at some point in your implementation.
|
||||
|
||||
@param sender The object calling this method.
|
||||
*/
|
||||
- (void)didCommitTextEditing:(id)sender NS_REQUIRES_SUPER;
|
||||
|
||||
/**
|
||||
Notifies the view controller when the editing bar's right button's action has been triggered, manually or by using the external keyboard's Esc key.
|
||||
You can override this method to perform additional tasks associated with accepting changes. You MUST call super at some point in your implementation.
|
||||
|
||||
@param sender The object calling this method.
|
||||
*/
|
||||
- (void)didCancelTextEditing:(id)sender NS_REQUIRES_SUPER;
|
||||
|
||||
|
||||
#pragma mark - Text Auto-Completion
|
||||
///------------------------------------------------
|
||||
/// @name Text Auto-Completion
|
||||
///------------------------------------------------
|
||||
|
||||
/** The table view used to display autocompletion results. */
|
||||
@property (nonatomic, readonly) UITableView *autoCompletionView;
|
||||
|
||||
/** The recently found prefix symbol used as prefix for autocompletion mode. */
|
||||
@property (nonatomic, readonly, copy) NSString *foundPrefix;
|
||||
|
||||
/** The range of the found prefix in the text view content. */
|
||||
@property (nonatomic, readonly) NSRange foundPrefixRange;
|
||||
|
||||
/** The recently found word at the text view's caret position. */
|
||||
@property (nonatomic, readonly, copy) NSString *foundWord;
|
||||
|
||||
/** YES if the autocompletion mode is active. */
|
||||
@property (nonatomic, readonly, getter = isAutoCompleting) BOOL autoCompleting;
|
||||
|
||||
/** An array containing all the registered prefix strings for autocompletion. */
|
||||
@property (nonatomic, readonly, copy) NSArray *registeredPrefixes;
|
||||
|
||||
/**
|
||||
Registers any string prefix for autocompletion detection, useful for user mentions and/or hashtags autocompletion.
|
||||
The prefix must be valid NSString (i.e: '@', '#', '\', and so on). This also checks if no repeated prefix is inserted.
|
||||
|
||||
@param prefixes An array of prefix strings.
|
||||
*/
|
||||
- (void)registerPrefixesForAutoCompletion:(NSArray *)prefixes;
|
||||
|
||||
/**
|
||||
Verifies that the autocompletion view should be shown. Default is NO.
|
||||
To enabled autocompletion, MUST override this method to perform additional tasks, before the autocompletion view is shown (i.e. populating the data source).
|
||||
|
||||
@return YES if the autocompletion view should be shown.
|
||||
*/
|
||||
- (BOOL)canShowAutoCompletion;
|
||||
|
||||
/**
|
||||
Returns a custom height for the autocompletion view. Default is 0.0.
|
||||
You can override this method to return a custom height.
|
||||
|
||||
@return The autocompletion view's height.
|
||||
*/
|
||||
- (CGFloat)heightForAutoCompletionView;
|
||||
|
||||
/**
|
||||
Returns the maximum height for the autocompletion view. Default is 140 pts.
|
||||
You can override this method to return a custom max height.
|
||||
|
||||
@return The autocompletion view's max height.
|
||||
*/
|
||||
- (CGFloat)maximumHeightForAutoCompletionView;
|
||||
|
||||
/**
|
||||
Cancels and hides the autocompletion view, animated.
|
||||
*/
|
||||
- (void)cancelAutoCompletion;
|
||||
|
||||
/**
|
||||
Accepts the autocompletion, replacing the detected word with a new string, keeping the prefix.
|
||||
This method is an abstraction of -acceptAutoCompletionWithString:keepPrefix:
|
||||
|
||||
@param string The string to be used for replacing autocompletion placeholders.
|
||||
*/
|
||||
- (void)acceptAutoCompletionWithString:(NSString *)string;
|
||||
|
||||
/**
|
||||
Accepts the autocompletion, replacing the detected word with a new string, and optionally replacing the prefix too.
|
||||
|
||||
@param string The string to be used for replacing autocompletion placeholders.
|
||||
@param keepPrefix YES if the prefix shouldn't be replaced.
|
||||
*/
|
||||
- (void)acceptAutoCompletionWithString:(NSString *)string keepPrefix:(BOOL)keepPrefix;
|
||||
|
||||
|
||||
#pragma mark - Text Caching
|
||||
///------------------------------------------------
|
||||
/// @name Text Caching
|
||||
///------------------------------------------------
|
||||
|
||||
/**
|
||||
Returns the key to be associated with a given text to be cached. Default is nil.
|
||||
To enable text caching, you must override this method to return valid key.
|
||||
The text view will be populated automatically when the view controller is configured.
|
||||
You don't need call super since this method doesn't do anything.
|
||||
|
||||
@return The key for which to enable text caching.
|
||||
*/
|
||||
- (id)keyForTextCaching;
|
||||
|
||||
/**
|
||||
Removes the current's vien controller cached text.
|
||||
To enable this, you must return a valid key string in -keyForTextCaching.
|
||||
*/
|
||||
- (void)clearCachedText;
|
||||
|
||||
/**
|
||||
Removes all the cached text from disk.
|
||||
*/
|
||||
+ (void)clearAllCachedText;
|
||||
|
||||
|
||||
#pragma mark - Customization
|
||||
///------------------------------------------------
|
||||
/// @name Customization
|
||||
///------------------------------------------------
|
||||
|
||||
/**
|
||||
Registers a class for customizing the behavior and appearance of the text view.
|
||||
You need to call this method inside of any initialization method.
|
||||
|
||||
@param textViewClass A SLKTextView subclass.
|
||||
*/
|
||||
- (void)registerClassForTextView:(Class)textViewClass;
|
||||
|
||||
|
||||
#pragma mark - Delegate Methods Requiring Super
|
||||
///------------------------------------------------
|
||||
/// @name Delegate Methods Requiring Super
|
||||
///------------------------------------------------
|
||||
|
||||
/** UITextViewDelegate */
|
||||
- (BOOL)textView:(SLKTextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text NS_REQUIRES_SUPER;
|
||||
|
||||
/** UIScrollViewDelegate */
|
||||
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView NS_REQUIRES_SUPER;
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView NS_REQUIRES_SUPER;
|
||||
|
||||
/** UIGestureRecognizerDelegate */
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer NS_REQUIRES_SUPER;
|
||||
|
||||
/** UIAlertViewDelegate */
|
||||
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex NS_REQUIRES_SUPER;
|
||||
|
||||
@end
|
||||
1956
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKTextViewController.m
generated
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
UIKIT_EXTERN NSString * const SLKTypingIndicatorViewWillShowNotification;
|
||||
UIKIT_EXTERN NSString * const SLKTypingIndicatorViewWillHideNotification;
|
||||
|
||||
/** @name A custom view to display an indicator of users typing. */
|
||||
@interface SLKTypingIndicatorView : UIView
|
||||
|
||||
/** The amount of time a name should keep visible. If is zero, the indicator will not remove nor disappear automatically. Default is 6.0 seconds*/
|
||||
@property (nonatomic, readwrite) NSTimeInterval interval;
|
||||
|
||||
/** If YES, the user can dismiss the indicator by tapping on it. Default is YES. */
|
||||
@property (nonatomic, readwrite) BOOL canResignByTouch;
|
||||
|
||||
/** Returns YES if the indicator is visible. */
|
||||
@property (nonatomic, readwrite, getter = isVisible) BOOL visible;
|
||||
|
||||
/** The appropriate height of the view. */
|
||||
@property (nonatomic, readonly) CGFloat height;
|
||||
|
||||
/** The color of the text. Default is grayColor. */
|
||||
@property (nonatomic, strong) UIColor *textColor;
|
||||
|
||||
/** The font of the text. Default is system font, 12 pts. */
|
||||
@property (nonatomic, strong) UIFont *textFont;
|
||||
|
||||
/** The font to be used when matching a username string. Default is system bold font, 12 pts. */
|
||||
@property (nonatomic, strong) UIFont *highlightFont;
|
||||
|
||||
/** The inner padding to use when laying out content in the view. Default is {10, 40, 10, 10}. */
|
||||
@property (nonatomic, assign) UIEdgeInsets contentInset;
|
||||
|
||||
/**
|
||||
Inserts a user name, only if that user name is not yet on the list.
|
||||
Each inserted name has an attached timer, which will automatically remove the name from the list once the interval is reached (default 6 seconds).
|
||||
|
||||
The control follows a set of display rules, to accomodate the screen size:
|
||||
|
||||
- When only 1 user name is set, it will display ":name is typing"
|
||||
|
||||
- When only 2 user names are set, it will display ":name & :name are typing"
|
||||
|
||||
- When more than 2 user names are set, it will display "several people are typing"
|
||||
|
||||
@param username The user name string.
|
||||
*/
|
||||
- (void)insertUsername:(NSString *)username;
|
||||
|
||||
/**
|
||||
Removes a user name, if existent on the list.
|
||||
Once there are no more items on the list, the indicator will automatically try to hide (by setting it self to visible = NO).
|
||||
|
||||
@param username The user name string.
|
||||
*/
|
||||
- (void)removeUsername:(NSString *)username;
|
||||
|
||||
/**
|
||||
Dismisses the indicator view.
|
||||
*/
|
||||
- (void)dismissIndicator;
|
||||
|
||||
@end
|
||||
358
src/ui/ios/GF-Offline-Translator/Pods/SlackTextViewController/Source/Classes/SLKTypingIndicatorView.m
generated
Normal file
@@ -0,0 +1,358 @@
|
||||
//
|
||||
// Copyright 2014 Slack Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "SLKTypingIndicatorView.h"
|
||||
#import "UIView+SLKAdditions.h"
|
||||
#import "SLKUIConstants.h"
|
||||
|
||||
NSString * const SLKTypingIndicatorViewWillShowNotification = @"SLKTypingIndicatorViewWillShowNotification";
|
||||
NSString * const SLKTypingIndicatorViewWillHideNotification = @"SLKTypingIndicatorViewWillHideNotification";
|
||||
|
||||
#define SLKTypingIndicatorViewIdentifier [NSString stringWithFormat:@"%@.%@", SLKTextViewControllerDomain, NSStringFromClass([self class])]
|
||||
|
||||
@interface SLKTypingIndicatorView ()
|
||||
|
||||
// The text label used to display the typing indicator content.
|
||||
@property (nonatomic, strong) UILabel *textLabel;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *usernames;
|
||||
@property (nonatomic, strong) NSMutableArray *timers;
|
||||
|
||||
// Auto-Layout margin constraints used for updating their constants
|
||||
@property (nonatomic, strong) NSLayoutConstraint *leftContraint;
|
||||
@property (nonatomic, strong) NSLayoutConstraint *rightContraint;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SLKTypingIndicatorView
|
||||
|
||||
#pragma mark - Initializer
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
[self slk_commonInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
if (self = [super initWithCoder:coder]) {
|
||||
[self slk_commonInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)slk_commonInit
|
||||
{
|
||||
self.interval = 6.0;
|
||||
self.canResignByTouch = YES;
|
||||
self.usernames = [NSMutableArray new];
|
||||
self.timers = [NSMutableArray new];
|
||||
|
||||
self.textColor = [UIColor grayColor];
|
||||
self.textFont = [UIFont systemFontOfSize:12.0];
|
||||
self.highlightFont = [UIFont boldSystemFontOfSize:12.0];
|
||||
self.contentInset = UIEdgeInsetsMake(10.0, 40.0, 10.0, 10.0);
|
||||
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
[self addSubview:self.textLabel];
|
||||
|
||||
[self slk_setupConstraints];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UIView Overrides
|
||||
|
||||
- (CGSize)intrinsicContentSize
|
||||
{
|
||||
return CGSizeMake(UIViewNoIntrinsicMetric, [self height]);
|
||||
}
|
||||
|
||||
+ (BOOL)requiresConstraintBasedLayout
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UILabel *)textLabel
|
||||
{
|
||||
if (!_textLabel)
|
||||
{
|
||||
_textLabel = [UILabel new];
|
||||
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
_textLabel.backgroundColor = [UIColor clearColor];
|
||||
_textLabel.userInteractionEnabled = NO;
|
||||
_textLabel.hidden = YES;
|
||||
}
|
||||
return _textLabel;
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedString
|
||||
{
|
||||
if (self.usernames.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *text = nil;
|
||||
NSString *firstObject = [self.usernames firstObject];
|
||||
NSString *lastObject = [self.usernames lastObject];
|
||||
|
||||
if (self.usernames.count == 1) {
|
||||
text = [NSString stringWithFormat:NSLocalizedString(@"%@ is typing", nil), firstObject];
|
||||
}
|
||||
else if (self.usernames.count == 2) {
|
||||
text = [NSString stringWithFormat:NSLocalizedString(@"%@ & %@ are typing", nil), firstObject, lastObject];
|
||||
}
|
||||
else if (self.usernames.count > 2) {
|
||||
text = NSLocalizedString(@"Several people are typing", nil);
|
||||
}
|
||||
|
||||
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
|
||||
style.alignment = NSTextAlignmentLeft;
|
||||
style.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
style.minimumLineHeight = 10.0;
|
||||
|
||||
NSDictionary *attributes = @{NSFontAttributeName: self.textFont,
|
||||
NSForegroundColorAttributeName: self.textColor,
|
||||
NSParagraphStyleAttributeName: style,
|
||||
};
|
||||
|
||||
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
|
||||
|
||||
if (self.usernames.count <= 2) {
|
||||
[attributedString addAttribute:NSFontAttributeName value:self.highlightFont range:[text rangeOfString:firstObject]];
|
||||
[attributedString addAttribute:NSFontAttributeName value:self.highlightFont range:[text rangeOfString:lastObject]];
|
||||
}
|
||||
|
||||
return attributedString;
|
||||
}
|
||||
|
||||
- (CGFloat)height
|
||||
{
|
||||
CGFloat height = self.textFont.lineHeight;
|
||||
height += self.contentInset.top;
|
||||
height += self.contentInset.bottom;
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
- (NSTimer *)slk_timerWithIdentifier:(NSString *)identifier
|
||||
{
|
||||
for (NSTimer *timer in self.timers) {
|
||||
if ([identifier isEqualToString:[timer.userInfo objectForKey:SLKTypingIndicatorViewIdentifier]]) {
|
||||
return timer;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)setVisible:(BOOL)visible
|
||||
{
|
||||
if (visible == self.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *notificationName = visible ? SLKTypingIndicatorViewWillShowNotification : SLKTypingIndicatorViewWillHideNotification;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self];
|
||||
|
||||
if (visible) {
|
||||
self.textLabel.hidden = NO;
|
||||
}
|
||||
else {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
self.textLabel.hidden = YES;
|
||||
});
|
||||
}
|
||||
|
||||
_visible = visible;
|
||||
|
||||
if (!visible) {
|
||||
[self slk_cleanAll];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setContentInset:(UIEdgeInsets)insets
|
||||
{
|
||||
if (UIEdgeInsetsEqualToEdgeInsets(self.contentInset, insets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (UIEdgeInsetsEqualToEdgeInsets(self.contentInset, UIEdgeInsetsZero)) {
|
||||
_contentInset = insets;
|
||||
return;
|
||||
}
|
||||
|
||||
_contentInset = insets;
|
||||
|
||||
[self slk_updateConstraintConstants];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
- (void)insertUsername:(NSString *)username;
|
||||
{
|
||||
if (!username) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL isShowing = [self.usernames containsObject:username];
|
||||
|
||||
if (_interval > 0.0) {
|
||||
|
||||
if (isShowing) {
|
||||
NSTimer *timer = [self slk_timerWithIdentifier:username];
|
||||
[self slk_invalidateTimer:timer];
|
||||
}
|
||||
|
||||
NSTimer *timer = [NSTimer timerWithTimeInterval:_interval target:self selector:@selector(slk_shouldRemoveUsername:) userInfo:@{SLKTypingIndicatorViewIdentifier: username} repeats:NO];
|
||||
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
|
||||
[self.timers addObject:timer];
|
||||
}
|
||||
|
||||
if (isShowing) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.usernames addObject:username];
|
||||
|
||||
self.textLabel.attributedText = [self attributedString];
|
||||
|
||||
if (!self.isVisible) {
|
||||
[self setVisible:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeUsername:(NSString *)username
|
||||
{
|
||||
if (!username || ![self.usernames containsObject:username]) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.usernames removeObject:username];
|
||||
|
||||
if (self.usernames.count > 0) {
|
||||
self.textLabel.attributedText = [self attributedString];
|
||||
}
|
||||
else if (self.isVisible) {
|
||||
[self setVisible:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissIndicator
|
||||
{
|
||||
if (self.isVisible) {
|
||||
[self setVisible:NO];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Private Methods
|
||||
|
||||
- (void)slk_shouldRemoveUsername:(NSTimer *)timer
|
||||
{
|
||||
NSString *identifier = [timer.userInfo objectForKey:SLKTypingIndicatorViewIdentifier];
|
||||
|
||||
[self removeUsername:identifier];
|
||||
[self slk_invalidateTimer:timer];
|
||||
}
|
||||
|
||||
- (void)slk_invalidateTimer:(NSTimer *)timer
|
||||
{
|
||||
if (timer) {
|
||||
[timer invalidate];
|
||||
[self.timers removeObject:timer];
|
||||
timer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)slk_invalidateTimers
|
||||
{
|
||||
for (NSTimer *timer in self.timers) {
|
||||
[timer invalidate];
|
||||
}
|
||||
|
||||
[self.timers removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)slk_cleanAll
|
||||
{
|
||||
[self slk_invalidateTimers];
|
||||
|
||||
self.textLabel.text = nil;
|
||||
|
||||
[self.usernames removeAllObjects];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - View Auto-Layout
|
||||
|
||||
- (void)slk_setupConstraints
|
||||
{
|
||||
NSDictionary *views = @{@"textLabel": self.textLabel};
|
||||
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[textLabel]|" options:0 metrics:nil views:views]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[textLabel]-(0@750)-|" options:0 metrics:nil views:views]];
|
||||
|
||||
self.leftContraint = [[self slk_constraintsForAttribute:NSLayoutAttributeLeading] firstObject];
|
||||
self.rightContraint = [[self slk_constraintsForAttribute:NSLayoutAttributeTrailing] firstObject];
|
||||
|
||||
[self slk_updateConstraintConstants];
|
||||
}
|
||||
|
||||
- (void)slk_updateConstraintConstants
|
||||
{
|
||||
self.leftContraint.constant = self.contentInset.left;
|
||||
self.rightContraint.constant = self.contentInset.right;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Hit Testing
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
UIView *view = [super hitTest:point withEvent:event];
|
||||
|
||||
if ([view isEqual:self]) {
|
||||
if (self.isVisible && self.canResignByTouch) {
|
||||
[self setVisible:NO];
|
||||
}
|
||||
return view;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Lifeterm
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self slk_cleanAll];
|
||||
|
||||
_textLabel = nil;
|
||||
_usernames = nil;
|
||||
_timers = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "Pods-SlackTextViewController.xcconfig"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SlackTextViewController" "${PODS_ROOT}/Headers/Private/SlackTextViewController/Additions" "${PODS_ROOT}/Headers/Private/SlackTextViewController/Classes" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/SlackTextViewController" "${PODS_ROOT}/Headers/Public/SlackTextViewController/Additions" "${PODS_ROOT}/Headers/Public/SlackTextViewController/Classes"
|
||||
OTHER_LDFLAGS = -ObjC
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
SKIP_INSTALL = YES
|
||||
@@ -0,0 +1,5 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@interface PodsDummy_Pods_SlackTextViewController : NSObject
|
||||
@end
|
||||
@implementation PodsDummy_Pods_SlackTextViewController
|
||||
@end
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
#import "Pods-environment.h"
|
||||